summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fs/bcachefs/acl.c75
-rw-r--r--fs/bcachefs/acl.h22
-rw-r--r--fs/bcachefs/dirent.c289
-rw-r--r--fs/bcachefs/dirent.h12
-rw-r--r--fs/bcachefs/fsck.c35
-rw-r--r--fs/bcachefs/inode.c107
-rw-r--r--fs/bcachefs/inode.h5
-rw-r--r--fs/bcachefs/str_hash.h317
-rw-r--r--fs/bcachefs/xattr.c81
-rw-r--r--fs/bcachefs/xattr.h9
10 files changed, 474 insertions, 478 deletions
diff --git a/fs/bcachefs/acl.c b/fs/bcachefs/acl.c
index a8735bc04b4d..e98adb07649d 100644
--- a/fs/bcachefs/acl.c
+++ b/fs/bcachefs/acl.c
@@ -132,7 +132,8 @@ invalid:
* Convert from in-memory to filesystem representation.
*/
static struct bkey_i_xattr *
-bch2_acl_to_xattr(const struct posix_acl *acl,
+bch2_acl_to_xattr(struct btree_trans *trans,
+ const struct posix_acl *acl,
int type)
{
struct bkey_i_xattr *xattr;
@@ -164,7 +165,7 @@ bch2_acl_to_xattr(const struct posix_acl *acl,
if (u64s > U8_MAX)
return ERR_PTR(-E2BIG);
- xattr = kmalloc(u64s * sizeof(u64), GFP_KERNEL);
+ xattr = bch2_trans_kmalloc(trans, u64s * sizeof(u64));
if (IS_ERR(xattr))
return xattr;
@@ -214,20 +215,29 @@ struct posix_acl *bch2_get_acl(struct inode *vinode, int type)
{
struct bch_inode_info *inode = to_bch_ei(vinode);
struct bch_fs *c = inode->v.i_sb->s_fs_info;
- struct btree_iter iter;
+ struct btree_trans trans;
+ struct btree_iter *iter;
struct bkey_s_c_xattr xattr;
- struct bkey_s_c k;
struct posix_acl *acl = NULL;
- int name_index = acl_to_xattr_type(type);
- k = bch2_xattr_get_iter(c, &iter, inode, "", name_index);
- if (IS_ERR(k.k)) {
- if (PTR_ERR(k.k) != -ENOENT)
- acl = ERR_CAST(k.k);
+ bch2_trans_init(&trans, c);
+retry:
+ bch2_trans_begin(&trans);
+
+ iter = bch2_hash_lookup(&trans, bch2_xattr_hash_desc,
+ &inode->ei_str_hash, inode->v.i_ino,
+ &X_SEARCH(acl_to_xattr_type(type), "", 0),
+ 0);
+ if (IS_ERR(iter)) {
+ if (PTR_ERR(iter) == -EINTR)
+ goto retry;
+
+ if (PTR_ERR(iter) != -ENOENT)
+ acl = ERR_CAST(iter);
goto out;
}
- xattr = bkey_s_c_to_xattr(k);
+ xattr = bkey_s_c_to_xattr(bch2_btree_iter_peek_slot(iter));
acl = bch2_acl_from_disk(xattr_val(xattr.v),
le16_to_cpu(xattr.v->x_val_len));
@@ -235,43 +245,56 @@ struct posix_acl *bch2_get_acl(struct inode *vinode, int type)
if (!IS_ERR(acl))
set_cached_acl(&inode->v, type, acl);
out:
- bch2_btree_iter_unlock(&iter);
+ bch2_trans_exit(&trans);
return acl;
}
-int __bch2_set_acl(struct inode *vinode, struct posix_acl *acl, int type)
+int bch2_set_acl_trans(struct btree_trans *trans,
+ struct bch_inode_unpacked *inode_u,
+ const struct bch_hash_info *hash_info,
+ struct posix_acl *acl, int type)
{
- struct bch_inode_info *inode = to_bch_ei(vinode);
- struct bch_fs *c = inode->v.i_sb->s_fs_info;
int ret;
if (type == ACL_TYPE_DEFAULT &&
- !S_ISDIR(inode->v.i_mode))
+ !S_ISDIR(inode_u->bi_mode))
return acl ? -EACCES : 0;
if (acl) {
struct bkey_i_xattr *xattr =
- bch2_acl_to_xattr(acl, type);
+ bch2_acl_to_xattr(trans, acl, type);
if (IS_ERR(xattr))
return PTR_ERR(xattr);
- ret = bch2_hash_set(bch2_xattr_hash_desc, &inode->ei_str_hash,
- c, inode->v.i_ino, &inode->ei_journal_seq,
- &xattr->k_i, 0);
- kfree(xattr);
+ ret = __bch2_hash_set(trans, bch2_xattr_hash_desc, hash_info,
+ inode_u->bi_inum, &xattr->k_i, 0);
} else {
struct xattr_search_key search =
X_SEARCH(acl_to_xattr_type(type), "", 0);
- ret = bch2_hash_delete(bch2_xattr_hash_desc, &inode->ei_str_hash,
- c, inode->v.i_ino, &inode->ei_journal_seq,
- &search);
+ ret = bch2_hash_delete(trans, bch2_xattr_hash_desc, hash_info,
+ inode_u->bi_inum, &search);
}
- if (!ret)
- set_cached_acl(&inode->v, type, acl);
+ return ret == -ENOENT ? 0 : ret;
+}
- return ret;
+int __bch2_set_acl(struct inode *vinode, struct posix_acl *acl, int type)
+{
+ struct bch_inode_info *inode = to_bch_ei(vinode);
+ struct bch_fs *c = inode->v.i_sb->s_fs_info;
+ int ret;
+
+ ret = bch2_trans_do(c, &inode->ei_journal_seq, BTREE_INSERT_ATOMIC,
+ bch2_set_acl_trans(&trans,
+ &inode->ei_inode,
+ &inode->ei_str_hash,
+ acl, type));
+ if (ret)
+ return ret;
+
+ set_cached_acl(&inode->v, type, acl);
+ return 0;
}
int bch2_set_acl(struct inode *vinode, struct posix_acl *acl, int type)
diff --git a/fs/bcachefs/acl.h b/fs/bcachefs/acl.h
index 0be31ee9e59d..2e5ab78c779a 100644
--- a/fs/bcachefs/acl.h
+++ b/fs/bcachefs/acl.h
@@ -1,6 +1,10 @@
#ifndef _BCACHEFS_ACL_H
#define _BCACHEFS_ACL_H
+struct bch_inode_unpacked;
+struct bch_hash_info;
+struct posix_acl;
+
#ifdef CONFIG_BCACHEFS_POSIX_ACL
#define BCH_ACL_VERSION 0x0001
@@ -20,20 +24,26 @@ typedef struct {
__le32 a_version;
} bch_acl_header;
-struct posix_acl;
+struct posix_acl *bch2_get_acl(struct inode *, int);
-extern struct posix_acl *bch2_get_acl(struct inode *, int);
-extern int __bch2_set_acl(struct inode *, struct posix_acl *, int);
-extern int bch2_set_acl(struct inode *, struct posix_acl *, int);
+int bch2_set_acl_trans(struct btree_trans *,
+ struct bch_inode_unpacked *,
+ const struct bch_hash_info *,
+ struct posix_acl *, int);
+int __bch2_set_acl(struct inode *, struct posix_acl *, int);
+int bch2_set_acl(struct inode *, struct posix_acl *, int);
#else
-static inline int __bch2_set_acl(struct inode *inode, struct posix_acl *acl, int type)
+static inline int bch2_set_acl_trans(struct btree_trans *trans,
+ struct bch_inode_unpacked *inode_u,
+ const struct bch_hash_info *hash_info,
+ struct posix_acl *acl, int type)
{
return 0;
}
-static inline int bch2_set_acl(struct inode *inode, struct posix_acl *acl, int type)
+static inline int __bch2_set_acl(struct inode *inode, struct posix_acl *acl, int type)
{
return 0;
}
diff --git a/fs/bcachefs/dirent.c b/fs/bcachefs/dirent.c
index d3dd3eb71837..17fbce473995 100644
--- a/fs/bcachefs/dirent.c
+++ b/fs/bcachefs/dirent.c
@@ -141,8 +141,8 @@ void bch2_dirent_to_text(struct bch_fs *c, char *buf,
}
}
-static struct bkey_i_dirent *dirent_create_key(u8 type,
- const struct qstr *name, u64 dst)
+static struct bkey_i_dirent *dirent_create_key(struct btree_trans *trans,
+ u8 type, const struct qstr *name, u64 dst)
{
struct bkey_i_dirent *dirent;
unsigned u64s = BKEY_U64s + dirent_val_u64s(name->len);
@@ -152,9 +152,9 @@ static struct bkey_i_dirent *dirent_create_key(u8 type,
BUG_ON(u64s > U8_MAX);
- dirent = kmalloc(u64s * sizeof(u64), GFP_NOFS);
- if (!dirent)
- return ERR_PTR(-ENOMEM);
+ dirent = bch2_trans_kmalloc(trans, u64s * sizeof(u64));
+ if (IS_ERR(dirent))
+ return dirent;
bkey_dirent_init(&dirent->k_i);
dirent->k.u64s = u64s;
@@ -172,23 +172,31 @@ static struct bkey_i_dirent *dirent_create_key(u8 type,
return dirent;
}
-int bch2_dirent_create(struct bch_fs *c, u64 dir_inum,
- const struct bch_hash_info *hash_info,
- u8 type, const struct qstr *name, u64 dst_inum,
- u64 *journal_seq, int flags)
+int __bch2_dirent_create(struct btree_trans *trans,
+ u64 dir_inum, const struct bch_hash_info *hash_info,
+ u8 type, const struct qstr *name, u64 dst_inum,
+ int flags)
{
struct bkey_i_dirent *dirent;
int ret;
- dirent = dirent_create_key(type, name, dst_inum);
- if (IS_ERR(dirent))
- return PTR_ERR(dirent);
+ dirent = dirent_create_key(trans, type, name, dst_inum);
+ ret = PTR_ERR_OR_ZERO(dirent);
+ if (ret)
+ return ret;
- ret = bch2_hash_set(bch2_dirent_hash_desc, hash_info, c, dir_inum,
- journal_seq, &dirent->k_i, flags);
- kfree(dirent);
+ return __bch2_hash_set(trans, bch2_dirent_hash_desc, hash_info,
+ dir_inum, &dirent->k_i, flags);
+}
- return ret;
+int bch2_dirent_create(struct bch_fs *c, u64 dir_inum,
+ const struct bch_hash_info *hash_info,
+ u8 type, const struct qstr *name, u64 dst_inum,
+ u64 *journal_seq, int flags)
+{
+ return bch2_trans_do(c, journal_seq, flags,
+ __bch2_dirent_create(&trans, dir_inum, hash_info,
+ type, name, dst_inum, flags));
}
static void dirent_copy_target(struct bkey_i_dirent *dst,
@@ -204,151 +212,129 @@ static struct bpos bch2_dirent_pos(struct bch_inode_info *inode,
return POS(inode->v.i_ino, bch2_dirent_hash(&inode->ei_str_hash, name));
}
-int bch2_dirent_rename(struct bch_fs *c,
+int __bch2_dirent_rename(struct btree_trans *trans,
struct bch_inode_info *src_dir, const struct qstr *src_name,
struct bch_inode_info *dst_dir, const struct qstr *dst_name,
- u64 *journal_seq, enum bch_rename_mode mode)
+ enum bch_rename_mode mode)
{
- struct btree_iter src_iter, dst_iter, whiteout_iter;
+ struct btree_iter *src_iter, *dst_iter;
struct bkey_s_c old_src, old_dst;
- struct bkey delete;
struct bkey_i_dirent *new_src = NULL, *new_dst = NULL;
- struct bpos src_pos = bch2_dirent_pos(src_dir, src_name);
struct bpos dst_pos = bch2_dirent_pos(dst_dir, dst_name);
- bool need_whiteout;
int ret;
- bch2_btree_iter_init(&src_iter, c, BTREE_ID_DIRENTS, src_pos,
- BTREE_ITER_SLOTS|BTREE_ITER_INTENT);
- bch2_btree_iter_init(&dst_iter, c, BTREE_ID_DIRENTS, dst_pos,
- BTREE_ITER_SLOTS|BTREE_ITER_INTENT);
- bch2_btree_iter_link(&src_iter, &dst_iter);
-
- bch2_btree_iter_init(&whiteout_iter, c, BTREE_ID_DIRENTS, src_pos,
- BTREE_ITER_SLOTS);
- bch2_btree_iter_link(&src_iter, &whiteout_iter);
-
- if (mode == BCH_RENAME_EXCHANGE) {
- new_src = dirent_create_key(0, src_name, 0);
- if (IS_ERR(new_src)) {
- ret = PTR_ERR(new_src);
- goto err;
- }
- } else {
- new_src = (void *) &delete;
- }
-
- new_dst = dirent_create_key(0, dst_name, 0);
- if (IS_ERR(new_dst)) {
- ret = PTR_ERR(new_dst);
- goto err;
- }
-retry:
- /*
- * Note that on -EINTR/dropped locks we're not restarting the lookup
- * from the original hashed position (like we do when creating dirents,
- * in bch_hash_set) - we never move existing dirents to different slot:
- */
- old_src = bch2_hash_lookup_at(bch2_dirent_hash_desc,
- &src_dir->ei_str_hash,
- &src_iter, src_name);
- if ((ret = btree_iter_err(old_src)))
- goto err;
-
- ret = bch2_hash_needs_whiteout(bch2_dirent_hash_desc,
- &src_dir->ei_str_hash,
- &whiteout_iter, &src_iter);
- if (ret < 0)
- goto err;
- need_whiteout = ret;
-
/*
+ * Lookup dst:
+ *
* Note that in BCH_RENAME mode, we're _not_ checking if
* the target already exists - we're relying on the VFS
* to do that check for us for correctness:
*/
- old_dst = mode == BCH_RENAME
- ? bch2_hash_hole_at(bch2_dirent_hash_desc, &dst_iter)
- : bch2_hash_lookup_at(bch2_dirent_hash_desc,
- &dst_dir->ei_str_hash,
- &dst_iter, dst_name);
- if ((ret = btree_iter_err(old_dst)))
- goto err;
-
- switch (mode) {
- case BCH_RENAME:
+ dst_iter = mode == BCH_RENAME
+ ? bch2_hash_hole(trans, bch2_dirent_hash_desc,
+ &dst_dir->ei_str_hash,
+ dst_dir->v.i_ino, dst_name)
+ : bch2_hash_lookup(trans, bch2_dirent_hash_desc,
+ &dst_dir->ei_str_hash,
+ dst_dir->v.i_ino, dst_name,
+ BTREE_ITER_INTENT);
+ if (IS_ERR(dst_iter))
+ return PTR_ERR(dst_iter);
+ old_dst = bch2_btree_iter_peek_slot(dst_iter);
+
+ /* Lookup src: */
+ src_iter = bch2_hash_lookup(trans, bch2_dirent_hash_desc,
+ &src_dir->ei_str_hash,
+ src_dir->v.i_ino, src_name,
+ BTREE_ITER_INTENT);
+ if (IS_ERR(src_iter))
+ return PTR_ERR(src_iter);
+ old_src = bch2_btree_iter_peek_slot(src_iter);
+
+ /* Create new dst key: */
+ new_dst = dirent_create_key(trans, 0, dst_name, 0);
+ if (IS_ERR(new_dst))
+ return PTR_ERR(new_dst);
+
+ dirent_copy_target(new_dst, bkey_s_c_to_dirent(old_src));
+ new_dst->k.p = dst_iter->pos;
+
+ /* Create new src key: */
+ if (mode == BCH_RENAME_EXCHANGE) {
+ new_src = dirent_create_key(trans, 0, src_name, 0);
+ if (IS_ERR(new_src))
+ return PTR_ERR(new_src);
+
+ dirent_copy_target(new_src, bkey_s_c_to_dirent(old_dst));
+ new_src->k.p = src_iter->pos;
+ } else {
+ new_src = bch2_trans_kmalloc(trans, sizeof(struct bkey_i));
+ if (IS_ERR(new_src))
+ return PTR_ERR(new_src);
bkey_init(&new_src->k);
- dirent_copy_target(new_dst, bkey_s_c_to_dirent(old_src));
+ new_src->k.p = src_iter->pos;
- if (bkey_cmp(dst_pos, src_iter.pos) <= 0 &&
- bkey_cmp(src_iter.pos, dst_iter.pos) < 0) {
+ if (bkey_cmp(dst_pos, src_iter->pos) <= 0 &&
+ bkey_cmp(src_iter->pos, dst_iter->pos) < 0) {
/*
- * If we couldn't insert new_dst at its hashed
- * position (dst_pos) due to a hash collision,
- * and we're going to be deleting in
- * between the hashed position and first empty
- * slot we found - just overwrite the pos we
- * were going to delete:
- *
- * Note: this is a correctness issue, in this
- * situation bch2_hash_needs_whiteout() could
- * return false when the whiteout would have
- * been needed if we inserted at the pos
- * __dirent_find_hole() found
+ * We have a hash collision for the new dst key,
+ * and new_src - the key we're deleting - is between
+ * new_dst's hashed slot and the slot we're going to be
+ * inserting it into - oops. This will break the hash
+ * table if we don't deal with it:
*/
- new_dst->k.p = src_iter.pos;
- ret = bch2_btree_insert_at(c, NULL, NULL,
- journal_seq,
- BTREE_INSERT_ATOMIC,
- BTREE_INSERT_ENTRY(&src_iter,
- &new_dst->k_i));
- goto err;
+ if (mode == BCH_RENAME) {
+ /*
+ * If we're not overwriting, we can just insert
+ * new_dst at the src position:
+ */
+ new_dst->k.p = src_iter->pos;
+ bch2_trans_update(trans, src_iter, &new_dst->k_i, 0);
+ return 0;
+ } else {
+ /* If we're overwriting, we can't insert new_dst
+ * at a different slot because it has to
+ * overwrite old_dst - just make sure to use a
+ * whiteout when deleting src:
+ */
+ new_src->k.type = BCH_DIRENT_WHITEOUT;
+ }
+ } else {
+ /* Check if we need a whiteout to delete src: */
+ ret = bch2_hash_needs_whiteout(trans, bch2_dirent_hash_desc,
+ &src_dir->ei_str_hash,
+ src_iter);
+ if (ret < 0)
+ return ret;
+
+ if (ret)
+ new_src->k.type = BCH_DIRENT_WHITEOUT;
}
+ }
- if (need_whiteout)
- new_src->k.type = BCH_DIRENT_WHITEOUT;
- break;
- case BCH_RENAME_OVERWRITE:
- bkey_init(&new_src->k);
- dirent_copy_target(new_dst, bkey_s_c_to_dirent(old_src));
+ bch2_trans_update(trans, src_iter, &new_src->k_i, 0);
+ bch2_trans_update(trans, dst_iter, &new_dst->k_i, 0);
+ return 0;
+}
- if (bkey_cmp(dst_pos, src_iter.pos) <= 0 &&
- bkey_cmp(src_iter.pos, dst_iter.pos) < 0) {
- /*
- * Same case described above -
- * bch_hash_needs_whiteout could spuriously
- * return false, but we have to insert at
- * dst_iter.pos because we're overwriting
- * another dirent:
- */
- new_src->k.type = BCH_DIRENT_WHITEOUT;
- } else if (need_whiteout)
- new_src->k.type = BCH_DIRENT_WHITEOUT;
- break;
- case BCH_RENAME_EXCHANGE:
- dirent_copy_target(new_src, bkey_s_c_to_dirent(old_dst));
- dirent_copy_target(new_dst, bkey_s_c_to_dirent(old_src));
- break;
- }
+int bch2_dirent_rename(struct bch_fs *c,
+ struct bch_inode_info *src_dir, const struct qstr *src_name,
+ struct bch_inode_info *dst_dir, const struct qstr *dst_name,
+ u64 *journal_seq, enum bch_rename_mode mode)
+{
+ return bch2_trans_do(c, journal_seq, BTREE_INSERT_ATOMIC,
+ __bch2_dirent_rename(&trans,
+ src_dir, src_name,
+ dst_dir, dst_name,
+ mode));
+}
- new_src->k.p = src_iter.pos;
- new_dst->k.p = dst_iter.pos;
- ret = bch2_btree_insert_at(c, NULL, NULL, journal_seq,
- BTREE_INSERT_ATOMIC,
- BTREE_INSERT_ENTRY(&src_iter, &new_src->k_i),
- BTREE_INSERT_ENTRY(&dst_iter, &new_dst->k_i));
-err:
- if (ret == -EINTR)
- goto retry;
-
- bch2_btree_iter_unlock(&whiteout_iter);
- bch2_btree_iter_unlock(&dst_iter);
- bch2_btree_iter_unlock(&src_iter);
-
- if (new_src != (void *) &delete)
- kfree(new_src);
- kfree(new_dst);
- return ret;
+int __bch2_dirent_delete(struct btree_trans *trans, u64 dir_inum,
+ const struct bch_hash_info *hash_info,
+ const struct qstr *name)
+{
+ return bch2_hash_delete(trans, bch2_dirent_hash_desc, hash_info,
+ dir_inum, name);
}
int bch2_dirent_delete(struct bch_fs *c, u64 dir_inum,
@@ -356,27 +342,34 @@ int bch2_dirent_delete(struct bch_fs *c, u64 dir_inum,
const struct qstr *name,
u64 *journal_seq)
{
- return bch2_hash_delete(bch2_dirent_hash_desc, hash_info,
- c, dir_inum, journal_seq, name);
+ return bch2_trans_do(c, journal_seq,
+ BTREE_INSERT_ATOMIC|
+ BTREE_INSERT_NOFAIL,
+ __bch2_dirent_delete(&trans, dir_inum, hash_info, name));
}
u64 bch2_dirent_lookup(struct bch_fs *c, u64 dir_inum,
const struct bch_hash_info *hash_info,
const struct qstr *name)
{
- struct btree_iter iter;
+ struct btree_trans trans;
+ struct btree_iter *iter;
struct bkey_s_c k;
u64 inum;
- k = bch2_hash_lookup(bch2_dirent_hash_desc, hash_info, c,
- dir_inum, &iter, name);
- if (IS_ERR(k.k)) {
- bch2_btree_iter_unlock(&iter);
+ bch2_trans_init(&trans, c);
+
+ iter = bch2_hash_lookup(&trans, bch2_dirent_hash_desc,
+ hash_info, dir_inum, name, 0);
+ if (IS_ERR(iter)) {
+ BUG_ON(PTR_ERR(iter) == -EINTR);
+ bch2_trans_exit(&trans);
return 0;
}
+ k = bch2_btree_iter_peek_slot(iter);
inum = le64_to_cpu(bkey_s_c_to_dirent(k).v->d_inum);
- bch2_btree_iter_unlock(&iter);
+ bch2_trans_exit(&trans);
return inum;
}
diff --git a/fs/bcachefs/dirent.h b/fs/bcachefs/dirent.h
index 5d066af18f95..2578bd887c73 100644
--- a/fs/bcachefs/dirent.h
+++ b/fs/bcachefs/dirent.h
@@ -21,8 +21,16 @@ struct bch_hash_info;
struct bch_inode_info;
unsigned bch2_dirent_name_bytes(struct bkey_s_c_dirent);
+
+int __bch2_dirent_create(struct btree_trans *, u64,
+ const struct bch_hash_info *, u8,
+ const struct qstr *, u64, int);
int bch2_dirent_create(struct bch_fs *c, u64, const struct bch_hash_info *,
u8, const struct qstr *, u64, u64 *, int);
+
+int __bch2_dirent_delete(struct btree_trans *, u64,
+ const struct bch_hash_info *,
+ const struct qstr *);
int bch2_dirent_delete(struct bch_fs *, u64, const struct bch_hash_info *,
const struct qstr *, u64 *);
@@ -32,6 +40,10 @@ enum bch_rename_mode {
BCH_RENAME_EXCHANGE,
};
+int __bch2_dirent_rename(struct btree_trans *,
+ struct bch_inode_info *, const struct qstr *,
+ struct bch_inode_info *, const struct qstr *,
+ enum bch_rename_mode);
int bch2_dirent_rename(struct bch_fs *,
struct bch_inode_info *, const struct qstr *,
struct bch_inode_info *, const struct qstr *,
diff --git a/fs/bcachefs/fsck.c b/fs/bcachefs/fsck.c
index 3bbb0a2e8ac5..687247c789b1 100644
--- a/fs/bcachefs/fsck.c
+++ b/fs/bcachefs/fsck.c
@@ -173,6 +173,39 @@ err:
return ret;
}
+/* fsck hasn't been converted to new transactions yet: */
+static int fsck_hash_delete_at(const struct bch_hash_desc desc,
+ struct bch_hash_info *info,
+ struct btree_iter *orig_iter)
+{
+ struct btree_trans trans;
+ struct btree_iter *iter;
+ int ret;
+
+ bch2_btree_iter_unlock(orig_iter);
+
+ bch2_trans_init(&trans, orig_iter->c);
+retry:
+ bch2_trans_begin(&trans);
+
+ iter = bch2_trans_copy_iter(&trans, orig_iter);
+ if (IS_ERR(iter)) {
+ ret = PTR_ERR(iter);
+ goto err;
+ }
+
+ ret = bch2_hash_delete_at(&trans, desc, info, iter) ?:
+ bch2_trans_commit(&trans, NULL, NULL, NULL,
+ BTREE_INSERT_ATOMIC|
+ BTREE_INSERT_NOFAIL);
+err:
+ if (ret == -EINTR)
+ goto retry;
+
+ bch2_trans_exit(&trans);
+ return ret;
+}
+
static int hash_check_key(const struct bch_hash_desc desc,
struct hash_check *h, struct bch_fs *c,
struct btree_iter *k_iter, struct bkey_s_c k)
@@ -226,7 +259,7 @@ static int hash_check_key(const struct bch_hash_desc desc,
"duplicate hash table keys:\n%s",
(bch2_bkey_val_to_text(c, bkey_type(0, desc.btree_id),
buf, sizeof(buf), k), buf))) {
- ret = bch2_hash_delete_at(desc, &h->info, &h->iter, NULL);
+ ret = fsck_hash_delete_at(desc, &h->info, &h->iter);
if (ret)
return ret;
return 1;
diff --git a/fs/bcachefs/inode.c b/fs/bcachefs/inode.c
index 6882fb0aa906..987ff1691c17 100644
--- a/fs/bcachefs/inode.c
+++ b/fs/bcachefs/inode.c
@@ -278,12 +278,27 @@ void bch2_inode_init(struct bch_fs *c, struct bch_inode_unpacked *inode_u,
}
}
-int bch2_inode_create(struct bch_fs *c, struct bch_inode_unpacked *inode_u,
- u64 min, u64 max, u64 *hint)
+static inline u32 bkey_generation(struct bkey_s_c k)
{
- struct bkey_inode_buf inode_p;
- struct btree_iter iter;
- bool searched_from_start = false;
+ switch (k.k->type) {
+ case BCH_INODE_BLOCKDEV:
+ case BCH_INODE_FS:
+ BUG();
+ case BCH_INODE_GENERATION:
+ return le32_to_cpu(bkey_s_c_to_inode_generation(k).v->bi_generation);
+ default:
+ return 0;
+ }
+}
+
+int __bch2_inode_create(struct btree_trans *trans,
+ struct bch_inode_unpacked *inode_u,
+ u64 min, u64 max, u64 *hint)
+{
+ struct bch_fs *c = trans->c;
+ struct bkey_inode_buf *inode_p;
+ struct btree_iter *iter;
+ u64 start;
int ret;
if (!max)
@@ -292,82 +307,66 @@ int bch2_inode_create(struct bch_fs *c, struct bch_inode_unpacked *inode_u,
if (c->opts.inodes_32bit)
max = min_t(u64, max, U32_MAX);
- if (*hint >= max || *hint < min)
- *hint = min;
+ start = READ_ONCE(*hint);
- if (*hint == min)
- searched_from_start = true;
-again:
- bch2_btree_iter_init(&iter, c, BTREE_ID_INODES, POS(*hint, 0),
- BTREE_ITER_SLOTS|BTREE_ITER_INTENT);
+ if (start >= max || start < min)
+ start = min;
+
+ inode_p = bch2_trans_kmalloc(trans, sizeof(*inode_p));
+ if (IS_ERR(inode_p))
+ return PTR_ERR(inode_p);
+ iter = bch2_trans_get_iter(trans,
+ BTREE_ID_INODES, POS(start, 0),
+ BTREE_ITER_SLOTS|BTREE_ITER_INTENT);
+ if (IS_ERR(iter))
+ return PTR_ERR(iter);
+again:
while (1) {
- struct bkey_s_c k = bch2_btree_iter_peek_slot(&iter);
- u32 bi_generation = 0;
+ struct bkey_s_c k = bch2_btree_iter_peek_slot(iter);
ret = btree_iter_err(k);
- if (ret) {
- bch2_btree_iter_unlock(&iter);
+ if (ret)
return ret;
- }
switch (k.k->type) {
case BCH_INODE_BLOCKDEV:
case BCH_INODE_FS:
/* slot used */
- if (iter.pos.inode == max)
+ if (iter->pos.inode >= max)
goto out;
- bch2_btree_iter_next_slot(&iter);
+ bch2_btree_iter_next_slot(iter);
break;
- case BCH_INODE_GENERATION: {
- struct bkey_s_c_inode_generation g =
- bkey_s_c_to_inode_generation(k);
- bi_generation = le32_to_cpu(g.v->bi_generation);
- /* fallthrough: */
- }
default:
- inode_u->bi_generation = bi_generation;
-
- bch2_inode_pack(&inode_p, inode_u);
- inode_p.inode.k.p = k.k->p;
-
- ret = bch2_btree_insert_at(c, NULL, NULL, NULL,
- BTREE_INSERT_ATOMIC,
- BTREE_INSERT_ENTRY(&iter,
- &inode_p.inode.k_i));
-
- if (ret != -EINTR) {
- bch2_btree_iter_unlock(&iter);
-
- if (!ret) {
- inode_u->bi_inum =
- inode_p.inode.k.p.inode;
- *hint = inode_p.inode.k.p.inode + 1;
- }
-
- return ret;
- }
-
- if (ret == -EINTR)
- continue;
+ *hint = k.k->p.inode;
+ inode_u->bi_inum = k.k->p.inode;
+ inode_u->bi_generation = bkey_generation(k);
+ bch2_inode_pack(inode_p, inode_u);
+ bch2_trans_update(trans, iter, &inode_p->inode.k_i, 0);
+ return 0;
}
}
out:
- bch2_btree_iter_unlock(&iter);
-
- if (!searched_from_start) {
+ if (start != min) {
/* Retry from start */
- *hint = min;
- searched_from_start = true;
+ start = min;
+ bch2_btree_iter_set_pos(iter, POS(start, 0));
goto again;
}
return -ENOSPC;
}
+int bch2_inode_create(struct bch_fs *c, struct bch_inode_unpacked *inode_u,
+ u64 min, u64 max, u64 *hint)
+{
+ return bch2_trans_do(c, NULL, BTREE_INSERT_ATOMIC,
+ __bch2_inode_create(&trans, inode_u, min, max, hint));
+}
+
int bch2_inode_truncate(struct bch_fs *c, u64 inode_nr, u64 new_size,
struct extent_insert_hook *hook, u64 *journal_seq)
{
diff --git a/fs/bcachefs/inode.h b/fs/bcachefs/inode.h
index 055d0053c781..ca995194b2b3 100644
--- a/fs/bcachefs/inode.h
+++ b/fs/bcachefs/inode.h
@@ -38,8 +38,13 @@ int bch2_inode_unpack(struct bkey_s_c_inode, struct bch_inode_unpacked *);
void bch2_inode_init(struct bch_fs *, struct bch_inode_unpacked *,
uid_t, gid_t, umode_t, dev_t,
struct bch_inode_unpacked *);
+
+int __bch2_inode_create(struct btree_trans *,
+ struct bch_inode_unpacked *,
+ u64, u64, u64 *);
int bch2_inode_create(struct bch_fs *, struct bch_inode_unpacked *,
u64, u64, u64 *);
+
int bch2_inode_truncate(struct bch_fs *, u64, u64,
struct extent_insert_hook *, u64 *);
int bch2_inode_rm(struct bch_fs *, u64);
diff --git a/fs/bcachefs/str_hash.h b/fs/bcachefs/str_hash.h
index 275ac8625b4a..058b280fe7d9 100644
--- a/fs/bcachefs/str_hash.h
+++ b/fs/bcachefs/str_hash.h
@@ -126,46 +126,29 @@ struct bch_hash_desc {
bool (*cmp_bkey)(struct bkey_s_c, struct bkey_s_c);
};
-static inline struct bkey_s_c
-bch2_hash_lookup_at(const struct bch_hash_desc desc,
- const struct bch_hash_info *info,
- struct btree_iter *iter, const void *search)
+static inline struct btree_iter *
+bch2_hash_lookup(struct btree_trans *trans,
+ const struct bch_hash_desc desc,
+ const struct bch_hash_info *info,
+ u64 inode, const void *key,
+ unsigned flags)
{
- u64 inode = iter->pos.inode;
+ struct btree_iter *iter;
struct bkey_s_c k;
- for_each_btree_key_continue(iter, BTREE_ITER_SLOTS, k) {
- if (iter->pos.inode != inode)
- break;
-
- if (k.k->type == desc.key_type) {
- if (!desc.cmp_key(k, search))
- return k;
- } else if (k.k->type == desc.whiteout_type) {
- ;
- } else {
- /* hole, not found */
- break;
- }
- }
- return btree_iter_err(k) ? k : bkey_s_c_err(-ENOENT);
-}
-
-static inline struct bkey_s_c
-bch2_hash_lookup_bkey_at(const struct bch_hash_desc desc,
- const struct bch_hash_info *info,
- struct btree_iter *iter, struct bkey_s_c search)
-{
- u64 inode = iter->pos.inode;
- struct bkey_s_c k;
+ iter = bch2_trans_get_iter(trans, desc.btree_id,
+ POS(inode, desc.hash_key(info, key)),
+ BTREE_ITER_SLOTS|flags);
+ if (IS_ERR(iter))
+ return iter;
for_each_btree_key_continue(iter, BTREE_ITER_SLOTS, k) {
if (iter->pos.inode != inode)
break;
if (k.k->type == desc.key_type) {
- if (!desc.cmp_bkey(k, search))
- return k;
+ if (!desc.cmp_key(k, key))
+ return iter;
} else if (k.k->type == desc.whiteout_type) {
;
} else {
@@ -173,72 +156,48 @@ bch2_hash_lookup_bkey_at(const struct bch_hash_desc desc,
break;
}
}
- return btree_iter_err(k) ? k : bkey_s_c_err(-ENOENT);
-}
-
-static inline struct bkey_s_c
-bch2_hash_lookup(const struct bch_hash_desc desc,
- const struct bch_hash_info *info,
- struct bch_fs *c, u64 inode,
- struct btree_iter *iter, const void *key)
-{
- bch2_btree_iter_init(iter, c, desc.btree_id,
- POS(inode, desc.hash_key(info, key)),
- BTREE_ITER_SLOTS);
-
- return bch2_hash_lookup_at(desc, info, iter, key);
-}
-
-static inline struct bkey_s_c
-bch2_hash_lookup_intent(const struct bch_hash_desc desc,
- const struct bch_hash_info *info,
- struct bch_fs *c, u64 inode,
- struct btree_iter *iter, const void *key)
-{
- bch2_btree_iter_init(iter, c, desc.btree_id,
- POS(inode, desc.hash_key(info, key)),
- BTREE_ITER_SLOTS|BTREE_ITER_INTENT);
- return bch2_hash_lookup_at(desc, info, iter, key);
+ return IS_ERR(k.k) ? ERR_CAST(k.k) : ERR_PTR(-ENOENT);
}
-static inline struct bkey_s_c
-bch2_hash_hole_at(const struct bch_hash_desc desc, struct btree_iter *iter)
+static inline struct btree_iter *
+bch2_hash_hole(struct btree_trans *trans,
+ const struct bch_hash_desc desc,
+ const struct bch_hash_info *info,
+ u64 inode, const void *key)
{
- u64 inode = iter->pos.inode;
+ struct btree_iter *iter;
struct bkey_s_c k;
+ iter = bch2_trans_get_iter(trans, desc.btree_id,
+ POS(inode, desc.hash_key(info, key)),
+ BTREE_ITER_SLOTS|BTREE_ITER_INTENT);
+ if (IS_ERR(iter))
+ return iter;
+
for_each_btree_key_continue(iter, BTREE_ITER_SLOTS, k) {
if (iter->pos.inode != inode)
break;
if (k.k->type != desc.key_type)
- return k;
+ return iter;
}
- return btree_iter_err(k) ? k : bkey_s_c_err(-ENOENT);
-}
-
-static inline struct bkey_s_c bch2_hash_hole(const struct bch_hash_desc desc,
- const struct bch_hash_info *info,
- struct bch_fs *c, u64 inode,
- struct btree_iter *iter,
- const void *key)
-{
- bch2_btree_iter_init(iter, c, desc.btree_id,
- POS(inode, desc.hash_key(info, key)),
- BTREE_ITER_SLOTS|BTREE_ITER_INTENT);
- return bch2_hash_hole_at(desc, iter);
+ return IS_ERR(k.k) ? ERR_CAST(k.k) : ERR_PTR(-ENOSPC);
}
-static inline int bch2_hash_needs_whiteout(const struct bch_hash_desc desc,
+static inline int bch2_hash_needs_whiteout(struct btree_trans *trans,
+ const struct bch_hash_desc desc,
const struct bch_hash_info *info,
- struct btree_iter *iter,
struct btree_iter *start)
{
+ struct btree_iter *iter;
struct bkey_s_c k;
- bch2_btree_iter_copy(iter, start);
+ iter = bch2_trans_copy_iter(trans, start);
+ if (IS_ERR(iter))
+ return PTR_ERR(iter);
+
bch2_btree_iter_next_slot(iter);
for_each_btree_key_continue(iter, BTREE_ITER_SLOTS, k) {
@@ -253,142 +212,108 @@ static inline int bch2_hash_needs_whiteout(const struct bch_hash_desc desc,
return btree_iter_err(k);
}
-static inline int bch2_hash_set(const struct bch_hash_desc desc,
- const struct bch_hash_info *info,
- struct bch_fs *c, u64 inode,
- u64 *journal_seq,
- struct bkey_i *insert, int flags)
+static inline int __bch2_hash_set(struct btree_trans *trans,
+ const struct bch_hash_desc desc,
+ const struct bch_hash_info *info,
+ u64 inode, struct bkey_i *insert, int flags)
{
- struct btree_iter iter, hashed_slot;
+ struct btree_iter *iter, *slot = NULL;
struct bkey_s_c k;
- int ret;
- bch2_btree_iter_init(&hashed_slot, c, desc.btree_id,
- POS(inode, desc.hash_bkey(info, bkey_i_to_s_c(insert))),
- BTREE_ITER_SLOTS|BTREE_ITER_INTENT);
- bch2_btree_iter_init(&iter, c, desc.btree_id, hashed_slot.pos,
- BTREE_ITER_SLOTS|BTREE_ITER_INTENT);
- bch2_btree_iter_link(&hashed_slot, &iter);
-retry:
- /*
- * On hash collision, we have to keep the slot we hashed to locked while
- * we do the insert - to avoid racing with another thread deleting
- * whatever's in the slot we hashed to:
- */
- ret = bch2_btree_iter_traverse(&hashed_slot);
- if (ret)
- goto err;
-
- /*
- * On -EINTR/retry, we dropped locks - always restart from the slot we
- * hashed to:
- */
- bch2_btree_iter_copy(&iter, &hashed_slot);
-
- k = bch2_hash_lookup_bkey_at(desc, info, &iter, bkey_i_to_s_c(insert));
-
- ret = btree_iter_err(k);
- if (ret == -ENOENT) {
- if (flags & BCH_HASH_SET_MUST_REPLACE) {
- ret = -ENOENT;
- goto err;
+ iter = bch2_trans_get_iter(trans, desc.btree_id,
+ POS(inode, desc.hash_bkey(info, bkey_i_to_s_c(insert))),
+ BTREE_ITER_SLOTS|BTREE_ITER_INTENT);
+ if (IS_ERR(iter))
+ return PTR_ERR(iter);
+
+ for_each_btree_key_continue(iter, BTREE_ITER_SLOTS, k) {
+ if (iter->pos.inode != inode)
+ break;
+
+ if (k.k->type == desc.key_type) {
+ if (!desc.cmp_bkey(k, bkey_i_to_s_c(insert)))
+ goto found;
+
+ /* hash collision: */
+ continue;
}
- /*
- * Not found, so we're now looking for any open
- * slot - we might have skipped over a whiteout
- * that we could have used, so restart from the
- * slot we hashed to:
- */
- bch2_btree_iter_copy(&iter, &hashed_slot);
- k = bch2_hash_hole_at(desc, &iter);
- if ((ret = btree_iter_err(k)))
- goto err;
- } else if (!ret) {
- if (flags & BCH_HASH_SET_MUST_CREATE) {
- ret = -EEXIST;
- goto err;
+ if (!slot &&
+ !(flags & BCH_HASH_SET_MUST_REPLACE)) {
+ slot = bch2_trans_copy_iter(trans, iter);
+ if (IS_ERR(slot))
+ return PTR_ERR(slot);
}
- } else {
- goto err;
+
+ if (k.k->type != desc.whiteout_type)
+ goto not_found;
}
- insert->k.p = iter.pos;
- ret = bch2_btree_insert_at(c, NULL, NULL, journal_seq,
- BTREE_INSERT_ATOMIC|flags,
- BTREE_INSERT_ENTRY(&iter, insert));
-err:
- if (ret == -EINTR)
- goto retry;
-
- /*
- * On successful insert, we don't want to clobber ret with error from
- * iter:
- */
- bch2_btree_iter_unlock(&iter);
- bch2_btree_iter_unlock(&hashed_slot);
- return ret;
+ return btree_iter_err(k) ?: -ENOSPC;
+not_found:
+ if (flags & BCH_HASH_SET_MUST_REPLACE)
+ return -ENOENT;
+
+ insert->k.p = slot->pos;
+ bch2_trans_update(trans, slot, insert, 0);
+ return 0;
+found:
+ if (flags & BCH_HASH_SET_MUST_CREATE)
+ return -EEXIST;
+
+ insert->k.p = iter->pos;
+ bch2_trans_update(trans, iter, insert, 0);
+ return 0;
}
-static inline int bch2_hash_delete_at(const struct bch_hash_desc desc,
- const struct bch_hash_info *info,
- struct btree_iter *iter,
- u64 *journal_seq)
+static inline int bch2_hash_set(const struct bch_hash_desc desc,
+ const struct bch_hash_info *info,
+ struct bch_fs *c, u64 inode,
+ u64 *journal_seq,
+ struct bkey_i *insert, int flags)
{
- struct btree_iter whiteout_iter;
- struct bkey_i delete;
- int ret = -ENOENT;
+ return bch2_trans_do(c, journal_seq, flags|BTREE_INSERT_ATOMIC,
+ __bch2_hash_set(&trans, desc, info,
+ inode, insert, flags));
+}
- bch2_btree_iter_init(&whiteout_iter, iter->c, desc.btree_id,
- iter->pos, BTREE_ITER_SLOTS);
- bch2_btree_iter_link(iter, &whiteout_iter);
+static inline int bch2_hash_delete_at(struct btree_trans *trans,
+ const struct bch_hash_desc desc,
+ const struct bch_hash_info *info,
+ struct btree_iter *iter)
+{
+ struct bkey_i *delete;
+ int ret;
- ret = bch2_hash_needs_whiteout(desc, info, &whiteout_iter, iter);
+ ret = bch2_hash_needs_whiteout(trans, desc, info, iter);
if (ret < 0)
- goto err;
-
- bkey_init(&delete.k);
- delete.k.p = iter->pos;
- delete.k.type = ret ? desc.whiteout_type : KEY_TYPE_DELETED;
-
- ret = bch2_btree_insert_at(iter->c, NULL, NULL, journal_seq,
- BTREE_INSERT_NOFAIL|
- BTREE_INSERT_ATOMIC,
- BTREE_INSERT_ENTRY(iter, &delete));
-err:
- bch2_btree_iter_unlink(&whiteout_iter);
- return ret;
+ return ret;
+
+ delete = bch2_trans_kmalloc(trans, sizeof(*delete));
+ if (IS_ERR(delete))
+ return PTR_ERR(delete);
+
+ bkey_init(&delete->k);
+ delete->k.p = iter->pos;
+ delete->k.type = ret ? desc.whiteout_type : KEY_TYPE_DELETED;
+
+ bch2_trans_update(trans, iter, delete, 0);
+ return 0;
}
-static inline int bch2_hash_delete(const struct bch_hash_desc desc,
- const struct bch_hash_info *info,
- struct bch_fs *c, u64 inode,
- u64 *journal_seq, const void *key)
+static inline int bch2_hash_delete(struct btree_trans *trans,
+ const struct bch_hash_desc desc,
+ const struct bch_hash_info *info,
+ u64 inode, const void *key)
{
- struct btree_iter iter, whiteout_iter;
- struct bkey_s_c k;
- int ret = -ENOENT;
-
- bch2_btree_iter_init(&iter, c, desc.btree_id,
- POS(inode, desc.hash_key(info, key)),
- BTREE_ITER_SLOTS|BTREE_ITER_INTENT);
- bch2_btree_iter_init(&whiteout_iter, c, desc.btree_id,
- POS(inode, desc.hash_key(info, key)),
- BTREE_ITER_SLOTS);
- bch2_btree_iter_link(&iter, &whiteout_iter);
-retry:
- k = bch2_hash_lookup_at(desc, info, &iter, key);
- if ((ret = btree_iter_err(k)))
- goto err;
-
- ret = bch2_hash_delete_at(desc, info, &iter, journal_seq);
-err:
- if (ret == -EINTR)
- goto retry;
-
- bch2_btree_iter_unlock(&whiteout_iter);
- bch2_btree_iter_unlock(&iter);
- return ret;
+ struct btree_iter *iter;
+
+ iter = bch2_hash_lookup(trans, desc, info, inode, key,
+ BTREE_ITER_INTENT);
+ if (IS_ERR(iter))
+ return PTR_ERR(iter);
+
+ return bch2_hash_delete_at(trans, desc, info, iter);
}
#endif /* _BCACHEFS_STR_HASH_H */
diff --git a/fs/bcachefs/xattr.c b/fs/bcachefs/xattr.c
index 8eb1b1703e7e..27eb889b76e4 100644
--- a/fs/bcachefs/xattr.c
+++ b/fs/bcachefs/xattr.c
@@ -143,32 +143,28 @@ void bch2_xattr_to_text(struct bch_fs *c, char *buf,
}
}
-struct bkey_s_c bch2_xattr_get_iter(struct bch_fs *c,
- struct btree_iter *iter,
- struct bch_inode_info *inode,
- const char *name, int type)
-{
- return bch2_hash_lookup(bch2_xattr_hash_desc,
- &inode->ei_str_hash,
- c, inode->v.i_ino, iter,
- &X_SEARCH(type, name, strlen(name)));
-}
-
int bch2_xattr_get(struct bch_fs *c, struct bch_inode_info *inode,
- const char *name, void *buffer, size_t size, int type)
+ const char *name, void *buffer, size_t size, int type)
{
- struct btree_iter iter;
- struct bkey_s_c k;
+ struct btree_trans trans;
+ struct btree_iter *iter;
struct bkey_s_c_xattr xattr;
int ret;
- k = bch2_hash_lookup(bch2_xattr_hash_desc, &inode->ei_str_hash, c,
- inode->v.i_ino, &iter,
- &X_SEARCH(type, name, strlen(name)));
- if (IS_ERR(k.k))
- return bch2_btree_iter_unlock(&iter) ?: -ENODATA;
+ bch2_trans_init(&trans, c);
+
+ iter = bch2_hash_lookup(&trans, bch2_xattr_hash_desc,
+ &inode->ei_str_hash, inode->v.i_ino,
+ &X_SEARCH(type, name, strlen(name)),
+ 0);
+ if (IS_ERR(iter)) {
+ bch2_trans_exit(&trans);
+ BUG_ON(PTR_ERR(iter) == -EINTR);
- xattr = bkey_s_c_to_xattr(k);
+ return PTR_ERR(iter) == -ENOENT ? -ENODATA : PTR_ERR(iter);
+ }
+
+ xattr = bkey_s_c_to_xattr(bch2_btree_iter_peek_slot(iter));
ret = le16_to_cpu(xattr.v->x_val_len);
if (buffer) {
if (ret > size)
@@ -177,47 +173,48 @@ int bch2_xattr_get(struct bch_fs *c, struct bch_inode_info *inode,
memcpy(buffer, xattr_val(xattr.v), ret);
}
- bch2_btree_iter_unlock(&iter);
+ bch2_trans_exit(&trans);
return ret;
}
-int bch2_xattr_set(struct bch_fs *c, u64 inum,
+int bch2_xattr_set(struct btree_trans *trans, u64 inum,
const struct bch_hash_info *hash_info,
const char *name, const void *value, size_t size,
- int flags, int type, u64 *journal_seq)
+ int type, int flags)
{
- struct xattr_search_key search = X_SEARCH(type, name, strlen(name));
int ret;
if (value) {
struct bkey_i_xattr *xattr;
+ unsigned namelen = strlen(name);
unsigned u64s = BKEY_U64s +
- xattr_val_u64s(search.name.len, size);
+ xattr_val_u64s(namelen, size);
if (u64s > U8_MAX)
return -ERANGE;
- xattr = kmalloc(u64s * sizeof(u64), GFP_NOFS);
- if (!xattr)
- return -ENOMEM;
+ xattr = bch2_trans_kmalloc(trans, u64s * sizeof(u64));
+ if (IS_ERR(xattr))
+ return PTR_ERR(xattr);
bkey_xattr_init(&xattr->k_i);
xattr->k.u64s = u64s;
xattr->v.x_type = type;
- xattr->v.x_name_len = search.name.len;
+ xattr->v.x_name_len = namelen;
xattr->v.x_val_len = cpu_to_le16(size);
- memcpy(xattr->v.x_name, search.name.name, search.name.len);
+ memcpy(xattr->v.x_name, name, namelen);
memcpy(xattr_val(&xattr->v), value, size);
- ret = bch2_hash_set(bch2_xattr_hash_desc, hash_info, c,
- inum, journal_seq,
- &xattr->k_i,
- (flags & XATTR_CREATE ? BCH_HASH_SET_MUST_CREATE : 0)|
- (flags & XATTR_REPLACE ? BCH_HASH_SET_MUST_REPLACE : 0));
- kfree(xattr);
+ ret = __bch2_hash_set(trans, bch2_xattr_hash_desc, hash_info,
+ inum, &xattr->k_i,
+ (flags & XATTR_CREATE ? BCH_HASH_SET_MUST_CREATE : 0)|
+ (flags & XATTR_REPLACE ? BCH_HASH_SET_MUST_REPLACE : 0));
} else {
- ret = bch2_hash_delete(bch2_xattr_hash_desc, hash_info,
- c, inum, journal_seq, &search);
+ struct xattr_search_key search =
+ X_SEARCH(type, name, strlen(name));
+
+ ret = bch2_hash_delete(trans, bch2_xattr_hash_desc,
+ hash_info, inum, &search);
}
if (ret == -ENOENT)
@@ -309,9 +306,11 @@ static int bch2_xattr_set_handler(const struct xattr_handler *handler,
struct bch_inode_info *inode = to_bch_ei(vinode);
struct bch_fs *c = inode->v.i_sb->s_fs_info;
- return bch2_xattr_set(c, inode->v.i_ino, &inode->ei_str_hash,
- name, value, size, flags, handler->flags,
- &inode->ei_journal_seq);
+ return bch2_trans_do(c, &inode->ei_journal_seq, BTREE_INSERT_ATOMIC,
+ bch2_xattr_set(&trans, inode->v.i_ino,
+ &inode->ei_str_hash,
+ name, value, size,
+ handler->flags, flags));
}
static const struct xattr_handler bch_xattr_user_handler = {
diff --git a/fs/bcachefs/xattr.h b/fs/bcachefs/xattr.h
index 1365032d56c3..0689d327cdc4 100644
--- a/fs/bcachefs/xattr.h
+++ b/fs/bcachefs/xattr.h
@@ -35,15 +35,12 @@ struct xattr_handler;
struct bch_hash_info;
struct bch_inode_info;
-struct bkey_s_c bch2_xattr_get_iter(struct bch_fs *,
- struct btree_iter *,
- struct bch_inode_info *,
- const char *, int);
int bch2_xattr_get(struct bch_fs *, struct bch_inode_info *,
const char *, void *, size_t, int);
-int bch2_xattr_set(struct bch_fs *, u64, const struct bch_hash_info *,
- const char *, const void *, size_t, int, int, u64 *);
+int bch2_xattr_set(struct btree_trans *, u64, const struct bch_hash_info *,
+ const char *, const void *, size_t, int, int);
+
ssize_t bch2_xattr_list(struct dentry *, char *, size_t);
extern const struct xattr_handler *bch2_xattr_handlers[];