X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=fs%2Fnfs%2Fnfs2xdr.c;h=f0015fa876e14ab9fa5228d24d6252837283ddcc;hb=43bc926fffd92024b46cafaf7350d669ba9ca884;hp=6a324838fa34193b76a91a97146d7dcedb420141;hpb=9213980e6a70d8473e0ffd4b39ab5b6caaba9ff5;p=linux-2.6.git diff --git a/fs/nfs/nfs2xdr.c b/fs/nfs/nfs2xdr.c index 6a324838f..f0015fa87 100644 --- a/fs/nfs/nfs2xdr.c +++ b/fs/nfs/nfs2xdr.c @@ -57,7 +57,7 @@ extern int nfs_stat_to_errno(int stat); #define NFS_attrstat_sz (1+NFS_fattr_sz) #define NFS_diropres_sz (1+NFS_fhandle_sz+NFS_fattr_sz) -#define NFS_readlinkres_sz (1) +#define NFS_readlinkres_sz (2) #define NFS_readres_sz (1+NFS_fattr_sz+1) #define NFS_writeres_sz (NFS_attrstat_sz) #define NFS_stat_sz (1) @@ -77,8 +77,6 @@ xdr_encode_fhandle(u32 *p, struct nfs_fh *fhandle) static inline u32 * xdr_decode_fhandle(u32 *p, struct nfs_fh *fhandle) { - /* Zero handle first to allow comparisons */ - memset(fhandle, 0, sizeof(*fhandle)); /* NFSv2 handles have a fixed length */ fhandle->size = NFS2_FHSIZE; memcpy(fhandle->data, p, NFS2_FHSIZE); @@ -94,6 +92,23 @@ xdr_encode_time(u32 *p, struct timespec *timep) return p; } +static inline u32* +xdr_encode_current_server_time(u32 *p, struct timespec *timep) +{ + /* + * Passing the invalid value useconds=1000000 is a + * Sun convention for "set to current server time". + * It's needed to make permissions checks for the + * "touch" program across v2 mounts to Solaris and + * Irix boxes work correctly. See description of + * sattr in section 6.1 of "NFS Illustrated" by + * Brent Callaghan, Addison-Wesley, ISBN 0-201-32750-5 + */ + *p++ = htonl(timep->tv_sec); + *p++ = htonl(1000000); + return p; +} + static inline u32* xdr_decode_time(u32 *p, struct timespec *timep) { @@ -128,36 +143,38 @@ xdr_decode_fattr(u32 *p, struct nfs_fattr *fattr) fattr->mode = (fattr->mode & ~S_IFMT) | S_IFIFO; fattr->rdev = 0; } - fattr->timestamp = jiffies; return p; } -#define SATTR(p, attr, flag, field) \ - *p++ = (attr->ia_valid & flag) ? htonl(attr->field) : ~(u32) 0 static inline u32 * xdr_encode_sattr(u32 *p, struct iattr *attr) { - SATTR(p, attr, ATTR_MODE, ia_mode); - SATTR(p, attr, ATTR_UID, ia_uid); - SATTR(p, attr, ATTR_GID, ia_gid); - SATTR(p, attr, ATTR_SIZE, ia_size); + const u32 not_set = __constant_htonl(0xFFFFFFFF); - if (attr->ia_valid & (ATTR_ATIME|ATTR_ATIME_SET)) { + *p++ = (attr->ia_valid & ATTR_MODE) ? htonl(attr->ia_mode) : not_set; + *p++ = (attr->ia_valid & ATTR_UID) ? htonl(attr->ia_uid) : not_set; + *p++ = (attr->ia_valid & ATTR_GID) ? htonl(attr->ia_gid) : not_set; + *p++ = (attr->ia_valid & ATTR_SIZE) ? htonl(attr->ia_size) : not_set; + + if (attr->ia_valid & ATTR_ATIME_SET) { p = xdr_encode_time(p, &attr->ia_atime); + } else if (attr->ia_valid & ATTR_ATIME) { + p = xdr_encode_current_server_time(p, &attr->ia_atime); } else { - *p++ = ~(u32) 0; - *p++ = ~(u32) 0; + *p++ = not_set; + *p++ = not_set; } - if (attr->ia_valid & (ATTR_MTIME|ATTR_MTIME_SET)) { + if (attr->ia_valid & ATTR_MTIME_SET) { p = xdr_encode_time(p, &attr->ia_mtime); + } else if (attr->ia_valid & ATTR_MTIME) { + p = xdr_encode_current_server_time(p, &attr->ia_mtime); } else { - *p++ = ~(u32) 0; - *p++ = ~(u32) 0; + *p++ = not_set; + *p++ = not_set; } return p; } -#undef SATTR /* * NFS encode functions @@ -231,7 +248,7 @@ nfs_xdr_readargs(struct rpc_rqst *req, u32 *p, struct nfs_readargs *args) static int nfs_xdr_readres(struct rpc_rqst *req, u32 *p, struct nfs_readres *res) { - struct iovec *iov = req->rq_rcv_buf.head; + struct kvec *iov = req->rq_rcv_buf.head; int status, count, recvd, hdrlen; if ((status = ntohl(*p++))) @@ -375,7 +392,7 @@ static int nfs_xdr_readdirres(struct rpc_rqst *req, u32 *p, void *dummy) { struct xdr_buf *rcvbuf = &req->rq_rcv_buf; - struct iovec *iov = rcvbuf->head; + struct kvec *iov = rcvbuf->head; struct page **page; int hdrlen, recvd; int status, nr; @@ -511,7 +528,6 @@ static int nfs_xdr_readlinkargs(struct rpc_rqst *req, u32 *p, struct nfs_readlinkargs *args) { struct rpc_auth *auth = req->rq_task->tk_auth; - unsigned int count = args->count - 5; unsigned int replen; p = xdr_encode_fhandle(p, args->fh); @@ -519,7 +535,7 @@ nfs_xdr_readlinkargs(struct rpc_rqst *req, u32 *p, struct nfs_readlinkargs *args /* Inline the page array */ replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readlinkres_sz) << 2; - xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0, count); + xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, args->pgbase, args->pglen); return 0; } @@ -530,33 +546,39 @@ static int nfs_xdr_readlinkres(struct rpc_rqst *req, u32 *p, void *dummy) { struct xdr_buf *rcvbuf = &req->rq_rcv_buf; - struct iovec *iov = rcvbuf->head; - unsigned int hdrlen; - u32 *strlen, len; - char *string; + struct kvec *iov = rcvbuf->head; + int hdrlen, len, recvd; + char *kaddr; int status; if ((status = ntohl(*p++))) return -nfs_stat_to_errno(status); + /* Convert length of symlink */ + len = ntohl(*p++); + if (len >= rcvbuf->page_len || len <= 0) { + dprintk(KERN_WARNING "nfs: server returned giant symlink!\n"); + return -ENAMETOOLONG; + } hdrlen = (u8 *) p - (u8 *) iov->iov_base; - if (iov->iov_len > hdrlen) { + if (iov->iov_len < hdrlen) { + printk(KERN_WARNING "NFS: READLINK reply header overflowed:" + "length %d > %Zu\n", hdrlen, iov->iov_len); + return -errno_NFSERR_IO; + } else if (iov->iov_len != hdrlen) { dprintk("NFS: READLINK header is short. iovec will be shifted.\n"); xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen); } - - strlen = (u32*)kmap_atomic(rcvbuf->pages[0], KM_USER0); - /* Convert length of symlink */ - len = ntohl(*strlen); - if (len > rcvbuf->page_len) { - dprintk(KERN_WARNING "nfs: server returned giant symlink!\n"); - kunmap_atomic(strlen, KM_USER0); - return -ENAMETOOLONG; + recvd = req->rq_rcv_buf.len - hdrlen; + if (recvd < len) { + printk(KERN_WARNING "NFS: server cheating in readlink reply: " + "count %u > recvd %u\n", len, recvd); + return -EIO; } - *strlen = len; + /* NULL terminate the string we got */ - string = (char *)(strlen + 1); - string[len] = '\0'; - kunmap_atomic(strlen, KM_USER0); + kaddr = (char *)kmap_atomic(rcvbuf->pages[0], KM_USER0); + kaddr[len+rcvbuf->page_base] = '\0'; + kunmap_atomic(kaddr, KM_USER0); return 0; } @@ -660,7 +682,9 @@ nfs_stat_to_errno(int stat) .p_encode = (kxdrproc_t) nfs_xdr_##argtype, \ .p_decode = (kxdrproc_t) nfs_xdr_##restype, \ .p_bufsiz = MAX(NFS_##argtype##_sz,NFS_##restype##_sz) << 2, \ - .p_timer = timer \ + .p_timer = timer, \ + .p_statidx = NFSPROC_##proc, \ + .p_name = #proc, \ } struct rpc_procinfo nfs_procedures[] = { PROC(GETATTR, fhandle, attrstat, 1), @@ -682,6 +706,6 @@ struct rpc_procinfo nfs_procedures[] = { struct rpc_version nfs_version2 = { .number = 2, - .nrprocs = sizeof(nfs_procedures)/sizeof(nfs_procedures[0]), + .nrprocs = ARRAY_SIZE(nfs_procedures), .procs = nfs_procedures };