Message ID | 20230720125806.1385279-3-aahringo@redhat.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | [RFC,v6.5-rc2,1/3] fs: lockd: nlm_blocked list race fixes | expand |
On Thu, 2023-07-20 at 08:58 -0400, Alexander Aring wrote: > This patch reverts mostly commit 40595cdc93ed ("nfs: block notification > on fs with its own ->lock") and introduces an EXPORT_OP_SAFE_ASYNC_LOCK > export flag to signal that the "own ->lock" implementation supports > async lock requests. The only main user is DLM that is used by GFS2 and > OCFS2 filesystem. Those implement their own lock() implementation and > return FILE_LOCK_DEFERRED as return value. Since commit 40595cdc93ed > ("nfs: block notification on fs with its own ->lock") the DLM > implementation were never updated. This patch should prepare for DLM > to set the EXPORT_OP_SAFE_ASYNC_LOCK export flag and update the DLM > plock implementation regarding to it. > > Signed-off-by: Alexander Aring <aahringo@redhat.com> > --- > fs/lockd/svclock.c | 5 ++--- > fs/nfsd/nfs4state.c | 11 ++++++++--- > include/linux/exportfs.h | 1 + > 3 files changed, 11 insertions(+), 6 deletions(-) > > diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c > index 62ef27a69a9e..54a67bd33843 100644 > --- a/fs/lockd/svclock.c > +++ b/fs/lockd/svclock.c > @@ -483,9 +483,7 @@ nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file, > struct nlm_host *host, struct nlm_lock *lock, int wait, > struct nlm_cookie *cookie, int reclaim) > { > -#if IS_ENABLED(CONFIG_SUNRPC_DEBUG) > struct inode *inode = nlmsvc_file_inode(file); > -#endif > struct nlm_block *block = NULL; > int error; > int mode; > @@ -499,7 +497,8 @@ nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file, > (long long)lock->fl.fl_end, > wait); > > - if (nlmsvc_file_file(file)->f_op->lock) { > + if (!(inode->i_sb->s_export_op->flags & EXPORT_OP_SAFE_ASYNC_LOCK) && > + nlmsvc_file_file(file)->f_op->lock) { > async_block = wait; > wait = 0; > } > diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c > index 6e61fa3acaf1..efcea229d640 100644 > --- a/fs/nfsd/nfs4state.c > +++ b/fs/nfsd/nfs4state.c > @@ -7432,6 +7432,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, > struct nfsd4_blocked_lock *nbl = NULL; > struct file_lock *file_lock = NULL; > struct file_lock *conflock = NULL; > + struct super_block *sb; > __be32 status = 0; > int lkflg; > int err; > @@ -7453,6 +7454,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, > dprintk("NFSD: nfsd4_lock: permission denied!\n"); > return status; > } > + sb = cstate->current_fh.fh_dentry->d_sb; > > if (lock->lk_is_new) { > if (nfsd4_has_session(cstate)) > @@ -7504,7 +7506,8 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, > fp = lock_stp->st_stid.sc_file; > switch (lock->lk_type) { > case NFS4_READW_LT: > - if (nfsd4_has_session(cstate)) > + if (sb->s_export_op->flags & EXPORT_OP_SAFE_ASYNC_LOCK && This will break existing filesystems that don't set the new flag. Maybe you also need to test for the filesystem's ->lock operation here too? This might be more nicely expressed in a helper function. > + nfsd4_has_session(cstate)) > fl_flags |= FL_SLEEP; > fallthrough; > case NFS4_READ_LT: > @@ -7516,7 +7519,8 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, > fl_type = F_RDLCK; > break; > case NFS4_WRITEW_LT: > - if (nfsd4_has_session(cstate)) > + if (sb->s_export_op->flags & EXPORT_OP_SAFE_ASYNC_LOCK && > + nfsd4_has_session(cstate)) > fl_flags |= FL_SLEEP; > fallthrough; > case NFS4_WRITE_LT: > @@ -7544,7 +7548,8 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, > * for file locks), so don't attempt blocking lock notifications > * on those filesystems: > */ > - if (nf->nf_file->f_op->lock) > + if (!(sb->s_export_op->flags & EXPORT_OP_SAFE_ASYNC_LOCK) && > + nf->nf_file->f_op->lock) > fl_flags &= ~FL_SLEEP; > > nbl = find_or_allocate_block(lock_sop, &fp->fi_fhandle, nn); > diff --git a/include/linux/exportfs.h b/include/linux/exportfs.h > index 11fbd0ee1370..da742abbaf3e 100644 > --- a/include/linux/exportfs.h > +++ b/include/linux/exportfs.h > @@ -224,6 +224,7 @@ struct export_operations { > atomic attribute updates > */ > #define EXPORT_OP_FLUSH_ON_CLOSE (0x20) /* fs flushes file data on close */ > +#define EXPORT_OP_SAFE_ASYNC_LOCK (0x40) /* fs can do async lock request */ > unsigned long flags; > }; >
Hi, On Fri, Jul 21, 2023 at 1:46 PM Jeff Layton <jlayton@kernel.org> wrote: > > On Thu, 2023-07-20 at 08:58 -0400, Alexander Aring wrote: > > This patch reverts mostly commit 40595cdc93ed ("nfs: block notification > > on fs with its own ->lock") and introduces an EXPORT_OP_SAFE_ASYNC_LOCK > > export flag to signal that the "own ->lock" implementation supports > > async lock requests. The only main user is DLM that is used by GFS2 and > > OCFS2 filesystem. Those implement their own lock() implementation and > > return FILE_LOCK_DEFERRED as return value. Since commit 40595cdc93ed > > ("nfs: block notification on fs with its own ->lock") the DLM > > implementation were never updated. This patch should prepare for DLM > > to set the EXPORT_OP_SAFE_ASYNC_LOCK export flag and update the DLM > > plock implementation regarding to it. > > > > Signed-off-by: Alexander Aring <aahringo@redhat.com> > > --- > > fs/lockd/svclock.c | 5 ++--- > > fs/nfsd/nfs4state.c | 11 ++++++++--- > > include/linux/exportfs.h | 1 + > > 3 files changed, 11 insertions(+), 6 deletions(-) > > > > diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c > > index 62ef27a69a9e..54a67bd33843 100644 > > --- a/fs/lockd/svclock.c > > +++ b/fs/lockd/svclock.c > > @@ -483,9 +483,7 @@ nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file, > > struct nlm_host *host, struct nlm_lock *lock, int wait, > > struct nlm_cookie *cookie, int reclaim) > > { > > -#if IS_ENABLED(CONFIG_SUNRPC_DEBUG) > > struct inode *inode = nlmsvc_file_inode(file); > > -#endif > > struct nlm_block *block = NULL; > > int error; > > int mode; > > @@ -499,7 +497,8 @@ nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file, > > (long long)lock->fl.fl_end, > > wait); > > > > - if (nlmsvc_file_file(file)->f_op->lock) { > > + if (!(inode->i_sb->s_export_op->flags & EXPORT_OP_SAFE_ASYNC_LOCK) && > > + nlmsvc_file_file(file)->f_op->lock) { > > async_block = wait; > > wait = 0; > > } > > diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c > > index 6e61fa3acaf1..efcea229d640 100644 > > --- a/fs/nfsd/nfs4state.c > > +++ b/fs/nfsd/nfs4state.c > > @@ -7432,6 +7432,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, > > struct nfsd4_blocked_lock *nbl = NULL; > > struct file_lock *file_lock = NULL; > > struct file_lock *conflock = NULL; > > + struct super_block *sb; > > __be32 status = 0; > > int lkflg; > > int err; > > @@ -7453,6 +7454,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, > > dprintk("NFSD: nfsd4_lock: permission denied!\n"); > > return status; > > } > > + sb = cstate->current_fh.fh_dentry->d_sb; > > > > if (lock->lk_is_new) { > > if (nfsd4_has_session(cstate)) > > @@ -7504,7 +7506,8 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, > > fp = lock_stp->st_stid.sc_file; > > switch (lock->lk_type) { > > case NFS4_READW_LT: > > - if (nfsd4_has_session(cstate)) > > + if (sb->s_export_op->flags & EXPORT_OP_SAFE_ASYNC_LOCK && > > This will break existing filesystems that don't set the new flag. Maybe > you also need to test for the filesystem's ->lock operation here too? > yes. > This might be more nicely expressed in a helper function. ok. - Alex
diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c index 62ef27a69a9e..54a67bd33843 100644 --- a/fs/lockd/svclock.c +++ b/fs/lockd/svclock.c @@ -483,9 +483,7 @@ nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file, struct nlm_host *host, struct nlm_lock *lock, int wait, struct nlm_cookie *cookie, int reclaim) { -#if IS_ENABLED(CONFIG_SUNRPC_DEBUG) struct inode *inode = nlmsvc_file_inode(file); -#endif struct nlm_block *block = NULL; int error; int mode; @@ -499,7 +497,8 @@ nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file, (long long)lock->fl.fl_end, wait); - if (nlmsvc_file_file(file)->f_op->lock) { + if (!(inode->i_sb->s_export_op->flags & EXPORT_OP_SAFE_ASYNC_LOCK) && + nlmsvc_file_file(file)->f_op->lock) { async_block = wait; wait = 0; } diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 6e61fa3acaf1..efcea229d640 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -7432,6 +7432,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_blocked_lock *nbl = NULL; struct file_lock *file_lock = NULL; struct file_lock *conflock = NULL; + struct super_block *sb; __be32 status = 0; int lkflg; int err; @@ -7453,6 +7454,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, dprintk("NFSD: nfsd4_lock: permission denied!\n"); return status; } + sb = cstate->current_fh.fh_dentry->d_sb; if (lock->lk_is_new) { if (nfsd4_has_session(cstate)) @@ -7504,7 +7506,8 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, fp = lock_stp->st_stid.sc_file; switch (lock->lk_type) { case NFS4_READW_LT: - if (nfsd4_has_session(cstate)) + if (sb->s_export_op->flags & EXPORT_OP_SAFE_ASYNC_LOCK && + nfsd4_has_session(cstate)) fl_flags |= FL_SLEEP; fallthrough; case NFS4_READ_LT: @@ -7516,7 +7519,8 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, fl_type = F_RDLCK; break; case NFS4_WRITEW_LT: - if (nfsd4_has_session(cstate)) + if (sb->s_export_op->flags & EXPORT_OP_SAFE_ASYNC_LOCK && + nfsd4_has_session(cstate)) fl_flags |= FL_SLEEP; fallthrough; case NFS4_WRITE_LT: @@ -7544,7 +7548,8 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, * for file locks), so don't attempt blocking lock notifications * on those filesystems: */ - if (nf->nf_file->f_op->lock) + if (!(sb->s_export_op->flags & EXPORT_OP_SAFE_ASYNC_LOCK) && + nf->nf_file->f_op->lock) fl_flags &= ~FL_SLEEP; nbl = find_or_allocate_block(lock_sop, &fp->fi_fhandle, nn); diff --git a/include/linux/exportfs.h b/include/linux/exportfs.h index 11fbd0ee1370..da742abbaf3e 100644 --- a/include/linux/exportfs.h +++ b/include/linux/exportfs.h @@ -224,6 +224,7 @@ struct export_operations { atomic attribute updates */ #define EXPORT_OP_FLUSH_ON_CLOSE (0x20) /* fs flushes file data on close */ +#define EXPORT_OP_SAFE_ASYNC_LOCK (0x40) /* fs can do async lock request */ unsigned long flags; };
This patch reverts mostly commit 40595cdc93ed ("nfs: block notification on fs with its own ->lock") and introduces an EXPORT_OP_SAFE_ASYNC_LOCK export flag to signal that the "own ->lock" implementation supports async lock requests. The only main user is DLM that is used by GFS2 and OCFS2 filesystem. Those implement their own lock() implementation and return FILE_LOCK_DEFERRED as return value. Since commit 40595cdc93ed ("nfs: block notification on fs with its own ->lock") the DLM implementation were never updated. This patch should prepare for DLM to set the EXPORT_OP_SAFE_ASYNC_LOCK export flag and update the DLM plock implementation regarding to it. Signed-off-by: Alexander Aring <aahringo@redhat.com> --- fs/lockd/svclock.c | 5 ++--- fs/nfsd/nfs4state.c | 11 ++++++++--- include/linux/exportfs.h | 1 + 3 files changed, 11 insertions(+), 6 deletions(-)