On Thu, 24 Oct 2024 at 18:47, Hanna Czenczek <hreitz@xxxxxxxxxx> wrote: > To be able to issue INIT (and GETATTR), we need to at least partially > initialize the super_block structure, which is currently done via > fuse_fill_super_common(). What exactly is needed to be initialized? > @@ -1762,18 +1801,12 @@ int fuse_fill_super_common(struct super_block *sb, struct fuse_fs_context *ctx) > sb->s_d_op = &fuse_dentry_operations; > > mutex_lock(&fuse_mutex); > - err = -EINVAL; > - if (ctx->fudptr && *ctx->fudptr) > - goto err_unlock; > - > err = fuse_ctl_add_conn(fc); > if (err) > goto err_unlock; > > list_add_tail(&fc->entry, &fuse_conn_list); > sb->s_root = root_dentry; > - if (ctx->fudptr) > - *ctx->fudptr = fud; This is wrong, because we need the fuse_mutex protection for checking and setting the private_data on the fuse device file. If this split is needed (which I'm not sure) then fud allocation should probably be moved to part2 instead of moving the *ctx->fudptr setup to part1. > @@ -1635,8 +1657,16 @@ static void virtio_kill_sb(struct super_block *sb) > struct fuse_mount *fm = get_fuse_mount_super(sb); > bool last; > > - /* If mount failed, we can still be called without any fc */ > - if (sb->s_root) { > + /* > + * Only destroy the connection after full initialization, i.e. > + * once s_root is set (see commit d534d31d6a45d). > + * One exception: For virtio-fs, we call INIT before s_root is > + * set so we can determine the root node's mode. We must call > + * DESTROY after INIT. So if an error occurs during that time > + * window (specifically in fuse_make_root_inode()), we still > + * need to call virtio_fs_conn_destroy() here. > + */ > + if (sb->s_root || (fm->fc && fm->fc->initialized && !fm->submount)) { How could fm->submount be set if sb->s_root isn't? Or sb->s_root set and fc->initialized isn't? Seems it would be sufficient to check fm->fc->initialized, no? Thanks, Miklos