summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@gmail.com>2021-03-16 01:33:39 -0400
committerKent Overstreet <kent.overstreet@linux.dev>2023-03-13 11:34:05 -0400
commit67cc03ac1696dd9ac2eec93e2ac67aa7c9328fd5 (patch)
tree21f62f2ca84db5bd53b508aae6aa52c509b44e98
parent90a936a72c9db12821a844280ac33626cba289bc (diff)
bcachefs: Add subvolume to ei_inode_info
Filesystem operations generally operate within a subvolume: at the start of every btree transaction we'll be looking up (and locking) the subvolume to get the current snapshot ID, which we then use for our other btree lookups in BTREE_ITER_FILTER_SNAPSHOTS mode. But inodes don't record what subvolume they're in - they can't, because if they did we'd have to update every single inode within a subvolume when taking a snapshot in order to keep that field up to date. So it needs to be tracked in memory, based on how we got to that inode. Hence this patch adds a subvolume field to ei_inode_info, and switches to iget5() so we can index by it in the inode hash table. Signed-off-by: Kent Overstreet <kent.overstreet@gmail.com>
-rw-r--r--fs/bcachefs/fs-ioctl.c6
-rw-r--r--fs/bcachefs/fs.c85
-rw-r--r--fs/bcachefs/fs.h12
3 files changed, 76 insertions, 27 deletions
diff --git a/fs/bcachefs/fs-ioctl.c b/fs/bcachefs/fs-ioctl.c
index 91a0e761c8e7..494879b5bed3 100644
--- a/fs/bcachefs/fs-ioctl.c
+++ b/fs/bcachefs/fs-ioctl.c
@@ -192,7 +192,7 @@ static int bch2_ioc_reinherit_attrs(struct bch_fs *c,
char *kname = NULL;
struct qstr qstr;
int ret = 0;
- u64 inum;
+ subvol_inum inum = { .subvol = 1 };
kname = kmalloc(BCH_NAME_MAX + 1, GFP_KERNEL);
if (!kname)
@@ -206,9 +206,9 @@ static int bch2_ioc_reinherit_attrs(struct bch_fs *c,
qstr.name = kname;
ret = -ENOENT;
- inum = bch2_dirent_lookup(c, src->v.i_ino, &hash,
+ inum.inum = bch2_dirent_lookup(c, src->v.i_ino, &hash,
&qstr);
- if (!inum)
+ if (!inum.inum)
goto err1;
vinode = bch2_vfs_inode_get(c, inum);
diff --git a/fs/bcachefs/fs.c b/fs/bcachefs/fs.c
index 52e1f0be8d81..0b42e1c67501 100644
--- a/fs/bcachefs/fs.c
+++ b/fs/bcachefs/fs.c
@@ -37,7 +37,7 @@
static struct kmem_cache *bch2_inode_cache;
-static void bch2_vfs_inode_init(struct bch_fs *,
+static void bch2_vfs_inode_init(struct bch_fs *, subvol_inum,
struct bch_inode_info *,
struct bch_inode_unpacked *);
@@ -209,40 +209,68 @@ int bch2_fs_quota_transfer(struct bch_fs *c,
return ret;
}
-struct inode *bch2_vfs_inode_get(struct bch_fs *c, u64 inum)
+static int bch2_iget5_test(struct inode *vinode, void *p)
+{
+ struct bch_inode_info *inode = to_bch_ei(vinode);
+ subvol_inum *inum = p;
+
+ return inode->ei_subvol == inum->subvol &&
+ inode->ei_inode.bi_inum == inum->inum;
+}
+
+static int bch2_iget5_set(struct inode *vinode, void *p)
+{
+ struct bch_inode_info *inode = to_bch_ei(vinode);
+ subvol_inum *inum = p;
+
+ inode->v.i_ino = inum->inum;
+ inode->ei_subvol = inum->subvol;
+ inode->ei_inode.bi_inum = inum->inum;
+ return 0;
+}
+
+static unsigned bch2_inode_hash(subvol_inum inum)
+{
+ return jhash_3words(inum.subvol, inum.inum >> 32, inum.inum, JHASH_INITVAL);
+}
+
+struct inode *bch2_vfs_inode_get(struct bch_fs *c, subvol_inum inum)
{
struct bch_inode_unpacked inode_u;
struct bch_inode_info *inode;
int ret;
- inode = to_bch_ei(iget_locked(c->vfs_sb, inum));
+ /*
+ * debug assert, to be removed when we start creating
+ * subvolumes/snapshots:
+ */
+ BUG_ON(inum.subvol != BCACHEFS_ROOT_SUBVOL);
+
+ inode = to_bch_ei(iget5_locked(c->vfs_sb,
+ bch2_inode_hash(inum),
+ bch2_iget5_test,
+ bch2_iget5_set,
+ &inum));
if (unlikely(!inode))
return ERR_PTR(-ENOMEM);
if (!(inode->v.i_state & I_NEW))
return &inode->v;
- ret = bch2_inode_find_by_inum(c, inum, &inode_u);
+ ret = bch2_inode_find_by_inum(c, inum.inum, &inode_u);
if (ret) {
iget_failed(&inode->v);
return ERR_PTR(ret);
}
- bch2_vfs_inode_init(c, inode, &inode_u);
+ bch2_vfs_inode_init(c, inum, inode, &inode_u);
- inode->ei_journal_seq = bch2_inode_journal_seq(&c->journal, inum);
+ inode->ei_journal_seq = bch2_inode_journal_seq(&c->journal, inum.inum);
unlock_new_inode(&inode->v);
return &inode->v;
}
-static int inum_test(struct inode *inode, void *p)
-{
- unsigned long *ino = p;
-
- return *ino == inode->i_ino;
-}
-
static struct bch_inode_info *
__bch2_create(struct user_namespace *mnt_userns,
struct bch_inode_info *dir, struct dentry *dentry,
@@ -254,6 +282,7 @@ __bch2_create(struct user_namespace *mnt_userns,
struct bch_inode_info *inode, *old;
struct bch_inode_unpacked inode_u;
struct posix_acl *default_acl = NULL, *acl = NULL;
+ subvol_inum inum;
u64 journal_seq = 0;
int ret;
@@ -310,7 +339,10 @@ err_before_quota:
mutex_unlock(&dir->ei_update_lock);
}
- bch2_vfs_inode_init(c, inode, &inode_u);
+ inum.subvol = inode_u.bi_subvol ?: dir->ei_subvol;
+ inum.inum = inode_u.bi_inum;
+
+ bch2_vfs_inode_init(c, inum, inode, &inode_u);
journal_seq_copy(c, inode, journal_seq);
set_cached_acl(&inode->v, ACL_TYPE_ACCESS, acl);
@@ -323,8 +355,12 @@ err_before_quota:
*/
inode->v.i_state |= I_CREATING;
- old = to_bch_ei(inode_insert5(&inode->v, inode->v.i_ino,
- inum_test, NULL, &inode->v.i_ino));
+
+ old = to_bch_ei(inode_insert5(&inode->v,
+ bch2_inode_hash(inum),
+ bch2_iget5_test,
+ bch2_iget5_set,
+ &inum));
BUG_ON(!old);
if (unlikely(old != inode)) {
@@ -370,12 +406,12 @@ static struct dentry *bch2_lookup(struct inode *vdir, struct dentry *dentry,
struct bch_inode_info *dir = to_bch_ei(vdir);
struct bch_hash_info hash = bch2_hash_info_init(c, &dir->ei_inode);
struct inode *vinode = NULL;
- u64 inum;
+ subvol_inum inum = { .subvol = 1 };
- inum = bch2_dirent_lookup(c, dir->v.i_ino, &hash,
+ inum.inum = bch2_dirent_lookup(c, dir->v.i_ino, &hash,
&dentry->d_name);
- if (inum)
+ if (inum.inum)
vinode = bch2_vfs_inode_get(c, inum);
return d_splice_alias(vinode, dentry);
@@ -1098,6 +1134,7 @@ static const struct address_space_operations bch_address_space_operations = {
.error_remove_page = generic_error_remove_page,
};
+#if 0
static struct inode *bch2_nfs_get_inode(struct super_block *sb,
u64 ino, u32 generation)
{
@@ -1131,14 +1168,15 @@ static struct dentry *bch2_fh_to_parent(struct super_block *sb, struct fid *fid,
return generic_fh_to_parent(sb, fid, fh_len, fh_type,
bch2_nfs_get_inode);
}
+#endif
static const struct export_operations bch_export_ops = {
- .fh_to_dentry = bch2_fh_to_dentry,
- .fh_to_parent = bch2_fh_to_parent,
+ //.fh_to_dentry = bch2_fh_to_dentry,
+ //.fh_to_parent = bch2_fh_to_parent,
//.get_parent = bch2_get_parent,
};
-static void bch2_vfs_inode_init(struct bch_fs *c,
+static void bch2_vfs_inode_init(struct bch_fs *c, subvol_inum inum,
struct bch_inode_info *inode,
struct bch_inode_unpacked *bi)
{
@@ -1154,6 +1192,7 @@ static void bch2_vfs_inode_init(struct bch_fs *c,
inode->ei_journal_seq = 0;
inode->ei_quota_reserved = 0;
inode->ei_qid = bch_qid(bi);
+ inode->ei_subvol = inum.subvol;
inode->v.i_mapping->a_ops = &bch_address_space_operations;
@@ -1595,7 +1634,7 @@ got_sb:
sb->s_flags |= SB_POSIXACL;
#endif
- vinode = bch2_vfs_inode_get(c, BCACHEFS_ROOT_INO);
+ vinode = bch2_vfs_inode_get(c, BCACHEFS_ROOT_SUBVOL_INUM);
if (IS_ERR(vinode)) {
bch_err(c, "error mounting: error getting root inode %i",
(int) PTR_ERR(vinode));
diff --git a/fs/bcachefs/fs.h b/fs/bcachefs/fs.h
index 0a5c54429290..19acaee64f1d 100644
--- a/fs/bcachefs/fs.h
+++ b/fs/bcachefs/fs.h
@@ -44,10 +44,20 @@ struct bch_inode_info {
struct mutex ei_quota_lock;
struct bch_qid ei_qid;
+ u32 ei_subvol;
+
/* copy of inode in btree: */
struct bch_inode_unpacked ei_inode;
};
+static inline subvol_inum inode_inum(struct bch_inode_info *inode)
+{
+ return (subvol_inum) {
+ .subvol = inode->ei_subvol,
+ .inum = inode->ei_inode.bi_inum,
+ };
+}
+
/*
* Set if we've gotten a btree error for this inode, and thus the vfs inode and
* btree inode may be inconsistent:
@@ -153,7 +163,7 @@ static inline int bch2_set_projid(struct bch_fs *c,
KEY_TYPE_QUOTA_PREALLOC);
}
-struct inode *bch2_vfs_inode_get(struct bch_fs *, u64);
+struct inode *bch2_vfs_inode_get(struct bch_fs *, subvol_inum);
/* returns 0 if we want to do the update, or error is passed up */
typedef int (*inode_set_fn)(struct bch_inode_info *,