nfsd4: remove unnecessary cl_verifier check from setclientid_confirm
[safe/jmp/linux-2.6] / fs / nfsd / nfs4state.c
index 03b0578..23b5fc7 100644 (file)
 #include <linux/nfsd/state.h>
 #include <linux/nfsd/xdr4.h>
 #include <linux/namei.h>
+#include <linux/swap.h>
 #include <linux/mutex.h>
+#include <linux/lockd/bind.h>
+#include <linux/module.h>
 
 #define NFSDDBG_FACILITY                NFSDDBG_PROC
 
@@ -148,6 +151,7 @@ get_nfs4_file(struct nfs4_file *fi)
 }
 
 static int num_delegations;
+unsigned int max_delegations;
 
 /*
  * Open owner state (share locks)
@@ -191,7 +195,9 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_f
        struct nfs4_callback *cb = &stp->st_stateowner->so_client->cl_callback;
 
        dprintk("NFSD alloc_init_deleg\n");
-       if (num_delegations > STATEID_HASH_SIZE * 4)
+       if (fp->fi_had_conflict)
+               return NULL;
+       if (num_delegations > max_delegations)
                return NULL;
        dp = kmem_cache_alloc(deleg_slab, GFP_KERNEL);
        if (dp == NULL)
@@ -250,7 +256,7 @@ nfs4_close_delegation(struct nfs4_delegation *dp)
        /* The following nfsd_close may not actually close the file,
         * but we want to remove the lease in any case. */
        if (dp->dl_flock)
-               setlease(filp, F_UNLCK, &dp->dl_flock);
+               vfs_setlease(filp, F_UNLCK, &dp->dl_flock);
        nfsd_close(filp);
 }
 
