NFSv4: Implement the fs_locations function call
authorTrond Myklebust <Trond.Myklebust@netapp.com>
Fri, 9 Jun 2006 13:34:22 +0000 (09:34 -0400)
committerTrond Myklebust <Trond.Myklebust@netapp.com>
Fri, 9 Jun 2006 13:34:22 +0000 (09:34 -0400)
NFSv4 allows for the fact that filesystems may be replicated across
several servers or that they may be migrated to a backup server in case of
failure of the primary server.
fs_locations is an NFSv4 operation for retrieving information about the
location of migrated and/or replicated filesystems.

Based on an initial implementation by Jiaying Zhang <jiayingz@citi.umich.edu>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
fs/nfs/nfs4_fs.h
fs/nfs/nfs4proc.c
fs/nfs/nfs4xdr.c
include/linux/nfs4.h
include/linux/nfs_xdr.h

index 307832fd1a49e0056756d836c2b36e7971de8f6b..5b7651171215d37a0f7c5e3d0d4a76534174f99a 100644 (file)
@@ -218,6 +218,8 @@ extern int nfs4_do_close(struct inode *inode, struct nfs4_state *state);
 extern struct dentry *nfs4_atomic_open(struct inode *, struct dentry *, struct nameidata *);
 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);
 
 extern struct nfs4_state_recovery_ops nfs4_reboot_recovery_ops;
 extern struct nfs4_state_recovery_ops nfs4_network_partition_recovery_ops;
index 308407205e6c2f8d09b0b38c3d9ec040ec21441b..768514dc0c4c56ff30669bb0abb04688102eb347 100644 (file)
@@ -3570,6 +3570,35 @@ ssize_t nfs4_listxattr(struct dentry *dentry, char *buf, size_t buflen)
        return len;
 }
 
+int nfs4_proc_fs_locations(struct inode *dir, struct dentry *dentry,
+               struct nfs_fs_locations *fs_locations, struct page *page)
+{
+       struct nfs_server *server = NFS_SERVER(dir);
+       u32 bitmask[2] = {
+               [0] = server->attr_bitmask[0] | FATTR4_WORD0_FS_LOCATIONS,
+               [1] = server->attr_bitmask[1],
+       };
+       struct nfs4_fs_locations_arg args = {
+               .dir_fh = NFS_FH(dir),
+               .name = &dentry->d_name,
+               .page = page,
+               .bitmask = bitmask,
+       };
+       struct rpc_message msg = {
+               .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FS_LOCATIONS],
+               .rpc_argp = &args,
+               .rpc_resp = &fs_locations,
+       };
+       int status;
+
+       dprintk("%s: start\n", __FUNCTION__);
+       fs_locations->fattr.valid = 0;
+       fs_locations->server = server;
+       status = rpc_call_sync(server->client, &msg, 0);
+       dprintk("%s: returned status = %d\n", __FUNCTION__, status);
+       return status;
+}
+
 struct nfs4_state_recovery_ops nfs4_reboot_recovery_ops = {
        .recover_open   = nfs4_open_reclaim,
        .recover_lock   = nfs4_lock_reclaim,
index 0d5794675944942683d0c2ecefce08489126dd3e..7add3137b6b60730451f933dd2b9a2af8a19cf54 100644 (file)
@@ -411,6 +411,15 @@ static int nfs_stat_to_errno(int);
 #define NFS4_dec_setacl_sz     (compound_decode_hdr_maxsz + \
                                decode_putfh_maxsz + \
                                op_decode_hdr_maxsz + nfs4_fattr_bitmap_maxsz)
+#define NFS4_enc_fs_locations_sz \
+                               (compound_encode_hdr_maxsz + \
+                                encode_putfh_maxsz + \
+                                encode_getattr_maxsz)
+#define NFS4_dec_fs_locations_sz \
+                               (compound_decode_hdr_maxsz + \
+                                decode_putfh_maxsz + \
+                                op_decode_hdr_maxsz + \
+                                nfs4_fattr_bitmap_maxsz)
 
 static struct {
        unsigned int    mode;
@@ -2002,6 +2011,38 @@ out:
        return status;
 }
 
