Merge tag 'fuse-update-6.9' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi...
[linux-2.6-microblaze.git] / fs / fuse / inode.c
index 516ea29..3a5d888 100644 (file)
@@ -111,6 +111,9 @@ static struct inode *fuse_alloc_inode(struct super_block *sb)
        if (IS_ENABLED(CONFIG_FUSE_DAX) && !fuse_dax_inode_alloc(sb, fi))
                goto out_free_forget;
 
+       if (IS_ENABLED(CONFIG_FUSE_PASSTHROUGH))
+               fuse_inode_backing_set(fi, NULL);
+
        return &fi->inode;
 
 out_free_forget:
@@ -129,6 +132,9 @@ static void fuse_free_inode(struct inode *inode)
 #ifdef CONFIG_FUSE_DAX
        kfree(fi->dax);
 #endif
+       if (IS_ENABLED(CONFIG_FUSE_PASSTHROUGH))
+               fuse_backing_put(fuse_inode_backing(fi));
+
        kmem_cache_free(fuse_inode_cachep, fi);
 }
 
@@ -469,8 +475,11 @@ retry:
        } else if (fuse_stale_inode(inode, generation, attr)) {
                /* nodeid was reused, any I/O on the old inode should fail */
                fuse_make_bad(inode);
-               iput(inode);
-               goto retry;
+               if (inode != d_inode(sb->s_root)) {
+                       remove_inode_hash(inode);
+                       iput(inode);
+                       goto retry;
+               }
        }
        fi = get_fuse_inode(inode);
        spin_lock(&fi->lock);
@@ -924,6 +933,9 @@ void fuse_conn_init(struct fuse_conn *fc, struct fuse_mount *fm,
        fc->max_pages = FUSE_DEFAULT_MAX_PAGES_PER_REQ;
        fc->max_pages_limit = FUSE_MAX_MAX_PAGES;
 
+       if (IS_ENABLED(CONFIG_FUSE_PASSTHROUGH))
+               fuse_backing_files_init(fc);
+
        INIT_LIST_HEAD(&fc->mounts);
        list_add(&fm->fc_entry, &fc->mounts);
        fm->fc = fc;
@@ -954,6 +966,8 @@ void fuse_conn_put(struct fuse_conn *fc)
                        WARN_ON(atomic_read(&bucket->count) != 1);
                        kfree(bucket);
                }
+               if (IS_ENABLED(CONFIG_FUSE_PASSTHROUGH))
+                       fuse_backing_files_free(fc);
                call_rcu(&fc->rcu, delayed_release);
        }
 }
@@ -974,7 +988,7 @@ static struct inode *fuse_get_root_inode(struct super_block *sb, unsigned mode)
        attr.mode = mode;
        attr.ino = FUSE_ROOT_ID;
        attr.nlink = 1;
-       return fuse_iget(sb, 1, 0, &attr, 0, 0);
+       return fuse_iget(sb, FUSE_ROOT_ID, 0, &attr, 0, 0);
 }
 
 struct fuse_inode_handle {
@@ -1117,6 +1131,11 @@ static struct dentry *fuse_get_parent(struct dentry *child)
        return parent;
 }
 
+/* only for fid encoding; no support for file handle */
+static const struct export_operations fuse_export_fid_operations = {
+       .encode_fh      = fuse_encode_fh,
+};
+
 static const struct export_operations fuse_export_operations = {
        .fh_to_dentry   = fuse_fh_to_dentry,
        .fh_to_parent   = fuse_fh_to_parent,
@@ -1291,6 +1310,26 @@ static void process_init_reply(struct fuse_mount *fm, struct fuse_args *args,
                                fc->create_supp_group = 1;
                        if (flags & FUSE_DIRECT_IO_ALLOW_MMAP)
                                fc->direct_io_allow_mmap = 1;
+                       /*
+                        * max_stack_depth is the max stack depth of FUSE fs,
+                        * so it has to be at least 1 to support passthrough
+                        * to backing files.
+                        *
+                        * with max_stack_depth > 1, the backing files can be
+                        * on a stacked fs (e.g. overlayfs) themselves and with
+                        * max_stack_depth == 1, FUSE fs can be stacked as the
+                        * underlying fs of a stacked fs (e.g. overlayfs).
+                        */
+                       if (IS_ENABLED(CONFIG_FUSE_PASSTHROUGH) &&
+                           (flags & FUSE_PASSTHROUGH) &&
+                           arg->max_stack_depth > 0 &&
+                           arg->max_stack_depth <= FILESYSTEM_MAX_STACK_DEPTH) {
+                               fc->passthrough = 1;
+                               fc->max_stack_depth = arg->max_stack_depth;
+                               fm->sb->s_stack_depth = arg->max_stack_depth;
+                       }
+                       if (flags & FUSE_NO_EXPORT_SUPPORT)
+                               fm->sb->s_export_op = &fuse_export_fid_operations;
                } else {
                        ra_pages = fc->max_read / PAGE_SIZE;
                        fc->no_lock = 1;
@@ -1337,7 +1376,8 @@ void fuse_send_init(struct fuse_mount *fm)
                FUSE_NO_OPENDIR_SUPPORT | FUSE_EXPLICIT_INVAL_DATA |
                FUSE_HANDLE_KILLPRIV_V2 | FUSE_SETXATTR_EXT | FUSE_INIT_EXT |
                FUSE_SECURITY_CTX | FUSE_CREATE_SUPP_GROUP |
-               FUSE_HAS_EXPIRE_ONLY | FUSE_DIRECT_IO_ALLOW_MMAP;
+               FUSE_HAS_EXPIRE_ONLY | FUSE_DIRECT_IO_ALLOW_MMAP |
+               FUSE_NO_EXPORT_SUPPORT | FUSE_HAS_RESEND;
 #ifdef CONFIG_FUSE_DAX
        if (fm->fc->dax)
                flags |= FUSE_MAP_ALIGNMENT;
@@ -1346,6 +1386,8 @@ void fuse_send_init(struct fuse_mount *fm)
 #endif
        if (fm->fc->auto_submounts)
                flags |= FUSE_SUBMOUNTS;
+       if (IS_ENABLED(CONFIG_FUSE_PASSTHROUGH))
+               flags |= FUSE_PASSTHROUGH;
 
        ia->in.flags = flags;
        ia->in.flags2 = flags >> 32;
@@ -1496,8 +1538,8 @@ static void fuse_fill_attr_from_inode(struct fuse_attr *attr,
                .ctimensec      = ctime.tv_nsec,
                .mode           = fi->inode.i_mode,
                .nlink          = fi->inode.i_nlink,
-               .uid            = fi->inode.i_uid.val,
-               .gid            = fi->inode.i_gid.val,
+               .uid            = __kuid_val(fi->inode.i_uid),
+               .gid            = __kgid_val(fi->inode.i_gid),
                .rdev           = fi->inode.i_rdev,
                .blksize        = 1u << fi->inode.i_blkbits,
        };
@@ -1534,6 +1576,7 @@ static int fuse_fill_super_submount(struct super_block *sb,
        sb->s_bdi = bdi_get(parent_sb->s_bdi);
 
        sb->s_xattr = parent_sb->s_xattr;
+       sb->s_export_op = parent_sb->s_export_op;
        sb->s_time_gran = parent_sb->s_time_gran;
        sb->s_blocksize = parent_sb->s_blocksize;
        sb->s_blocksize_bits = parent_sb->s_blocksize_bits;