diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1997-12-06 23:51:34 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1997-12-06 23:51:34 +0000 |
commit | 230e5ab6a084ed50470f101934782dbf54b0d06b (patch) | |
tree | 5dd821c8d33f450470588e7a543f74bf74306e9e /fs/nfs/nfs2xdr.c | |
parent | c9b1c8a64c6444d189856f1e26bdcb8b4cd0113a (diff) |
Merge with Linux 2.1.67.
Diffstat (limited to 'fs/nfs/nfs2xdr.c')
-rw-r--r-- | fs/nfs/nfs2xdr.c | 48 |
1 files changed, 30 insertions, 18 deletions
diff --git a/fs/nfs/nfs2xdr.c b/fs/nfs/nfs2xdr.c index 5eec5eb65..0311b7d0b 100644 --- a/fs/nfs/nfs2xdr.c +++ b/fs/nfs/nfs2xdr.c @@ -23,6 +23,7 @@ #include <linux/nfs_fs.h> #define NFSDBG_FACILITY NFSDBG_XDR +/* #define NFS_PARANOIA 1 */ #define QUADLEN(len) (((len) + 3) >> 2) static int nfs_stat_to_errno(int stat); @@ -371,17 +372,18 @@ nfs_xdr_readdirargs(struct rpc_rqst *req, u32 *p, struct nfs_readdirargs *args) * to avoid a malloc of NFS_MAXNAMLEN+1 for each file name. * After decoding, the layout in memory looks like this: * entry1 entry2 ... entryN <space> stringN ... string2 string1 + * Each entry consists of three __u32 values, the same space as NFS uses. * Note that the strings are not null-terminated so that the entire number * of entries returned by the server should fit into the buffer. */ static int nfs_xdr_readdirres(struct rpc_rqst *req, u32 *p, struct nfs_readdirres *res) { - struct nfs_entry *entry; struct iovec *iov = req->rq_rvec; int status, nr, len; - char *string; + char *string, *start; u32 *end; + __u32 fileid, cookie, *entry; if ((status = ntohl(*p++))) return -nfs_stat_to_errno(status); @@ -396,10 +398,11 @@ nfs_xdr_readdirres(struct rpc_rqst *req, u32 *p, struct nfs_readdirres *res) end = (u32 *) ((u8 *) p + iov[1].iov_len); /* Get start and end of dirent buffer */ - entry = (struct nfs_entry *) res->buffer; + entry = (__u32 *) res->buffer; + start = (char *) res->buffer; string = (char *) res->buffer + res->bufsiz; - for (nr = 0; *p++; nr++, entry++) { - entry->fileid = ntohl(*p++); + for (nr = 0; *p++; nr++) { + fileid = ntohl(*p++); len = ntohl(*p++); if ((p + QUADLEN(len) + 3) > end) { @@ -413,27 +416,36 @@ nfs_xdr_readdirres(struct rpc_rqst *req, u32 *p, struct nfs_readdirres *res) return -errno_NFSERR_IO; } string -= len; - if ((void *) (entry+1) > (void *) string) { - /* This may actually happen because an nfs_entry - * will take up more space than the XDR data. On - * 32bit machines that's due to 8byte alignment, - * on 64bit machines that's because the char * takes - * up 2 longs. - * - * THIS IS BAD! + if ((void *) (entry+3) > (void *) string) { + /* + * This error is impossible as long as the temp + * buffer is no larger than the user buffer. The + * current packing algorithm uses the same amount + * of space in the user buffer as in the XDR data, + * so it's guaranteed to fit. */ - printk(KERN_NOTICE "NFS: should not happen in %s!\n", + printk("NFS: incorrect buffer size in %s!\n", __FUNCTION__); break; } - entry->name = string; - entry->length = len; memmove(string, p, len); p += QUADLEN(len); - entry->cookie = ntohl(*p++); - entry->eof = !p[0] && p[1]; + cookie = ntohl(*p++); + /* + * To make everything fit, we encode the length, offset, + * and eof flag into 32 bits. This works for filenames + * up to 32K and PAGE_SIZE up to 64K. + */ + status = !p[0] && p[1] ? (1 << 15) : 0; /* eof flag */ + *entry++ = fileid; + *entry++ = cookie; + *entry++ = ((string - start) << 16) | status | (len & 0x7FFF); } +#ifdef NFS_PARANOIA +printk("nfs_xdr_readdirres: %d entries, ent sp=%d, str sp=%d\n", +nr, ((char *) entry - start), (start + res->bufsiz - string)); +#endif return nr; } |