From patchwork Thu Jan 27 04:58:10 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: NeilBrown X-Patchwork-Id: 12726272 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 7469AC433EF for ; Thu, 27 Jan 2022 04:59:45 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236090AbiA0E7o (ORCPT ); Wed, 26 Jan 2022 23:59:44 -0500 Received: from smtp-out1.suse.de ([195.135.220.28]:43898 "EHLO smtp-out1.suse.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236089AbiA0E7o (ORCPT ); Wed, 26 Jan 2022 23:59:44 -0500 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 111B0210DE; Thu, 27 Jan 2022 04:59:43 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1643259583; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=nv39KLywJE4fn+ScVf89K78uppvf03mcFnjKLSGd8UA=; b=GHm88u2GcU5z2I50XGC42QpHHBzBdd//C0U8x6pdNrJY5IDuG1vomCVeV4Vuufht4MWJ+8 VZzij7grbFRoWjh3i7F/iudXVf24PpAujamJf05O7XiJCtQmSwz2BYmVrWuZaAMuIBxzFh EGwSaoNHUw205sVOX/sUOwKriAFCJsY= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1643259583; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=nv39KLywJE4fn+ScVf89K78uppvf03mcFnjKLSGd8UA=; b=uOXX10nA1yJPK/aeJ/K3m9K0GeNJje5RB8HX9GyxG/twWrPn6Kh6ihyJoCTUMSPJAS84YF hEILmjarXCKMhUDQ== 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 3577513BCF; Thu, 27 Jan 2022 04:59:41 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id AD2kOL0m8mEwVgAAMHmgww (envelope-from ); Thu, 27 Jan 2022 04:59:41 +0000 Subject: [PATCH 1/4] nfsd: prepare for supporting admin-revocation of state From: NeilBrown To: Chuck Lever Cc: linux-nfs@vger.kernel.org Date: Thu, 27 Jan 2022 15:58:10 +1100 Message-ID: <164325949068.23133.18090188528073823272.stgit@noble.brown> In-Reply-To: <164325908579.23133.4781039121536248752.stgit@noble.brown> References: <164325908579.23133.4781039121536248752.stgit@noble.brown> User-Agent: StGit/0.23 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 - 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 Reported-by: kernel test robot Reported-by: kernel test robot --- fs/nfsd/nfs4layouts.c | 2 + fs/nfsd/nfs4state.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++-- fs/nfsd/nfsctl.c | 1 + fs/nfsd/nfsd.h | 1 + fs/nfsd/state.h | 26 ++++++++++------ 5 files changed, 95 insertions(+), 14 deletions(-) diff --git a/fs/nfsd/nfs4layouts.c b/fs/nfsd/nfs4layouts.c index 6d1b5bb051c5..211cbefa3d80 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 72900b89cf84..ad02b4ebe1b6 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -1575,6 +1575,55 @@ 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 = 0; + struct nfs4_stid *stid; + + spin_lock(&clp->cl_lock); + do { + id += 1; + stid = idr_get_next_ul(&clp->cl_stateids, &id); + } while (stid && + !((stid->sc_type & sc_types) && + stid->sc_file->fi_inode->i_sb == sb)); + if (stid) + refcount_inc(&stid->sc_count); + 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) { @@ -2349,7 +2398,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; @@ -2426,6 +2476,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; @@ -3907,6 +3959,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); @@ -4361,6 +4415,11 @@ nfsd4_verify_open_stid(struct nfs4_stid *s) break; case NFS4_REVOKED_DELEG_STID: ret = nfserr_deleg_revoked; + break; + case NFS4_ADMIN_REVOKED_STID: + case NFS4_ADMIN_REVOKED_DELEG_STID: + ret = nfserr_admin_revoked; + break; } return ret; } @@ -4893,6 +4952,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) { @@ -5840,6 +5904,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)); @@ -5858,7 +5927,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; @@ -5893,6 +5962,10 @@ nfsd4_lookup_stateid(struct nfsd4_compound_state *cstate, return nfserr_deleg_revoked; return nfserr_bad_stateid; } + if (((*s)->sc_type == NFS4_ADMIN_REVOKED_DELEG_STID) && !return_revoked) { + nfs4_put_stid(*s); + return nfserr_admin_revoked; + } return nfs_ok; } @@ -6235,7 +6308,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 b9f27fbcd768..2576867bdd71 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c @@ -323,6 +323,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 3e5008b475ff..f9fdd4078956 100644 --- a/fs/nfsd/nfsd.h +++ b/fs/nfsd/nfsd.h @@ -249,6 +249,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 95457cfd37fc..8429bfc06216 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h @@ -88,17 +88,20 @@ 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) stateid_t sc_stateid; spinlock_t sc_lock; struct nfs4_client *sc_client; @@ -330,6 +333,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; @@ -645,7 +649,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 *)); @@ -691,6 +695,8 @@ static inline void get_nfs4_file(struct nfs4_file *fi) } struct nfsd_file *find_any_file(struct nfs4_file *f); +void nfsd4_revoke_states(struct net *net, struct super_block *sb); + /* grace period management */ void nfsd4_end_grace(struct nfsd_net *nn); From patchwork Thu Jan 27 04:58:10 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: NeilBrown X-Patchwork-Id: 12726273 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 CA5CCC433F5 for ; Thu, 27 Jan 2022 04:59:49 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236095AbiA0E7t (ORCPT ); Wed, 26 Jan 2022 23:59:49 -0500 Received: from smtp-out1.suse.de ([195.135.220.28]:44080 "EHLO smtp-out1.suse.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236089AbiA0E7s (ORCPT ); Wed, 26 Jan 2022 23:59:48 -0500 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 4D1DA218E8; Thu, 27 Jan 2022 04:59:47 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1643259587; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=GAyYFRFbqVs3ttE0Jk7k2AtafmN+5suCAaIm4G6c5tw=; b=t9EQEs7W2KGsC5CHJNjgXIM7w1R70D0UOTY4yVSaFj3xH1KMh1WzBCb3dNLu5CU5Its7zK DW+FrtRqCCbIB80vA7NDpwhLcd04VB++McwyrM2U8mPeOqqHtIlvEf00isHphFqtRP0zs8 ZwMj2vTRq0dZqiyP3ph6a5KlRXufjek= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1643259587; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=GAyYFRFbqVs3ttE0Jk7k2AtafmN+5suCAaIm4G6c5tw=; b=tJX87Npq1XHSHtbMO0/Ln7bwvWkisZY9b28PBOSzrvgHlg6VMvGZO31gavIPB89uqVS5CD qk06RxnysdG2RXBQ== 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 74C3C13BCF; Thu, 27 Jan 2022 04:59:46 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id f3N0DMIm8mE2VgAAMHmgww (envelope-from ); Thu, 27 Jan 2022 04:59:46 +0000 Subject: [PATCH 2/4] nfsd: allow open state ids to be revoked and then freed From: NeilBrown To: Chuck Lever Cc: linux-nfs@vger.kernel.org Date: Thu, 27 Jan 2022 15:58:10 +1100 Message-ID: <164325949070.23133.8692722614255991208.stgit@noble.brown> In-Reply-To: <164325908579.23133.4781039121536248752.stgit@noble.brown> References: <164325908579.23133.4781039121536248752.stgit@noble.brown> User-Agent: StGit/0.23 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 | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index ad02b4ebe1b6..6854546ebd08 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -1113,6 +1113,9 @@ nfs4_put_stid(struct nfs4_stid *s) return; } idr_remove(&clp->cl_stateids, s->sc_stateid.si_opaque.so_id); + if (s->sc_type == NFS4_ADMIN_REVOKED_STID) + atomic_dec(&clp->cl_admin_revoked); + s->sc_type = 0; nfs4_free_cpntf_statelist(clp->net, s); spin_unlock(&clp->cl_lock); s->sc_free(s); @@ -1165,6 +1168,9 @@ static void destroy_unhashed_deleg(struct nfs4_delegation *dp) void nfs4_unhash_stid(struct nfs4_stid *s) { + struct nfs4_client *clp = s->sc_client; + if (s->sc_type == NFS4_ADMIN_REVOKED_STID) + atomic_dec(&clp->cl_admin_revoked); s->sc_type = 0; } @@ -1431,6 +1437,9 @@ static void put_ol_stateid_locked(struct nfs4_ol_stateid *stp, } idr_remove(&clp->cl_stateids, s->sc_stateid.si_opaque.so_id); + if (s->sc_type == NFS4_ADMIN_REVOKED_STID) + atomic_dec(&clp->cl_admin_revoked); + s->sc_type = 0; list_add(&stp->st_locks, reaplist); } @@ -1601,7 +1610,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_OPEN_STID; spin_lock(&nn->client_lock); for (idhashval = 0; idhashval < CLIENT_HASH_MASK; idhashval++) { @@ -1612,8 +1621,23 @@ 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_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); + /* FIXME revoke the locks */ + } + mutex_unlock(&stp->st_mutex); + break; } nfs4_put_stid(stid); spin_lock(&nn->client_lock); @@ -6235,6 +6259,8 @@ nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, stateid_t *stateid = &free_stateid->fr_stateid; struct nfs4_stid *s; struct nfs4_delegation *dp; + struct nfs4_ol_stateid *stp; + LIST_HEAD(reaplist); struct nfs4_client *cl = cstate->clp; __be32 ret = nfserr_bad_stateid; @@ -6259,6 +6285,15 @@ nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, spin_unlock(&cl->cl_lock); ret = nfsd4_free_lock_stateid(stateid, s); goto out; + case NFS4_ADMIN_REVOKED_STID: + stp = openlockstateid(s); + spin_unlock(&s->sc_lock); + if (unhash_open_stateid(stp, &reaplist)) + put_ol_stateid_locked(stp, &reaplist); + spin_unlock(&cl->cl_lock); + free_ol_stateid_reaplist(&reaplist); + ret = nfs_ok; + goto out; case NFS4_REVOKED_DELEG_STID: spin_unlock(&s->sc_lock); dp = delegstateid(s); From patchwork Thu Jan 27 04:58:10 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: NeilBrown X-Patchwork-Id: 12726274 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 CEAC5C433F5 for ; Thu, 27 Jan 2022 04:59:54 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236094AbiA0E7y (ORCPT ); Wed, 26 Jan 2022 23:59:54 -0500 Received: from smtp-out1.suse.de ([195.135.220.28]:44292 "EHLO smtp-out1.suse.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236089AbiA0E7x (ORCPT ); Wed, 26 Jan 2022 23:59:53 -0500 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 86D21218E5; Thu, 27 Jan 2022 04:59:52 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1643259592; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=UAcoqnGfYY92T5Yl55ulImuSDryAJbckhKtTwJNvkMA=; b=bb5UOy1BjOJfduYRJAco+LZWeW9AXZWDwAHc+pMb4rF4b5okGCNQLYwL9rDhFKgrujdjsM eQf/+L/XwaIqCbsFnjaGHb5MtedqSwygo+YuFGm4pyiohanQmxiuIB2BgrRALIl7sOMP9i 1ror4Cc9VbgkSL2UjmTLAcW3KkcQymg= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1643259592; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=UAcoqnGfYY92T5Yl55ulImuSDryAJbckhKtTwJNvkMA=; b=JTA3oFALjpR4DafEcgFrpe9lbEeFIn7ekF2b4eAsLibPEfdwC3JivN0I2j0pqhvoyxtJjq VhSpONwRc61BsIBw== 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 AF4DB13BCF; Thu, 27 Jan 2022 04:59:51 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id IsPnGscm8mFIVgAAMHmgww (envelope-from ); Thu, 27 Jan 2022 04:59:51 +0000 Subject: [PATCH 3/4] nfsd: allow lock state ids to be revoked and then freed From: NeilBrown To: Chuck Lever Cc: linux-nfs@vger.kernel.org Date: Thu, 27 Jan 2022 15:58:10 +1100 Message-ID: <164325949071.23133.937354557714722900.stgit@noble.brown> In-Reply-To: <164325908579.23133.4781039121536248752.stgit@noble.brown> References: <164325908579.23133.4781039121536248752.stgit@noble.brown> User-Agent: StGit/0.23 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 | 43 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 6854546ebd08..b1dc8ed1d356 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -1113,7 +1113,8 @@ nfs4_put_stid(struct nfs4_stid *s) return; } idr_remove(&clp->cl_stateids, s->sc_stateid.si_opaque.so_id); - if (s->sc_type == NFS4_ADMIN_REVOKED_STID) + if (s->sc_type == NFS4_ADMIN_REVOKED_STID || + s->sc_type == NFS4_ADMIN_REVOKED_LOCK_STID) atomic_dec(&clp->cl_admin_revoked); s->sc_type = 0; nfs4_free_cpntf_statelist(clp->net, s); @@ -1169,7 +1170,8 @@ static void destroy_unhashed_deleg(struct nfs4_delegation *dp) void nfs4_unhash_stid(struct nfs4_stid *s) { struct nfs4_client *clp = s->sc_client; - if (s->sc_type == NFS4_ADMIN_REVOKED_STID) + if (s->sc_type == NFS4_ADMIN_REVOKED_STID || + s->sc_type == NFS4_ADMIN_REVOKED_LOCK_STID) atomic_dec(&clp->cl_admin_revoked); s->sc_type = 0; } @@ -1437,7 +1439,8 @@ static void put_ol_stateid_locked(struct nfs4_ol_stateid *stp, } idr_remove(&clp->cl_stateids, s->sc_stateid.si_opaque.so_id); - if (s->sc_type == NFS4_ADMIN_REVOKED_STID) + if (s->sc_type == NFS4_ADMIN_REVOKED_STID || + s->sc_type == NFS4_ADMIN_REVOKED_LOCK_STID) atomic_dec(&clp->cl_admin_revoked); s->sc_type = 0; list_add(&stp->st_locks, reaplist); @@ -1610,7 +1613,7 @@ void nfsd4_revoke_states(struct net *net, struct super_block *sb) unsigned int idhashval; unsigned short sc_types; - sc_types = NFS4_OPEN_STID; + sc_types = NFS4_OPEN_STID | NFS4_LOCK_STID; spin_lock(&nn->client_lock); for (idhashval = 0; idhashval < CLIENT_HASH_MASK; idhashval++) { @@ -1638,6 +1641,28 @@ void nfsd4_revoke_states(struct net *net, struct super_block *sb) } mutex_unlock(&stp->st_mutex); break; + 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); @@ -6261,6 +6286,7 @@ nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfs4_delegation *dp; struct nfs4_ol_stateid *stp; LIST_HEAD(reaplist); + bool unhashed; struct nfs4_client *cl = cstate->clp; __be32 ret = nfserr_bad_stateid; @@ -6294,6 +6320,15 @@ nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, free_ol_stateid_reaplist(&reaplist); ret = nfs_ok; goto out; + case NFS4_ADMIN_REVOKED_LOCK_STID: + stp = openlockstateid(s); + spin_unlock(&s->sc_lock); + unhashed = unhash_lock_stateid(stp); + spin_unlock(&cl->cl_lock); + if (unhashed) + nfs4_put_stid(s); + ret = nfs_ok; + goto out; case NFS4_REVOKED_DELEG_STID: spin_unlock(&s->sc_lock); dp = delegstateid(s); From patchwork Thu Jan 27 04:58:10 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: NeilBrown X-Patchwork-Id: 12726275 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 DB341C433EF for ; Thu, 27 Jan 2022 04:59:58 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236096AbiA0E76 (ORCPT ); Wed, 26 Jan 2022 23:59:58 -0500 Received: from smtp-out2.suse.de ([195.135.220.29]:44512 "EHLO smtp-out2.suse.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236089AbiA0E75 (ORCPT ); Wed, 26 Jan 2022 23:59:57 -0500 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 E65561F76C; Thu, 27 Jan 2022 04:59:56 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1643259596; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=214MWV4/ujoXspMn/NBhkpmz5/Of2CqMEcAdw8yB8MI=; b=GaycZBcm/ALgeug1VIuZMqwfD6R3xJRcZCZ43rq0LcZ014nILzaxIsI5zP4JBYAQGvAtRz dwbkHX6L9H7k5dFXttMhhaqugiyJLvz0cS2qcKEI3cfCxPFwkDpV3T5HvHI0Yvyz4ghR+v QPlF+ByP8w0Nsu7JMfUr4OIM6g+lIxI= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1643259596; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=214MWV4/ujoXspMn/NBhkpmz5/Of2CqMEcAdw8yB8MI=; b=+1cUAFyDiBfFArZiCWWsbbu+RNLq7Wj5hhTrZr8osYsv+GjaNzrSGQL2KOo5uaAGDtuBMP +tNGkAPqxWhQ+BAQ== 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 1BEB413BCF; Thu, 27 Jan 2022 04:59:55 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id IrJdMssm8mFPVgAAMHmgww (envelope-from ); Thu, 27 Jan 2022 04:59:55 +0000 Subject: [PATCH 4/4] nfsd: allow delegation state ids to be revoked and then freed From: NeilBrown To: Chuck Lever Cc: linux-nfs@vger.kernel.org Date: Thu, 27 Jan 2022 15:58:10 +1100 Message-ID: <164325949071.23133.1986695063796663253.stgit@noble.brown> In-Reply-To: <164325908579.23133.4781039121536248752.stgit@noble.brown> References: <164325908579.23133.4781039121536248752.stgit@noble.brown> User-Agent: StGit/0.23 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 | 35 ++++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index b1dc8ed1d356..30177554a77b 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -1270,14 +1270,15 @@ 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; WARN_ON(!list_empty(&dp->dl_recall_lru)); - if (clp->cl_minorversion) { - dp->dl_stid.sc_type = NFS4_REVOKED_DELEG_STID; + if (clp->cl_minorversion || sc_type == NFS4_ADMIN_REVOKED_DELEG_STID) { + dp->dl_stid.sc_type = sc_type; refcount_inc(&dp->dl_stid.sc_count); spin_lock(&clp->cl_lock); list_add(&dp->dl_recall_lru, &clp->cl_revoked); @@ -1613,7 +1614,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++) { @@ -1625,6 +1626,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) { @@ -1663,6 +1665,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); @@ -4742,8 +4756,9 @@ static int nfsd4_cb_recall_done(struct nfsd4_callback *cb, struct nfs4_delegation *dp = cb_to_delegation(cb); 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: @@ -5770,7 +5785,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); @@ -5988,8 +6003,9 @@ nfsd4_lookup_stateid(struct nfsd4_compound_state *cstate, */ if (typemask & NFS4_REVOKED_DELEG_STID) return_revoked = true; - else if (typemask & NFS4_DELEG_STID) - typemask |= NFS4_REVOKED_DELEG_STID; + if (typemask & NFS4_DELEG_STID) + typemask |= NFS4_REVOKED_DELEG_STID | + NFS4_ADMIN_REVOKED_DELEG_STID; if (ZERO_STATEID(stateid) || ONE_STATEID(stateid) || CLOSE_STATEID(stateid)) @@ -6330,6 +6346,7 @@ nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, ret = nfs_ok; goto out; case NFS4_REVOKED_DELEG_STID: + case NFS4_ADMIN_REVOKED_DELEG_STID: spin_unlock(&s->sc_lock); dp = delegstateid(s); list_del_init(&dp->dl_recall_lru);