nfsd4: remove unnecessary cl_verifier check from setclientid_confirm
[safe/jmp/linux-2.6] / fs / nfsd / nfs4state.c
index 09573b9..23b5fc7 100644 (file)
@@ -358,9 +358,22 @@ alloc_client(struct xdr_netobj name)
        return clp;
 }
 
+static void
+shutdown_callback_client(struct nfs4_client *clp)
+{
+       struct rpc_clnt *clnt = clp->cl_callback.cb_client;
+
+       /* shutdown rpc client, ending any outstanding recall rpcs */
+       if (clnt) {
+               clp->cl_callback.cb_client = NULL;
+               rpc_shutdown_client(clnt);
+       }
+}
+
 static inline void
 free_client(struct nfs4_client *clp)
 {
+       shutdown_callback_client(clp);
        if (clp->cl_cred.cr_group_info)
                put_group_info(clp->cl_cred.cr_group_info);
        kfree(clp->cl_name.data);
@@ -375,18 +388,6 @@ put_nfs4_client(struct nfs4_client *clp)
 }
 
 static void
-shutdown_callback_client(struct nfs4_client *clp)
-{
-       struct rpc_clnt *clnt = clp->cl_callback.cb_client;
-
-       /* shutdown rpc client, ending any outstanding recall rpcs */
-       if (clnt) {
-               clp->cl_callback.cb_client = NULL;
-               rpc_shutdown_client(clnt);
-       }
-}
-
-static void
 expire_client(struct nfs4_client *clp)
 {
        struct nfs4_stateowner *sop;
@@ -396,8 +397,6 @@ expire_client(struct nfs4_client *clp)
        dprintk("NFSD: expire_client cl_count %d\n",
                            atomic_read(&clp->cl_count));
 
-       shutdown_callback_client(clp);
-
        INIT_LIST_HEAD(&reaplist);
        spin_lock(&recall_lock);
        while (!list_empty(&clp->cl_delegations)) {
@@ -492,15 +491,14 @@ gen_clid(struct nfs4_client *clp) {
        clp->cl_clientid.cl_id = current_clientid++; 
 }
 
-static void
-gen_confirm(struct nfs4_client *clp) {
-       struct timespec         tv;
-       u32 *                   p;
+static void gen_confirm(struct nfs4_client *clp)
+{
+       static u32 i;
+       u32 *p;
 
-       tv = CURRENT_TIME;
        p = (u32 *)clp->cl_confirm.data;
-       *p++ = tv.tv_sec;
-       *p++ = tv.tv_nsec;
+       *p++ = get_seconds();
+       *p++ = i++;
 }
 
 static int
@@ -684,39 +682,6 @@ out_err:
        return;
 }
 
-/*
- * RFC 3010 has a complex implmentation description of processing a 
- * SETCLIENTID request consisting of 5 bullets, labeled as 
- * CASE0 - CASE4 below.
- *
- * NOTES:
- *     callback information will be processed in a future patch
- *
- *     an unconfirmed record is added when:
- *      NORMAL (part of CASE 4): there is no confirmed nor unconfirmed record.
- *     CASE 1: confirmed record found with matching name, principal,
- *             verifier, and clientid.
- *     CASE 2: confirmed record found with matching name, principal,
- *             and there is no unconfirmed record with matching
- *             name and principal
- *
- *      an unconfirmed record is replaced when:
- *     CASE 3: confirmed record found with matching name, principal,
- *             and an unconfirmed record is found with matching 
- *             name, principal, and with clientid and
- *             confirm that does not match the confirmed record.
- *     CASE 4: there is no confirmed record with matching name and 
- *             principal. there is an unconfirmed record with 
- *             matching name, principal.
- *
- *     an unconfirmed record is deleted when:
- *     CASE 1: an unconfirmed record that matches input name, verifier,
- *             and confirmed clientid.
- *     CASE 4: any unconfirmed records with matching name and principal
- *             that exist after an unconfirmed record has been replaced
- *             as described above.
- *
- */
 __be32
 nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
                  struct nfsd4_setclientid *setclid)
@@ -749,11 +714,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
        nfs4_lock_state();
        conf = find_confirmed_client_by_str(dname, strhashval);
        if (conf) {
-               /* 
-                * CASE 0:
-                * clname match, confirmed, different principal
-                * or different ip_address
-                */
+               /* RFC 3530 14.2.33 CASE 0: */
                status = nfserr_clid_inuse;
                if (!same_creds(&conf->cl_cred, &rqstp->rq_cred)
                                || conf->cl_addr != sin->sin_addr.s_addr) {
@@ -762,38 +723,28 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
                        goto out;
                }
        }
+       /*
+        * section 14.2.33 of RFC 3530 (under the heading "IMPLEMENTATION")
+        * has a description of SETCLIENTID request processing consisting
+        * of 5 bullet points, labeled as CASE0 - CASE4 below.
+        */
        unconf = find_unconfirmed_client_by_str(dname, strhashval);
        status = nfserr_resource;
        if (!conf) {
-               /* 
-                * CASE 4:
-                * placed first, because it is the normal case.
+               /*
+                * RFC 3530 14.2.33 CASE 4:
+                * placed first, because it is the normal case
                 */
                if (unconf)
                        expire_client(unconf);
                new = create_client(clname, dname);
                if (new == NULL)
                        goto out;
-               copy_verf(new, &clverifier);
-               new->cl_addr = sin->sin_addr.s_addr;
-               copy_cred(&new->cl_cred,&rqstp->rq_cred);
                gen_clid(new);
-               gen_confirm(new);
-               gen_callback(new, setclid);
-               add_to_unconfirmed(new, strhashval);
        } else if (same_verf(&conf->cl_verifier, &clverifier)) {
                /*
-                * CASE 1:
-                * cl_name match, confirmed, principal match
-                * verifier match: probable callback update
-                *
-                * remove any unconfirmed nfs4_client with 
-                * matching cl_name, cl_verifier, and cl_clientid
-                *
-                * create and insert an unconfirmed nfs4_client with same 
-                * cl_name, cl_verifier, and cl_clientid as existing 
-                * nfs4_client,  but with the new callback info and a 
-                * new cl_confirm
+                * RFC 3530 14.2.33 CASE 1:
+                * probable callback update
                 */
                if (unconf) {
                        /* Note this is removing unconfirmed {*x***},
@@ -806,65 +757,35 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
                new = create_client(clname, dname);
                if (new == NULL)
                        goto out;
-               copy_verf(new,&conf->cl_verifier);
-               new->cl_addr = sin->sin_addr.s_addr;
-               copy_cred(&new->cl_cred,&rqstp->rq_cred);
                copy_clid(new, conf);
-               gen_confirm(new);
-               gen_callback(new, setclid);
-               add_to_unconfirmed(new,strhashval);
        } else if (!unconf) {
                /*
-                * CASE 2:
-                * clname match, confirmed, principal match
-                * verfier does not match
-                * no unconfirmed. create a new unconfirmed nfs4_client
-                * using input clverifier, clname, and callback info
-                * and generate a new cl_clientid and cl_confirm.
+                * RFC 3530 14.2.33 CASE 2:
+                * probable client reboot; state will be removed if
+                * confirmed.
                 */
                new = create_client(clname, dname);
                if (new == NULL)
                        goto out;
-               copy_verf(new,&clverifier);
-               new->cl_addr = sin->sin_addr.s_addr;
-               copy_cred(&new->cl_cred,&rqstp->rq_cred);
                gen_clid(new);
-               gen_confirm(new);
-               gen_callback(new, setclid);
-               add_to_unconfirmed(new, strhashval);
-       } else if (!same_verf(&conf->cl_confirm, &unconf->cl_confirm)) {
-               /*      
-                * CASE3:
-                * confirmed found (name, principal match)
-                * confirmed verifier does not match input clverifier
-                *
-                * unconfirmed found (name match)
-                * confirmed->cl_confirm != unconfirmed->cl_confirm
-                *
-                * remove unconfirmed.
-                *
-                * create an unconfirmed nfs4_client 
-                * with same cl_name as existing confirmed nfs4_client, 
-                * but with new callback info, new cl_clientid,
-                * new cl_verifier and a new cl_confirm
+       } else {
+               /*
+                * RFC 3530 14.2.33 CASE 3:
+                * probable client reboot; state will be removed if
+                * confirmed.
                 */
                expire_client(unconf);
                new = create_client(clname, dname);
                if (new == NULL)
                        goto out;
-               copy_verf(new,&clverifier);
-               new->cl_addr = sin->sin_addr.s_addr;
-               copy_cred(&new->cl_cred,&rqstp->rq_cred);
                gen_clid(new);
-               gen_confirm(new);
-               gen_callback(new, setclid);
-               add_to_unconfirmed(new, strhashval);
-       } else {
-               /* No cases hit !!! */
-               status = nfserr_inval;
-               goto out;
-
        }
+       copy_verf(new, &clverifier);
+       new->cl_addr = sin->sin_addr.s_addr;
+       copy_cred(&new->cl_cred, &rqstp->rq_cred);
+       gen_confirm(new);
+       gen_callback(new, setclid);
+       add_to_unconfirmed(new, strhashval);
        setclid->se_clientid.cl_boot = new->cl_clientid.cl_boot;
        setclid->se_clientid.cl_id = new->cl_clientid.cl_id;
        memcpy(setclid->se_confirm.data, new->cl_confirm.data, sizeof(setclid->se_confirm.data));
@@ -876,11 +797,9 @@ out:
 
 
 /*
- * RFC 3010 has a complex implmentation description of processing a 
- * SETCLIENTID_CONFIRM request consisting of 4 bullets describing
- * processing on a DRC miss, labeled as CASE1 - CASE4 below.
- *
- * NOTE: callback information will be processed here in a future patch
+ * Section 14.2.34 of RFC 3530 (under the heading "IMPLEMENTATION") has
+ * a description of SETCLIENTID_CONFIRM request processing consisting of 4
+ * bullets, labeled as CASE1 - CASE4 below.
  */
 __be32
 nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
@@ -911,16 +830,18 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
        if (unconf && unconf->cl_addr != sin->sin_addr.s_addr)
                goto out;
 
+       /*
+        * section 14.2.34 of RFC 3530 has a description of
+        * SETCLIENTID_CONFIRM request processing consisting
+        * of 4 bullet points, labeled as CASE1 - CASE4 below.
+        */
        if ((conf && unconf) && 
            (same_verf(&unconf->cl_confirm, &confirm)) &&
-           (same_verf(&conf->cl_verifier, &unconf->cl_verifier)) &&
-           (same_name(conf->cl_recdir,unconf->cl_recdir))  &&
            (!same_verf(&conf->cl_confirm, &unconf->cl_confirm))) {
-               /* CASE 1:
-               * unconf record that matches input clientid and input confirm.
-               * conf record that matches input clientid.
-               * conf and unconf records match names, verifiers
-               */
+               /*
+                * RFC 3530 14.2.34 CASE 1:
+                * callback update
+                */
                if (!same_creds(&conf->cl_cred, &unconf->cl_cred))
                        status = nfserr_clid_inuse;
                else {
@@ -933,15 +854,11 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
                        status = nfs_ok;
 
                }
-       } else if ((conf && !unconf) ||
-           ((conf && unconf) && 
-            (!same_verf(&conf->cl_verifier, &unconf->cl_verifier) ||
-             !same_name(conf->cl_recdir, unconf->cl_recdir)))) {
-               /* CASE 2:
-                * conf record that matches input clientid.
-                * if unconf record matches input clientid, then
-                * unconf->cl_name or unconf->cl_verifier don't match the
-                * conf record.
+       } else if (conf && !unconf) {
+               /*
+                * RFC 3530 14.2.34 CASE 2:
+                * probable retransmitted request; play it safe and
+                * do nothing.
                 */
                if (!same_creds(&conf->cl_cred, &rqstp->rq_cred))
                        status = nfserr_clid_inuse;
@@ -949,10 +866,9 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
                        status = nfs_ok;
        } else if (!conf && unconf
                        && same_verf(&unconf->cl_confirm, &confirm)) {
-               /* CASE 3:
-                * conf record not found.
-                * unconf record found.
-                * unconf->cl_confirm matches input confirm
+               /*
+                * RFC 3530 14.2.34 CASE 3:
+                * Normal case; new or rebooted client:
                 */
                if (!same_creds(&unconf->cl_cred, &rqstp->rq_cred)) {
                        status = nfserr_clid_inuse;
@@ -967,16 +883,15 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
                        }
                        move_to_confirmed(unconf);
                        conf = unconf;
+                       nfsd4_probe_callback(conf);
                        status = nfs_ok;
                }
        } else if ((!conf || (conf && !same_verf(&conf->cl_confirm, &confirm)))
            && (!unconf || (unconf && !same_verf(&unconf->cl_confirm,
                                                                &confirm)))) {
-               /* CASE 4:
-                * conf record not found, or if conf, conf->cl_confirm does not
-                * match input confirm.
-                * unconf record not found, or if unconf, unconf->cl_confirm
-                * does not match input confirm.
+               /*
+                * RFC 3530 14.2.34 CASE 4:
+                * Client probably hasn't noticed that we rebooted yet.
                 */
                status = nfserr_stale_clientid;
        } else {
@@ -984,8 +899,6 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
                status = nfserr_clid_inuse;
        }
 out:
-       if (!status)
-               nfsd4_probe_callback(conf);
        nfs4_unlock_state();
        return status;
 }
