Merge tag 'nfsd-5.2' of git://linux-nfs.org/~bfields/linux
[platform/kernel/linux-starfive.git] / fs / nfsd / nfs4state.c
index eca4a23..618e660 100644 (file)
@@ -77,6 +77,7 @@ static u64 current_sessionid = 1;
 /* forward declarations */
 static bool check_for_locks(struct nfs4_file *fp, struct nfs4_lockowner *lowner);
 static void nfs4_free_ol_stateid(struct nfs4_stid *stid);
+void nfsd4_end_grace(struct nfsd_net *nn);
 
 /* Locking: */
 
@@ -1067,9 +1068,9 @@ static unsigned int clientid_hashval(u32 id)
        return id & CLIENT_HASH_MASK;
 }
 
-static unsigned int clientstr_hashval(const char *name)
+static unsigned int clientstr_hashval(struct xdr_netobj name)
 {
-       return opaque_hashval(name, 8) & CLIENT_HASH_MASK;
+       return opaque_hashval(name.data, 8) & CLIENT_HASH_MASK;
 }
 
 /*
@@ -1997,6 +1998,22 @@ destroy_client(struct nfs4_client *clp)
        __destroy_client(clp);
 }
 
+static void inc_reclaim_complete(struct nfs4_client *clp)
+{
+       struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
+
+       if (!nn->track_reclaim_completes)
+               return;
+       if (!nfsd4_find_reclaim_client(clp->cl_name, nn))
+               return;
+       if (atomic_inc_return(&nn->nr_reclaim_complete) ==
+                       nn->reclaim_str_hashtbl_size) {
+               printk(KERN_INFO "NFSD: all clients done reclaiming, ending NFSv4 grace period (net %x)\n",
+                               clp->net->ns.inum);
+               nfsd4_end_grace(nn);
+       }
+}
+
 static void expire_client(struct nfs4_client *clp)
 {
        unhash_client(clp);
@@ -2048,11 +2065,6 @@ compare_blob(const struct xdr_netobj *o1, const struct xdr_netobj *o2)
        return memcmp(o1->data, o2->data, o1->len);
 }
 
-static int same_name(const char *n1, const char *n2)
-{
-       return 0 == memcmp(n1, n2, HEXDIR_LEN);
-}
-
 static int
 same_verf(nfs4_verifier *v1, nfs4_verifier *v2)
 {
@@ -3354,6 +3366,7 @@ nfsd4_reclaim_complete(struct svc_rqst *rqstp,
 
        status = nfs_ok;
        nfsd4_client_record_create(cstate->session->se_client);
+       inc_reclaim_complete(cstate->session->se_client);
 out:
        return status;
 }
@@ -3958,6 +3971,9 @@ static int nfsd4_cb_recall_done(struct nfsd4_callback *cb,
        switch (task->tk_status) {
        case 0:
                return 1;
+       case -NFS4ERR_DELAY:
+               rpc_delay(task, 2 * HZ);
+               return 0;
        case -EBADHANDLE:
        case -NFS4ERR_BAD_STATEID:
                /*
@@ -3970,7 +3986,7 @@ static int nfsd4_cb_recall_done(struct nfsd4_callback *cb,
                }
                /*FALLTHRU*/
        default:
-               return -1;
+               return 1;
        }
 }
 
@@ -4713,7 +4729,6 @@ nfsd4_end_grace(struct nfsd_net *nn)
        if (nn->grace_ended)
                return;
 
-       dprintk("NFSD: end of grace period\n");
        nn->grace_ended = true;
        /*
         * If the server goes down again right now, an NFSv4
@@ -4749,6 +4764,10 @@ static bool clients_still_reclaiming(struct nfsd_net *nn)
        unsigned long double_grace_period_end = nn->boot_time +
                                                2 * nn->nfsd4_lease;
 
+       if (nn->track_reclaim_completes &&
+                       atomic_read(&nn->nr_reclaim_complete) ==
+                       nn->reclaim_str_hashtbl_size)
+               return false;
        if (!nn->somebody_reclaimed)
                return false;
        nn->somebody_reclaimed = false;
@@ -4779,6 +4798,7 @@ nfs4_laundromat(struct nfsd_net *nn)
                new_timeo = 0;
                goto out;
        }
+       dprintk("NFSD: end of grace period\n");
        nfsd4_end_grace(nn);
        INIT_LIST_HEAD(&reaplist);
        spin_lock(&nn->client_lock);
@@ -6458,7 +6478,7 @@ alloc_reclaim(void)
 }
 
 bool
-nfs4_has_reclaimed_state(const char *name, struct nfsd_net *nn)
+nfs4_has_reclaimed_state(struct xdr_netobj name, struct nfsd_net *nn)
 {
        struct nfs4_client_reclaim *crp;
 
@@ -6468,20 +6488,24 @@ nfs4_has_reclaimed_state(const char *name, struct nfsd_net *nn)
 
 /*
  * failure => all reset bets are off, nfserr_no_grace...
+ *
+ * The caller is responsible for freeing name.data if NULL is returned (it
+ * will be freed in nfs4_remove_reclaim_record in the normal case).
  */
 struct nfs4_client_reclaim *
-nfs4_client_to_reclaim(const char *name, struct nfsd_net *nn)
+nfs4_client_to_reclaim(struct xdr_netobj name, struct nfsd_net *nn)
 {
        unsigned int strhashval;
        struct nfs4_client_reclaim *crp;
 
-       dprintk("NFSD nfs4_client_to_reclaim NAME: %.*s\n", HEXDIR_LEN, name);
+       dprintk("NFSD nfs4_client_to_reclaim NAME: %.*s\n", name.len, name.data);
        crp = alloc_reclaim();
        if (crp) {
                strhashval = clientstr_hashval(name);
                INIT_LIST_HEAD(&crp->cr_strhash);
                list_add(&crp->cr_strhash, &nn->reclaim_str_hashtbl[strhashval]);
-               memcpy(crp->cr_recdir, name, HEXDIR_LEN);
+               crp->cr_name.data = name.data;
+               crp->cr_name.len = name.len;
                crp->cr_clp = NULL;
                nn->reclaim_str_hashtbl_size++;
        }
@@ -6492,6 +6516,7 @@ void
 nfs4_remove_reclaim_record(struct nfs4_client_reclaim *crp, struct nfsd_net *nn)
 {
        list_del(&crp->cr_strhash);
+       kfree(crp->cr_name.data);
        kfree(crp);
        nn->reclaim_str_hashtbl_size--;
 }
@@ -6515,16 +6540,16 @@ nfs4_release_reclaim(struct nfsd_net *nn)
 /*
  * called from OPEN, CLAIM_PREVIOUS with a new clientid. */
 struct nfs4_client_reclaim *
-nfsd4_find_reclaim_client(const char *recdir, struct nfsd_net *nn)
+nfsd4_find_reclaim_client(struct xdr_netobj name, struct nfsd_net *nn)
 {
        unsigned int strhashval;
        struct nfs4_client_reclaim *crp = NULL;
 
-       dprintk("NFSD: nfs4_find_reclaim_client for recdir %s\n", recdir);
+       dprintk("NFSD: nfs4_find_reclaim_client for name %.*s\n", name.len, name.data);
 
-       strhashval = clientstr_hashval(recdir);
+       strhashval = clientstr_hashval(name);
        list_for_each_entry(crp, &nn->reclaim_str_hashtbl[strhashval], cr_strhash) {
-               if (same_name(crp->cr_recdir, recdir)) {
+               if (compare_blob(&crp->cr_name, &name) == 0) {
                        return crp;
                }
        }
@@ -7262,10 +7287,19 @@ nfs4_state_start_net(struct net *net)
                return ret;
        locks_start_grace(net, &nn->nfsd4_manager);
        nfsd4_client_tracking_init(net);
+       if (nn->track_reclaim_completes && nn->reclaim_str_hashtbl_size == 0)
+               goto skip_grace;
        printk(KERN_INFO "NFSD: starting %ld-second grace period (net %x)\n",
               nn->nfsd4_grace, net->ns.inum);
        queue_delayed_work(laundry_wq, &nn->laundromat_work, nn->nfsd4_grace * HZ);
        return 0;
+
+skip_grace:
+       printk(KERN_INFO "NFSD: no clients to reclaim, skipping NFSv4 grace period (net %x)\n",
+                       net->ns.inum);
+       queue_delayed_work(laundry_wq, &nn->laundromat_work, nn->nfsd4_lease * HZ);
+       nfsd4_end_grace(nn);
+       return 0;
 }
 
 /* initialization to perform when the nfsd service is started: */