diff options
-rw-r--r-- | fs/bcachefs/Makefile | 1 | ||||
-rw-r--r-- | fs/bcachefs/dirent.c | 97 | ||||
-rw-r--r-- | fs/bcachefs/dirent.h | 29 | ||||
-rw-r--r-- | fs/bcachefs/fs-common.c | 280 | ||||
-rw-r--r-- | fs/bcachefs/fs-common.h | 37 | ||||
-rw-r--r-- | fs/bcachefs/fs-ioctl.c | 10 | ||||
-rw-r--r-- | fs/bcachefs/fs.c | 495 | ||||
-rw-r--r-- | fs/bcachefs/fs.h | 13 | ||||
-rw-r--r-- | fs/bcachefs/fsck.c | 76 | ||||
-rw-r--r-- | fs/bcachefs/inode.c | 39 | ||||
-rw-r--r-- | fs/bcachefs/inode.h | 16 | ||||
-rw-r--r-- | fs/bcachefs/recovery.c | 26 |
12 files changed, 586 insertions, 533 deletions
diff --git a/fs/bcachefs/Makefile b/fs/bcachefs/Makefile index 4c2608409144..9d120936703a 100644 --- a/fs/bcachefs/Makefile +++ b/fs/bcachefs/Makefile @@ -27,6 +27,7 @@ bcachefs-y := \ error.o \ extents.o \ fs.o \ + fs-common.o \ fs-ioctl.o \ fs-io.o \ fsck.o \ diff --git a/fs/bcachefs/dirent.c b/fs/bcachefs/dirent.c index 38dd96808e90..304128d7251f 100644 --- a/fs/bcachefs/dirent.c +++ b/fs/bcachefs/dirent.c @@ -138,10 +138,10 @@ static struct bkey_i_dirent *dirent_create_key(struct btree_trans *trans, return dirent; } -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) +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; @@ -155,16 +155,6 @@ int __bch2_dirent_create(struct btree_trans *trans, dir_inum, &dirent->k_i, flags); } -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, struct bkey_s_c_dirent src) { @@ -172,23 +162,22 @@ static void dirent_copy_target(struct bkey_i_dirent *dst, dst->v.d_type = src.v->d_type; } -static struct bpos bch2_dirent_pos(struct bch_inode_info *inode, - const struct qstr *name) -{ - return POS(inode->v.i_ino, bch2_dirent_hash(&inode->ei_str_hash, name)); -} - 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, - enum bch_rename_mode mode) + u64 src_dir, struct bch_hash_info *src_hash, + u64 dst_dir, struct bch_hash_info *dst_hash, + const struct qstr *src_name, u64 *src_inum, + const struct qstr *dst_name, u64 *dst_inum, + enum bch_rename_mode mode) { struct btree_iter *src_iter, *dst_iter; struct bkey_s_c old_src, old_dst; struct bkey_i_dirent *new_src = NULL, *new_dst = NULL; - struct bpos dst_pos = bch2_dirent_pos(dst_dir, dst_name); + struct bpos dst_pos = + POS(dst_dir, bch2_dirent_hash(dst_hash, dst_name)); int ret; + *src_inum = *dst_inum = 0; + /* * Lookup dst: * @@ -198,24 +187,25 @@ int bch2_dirent_rename(struct btree_trans *trans, */ 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) + dst_hash, dst_dir, dst_name) : bch2_hash_lookup(trans, bch2_dirent_hash_desc, - &dst_dir->ei_str_hash, - dst_dir->v.i_ino, dst_name, + dst_hash, dst_dir, dst_name, BTREE_ITER_INTENT); if (IS_ERR(dst_iter)) return PTR_ERR(dst_iter); old_dst = bch2_btree_iter_peek_slot(dst_iter); + if (mode != BCH_RENAME) + *dst_inum = le64_to_cpu(bkey_s_c_to_dirent(old_dst).v->d_inum); + /* Lookup src: */ src_iter = bch2_hash_lookup(trans, bch2_dirent_hash_desc, - &src_dir->ei_str_hash, - src_dir->v.i_ino, src_name, + src_hash, src_dir, src_name, BTREE_ITER_INTENT); if (IS_ERR(src_iter)) return PTR_ERR(src_iter); old_src = bch2_btree_iter_peek_slot(src_iter); + *src_inum = le64_to_cpu(bkey_s_c_to_dirent(old_src).v->d_inum); /* Create new dst key: */ new_dst = dirent_create_key(trans, 0, dst_name, 0); @@ -269,8 +259,7 @@ int bch2_dirent_rename(struct btree_trans *trans, } 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); + src_hash, src_iter); if (ret < 0) return ret; @@ -284,12 +273,12 @@ int bch2_dirent_rename(struct btree_trans *trans, return 0; } -int __bch2_dirent_delete(struct btree_trans *trans, u64 dir_inum, - const struct bch_hash_info *hash_info, - const struct qstr *name) +int bch2_dirent_delete_at(struct btree_trans *trans, + const struct bch_hash_info *hash_info, + struct btree_iter *iter) { - return bch2_hash_delete(trans, bch2_dirent_hash_desc, hash_info, - dir_inum, name); + return bch2_hash_delete_at(trans, bch2_dirent_hash_desc, + hash_info, iter); } int bch2_dirent_delete(struct bch_fs *c, u64 dir_inum, @@ -300,7 +289,17 @@ int bch2_dirent_delete(struct bch_fs *c, u64 dir_inum, return bch2_trans_do(c, journal_seq, BTREE_INSERT_ATOMIC| BTREE_INSERT_NOFAIL, - __bch2_dirent_delete(&trans, dir_inum, hash_info, name)); + bch2_hash_delete(&trans, bch2_dirent_hash_desc, hash_info, + dir_inum, name)); +} + +struct btree_iter * +__bch2_dirent_lookup_trans(struct btree_trans *trans, u64 dir_inum, + const struct bch_hash_info *hash_info, + const struct qstr *name) +{ + return bch2_hash_lookup(trans, bch2_dirent_hash_desc, + hash_info, dir_inum, name, 0); } u64 bch2_dirent_lookup(struct bch_fs *c, u64 dir_inum, @@ -314,8 +313,7 @@ u64 bch2_dirent_lookup(struct bch_fs *c, u64 dir_inum, bch2_trans_init(&trans, c, 0, 0); - iter = bch2_hash_lookup(&trans, bch2_dirent_hash_desc, - hash_info, dir_inum, name, 0); + iter = __bch2_dirent_lookup_trans(&trans, dir_inum, hash_info, name); if (IS_ERR(iter)) { BUG_ON(PTR_ERR(iter) == -EINTR); goto out; @@ -349,16 +347,8 @@ int bch2_empty_dir_trans(struct btree_trans *trans, u64 dir_inum) return ret; } -int bch2_empty_dir(struct bch_fs *c, u64 dir_inum) +int bch2_readdir(struct bch_fs *c, u64 inum, struct dir_context *ctx) { - return bch2_trans_do(c, NULL, 0, - bch2_empty_dir_trans(&trans, dir_inum)); -} - -int bch2_readdir(struct bch_fs *c, struct file *file, - struct dir_context *ctx) -{ - struct bch_inode_info *inode = file_bch_inode(file); struct btree_trans trans; struct btree_iter *iter; struct bkey_s_c k; @@ -366,22 +356,19 @@ int bch2_readdir(struct bch_fs *c, struct file *file, unsigned len; int ret; - if (!dir_emit_dots(file, ctx)) - return 0; - bch2_trans_init(&trans, c, 0, 0); for_each_btree_key(&trans, iter, BTREE_ID_DIRENTS, - POS(inode->v.i_ino, ctx->pos), 0, k, ret) { + POS(inum, ctx->pos), 0, k, ret) { if (k.k->type != KEY_TYPE_dirent) continue; dirent = bkey_s_c_to_dirent(k); - if (bkey_cmp(k.k->p, POS(inode->v.i_ino, ctx->pos)) < 0) + if (bkey_cmp(k.k->p, POS(inum, ctx->pos)) < 0) continue; - if (k.k->p.inode > inode->v.i_ino) + if (k.k->p.inode > inum) break; len = bch2_dirent_name_bytes(dirent); diff --git a/fs/bcachefs/dirent.h b/fs/bcachefs/dirent.h index bc64718a7832..9a57ad005468 100644 --- a/fs/bcachefs/dirent.h +++ b/fs/bcachefs/dirent.h @@ -29,15 +29,13 @@ static inline unsigned dirent_val_u64s(unsigned len) sizeof(u64)); } -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_create(struct btree_trans *, u64, + const struct bch_hash_info *, u8, + const struct qstr *, u64, int); + +int bch2_dirent_delete_at(struct btree_trans *, + const struct bch_hash_info *, + struct btree_iter *); int bch2_dirent_delete(struct bch_fs *, u64, const struct bch_hash_info *, const struct qstr *, u64 *); @@ -48,15 +46,20 @@ enum bch_rename_mode { }; int bch2_dirent_rename(struct btree_trans *, - struct bch_inode_info *, const struct qstr *, - struct bch_inode_info *, const struct qstr *, + u64, struct bch_hash_info *, + u64, struct bch_hash_info *, + const struct qstr *, u64 *, + const struct qstr *, u64 *, enum bch_rename_mode); +struct btree_iter * +__bch2_dirent_lookup_trans(struct btree_trans *, u64, + const struct bch_hash_info *, + const struct qstr *); u64 bch2_dirent_lookup(struct bch_fs *, u64, const struct bch_hash_info *, const struct qstr *); int bch2_empty_dir_trans(struct btree_trans *, u64); -int bch2_empty_dir(struct bch_fs *, u64); -int bch2_readdir(struct bch_fs *, struct file *, struct dir_context *); +int bch2_readdir(struct bch_fs *, u64, struct dir_context *); #endif /* _BCACHEFS_DIRENT_H */ diff --git a/fs/bcachefs/fs-common.c b/fs/bcachefs/fs-common.c new file mode 100644 index 000000000000..fdd2b9b6716f --- /dev/null +++ b/fs/bcachefs/fs-common.c @@ -0,0 +1,280 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include "bcachefs.h" +#include "acl.h" +#include "btree_update.h" +#include "dirent.h" +#include "fs-common.h" +#include "inode.h" +#include "xattr.h" + +#include <linux/posix_acl.h> + +int bch2_create_trans(struct btree_trans *trans, u64 dir_inum, + struct bch_inode_unpacked *dir_u, + struct bch_inode_unpacked *new_inode, + const struct qstr *name, + uid_t uid, gid_t gid, umode_t mode, dev_t rdev, + struct posix_acl *default_acl, + struct posix_acl *acl) +{ + struct bch_fs *c = trans->c; + struct btree_iter *dir_iter; + struct bch_hash_info hash = bch2_hash_info_init(c, new_inode); + u64 now = bch2_current_time(trans->c); + int ret; + + dir_iter = bch2_inode_peek(trans, dir_u, dir_inum, + name ? BTREE_ITER_INTENT : 0); + if (IS_ERR(dir_iter)) + return PTR_ERR(dir_iter); + + bch2_inode_init_late(new_inode, now, uid, gid, mode, rdev, dir_u); + + if (!name) + new_inode->bi_flags |= BCH_INODE_UNLINKED; + + ret = bch2_inode_create(trans, new_inode, + BLOCKDEV_INODE_MAX, 0, + &c->unused_inode_hint); + if (ret) + return ret; + + if (default_acl) { + ret = bch2_set_acl_trans(trans, new_inode, &hash, + default_acl, ACL_TYPE_DEFAULT); + if (ret) + return ret; + } + + if (acl) { + ret = bch2_set_acl_trans(trans, new_inode, &hash, + acl, ACL_TYPE_ACCESS); + if (ret) + return ret; + } + + if (name) { + struct bch_hash_info dir_hash = bch2_hash_info_init(c, dir_u); + dir_u->bi_mtime = dir_u->bi_ctime = now; + + if (S_ISDIR(new_inode->bi_mode)) + dir_u->bi_nlink++; + + ret = bch2_inode_write(trans, dir_iter, dir_u); + if (ret) + return ret; + + ret = bch2_dirent_create(trans, dir_inum, &dir_hash, + mode_to_type(new_inode->bi_mode), + name, new_inode->bi_inum, + BCH_HASH_SET_MUST_CREATE); + if (ret) + return ret; + } + + return 0; +} + +int bch2_link_trans(struct btree_trans *trans, + u64 dir_inum, + u64 inum, struct bch_inode_unpacked *inode_u, + const struct qstr *name) +{ + struct btree_iter *dir_iter, *inode_iter; + struct bch_inode_unpacked dir_u; + struct bch_hash_info dir_hash; + u64 now = bch2_current_time(trans->c); + + dir_iter = bch2_inode_peek(trans, &dir_u, dir_inum, 0); + if (IS_ERR(dir_iter)) + return PTR_ERR(dir_iter); + + inode_iter = bch2_inode_peek(trans, inode_u, inum, BTREE_ITER_INTENT); + if (IS_ERR(inode_iter)) + return PTR_ERR(inode_iter); + + dir_hash = bch2_hash_info_init(trans->c, &dir_u); + + inode_u->bi_ctime = now; + bch2_inode_nlink_inc(inode_u); + + return bch2_dirent_create(trans, dir_inum, &dir_hash, + mode_to_type(inode_u->bi_mode), + name, inum, BCH_HASH_SET_MUST_CREATE) ?: + bch2_inode_write(trans, inode_iter, inode_u); +} + +int bch2_unlink_trans(struct btree_trans *trans, + u64 dir_inum, struct bch_inode_unpacked *dir_u, + struct bch_inode_unpacked *inode_u, + const struct qstr *name) +{ + struct btree_iter *dir_iter, *dirent_iter, *inode_iter; + struct bch_hash_info dir_hash; + u64 inum, now = bch2_current_time(trans->c); + struct bkey_s_c k; + + dir_iter = bch2_inode_peek(trans, dir_u, dir_inum, BTREE_ITER_INTENT); + if (IS_ERR(dir_iter)) + return PTR_ERR(dir_iter); + + dir_hash = bch2_hash_info_init(trans->c, dir_u); + + dirent_iter = __bch2_dirent_lookup_trans(trans, dir_inum, + &dir_hash, name); + if (IS_ERR(dirent_iter)) + return PTR_ERR(dirent_iter); + + k = bch2_btree_iter_peek_slot(dirent_iter); + inum = le64_to_cpu(bkey_s_c_to_dirent(k).v->d_inum); + + inode_iter = bch2_inode_peek(trans, inode_u, inum, BTREE_ITER_INTENT); + if (IS_ERR(inode_iter)) + return PTR_ERR(inode_iter); + + dir_u->bi_mtime = dir_u->bi_ctime = inode_u->bi_ctime = now; + dir_u->bi_nlink -= S_ISDIR(inode_u->bi_mode); + bch2_inode_nlink_dec(inode_u); + + return (S_ISDIR(inode_u->bi_mode) + ? bch2_empty_dir_trans(trans, inum) + : 0) ?: + bch2_dirent_delete_at(trans, &dir_hash, dirent_iter) ?: + bch2_inode_write(trans, dir_iter, dir_u) ?: + bch2_inode_write(trans, inode_iter, inode_u); +} + +bool bch2_reinherit_attrs(struct bch_inode_unpacked *dst_u, + struct bch_inode_unpacked *src_u) +{ + u64 src, dst; + unsigned id; + bool ret = false; + + for (id = 0; id < Inode_opt_nr; id++) { + if (dst_u->bi_fields_set & (1 << id)) + continue; + + src = bch2_inode_opt_get(src_u, id); + dst = bch2_inode_opt_get(dst_u, id); + + if (src == dst) + continue; + + bch2_inode_opt_set(dst_u, id, src); + ret = true; + } + + return ret; +} + +int bch2_rename_trans(struct btree_trans *trans, + u64 src_dir, struct bch_inode_unpacked *src_dir_u, + u64 dst_dir, struct bch_inode_unpacked *dst_dir_u, + struct bch_inode_unpacked *src_inode_u, + struct bch_inode_unpacked *dst_inode_u, + const struct qstr *src_name, + const struct qstr *dst_name, + enum bch_rename_mode mode) +{ + struct btree_iter *src_dir_iter, *dst_dir_iter = NULL; + struct btree_iter *src_inode_iter, *dst_inode_iter = NULL; + struct bch_hash_info src_hash, dst_hash; + u64 src_inode, dst_inode, now = bch2_current_time(trans->c); + int ret; + + src_dir_iter = bch2_inode_peek(trans, src_dir_u, src_dir, + BTREE_ITER_INTENT); + if (IS_ERR(src_dir_iter)) + return PTR_ERR(src_dir_iter); + + src_hash = bch2_hash_info_init(trans->c, src_dir_u); + + if (dst_dir != src_dir) { + dst_dir_iter = bch2_inode_peek(trans, dst_dir_u, dst_dir, + BTREE_ITER_INTENT); + if (IS_ERR(dst_dir_iter)) + return PTR_ERR(dst_dir_iter); + + dst_hash = bch2_hash_info_init(trans->c, dst_dir_u); + } else { + dst_dir_u = src_dir_u; + dst_hash = src_hash; + } + + ret = bch2_dirent_rename(trans, + src_dir, &src_hash, + dst_dir, &dst_hash, + src_name, &src_inode, + dst_name, &dst_inode, + mode); + if (ret) + return ret; + + src_inode_iter = bch2_inode_peek(trans, src_inode_u, src_inode, + BTREE_ITER_INTENT); + if (IS_ERR(src_inode_iter)) + return PTR_ERR(src_inode_iter); + + if (dst_inode) { + dst_inode_iter = bch2_inode_peek(trans, dst_inode_u, dst_inode, + BTREE_ITER_INTENT); + if (IS_ERR(dst_inode_iter)) + return PTR_ERR(dst_inode_iter); + } + + if (mode == BCH_RENAME_OVERWRITE) { + if (S_ISDIR(src_inode_u->bi_mode) != + S_ISDIR(dst_inode_u->bi_mode)) + return -ENOTDIR; + + if (S_ISDIR(dst_inode_u->bi_mode) && + bch2_empty_dir_trans(trans, dst_inode)) + return -ENOTEMPTY; + } + + if (bch2_reinherit_attrs(src_inode_u, dst_dir_u) && + S_ISDIR(src_inode_u->bi_mode)) + return -EXDEV; + + if (mode == BCH_RENAME_EXCHANGE && + bch2_reinherit_attrs(dst_inode_u, src_dir_u) && + S_ISDIR(dst_inode_u->bi_mode)) + return -EXDEV; + + if (S_ISDIR(src_inode_u->bi_mode)) { + src_dir_u->bi_nlink--; + dst_dir_u->bi_nlink++; + } + + if (dst_inode && S_ISDIR(dst_inode_u->bi_mode)) { + dst_dir_u->bi_nlink--; + src_dir_u->bi_nlink += mode == BCH_RENAME_EXCHANGE; + } + + if (mode == BCH_RENAME_OVERWRITE) + bch2_inode_nlink_dec(dst_inode_u); + + src_dir_u->bi_mtime = now; + src_dir_u->bi_ctime = now; + + if (src_dir != dst_dir) { + dst_dir_u->bi_mtime = now; + dst_dir_u->bi_ctime = now; + } + + src_inode_u->bi_ctime = now; + + if (dst_inode) + dst_inode_u->bi_ctime = now; + + return bch2_inode_write(trans, src_dir_iter, src_dir_u) ?: + (src_dir != dst_dir + ? bch2_inode_write(trans, dst_dir_iter, dst_dir_u) + : 0 ) ?: + bch2_inode_write(trans, src_inode_iter, src_inode_u) ?: + (dst_inode + ? bch2_inode_write(trans, dst_inode_iter, dst_inode_u) + : 0 ); +} diff --git a/fs/bcachefs/fs-common.h b/fs/bcachefs/fs-common.h new file mode 100644 index 000000000000..7adcfcf92aec --- /dev/null +++ b/fs/bcachefs/fs-common.h @@ -0,0 +1,37 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _BCACHEFS_FS_COMMON_H +#define _BCACHEFS_FS_COMMON_H + +struct posix_acl; + +int bch2_create_trans(struct btree_trans *, u64, + struct bch_inode_unpacked *, + struct bch_inode_unpacked *, + const struct qstr *, + uid_t, gid_t, umode_t, dev_t, + struct posix_acl *, + struct posix_acl *); + +int bch2_link_trans(struct btree_trans *, + u64, + u64, struct bch_inode_unpacked *, + const struct qstr *); + +int bch2_unlink_trans(struct btree_trans *, + u64, struct bch_inode_unpacked *, + struct bch_inode_unpacked *, + const struct qstr *); + +int bch2_rename_trans(struct btree_trans *, + u64, struct bch_inode_unpacked *, + u64, struct bch_inode_unpacked *, + struct bch_inode_unpacked *, + struct bch_inode_unpacked *, + const struct qstr *, + const struct qstr *, + enum bch_rename_mode); + +bool bch2_reinherit_attrs(struct bch_inode_unpacked *, + struct bch_inode_unpacked *); + +#endif /* _BCACHEFS_FS_COMMON_H */ diff --git a/fs/bcachefs/fs-ioctl.c b/fs/bcachefs/fs-ioctl.c index 0cf2621ec4fc..acc0a230ff0c 100644 --- a/fs/bcachefs/fs-ioctl.c +++ b/fs/bcachefs/fs-ioctl.c @@ -5,6 +5,7 @@ #include "chardev.h" #include "dirent.h" #include "fs.h" +#include "fs-common.h" #include "fs-ioctl.h" #include "quota.h" @@ -164,6 +165,15 @@ err: return ret; } +static int bch2_reinherit_attrs_fn(struct bch_inode_info *inode, + struct bch_inode_unpacked *bi, + void *p) +{ + struct bch_inode_info *dir = p; + + return !bch2_reinherit_attrs(bi, &dir->ei_inode); +} + static int bch2_ioc_reinherit_attrs(struct bch_fs *c, struct file *file, struct bch_inode_info *src, diff --git a/fs/bcachefs/fs.c b/fs/bcachefs/fs.c index cbe1b90e80c2..b19a2deed5c1 100644 --- a/fs/bcachefs/fs.c +++ b/fs/bcachefs/fs.c @@ -9,6 +9,7 @@ #include "dirent.h" #include "extents.h" #include "fs.h" +#include "fs-common.h" #include "fs-io.h" #include "fs-ioctl.h" #include "fsck.h" @@ -148,34 +149,13 @@ void bch2_inode_update_after_write(struct bch_fs *c, bch2_inode_flags_to_vfs(inode); } -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 btree_iter *iter = NULL; - int ret = 0; - - iter = bch2_inode_peek(trans, inode_u, inode->v.i_ino, - BTREE_ITER_INTENT); - ret = PTR_ERR_OR_ZERO(iter); - if (ret) - return ret; - - ret = set ? set(inode, inode_u, p) : 0; - if (ret) - return ret; - - return bch2_inode_write(trans, iter, inode_u); -} - 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 btree_iter *iter; struct bch_inode_unpacked inode_u; int ret; @@ -183,7 +163,11 @@ int __must_check bch2_write_inode(struct bch_fs *c, retry: bch2_trans_begin(&trans); - ret = bch2_write_inode_trans(&trans, inode, &inode_u, set, p) ?: + iter = bch2_inode_peek(&trans, &inode_u, inode->v.i_ino, + BTREE_ITER_INTENT); + ret = PTR_ERR_OR_ZERO(iter) ?: + (set ? set(inode, &inode_u, p) : 0) ?: + bch2_inode_write(&trans, iter, &inode_u) ?: bch2_trans_commit(&trans, NULL, &inode->ei_journal_seq, BTREE_INSERT_ATOMIC| @@ -238,32 +222,6 @@ int bch2_fs_quota_transfer(struct bch_fs *c, return ret; } -int bch2_reinherit_attrs_fn(struct bch_inode_info *inode, - struct bch_inode_unpacked *bi, - void *p) -{ - struct bch_inode_info *dir = p; - u64 src, dst; - unsigned id; - int ret = 1; - - for (id = 0; id < Inode_opt_nr; id++) { - if (bi->bi_fields_set & (1 << id)) - continue; - - src = bch2_inode_opt_get(&dir->ei_inode, id); - dst = bch2_inode_opt_get(bi, id); - - if (src == dst) - continue; - - bch2_inode_opt_set(bi, id, src); - ret = 0; - } - - return ret; -} - struct inode *bch2_vfs_inode_get(struct bch_fs *c, u64 inum) { struct bch_inode_unpacked inode_u; @@ -291,39 +249,6 @@ struct inode *bch2_vfs_inode_get(struct bch_fs *c, u64 inum) return &inode->v; } -static void bch2_inode_init_owner(struct bch_inode_unpacked *inode_u, - const struct inode *dir, umode_t mode) -{ - kuid_t uid = current_fsuid(); - kgid_t gid; - - if (dir && dir->i_mode & S_ISGID) { - gid = dir->i_gid; - if (S_ISDIR(mode)) - mode |= S_ISGID; - } else - gid = current_fsgid(); - - inode_u->bi_uid = from_kuid(i_user_ns(dir), uid); - inode_u->bi_gid = from_kgid(i_user_ns(dir), gid); - inode_u->bi_mode = mode; -} - -static int inode_update_for_create_fn(struct bch_inode_info *inode, - struct bch_inode_unpacked *bi, - void *p) -{ - struct bch_fs *c = inode->v.i_sb->s_fs_info; - struct bch_inode_unpacked *new_inode = p; - - bi->bi_mtime = bi->bi_ctime = bch2_current_time(c); - - if (S_ISDIR(new_inode->bi_mode)) - bi->bi_nlink++; - - return 0; -} - static int inum_test(struct inode *inode, void *p) { unsigned long *ino = p; @@ -341,40 +266,27 @@ __bch2_create(struct mnt_idmap *idmap, struct bch_inode_unpacked dir_u; struct bch_inode_info *inode, *old; struct bch_inode_unpacked inode_u; - struct bch_hash_info hash_info; struct posix_acl *default_acl = NULL, *acl = NULL; u64 journal_seq = 0; int ret; - bch2_inode_init(c, &inode_u, 0, 0, 0, rdev, &dir->ei_inode); - bch2_inode_init_owner(&inode_u, &dir->v, mode); - - hash_info = bch2_hash_info_init(c, &inode_u); - - if (tmpfile) - inode_u.bi_flags |= BCH_INODE_UNLINKED; - - ret = bch2_quota_acct(c, bch_qid(&inode_u), Q_INO, 1, - KEY_TYPE_QUOTA_PREALLOC); - if (ret) - return ERR_PTR(ret); - + /* + * preallocate acls + vfs inode before btree transaction, so that + * nothing can fail after the transaction succeeds: + */ #ifdef CONFIG_BCACHEFS_POSIX_ACL - ret = posix_acl_create(&dir->v, &inode_u.bi_mode, &default_acl, &acl); + ret = posix_acl_create(&dir->v, &mode, &default_acl, &acl); if (ret) - goto err; + return ERR_PTR(ret); #endif - - /* - * preallocate vfs inode before btree transaction, so that nothing can - * fail after the transaction succeeds: - */ inode = to_bch_ei(new_inode(c->vfs_sb)); if (unlikely(!inode)) { - ret = -ENOMEM; + inode = ERR_PTR(-ENOMEM); goto err; } + bch2_inode_init_early(c, &inode_u); + if (!tmpfile) mutex_lock(&dir->ei_update_lock); @@ -382,38 +294,28 @@ __bch2_create(struct mnt_idmap *idmap, retry: bch2_trans_begin(&trans); - ret = __bch2_inode_create(&trans, &inode_u, - BLOCKDEV_INODE_MAX, 0, - &c->unused_inode_hint) ?: - (default_acl - ? bch2_set_acl_trans(&trans, &inode_u, &hash_info, - default_acl, ACL_TYPE_DEFAULT) - : 0) ?: - (acl - ? bch2_set_acl_trans(&trans, &inode_u, &hash_info, - acl, ACL_TYPE_ACCESS) - : 0) ?: - (!tmpfile - ? __bch2_dirent_create(&trans, dir->v.i_ino, - &dir->ei_str_hash, - mode_to_type(mode), - &dentry->d_name, - inode_u.bi_inum, - BCH_HASH_SET_MUST_CREATE) - : 0) ?: - (!tmpfile - ? bch2_write_inode_trans(&trans, dir, &dir_u, - inode_update_for_create_fn, - &inode_u) - : 0) ?: - bch2_trans_commit(&trans, NULL, - &journal_seq, + ret = bch2_create_trans(&trans, dir->v.i_ino, &dir_u, &inode_u, + !tmpfile ? &dentry->d_name : NULL, + from_kuid(i_user_ns(&dir->v), current_fsuid()), + from_kgid(i_user_ns(&dir->v), current_fsgid()), + mode, rdev, + default_acl, acl) ?: + bch2_quota_acct(c, bch_qid(&inode_u), Q_INO, 1, + KEY_TYPE_QUOTA_PREALLOC); + if (unlikely(ret)) + goto err_before_quota; + + ret = bch2_trans_commit(&trans, NULL, &journal_seq, BTREE_INSERT_ATOMIC| BTREE_INSERT_NOUNLOCK); - if (ret == -EINTR) - goto retry; - if (unlikely(ret)) + if (unlikely(ret)) { + bch2_quota_acct(c, bch_qid(&inode_u), Q_INO, -1, + KEY_TYPE_QUOTA_WARN); +err_before_quota: + if (ret == -EINTR) + goto retry; goto err_trans; + } if (!tmpfile) { bch2_inode_update_after_write(c, dir, &dir_u, @@ -444,7 +346,7 @@ retry: * We raced, another process pulled the new inode into cache * before us: */ - old->ei_journal_seq = inode->ei_journal_seq; + journal_seq_copy(old, journal_seq); make_bad_inode(&inode->v); iput(&inode->v); @@ -458,7 +360,7 @@ retry: } bch2_trans_exit(&trans); -out: +err: posix_acl_release(default_acl); posix_acl_release(acl); return inode; @@ -469,10 +371,8 @@ err_trans: bch2_trans_exit(&trans); make_bad_inode(&inode->v); iput(&inode->v); -err: - bch2_quota_acct(c, bch_qid(&inode_u), Q_INO, -1, KEY_TYPE_QUOTA_WARN); inode = ERR_PTR(ret); - goto out; + goto err; } /* methods */ @@ -515,40 +415,23 @@ static int __bch2_link(struct bch_fs *c, struct dentry *dentry) { struct btree_trans trans; - struct btree_iter *inode_iter; struct bch_inode_unpacked inode_u; int ret; mutex_lock(&inode->ei_update_lock); bch2_trans_init(&trans, c, 4, 1024); -retry: - bch2_trans_begin(&trans); - ret = __bch2_dirent_create(&trans, dir->v.i_ino, - &dir->ei_str_hash, - mode_to_type(inode->v.i_mode), - &dentry->d_name, - inode->v.i_ino, - BCH_HASH_SET_MUST_CREATE); - if (ret) - goto err; - inode_iter = bch2_inode_peek(&trans, &inode_u, inode->v.i_ino, - BTREE_ITER_INTENT); - ret = PTR_ERR_OR_ZERO(inode_iter); - if (ret) - goto err; - - inode_u.bi_ctime = bch2_current_time(c); - bch2_inode_nlink_inc(&inode_u); - - ret = bch2_inode_write(&trans, inode_iter, &inode_u) ?: - bch2_trans_commit(&trans, NULL, - &inode->ei_journal_seq, - BTREE_INSERT_ATOMIC| - BTREE_INSERT_NOUNLOCK); -err: - if (ret == -EINTR) - goto retry; + do { + bch2_trans_begin(&trans); + ret = bch2_link_trans(&trans, + dir->v.i_ino, + inode->v.i_ino, &inode_u, + &dentry->d_name) ?: + bch2_trans_commit(&trans, NULL, + &inode->ei_journal_seq, + BTREE_INSERT_ATOMIC| + BTREE_INSERT_NOUNLOCK); + } while (ret == -EINTR); if (likely(!ret)) bch2_inode_update_after_write(c, inode, &inode_u, ATTR_CTIME); @@ -582,60 +465,36 @@ static int bch2_unlink(struct inode *vdir, struct dentry *dentry) struct bch_fs *c = vdir->i_sb->s_fs_info; struct bch_inode_info *dir = to_bch_ei(vdir); struct bch_inode_info *inode = to_bch_ei(dentry->d_inode); - struct btree_iter *dir_iter, *inode_iter; struct bch_inode_unpacked dir_u, inode_u; struct btree_trans trans; int ret; bch2_lock_inodes(INODE_UPDATE_LOCK, dir, inode); bch2_trans_init(&trans, c, 4, 1024); -retry: - bch2_trans_begin(&trans); - - ret = __bch2_dirent_delete(&trans, dir->v.i_ino, - &dir->ei_str_hash, - &dentry->d_name); - if (ret) - goto btree_err; - - dir_iter = bch2_inode_peek(&trans, &dir_u, dir->v.i_ino, - BTREE_ITER_INTENT); - ret = PTR_ERR_OR_ZERO(dir_iter); - if (ret) - goto btree_err; - - inode_iter = bch2_inode_peek(&trans, &inode_u, inode->v.i_ino, - BTREE_ITER_INTENT); - ret = PTR_ERR_OR_ZERO(inode_iter); - if (ret) - goto btree_err; - - dir_u.bi_mtime = dir_u.bi_ctime = inode_u.bi_ctime = - bch2_current_time(c); - - dir_u.bi_nlink -= S_ISDIR(inode_u.bi_mode); - bch2_inode_nlink_dec(&inode_u); - ret = bch2_inode_write(&trans, dir_iter, &dir_u) ?: - bch2_inode_write(&trans, inode_iter, &inode_u) ?: - bch2_trans_commit(&trans, NULL, - &dir->ei_journal_seq, - BTREE_INSERT_ATOMIC| - BTREE_INSERT_NOUNLOCK| - BTREE_INSERT_NOFAIL); -btree_err: - if (ret == -EINTR) - goto retry; - if (ret) - goto err; - - journal_seq_copy(inode, dir->ei_journal_seq); + do { + bch2_trans_begin(&trans); + + ret = bch2_unlink_trans(&trans, + dir->v.i_ino, &dir_u, + &inode_u, &dentry->d_name) ?: + bch2_trans_commit(&trans, NULL, + &dir->ei_journal_seq, + BTREE_INSERT_ATOMIC| + BTREE_INSERT_NOUNLOCK| + BTREE_INSERT_NOFAIL); + } while (ret == -EINTR); + + if (likely(!ret)) { + BUG_ON(inode_u.bi_inum != inode->v.i_ino); + + journal_seq_copy(inode, dir->ei_journal_seq); + bch2_inode_update_after_write(c, dir, &dir_u, + ATTR_MTIME|ATTR_CTIME); + bch2_inode_update_after_write(c, inode, &inode_u, + ATTR_MTIME); + } - bch2_inode_update_after_write(c, dir, &dir_u, - ATTR_MTIME|ATTR_CTIME); - bch2_inode_update_after_write(c, inode, &inode_u, - ATTR_MTIME); -err: bch2_trans_exit(&trans); bch2_unlock_inodes(INODE_UPDATE_LOCK, dir, inode); @@ -693,11 +552,6 @@ static int bch2_mkdir(struct mnt_idmap *idmap, static int bch2_rmdir(struct inode *vdir, struct dentry *dentry) { - struct bch_fs *c = vdir->i_sb->s_fs_info; - - if (bch2_empty_dir(c, dentry->d_inode->i_ino)) - return -ENOTEMPTY; - return bch2_unlink(vdir, dentry); } @@ -715,99 +569,31 @@ static int bch2_mknod(struct mnt_idmap *idmap, return 0; } -struct rename_info { - u64 now; - struct bch_inode_info *src_dir; - struct bch_inode_info *dst_dir; - struct bch_inode_info *src_inode; - struct bch_inode_info *dst_inode; - enum bch_rename_mode mode; -}; - -static int inode_update_for_rename_fn(struct bch_inode_info *inode, - struct bch_inode_unpacked *bi, - void *p) -{ - struct rename_info *info = p; - int ret; - - if (inode == info->src_dir) { - bi->bi_nlink -= S_ISDIR(info->src_inode->v.i_mode); - bi->bi_nlink += info->dst_inode && - S_ISDIR(info->dst_inode->v.i_mode) && - info->mode == BCH_RENAME_EXCHANGE; - } - - if (inode == info->dst_dir) { - bi->bi_nlink += S_ISDIR(info->src_inode->v.i_mode); - bi->bi_nlink -= info->dst_inode && - S_ISDIR(info->dst_inode->v.i_mode); - } - - if (inode == info->src_inode) { - ret = bch2_reinherit_attrs_fn(inode, bi, info->dst_dir); - - BUG_ON(!ret && S_ISDIR(info->src_inode->v.i_mode)); - } - - if (inode == info->dst_inode && - info->mode == BCH_RENAME_EXCHANGE) { - ret = bch2_reinherit_attrs_fn(inode, bi, info->src_dir); - - BUG_ON(!ret && S_ISDIR(info->dst_inode->v.i_mode)); - } - - if (inode == info->dst_inode && - info->mode == BCH_RENAME_OVERWRITE) { - BUG_ON(bi->bi_nlink && - S_ISDIR(info->dst_inode->v.i_mode)); - - bch2_inode_nlink_dec(bi); - } - - if (inode == info->src_dir || - inode == info->dst_dir) - bi->bi_mtime = info->now; - bi->bi_ctime = info->now; - - return 0; -} - static int bch2_rename2(struct mnt_idmap *idmap, struct inode *src_vdir, struct dentry *src_dentry, struct inode *dst_vdir, struct dentry *dst_dentry, unsigned flags) { struct bch_fs *c = src_vdir->i_sb->s_fs_info; - struct rename_info i = { - .src_dir = to_bch_ei(src_vdir), - .dst_dir = to_bch_ei(dst_vdir), - .src_inode = to_bch_ei(src_dentry->d_inode), - .dst_inode = to_bch_ei(dst_dentry->d_inode), - .mode = flags & RENAME_EXCHANGE - ? BCH_RENAME_EXCHANGE - : dst_dentry->d_inode - ? BCH_RENAME_OVERWRITE : BCH_RENAME, - }; - struct btree_trans trans; + struct bch_inode_info *src_dir = to_bch_ei(src_vdir); + struct bch_inode_info *dst_dir = to_bch_ei(dst_vdir); + struct bch_inode_info *src_inode = to_bch_ei(src_dentry->d_inode); + struct bch_inode_info *dst_inode = to_bch_ei(dst_dentry->d_inode); struct bch_inode_unpacked dst_dir_u, src_dir_u; struct bch_inode_unpacked src_inode_u, dst_inode_u; + struct btree_trans trans; + enum bch_rename_mode mode = flags & RENAME_EXCHANGE + ? BCH_RENAME_EXCHANGE + : dst_dentry->d_inode + ? BCH_RENAME_OVERWRITE : BCH_RENAME; u64 journal_seq = 0; int ret; if (flags & ~(RENAME_NOREPLACE|RENAME_EXCHANGE)) return -EINVAL; - if (i.mode == BCH_RENAME_OVERWRITE) { - if (S_ISDIR(i.src_inode->v.i_mode) != - S_ISDIR(i.dst_inode->v.i_mode)) - return -ENOTDIR; - - if (S_ISDIR(i.src_inode->v.i_mode) && - bch2_empty_dir(c, i.dst_inode->v.i_ino)) - return -ENOTEMPTY; - - ret = filemap_write_and_wait_range(i.src_inode->v.i_mapping, + if (mode == BCH_RENAME_OVERWRITE) { + ret = filemap_write_and_wait_range(src_inode->v.i_mapping, 0, LLONG_MAX); if (ret) return ret; @@ -816,37 +602,24 @@ static int bch2_rename2(struct mnt_idmap *idmap, bch2_trans_init(&trans, c, 8, 2048); bch2_lock_inodes(INODE_UPDATE_LOCK, - i.src_dir, - i.dst_dir, - i.src_inode, - i.dst_inode); - - if (S_ISDIR(i.src_inode->v.i_mode) && - inode_attrs_changing(i.dst_dir, i.src_inode)) { - ret = -EXDEV; - goto err; - } - - if (i.mode == BCH_RENAME_EXCHANGE && - S_ISDIR(i.dst_inode->v.i_mode) && - inode_attrs_changing(i.src_dir, i.dst_inode)) { - ret = -EXDEV; - goto err; - } - - if (inode_attr_changing(i.dst_dir, i.src_inode, Inode_opt_project)) { - ret = bch2_fs_quota_transfer(c, i.src_inode, - i.dst_dir->ei_qid, + src_dir, + dst_dir, + src_inode, + dst_inode); + + if (inode_attr_changing(dst_dir, src_inode, Inode_opt_project)) { + ret = bch2_fs_quota_transfer(c, src_inode, + dst_dir->ei_qid, 1 << QTYP_PRJ, KEY_TYPE_QUOTA_PREALLOC); if (ret) goto err; } - if (i.mode == BCH_RENAME_EXCHANGE && - inode_attr_changing(i.src_dir, i.dst_inode, Inode_opt_project)) { - ret = bch2_fs_quota_transfer(c, i.dst_inode, - i.src_dir->ei_qid, + if (mode == BCH_RENAME_EXCHANGE && + inode_attr_changing(src_dir, dst_inode, Inode_opt_project)) { + ret = bch2_fs_quota_transfer(c, dst_inode, + src_dir->ei_qid, 1 << QTYP_PRJ, KEY_TYPE_QUOTA_PREALLOC); if (ret) @@ -855,24 +628,14 @@ static int bch2_rename2(struct mnt_idmap *idmap, retry: bch2_trans_begin(&trans); - i.now = bch2_current_time(c); - - ret = bch2_dirent_rename(&trans, - i.src_dir, &src_dentry->d_name, - i.dst_dir, &dst_dentry->d_name, - i.mode) ?: - bch2_write_inode_trans(&trans, i.src_dir, &src_dir_u, - inode_update_for_rename_fn, &i) ?: - (i.src_dir != i.dst_dir - ? bch2_write_inode_trans(&trans, i.dst_dir, &dst_dir_u, - inode_update_for_rename_fn, &i) - : 0 ) ?: - bch2_write_inode_trans(&trans, i.src_inode, &src_inode_u, - inode_update_for_rename_fn, &i) ?: - (i.dst_inode - ? bch2_write_inode_trans(&trans, i.dst_inode, &dst_inode_u, - inode_update_for_rename_fn, &i) - : 0 ) ?: + ret = bch2_rename_trans(&trans, + src_dir->v.i_ino, &src_dir_u, + dst_dir->v.i_ino, &dst_dir_u, + &src_inode_u, + &dst_inode_u, + &src_dentry->d_name, + &dst_dentry->d_name, + mode) ?: bch2_trans_commit(&trans, NULL, &journal_seq, BTREE_INSERT_ATOMIC| @@ -882,43 +645,47 @@ retry: if (unlikely(ret)) goto err; - bch2_inode_update_after_write(c, i.src_dir, &src_dir_u, + BUG_ON(src_inode->v.i_ino != src_inode_u.bi_inum); + BUG_ON(dst_inode && + dst_inode->v.i_ino != dst_inode_u.bi_inum); + + bch2_inode_update_after_write(c, src_dir, &src_dir_u, ATTR_MTIME|ATTR_CTIME); - journal_seq_copy(i.src_dir, journal_seq); + journal_seq_copy(src_dir, journal_seq); - if (i.src_dir != i.dst_dir) { - bch2_inode_update_after_write(c, i.dst_dir, &dst_dir_u, + if (src_dir != dst_dir) { + bch2_inode_update_after_write(c, dst_dir, &dst_dir_u, ATTR_MTIME|ATTR_CTIME); - journal_seq_copy(i.dst_dir, journal_seq); + journal_seq_copy(dst_dir, journal_seq); } - journal_seq_copy(i.src_inode, journal_seq); - if (i.dst_inode) - journal_seq_copy(i.dst_inode, journal_seq); - - bch2_inode_update_after_write(c, i.src_inode, &src_inode_u, + bch2_inode_update_after_write(c, src_inode, &src_inode_u, ATTR_CTIME); - if (i.dst_inode) - bch2_inode_update_after_write(c, i.dst_inode, &dst_inode_u, + journal_seq_copy(src_inode, journal_seq); + + if (dst_inode) { + bch2_inode_update_after_write(c, dst_inode, &dst_inode_u, ATTR_CTIME); + journal_seq_copy(dst_inode, journal_seq); + } err: bch2_trans_exit(&trans); - bch2_fs_quota_transfer(c, i.src_inode, - bch_qid(&i.src_inode->ei_inode), + bch2_fs_quota_transfer(c, src_inode, + bch_qid(&src_inode->ei_inode), 1 << QTYP_PRJ, KEY_TYPE_QUOTA_NOCHECK); - if (i.dst_inode) - bch2_fs_quota_transfer(c, i.dst_inode, - bch_qid(&i.dst_inode->ei_inode), + if (dst_inode) + bch2_fs_quota_transfer(c, dst_inode, + bch_qid(&dst_inode->ei_inode), 1 << QTYP_PRJ, KEY_TYPE_QUOTA_NOCHECK); bch2_unlock_inodes(INODE_UPDATE_LOCK, - i.src_dir, - i.dst_dir, - i.src_inode, - i.dst_inode); + src_dir, + dst_dir, + src_inode, + dst_inode); return ret; } @@ -1251,9 +1018,13 @@ static loff_t bch2_dir_llseek(struct file *file, loff_t offset, int whence) static int bch2_vfs_readdir(struct file *file, struct dir_context *ctx) { - struct bch_fs *c = file_inode(file)->i_sb->s_fs_info; + struct bch_inode_info *inode = file_bch_inode(file); + struct bch_fs *c = inode->v.i_sb->s_fs_info; + + if (!dir_emit_dots(file, ctx)) + return 0; - return bch2_readdir(c, file, ctx); + return bch2_readdir(c, inode->v.i_ino, ctx); } static const struct file_operations bch_file_operations = { diff --git a/fs/bcachefs/fs.h b/fs/bcachefs/fs.h index c3ee9c17064f..b3a2993dd9bc 100644 --- a/fs/bcachefs/fs.h +++ b/fs/bcachefs/fs.h @@ -103,11 +103,6 @@ static inline struct bch_inode_info *file_bch_inode(struct file *file) return to_bch_ei(file_inode(file)); } -static inline u8 mode_to_type(umode_t mode) -{ - return (mode >> 12) & 15; -} - static inline bool inode_attr_changing(struct bch_inode_info *dir, struct bch_inode_info *inode, enum inode_opt_id id) @@ -162,17 +157,9 @@ 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 *, unsigned); -int bch2_reinherit_attrs_fn(struct bch_inode_info *, - struct bch_inode_unpacked *, - void *); - void bch2_vfs_exit(void); int bch2_vfs_init(void); diff --git a/fs/bcachefs/fsck.c b/fs/bcachefs/fsck.c index c5540536f47c..5acf1fb64543 100644 --- a/fs/bcachefs/fsck.c +++ b/fs/bcachefs/fsck.c @@ -4,7 +4,7 @@ #include "btree_update.h" #include "dirent.h" #include "error.h" -#include "fs.h" +#include "fs-common.h" #include "fsck.h" #include "inode.h" #include "keylist.h" @@ -80,9 +80,7 @@ static int reattach_inode(struct bch_fs *c, struct bch_inode_unpacked *lostfound_inode, u64 inum) { - struct bch_hash_info lostfound_hash_info = - bch2_hash_info_init(c, lostfound_inode); - struct bkey_inode_buf packed; + struct bch_inode_unpacked inode_u; char name_buf[20]; struct qstr name; int ret; @@ -90,30 +88,14 @@ static int reattach_inode(struct bch_fs *c, snprintf(name_buf, sizeof(name_buf), "%llu", inum); name = (struct qstr) QSTR(name_buf); - lostfound_inode->bi_nlink++; - - bch2_inode_pack(&packed, lostfound_inode); - - ret = bch2_btree_insert(c, BTREE_ID_INODES, &packed.inode.k_i, - NULL, NULL, - BTREE_INSERT_NOFAIL| - BTREE_INSERT_LAZY_RW); - if (ret) { - bch_err(c, "error %i reattaching inode %llu while updating lost+found", - ret, inum); - return ret; - } + ret = bch2_trans_do(c, NULL, + BTREE_INSERT_ATOMIC| + BTREE_INSERT_LAZY_RW, + bch2_link_trans(&trans, lostfound_inode->bi_inum, + inum, &inode_u, &name)); + if (ret) + bch_err(c, "error %i reattaching inode %llu", ret, inum); - ret = bch2_dirent_create(c, lostfound_inode->bi_inum, - &lostfound_hash_info, - DT_DIR, &name, inum, NULL, - BTREE_INSERT_NOFAIL| - BTREE_INSERT_LAZY_RW); - if (ret) { - bch_err(c, "error %i reattaching inode %llu while creating new dirent", - ret, inum); - return ret; - } return ret; } @@ -758,7 +740,7 @@ static int check_root(struct bch_fs *c, struct bch_inode_unpacked *root_inode) fsck_err: return ret; create_root: - bch2_inode_init(c, root_inode, 0, 0, S_IFDIR|S_IRWXU|S_IRUGO|S_IXUGO, + bch2_inode_init(c, root_inode, 0, 0, S_IFDIR|0755, 0, NULL); root_inode->bi_inum = BCACHEFS_ROOT_INO; @@ -778,7 +760,6 @@ static int check_lostfound(struct bch_fs *c, struct qstr lostfound = QSTR("lost+found"); struct bch_hash_info root_hash_info = bch2_hash_info_init(c, root_inode); - struct bkey_inode_buf packed; u64 inum; int ret; @@ -806,33 +787,20 @@ static int check_lostfound(struct bch_fs *c, fsck_err: return ret; create_lostfound: - root_inode->bi_nlink++; - - bch2_inode_pack(&packed, root_inode); - - ret = bch2_btree_insert(c, BTREE_ID_INODES, &packed.inode.k_i, - NULL, NULL, - BTREE_INSERT_NOFAIL| - BTREE_INSERT_LAZY_RW); - if (ret) - return ret; - - bch2_inode_init(c, lostfound_inode, 0, 0, S_IFDIR|S_IRWXU|S_IRUGO|S_IXUGO, - 0, root_inode); - - ret = bch2_inode_create(c, lostfound_inode, BLOCKDEV_INODE_MAX, 0, - &c->unused_inode_hint); + bch2_inode_init_early(c, lostfound_inode); + + ret = bch2_trans_do(c, NULL, + BTREE_INSERT_ATOMIC| + BTREE_INSERT_NOFAIL| + BTREE_INSERT_LAZY_RW, + bch2_create_trans(&trans, + BCACHEFS_ROOT_INO, root_inode, + lostfound_inode, &lostfound, + 0, 0, S_IFDIR|0755, 0, NULL, NULL)); if (ret) - return ret; - - ret = bch2_dirent_create(c, BCACHEFS_ROOT_INO, &root_hash_info, DT_DIR, - &lostfound, lostfound_inode->bi_inum, NULL, - BTREE_INSERT_NOFAIL| - BTREE_INSERT_LAZY_RW); - if (ret) - return ret; + bch_err(c, "error creating lost+found: %i", ret); - return 0; + return ret; } struct inode_bitmap { diff --git a/fs/bcachefs/inode.c b/fs/bcachefs/inode.c index 3dc46faaebbc..aeae536b39f1 100644 --- a/fs/bcachefs/inode.c +++ b/fs/bcachefs/inode.c @@ -297,11 +297,9 @@ void bch2_inode_generation_to_text(struct printbuf *out, struct bch_fs *c, pr_buf(out, "generation: %u", le32_to_cpu(gen.v->bi_generation)); } -void bch2_inode_init(struct bch_fs *c, struct bch_inode_unpacked *inode_u, - uid_t uid, gid_t gid, umode_t mode, dev_t rdev, - struct bch_inode_unpacked *parent) +void bch2_inode_init_early(struct bch_fs *c, + struct bch_inode_unpacked *inode_u) { - s64 now = bch2_current_time(c); enum bch_str_hash_type str_hash = bch2_str_hash_opt_to_type(c, c->opts.str_hash); @@ -311,7 +309,12 @@ void bch2_inode_init(struct bch_fs *c, struct bch_inode_unpacked *inode_u, inode_u->bi_flags |= str_hash << INODE_STR_HASH_OFFSET; get_random_bytes(&inode_u->bi_hash_seed, sizeof(inode_u->bi_hash_seed)); +} +void bch2_inode_init_late(struct bch_inode_unpacked *inode_u, u64 now, + uid_t uid, gid_t gid, umode_t mode, dev_t rdev, + struct bch_inode_unpacked *parent) +{ inode_u->bi_mode = mode; inode_u->bi_uid = uid; inode_u->bi_gid = gid; @@ -321,6 +324,12 @@ void bch2_inode_init(struct bch_fs *c, struct bch_inode_unpacked *inode_u, inode_u->bi_ctime = now; inode_u->bi_otime = now; + if (parent && parent->bi_mode & S_ISGID) { + inode_u->bi_gid = parent->bi_gid; + if (S_ISDIR(mode)) + inode_u->bi_mode |= S_ISGID; + } + if (parent) { #define x(_name, ...) inode_u->bi_##_name = parent->bi_##_name; BCH_INODE_OPTS() @@ -328,6 +337,15 @@ void bch2_inode_init(struct bch_fs *c, struct bch_inode_unpacked *inode_u, } } +void bch2_inode_init(struct bch_fs *c, struct bch_inode_unpacked *inode_u, + uid_t uid, gid_t gid, umode_t mode, dev_t rdev, + struct bch_inode_unpacked *parent) +{ + bch2_inode_init_early(c, inode_u); + bch2_inode_init_late(inode_u, bch2_current_time(c), + uid, gid, mode, rdev, parent); +} + static inline u32 bkey_generation(struct bkey_s_c k) { switch (k.k->type) { @@ -340,9 +358,9 @@ static inline u32 bkey_generation(struct bkey_s_c k) } } -int __bch2_inode_create(struct btree_trans *trans, - struct bch_inode_unpacked *inode_u, - u64 min, u64 max, u64 *hint) +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; @@ -408,13 +426,6 @@ out: 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_rm(struct bch_fs *c, u64 inode_nr) { struct btree_trans trans; diff --git a/fs/bcachefs/inode.h b/fs/bcachefs/inode.h index c5626c668639..b32c0a47c25d 100644 --- a/fs/bcachefs/inode.h +++ b/fs/bcachefs/inode.h @@ -51,14 +51,17 @@ struct btree_iter *bch2_inode_peek(struct btree_trans *, int bch2_inode_write(struct btree_trans *, struct btree_iter *, struct bch_inode_unpacked *); +void bch2_inode_init_early(struct bch_fs *, + struct bch_inode_unpacked *); +void bch2_inode_init_late(struct bch_inode_unpacked *, u64, + uid_t, gid_t, umode_t, dev_t, + 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 *, +int bch2_inode_create(struct btree_trans *, + struct bch_inode_unpacked *, u64, u64, u64 *); int bch2_inode_rm(struct bch_fs *, u64); @@ -108,6 +111,11 @@ static inline u64 bch2_inode_opt_get(struct bch_inode_unpacked *inode, } } +static inline u8 mode_to_type(umode_t mode) +{ + return (mode >> 12) & 15; +} + /* i_nlink: */ static inline unsigned nlink_bias(umode_t mode) diff --git a/fs/bcachefs/recovery.c b/fs/bcachefs/recovery.c index 2e880955a07c..e6015bc13e9b 100644 --- a/fs/bcachefs/recovery.c +++ b/fs/bcachefs/recovery.c @@ -10,6 +10,7 @@ #include "dirent.h" #include "ec.h" #include "error.h" +#include "fs-common.h" #include "fsck.h" #include "journal_io.h" #include "journal_reclaim.h" @@ -952,7 +953,6 @@ int bch2_fs_initialize(struct bch_fs *c) { struct bch_inode_unpacked root_inode, lostfound_inode; struct bkey_inode_buf packed_inode; - struct bch_hash_info root_hash_info; struct qstr lostfound = QSTR("lost+found"); const char *err = "cannot allocate memory"; struct bch_dev *ca; @@ -997,7 +997,6 @@ int bch2_fs_initialize(struct bch_fs *c) bch2_inode_init(c, &root_inode, 0, 0, S_IFDIR|S_IRWXU|S_IRUGO|S_IXUGO, 0, NULL); root_inode.bi_inum = BCACHEFS_ROOT_INO; - root_inode.bi_nlink++; /* lost+found */ bch2_inode_pack(&packed_inode, &root_inode); err = "error creating root directory"; @@ -1007,24 +1006,15 @@ int bch2_fs_initialize(struct bch_fs *c) if (ret) goto err; - bch2_inode_init(c, &lostfound_inode, 0, 0, - S_IFDIR|S_IRWXU|S_IRUGO|S_IXUGO, 0, - &root_inode); - lostfound_inode.bi_inum = BCACHEFS_ROOT_INO + 1; - bch2_inode_pack(&packed_inode, &lostfound_inode); + bch2_inode_init_early(c, &lostfound_inode); err = "error creating lost+found"; - ret = bch2_btree_insert(c, BTREE_ID_INODES, - &packed_inode.inode.k_i, - NULL, NULL, 0); - if (ret) - goto err; - - root_hash_info = bch2_hash_info_init(c, &root_inode); - - ret = bch2_dirent_create(c, BCACHEFS_ROOT_INO, &root_hash_info, DT_DIR, - &lostfound, lostfound_inode.bi_inum, NULL, - BTREE_INSERT_NOFAIL); + ret = bch2_trans_do(c, NULL, BTREE_INSERT_ATOMIC, + bch2_create_trans(&trans, BCACHEFS_ROOT_INO, + &root_inode, &lostfound_inode, + &lostfound, + 0, 0, 0755, 0, + NULL, NULL)); if (ret) goto err; |