]> git.sesse.net Git - bcachefs-tools-debian/blobdiff - libbcachefs/fs.c
Update bcachefs sources to b964c6cba8 bcachefs: Change lockrestart_do() to always...
[bcachefs-tools-debian] / libbcachefs / fs.c
index a2654c862b7bc0978668fae0fe87cbd4ef830068..631fb87b81c9ca9866eaab3413fbe916a6fd4e5a 100644 (file)
 #include <linux/exportfs.h>
 #include <linux/fiemap.h>
 #include <linux/module.h>
+#include <linux/pagemap.h>
 #include <linux/posix_acl.h>
 #include <linux/random.h>
 #include <linux/statfs.h>
+#include <linux/string.h>
 #include <linux/xattr.h>
 
 static struct kmem_cache *bch2_inode_cache;
@@ -143,7 +145,7 @@ int __must_check bch2_write_inode(struct bch_fs *c,
        struct bch_inode_unpacked inode_u;
        int ret;
 
-       bch2_trans_init(&trans, c, 0, 0);
+       bch2_trans_init(&trans, c, 0, 512);
 retry:
        bch2_trans_begin(&trans);
 
@@ -154,7 +156,6 @@ retry:
                bch2_inode_write(&trans, iter, &inode_u) ?:
                bch2_trans_commit(&trans, NULL,
                                  &inode->ei_journal_seq,
-                                 BTREE_INSERT_NOUNLOCK|
                                  BTREE_INSERT_NOFAIL);
 
        /*
@@ -243,11 +244,11 @@ static int inum_test(struct inode *inode, void *p)
 }
 
 static struct bch_inode_info *
-__bch2_create(struct bch_inode_info *dir, struct dentry *dentry,
+__bch2_create(struct user_namespace *mnt_userns,
+             struct bch_inode_info *dir, struct dentry *dentry,
              umode_t mode, dev_t rdev, bool tmpfile)
 {
        struct bch_fs *c = dir->v.i_sb->s_fs_info;
-       struct user_namespace *ns = dir->v.i_sb->s_user_ns;
        struct btree_trans trans;
        struct bch_inode_unpacked dir_u;
        struct bch_inode_info *inode, *old;
@@ -283,8 +284,8 @@ retry:
 
        ret   = bch2_create_trans(&trans, dir->v.i_ino, &dir_u, &inode_u,
                                  !tmpfile ? &dentry->d_name : NULL,
-                                 from_kuid(ns, current_fsuid()),
-                                 from_kgid(ns, current_fsgid()),
+                                 from_kuid(mnt_userns, current_fsuid()),
+                                 from_kgid(mnt_userns, current_fsgid()),
                                  mode, rdev,
                                  default_acl, acl) ?:
                bch2_quota_acct(c, bch_qid(&inode_u), Q_INO, 1,
@@ -292,8 +293,7 @@ retry:
        if (unlikely(ret))
                goto err_before_quota;
 
-       ret   = bch2_trans_commit(&trans, NULL, &journal_seq,
-                                 BTREE_INSERT_NOUNLOCK);
+       ret   = bch2_trans_commit(&trans, NULL, &journal_seq, 0);
        if (unlikely(ret)) {
                bch2_quota_acct(c, bch_qid(&inode_u), Q_INO, -1,
                                KEY_TYPE_QUOTA_WARN);
@@ -368,11 +368,11 @@ static struct dentry *bch2_lookup(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_hash_info hash = bch2_hash_info_init(c, &dir->ei_inode);
        struct inode *vinode = NULL;
        u64 inum;
 
-       inum = bch2_dirent_lookup(c, dir->v.i_ino,
-                                 &dir->ei_str_hash,
+       inum = bch2_dirent_lookup(c, dir->v.i_ino, &hash,
                                  &dentry->d_name);
 
        if (inum)
@@ -381,11 +381,12 @@ static struct dentry *bch2_lookup(struct inode *vdir, struct dentry *dentry,
        return d_splice_alias(vinode, dentry);
 }
 
-static int bch2_mknod(struct inode *vdir, struct dentry *dentry,
+static int bch2_mknod(struct user_namespace *mnt_userns,
+                     struct inode *vdir, struct dentry *dentry,
                      umode_t mode, dev_t rdev)
 {
        struct bch_inode_info *inode =
-               __bch2_create(to_bch_ei(vdir), dentry, mode, rdev, false);
+               __bch2_create(mnt_userns, to_bch_ei(vdir), dentry, mode, rdev, false);
 
        if (IS_ERR(inode))
                return PTR_ERR(inode);
@@ -394,10 +395,11 @@ static int bch2_mknod(struct inode *vdir, struct dentry *dentry,
        return 0;
 }
 
-static int bch2_create(struct inode *vdir, struct dentry *dentry,
+static int bch2_create(struct user_namespace *mnt_userns,
+                      struct inode *vdir, struct dentry *dentry,
                       umode_t mode, bool excl)
 {
-       return bch2_mknod(vdir, dentry, mode|S_IFREG, 0);
+       return bch2_mknod(mnt_userns, vdir, dentry, mode|S_IFREG, 0);
 }
 
 static int __bch2_link(struct bch_fs *c,
@@ -412,16 +414,11 @@ static int __bch2_link(struct bch_fs *c,
        mutex_lock(&inode->ei_update_lock);
        bch2_trans_init(&trans, c, 4, 1024);
 
-       do {
-               bch2_trans_begin(&trans);
-               ret   = bch2_link_trans(&trans,
+       ret = __bch2_trans_do(&trans, NULL, &inode->ei_journal_seq, 0,
+                       bch2_link_trans(&trans,
                                        dir->v.i_ino,
                                        inode->v.i_ino, &dir_u, &inode_u,
-                                       &dentry->d_name) ?:
-                       bch2_trans_commit(&trans, NULL,
-                                       &inode->ei_journal_seq,
-                                       BTREE_INSERT_NOUNLOCK);
-       } while (ret == -EINTR);
+                                       &dentry->d_name));
 
        if (likely(!ret)) {
                BUG_ON(inode_u.bi_inum != inode->v.i_ino);
@@ -468,17 +465,11 @@ static int bch2_unlink(struct inode *vdir, struct dentry *dentry)
        bch2_lock_inodes(INODE_UPDATE_LOCK, dir, inode);
        bch2_trans_init(&trans, c, 4, 1024);
 
-       do {
-               bch2_trans_begin(&trans);
-
-               ret   = bch2_unlink_trans(&trans,
+       ret = __bch2_trans_do(&trans, NULL, &dir->ei_journal_seq,
+                             BTREE_INSERT_NOFAIL,
+                       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_NOUNLOCK|
-                                         BTREE_INSERT_NOFAIL);
-       } while (ret == -EINTR);
+                                         &inode_u, &dentry->d_name));
 
        if (likely(!ret)) {
                BUG_ON(inode_u.bi_inum != inode->v.i_ino);
@@ -496,14 +487,15 @@ static int bch2_unlink(struct inode *vdir, struct dentry *dentry)
        return ret;
 }
 
-static int bch2_symlink(struct inode *vdir, struct dentry *dentry,
+static int bch2_symlink(struct user_namespace *mnt_userns,
+                       struct inode *vdir, struct dentry *dentry,
                        const char *symname)
 {
        struct bch_fs *c = vdir->i_sb->s_fs_info;
        struct bch_inode_info *dir = to_bch_ei(vdir), *inode;
        int ret;
 
-       inode = __bch2_create(dir, dentry, S_IFLNK|S_IRWXUGO, 0, true);
+       inode = __bch2_create(mnt_userns, dir, dentry, S_IFLNK|S_IRWXUGO, 0, true);
        if (unlikely(IS_ERR(inode)))
                return PTR_ERR(inode);
 
@@ -531,12 +523,14 @@ err:
        return ret;
 }
 
-static int bch2_mkdir(struct inode *vdir, struct dentry *dentry, umode_t mode)
+static int bch2_mkdir(struct user_namespace *mnt_userns,
+                     struct inode *vdir, struct dentry *dentry, umode_t mode)
 {
-       return bch2_mknod(vdir, dentry, mode|S_IFDIR, 0);
+       return bch2_mknod(mnt_userns, vdir, dentry, mode|S_IFDIR, 0);
 }
 
-static int bch2_rename2(struct inode *src_vdir, struct dentry *src_dentry,
+static int bch2_rename2(struct user_namespace *mnt_userns,
+                       struct inode *src_vdir, struct dentry *src_dentry,
                        struct inode *dst_vdir, struct dentry *dst_dentry,
                        unsigned flags)
 {
@@ -592,21 +586,15 @@ static int bch2_rename2(struct inode *src_vdir, struct dentry *src_dentry,
                        goto err;
        }
 
-retry:
-       bch2_trans_begin(&trans);
-       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_NOUNLOCK);
-       if (ret == -EINTR)
-               goto retry;
+       ret = __bch2_trans_do(&trans, NULL, &journal_seq, 0,
+                       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));
        if (unlikely(ret))
                goto err;
 
@@ -655,17 +643,21 @@ err:
        return ret;
 }
 
-void bch2_setattr_copy(struct bch_inode_info *inode,
-                      struct bch_inode_unpacked *bi,
-                      struct iattr *attr)
+static void bch2_setattr_copy(struct user_namespace *mnt_userns,
+                             struct bch_inode_info *inode,
+                             struct bch_inode_unpacked *bi,
+                             struct iattr *attr)
 {
        struct bch_fs *c = inode->v.i_sb->s_fs_info;
        unsigned int ia_valid = attr->ia_valid;
 
        if (ia_valid & ATTR_UID)
-               bi->bi_uid = from_kuid(c->vfs_sb->s_user_ns, attr->ia_uid);
+               bi->bi_uid = from_kuid(mnt_userns, attr->ia_uid);
        if (ia_valid & ATTR_GID)
-               bi->bi_gid = from_kgid(c->vfs_sb->s_user_ns, attr->ia_gid);
+               bi->bi_gid = from_kgid(mnt_userns, attr->ia_gid);
+
+       if (ia_valid & ATTR_SIZE)
+               bi->bi_size = attr->ia_size;
 
        if (ia_valid & ATTR_ATIME)
                bi->bi_atime = timespec_to_bch2_time(c, attr->ia_atime);
@@ -681,14 +673,15 @@ void bch2_setattr_copy(struct bch_inode_info *inode,
                        : inode->v.i_gid;
 
                if (!in_group_p(gid) &&
-                   !capable_wrt_inode_uidgid(&inode->v, CAP_FSETID))
+                   !capable_wrt_inode_uidgid(mnt_userns, &inode->v, CAP_FSETID))
                        mode &= ~S_ISGID;
                bi->bi_mode = mode;
        }
 }
 
-static int bch2_setattr_nonsize(struct bch_inode_info *inode,
-                               struct iattr *attr)
+int bch2_setattr_nonsize(struct user_namespace *mnt_userns,
+                        struct bch_inode_info *inode,
+                        struct iattr *attr)
 {
        struct bch_fs *c = inode->v.i_sb->s_fs_info;
        struct bch_qid qid;
@@ -725,10 +718,10 @@ retry:
        if (ret)
                goto btree_err;
 
-       bch2_setattr_copy(inode, &inode_u, attr);
+       bch2_setattr_copy(mnt_userns, inode, &inode_u, attr);
 
        if (attr->ia_valid & ATTR_MODE) {
-               ret = bch2_acl_chmod(&trans, inode, inode_u.bi_mode, &acl);
+               ret = bch2_acl_chmod(&trans, &inode_u, inode_u.bi_mode, &acl);
                if (ret)
                        goto btree_err;
        }
@@ -736,9 +729,10 @@ retry:
        ret =   bch2_inode_write(&trans, inode_iter, &inode_u) ?:
                bch2_trans_commit(&trans, NULL,
                                  &inode->ei_journal_seq,
-                                 BTREE_INSERT_NOUNLOCK|
                                  BTREE_INSERT_NOFAIL);
 btree_err:
+       bch2_trans_iter_put(&trans, inode_iter);
+
        if (ret == -EINTR)
                goto retry;
        if (unlikely(ret))
@@ -756,7 +750,8 @@ err:
        return ret;
 }
 
-static int bch2_getattr(const struct path *path, struct kstat *stat,
+static int bch2_getattr(struct user_namespace *mnt_userns,
+                       const struct path *path, struct kstat *stat,
                        u32 request_mask, unsigned query_flags)
 {
        struct bch_inode_info *inode = to_bch_ei(d_inode(path->dentry));
@@ -796,26 +791,28 @@ static int bch2_getattr(const struct path *path, struct kstat *stat,
        return 0;
 }
 
-static int bch2_setattr(struct dentry *dentry, struct iattr *iattr)
+static int bch2_setattr(struct user_namespace *mnt_userns,
+                       struct dentry *dentry, struct iattr *iattr)
 {
        struct bch_inode_info *inode = to_bch_ei(dentry->d_inode);
        int ret;
 
        lockdep_assert_held(&inode->v.i_rwsem);
 
-       ret = setattr_prepare(dentry, iattr);
+       ret = setattr_prepare(mnt_userns, dentry, iattr);
        if (ret)
                return ret;
 
        return iattr->ia_valid & ATTR_SIZE
-               ? bch2_truncate(inode, iattr)
-               : bch2_setattr_nonsize(inode, iattr);
+               ? bch2_truncate(mnt_userns, inode, iattr)
+               : bch2_setattr_nonsize(mnt_userns, inode, iattr);
 }
 
-static int bch2_tmpfile(struct inode *vdir, struct dentry *dentry, umode_t mode)
+static int bch2_tmpfile(struct user_namespace *mnt_userns,
+                       struct inode *vdir, struct dentry *dentry, umode_t mode)
 {
        struct bch_inode_info *inode =
-               __bch2_create(to_bch_ei(vdir), dentry, mode, 0, true);
+               __bch2_create(mnt_userns, to_bch_ei(vdir), dentry, mode, 0, true);
 
        if (IS_ERR(inode))
                return PTR_ERR(inode);
@@ -903,15 +900,19 @@ static int bch2_fiemap(struct inode *vinode, struct fiemap_extent_info *info,
        bch2_bkey_buf_init(&prev);
        bch2_trans_init(&trans, c, 0, 0);
 
-       iter = bch2_trans_get_iter(&trans, BTREE_ID_EXTENTS,
+       iter = bch2_trans_get_iter(&trans, BTREE_ID_extents,
                                   POS(ei->v.i_ino, start >> 9), 0);
 retry:
+       bch2_trans_begin(&trans);
+
        while ((k = bch2_btree_iter_peek(iter)).k &&
               !(ret = bkey_err(k)) &&
               bkey_cmp(iter->pos, end) < 0) {
+               enum btree_id data_btree = BTREE_ID_extents;
+
                if (!bkey_extent_is_data(k.k) &&
                    k.k->type != KEY_TYPE_reservation) {
-                       bch2_btree_iter_next(iter);
+                       bch2_btree_iter_advance(iter);
                        continue;
                }
 
@@ -921,7 +922,7 @@ retry:
 
                bch2_bkey_buf_reassemble(&cur, c, k);
 
-               ret = bch2_read_indirect_extent(&trans,
+               ret = bch2_read_indirect_extent(&trans, &data_btree,
                                        &offset_into_extent, &cur);
                if (ret)
                        break;
@@ -960,6 +961,7 @@ retry:
                ret = bch2_fill_extent(c, info, bkey_i_to_s_c(prev.k),
                                       FIEMAP_EXTENT_LAST);
 
+       bch2_trans_iter_put(&trans, iter);
        ret = bch2_trans_exit(&trans) ?: ret;
        bch2_bkey_buf_exit(&cur, c);
        bch2_bkey_buf_exit(&prev, c);
@@ -1007,10 +1009,7 @@ static const struct file_operations bch_file_operations = {
        .open           = generic_file_open,
        .fsync          = bch2_fsync,
        .splice_read    = generic_file_splice_read,
-#if 0
-       /* Busted: */
        .splice_write   = iter_file_splice_write,
-#endif
        .fallocate      = bch2_fallocate_dispatch,
        .unlocked_ioctl = bch2_fs_file_ioctl,
 #ifdef CONFIG_COMPAT
@@ -1154,7 +1153,6 @@ static void bch2_vfs_inode_init(struct bch_fs *c,
        inode->ei_flags         = 0;
        inode->ei_journal_seq   = 0;
        inode->ei_quota_reserved = 0;
-       inode->ei_str_hash      = bch2_hash_info_init(c, bi);
        inode->ei_qid           = bch_qid(bi);
 
        inode->v.i_mapping->a_ops = &bch_address_space_operations;
@@ -1273,8 +1271,8 @@ static int bch2_statfs(struct dentry *dentry, struct kstatfs *buf)
        buf->f_type     = BCACHEFS_STATFS_MAGIC;
        buf->f_bsize    = sb->s_blocksize;
        buf->f_blocks   = usage.capacity >> shift;
-       buf->f_bfree    = (usage.capacity - usage.used) >> shift;
-       buf->f_bavail   = buf->f_bfree;
+       buf->f_bfree    = usage.free >> shift;
+       buf->f_bavail   = avail_factor(usage.free) >> shift;
 
        buf->f_files    = usage.nr_inodes + avail_inodes;
        buf->f_ffree    = avail_inodes;
@@ -1303,16 +1301,17 @@ static int bch2_sync_fs(struct super_block *sb, int wait)
        return bch2_journal_flush(&c->journal);
 }
 
-static struct bch_fs *bch2_path_to_fs(const char *dev)
+static struct bch_fs *bch2_path_to_fs(const char *path)
 {
        struct bch_fs *c;
-       struct block_device *bdev = lookup_bdev(dev);
+       dev_t dev;
+       int ret;
 
-       if (IS_ERR(bdev))
-               return ERR_CAST(bdev);
+       ret = lookup_bdev(path, &dev);
+       if (ret)
+               return ERR_PTR(ret);
 
-       c = bch2_bdev_to_fs(bdev);
-       bdput(bdev);
+       c = bch2_dev_to_fs(dev);
        if (c)
                closure_put(&c->cl);
        return c ?: ERR_PTR(-ENOENT);
@@ -1498,6 +1497,9 @@ static struct dentry *bch2_mount(struct file_system_type *fs_type,
        if (ret)
                return ERR_PTR(ret);
 
+       if (!dev_name || strlen(dev_name) == 0)
+               return ERR_PTR(-EINVAL);
+
        devs = split_devs(dev_name, &nr_devs);
        if (!devs)
                return ERR_PTR(-ENOMEM);
@@ -1564,7 +1566,9 @@ got_sb:
 #endif
        sb->s_xattr             = bch2_xattr_handlers;
        sb->s_magic             = BCACHEFS_STATFS_MAGIC;
-       sb->s_time_gran         = c->sb.time_precision;
+       sb->s_time_gran         = c->sb.nsec_per_time_unit;
+       sb->s_time_min          = div_s64(S64_MIN, c->sb.time_units_per_sec) + 1;
+       sb->s_time_max          = div_s64(S64_MAX, c->sb.time_units_per_sec);
        c->vfs_sb               = sb;
        strlcpy(sb->s_id, c->name, sizeof(sb->s_id));
 
@@ -1584,6 +1588,8 @@ got_sb:
                break;
        }
 
+       c->dev = sb->s_dev;
+
 #ifdef CONFIG_BCACHEFS_POSIX_ACL
        if (c->opts.acl)
                sb->s_flags     |= SB_POSIXACL;