diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index 5b7651171215d37a0f7c5e3d0d4a76534174f99a..22a5f838ea58f27fd66e5a84c2e7de523c95783d 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h @@ -219,7 +219,7 @@ extern struct dentry *nfs4_atomic_open(struct inode *, struct dentry *, struct n extern int nfs4_open_revalidate(struct inode *, struct dentry *, int, struct nameidata *); extern int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle); extern int nfs4_proc_fs_locations(struct inode *dir, struct dentry *dentry, - struct nfs_fs_locations *fs_locations, struct page *page); + struct nfs4_fs_locations *fs_locations, struct page *page); extern struct nfs4_state_recovery_ops nfs4_reboot_recovery_ops; extern struct nfs4_state_recovery_ops nfs4_network_partition_recovery_ops; diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 768514dc0c4c56ff30669bb0abb04688102eb347..043223a0eda63a2ed56504569c90e5d2709df1db 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -3571,7 +3571,7 @@ ssize_t nfs4_listxattr(struct dentry *dentry, char *buf, size_t buflen) } int nfs4_proc_fs_locations(struct inode *dir, struct dentry *dentry, - struct nfs_fs_locations *fs_locations, struct page *page) + struct nfs4_fs_locations *fs_locations, struct page *page) { struct nfs_server *server = NFS_SERVER(dir); u32 bitmask[2] = { @@ -3587,7 +3587,7 @@ int nfs4_proc_fs_locations(struct inode *dir, struct dentry *dentry, struct rpc_message msg = { .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FS_LOCATIONS], .rpc_argp = &args, - .rpc_resp = &fs_locations, + .rpc_resp = fs_locations, }; int status; diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 7add3137b6b60730451f933dd2b9a2af8a19cf54..f6a1ea7df3742196236c80812316303c08d1ce2b 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -2377,7 +2377,43 @@ static int decode_attr_files_total(struct xdr_stream *xdr, uint32_t *bitmap, uin return status; } -static int decode_attr_fs_locations(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs_fs_locations *res) +static int decode_pathname(struct xdr_stream *xdr, struct nfs4_pathname *path) +{ + int n; + uint32_t *p; + int status = 0; + + READ_BUF(4); + READ32(n); + if (n <= 0) + goto out_eio; + dprintk("path "); + path->ncomponents = 0; + while (path->ncomponents < n) { + struct nfs4_string *component = &path->components[path->ncomponents]; + status = decode_opaque_inline(xdr, &component->len, &component->data); + if (unlikely(status != 0)) + goto out_eio; + if (path->ncomponents != n) + dprintk("/"); + dprintk("%s", component->data); + if (path->ncomponents < NFS4_PATHNAME_MAXCOMPONENTS) + path->ncomponents++; + else { + dprintk("cannot parse %d components in path\n", n); + goto out_eio; + } + } +out: + dprintk("\n"); + return status; +out_eio: + dprintk(" status %d", status); + status = -EIO; + goto out; +} + +static int decode_attr_fs_locations(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs4_fs_locations *res) { int n; uint32_t *p; @@ -2388,7 +2424,8 @@ static int decode_attr_fs_locations(struct xdr_stream *xdr, uint32_t *bitmap, st status = 0; if (unlikely(!(bitmap[0] & FATTR4_WORD0_FS_LOCATIONS))) goto out; - status = decode_opaque_inline(xdr, &res->fs_pathlen, &res->fs_path); + dprintk("%s: fsroot ", __FUNCTION__); + status = decode_pathname(xdr, &res->fs_path); if (unlikely(status != 0)) goto out; READ_BUF(4); @@ -2397,15 +2434,40 @@ static int decode_attr_fs_locations(struct xdr_stream *xdr, uint32_t *bitmap, st goto out_eio; res->nlocations = 0; while (res->nlocations < n) { - struct nfs_fs_location *loc = &res->locations[res->nlocations]; + int m; + struct nfs4_fs_location *loc = &res->locations[res->nlocations]; - status = decode_opaque_inline(xdr, &loc->serverlen, &loc->server); - if (unlikely(status != 0)) + READ_BUF(4); + READ32(m); + if (m <= 0) goto out_eio; - status = decode_opaque_inline(xdr, &loc->rootpathlen, &loc->rootpath); + + loc->nservers = 0; + dprintk("%s: servers ", __FUNCTION__); + while (loc->nservers < m) { + struct nfs4_string *server = &loc->servers[loc->nservers]; + status = decode_opaque_inline(xdr, &server->len, &server->data); + if (unlikely(status != 0)) + goto out_eio; + dprintk("%s ", server->data); + if (loc->nservers < NFS4_FS_LOCATION_MAXSERVERS) + loc->nservers++; + else { + int i; + dprintk("%s: using first %d of %d servers returned for location %d\n", __FUNCTION__, NFS4_FS_LOCATION_MAXSERVERS, m, res->nlocations); + for (i = loc->nservers; i < m; i++) { + int len; + char *data; + status = decode_opaque_inline(xdr, &len, &data); + if (unlikely(status != 0)) + goto out_eio; + } + } + } + status = decode_pathname(xdr, &loc->rootpath); if (unlikely(status != 0)) goto out_eio; - if (res->nlocations < NFS_FS_LOCATIONS_MAXENTRIES) + if (res->nlocations < NFS4_FS_LOCATIONS_MAXENTRIES) res->nlocations++; } out: @@ -2948,7 +3010,7 @@ static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr, cons if ((status = decode_attr_fileid(xdr, bitmap, &fattr->fileid)) != 0) goto xdr_error; if ((status = decode_attr_fs_locations(xdr, bitmap, container_of(fattr, - struct nfs_fs_locations, + struct nfs4_fs_locations, fattr))) != 0) goto xdr_error; if ((status = decode_attr_mode(xdr, bitmap, &fattr->mode)) != 0) @@ -4297,7 +4359,7 @@ static int nfs4_xdr_dec_delegreturn(struct rpc_rqst *rqstp, uint32_t *p, struct /* * FS_LOCATIONS request */ -static int nfs4_xdr_dec_fs_locations(struct rpc_rqst *req, uint32_t *p, struct nfs_fs_locations *res) +static int nfs4_xdr_dec_fs_locations(struct rpc_rqst *req, uint32_t *p, struct nfs4_fs_locations *res) { struct xdr_stream xdr; struct compound_hdr hdr; diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index 15a20b8153027df535ae3a040249598294fe0914..d6eea834872862b13ce8cf536c991c202ef7924a 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -679,21 +679,31 @@ struct nfs4_server_caps_res { u32 has_symlinks; }; -struct nfs_fs_location { - unsigned int serverlen; - char * server; - unsigned int rootpathlen; - char * rootpath; +struct nfs4_string { + unsigned int len; + char *data; }; -#define NFS_FS_LOCATIONS_MAXENTRIES 10 -struct nfs_fs_locations { +#define NFS4_PATHNAME_MAXCOMPONENTS 512 +struct nfs4_pathname { + unsigned int ncomponents; + struct nfs4_string components[NFS4_PATHNAME_MAXCOMPONENTS]; +}; + +#define NFS4_FS_LOCATION_MAXSERVERS 10 +struct nfs4_fs_location { + unsigned int nservers; + struct nfs4_string servers[NFS4_FS_LOCATION_MAXSERVERS]; + struct nfs4_pathname rootpath; +}; + +#define NFS4_FS_LOCATIONS_MAXENTRIES 10 +struct nfs4_fs_locations { struct nfs_fattr fattr; const struct nfs_server *server; - unsigned int fs_pathlen; - char * fs_path; + struct nfs4_pathname fs_path; int nlocations; - struct nfs_fs_location locations[NFS_FS_LOCATIONS_MAXENTRIES]; + struct nfs4_fs_location locations[NFS4_FS_LOCATIONS_MAXENTRIES]; }; struct nfs4_fs_locations_arg {