@@ -352,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);
@@ -369,19 +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);
-               rpciod_down();
-       }
-}
-
-static void
 expire_client(struct nfs4_client *clp)
 {
        struct nfs4_stateowner *sop;
@@ -391,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)) {
@@ -457,26 +461,28 @@ copy_cred(struct svc_cred *target, struct svc_cred *source) {
 }
 
 static inline int
-same_name(const char *n1, const char *n2) {
+same_name(const char *n1, const char *n2)
+{
        return 0 == memcmp(n1, n2, HEXDIR_LEN);
 }
 
 static int
-cmp_verf(nfs4_verifier *v1, nfs4_verifier *v2) {
-       return(!memcmp(v1->data,v2->data,sizeof(v1->data)));
+same_verf(nfs4_verifier *v1, nfs4_verifier *v2)
+{
+       return 0 == memcmp(v1->data, v2->data, sizeof(v1->data));
 }
 
 static int
-cmp_clid(clientid_t * cl1, clientid_t * cl2) {
-       return((cl1->cl_boot == cl2->cl_boot) &&
-               (cl1->cl_id == cl2->cl_id));
+same_clid(clientid_t *cl1, clientid_t *cl2)
+{
+       return (cl1->cl_boot == cl2->cl_boot) && (cl1->cl_id == cl2->cl_id);
 }
 
 /* XXX what about NGROUP */
 static int
-cmp_creds(struct svc_cred *cr1, struct svc_cred *cr2){
-       return(cr1->cr_uid == cr2->cr_uid);
-
+same_creds(struct svc_cred *cr1, struct svc_cred *cr2)
+{
+       return cr1->cr_uid == cr2->cr_uid;
 }
 
 static void
@@ -485,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
@@ -502,7 +507,7 @@ check_name(struct xdr_netobj name) {
        if (name.len == 0) 
                return 0;
        if (name.len > NFS4_OPAQUE_LIMIT) {
-               printk("NFSD: check_name: name too long(%d)!\n", name.len);
+               dprintk("NFSD: check_name: name too long(%d)!\n", name.len);
                return 0;
        }
        return 1;
@@ -541,7 +546,7 @@ find_confirmed_client(clientid_t *clid)
        unsigned int idhashval = clientid_hashval(clid->cl_id);
 
        list_for_each_entry(clp, &conf_id_hashtbl[idhashval], cl_idhash) {
-               if (cmp_clid(&clp->cl_clientid, clid))
+               if (same_clid(&clp->cl_clientid, clid))
                        return clp;
        }
        return NULL;
@@ -554,7 +559,7 @@ find_unconfirmed_client(clientid_t *clid)
        unsigned int idhashval = clientid_hashval(clid->cl_id);
 
        list_for_each_entry(clp, &unconf_id_hashtbl[idhashval], cl_idhash) {
-               if (cmp_clid(&clp->cl_clientid, clid))
+               if (same_clid(&clp->cl_clientid, clid))
                        return clp;
        }
        return NULL;
@@ -677,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)
@@ -742,51 +714,37 @@ 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 (!cmp_creds(&conf->cl_cred, &rqstp->rq_cred)
+               if (!same_creds(&conf->cl_cred, &rqstp->rq_cred)
                                || conf->cl_addr != sin->sin_addr.s_addr) {
                        dprintk("NFSD: setclientid: string in use by client"
                                "at %u.%u.%u.%u\n", NIPQUAD(conf->cl_addr));
                        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 (cmp_verf(&conf->cl_verifier, &clverifier)) {
+       } 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***},
@@ -799,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 (!cmp_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));
@@ -869,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,
@@ -904,17 +830,19 @@ 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) && 
-           (cmp_verf(&unconf->cl_confirm, &confirm)) &&
-           (cmp_verf(&conf->cl_verifier, &unconf->cl_verifier)) &&
-           (same_name(conf->cl_recdir,unconf->cl_recdir))  &&
-           (!cmp_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
-               */
-               if (!cmp_creds(&conf->cl_cred, &unconf->cl_cred)) 
+           (same_verf(&unconf->cl_confirm, &confirm)) &&
+           (!same_verf(&conf->cl_confirm, &unconf->cl_confirm))) {
+               /*
+                * RFC 3530 14.2.34 CASE 1:
+                * callback update
+                */
+               if (!same_creds(&conf->cl_cred, &unconf->cl_cred))
                        status = nfserr_clid_inuse;
                else {
                        /* XXX: We just turn off callbacks until we can handle
@@ -926,28 +854,23 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
                        status = nfs_ok;
 
                }
-       } else if ((conf && !unconf) ||
-           ((conf && unconf) && 
-            (!cmp_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 (!cmp_creds(&conf->cl_cred,&rqstp->rq_cred))
+               if (!same_creds(&conf->cl_cred, &rqstp->rq_cred))
                        status = nfserr_clid_inuse;
                else
                        status = nfs_ok;
        } else if (!conf && unconf
-                       && cmp_verf(&unconf->cl_confirm, &confirm)) {
-               /* CASE 3:
-                * conf record not found.
-                * unconf record found.
-                * unconf->cl_confirm matches input confirm
+                       && same_verf(&unconf->cl_confirm, &confirm)) {
+               /*
+                * RFC 3530 14.2.34 CASE 3:
+                * Normal case; new or rebooted client:
                 */
-               if (!cmp_creds(&unconf->cl_cred, &rqstp->rq_cred)) {
+               if (!same_creds(&unconf->cl_cred, &rqstp->rq_cred)) {
                        status = nfserr_clid_inuse;
                } else {
                        unsigned int hash =
@@ -960,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 && !cmp_verf(&conf->cl_confirm, &confirm)))
-           && (!unconf || (unconf && !cmp_verf(&unconf->cl_confirm,
+       } 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 {
@@ -977,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;
 }
@@ -999,6 +919,7 @@ alloc_init_file(struct inode *ino)
                list_add(&fp->fi_hash, &file_hashtbl[hashval]);
                fp->fi_inode = igrab(ino);
                fp->fi_id = current_fileid++;
+               fp->fi_had_conflict = false;
                return fp;
        }
        return NULL;
@@ -1013,7 +934,7 @@ nfsd4_free_slab(struct kmem_cache **slab)
        *slab = NULL;
 }
 
-static void
+void
 nfsd4_free_slabs(void)
 {
        nfsd4_free_slab(&stateowner_slab);
@@ -1026,19 +947,19 @@ static int
 nfsd4_init_slabs(void)
 {
        stateowner_slab = kmem_cache_create("nfsd4_stateowners",
-                       sizeof(struct nfs4_stateowner), 0, 0, NULL, NULL);
+                       sizeof(struct nfs4_stateowner), 0, 0, NULL);
        if (stateowner_slab == NULL)
                goto out_nomem;
        file_slab = kmem_cache_create("nfsd4_files",
-                       sizeof(struct nfs4_file), 0, 0, NULL, NULL);
+                       sizeof(struct nfs4_file), 0, 0, NULL);
        if (file_slab == NULL)
                goto out_nomem;
        stateid_slab = kmem_cache_create("nfsd4_stateids",
-                       sizeof(struct nfs4_stateid), 0, 0, NULL, NULL);
+                       sizeof(struct nfs4_stateid), 0, 0, NULL);
        if (stateid_slab == NULL)
                goto out_nomem;
        deleg_slab = kmem_cache_create("nfsd4_delegations",
-                       sizeof(struct nfs4_delegation), 0, 0, NULL, NULL);
+                       sizeof(struct nfs4_delegation), 0, 0, NULL);
        if (deleg_slab == NULL)
                goto out_nomem;
        return 0;
@@ -1201,10 +1122,12 @@ move_to_close_lru(struct nfs4_stateowner *sop)
 }
 
 static int
-cmp_owner_str(struct nfs4_stateowner *sop, struct xdr_netobj *owner, clientid_t *clid) {
-       return ((sop->so_owner.len == owner->len) && 
-        !memcmp(sop->so_owner.data, owner->data, owner->len) && 
-         (sop->so_client->cl_clientid.cl_id == clid->cl_id));
+same_owner_str(struct nfs4_stateowner *sop, struct xdr_netobj *owner,
+                                                       clientid_t *clid)
+{
+       return (sop->so_owner.len == owner->len) &&
+               0 == memcmp(sop->so_owner.data, owner->data, owner->len) &&
+               (sop->so_client->cl_clientid.cl_id == clid->cl_id);
 }
 
 static struct nfs4_stateowner *
@@ -1213,7 +1136,7 @@ find_openstateowner_str(unsigned int hashval, struct nfsd4_open *open)
        struct nfs4_stateowner *so = NULL;
 
        list_for_each_entry(so, &ownerstr_hashtbl[hashval], so_strhash) {
-               if (cmp_owner_str(so, &open->op_owner, &open->op_clientid))
+               if (same_owner_str(so, &open->op_owner, &open->op_clientid))
                        return so;
        }
        return NULL;
@@ -1325,8 +1248,7 @@ do_recall(void *__dp)
 {
        struct nfs4_delegation *dp = __dp;
 
-       daemonize("nfsv4-recall");
-
+       dp->dl_file->fi_had_conflict = true;
        nfsd4_cb_recall(dp);
        return 0;
 }
@@ -1355,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);
@@ -1363,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)) {
@@ -1373,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);
        }
 }
