bcachefs: Use ei_update_lock consistently
authorKent Overstreet <kent.overstreet@gmail.com>
Sat, 21 Jul 2018 02:23:42 +0000 (22:23 -0400)
committerKent Overstreet <kent.overstreet@linux.dev>
Sun, 22 Oct 2023 21:08:07 +0000 (17:08 -0400)
This is prep work for using deferred btree updates for inode updates -
the way inodes are done now we're relying on btree locking for ei_inode
and ei_update_lock could probably be removed, but it'll actually be
needed when we switch to deferred updates.

Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
fs/bcachefs/acl.c
fs/bcachefs/fs.c

index c81e5365ec84e9618185f08e16bc9983f244673b..2856736f72245c6510f995f595143ff49c92cb45 100644 (file)
@@ -304,13 +304,14 @@ int bch2_set_acl(struct mnt_idmap *idmap,
        umode_t mode = inode->v.i_mode;
        int ret;
 
+       mutex_lock(&inode->ei_update_lock);
+       bch2_trans_init(&trans, c);
+
        if (type == ACL_TYPE_ACCESS && acl) {
                ret = posix_acl_update_mode(idmap, &inode->v, &mode, &acl);
                if (ret)
-                       return ret;
+                       goto err;
        }
-
-       bch2_trans_init(&trans, c);
 retry:
        bch2_trans_begin(&trans);
 
@@ -336,6 +337,7 @@ retry:
        set_cached_acl(&inode->v, type, acl);
 err:
        bch2_trans_exit(&trans);
+       mutex_unlock(&inode->ei_update_lock);
 
        return ret;
 }
index f10ee147d389cb73905393a4cf5964a2f51c375d..a4d82252bc49df398e6d87404defcd45999701fd 100644 (file)
@@ -51,6 +51,30 @@ static void journal_seq_copy(struct bch_inode_info *dst,
        } while ((v = cmpxchg(&dst->ei_journal_seq, old, journal_seq)) != old);
 }
 
+static inline int ptrcmp(void *l, void *r)
+{
+       return (l > r) - (l < r);
+}
+
+#define __bch2_lock_inodes(_lock, ...)                                 \
+do {                                                                   \
+       struct bch_inode_info *a[] = { NULL, __VA_ARGS__ };             \
+       unsigned i;                                                     \
+                                                                       \
+       bubble_sort(&a[1], ARRAY_SIZE(a) - 1 , ptrcmp);                 \
+                                                                       \
+       for (i = ARRAY_SIZE(a) - 1; a[i]; --i)                          \
+               if (a[i] != a[i - 1]) {                                 \
+                       if (_lock)                                      \
+                               mutex_lock_nested(&a[i]->ei_update_lock, i);\
+                       else                                            \
+                               mutex_unlock(&a[i]->ei_update_lock);    \
+               }                                                       \
+} while (0)
+
+#define bch2_lock_inodes(...)  __bch2_lock_inodes(true, __VA_ARGS__)
+#define bch2_unlock_inodes(...)        __bch2_lock_inodes(false, __VA_ARGS__)
+
 static void __pagecache_lock_put(struct pagecache_lock *lock, long i)
 {
        BUG_ON(atomic_long_read(&lock->v) == 0);
@@ -161,6 +185,8 @@ int __must_check bch2_write_inode_trans(struct btree_trans *trans,
        struct bkey_inode_buf *inode_p;
        int ret;
 
+       lockdep_assert_held(&inode->ei_update_lock);
+
        iter = bch2_trans_get_iter(trans, BTREE_ID_INODES,
                        POS(inode->v.i_ino, 0),
                        BTREE_ITER_SLOTS|BTREE_ITER_INTENT);
@@ -422,6 +448,9 @@ out:
        posix_acl_release(acl);
        return inode;
 err_trans:
+       if (!tmpfile)
+               mutex_unlock(&dir->ei_update_lock);
+
        bch2_trans_exit(&trans);
        make_bad_inode(&inode->v);
        iput(&inode->v);
@@ -490,6 +519,7 @@ static int __bch2_link(struct bch_fs *c,
        struct bch_inode_unpacked inode_u;
        int ret;
 
+       mutex_lock(&inode->ei_update_lock);
        bch2_trans_init(&trans, c);
 retry:
        bch2_trans_begin(&trans);
@@ -515,6 +545,7 @@ retry:
                bch2_inode_update_after_write(c, inode, &inode_u, ATTR_CTIME);
 
        bch2_trans_exit(&trans);
+       mutex_unlock(&inode->ei_update_lock);
        return ret;
 }
 
@@ -575,6 +606,7 @@ static int bch2_unlink(struct inode *vdir, struct dentry *dentry)
        struct btree_trans trans;
        int ret;
 
+       bch2_lock_inodes(dir, inode);
        bch2_trans_init(&trans, c);
 retry:
        bch2_trans_begin(&trans);
@@ -607,6 +639,7 @@ retry:
                                      ATTR_MTIME);
 err:
        bch2_trans_exit(&trans);
+       bch2_unlock_inodes(dir, inode);
 
        return ret;
 }
@@ -771,6 +804,11 @@ static int bch2_rename2(struct mnt_idmap *idmap,
                        return ret;
        }
 
+       bch2_lock_inodes(i.src_dir,
+                        i.dst_dir,
+                        i.src_inode,
+                        i.dst_inode);
+
        bch2_trans_init(&trans, c);
 retry:
        bch2_trans_begin(&trans);
@@ -818,6 +856,10 @@ retry:
                                              ATTR_CTIME);
 err:
        bch2_trans_exit(&trans);
+       bch2_unlock_inodes(i.src_dir,
+                          i.dst_dir,
+                          i.src_inode,
+                          i.dst_inode);
 
        return ret;
 }