+/*
+ * Encode FS_LOCATIONS request
+ */
+static int nfs4_xdr_enc_fs_locations(struct rpc_rqst *req, uint32_t *p, struct nfs4_fs_locations_arg *args)
+{
+       struct xdr_stream xdr;
+       struct compound_hdr hdr = {
+               .nops = 3,
+       };
+       struct rpc_auth *auth = req->rq_task->tk_auth;
+       int replen;
+       int status;
+
+       xdr_init_encode(&xdr, &req->rq_snd_buf, p);
+       encode_compound_hdr(&xdr, &hdr);
+       if ((status = encode_putfh(&xdr, args->dir_fh)) != 0)
+               goto out;
+       if ((status = encode_lookup(&xdr, args->name)) != 0)
+               goto out;
+       if ((status = encode_getfattr(&xdr, args->bitmask)) != 0)
+               goto out;
+       /* set up reply
+        *   toplevel_status + taglen + rescount + OP_PUTFH + status
+        *   + OP_LOOKUP + status + OP_GETATTR + status = 7
+        */
+       replen = (RPC_REPHDRSIZE + auth->au_rslack + 7) << 2;
+       xdr_inline_pages(&req->rq_rcv_buf, replen, &args->page,
+                       0, PAGE_SIZE);
+out:
+       return status;
+}
+
 /*
  * START OF "GENERIC" DECODE ROUTINES.
  *   These may look a little ugly since they are imported from a "generic"
@@ -2036,7 +2077,7 @@ out:
        } \
 } while (0)
 
-static int decode_opaque_inline(struct xdr_stream *xdr, uint32_t *len, char **string)
+static int decode_opaque_inline(struct xdr_stream *xdr, unsigned int *len, char **string)
 {
        uint32_t *p;
 
@@ -2087,7 +2128,7 @@ static int decode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected)
 static int decode_ace(struct xdr_stream *xdr, void *ace, struct nfs4_client *clp)
 {
        uint32_t *p;
-       uint32_t strlen;
+       unsigned int strlen;
        char *str;
 
        READ_BUF(12);
@@ -2336,6 +2377,45 @@ 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)
+{
+       int n;
+       uint32_t *p;
+       int status = -EIO;
+
+       if (unlikely(bitmap[0] & (FATTR4_WORD0_FS_LOCATIONS -1U)))
+               goto out;
+       status = 0;
+       if (unlikely(!(bitmap[0] & FATTR4_WORD0_FS_LOCATIONS)))
+               goto out;
+       status = decode_opaque_inline(xdr, &res->fs_pathlen, &res->fs_path);
+       if (unlikely(status != 0))
+               goto out;
+       READ_BUF(4);
+       READ32(n);
+       if (n <= 0)
+               goto out_eio;
+       res->nlocations = 0;
+       while (res->nlocations < n) {
+               struct nfs_fs_location *loc = &res->locations[res->nlocations];
+
+               status = decode_opaque_inline(xdr, &loc->serverlen, &loc->server);
+               if (unlikely(status != 0))
+                       goto out_eio;
+               status = decode_opaque_inline(xdr, &loc->rootpathlen, &loc->rootpath);
+               if (unlikely(status != 0))
+                       goto out_eio;
+               if (res->nlocations < NFS_FS_LOCATIONS_MAXENTRIES)
+                       res->nlocations++;
+       }
+out:
+       dprintk("%s: fs_locations done, error = %d\n", __FUNCTION__, status);
+       return status;
+out_eio:
+       status = -EIO;
+       goto out;
+}
+
 static int decode_attr_maxfilesize(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
 {
        uint32_t *p;
@@ -2867,6 +2947,10 @@ static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr, cons
                goto xdr_error;
        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,
+                                               fattr))) != 0)
+               goto xdr_error;
        if ((status = decode_attr_mode(xdr, bitmap, &fattr->mode)) != 0)
                goto xdr_error;
        fattr->mode |= fmode;
@@ -4210,6 +4294,29 @@ out:
        return status;
 }
 
+/*
+ * FS_LOCATIONS request
+ */
+static int nfs4_xdr_dec_fs_locations(struct rpc_rqst *req, uint32_t *p, struct nfs_fs_locations *res)
+{
+       struct xdr_stream xdr;
+       struct compound_hdr hdr;
+       int status;
+
+       xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
+       status = decode_compound_hdr(&xdr, &hdr);
+       if (status != 0)
+               goto out;
+       if ((status = decode_putfh(&xdr)) != 0)
+               goto out;
+       if ((status = decode_lookup(&xdr)) != 0)
+               goto out;
+       xdr_enter_page(&xdr, PAGE_SIZE);
+       status = decode_getfattr(&xdr, &res->fattr, res->server);
+out:
+       return status;
+}
+
 uint32_t *nfs4_decode_dirent(uint32_t *p, struct nfs_entry *entry, int plus)
 {
        uint32_t bitmap[2] = {0};
@@ -4381,6 +4488,7 @@ struct rpc_procinfo       nfs4_procedures[] = {
   PROC(DELEGRETURN,    enc_delegreturn, dec_delegreturn),
   PROC(GETACL,         enc_getacl,     dec_getacl),
   PROC(SETACL,         enc_setacl,     dec_setacl),
+  PROC(FS_LOCATIONS,   enc_fs_locations, dec_fs_locations),
 };
 
 struct rpc_version             nfs_version4 = {
index 0c1c306cdaec7e77749319f68978e8785d2486dd..1477fc857f6b78b3aadee9ecd1712f9ca8633a05 100644 (file)
@@ -384,6 +384,7 @@ enum {
        NFSPROC4_CLNT_DELEGRETURN,
        NFSPROC4_CLNT_GETACL,
        NFSPROC4_CLNT_SETACL,
+       NFSPROC4_CLNT_FS_LOCATIONS,
 };
 
 #endif
index 95682f7d738a0ffbd5195fa12a9c237d098f56af..15a20b8153027df535ae3a040249598294fe0914 100644 (file)
@@ -679,6 +679,30 @@ struct nfs4_server_caps_res {
        u32                             has_symlinks;
 };
 
+struct nfs_fs_location {
+       unsigned int serverlen;
+       char * server;
+       unsigned int rootpathlen;
+       char * rootpath;
+};
+
+#define NFS_FS_LOCATIONS_MAXENTRIES 10
+struct nfs_fs_locations {
+       struct nfs_fattr fattr;
+       const struct nfs_server *server;
+       unsigned int fs_pathlen;
+       char * fs_path;
+       int nlocations;
+       struct nfs_fs_location locations[NFS_FS_LOCATIONS_MAXENTRIES];
+};
+
+struct nfs4_fs_locations_arg {
+       const struct nfs_fh *dir_fh;
+       const struct qstr *name;
+       struct page *page;
+       const u32 *bitmask;
+};
+
 #endif /* CONFIG_NFS_V4 */
 
 struct nfs_page;