]> git.neil.brown.name Git - history.git/commitdiff
The NFSv4 state model assumes that the client machine identifies
authorTrond Myklebust <trond.myklebust@fys.uio.no>
Tue, 7 Oct 2003 11:50:48 +0000 (07:50 -0400)
committerTrond Myklebust <trond.myklebust@fys.uio.no>
Tue, 7 Oct 2003 11:50:48 +0000 (07:50 -0400)
itself to the server once and once only.
This patch ensures that we do this by sharing the local identifier
struct nfs4_client among all mountpoints that talk to the same
server/ip address.

fs/nfs/nfs4proc.c
fs/nfs/nfs4state.c
include/linux/nfs_fs.h

index 31bb4b9650d4ad0bedca3a706b3f4534ffbe4bd7..cfb1908b84d34f3cfc50716f51c532e467907c61 100644 (file)
@@ -740,6 +740,7 @@ static int
 nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
                   struct nfs_fattr *fattr)
 {
+       struct nfs4_client      *clp;
        struct nfs4_compound    compound;
        struct nfs4_op          ops[4];
        struct nfs_fsinfo       fsinfo;
@@ -747,11 +748,24 @@ nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
        struct qstr             q;
        int                     status;
 
-       fattr->valid = 0;
-
-       if (!(server->nfs4_state = nfs4_get_client()))
+       clp = server->nfs4_state = nfs4_get_client(&server->addr.sin_addr);
+       if (!clp)
                return -ENOMEM;
 
+       down_write(&clp->cl_sem);
+       /* Has the clientid already been initialized? */
+       if (clp->cl_state != NFS4CLNT_NEW) {
+               /* Yep, so just read the root attributes and the lease time. */
+               fattr->valid = 0;
+               nfs4_setup_compound(&compound, ops, server, "getrootfh");
+               nfs4_setup_putrootfh(&compound);
+               nfs4_setup_getrootattr(&compound, fattr, &fsinfo);
+               nfs4_setup_getfh(&compound, fhandle);
+               if ((status = nfs4_call_compound(&compound, NULL, 0)))
+                       goto out_unlock;
+               goto no_setclientid;
+       }
+
        /* 
         * SETCLIENTID.
         * Until delegations are imported, we don't bother setting the program
@@ -760,28 +774,33 @@ nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
        nfs4_setup_compound(&compound, ops, server, "setclientid");
        nfs4_setup_setclientid(&compound, 0, 0);
        if ((status = nfs4_call_compound(&compound, NULL, 0)))
-               goto out;
+               goto out_unlock;
 
        /*
         * SETCLIENTID_CONFIRM, plus root filehandle.
         * We also get the lease time here.
         */
+       fattr->valid = 0;
        nfs4_setup_compound(&compound, ops, server, "setclientid_confirm");
        nfs4_setup_setclientid_confirm(&compound);
        nfs4_setup_putrootfh(&compound);
        nfs4_setup_getrootattr(&compound, fattr, &fsinfo);
        nfs4_setup_getfh(&compound, fhandle);
        if ((status = nfs4_call_compound(&compound, NULL, 0)))
-               goto out;
-       
+               goto out_unlock;
+       clp->cl_state = NFS4CLNT_OK;
+
+no_setclientid:
        /*
         * Now that we have instantiated the clientid and determined
         * the lease time, we can initialize the renew daemon for this
         * server.
+        * FIXME: we only need one renewd daemon per server.
         */
        server->lease_time = fsinfo.lease_time * HZ;
        if ((status = nfs4_init_renewd(server)))
-               goto out;
+               goto out_unlock;
+       up_write(&clp->cl_sem);
        
        /*
         * Now we do a separate LOOKUP for each component of the mount path.
@@ -799,6 +818,7 @@ nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
                        p++;
                q.len = p - q.name;
 
+               fattr->valid = 0;
                nfs4_setup_compound(&compound, ops, server, "mount");
                nfs4_setup_putfh(&compound, fhandle);
                nfs4_setup_lookup(&compound, &q);
@@ -813,8 +833,11 @@ nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
                }
                break;
        }
-
-out:
+       return status;
+out_unlock:
+       up_write(&clp->cl_sem);
+       nfs4_put_client(clp);
+       server->nfs4_state = NULL;
        return status;
 }
 
index 6249f8f010ee48a5716c04e043c1c5ac26c5899d..d1dac0c0a25c842241fb7c48455d03d75fe4f2fe 100644 (file)
@@ -51,6 +51,7 @@ nfs4_stateid zero_stateid =
 nfs4_stateid one_stateid =
        { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
 
+static LIST_HEAD(nfs4_clientid_list);
 
 /*
  * nfs4_get_client(): returns an empty client structure
@@ -60,22 +61,62 @@ nfs4_stateid one_stateid =
  * bother putting them in a slab cache...
  */
 struct nfs4_client *
-nfs4_get_client(void)
+nfs4_alloc_client(struct in_addr *addr)
 {
        struct nfs4_client *clp;
 
-       if ((clp = kmalloc(sizeof(*clp), GFP_KERNEL)))
+       if ((clp = kmalloc(sizeof(*clp), GFP_KERNEL))) {
                memset(clp, 0, sizeof(*clp));
+               memcpy(&clp->cl_addr, addr, sizeof(clp->cl_addr));
+               init_rwsem(&clp->cl_sem);
+               INIT_LIST_HEAD(&clp->cl_state_owners);
+               spin_lock_init(&clp->cl_lock);
+               atomic_set(&clp->cl_count, 1);
+               clp->cl_state = NFS4CLNT_NEW;
+       }
        return clp;
 }
 
 void
-nfs4_put_client(struct nfs4_client *clp)
+nfs4_free_client(struct nfs4_client *clp)
 {
        BUG_ON(!clp);
        kfree(clp);
 }
 
+struct nfs4_client *
+nfs4_get_client(struct in_addr *addr)
+{
+       struct nfs4_client *new, *clp = NULL;
+
+       new = nfs4_alloc_client(addr);
+       spin_lock(&state_spinlock);
+       list_for_each_entry(clp, &nfs4_clientid_list, cl_servers) {
+               if (memcmp(&clp->cl_addr, addr, sizeof(clp->cl_addr)) == 0)
+                       goto found;
+       }
+       if (new)
+               list_add(&new->cl_servers, &nfs4_clientid_list);
+       spin_unlock(&state_spinlock);
+       return new;
+found:
+       atomic_inc(&clp->cl_count);
+       spin_unlock(&state_spinlock);
+       if (new)
+               nfs4_free_client(new);
+       return clp;
+}
+
+void
+nfs4_put_client(struct nfs4_client *clp)
+{
+       if (!atomic_dec_and_lock(&clp->cl_count, &state_spinlock))
+               return;
+       list_del(&clp->cl_servers);
+       spin_unlock(&state_spinlock);
+       nfs4_free_client(clp);
+}
+
 static inline u32
 nfs4_alloc_lockowner_id(struct nfs4_client *clp)
 {
index e7aa4552b0a6be18a6791abadc62ff838bfe43f7..f57c6df50785d68db91483129cd293df2a8937b9 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/in.h>
 #include <linux/mm.h>
 #include <linux/pagemap.h>
+#include <linux/rwsem.h>
 #include <linux/wait.h>
 #include <linux/uio.h>
 
@@ -469,11 +470,32 @@ extern void * nfs_root_data(void);
  ((err) != NFSERR_RESOURCE)       &&  \
  ((err) != NFSERR_NOFILEHANDLE))
 
+enum nfs4_client_state {
+       NFS4CLNT_OK  = 0,
+       NFS4CLNT_NEW,
+};
+
+/*
+ * The nfs4_client identifies our client state to the server.
+ */
 struct nfs4_client {
-        u64                     cl_clientid;    /* constant */
-       nfs4_verifier           cl_confirm;     
+       struct list_head        cl_servers;     /* Global list of servers */
+       struct in_addr          cl_addr;        /* Server identifier */
+       u64                     cl_clientid;    /* constant */
+       nfs4_verifier           cl_confirm;
+       enum nfs4_client_state  cl_state;
 
        u32                     cl_lockowner_id;
+
+       /*
+        * The following rwsem ensures exclusive access to the server
+        * while we recover the state following a lease expiration.
+        */
+       struct rw_semaphore     cl_sem;
+
+       struct list_head        cl_state_owners;
+       spinlock_t              cl_lock;
+       atomic_t                cl_count;
 };
 
 /*
@@ -483,6 +505,7 @@ struct nfs4_client {
 * the protocol.
 */
 struct nfs4_state_owner {
+       struct list_head     so_list;    /* per-clientid list of state_owners */
        u32                  so_id;      /* 32-bit identifier, unique */
        struct semaphore     so_sema;
        u32                  so_seqid;   /* protected by so_sema */
@@ -499,7 +522,7 @@ extern int nfs4_do_close(struct inode *inode, struct nfs4_state_owner *sp);
 extern int nfs4_init_renewd(struct nfs_server *server);
 
 /* nfs4state.c */
-extern struct nfs4_client *nfs4_get_client(void);
+extern struct nfs4_client *nfs4_get_client(struct in_addr *);
 extern void nfs4_put_client(struct nfs4_client *clp);
 extern struct nfs4_state_owner * nfs4_get_state_owner(struct inode *inode);
 void nfs4_put_state_owner(struct inode *inode, struct nfs4_state_owner *sp);