* [PATCH v5 1/2] ceph: switch to vfs_inode_has_locks() to fix file lock bug [not found] <20221214033512.659913-1-xiubli@redhat.com> @ 2022-12-14 3:35 ` xiubli 2022-12-15 13:20 ` Ilya Dryomov 2022-12-14 3:35 ` [PATCH v5 2/2] ceph: add ceph specific member support for file_lock xiubli 1 sibling, 1 reply; 5+ messages in thread From: xiubli @ 2022-12-14 3:35 UTC (permalink / raw) To: jlayton, idryomov, ceph-devel Cc: mchangir, lhenriques, viro, linux-kernel, linux-fsdevel, Xiubo Li, stable From: Xiubo Li <xiubli@redhat.com> For the POSIX locks they are using the same owner, which is the thread id. And multiple POSIX locks could be merged into single one, so when checking whether the 'file' has locks may fail. For a file where some openers use locking and others don't is a really odd usage pattern though. Locks are like stoplights -- they only work if everyone pays attention to them. Just switch ceph_get_caps() to check whether any locks are set on the inode. If there are POSIX/OFD/FLOCK locks on the file at the time, we should set CHECK_FILELOCK, regardless of what fd was used to set the lock. Cc: stable@vger.kernel.org Cc: Jeff Layton <jlayton@kernel.org> Fixes: ff5d913dfc71 ("ceph: return -EIO if read/write against filp that lost file locks") Reviewed-by: Jeff Layton <jlayton@kernel.org> Signed-off-by: Xiubo Li <xiubli@redhat.com> --- fs/ceph/caps.c | 2 +- fs/ceph/locks.c | 4 ---- fs/ceph/super.h | 1 - 3 files changed, 1 insertion(+), 6 deletions(-) diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c index 065e9311b607..948136f81fc8 100644 --- a/fs/ceph/caps.c +++ b/fs/ceph/caps.c @@ -2964,7 +2964,7 @@ int ceph_get_caps(struct file *filp, int need, int want, loff_t endoff, int *got while (true) { flags &= CEPH_FILE_MODE_MASK; - if (atomic_read(&fi->num_locks)) + if (vfs_inode_has_locks(inode)) flags |= CHECK_FILELOCK; _got = 0; ret = try_get_cap_refs(inode, need, want, endoff, diff --git a/fs/ceph/locks.c b/fs/ceph/locks.c index 3e2843e86e27..b191426bf880 100644 --- a/fs/ceph/locks.c +++ b/fs/ceph/locks.c @@ -32,18 +32,14 @@ void __init ceph_flock_init(void) static void ceph_fl_copy_lock(struct file_lock *dst, struct file_lock *src) { - struct ceph_file_info *fi = dst->fl_file->private_data; struct inode *inode = file_inode(dst->fl_file); atomic_inc(&ceph_inode(inode)->i_filelock_ref); - atomic_inc(&fi->num_locks); } static void ceph_fl_release_lock(struct file_lock *fl) { - struct ceph_file_info *fi = fl->fl_file->private_data; struct inode *inode = file_inode(fl->fl_file); struct ceph_inode_info *ci = ceph_inode(inode); - atomic_dec(&fi->num_locks); if (atomic_dec_and_test(&ci->i_filelock_ref)) { /* clear error when all locks are released */ spin_lock(&ci->i_ceph_lock); diff --git a/fs/ceph/super.h b/fs/ceph/super.h index 14454f464029..e7662ff6f149 100644 --- a/fs/ceph/super.h +++ b/fs/ceph/super.h @@ -804,7 +804,6 @@ struct ceph_file_info { struct list_head rw_contexts; u32 filp_gen; - atomic_t num_locks; }; struct ceph_dir_file_info { -- 2.31.1 ^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH v5 1/2] ceph: switch to vfs_inode_has_locks() to fix file lock bug 2022-12-14 3:35 ` [PATCH v5 1/2] ceph: switch to vfs_inode_has_locks() to fix file lock bug xiubli @ 2022-12-15 13:20 ` Ilya Dryomov 2022-12-16 0:23 ` Xiubo Li 2022-12-16 6:45 ` Xiubo Li 0 siblings, 2 replies; 5+ messages in thread From: Ilya Dryomov @ 2022-12-15 13:20 UTC (permalink / raw) To: xiubli Cc: jlayton, ceph-devel, mchangir, lhenriques, viro, linux-kernel, linux-fsdevel, stable On Wed, Dec 14, 2022 at 4:35 AM <xiubli@redhat.com> wrote: > > From: Xiubo Li <xiubli@redhat.com> > > For the POSIX locks they are using the same owner, which is the > thread id. And multiple POSIX locks could be merged into single one, > so when checking whether the 'file' has locks may fail. > > For a file where some openers use locking and others don't is a > really odd usage pattern though. Locks are like stoplights -- they > only work if everyone pays attention to them. > > Just switch ceph_get_caps() to check whether any locks are set on > the inode. If there are POSIX/OFD/FLOCK locks on the file at the > time, we should set CHECK_FILELOCK, regardless of what fd was used > to set the lock. > > Cc: stable@vger.kernel.org > Cc: Jeff Layton <jlayton@kernel.org> > Fixes: ff5d913dfc71 ("ceph: return -EIO if read/write against filp that lost file locks") > Reviewed-by: Jeff Layton <jlayton@kernel.org> > Signed-off-by: Xiubo Li <xiubli@redhat.com> > --- > fs/ceph/caps.c | 2 +- > fs/ceph/locks.c | 4 ---- > fs/ceph/super.h | 1 - > 3 files changed, 1 insertion(+), 6 deletions(-) > > diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c > index 065e9311b607..948136f81fc8 100644 > --- a/fs/ceph/caps.c > +++ b/fs/ceph/caps.c > @@ -2964,7 +2964,7 @@ int ceph_get_caps(struct file *filp, int need, int want, loff_t endoff, int *got > > while (true) { > flags &= CEPH_FILE_MODE_MASK; > - if (atomic_read(&fi->num_locks)) > + if (vfs_inode_has_locks(inode)) > flags |= CHECK_FILELOCK; > _got = 0; > ret = try_get_cap_refs(inode, need, want, endoff, > diff --git a/fs/ceph/locks.c b/fs/ceph/locks.c > index 3e2843e86e27..b191426bf880 100644 > --- a/fs/ceph/locks.c > +++ b/fs/ceph/locks.c > @@ -32,18 +32,14 @@ void __init ceph_flock_init(void) > > static void ceph_fl_copy_lock(struct file_lock *dst, struct file_lock *src) > { > - struct ceph_file_info *fi = dst->fl_file->private_data; > struct inode *inode = file_inode(dst->fl_file); > atomic_inc(&ceph_inode(inode)->i_filelock_ref); > - atomic_inc(&fi->num_locks); > } > > static void ceph_fl_release_lock(struct file_lock *fl) > { > - struct ceph_file_info *fi = fl->fl_file->private_data; > struct inode *inode = file_inode(fl->fl_file); > struct ceph_inode_info *ci = ceph_inode(inode); > - atomic_dec(&fi->num_locks); > if (atomic_dec_and_test(&ci->i_filelock_ref)) { > /* clear error when all locks are released */ > spin_lock(&ci->i_ceph_lock); > diff --git a/fs/ceph/super.h b/fs/ceph/super.h > index 14454f464029..e7662ff6f149 100644 > --- a/fs/ceph/super.h > +++ b/fs/ceph/super.h > @@ -804,7 +804,6 @@ struct ceph_file_info { > struct list_head rw_contexts; > > u32 filp_gen; > - atomic_t num_locks; > }; > > struct ceph_dir_file_info { > -- > 2.31.1 > Hi Xiubo, You marked this for stable but there is an obvious dependency on vfs_inode_has_locks() that just got merged for 6.2-rc1. Are you intending to take it into stable kernels as well? Thanks, Ilya ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH v5 1/2] ceph: switch to vfs_inode_has_locks() to fix file lock bug 2022-12-15 13:20 ` Ilya Dryomov @ 2022-12-16 0:23 ` Xiubo Li 2022-12-16 6:45 ` Xiubo Li 1 sibling, 0 replies; 5+ messages in thread From: Xiubo Li @ 2022-12-16 0:23 UTC (permalink / raw) To: Ilya Dryomov Cc: jlayton, ceph-devel, mchangir, lhenriques, viro, linux-kernel, linux-fsdevel, stable On 15/12/2022 21:20, Ilya Dryomov wrote: > On Wed, Dec 14, 2022 at 4:35 AM <xiubli@redhat.com> wrote: >> From: Xiubo Li <xiubli@redhat.com> >> >> For the POSIX locks they are using the same owner, which is the >> thread id. And multiple POSIX locks could be merged into single one, >> so when checking whether the 'file' has locks may fail. >> >> For a file where some openers use locking and others don't is a >> really odd usage pattern though. Locks are like stoplights -- they >> only work if everyone pays attention to them. >> >> Just switch ceph_get_caps() to check whether any locks are set on >> the inode. If there are POSIX/OFD/FLOCK locks on the file at the >> time, we should set CHECK_FILELOCK, regardless of what fd was used >> to set the lock. >> >> Cc: stable@vger.kernel.org >> Cc: Jeff Layton <jlayton@kernel.org> >> Fixes: ff5d913dfc71 ("ceph: return -EIO if read/write against filp that lost file locks") >> Reviewed-by: Jeff Layton <jlayton@kernel.org> >> Signed-off-by: Xiubo Li <xiubli@redhat.com> >> --- >> fs/ceph/caps.c | 2 +- >> fs/ceph/locks.c | 4 ---- >> fs/ceph/super.h | 1 - >> 3 files changed, 1 insertion(+), 6 deletions(-) >> >> diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c >> index 065e9311b607..948136f81fc8 100644 >> --- a/fs/ceph/caps.c >> +++ b/fs/ceph/caps.c >> @@ -2964,7 +2964,7 @@ int ceph_get_caps(struct file *filp, int need, int want, loff_t endoff, int *got >> >> while (true) { >> flags &= CEPH_FILE_MODE_MASK; >> - if (atomic_read(&fi->num_locks)) >> + if (vfs_inode_has_locks(inode)) >> flags |= CHECK_FILELOCK; >> _got = 0; >> ret = try_get_cap_refs(inode, need, want, endoff, >> diff --git a/fs/ceph/locks.c b/fs/ceph/locks.c >> index 3e2843e86e27..b191426bf880 100644 >> --- a/fs/ceph/locks.c >> +++ b/fs/ceph/locks.c >> @@ -32,18 +32,14 @@ void __init ceph_flock_init(void) >> >> static void ceph_fl_copy_lock(struct file_lock *dst, struct file_lock *src) >> { >> - struct ceph_file_info *fi = dst->fl_file->private_data; >> struct inode *inode = file_inode(dst->fl_file); >> atomic_inc(&ceph_inode(inode)->i_filelock_ref); >> - atomic_inc(&fi->num_locks); >> } >> >> static void ceph_fl_release_lock(struct file_lock *fl) >> { >> - struct ceph_file_info *fi = fl->fl_file->private_data; >> struct inode *inode = file_inode(fl->fl_file); >> struct ceph_inode_info *ci = ceph_inode(inode); >> - atomic_dec(&fi->num_locks); >> if (atomic_dec_and_test(&ci->i_filelock_ref)) { >> /* clear error when all locks are released */ >> spin_lock(&ci->i_ceph_lock); >> diff --git a/fs/ceph/super.h b/fs/ceph/super.h >> index 14454f464029..e7662ff6f149 100644 >> --- a/fs/ceph/super.h >> +++ b/fs/ceph/super.h >> @@ -804,7 +804,6 @@ struct ceph_file_info { >> struct list_head rw_contexts; >> >> u32 filp_gen; >> - atomic_t num_locks; >> }; >> >> struct ceph_dir_file_info { >> -- >> 2.31.1 >> > Hi Xiubo, > > You marked this for stable but there is an obvious dependency on > vfs_inode_has_locks() that just got merged for 6.2-rc1. Are you > intending to take it into stable kernels as well? Hi Ilya, Yes. I can do the backport of these 3 patches myself later. Thanks - Xiubo > Thanks, > > Ilya > ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH v5 1/2] ceph: switch to vfs_inode_has_locks() to fix file lock bug 2022-12-15 13:20 ` Ilya Dryomov 2022-12-16 0:23 ` Xiubo Li @ 2022-12-16 6:45 ` Xiubo Li 1 sibling, 0 replies; 5+ messages in thread From: Xiubo Li @ 2022-12-16 6:45 UTC (permalink / raw) To: Ilya Dryomov Cc: jlayton, ceph-devel, mchangir, lhenriques, viro, linux-kernel, linux-fsdevel, stable On 15/12/2022 21:20, Ilya Dryomov wrote: > On Wed, Dec 14, 2022 at 4:35 AM <xiubli@redhat.com> wrote: >> From: Xiubo Li <xiubli@redhat.com> >> >> For the POSIX locks they are using the same owner, which is the >> thread id. And multiple POSIX locks could be merged into single one, >> so when checking whether the 'file' has locks may fail. >> >> For a file where some openers use locking and others don't is a >> really odd usage pattern though. Locks are like stoplights -- they >> only work if everyone pays attention to them. >> >> Just switch ceph_get_caps() to check whether any locks are set on >> the inode. If there are POSIX/OFD/FLOCK locks on the file at the >> time, we should set CHECK_FILELOCK, regardless of what fd was used >> to set the lock. >> >> Cc: stable@vger.kernel.org >> Cc: Jeff Layton <jlayton@kernel.org> >> Fixes: ff5d913dfc71 ("ceph: return -EIO if read/write against filp that lost file locks") >> Reviewed-by: Jeff Layton <jlayton@kernel.org> >> Signed-off-by: Xiubo Li <xiubli@redhat.com> >> --- >> fs/ceph/caps.c | 2 +- >> fs/ceph/locks.c | 4 ---- >> fs/ceph/super.h | 1 - >> 3 files changed, 1 insertion(+), 6 deletions(-) >> >> diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c >> index 065e9311b607..948136f81fc8 100644 >> --- a/fs/ceph/caps.c >> +++ b/fs/ceph/caps.c >> @@ -2964,7 +2964,7 @@ int ceph_get_caps(struct file *filp, int need, int want, loff_t endoff, int *got >> >> while (true) { >> flags &= CEPH_FILE_MODE_MASK; >> - if (atomic_read(&fi->num_locks)) >> + if (vfs_inode_has_locks(inode)) >> flags |= CHECK_FILELOCK; >> _got = 0; >> ret = try_get_cap_refs(inode, need, want, endoff, >> diff --git a/fs/ceph/locks.c b/fs/ceph/locks.c >> index 3e2843e86e27..b191426bf880 100644 >> --- a/fs/ceph/locks.c >> +++ b/fs/ceph/locks.c >> @@ -32,18 +32,14 @@ void __init ceph_flock_init(void) >> >> static void ceph_fl_copy_lock(struct file_lock *dst, struct file_lock *src) >> { >> - struct ceph_file_info *fi = dst->fl_file->private_data; >> struct inode *inode = file_inode(dst->fl_file); >> atomic_inc(&ceph_inode(inode)->i_filelock_ref); >> - atomic_inc(&fi->num_locks); >> } >> >> static void ceph_fl_release_lock(struct file_lock *fl) >> { >> - struct ceph_file_info *fi = fl->fl_file->private_data; >> struct inode *inode = file_inode(fl->fl_file); >> struct ceph_inode_info *ci = ceph_inode(inode); >> - atomic_dec(&fi->num_locks); >> if (atomic_dec_and_test(&ci->i_filelock_ref)) { >> /* clear error when all locks are released */ >> spin_lock(&ci->i_ceph_lock); >> diff --git a/fs/ceph/super.h b/fs/ceph/super.h >> index 14454f464029..e7662ff6f149 100644 >> --- a/fs/ceph/super.h >> +++ b/fs/ceph/super.h >> @@ -804,7 +804,6 @@ struct ceph_file_info { >> struct list_head rw_contexts; >> >> u32 filp_gen; >> - atomic_t num_locks; >> }; >> >> struct ceph_dir_file_info { >> -- >> 2.31.1 >> > Hi Xiubo, > > You marked this for stable but there is an obvious dependency on > vfs_inode_has_locks() that just got merged for 6.2-rc1. Are you > intending to take it into stable kernels as well? In the testing branch I just removed the stable list and will do the backport myself. Thanks - Xiubo > Thanks, > > Ilya > ^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH v5 2/2] ceph: add ceph specific member support for file_lock [not found] <20221214033512.659913-1-xiubli@redhat.com> 2022-12-14 3:35 ` [PATCH v5 1/2] ceph: switch to vfs_inode_has_locks() to fix file lock bug xiubli @ 2022-12-14 3:35 ` xiubli 1 sibling, 0 replies; 5+ messages in thread From: xiubli @ 2022-12-14 3:35 UTC (permalink / raw) To: jlayton, idryomov, ceph-devel Cc: mchangir, lhenriques, viro, linux-kernel, linux-fsdevel, Xiubo Li, stable From: Xiubo Li <xiubli@redhat.com> When ceph releasing the file_lock it will try to get the inode pointer from the fl->fl_file, which the memory could already be released by another thread in filp_close(). Because in VFS layer the fl->fl_file doesn't increase the file's reference counter. Will switch to use ceph dedicate lock info to track the inode. And in ceph_fl_release_lock() we should skip all the operations if the fl->fl_u.ceph_fl.fl_inode is not set, which should come from the request file_lock. And we will set fl->fl_u.ceph_fl.fl_inode when inserting it to the inode lock list, which is when copying the lock. Cc: stable@vger.kernel.org Cc: Jeff Layton <jlayton@kernel.org> URL: https://tracker.ceph.com/issues/57986 Reviewed-by: Jeff Layton <jlayton@kernel.org> Signed-off-by: Xiubo Li <xiubli@redhat.com> --- fs/ceph/locks.c | 20 ++++++++++++++++++-- include/linux/fs.h | 3 +++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/fs/ceph/locks.c b/fs/ceph/locks.c index b191426bf880..d31955f710f2 100644 --- a/fs/ceph/locks.c +++ b/fs/ceph/locks.c @@ -34,18 +34,34 @@ static void ceph_fl_copy_lock(struct file_lock *dst, struct file_lock *src) { struct inode *inode = file_inode(dst->fl_file); atomic_inc(&ceph_inode(inode)->i_filelock_ref); + dst->fl_u.ceph.inode = igrab(inode); } +/* + * Do not use the 'fl->fl_file' in release function, which + * is possibly already released by another thread. + */ static void ceph_fl_release_lock(struct file_lock *fl) { - struct inode *inode = file_inode(fl->fl_file); - struct ceph_inode_info *ci = ceph_inode(inode); + struct inode *inode = fl->fl_u.ceph.inode; + struct ceph_inode_info *ci; + + /* + * If inode is NULL it should be a request file_lock, + * nothing we can do. + */ + if (!inode) + return; + + ci = ceph_inode(inode); if (atomic_dec_and_test(&ci->i_filelock_ref)) { /* clear error when all locks are released */ spin_lock(&ci->i_ceph_lock); ci->i_ceph_flags &= ~CEPH_I_ERROR_FILELOCK; spin_unlock(&ci->i_ceph_lock); } + fl->fl_u.ceph.inode = NULL; + iput(inode); } static const struct file_lock_operations ceph_fl_lock_ops = { diff --git a/include/linux/fs.h b/include/linux/fs.h index 7b52fdfb6da0..c92c62f1e964 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1119,6 +1119,9 @@ struct file_lock { int state; /* state of grant or error if -ve */ unsigned int debug_id; } afs; + struct { + struct inode *inode; + } ceph; } fl_u; } __randomize_layout; -- 2.31.1 ^ permalink raw reply related [flat|nested] 5+ messages in thread
end of thread, other threads:[~2022-12-16 6:46 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <20221214033512.659913-1-xiubli@redhat.com>
2022-12-14 3:35 ` [PATCH v5 1/2] ceph: switch to vfs_inode_has_locks() to fix file lock bug xiubli
2022-12-15 13:20 ` Ilya Dryomov
2022-12-16 0:23 ` Xiubo Li
2022-12-16 6:45 ` Xiubo Li
2022-12-14 3:35 ` [PATCH v5 2/2] ceph: add ceph specific member support for file_lock xiubli
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox