]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
NFSD: Block DESTROY_CLIENTID only when there are ongoing async COPY operations
authorChuck Lever <chuck.lever@oracle.com>
Thu, 31 Oct 2024 13:40:06 +0000 (09:40 -0400)
committerChuck Lever <chuck.lever@oracle.com>
Tue, 19 Nov 2024 01:23:10 +0000 (20:23 -0500)
Currently __destroy_client() consults the nfs4_client's async_copies
list to determine whether there are ongoing async COPY operations.
However, NFSD now keeps copy state in that list even when the
async copy has completed, to enable OFFLOAD_STATUS to find the
COPY results for a while after the COPY has completed.

DESTROY_CLIENTID should not be blocked if the client's async_copies
list contains state for only completed copy operations.

Reviewed-by: Jeff Layton <jlayton@kernel.org>
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
fs/nfsd/nfs4proc.c
fs/nfsd/nfs4state.c
fs/nfsd/state.h

index 54db3979605fb717e404bd1833e5e01bc3706613..67349eca55b114ac49d312885434b1163c863d38 100644 (file)
@@ -1278,6 +1278,36 @@ out:
        return status;
 }
 
+/**
+ * nfsd4_has_active_async_copies - Check for ongoing copy operations
+ * @clp: Client to be checked
+ *
+ * NFSD maintains state for async COPY operations after they complete,
+ * and this state remains in the nfs4_client's async_copies list.
+ * Ongoing copies should block the destruction of the nfs4_client, but
+ * completed copies should not.
+ *
+ * Return values:
+ *   %true: At least one active async COPY is ongoing
+ *   %false: No active async COPY operations were found
+ */
+bool nfsd4_has_active_async_copies(struct nfs4_client *clp)
+{
+       struct nfsd4_copy *copy;
+       bool result = false;
+
+       spin_lock(&clp->async_lock);
+       list_for_each_entry(copy, &clp->async_copies, copies) {
+               if (!test_bit(NFSD4_COPY_F_COMPLETED, &copy->cp_flags) &&
+                   !test_bit(NFSD4_COPY_F_STOPPED, &copy->cp_flags)) {
+                       result = true;
+                       break;
+               }
+       }
+       spin_unlock(&clp->async_lock);
+       return result;
+}
+
 static void nfs4_put_copy(struct nfsd4_copy *copy)
 {
        if (!refcount_dec_and_test(&copy->refcount))
index a334f0a0e50ad62f447ad604b7e79d27629278f1..b8bedc6a157f49d384bf10c4b57bd11036105e9a 100644 (file)
@@ -3472,7 +3472,7 @@ static bool client_has_state(struct nfs4_client *clp)
 #endif
                || !list_empty(&clp->cl_delegations)
                || !list_empty(&clp->cl_sessions)
-               || !list_empty(&clp->async_copies);
+               || nfsd4_has_active_async_copies(clp);
 }
 
 static __be32 copy_impl_id(struct nfs4_client *clp,
index 2f735492cf6c749301ba1e65c8ad2265b98bbe01..4dd7ed7ae052492aaaa78694aeeb3f095dcfc80e 100644 (file)
@@ -738,6 +738,7 @@ extern void nfsd4_init_cb(struct nfsd4_callback *cb, struct nfs4_client *clp,
 extern bool nfsd4_run_cb(struct nfsd4_callback *cb);
 extern void nfsd4_shutdown_callback(struct nfs4_client *);
 extern void nfsd4_shutdown_copy(struct nfs4_client *clp);
+bool nfsd4_has_active_async_copies(struct nfs4_client *clp);
 extern struct nfs4_client_reclaim *nfs4_client_to_reclaim(struct xdr_netobj name,
                                struct xdr_netobj princhash, struct nfsd_net *nn);
 extern bool nfs4_has_reclaimed_state(struct xdr_netobj name, struct nfsd_net *nn);