diff options
author | Jeff Layton <jlayton@kernel.org> | 2022-06-03 16:39:57 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2022-08-25 11:40:13 +0200 |
commit | f546faa216d0f53a42ca73ba1fd8c48765b22d77 (patch) | |
tree | b6082f6aec01626c876a7ba0e301c547ec203ef0 | |
parent | 3e7ee4dd1ea43831935c0af39302788d67397584 (diff) | |
download | linux-stable-f546faa216d0f53a42ca73ba1fd8c48765b22d77.tar.gz linux-stable-f546faa216d0f53a42ca73ba1fd8c48765b22d77.tar.bz2 linux-stable-f546faa216d0f53a42ca73ba1fd8c48765b22d77.zip |
ceph: don't leak snap_rwsem in handle_cap_grant
commit 58dd4385577ed7969b80cdc9e2a31575aba6c712 upstream.
When handle_cap_grant is called on an IMPORT op, then the snap_rwsem is
held and the function is expected to release it before returning. It
currently fails to do that in all cases which could lead to a deadlock.
Fixes: 6f05b30ea063 ("ceph: reset i_requested_max_size if file write is not wanted")
Link: https://tracker.ceph.com/issues/55857
Signed-off-by: Jeff Layton <jlayton@kernel.org>
Reviewed-by: Luís Henriques <lhenriques@suse.de>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r-- | fs/ceph/caps.c | 27 |
1 files changed, 13 insertions, 14 deletions
diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c index d1faa9d2f1e8..883bb91ee257 100644 --- a/fs/ceph/caps.c +++ b/fs/ceph/caps.c @@ -3543,24 +3543,23 @@ static void handle_cap_grant(struct inode *inode, fill_inline = true; } - if (ci->i_auth_cap == cap && - le32_to_cpu(grant->op) == CEPH_CAP_OP_IMPORT) { - if (newcaps & ~extra_info->issued) - wake = true; + if (le32_to_cpu(grant->op) == CEPH_CAP_OP_IMPORT) { + if (ci->i_auth_cap == cap) { + if (newcaps & ~extra_info->issued) + wake = true; + + if (ci->i_requested_max_size > max_size || + !(le32_to_cpu(grant->wanted) & CEPH_CAP_ANY_FILE_WR)) { + /* re-request max_size if necessary */ + ci->i_requested_max_size = 0; + wake = true; + } - if (ci->i_requested_max_size > max_size || - !(le32_to_cpu(grant->wanted) & CEPH_CAP_ANY_FILE_WR)) { - /* re-request max_size if necessary */ - ci->i_requested_max_size = 0; - wake = true; + ceph_kick_flushing_inode_caps(session, ci); } - - ceph_kick_flushing_inode_caps(session, ci); - spin_unlock(&ci->i_ceph_lock); up_read(&session->s_mdsc->snap_rwsem); - } else { - spin_unlock(&ci->i_ceph_lock); } + spin_unlock(&ci->i_ceph_lock); if (fill_inline) ceph_fill_inline_data(inode, NULL, extra_info->inline_data, |