@@ -1397,7 +1325,7 @@ void nfsd_release_deleg_cb(struct file_lock *fl)
 /*
  * Set the delegation file_lock back pointer.
  *
- * Called from __setlease() with lock_kernel() held.
+ * Called from setlease() with lock_kernel() held.
  */
 static
 void nfsd_copy_lock_deleg_cb(struct file_lock *new, struct file_lock *fl)
@@ -1411,7 +1339,7 @@ void nfsd_copy_lock_deleg_cb(struct file_lock *new, struct file_lock *fl)
 }
 
 /*
- * Called from __setlease() with lock_kernel() held
+ * Called from setlease() with lock_kernel() held
  */
 static
 int nfsd_same_client_deleg_cb(struct file_lock *onlist, struct file_lock *try)
@@ -1711,10 +1639,10 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta
        fl.fl_file = stp->st_vfs_file;
        fl.fl_pid = current->tgid;
 
-       /* setlease checks to see if delegation should be handed out.
+       /* vfs_setlease checks to see if delegation should be handed out.
         * the lock_manager callbacks fl_mylease and fl_change are used
         */
-       if ((status = setlease(stp->st_vfs_file,
+       if ((status = vfs_setlease(stp->st_vfs_file,
                flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK, &flp))) {
                dprintk("NFSD: setlease failed [%d], no delegation\n", status);
                unhash_delegation(dp);
@@ -1733,7 +1661,7 @@ out:
        if (open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS
                        && flag == NFS4_OPEN_DELEGATE_NONE
                        && open->op_delegate_type != NFS4_OPEN_DELEGATE_NONE)
-               printk("NFSD: WARNING: refusing delegation reclaim\n");
+               dprintk("NFSD: WARNING: refusing delegation reclaim\n");
        open->op_delegate_type = flag;
 }
 
@@ -2039,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);
 }
 
 /*
@@ -2142,7 +2070,7 @@ nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *statei
        *sopp = NULL;
 
        if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) {
-               printk("NFSD: preprocess_seqid_op: magic stateid!\n");
+               dprintk("NFSD: preprocess_seqid_op: magic stateid!\n");
                return nfserr_bad_stateid;
        }
 
@@ -2176,25 +2104,24 @@ nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *statei
                lkflg = setlkflg(lock->lk_type);
 
                if (lock->lk_is_new) {
-                       if (!sop->so_is_open_owner)
-                              return nfserr_bad_stateid;
-                       if (!cmp_clid(&clp->cl_clientid, lockclid))
+                       if (!sop->so_is_open_owner)
+                               return nfserr_bad_stateid;
+                       if (!same_clid(&clp->cl_clientid, lockclid))
                               return nfserr_bad_stateid;
-                       /* stp is the open stateid */
-                       status = nfs4_check_openmode(stp, lkflg);
-                       if (status)
-                              return status;
-               } else {
-                       /* stp is the lock stateid */
-                       status = nfs4_check_openmode(stp->st_openstp, lkflg);
-                       if (status)
-                              return status;
+                       /* stp is the open stateid */
+                       status = nfs4_check_openmode(stp, lkflg);
+                       if (status)
+                               return status;
+               } else {
+                       /* stp is the lock stateid */
+                       status = nfs4_check_openmode(stp->st_openstp, lkflg);
+                       if (status)
+                               return status;
                }
-
        }
 
        if ((flags & CHECK_FH) && nfs4_check_fh(current_fh, stp)) {
-               printk("NFSD: preprocess_seqid_op: fh-stateid mismatch!\n");
+               dprintk("NFSD: preprocess_seqid_op: fh-stateid mismatch!\n");
                return nfserr_bad_stateid;
        }
 
@@ -2210,22 +2137,22 @@ nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *statei
                goto check_replay;
 
        if (sop->so_confirmed && flags & CONFIRM) {
-               printk("NFSD: preprocess_seqid_op: expected"
+               dprintk("NFSD: preprocess_seqid_op: expected"
                                " unconfirmed stateowner!\n");
                return nfserr_bad_stateid;
        }
        if (!sop->so_confirmed && !(flags & CONFIRM)) {
-               printk("NFSD: preprocess_seqid_op: stateowner not"
+               dprintk("NFSD: preprocess_seqid_op: stateowner not"
                                " confirmed yet!\n");
                return nfserr_bad_stateid;
        }
        if (stateid->si_generation > stp->st_stateid.si_generation) {
-               printk("NFSD: preprocess_seqid_op: future stateid?!\n");
+               dprintk("NFSD: preprocess_seqid_op: future stateid?!\n");
                return nfserr_bad_stateid;
        }
 
        if (stateid->si_generation < stp->st_stateid.si_generation) {
-               printk("NFSD: preprocess_seqid_op: old stateid!\n");
+               dprintk("NFSD: preprocess_seqid_op: old stateid!\n");
                return nfserr_old_stateid;
        }
        renew_client(sop->so_client);
@@ -2237,7 +2164,7 @@ check_replay:
                /* indicate replay to calling function */
                return nfserr_replay_me;
        }
-       printk("NFSD: preprocess_seqid_op: bad seqid (expected %d, got %d)\n",
+       dprintk("NFSD: preprocess_seqid_op: bad seqid (expected %d, got %d)\n",
                        sop->so_seqid, seqid);
        *sopp = NULL;
        return nfserr_bad_seqid;
@@ -2556,7 +2483,7 @@ find_lockstateowner_str(struct inode *inode, clientid_t *clid,
        struct nfs4_stateowner *op;
 
        list_for_each_entry(op, &lock_ownerstr_hashtbl[hashval], so_strhash) {
-               if (cmp_owner_str(op, owner, clid))
+               if (same_owner_str(op, owner, clid))
                        return op;
        }
        return NULL;
@@ -2773,7 +2700,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
        /* XXX?: Just to divert the locks_release_private at the start of
         * locks_copy_lock: */
        locks_init_lock(&conflock);
-       err = posix_lock_file(filp, &file_lock, &conflock);
+       err = vfs_lock_file(filp, cmd, &file_lock, &conflock);
        switch (-err) {
        case 0: /* success! */
                update_stateid(&lock_stp->st_stateid);
@@ -2790,7 +2717,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
                status = nfserr_deadlock;
                break;
        default:        
-               dprintk("NFSD: nfsd4_lock: posix_lock_file_conf() failed! status %d\n",err);
+               dprintk("NFSD: nfsd4_lock: vfs_lock_file() failed! status %d\n",err);
                status = nfserr_resource;
                break;
        }
@@ -2815,6 +2742,7 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
        struct inode *inode;
        struct file file;
        struct file_lock file_lock;
+       int error;
        __be32 status;
 
        if (nfs4_in_grace())
@@ -2849,7 +2777,7 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
                        file_lock.fl_type = F_WRLCK;
                break;
                default:
-                       printk("NFSD: nfs4_lockt: bad lock type!\n");
+                       dprintk("NFSD: nfs4_lockt: bad lock type!\n");
                        status = nfserr_inval;
                goto out;
        }
@@ -2870,16 +2798,20 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 
        nfs4_transform_lock_offset(&file_lock);
 
-       /* posix_test_lock uses the struct file _only_ to resolve the inode.
+       /* vfs_test_lock uses the struct file _only_ to resolve the inode.
         * since LOCKT doesn't require an OPEN, and therefore a struct
-        * file may not exist, pass posix_test_lock a struct file with
+        * file may not exist, pass vfs_test_lock a struct file with
         * only the dentry:inode set.
         */
        memset(&file, 0, sizeof (struct file));
        file.f_path.dentry = cstate->current_fh.fh_dentry;
 
        status = nfs_ok;
-       posix_test_lock(&file, &file_lock);
+       error = vfs_test_lock(&file, &file_lock);
+       if (error) {
+               status = nfserrno(error);
+               goto out;
+       }
        if (file_lock.fl_type != F_UNLCK) {
                status = nfserr_denied;
                nfs4_set_lock_denied(&file_lock, &lockt->lt_denied);
@@ -2935,9 +2867,9 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
        /*
        *  Try to unlock the file in the VFS.
        */
-       err = posix_lock_file(filp, &file_lock, NULL);
+       err = vfs_lock_file(filp, F_SETLK, &file_lock, NULL);
        if (err) {
-               dprintk("NFSD: nfs4_locku: posix_lock_file failed!\n");
+               dprintk("NFSD: nfs4_locku: vfs_lock_file failed!\n");
                goto out_nfserr;
        }
        /*
@@ -3015,7 +2947,7 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp,
        INIT_LIST_HEAD(&matches);
        for (i = 0; i < LOCK_HASH_SIZE; i++) {
                list_for_each_entry(sop, &lock_ownerid_hashtbl[i], so_idhash) {
-                       if (!cmp_owner_str(sop, owner, clid))
+                       if (!same_owner_str(sop, owner, clid))
                                continue;
                        list_for_each_entry(stp, &sop->so_stateids,
                                        st_perstateowner) {
@@ -3139,11 +3071,14 @@ nfs4_check_open_reclaim(clientid_t *clid)
 
 /* initialization to perform at module load time: */
 
-void
+int
 nfs4_state_init(void)
 {
-       int i;
+       int i, status;
 
+       status = nfsd4_init_slabs();
+       if (status)
+               return status;
        for (i = 0; i < CLIENT_HASH_SIZE; i++) {
                INIT_LIST_HEAD(&conf_id_hashtbl[i]);
                INIT_LIST_HEAD(&conf_str_hashtbl[i]);
@@ -3172,6 +3107,7 @@ nfs4_state_init(void)
        for (i = 0; i < CLIENT_HASH_SIZE; i++)
                INIT_LIST_HEAD(&reclaim_str_hashtbl[i]);
        reclaim_str_hashtbl_size = 0;
+       return 0;
 }
 
 static void
@@ -3187,36 +3123,60 @@ nfsd4_load_reboot_recovery_data(void)
                printk("NFSD: Failure reading reboot recovery data\n");
 }
 
+unsigned long
+get_nfs4_grace_period(void)
+{
+       return max(user_lease_time, lease_time) * HZ;
+}
+
+/*
+ * Since the lifetime of a delegation isn't limited to that of an open, a
+ * client may quite reasonably hang on to a delegation as long as it has
+ * the inode cached.  This becomes an obvious problem the first time a
+ * client's inode cache approaches the size of the server's total memory.
+ *
+ * For now we avoid this problem by imposing a hard limit on the number
+ * of delegations, which varies according to the server's memory size.
+ */
+static void
+set_max_delegations(void)
+{
+       /*
+        * Allow at most 4 delegations per megabyte of RAM.  Quick
+        * estimates suggest that in the worst case (where every delegation
+        * is for a different inode), a delegation could take about 1.5K,
+        * giving a worst case usage of about 6% of memory.
+        */
+       max_delegations = nr_free_buffer_pages() >> (20 - 2 - PAGE_SHIFT);
+}
+
 /* initialization to perform when the nfsd service is started: */
 
 static void
 __nfs4_state_start(void)
 {
-       time_t grace_time;
+       unsigned long grace_time;
 
        boot_time = get_seconds();
-       grace_time = max(user_lease_time, lease_time);
+       grace_time = get_nfs_grace_period();
        lease_time = user_lease_time;
        in_grace = 1;
-       printk("NFSD: starting %ld-second grace period\n", grace_time);
+       printk(KERN_INFO "NFSD: starting %ld-second grace period\n",
+              grace_time/HZ);
        laundry_wq = create_singlethread_workqueue("nfsd4");
-       queue_delayed_work(laundry_wq, &laundromat_work, grace_time*HZ);
+       queue_delayed_work(laundry_wq, &laundromat_work, grace_time);
+       set_max_delegations();
 }
 
-int
+void
 nfs4_state_start(void)
 {
-       int status;
-
        if (nfs4_init)
-               return 0;
-       status = nfsd4_init_slabs();
-       if (status)
-               return status;
+               return;
        nfsd4_load_reboot_recovery_data();
        __nfs4_state_start();
        nfs4_init = 1;
-       return 0;
+       return;
 }
 
 int
@@ -3274,7 +3234,6 @@ nfs4_state_shutdown(void)
        nfs4_lock_state();
        nfs4_release_reclaim();
        __nfs4_state_shutdown();
-       nfsd4_free_slabs();
        nfs4_unlock_state();
 }