On Mon, Oct 16, 2023 at 7:09 PM Amir Goldstein <amir73il@xxxxxxxxx> wrote: > > FUSE server calls the FUSE_DEV_IOC_BACKING_OPEN ioctl with a backing file > descriptor. If the call succeeds, a backing file identifier is returned. > > A later reply to OPEN request with the flag FOPEN_PASSTHROUGH will setup > passthrough of file operations on the open FUSE file to the backing file > associated with the id. If there is no backing file associated with id, > FOPEN_PASSTHROUGH flag is ignored. > > The FUSE server may call FUSE_DEV_IOC_BACKING_CLOSE ioctl to close the > backing file by its id. > If there is no backing file with that id, -ENOENT is returned. > > This can be done at any time, but if an open reply with FOPEN_PASSTHROUGH > flag is still in progress, the open may or may not end up setting up the > passthrough to the backing file. > > In any case, the backing file will be kept open by the FUSE driver until > the last fuse_file that was setup to passthrough to that backing file is > closed AND the FUSE_DEV_IOC_BACKING_CLOSE ioctl was called. > > Setting up backing files requires a server with CAP_SYS_ADMIN privileges. > For the backing file to be successfully setup, the backing file must > implement both read_iter and write_iter file operations. > > The limitation on the level of filesystem stacking allowed for the > backing file is enforced before setting up the backing file. > > Signed-off-by: Alessio Balsini <balsini@xxxxxxxxxxx> > Signed-off-by: Amir Goldstein <amir73il@xxxxxxxxx> > --- [...] > +int fuse_backing_open(struct fuse_conn *fc, struct fuse_backing_map *map) > +{ > + struct file *file; > + struct super_block *backing_sb; > + struct fuse_backing *fb = NULL; > + int res; > + > + pr_debug("%s: fd=%d flags=0x%x\n", __func__, map->fd, map->flags); > + > + /* TODO: relax CAP_SYS_ADMIN once backing files are visible to lsof */ > + res = -EPERM; > + if (!fc->passthrough || !capable(CAP_SYS_ADMIN)) > + goto out; > + > + res = -EINVAL; > + if (map->flags) > + goto out; > + > + file = fget(map->fd); > + res = -EBADF; > + if (!file) > + goto out; > + > + res = -EOPNOTSUPP; > + if (!file->f_op->read_iter || !file->f_op->write_iter) > + goto out_fput; > + Miklos, I need to clarify one thing regarding this patch. Your suggestion was: - mapping request is done with an O_PATH fd. - fuse_open() always opens a backing file (just like overlayfs) The reason I did not use fget_raw() to support O_PATH fd is because I wanted to keep the EOPNOTSUPP check above at ioctl time rather than deferring it to open/create reply time, when the user has no feedback of failure reasons. We could add O_PATH support later, but I think it is going to be more important when we support passthrough to inode operations and the limitation of requiring a non O_PATH fd is not is not that bad. It also serves as a proof that the server user is allowed to open the backing file for read/write and avoid the later permission failure of backing_file_open(). Thanks, Amir.