summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@gmail.com>2018-07-06 16:36:46 -0400
committerKent Overstreet <kent.overstreet@gmail.com>2018-12-27 11:38:15 -0500
commit03df729427e75d1ae10c89a0cf56dfc1273d855f (patch)
tree47fa26c641d938b57971e8b4b89c517dfa2918dc
parentbfe81aea3d8cbe4fa25b376d8cb83131a1218e36 (diff)
bcachefs: Convert bch2_write_inode() to new transactions
Signed-off-by: Kent Overstreet <kent.overstreet@gmail.com>
-rw-r--r--fs/bcachefs/dirent.c7
-rw-r--r--fs/bcachefs/fs-io.c6
-rw-r--r--fs/bcachefs/fs-ioctl.c25
-rw-r--r--fs/bcachefs/fs.c227
-rw-r--r--fs/bcachefs/fs.h10
-rw-r--r--fs/bcachefs/xattr.c2
6 files changed, 169 insertions, 108 deletions
diff --git a/fs/bcachefs/dirent.c b/fs/bcachefs/dirent.c
index 17fbce473995..8cd6049361a2 100644
--- a/fs/bcachefs/dirent.c
+++ b/fs/bcachefs/dirent.c
@@ -355,7 +355,7 @@ u64 bch2_dirent_lookup(struct bch_fs *c, u64 dir_inum,
struct btree_trans trans;
struct btree_iter *iter;
struct bkey_s_c k;
- u64 inum;
+ u64 inum = 0;
bch2_trans_init(&trans, c);
@@ -363,14 +363,13 @@ u64 bch2_dirent_lookup(struct bch_fs *c, u64 dir_inum,
hash_info, dir_inum, name, 0);
if (IS_ERR(iter)) {
BUG_ON(PTR_ERR(iter) == -EINTR);
- bch2_trans_exit(&trans);
- return 0;
+ goto out;
}
k = bch2_btree_iter_peek_slot(iter);
inum = le64_to_cpu(bkey_s_c_to_dirent(k).v->d_inum);
+out:
bch2_trans_exit(&trans);
-
return inum;
}
diff --git a/fs/bcachefs/fs-io.c b/fs/bcachefs/fs-io.c
index ba8d1fb3293d..c7c16839f5ca 100644
--- a/fs/bcachefs/fs-io.c
+++ b/fs/bcachefs/fs-io.c
@@ -193,7 +193,7 @@ static int __must_check bch2_write_inode_size(struct bch_fs *c,
struct bch_inode_info *inode,
loff_t new_size)
{
- return __bch2_write_inode(c, inode, inode_set_size, &new_size);
+ return __bch2_write_inode(c, inode, inode_set_size, &new_size, 0);
}
static void i_sectors_acct(struct bch_fs *c, struct bch_inode_info *inode,
@@ -259,7 +259,7 @@ static int i_sectors_dirty_finish(struct bch_fs *c, struct i_sectors_hook *h)
mutex_lock(&h->inode->ei_update_lock);
i_sectors_acct(c, h->inode, &h->quota_res, h->sectors);
- ret = __bch2_write_inode(c, h->inode, i_sectors_dirty_finish_fn, h);
+ ret = __bch2_write_inode(c, h->inode, i_sectors_dirty_finish_fn, h, 0);
if (!ret && h->new_i_size != U64_MAX)
i_size_write(&h->inode->v, h->new_i_size);
@@ -289,7 +289,7 @@ static int i_sectors_dirty_start(struct bch_fs *c, struct i_sectors_hook *h)
int ret;
mutex_lock(&h->inode->ei_update_lock);
- ret = __bch2_write_inode(c, h->inode, i_sectors_dirty_start_fn, h);
+ ret = __bch2_write_inode(c, h->inode, i_sectors_dirty_start_fn, h, 0);
mutex_unlock(&h->inode->ei_update_lock);
return ret;
diff --git a/fs/bcachefs/fs-ioctl.c b/fs/bcachefs/fs-ioctl.c
index 2c1ecf7732cd..336dbd4ba8d6 100644
--- a/fs/bcachefs/fs-ioctl.c
+++ b/fs/bcachefs/fs-ioctl.c
@@ -87,6 +87,8 @@ void bch2_inode_flags_to_vfs(struct bch_inode_info *inode)
struct flags_set {
unsigned mask;
unsigned flags;
+
+ unsigned projid;
};
static int bch2_inode_flags_set(struct bch_inode_info *inode,
@@ -150,7 +152,7 @@ static int bch2_ioc_setflags(struct bch_fs *c,
}
mutex_lock(&inode->ei_update_lock);
- ret = __bch2_write_inode(c, inode, bch2_inode_flags_set, &s);
+ ret = __bch2_write_inode(c, inode, bch2_inode_flags_set, &s, 0);
if (!ret)
bch2_inode_flags_to_vfs(inode);
@@ -185,9 +187,9 @@ static int bch2_set_projid(struct bch_fs *c,
qid.q[QTYP_PRJ] = projid;
- ret = bch2_quota_transfer(c, 1 << QTYP_PRJ, qid, inode->ei_qid,
- inode->v.i_blocks +
- inode->ei_quota_reserved);
+ return bch2_quota_transfer(c, 1 << QTYP_PRJ, qid, inode->ei_qid,
+ inode->v.i_blocks +
+ inode->ei_quota_reserved);
if (ret)
return ret;
@@ -195,6 +197,17 @@ static int bch2_set_projid(struct bch_fs *c,
return 0;
}
+static int fssetxattr_inode_update_fn(struct bch_inode_info *inode,
+ struct bch_inode_unpacked *bi,
+ void *p)
+{
+ struct flags_set *s = p;
+
+ bi->bi_project = s->projid;
+
+ return bch2_inode_flags_set(inode, bi, p);
+}
+
static int bch2_ioc_fssetxattr(struct bch_fs *c,
struct file *file,
struct bch_inode_info *inode,
@@ -211,6 +224,8 @@ static int bch2_ioc_fssetxattr(struct bch_fs *c,
if (fa.fsx_xflags)
return -EOPNOTSUPP;
+ s.projid = fa.fsx_projid;
+
ret = mnt_want_write_file(file);
if (ret)
return ret;
@@ -226,7 +241,7 @@ static int bch2_ioc_fssetxattr(struct bch_fs *c,
if (ret)
goto err_unlock;
- ret = __bch2_write_inode(c, inode, bch2_inode_flags_set, &s);
+ ret = __bch2_write_inode(c, inode, fssetxattr_inode_update_fn, &s, 0);
if (!ret)
bch2_inode_flags_to_vfs(inode);
err_unlock:
diff --git a/fs/bcachefs/fs.c b/fs/bcachefs/fs.c
index 8d09dcbf4840..1db8af2be79b 100644
--- a/fs/bcachefs/fs.c
+++ b/fs/bcachefs/fs.c
@@ -62,127 +62,156 @@ static void bch2_vfs_inode_init(struct bch_fs *,
* be set explicitly.
*/
-int __must_check __bch2_write_inode(struct bch_fs *c,
- struct bch_inode_info *inode,
- inode_set_fn set,
- void *p)
+void bch2_inode_update_after_write(struct bch_fs *c,
+ struct bch_inode_info *inode,
+ struct bch_inode_unpacked *bi,
+ unsigned fields)
{
- struct btree_iter iter;
- struct bch_inode_unpacked inode_u;
- struct bkey_inode_buf inode_p;
+ set_nlink(&inode->v, bi->bi_flags & BCH_INODE_UNLINKED
+ ? 0
+ : bi->bi_nlink + nlink_bias(inode->v.i_mode));
+
+ if (fields & ATTR_ATIME)
+ inode->v.i_atime = bch2_time_to_timespec(c, bi->bi_atime);
+ if (fields & ATTR_MTIME)
+ inode->v.i_mtime = bch2_time_to_timespec(c, bi->bi_mtime);
+ if (fields & ATTR_CTIME)
+ inode->v.i_ctime = bch2_time_to_timespec(c, bi->bi_ctime);
+
+ inode->ei_inode = *bi;
+ inode->ei_qid = bch_qid(bi);
+}
+
+int __must_check bch2_write_inode_trans(struct btree_trans *trans,
+ struct bch_inode_info *inode,
+ struct bch_inode_unpacked *inode_u,
+ inode_set_fn set,
+ void *p)
+{
+ struct bch_fs *c = trans->c;
+ struct btree_iter *iter;
+ struct bkey_inode_buf *inode_p;
+ struct bkey_s_c k;
u64 inum = inode->v.i_ino;
- unsigned i_nlink = READ_ONCE(inode->v.i_nlink);
int ret;
- /*
- * We can't write an inode with i_nlink == 0 because it's stored biased;
- * however, we don't need to because if i_nlink is 0 the inode is
- * getting deleted when it's evicted.
- */
- if (!i_nlink)
- return 0;
-
lockdep_assert_held(&inode->ei_update_lock);
- bch2_btree_iter_init(&iter, c, BTREE_ID_INODES, POS(inum, 0),
- BTREE_ITER_SLOTS|BTREE_ITER_INTENT);
+ iter = bch2_trans_get_iter(trans, BTREE_ID_INODES, POS(inum, 0),
+ BTREE_ITER_SLOTS|BTREE_ITER_INTENT);
+ if (IS_ERR(iter))
+ return PTR_ERR(iter);
- do {
- struct bkey_s_c k = bch2_btree_iter_peek_slot(&iter);
+ k = bch2_btree_iter_peek_slot(iter);
+ if ((ret = btree_iter_err(k)))
+ return ret;
- if ((ret = btree_iter_err(k)))
- goto out;
+ if (WARN_ONCE(k.k->type != BCH_INODE_FS,
+ "inode %llu not found when updating", inum))
+ return -ENOENT;
- if (WARN_ONCE(k.k->type != BCH_INODE_FS,
- "inode %llu not found when updating", inum)) {
- bch2_btree_iter_unlock(&iter);
- return -ENOENT;
- }
+ ret = bch2_inode_unpack(bkey_s_c_to_inode(k), inode_u);
+ if (WARN_ONCE(ret,
+ "error %i unpacking inode %llu", ret, inum))
+ return -ENOENT;
- ret = bch2_inode_unpack(bkey_s_c_to_inode(k), &inode_u);
- if (WARN_ONCE(ret,
- "error %i unpacking inode %llu", ret, inum)) {
- ret = -ENOENT;
- break;
- }
+ BUG_ON(inode_u->bi_size != inode->ei_inode.bi_size);
- BUG_ON(inode_u.bi_size != inode->ei_inode.bi_size);
+ BUG_ON(inode_u->bi_size != inode->ei_inode.bi_size &&
+ !(inode_u->bi_flags & BCH_INODE_I_SIZE_DIRTY) &&
+ inode_u->bi_size > i_size_read(&inode->v));
- if (set) {
- ret = set(inode, &inode_u, p);
- if (ret)
- goto out;
- }
+ inode_u->bi_mode = inode->v.i_mode;
+ inode_u->bi_uid = i_uid_read(&inode->v);
+ inode_u->bi_gid = i_gid_read(&inode->v);
+ inode_u->bi_project = inode->ei_qid.q[QTYP_PRJ];
+ inode_u->bi_dev = inode->v.i_rdev;
+ inode_u->bi_atime = timespec_to_bch2_time(c, inode->v.i_atime);
+ inode_u->bi_mtime = timespec_to_bch2_time(c, inode->v.i_mtime);
+ inode_u->bi_ctime = timespec_to_bch2_time(c, inode->v.i_ctime);
- BUG_ON(i_nlink < nlink_bias(inode->v.i_mode));
-
- BUG_ON(inode_u.bi_size != inode->ei_inode.bi_size &&
- !(inode_u.bi_flags & BCH_INODE_I_SIZE_DIRTY) &&
- inode_u.bi_size > i_size_read(&inode->v));
-
- inode_u.bi_mode = inode->v.i_mode;
- inode_u.bi_uid = i_uid_read(&inode->v);
- inode_u.bi_gid = i_gid_read(&inode->v);
- inode_u.bi_project = inode->ei_qid.q[QTYP_PRJ];
- inode_u.bi_nlink= i_nlink - nlink_bias(inode->v.i_mode);
- inode_u.bi_dev = inode->v.i_rdev;
- inode_u.bi_atime= timespec_to_bch2_time(c, inode->v.i_atime);
- inode_u.bi_mtime= timespec_to_bch2_time(c, inode->v.i_mtime);
- inode_u.bi_ctime= timespec_to_bch2_time(c, inode->v.i_ctime);
-
- bch2_inode_pack(&inode_p, &inode_u);
-
- ret = bch2_btree_insert_at(c, NULL, NULL,
- &inode->ei_journal_seq,
- BTREE_INSERT_ATOMIC|
- BTREE_INSERT_NOUNLOCK|
- BTREE_INSERT_NOFAIL,
- BTREE_INSERT_ENTRY(&iter, &inode_p.inode.k_i));
- } while (ret == -EINTR);
-
- if (!ret) {
- /*
- * the btree node lock protects inode->ei_inode, not
- * ei_update_lock; this is important for inode updates via
- * bchfs_write_index_update
- */
- inode->ei_inode = inode_u;
- inode->ei_qid = bch_qid(&inode_u);
+ if (set) {
+ ret = set(inode, inode_u, p);
+ if (ret)
+ return ret;
}
-out:
- bch2_btree_iter_unlock(&iter);
+ inode_p = bch2_trans_kmalloc(trans, sizeof(*inode_p));
+ if (IS_ERR(inode_p))
+ return PTR_ERR(inode_p);
+
+ bch2_inode_pack(inode_p, inode_u);
+ bch2_trans_update(trans, iter, &inode_p->inode.k_i, 0);
+ return 0;
+}
+
+int __must_check __bch2_write_inode(struct bch_fs *c,
+ struct bch_inode_info *inode,
+ inode_set_fn set,
+ void *p, unsigned fields)
+{
+ struct btree_trans trans;
+ struct bch_inode_unpacked inode_u;
+ int ret;
+
+ bch2_trans_init(&trans, c);
+retry:
+ bch2_trans_begin(&trans);
+
+ ret = bch2_write_inode_trans(&trans, inode, &inode_u, set, p) ?:
+ bch2_trans_commit(&trans, NULL, NULL,
+ &inode->ei_journal_seq,
+ BTREE_INSERT_ATOMIC|
+ BTREE_INSERT_NOUNLOCK|
+ BTREE_INSERT_NOFAIL);
+ if (ret == -EINTR)
+ goto retry;
+
+ /*
+ * the btree node lock protects inode->ei_inode, not ei_update_lock;
+ * this is important for inode updates via bchfs_write_index_update
+ */
+ if (!ret)
+ bch2_inode_update_after_write(c, inode, &inode_u, fields);
+
+ bch2_trans_exit(&trans);
return ret < 0 ? ret : 0;
}
int __must_check bch2_write_inode(struct bch_fs *c,
struct bch_inode_info *inode)
{
- return __bch2_write_inode(c, inode, NULL, NULL);
+ return __bch2_write_inode(c, inode, NULL, NULL, 0);
}
-static int bch2_inc_nlink(struct bch_fs *c, struct bch_inode_info *inode)
+static int inode_mod_nlink_fn(struct bch_inode_info *inode,
+ struct bch_inode_unpacked *bi, void *p)
+{
+ bi->bi_nlink += (long) p;
+ return 0;
+}
+
+static int bch2_mod_nlink(struct bch_fs *c, struct bch_inode_info *inode,
+ int count)
{
int ret;
mutex_lock(&inode->ei_update_lock);
- inc_nlink(&inode->v);
- ret = bch2_write_inode(c, inode);
+ ret = __bch2_write_inode(c, inode, inode_mod_nlink_fn,
+ (void *)(long) count, 0);
mutex_unlock(&inode->ei_update_lock);
return ret;
}
-static int bch2_dec_nlink(struct bch_fs *c, struct bch_inode_info *inode)
+static int bch2_inc_nlink(struct bch_fs *c, struct bch_inode_info *inode)
{
- int ret = 0;
-
- mutex_lock(&inode->ei_update_lock);
- drop_nlink(&inode->v);
- ret = bch2_write_inode(c, inode);
- mutex_unlock(&inode->ei_update_lock);
+ return bch2_mod_nlink(c, inode, 1);
+}
- return ret;
+static int bch2_dec_nlink(struct bch_fs *c, struct bch_inode_info *inode)
+{
+ return bch2_mod_nlink(c, inode, -1);
}
static struct inode *bch2_vfs_inode_get(struct bch_fs *c, u64 inum)
@@ -987,24 +1016,20 @@ static void bch2_vfs_inode_init(struct bch_fs *c,
struct bch_inode_info *inode,
struct bch_inode_unpacked *bi)
{
+ bch2_inode_update_after_write(c, inode, bi, ~0);
+
inode->v.i_mode = bi->bi_mode;
i_uid_write(&inode->v, bi->bi_uid);
i_gid_write(&inode->v, bi->bi_gid);
inode->v.i_blocks = bi->bi_sectors;
inode->v.i_ino = bi->bi_inum;
- set_nlink(&inode->v, bi->bi_nlink + nlink_bias(inode->v.i_mode));
inode->v.i_rdev = bi->bi_dev;
inode->v.i_generation = bi->bi_generation;
inode->v.i_size = bi->bi_size;
- inode->v.i_atime = bch2_time_to_timespec(c, bi->bi_atime);
- inode->v.i_mtime = bch2_time_to_timespec(c, bi->bi_mtime);
- inode->v.i_ctime = bch2_time_to_timespec(c, bi->bi_ctime);
inode->ei_journal_seq = 0;
inode->ei_quota_reserved = 0;
- inode->ei_qid = bch_qid(bi);
inode->ei_str_hash = bch2_hash_info_init(c, bi);
- inode->ei_inode = *bi;
bch2_inode_flags_to_vfs(inode);
@@ -1059,6 +1084,19 @@ static void bch2_destroy_inode(struct inode *vinode)
call_rcu(&vinode->i_rcu, bch2_i_callback);
}
+static int inode_update_times_fn(struct bch_inode_info *inode,
+ struct bch_inode_unpacked *bi,
+ void *p)
+{
+ struct bch_fs *c = inode->v.i_sb->s_fs_info;
+
+ bi->bi_atime = timespec_to_bch2_time(c, inode->v.i_atime);
+ bi->bi_mtime = timespec_to_bch2_time(c, inode->v.i_mtime);
+ bi->bi_ctime = timespec_to_bch2_time(c, inode->v.i_ctime);
+
+ return 0;
+}
+
static int bch2_vfs_write_inode(struct inode *vinode,
struct writeback_control *wbc)
{
@@ -1067,7 +1105,8 @@ static int bch2_vfs_write_inode(struct inode *vinode,
int ret;
mutex_lock(&inode->ei_update_lock);
- ret = bch2_write_inode(c, inode);
+ ret = __bch2_write_inode(c, inode, inode_update_times_fn, NULL,
+ ATTR_ATIME|ATTR_MTIME|ATTR_CTIME);
mutex_unlock(&inode->ei_update_lock);
if (c->opts.journal_flush_disabled)
diff --git a/fs/bcachefs/fs.h b/fs/bcachefs/fs.h
index fbbc7a3a3cb7..e2fc2706da44 100644
--- a/fs/bcachefs/fs.h
+++ b/fs/bcachefs/fs.h
@@ -51,8 +51,16 @@ struct bch_inode_unpacked;
typedef int (*inode_set_fn)(struct bch_inode_info *,
struct bch_inode_unpacked *, void *);
+void bch2_inode_update_after_write(struct bch_fs *,
+ struct bch_inode_info *,
+ struct bch_inode_unpacked *,
+ unsigned);
+int __must_check bch2_write_inode_trans(struct btree_trans *,
+ struct bch_inode_info *,
+ struct bch_inode_unpacked *,
+ inode_set_fn, void *);
int __must_check __bch2_write_inode(struct bch_fs *, struct bch_inode_info *,
- inode_set_fn, void *);
+ inode_set_fn, void *, unsigned);
int __must_check bch2_write_inode(struct bch_fs *,
struct bch_inode_info *);
diff --git a/fs/bcachefs/xattr.c b/fs/bcachefs/xattr.c
index 27eb889b76e4..7d0fee3a8c04 100644
--- a/fs/bcachefs/xattr.c
+++ b/fs/bcachefs/xattr.c
@@ -433,7 +433,7 @@ static int bch2_xattr_bcachefs_set(const struct xattr_handler *handler,
}
mutex_lock(&inode->ei_update_lock);
- ret = __bch2_write_inode(c, inode, inode_opt_set_fn, &s);
+ ret = __bch2_write_inode(c, inode, inode_opt_set_fn, &s, 0);
mutex_unlock(&inode->ei_update_lock);
if (value &&