From patchwork Wed Nov 1 00:57:08 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: NeilBrown X-Patchwork-Id: 13442459 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 3667AC4332F for ; Wed, 1 Nov 2023 01:01:10 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1347110AbjKABBK (ORCPT ); Tue, 31 Oct 2023 21:01:10 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:33040 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1345029AbjKABBK (ORCPT ); Tue, 31 Oct 2023 21:01:10 -0400 Received: from smtp-out2.suse.de (smtp-out2.suse.de [IPv6:2001:67c:2178:6::1d]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id ACD04C9 for ; Tue, 31 Oct 2023 18:01:04 -0700 (PDT) Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out2.suse.de (Postfix) with ESMTPS id 673BC1F45A; Wed, 1 Nov 2023 01:01:03 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1698800463; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=YXysBykSeW30chslpMH7j83afeQvJFFuwO8aP8ilkkM=; b=Bpx7YrfR0GstyTnA9Syy4Gw7e5QEjekY3mx7aco+01z26dkwE7JshTXrZs2knzQhvqCYxV xCT2asItVeEeJRC3jJUh3VlKVFkjQ4HKl9IJPZ4biw0gMDt/ohybI3tabEnVyM0TsRdSu1 nCT8uOq1p3azbleWHb9rdJps+TvspNY= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1698800463; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=YXysBykSeW30chslpMH7j83afeQvJFFuwO8aP8ilkkM=; b=JS06m/IXXbnUudeaMaWT3iVwS/7bvgZXMaECygr88luKPDTf7cLdi/FhgJGXuExiUbCw9D GsCzaey2/Ch2bJCA== Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap2.suse-dmz.suse.de (Postfix) with ESMTPS id 64B6A138EF; Wed, 1 Nov 2023 01:01:01 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id hwC0B02jQWX1OgAAMHmgww (envelope-from ); Wed, 01 Nov 2023 01:01:01 +0000 From: NeilBrown To: Chuck Lever , Jeff Layton Cc: linux-nfs@vger.kernel.org, Olga Kornievskaia , Dai Ngo , Tom Talpey Subject: [PATCH 1/6] nfsd: prepare for supporting admin-revocation of state Date: Wed, 1 Nov 2023 11:57:08 +1100 Message-ID: <20231101010049.27315-2-neilb@suse.de> X-Mailer: git-send-email 2.42.0 In-Reply-To: <20231101010049.27315-1-neilb@suse.de> References: <20231101010049.27315-1-neilb@suse.de> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-nfs@vger.kernel.org The NFSv4 protocol allows state to be revoked by the admin and has error codes which allow this to be communicated to the client. This patch - introduces 3 new state-id types for revoked open, lock, and delegation state. This requires the bitmask to be 'short', not 'char' - reports NFS4ERR_ADMIN_REVOKED when these are accessed - introduces a per-client counter of these states and returns SEQ4_STATUS_ADMIN_STATE_REVOKED when the counter is not zero. Decrement this when freeing any admin-revoked state. - introduces stub code to find all interesting states for a given superblock so they can be revoked via the 'unlock_filesystem' file in /proc/fs/nfsd/ No actual states are handled yet. Signed-off-by: NeilBrown Signed-off-by: NeilBrown --- fs/nfsd/nfs4layouts.c | 2 +- fs/nfsd/nfs4state.c | 93 +++++++++++++++++++++++++++++++++++++++---- fs/nfsd/nfsctl.c | 1 + fs/nfsd/nfsd.h | 1 + fs/nfsd/state.h | 35 +++++++++++----- fs/nfsd/trace.h | 8 +++- 6 files changed, 120 insertions(+), 20 deletions(-) diff --git a/fs/nfsd/nfs4layouts.c b/fs/nfsd/nfs4layouts.c index 5e8096bc5eaa..09d0363bfbc4 100644 --- a/fs/nfsd/nfs4layouts.c +++ b/fs/nfsd/nfs4layouts.c @@ -269,7 +269,7 @@ nfsd4_preprocess_layout_stateid(struct svc_rqst *rqstp, { struct nfs4_layout_stateid *ls; struct nfs4_stid *stid; - unsigned char typemask = NFS4_LAYOUT_STID; + unsigned short typemask = NFS4_LAYOUT_STID; __be32 status; if (create) diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 65fd5510323a..f3ba53a16105 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -1202,6 +1202,13 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_file *fp, return NULL; } +void nfs4_unhash_stid(struct nfs4_stid *s) +{ + if (s->sc_type & NFS4_ALL_ADMIN_REVOKED_STIDS) + atomic_dec(&s->sc_client->cl_admin_revoked); + s->sc_type = 0; +} + void nfs4_put_stid(struct nfs4_stid *s) { @@ -1215,6 +1222,7 @@ nfs4_put_stid(struct nfs4_stid *s) return; } idr_remove(&clp->cl_stateids, s->sc_stateid.si_opaque.so_id); + nfs4_unhash_stid(s); nfs4_free_cpntf_statelist(clp->net, s); spin_unlock(&clp->cl_lock); s->sc_free(s); @@ -1265,11 +1273,6 @@ static void destroy_unhashed_deleg(struct nfs4_delegation *dp) nfs4_put_stid(&dp->dl_stid); } -void nfs4_unhash_stid(struct nfs4_stid *s) -{ - s->sc_type = 0; -} - /** * nfs4_delegation_exists - Discover if this delegation already exists * @clp: a pointer to the nfs4_client we're granting a delegation to @@ -1536,6 +1539,7 @@ static void put_ol_stateid_locked(struct nfs4_ol_stateid *stp, } idr_remove(&clp->cl_stateids, s->sc_stateid.si_opaque.so_id); + nfs4_unhash_stid(s); list_add(&stp->st_locks, reaplist); } @@ -1680,6 +1684,53 @@ static void release_openowner(struct nfs4_openowner *oo) nfs4_put_stateowner(&oo->oo_owner); } +static struct nfs4_stid *find_one_sb_stid(struct nfs4_client *clp, + struct super_block *sb, + unsigned short sc_types) +{ + unsigned long id, tmp; + struct nfs4_stid *stid; + + spin_lock(&clp->cl_lock); + idr_for_each_entry_ul(&clp->cl_stateids, stid, tmp, id) + if ((stid->sc_type & sc_types) && + stid->sc_file->fi_inode->i_sb == sb) { + refcount_inc(&stid->sc_count); + break; + } + spin_unlock(&clp->cl_lock); + return stid; +} + +void nfsd4_revoke_states(struct net *net, struct super_block *sb) +{ + struct nfsd_net *nn = net_generic(net, nfsd_net_id); + unsigned int idhashval; + unsigned short sc_types; + + sc_types = 0; + + spin_lock(&nn->client_lock); + for (idhashval = 0; idhashval < CLIENT_HASH_MASK; idhashval++) { + struct list_head *head = &nn->conf_id_hashtbl[idhashval]; + struct nfs4_client *clp; + retry: + list_for_each_entry(clp, head, cl_idhash) { + struct nfs4_stid *stid = find_one_sb_stid(clp, sb, + sc_types); + if (stid) { + spin_unlock(&nn->client_lock); + switch (stid->sc_type) { + } + nfs4_put_stid(stid); + spin_lock(&nn->client_lock); + goto retry; + } + } + } + spin_unlock(&nn->client_lock); +} + static inline int hash_sessionid(struct nfs4_sessionid *sessionid) { @@ -2465,7 +2516,8 @@ find_stateid_locked(struct nfs4_client *cl, stateid_t *t) } static struct nfs4_stid * -find_stateid_by_type(struct nfs4_client *cl, stateid_t *t, char typemask) +find_stateid_by_type(struct nfs4_client *cl, stateid_t *t, + unsigned short typemask) { struct nfs4_stid *s; @@ -2549,6 +2601,8 @@ static int client_info_show(struct seq_file *m, void *v) } seq_printf(m, "callback state: %s\n", cb_state2str(clp->cl_cb_state)); seq_printf(m, "callback address: %pISpc\n", &clp->cl_cb_conn.cb_addr); + seq_printf(m, "admin-revoked states: %d\n", + atomic_read(&clp->cl_admin_revoked)); drop_client(clp); return 0; @@ -4108,6 +4162,8 @@ nfsd4_sequence(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, } if (!list_empty(&clp->cl_revoked)) seq->status_flags |= SEQ4_STATUS_RECALLABLE_STATE_REVOKED; + if (atomic_read(&clp->cl_admin_revoked)) + seq->status_flags |= SEQ4_STATUS_ADMIN_STATE_REVOKED; out_no_session: if (conn) free_conn(conn); @@ -5200,6 +5256,11 @@ nfs4_check_deleg(struct nfs4_client *cl, struct nfsd4_open *open, status = nfserr_deleg_revoked; goto out; } + if (deleg->dl_stid.sc_type == NFS4_ADMIN_REVOKED_DELEG_STID) { + nfs4_put_stid(&deleg->dl_stid); + status = nfserr_admin_revoked; + goto out; + } flags = share_access_to_flags(open->op_share_access); status = nfs4_check_delegmode(deleg, flags); if (status) { @@ -6478,6 +6539,11 @@ static __be32 nfsd4_validate_stateid(struct nfs4_client *cl, stateid_t *stateid) case NFS4_REVOKED_DELEG_STID: status = nfserr_deleg_revoked; break; + case NFS4_ADMIN_REVOKED_STID: + case NFS4_ADMIN_REVOKED_LOCK_STID: + case NFS4_ADMIN_REVOKED_DELEG_STID: + status = nfserr_admin_revoked; + break; case NFS4_OPEN_STID: case NFS4_LOCK_STID: status = nfsd4_check_openowner_confirmed(openlockstateid(s)); @@ -6496,7 +6562,7 @@ static __be32 nfsd4_validate_stateid(struct nfs4_client *cl, stateid_t *stateid) __be32 nfsd4_lookup_stateid(struct nfsd4_compound_state *cstate, - stateid_t *stateid, unsigned char typemask, + stateid_t *stateid, unsigned short typemask, struct nfs4_stid **s, struct nfsd_net *nn) { __be32 status; @@ -6512,6 +6578,13 @@ nfsd4_lookup_stateid(struct nfsd4_compound_state *cstate, else if (typemask & NFS4_DELEG_STID) typemask |= NFS4_REVOKED_DELEG_STID; + if (typemask & NFS4_OPEN_STID) + typemask |= NFS4_ADMIN_REVOKED_STID; + if (typemask & NFS4_LOCK_STID) + typemask |= NFS4_ADMIN_REVOKED_LOCK_STID; + if (typemask & NFS4_DELEG_STID) + typemask |= NFS4_ADMIN_REVOKED_DELEG_STID; + if (ZERO_STATEID(stateid) || ONE_STATEID(stateid) || CLOSE_STATEID(stateid)) return nfserr_bad_stateid; @@ -6532,6 +6605,10 @@ nfsd4_lookup_stateid(struct nfsd4_compound_state *cstate, return nfserr_deleg_revoked; return nfserr_bad_stateid; } + if (stid->sc_type & NFS4_ALL_ADMIN_REVOKED_STIDS) { + nfs4_put_stid(stid); + return nfserr_admin_revoked; + } *s = stid; return nfs_ok; } @@ -6899,7 +6976,7 @@ static __be32 nfs4_seqid_op_checks(struct nfsd4_compound_state *cstate, stateid_ */ static __be32 nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid, - stateid_t *stateid, char typemask, + stateid_t *stateid, unsigned short typemask, struct nfs4_ol_stateid **stpp, struct nfsd_net *nn) { diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index 739ed5bf71cd..50368eec86b0 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c @@ -281,6 +281,7 @@ static ssize_t write_unlock_fs(struct file *file, char *buf, size_t size) * 3. Is that directory the root of an exported file system? */ error = nlmsvc_unlock_all_by_sb(path.dentry->d_sb); + nfsd4_revoke_states(netns(file), path.dentry->d_sb); path_put(&path); return error; diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h index f5ff42f41ee7..d46203eac3c8 100644 --- a/fs/nfsd/nfsd.h +++ b/fs/nfsd/nfsd.h @@ -280,6 +280,7 @@ void nfsd_lockd_shutdown(void); #define nfserr_no_grace cpu_to_be32(NFSERR_NO_GRACE) #define nfserr_reclaim_bad cpu_to_be32(NFSERR_RECLAIM_BAD) #define nfserr_badname cpu_to_be32(NFSERR_BADNAME) +#define nfserr_admin_revoked cpu_to_be32(NFS4ERR_ADMIN_REVOKED) #define nfserr_cb_path_down cpu_to_be32(NFSERR_CB_PATH_DOWN) #define nfserr_locked cpu_to_be32(NFSERR_LOCKED) #define nfserr_wrongsec cpu_to_be32(NFSERR_WRONGSEC) diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index f96eaa8e9413..3af5ab55c978 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h @@ -88,17 +88,23 @@ struct nfsd4_callback_ops { */ struct nfs4_stid { refcount_t sc_count; -#define NFS4_OPEN_STID 1 -#define NFS4_LOCK_STID 2 -#define NFS4_DELEG_STID 4 + struct list_head sc_cp_list; + unsigned short sc_type; +#define NFS4_OPEN_STID BIT(0) +#define NFS4_LOCK_STID BIT(1) +#define NFS4_DELEG_STID BIT(2) /* For an open stateid kept around *only* to process close replays: */ -#define NFS4_CLOSED_STID 8 +#define NFS4_CLOSED_STID BIT(3) /* For a deleg stateid kept around only to process free_stateid's: */ -#define NFS4_REVOKED_DELEG_STID 16 -#define NFS4_CLOSED_DELEG_STID 32 -#define NFS4_LAYOUT_STID 64 - struct list_head sc_cp_list; - unsigned char sc_type; +#define NFS4_REVOKED_DELEG_STID BIT(4) +#define NFS4_CLOSED_DELEG_STID BIT(5) +#define NFS4_LAYOUT_STID BIT(6) +#define NFS4_ADMIN_REVOKED_STID BIT(7) +#define NFS4_ADMIN_REVOKED_LOCK_STID BIT(8) +#define NFS4_ADMIN_REVOKED_DELEG_STID BIT(9) +#define NFS4_ALL_ADMIN_REVOKED_STIDS (NFS4_ADMIN_REVOKED_STID | \ + NFS4_ADMIN_REVOKED_LOCK_STID | \ + NFS4_ADMIN_REVOKED_DELEG_STID) stateid_t sc_stateid; spinlock_t sc_lock; struct nfs4_client *sc_client; @@ -372,6 +378,7 @@ struct nfs4_client { clientid_t cl_clientid; /* generated by server */ nfs4_verifier cl_confirm; /* generated by server */ u32 cl_minorversion; + atomic_t cl_admin_revoked; /* count of admin-revoked states */ /* NFSv4.1 client implementation id: */ struct xdr_netobj cl_nii_domain; struct xdr_netobj cl_nii_name; @@ -694,7 +701,7 @@ extern __be32 nfs4_preprocess_stateid_op(struct svc_rqst *rqstp, stateid_t *stateid, int flags, struct nfsd_file **filp, struct nfs4_stid **cstid); __be32 nfsd4_lookup_stateid(struct nfsd4_compound_state *cstate, - stateid_t *stateid, unsigned char typemask, + stateid_t *stateid, unsigned short typemask, struct nfs4_stid **s, struct nfsd_net *nn); struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, struct kmem_cache *slab, void (*sc_free)(struct nfs4_stid *)); @@ -736,6 +743,14 @@ static inline void get_nfs4_file(struct nfs4_file *fi) } struct nfsd_file *find_any_file(struct nfs4_file *f); +#ifdef CONFIG_NFSD_V4 +void nfsd4_revoke_states(struct net *net, struct super_block *sb); +#else +static inline void nfsd4_revoke_states(struct net *net, struct super_block *sb) +{ +} +#endif + /* grace period management */ void nfsd4_end_grace(struct nfsd_net *nn); diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h index fbc0ccb40424..e359d531402c 100644 --- a/fs/nfsd/trace.h +++ b/fs/nfsd/trace.h @@ -648,6 +648,9 @@ TRACE_DEFINE_ENUM(NFS4_CLOSED_STID); TRACE_DEFINE_ENUM(NFS4_REVOKED_DELEG_STID); TRACE_DEFINE_ENUM(NFS4_CLOSED_DELEG_STID); TRACE_DEFINE_ENUM(NFS4_LAYOUT_STID); +TRACE_DEFINE_ENUM(NFS4_ADMIN_REVOKED_STID); +TRACE_DEFINE_ENUM(NFS4_ADMIN_REVOKED_LOCK_STID); +TRACE_DEFINE_ENUM(NFS4_ADMIN_REVOKED_DELEG_STID); #define show_stid_type(x) \ __print_flags(x, "|", \ @@ -657,7 +660,10 @@ TRACE_DEFINE_ENUM(NFS4_LAYOUT_STID); { NFS4_CLOSED_STID, "CLOSED" }, \ { NFS4_REVOKED_DELEG_STID, "REVOKED" }, \ { NFS4_CLOSED_DELEG_STID, "CLOSED_DELEG" }, \ - { NFS4_LAYOUT_STID, "LAYOUT" }) + { NFS4_LAYOUT_STID, "LAYOUT" }, \ + { NFS4_ADMIN_REVOKED_STID, "ADMIN_REVOKED" }, \ + { NFS4_ADMIN_REVOKED_LOCK_STID, "ADMIN_REVOKED_LOCK" }, \ + { NFS4_ADMIN_REVOKED_DELEG_STID,"ADMIN_REVOKED_DELEG" }) DECLARE_EVENT_CLASS(nfsd_stid_class, TP_PROTO( From patchwork Wed Nov 1 00:57:09 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: NeilBrown X-Patchwork-Id: 13442460 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id B4833C4167B for ; Wed, 1 Nov 2023 01:01:12 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1376925AbjKABBN (ORCPT ); Tue, 31 Oct 2023 21:01:13 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:33054 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1376924AbjKABBM (ORCPT ); Tue, 31 Oct 2023 21:01:12 -0400 Received: from smtp-out2.suse.de (smtp-out2.suse.de [IPv6:2001:67c:2178:6::1d]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 24A15C9 for ; Tue, 31 Oct 2023 18:01:10 -0700 (PDT) Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out2.suse.de (Postfix) with ESMTPS id D717C1F460; Wed, 1 Nov 2023 01:01:08 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1698800468; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=ZoEVGAM/kH9XPvUMzNhmj0SyiXtYsN9ufv+LSfLrSS0=; b=2Pvx3fnuLFJovqqW+vuO0rwJru8xsIYjIw/81hTDhLyDP1K9nF9ZtT8fIUcIR2cImcMGjQ X/lO0WvnCeYedPJplSbYqTKbcK2IHut98hsC7apfFnzEUSCgxZ83jOa1cuCEZTX/V7AswL ArPRJShuVr8j/PgPT7CGTYWvXlrs2yU= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1698800468; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=ZoEVGAM/kH9XPvUMzNhmj0SyiXtYsN9ufv+LSfLrSS0=; b=WdzE0qo9aU1PE6cevtz+liPEja6i9pYR8Ic6WLvaoCZZEWT/cRFhW0iKoljCZHsQBsxOPW bGcYtJcDeUnNx9CA== Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap2.suse-dmz.suse.de (Postfix) with ESMTPS id D1351138EF; Wed, 1 Nov 2023 01:01:06 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id /pv/IVKjQWX9OgAAMHmgww (envelope-from ); Wed, 01 Nov 2023 01:01:06 +0000 From: NeilBrown To: Chuck Lever , Jeff Layton Cc: linux-nfs@vger.kernel.org, Olga Kornievskaia , Dai Ngo , Tom Talpey Subject: [PATCH 2/6] nfsd: allow admin-revoked state to appear in /proc/fs/nfsd/clients/*/states Date: Wed, 1 Nov 2023 11:57:09 +1100 Message-ID: <20231101010049.27315-3-neilb@suse.de> X-Mailer: git-send-email 2.42.0 In-Reply-To: <20231101010049.27315-1-neilb@suse.de> References: <20231101010049.27315-1-neilb@suse.de> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-nfs@vger.kernel.org Change the "show" functions to show some content even if a file cannot be found, and call them for the ADMIN_REVOKED versions of state id. This use primarily useful for debugging - to ensure states are being removed eventually. Signed-off-by: NeilBrown --- fs/nfsd/nfs4state.c | 78 ++++++++++++++++++++++----------------------- 1 file changed, 38 insertions(+), 40 deletions(-) diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index f3ba53a16105..e15d35c57991 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -2679,17 +2679,10 @@ static int nfs4_show_open(struct seq_file *s, struct nfs4_stid *st) struct nfs4_stateowner *oo; unsigned int access, deny; - if (st->sc_type != NFS4_OPEN_STID && st->sc_type != NFS4_LOCK_STID) - return 0; /* XXX: or SEQ_SKIP? */ ols = openlockstateid(st); oo = ols->st_stateowner; nf = st->sc_file; - spin_lock(&nf->fi_lock); - file = find_any_file_locked(nf); - if (!file) - goto out; - seq_printf(s, "- "); nfs4_show_stateid(s, &st->sc_stateid); seq_printf(s, ": { type: open, "); @@ -2704,14 +2697,17 @@ static int nfs4_show_open(struct seq_file *s, struct nfs4_stid *st) deny & NFS4_SHARE_ACCESS_READ ? "r" : "-", deny & NFS4_SHARE_ACCESS_WRITE ? "w" : "-"); - nfs4_show_superblock(s, file); - seq_printf(s, ", "); - nfs4_show_fname(s, file); - seq_printf(s, ", "); + spin_lock(&nf->fi_lock); + file = find_any_file_locked(nf); + if (file) { + nfs4_show_superblock(s, file); + seq_puts(s, ", "); + nfs4_show_fname(s, file); + seq_puts(s, ", "); + } + spin_unlock(&nf->fi_lock); nfs4_show_owner(s, oo); seq_printf(s, " }\n"); -out: - spin_unlock(&nf->fi_lock); return 0; } @@ -2725,30 +2721,29 @@ static int nfs4_show_lock(struct seq_file *s, struct nfs4_stid *st) ols = openlockstateid(st); oo = ols->st_stateowner; nf = st->sc_file; - spin_lock(&nf->fi_lock); - file = find_any_file_locked(nf); - if (!file) - goto out; seq_printf(s, "- "); nfs4_show_stateid(s, &st->sc_stateid); seq_printf(s, ": { type: lock, "); - /* - * Note: a lock stateid isn't really the same thing as a lock, - * it's the locking state held by one owner on a file, and there - * may be multiple (or no) lock ranges associated with it. - * (Same for the matter is true of open stateids.) - */ + spin_lock(&nf->fi_lock); + file = find_any_file_locked(nf); + if (file) { + /* + * Note: a lock stateid isn't really the same thing as a lock, + * it's the locking state held by one owner on a file, and there + * may be multiple (or no) lock ranges associated with it. + * (Same for the matter is true of open stateids.) + */ - nfs4_show_superblock(s, file); - /* XXX: open stateid? */ - seq_printf(s, ", "); - nfs4_show_fname(s, file); - seq_printf(s, ", "); + nfs4_show_superblock(s, file); + /* XXX: open stateid? */ + seq_puts(s, ", "); + nfs4_show_fname(s, file); + seq_puts(s, ", "); + } nfs4_show_owner(s, oo); seq_printf(s, " }\n"); -out: spin_unlock(&nf->fi_lock); return 0; } @@ -2761,27 +2756,27 @@ static int nfs4_show_deleg(struct seq_file *s, struct nfs4_stid *st) ds = delegstateid(st); nf = st->sc_file; - spin_lock(&nf->fi_lock); - file = nf->fi_deleg_file; - if (!file) - goto out; seq_printf(s, "- "); nfs4_show_stateid(s, &st->sc_stateid); seq_printf(s, ": { type: deleg, "); /* Kinda dead code as long as we only support read delegs: */ - seq_printf(s, "access: %s, ", - ds->dl_type == NFS4_OPEN_DELEGATE_READ ? "r" : "w"); + seq_printf(s, "access: %s", + ds->dl_type == NFS4_OPEN_DELEGATE_READ ? "r" : "w"); /* XXX: lease time, whether it's being recalled. */ - nfs4_show_superblock(s, file); - seq_printf(s, ", "); - nfs4_show_fname(s, file); - seq_printf(s, " }\n"); -out: + spin_lock(&nf->fi_lock); + file = nf->fi_deleg_file; + if (file) { + seq_puts(s, ", "); + nfs4_show_superblock(s, file); + seq_puts(s, ", "); + nfs4_show_fname(s, file); + } spin_unlock(&nf->fi_lock); + seq_puts(s, " }\n"); return 0; } @@ -2813,10 +2808,13 @@ static int states_show(struct seq_file *s, void *v) switch (st->sc_type) { case NFS4_OPEN_STID: + case NFS4_ADMIN_REVOKED_STID: return nfs4_show_open(s, st); case NFS4_LOCK_STID: + case NFS4_ADMIN_REVOKED_LOCK_STID: return nfs4_show_lock(s, st); case NFS4_DELEG_STID: + case NFS4_ADMIN_REVOKED_DELEG_STID: return nfs4_show_deleg(s, st); case NFS4_LAYOUT_STID: return nfs4_show_layout(s, st); From patchwork Wed Nov 1 00:57:10 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: NeilBrown X-Patchwork-Id: 13442461 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 10680C4332F for ; Wed, 1 Nov 2023 01:01:22 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1376931AbjKABBW (ORCPT ); Tue, 31 Oct 2023 21:01:22 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:44984 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1376924AbjKABBV (ORCPT ); Tue, 31 Oct 2023 21:01:21 -0400 Received: from smtp-out1.suse.de (smtp-out1.suse.de [IPv6:2001:67c:2178:6::1c]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 9369BF4 for ; Tue, 31 Oct 2023 18:01:15 -0700 (PDT) Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out1.suse.de (Postfix) with ESMTPS id 499762184F; Wed, 1 Nov 2023 01:01:14 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1698800474; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=mEMvrgugH8OJnZVdaeGDlkzjt7mzcEWUEKn0B3JiNNA=; b=kb64DYs4W1nBViXXecwrFCJ5sE6PwSK7+eXRH4Q6YaJGEqXC/cRyDbTUD2vmcC9+M6Zvig +hAtUhFT0M81CkIOp+ZWnBk1PpSGiv6UUverDYljD1qPK5bBlKtExzPKI6yfJvZGZEXnhh c59n7gC0upWADuLS6eVh2QDpj7eu098= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1698800474; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=mEMvrgugH8OJnZVdaeGDlkzjt7mzcEWUEKn0B3JiNNA=; b=yD7UDwYWqM9OhPNWIrTpxbyPEBhwgRcg4qvMyd4s4WXh/2ZPX/KL6vsMRGi9VBABlb2T64 1tTCBMFSpAnbSfDQ== Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap2.suse-dmz.suse.de (Postfix) with ESMTPS id 42809138EF; Wed, 1 Nov 2023 01:01:11 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id vy6kOlejQWUJOwAAMHmgww (envelope-from ); Wed, 01 Nov 2023 01:01:11 +0000 From: NeilBrown To: Chuck Lever , Jeff Layton Cc: linux-nfs@vger.kernel.org, Olga Kornievskaia , Dai Ngo , Tom Talpey Subject: [PATCH 3/6] nfsd: allow admin-revoked NFSv4.0 state to be freed. Date: Wed, 1 Nov 2023 11:57:10 +1100 Message-ID: <20231101010049.27315-4-neilb@suse.de> X-Mailer: git-send-email 2.42.0 In-Reply-To: <20231101010049.27315-1-neilb@suse.de> References: <20231101010049.27315-1-neilb@suse.de> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-nfs@vger.kernel.org For NFSv4.1 and later the client easily discovers if there is any admin-revoked state and will then find and explicitly free it. For NFSv4.0 there is no such mechanism. The client can only find that state is admin-revoked if it tries to use that state, and there is no way for it to explicitly free the state. So the server must hold on to, at least, the stateid for an indefinite amount of time. A RELEASE_LOCKOWNER request might justify forgetting some of these stateids, as would the whole clients lease lapsing, but these are not reliable. This patch takes two approaches. Whenever a client uses an revoked stateid, that stateid is then discarded and will not be recognised again. This might confuse a client which expect to get NFS4ERR_ADMIN_REVOKED consistently once it get it at all, but should mostly work. Hopefully one error will lead to other resources being closed (e.g. process exits), which will result in more stateid being freed when a CLOSE attempt gets NFS4ERR_ADMIN_REVOKED. Also, any admin-revoked stateids that have been that way for more than one lease time are periodically revoke. No actual freeing of state happens in this patch. That will come in future patches which handle the different sorts of revoked state. Signed-off-by: NeilBrown --- fs/nfsd/netns.h | 4 ++ fs/nfsd/nfs4state.c | 98 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 102 insertions(+) diff --git a/fs/nfsd/netns.h b/fs/nfsd/netns.h index ec49b200b797..02f8fa095b0f 100644 --- a/fs/nfsd/netns.h +++ b/fs/nfsd/netns.h @@ -197,6 +197,10 @@ struct nfsd_net { atomic_t nfsd_courtesy_clients; struct shrinker nfsd_client_shrinker; struct work_struct nfsd_shrinker_work; + + /* last time an admin-revoke happened for NFSv4.0 */ + time64_t nfs40_last_revoke; + }; /* Simple check to find out if a given net was properly initialized */ diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index e15d35c57991..13484a9cef21 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -1724,6 +1724,14 @@ void nfsd4_revoke_states(struct net *net, struct super_block *sb) } nfs4_put_stid(stid); spin_lock(&nn->client_lock); + if (clp->cl_minorversion == 0) + /* Allow cleanup after a lease period. + * store_release ensures cleanup will + * see any newly revoked states if it + * sees the time updated. + */ + nn->nfs40_last_revoke = + ktime_get_boottime_seconds(); goto retry; } } @@ -4645,6 +4653,39 @@ nfsd4_find_existing_open(struct nfs4_file *fp, struct nfsd4_open *open) return ret; } +static void nfsd_drop_revoked_stid(struct nfs4_stid *s) +{ + struct nfs4_client *cl = s->sc_client; + + switch (s->sc_type) { + default: + spin_unlock(&cl->cl_lock); + } +} + +static void nfs40_drop_revoked_stid(struct nfs4_client *cl, + stateid_t *stid) +{ + /* NFSv4.0 has no way for the client to tell the server + * that it can forget an admin-revoked stateid. + * So we keep it around until the first time that the + * client uses it, and drop it the first time + * nfserr_admin_revoked is returned. + * For v4.1 and later we wait until explicitly told + * to free the stateid. + */ + if (cl->cl_minorversion == 0) { + struct nfs4_stid *st; + + spin_lock(&cl->cl_lock); + st = find_stateid_locked(cl, stid); + if (st) + nfsd_drop_revoked_stid(st); + else + spin_unlock(&cl->cl_lock); + } +} + static __be32 nfsd4_verify_open_stid(struct nfs4_stid *s) { @@ -4672,6 +4713,10 @@ nfsd4_lock_ol_stateid(struct nfs4_ol_stateid *stp) mutex_lock_nested(&stp->st_mutex, LOCK_STATEID_MUTEX); ret = nfsd4_verify_open_stid(&stp->st_stid); + if (ret == nfserr_admin_revoked) + nfs40_drop_revoked_stid(stp->st_stid.sc_client, + &stp->st_stid.sc_stateid); + if (ret != nfs_ok) mutex_unlock(&stp->st_mutex); return ret; @@ -5256,6 +5301,7 @@ nfs4_check_deleg(struct nfs4_client *cl, struct nfsd4_open *open, } if (deleg->dl_stid.sc_type == NFS4_ADMIN_REVOKED_DELEG_STID) { nfs4_put_stid(&deleg->dl_stid); + nfs40_drop_revoked_stid(cl, &open->op_delegate_stateid); status = nfserr_admin_revoked; goto out; } @@ -6253,6 +6299,43 @@ nfs4_process_client_reaplist(struct list_head *reaplist) } } +static void nfs40_clean_admin_revoked(struct nfsd_net *nn, + struct laundry_time *lt) +{ + struct nfs4_client *clp; + + spin_lock(&nn->client_lock); + if (nn->nfs40_last_revoke == 0 || + nn->nfs40_last_revoke > lt->cutoff) { + spin_unlock(&nn->client_lock); + return; + } + nn->nfs40_last_revoke = 0; + +retry: + list_for_each_entry(clp, &nn->client_lru, cl_lru) { + unsigned long id, tmp; + struct nfs4_stid *stid; + + if (atomic_read(&clp->cl_admin_revoked) == 0) + continue; + + spin_lock(&clp->cl_lock); + idr_for_each_entry_ul(&clp->cl_stateids, stid, tmp, id) + if (stid->sc_type & NFS4_ALL_ADMIN_REVOKED_STIDS) { + refcount_inc(&stid->sc_count); + spin_unlock(&nn->client_lock); + /* this function drops ->cl_lock */ + nfsd_drop_revoked_stid(stid); + nfs4_put_stid(stid); + spin_lock(&nn->client_lock); + goto retry; + } + spin_unlock(&clp->cl_lock); + } + spin_unlock(&nn->client_lock); +} + static time64_t nfs4_laundromat(struct nfsd_net *nn) { @@ -6286,6 +6369,8 @@ nfs4_laundromat(struct nfsd_net *nn) nfs4_get_client_reaplist(nn, &reaplist, <); nfs4_process_client_reaplist(&reaplist); + nfs40_clean_admin_revoked(nn, <); + spin_lock(&state_lock); list_for_each_safe(pos, next, &nn->del_recall_lru) { dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); @@ -6504,6 +6589,9 @@ static __be32 nfsd4_stid_check_stateid_generation(stateid_t *in, struct nfs4_sti if (ret == nfs_ok) ret = check_stateid_generation(in, &s->sc_stateid, has_session); spin_unlock(&s->sc_lock); + if (ret == nfserr_admin_revoked) + nfs40_drop_revoked_stid(s->sc_client, + &s->sc_stateid); return ret; } @@ -6555,6 +6643,8 @@ static __be32 nfsd4_validate_stateid(struct nfs4_client *cl, stateid_t *stateid) } out_unlock: spin_unlock(&cl->cl_lock); + if (status == nfserr_admin_revoked) + nfs40_drop_revoked_stid(cl, stateid); return status; } @@ -6604,6 +6694,7 @@ nfsd4_lookup_stateid(struct nfsd4_compound_state *cstate, return nfserr_bad_stateid; } if (stid->sc_type & NFS4_ALL_ADMIN_REVOKED_STIDS) { + nfs40_drop_revoked_stid(cstate->clp, stateid); nfs4_put_stid(stid); return nfserr_admin_revoked; } @@ -6923,6 +7014,13 @@ nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, nfs4_put_stid(s); ret = nfs_ok; goto out; + case NFS4_ADMIN_REVOKED_STID: + case NFS4_ADMIN_REVOKED_LOCK_STID: + case NFS4_ADMIN_REVOKED_DELEG_STID: + spin_unlock(&s->sc_lock); + nfsd_drop_revoked_stid(s); + ret = nfs_ok; + goto out; /* Default falls through and returns nfserr_bad_stateid */ } spin_unlock(&s->sc_lock); From patchwork Wed Nov 1 00:57:11 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: NeilBrown X-Patchwork-Id: 13442462 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 45559C4332F for ; Wed, 1 Nov 2023 01:01:28 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1376970AbjKABB2 (ORCPT ); Tue, 31 Oct 2023 21:01:28 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:60502 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1376924AbjKABB2 (ORCPT ); Tue, 31 Oct 2023 21:01:28 -0400 Received: from smtp-out1.suse.de (smtp-out1.suse.de [IPv6:2001:67c:2178:6::1c]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 8C337C9 for ; Tue, 31 Oct 2023 18:01:22 -0700 (PDT) Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out1.suse.de (Postfix) with ESMTPS id 4B00D2184F; Wed, 1 Nov 2023 01:01:21 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1698800481; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=Scl/o8gKJcHv4TzzDIWxdel+REbpoagEpcQ1ANoph9E=; b=riY1Cu97Wofn7/Go8f2B7RJ2iiF+AzP6IkqsFUHv1SOLR6rq4pZa2EypGw1wDGocFTKaoQ FFWN+7ajBFiGPtOGgTMc5ZrNN67dwST9R/cTlbOuBLWGeQ3YB4/wqjf3mAg0XN8s09ys+b 2qtPBfw8rNUWzKHXIqn2TZKNPbTRFF0= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1698800481; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=Scl/o8gKJcHv4TzzDIWxdel+REbpoagEpcQ1ANoph9E=; b=vzpVLswD07dwGXjF1UQwJifvIPchgB2fcCbntKEVFhRfxGv2j4CmtkQRMNYs889wrypxot 7D72uFSJC83AKUCw== Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap2.suse-dmz.suse.de (Postfix) with ESMTPS id 9C5CF138EF; Wed, 1 Nov 2023 01:01:17 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id 2eAoFV2jQWUQOwAAMHmgww (envelope-from ); Wed, 01 Nov 2023 01:01:17 +0000 From: NeilBrown To: Chuck Lever , Jeff Layton Cc: linux-nfs@vger.kernel.org, Olga Kornievskaia , Dai Ngo , Tom Talpey Subject: [PATCH 4/6] nfsd: allow lock state ids to be revoked and then freed Date: Wed, 1 Nov 2023 11:57:11 +1100 Message-ID: <20231101010049.27315-5-neilb@suse.de> X-Mailer: git-send-email 2.42.0 In-Reply-To: <20231101010049.27315-1-neilb@suse.de> References: <20231101010049.27315-1-neilb@suse.de> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-nfs@vger.kernel.org Revoking state through 'unlock_filesystem' now revokes any lock states found. When the stateids are then freed by the client, the revoked stateids will be cleaned up correctly. Signed-off-by: NeilBrown --- fs/nfsd/nfs4state.c | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 13484a9cef21..c2e064f6c7c4 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -1708,7 +1708,7 @@ void nfsd4_revoke_states(struct net *net, struct super_block *sb) unsigned int idhashval; unsigned short sc_types; - sc_types = 0; + sc_types = NFS4_LOCK_STID; spin_lock(&nn->client_lock); for (idhashval = 0; idhashval < CLIENT_HASH_MASK; idhashval++) { @@ -1719,8 +1719,33 @@ void nfsd4_revoke_states(struct net *net, struct super_block *sb) struct nfs4_stid *stid = find_one_sb_stid(clp, sb, sc_types); if (stid) { + struct nfs4_ol_stateid *stp; + spin_unlock(&nn->client_lock); switch (stid->sc_type) { + case NFS4_LOCK_STID: + stp = openlockstateid(stid); + mutex_lock_nested(&stp->st_mutex, + LOCK_STATEID_MUTEX); + if (stid->sc_type == NFS4_LOCK_STID) { + struct nfs4_lockowner *lo = + lockowner(stp->st_stateowner); + struct nfsd_file *nf; + + nf = find_any_file(stp->st_stid.sc_file); + if (nf) { + get_file(nf->nf_file); + filp_close(nf->nf_file, + (fl_owner_t)lo); + nfsd_file_put(nf); + } + release_all_access(stp); + stid->sc_type = + NFS4_ADMIN_REVOKED_LOCK_STID; + atomic_inc(&clp->cl_admin_revoked); + } + mutex_unlock(&stp->st_mutex); + break; } nfs4_put_stid(stid); spin_lock(&nn->client_lock); @@ -4656,8 +4681,17 @@ nfsd4_find_existing_open(struct nfs4_file *fp, struct nfsd4_open *open) static void nfsd_drop_revoked_stid(struct nfs4_stid *s) { struct nfs4_client *cl = s->sc_client; + struct nfs4_ol_stateid *stp; + bool unhashed; switch (s->sc_type) { + case NFS4_ADMIN_REVOKED_LOCK_STID: + stp = openlockstateid(s); + unhashed = unhash_lock_stateid(stp); + spin_unlock(&cl->cl_lock); + if (unhashed) + nfs4_put_stid(s); + break; default: spin_unlock(&cl->cl_lock); } From patchwork Wed Nov 1 00:57:12 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: NeilBrown X-Patchwork-Id: 13442463 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id ACB36C4167D for ; Wed, 1 Nov 2023 01:01:35 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1376924AbjKABBe (ORCPT ); Tue, 31 Oct 2023 21:01:34 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:60520 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1376986AbjKABBd (ORCPT ); Tue, 31 Oct 2023 21:01:33 -0400 Received: from smtp-out1.suse.de (smtp-out1.suse.de [195.135.220.28]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id F1660C9 for ; Tue, 31 Oct 2023 18:01:27 -0700 (PDT) Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out1.suse.de (Postfix) with ESMTPS id A70A221A94; Wed, 1 Nov 2023 01:01:26 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1698800486; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=X1rknSURYsxSIyPIoQagbT2dHgoOcSZ3yigXEepbSlI=; b=BtgjDNlte0gPxuwvFQlJhjM3YvKM44SAIAb+xpJNJNuQ+ycus02Jkr+1Jtgj5PoVR+MmuK LkmvmLKn17vLmJVY455PyKJkLysN69D6BpDrnZm5cIRhBlOKqiIZ3kz+vUUjiAjL7mq298 w7IFaQPyMrX1KIr0jwG/eaPmvIo9LVc= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1698800486; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=X1rknSURYsxSIyPIoQagbT2dHgoOcSZ3yigXEepbSlI=; b=chpW62G+if6+fCA+VZbvmXfA25kS8F+2m+ofNwOjZgkhbs5ue7S2c962oRYIftQwgKBNy7 LuCNesbZe9J8SADA== Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap2.suse-dmz.suse.de (Postfix) with ESMTPS id A5D3B138EF; Wed, 1 Nov 2023 01:01:24 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id mcqdF2SjQWUdOwAAMHmgww (envelope-from ); Wed, 01 Nov 2023 01:01:24 +0000 From: NeilBrown To: Chuck Lever , Jeff Layton Cc: linux-nfs@vger.kernel.org, Olga Kornievskaia , Dai Ngo , Tom Talpey Subject: [PATCH 5/6] nfsd: allow open state ids to be revoked and then freed Date: Wed, 1 Nov 2023 11:57:12 +1100 Message-ID: <20231101010049.27315-6-neilb@suse.de> X-Mailer: git-send-email 2.42.0 In-Reply-To: <20231101010049.27315-1-neilb@suse.de> References: <20231101010049.27315-1-neilb@suse.de> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-nfs@vger.kernel.org Revoking state through 'unlock_filesystem' now revokes any open states found. When the stateids are then freed by the client, the revoked stateids will be cleaned up correctly. Possibly the related lock states should be revoked too, but a subsequent patch will do that for all lock state on the superblock. Signed-off-by: NeilBrown --- fs/nfsd/nfs4state.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index c2e064f6c7c4..ed879f68944b 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -1708,7 +1708,7 @@ void nfsd4_revoke_states(struct net *net, struct super_block *sb) unsigned int idhashval; unsigned short sc_types; - sc_types = NFS4_LOCK_STID; + sc_types = NFS4_OPEN_STID | NFS4_LOCK_STID; spin_lock(&nn->client_lock); for (idhashval = 0; idhashval < CLIENT_HASH_MASK; idhashval++) { @@ -1723,6 +1723,18 @@ void nfsd4_revoke_states(struct net *net, struct super_block *sb) spin_unlock(&nn->client_lock); switch (stid->sc_type) { + case NFS4_OPEN_STID: + stp = openlockstateid(stid); + mutex_lock_nested(&stp->st_mutex, + OPEN_STATEID_MUTEX); + if (stid->sc_type == NFS4_OPEN_STID) { + release_all_access(stp); + stid->sc_type = + NFS4_ADMIN_REVOKED_STID; + atomic_inc(&clp->cl_admin_revoked); + } + mutex_unlock(&stp->st_mutex); + break; case NFS4_LOCK_STID: stp = openlockstateid(stid); mutex_lock_nested(&stp->st_mutex, @@ -4681,10 +4693,18 @@ nfsd4_find_existing_open(struct nfs4_file *fp, struct nfsd4_open *open) static void nfsd_drop_revoked_stid(struct nfs4_stid *s) { struct nfs4_client *cl = s->sc_client; + LIST_HEAD(reaplist); struct nfs4_ol_stateid *stp; bool unhashed; switch (s->sc_type) { + case NFS4_ADMIN_REVOKED_STID: + stp = openlockstateid(s); + if (unhash_open_stateid(stp, &reaplist)) + put_ol_stateid_locked(stp, &reaplist); + spin_unlock(&cl->cl_lock); + free_ol_stateid_reaplist(&reaplist); + break; case NFS4_ADMIN_REVOKED_LOCK_STID: stp = openlockstateid(s); unhashed = unhash_lock_stateid(stp); From patchwork Wed Nov 1 00:57:13 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: NeilBrown X-Patchwork-Id: 13442464 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 3AB53C4332F for ; Wed, 1 Nov 2023 01:01:41 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1376989AbjKABBk (ORCPT ); Tue, 31 Oct 2023 21:01:40 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:44294 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1376986AbjKABBj (ORCPT ); Tue, 31 Oct 2023 21:01:39 -0400 Received: from smtp-out1.suse.de (smtp-out1.suse.de [IPv6:2001:67c:2178:6::1c]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2E1FEDA for ; Tue, 31 Oct 2023 18:01:37 -0700 (PDT) Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out1.suse.de (Postfix) with ESMTPS id D901E2184F; Wed, 1 Nov 2023 01:01:35 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1698800495; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=jBjx/eZua0itBAgwFVdiluI795jNhIuQXlz6Q4PUwFc=; b=yN51Jdz6s6nnaQYJdtXOLFUEiekjBdO4VkgdDIi0MaCFiGccZYEEmBr0W9Wnq3KkwhEhrz 71Z0WjSL8OH5+BLpkFLGt/qUOYpzFCHAiGzkysgH2PubSmx7E2qOYVTeU+7as/fSFk/JtK /kPzD6aRqIWvQBTwG0BwP3l82GZ9hYU= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1698800495; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=jBjx/eZua0itBAgwFVdiluI795jNhIuQXlz6Q4PUwFc=; b=7Xih1imGNiLefIgt6RnyCsNkC53GdNvEwniC0eQq4jYb1xhAA7dUioZLyOhUeuVU+BR3Tp reUPkkSxJf4fnwDw== Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap2.suse-dmz.suse.de (Postfix) with ESMTPS id 5BC13138EF; Wed, 1 Nov 2023 01:01:30 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id S+ZjBWqjQWUjOwAAMHmgww (envelope-from ); Wed, 01 Nov 2023 01:01:30 +0000 From: NeilBrown To: Chuck Lever , Jeff Layton Cc: linux-nfs@vger.kernel.org, Olga Kornievskaia , Dai Ngo , Tom Talpey Subject: [PATCH 6/6] nfsd: allow delegation state ids to be revoked and then freed Date: Wed, 1 Nov 2023 11:57:13 +1100 Message-ID: <20231101010049.27315-7-neilb@suse.de> X-Mailer: git-send-email 2.42.0 In-Reply-To: <20231101010049.27315-1-neilb@suse.de> References: <20231101010049.27315-1-neilb@suse.de> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-nfs@vger.kernel.org Revoking state through 'unlock_filesystem' now revokes any delegation states found. When the stateids are then freed by the client, the revoked stateids will be cleaned up correctly. As there is already support for revoking delegations, we build on that for admin-revoking. Signed-off-by: NeilBrown --- fs/nfsd/nfs4state.c | 36 +++++++++++++++++++++++++++++------- 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index ed879f68944b..9fdbdc64262d 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -1367,7 +1367,8 @@ static void destroy_delegation(struct nfs4_delegation *dp) destroy_unhashed_deleg(dp); } -static void revoke_delegation(struct nfs4_delegation *dp) +static void revoke_delegation(struct nfs4_delegation *dp, + unsigned short sc_type) { struct nfs4_client *clp = dp->dl_stid.sc_client; @@ -1375,9 +1376,9 @@ static void revoke_delegation(struct nfs4_delegation *dp) trace_nfsd_stid_revoke(&dp->dl_stid); - if (clp->cl_minorversion) { + if (clp->cl_minorversion || sc_type == NFS4_ADMIN_REVOKED_DELEG_STID) { spin_lock(&clp->cl_lock); - dp->dl_stid.sc_type = NFS4_REVOKED_DELEG_STID; + dp->dl_stid.sc_type = sc_type; refcount_inc(&dp->dl_stid.sc_count); list_add(&dp->dl_recall_lru, &clp->cl_revoked); spin_unlock(&clp->cl_lock); @@ -1708,7 +1709,7 @@ void nfsd4_revoke_states(struct net *net, struct super_block *sb) unsigned int idhashval; unsigned short sc_types; - sc_types = NFS4_OPEN_STID | NFS4_LOCK_STID; + sc_types = NFS4_OPEN_STID | NFS4_LOCK_STID | NFS4_DELEG_STID; spin_lock(&nn->client_lock); for (idhashval = 0; idhashval < CLIENT_HASH_MASK; idhashval++) { @@ -1720,6 +1721,7 @@ void nfsd4_revoke_states(struct net *net, struct super_block *sb) sc_types); if (stid) { struct nfs4_ol_stateid *stp; + struct nfs4_delegation *dp; spin_unlock(&nn->client_lock); switch (stid->sc_type) { @@ -1758,6 +1760,18 @@ void nfsd4_revoke_states(struct net *net, struct super_block *sb) } mutex_unlock(&stp->st_mutex); break; + case NFS4_DELEG_STID: + dp = delegstateid(stid); + spin_lock(&state_lock); + if (!unhash_delegation_locked(dp)) + dp = NULL; + spin_unlock(&state_lock); + if (dp) { + list_del_init(&dp->dl_recall_lru); + revoke_delegation( + dp, NFS4_ADMIN_REVOKED_DELEG_STID); + } + break; } nfs4_put_stid(stid); spin_lock(&nn->client_lock); @@ -4695,6 +4709,7 @@ static void nfsd_drop_revoked_stid(struct nfs4_stid *s) struct nfs4_client *cl = s->sc_client; LIST_HEAD(reaplist); struct nfs4_ol_stateid *stp; + struct nfs4_delegation *dp; bool unhashed; switch (s->sc_type) { @@ -4712,6 +4727,12 @@ static void nfsd_drop_revoked_stid(struct nfs4_stid *s) if (unhashed) nfs4_put_stid(s); break; + case NFS4_ADMIN_REVOKED_DELEG_STID: + dp = delegstateid(s); + list_del_init(&dp->dl_recall_lru); + spin_unlock(&cl->cl_lock); + nfs4_put_stid(s); + break; default: spin_unlock(&cl->cl_lock); } @@ -5073,8 +5094,9 @@ static int nfsd4_cb_recall_done(struct nfsd4_callback *cb, trace_nfsd_cb_recall_done(&dp->dl_stid.sc_stateid, task); if (dp->dl_stid.sc_type == NFS4_CLOSED_DELEG_STID || - dp->dl_stid.sc_type == NFS4_REVOKED_DELEG_STID) - return 1; + dp->dl_stid.sc_type == NFS4_REVOKED_DELEG_STID || + dp->dl_stid.sc_type == NFS4_ADMIN_REVOKED_DELEG_STID) + return 1; switch (task->tk_status) { case 0: @@ -6438,7 +6460,7 @@ nfs4_laundromat(struct nfsd_net *nn) dp = list_first_entry(&reaplist, struct nfs4_delegation, dl_recall_lru); list_del_init(&dp->dl_recall_lru); - revoke_delegation(dp); + revoke_delegation(dp, NFS4_REVOKED_DELEG_STID); } spin_lock(&nn->client_lock);