@@ -1364,6 +1277,7 @@ void nfsd_break_deleg_cb(struct file_lock *fl)
         * lock) we know the server hasn't removed the lease yet, we know
         * it's safe to take a reference: */
        atomic_inc(&dp->dl_count);
+       atomic_inc(&dp->dl_client->cl_count);
 
        spin_lock(&recall_lock);
        list_add_tail(&dp->dl_recall_lru, &del_recall_lru);
@@ -1372,8 +1286,12 @@ void nfsd_break_deleg_cb(struct file_lock *fl)
        /* only place dl_time is set. protected by lock_kernel*/
        dp->dl_time = get_seconds();
 
-       /* XXX need to merge NFSD_LEASE_TIME with fs/locks.c:lease_break_time */
-       fl->fl_break_time = jiffies + NFSD_LEASE_TIME * HZ;
+       /*
+        * We don't want the locks code to timeout the lease for us;
+        * we'll remove it ourself if the delegation isn't returned
+        * in time.
+        */
+       fl->fl_break_time = 0;
 
        t = kthread_run(do_recall, dp, "%s", "nfs4_cb_recall");
        if (IS_ERR(t)) {
@@ -1382,6 +1300,7 @@ void nfsd_break_deleg_cb(struct file_lock *fl)
                printk(KERN_INFO "NFSD: Callback thread failed for "
                        "for client (clientid %08x/%08x)\n",
                        clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id);
+               put_nfs4_client(dp->dl_client);
                nfs4_put_delegation(dp);
        }
 }
@@ -2048,7 +1967,7 @@ static inline int
 io_during_grace_disallowed(struct inode *inode, int flags)
 {
        return nfs4_in_grace() && (flags & (RD_STATE | WR_STATE))
-               && MANDATORY_LOCK(inode);
+               && mandatory_lock(inode);
 }
 
 /*