ceph: hold i_ceph_lock when removing caps for freeing inode [Linux 4.14.136]

This Linux kernel change "ceph: hold i_ceph_lock when removing caps for freeing inode" is included in the Linux 4.14.136 release. This change is authored by Yan, Zheng <zyan [at] redhat.com> on Thu May 23 11:01:37 2019 +0800. The commit for this change in Linux stable tree is 13d2558 (patch) which is from upstream commit d6e4781. The same Linux upstream change may have been applied to various maintained Linux releases and you can find all Linux releases containing changes from upstream d6e4781.

ceph: hold i_ceph_lock when removing caps for freeing inode

commit d6e47819721ae2d9d090058ad5570a66f3c42e39 upstream.

ceph_d_revalidate(, LOOKUP_RCU) may call __ceph_caps_issued_mask()
on a freeing inode.

Signed-off-by: "Yan, Zheng" <zyan@redhat.com>
Reviewed-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

There are 7 lines of Linux source code added/deleted in this change. Code changes to Linux kernel are as follows.

 fs/ceph/caps.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c
index 92eb9c3..238d243 100644
--- a/fs/ceph/caps.c
+++ b/fs/ceph/caps.c
@@ -1119,20 +1119,23 @@ static int send_cap_msg(struct cap_msg_args *arg)
 }

 /*
- * Queue cap releases when an inode is dropped from our cache.  Since
- * inode is about to be destroyed, there is no need for i_ceph_lock.
+ * Queue cap releases when an inode is dropped from our cache.
  */
 void ceph_queue_caps_release(struct inode *inode)
 {
    struct ceph_inode_info *ci = ceph_inode(inode);
    struct rb_node *p;

+   /* lock i_ceph_lock, because ceph_d_revalidate(..., LOOKUP_RCU)
+    * may call __ceph_caps_issued_mask() on a freeing inode. */
+   spin_lock(&ci->i_ceph_lock);
    p = rb_first(&ci->i_caps);
    while (p) {
        struct ceph_cap *cap = rb_entry(p, struct ceph_cap, ci_node);
        p = rb_next(p);
        __ceph_remove_cap(cap, true);
    }
+   spin_unlock(&ci->i_ceph_lock);
 }

 /*

Leave a Reply

Your email address will not be published. Required fields are marked *