]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blobdiff - fs/nfsd/nfs4state.c
smb3: Fix root directory when server returns inode number of zero
[mirror_ubuntu-bionic-kernel.git] / fs / nfsd / nfs4state.c
index b29b5a185a2cb444f95fce2685381755d05d9429..974b1be7f14889d2408721c3269024682f05c7d1 100644 (file)
@@ -268,6 +268,35 @@ free_blocked_lock(struct nfsd4_blocked_lock *nbl)
        kfree(nbl);
 }
 
+static void
+remove_blocked_locks(struct nfs4_lockowner *lo)
+{
+       struct nfs4_client *clp = lo->lo_owner.so_client;
+       struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
+       struct nfsd4_blocked_lock *nbl;
+       LIST_HEAD(reaplist);
+
+       /* Dequeue all blocked locks */
+       spin_lock(&nn->blocked_locks_lock);
+       while (!list_empty(&lo->lo_blocked)) {
+               nbl = list_first_entry(&lo->lo_blocked,
+                                       struct nfsd4_blocked_lock,
+                                       nbl_list);
+               list_del_init(&nbl->nbl_list);
+               list_move(&nbl->nbl_lru, &reaplist);
+       }
+       spin_unlock(&nn->blocked_locks_lock);
+
+       /* Now free them */
+       while (!list_empty(&reaplist)) {
+               nbl = list_first_entry(&reaplist, struct nfsd4_blocked_lock,
+                                       nbl_lru);
+               list_del_init(&nbl->nbl_lru);
+               posix_unblock_lock(&nbl->nbl_lock);
+               free_blocked_lock(nbl);
+       }
+}
+
 static int
 nfsd4_cb_notify_lock_done(struct nfsd4_callback *cb, struct rpc_task *task)
 {
@@ -1866,6 +1895,7 @@ static __be32 mark_client_expired_locked(struct nfs4_client *clp)
 static void
 __destroy_client(struct nfs4_client *clp)
 {
+       int i;
        struct nfs4_openowner *oo;
        struct nfs4_delegation *dp;
        struct list_head reaplist;
@@ -1895,6 +1925,16 @@ __destroy_client(struct nfs4_client *clp)
                nfs4_get_stateowner(&oo->oo_owner);
                release_openowner(oo);
        }
+       for (i = 0; i < OWNER_HASH_SIZE; i++) {
+               struct nfs4_stateowner *so, *tmp;
+
+               list_for_each_entry_safe(so, tmp, &clp->cl_ownerstr_hashtbl[i],
+                                        so_strhash) {
+                       /* Should be no openowners at this point */
+                       WARN_ON_ONCE(so->so_is_open_owner);
+                       remove_blocked_locks(lockowner(so));
+               }
+       }
        nfsd4_return_all_client_layouts(clp);
        nfsd4_shutdown_callback(clp);
        if (clp->cl_cb_conn.cb_xprt)
@@ -3590,6 +3630,7 @@ nfsd4_verify_open_stid(struct nfs4_stid *s)
        switch (s->sc_type) {
        default:
                break;
+       case 0:
        case NFS4_CLOSED_STID:
        case NFS4_CLOSED_DELEG_STID:
                ret = nfserr_bad_stateid;
@@ -6357,6 +6398,7 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp,
        }
        spin_unlock(&clp->cl_lock);
        free_ol_stateid_reaplist(&reaplist);
+       remove_blocked_locks(lo);
        nfs4_put_stateowner(&lo->lo_owner);
 
        return status;
@@ -7142,6 +7184,8 @@ nfs4_state_destroy_net(struct net *net)
                }
        }
 
+       WARN_ON(!list_empty(&nn->blocked_locks_lru));
+
        for (i = 0; i < CLIENT_HASH_SIZE; i++) {
                while (!list_empty(&nn->unconf_id_hashtbl[i])) {
                        clp = list_entry(nn->unconf_id_hashtbl[i].next, struct nfs4_client, cl_idhash);
@@ -7208,7 +7252,6 @@ nfs4_state_shutdown_net(struct net *net)
        struct nfs4_delegation *dp = NULL;
        struct list_head *pos, *next, reaplist;
        struct nfsd_net *nn = net_generic(net, nfsd_net_id);
-       struct nfsd4_blocked_lock *nbl;
 
        cancel_delayed_work_sync(&nn->laundromat_work);
        locks_end_grace(&nn->nfsd4_manager);
@@ -7229,24 +7272,6 @@ nfs4_state_shutdown_net(struct net *net)
                nfs4_put_stid(&dp->dl_stid);
        }
 
-       BUG_ON(!list_empty(&reaplist));
-       spin_lock(&nn->blocked_locks_lock);
-       while (!list_empty(&nn->blocked_locks_lru)) {
-               nbl = list_first_entry(&nn->blocked_locks_lru,
-                                       struct nfsd4_blocked_lock, nbl_lru);
-               list_move(&nbl->nbl_lru, &reaplist);
-               list_del_init(&nbl->nbl_list);
-       }
-       spin_unlock(&nn->blocked_locks_lock);
-
-       while (!list_empty(&reaplist)) {
-               nbl = list_first_entry(&reaplist,
-                                       struct nfsd4_blocked_lock, nbl_lru);
-               list_del_init(&nbl->nbl_lru);
-               posix_unblock_lock(&nbl->nbl_lock);
-               free_blocked_lock(nbl);
-       }
-
        nfsd4_client_tracking_exit(net);
        nfs4_state_destroy_net(net);
 }