summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/nfs/nfs4_fs.h2
-rw-r--r--fs/nfs/nfs4proc.c4
-rw-r--r--fs/nfs/nfs4xdr.c80
-rw-r--r--include/linux/nfs_xdr.h30
4 files changed, 94 insertions, 22 deletions
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h
index 5b765117121..22a5f838ea5 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 768514dc0c4..043223a0eda 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 7add3137b6b..f6a1ea7df37 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 @@ out:
/*
* 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 15a20b81530..d6eea834872 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 {