mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
fuse: support opening 64 bit backing ID
Add backing_id_64 field to fuse_open_out to allow opening files with 64-bit server-allocated backing IDs. If the connection was initialized with FUSE_PASSTHROUGH_V2, the kernel reads the backing ID from open_out.backing_id_64 instead of open_out.backing_id. The open reply is now variable-length for backward compatibility with servers that don't send the new backing_id_64 field. Reviewed-by: Amir Goldstein <amir73il@gmail.com> Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
This commit is contained in:
parent
2f19d54c05
commit
c712cd3625
|
|
@ -876,6 +876,7 @@ static int fuse_create_open(struct mnt_idmap *idmap, struct inode *dir,
|
|||
args.out_args[0].value = &outentry;
|
||||
/* Store outarg for fuse_finish_open() */
|
||||
outopenp = &ff->args->open_outarg;
|
||||
args.out_argvar = true; /* compat */
|
||||
args.out_args[1].size = sizeof(*outopenp);
|
||||
args.out_args[1].value = outopenp;
|
||||
|
||||
|
|
@ -885,7 +886,7 @@ static int fuse_create_open(struct mnt_idmap *idmap, struct inode *dir,
|
|||
|
||||
err = fuse_simple_idmap_request(idmap, fm, &args);
|
||||
free_ext_value(&args);
|
||||
if (err)
|
||||
if (err < 0)
|
||||
goto out_free_ff;
|
||||
|
||||
err = -EIO;
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ static int fuse_send_open(struct fuse_mount *fm, u64 nodeid,
|
|||
{
|
||||
struct fuse_open_in inarg;
|
||||
FUSE_ARGS(args);
|
||||
int res;
|
||||
|
||||
memset(&inarg, 0, sizeof(inarg));
|
||||
inarg.flags = open_flags & ~(O_CREAT | O_EXCL | O_NOCTTY);
|
||||
|
|
@ -45,10 +46,13 @@ static int fuse_send_open(struct fuse_mount *fm, u64 nodeid,
|
|||
args.in_args[0].size = sizeof(inarg);
|
||||
args.in_args[0].value = &inarg;
|
||||
args.out_numargs = 1;
|
||||
args.out_argvar = true; /* compat */
|
||||
args.out_args[0].size = sizeof(*outargp);
|
||||
args.out_args[0].value = outargp;
|
||||
|
||||
return fuse_simple_request(fm, &args);
|
||||
res = fuse_simple_request(fm, &args);
|
||||
|
||||
return res < 0 ? res : 0;
|
||||
}
|
||||
|
||||
struct fuse_file *fuse_file_alloc(struct fuse_mount *fm, bool release)
|
||||
|
|
|
|||
|
|
@ -1314,7 +1314,7 @@ static inline struct fuse_backing *fuse_inode_backing_set(struct fuse_inode *fi,
|
|||
#endif
|
||||
}
|
||||
|
||||
struct fuse_backing *fuse_passthrough_open(struct file *file, int backing_id);
|
||||
int fuse_passthrough_open(struct file *file, struct fuse_backing *fb);
|
||||
void fuse_passthrough_release(struct fuse_file *ff, struct fuse_backing *fb);
|
||||
|
||||
static inline bool fuse_is_passthrough(struct fuse_file *ff)
|
||||
|
|
|
|||
|
|
@ -165,7 +165,9 @@ static int fuse_file_passthrough_open(struct inode *inode, struct file *file)
|
|||
{
|
||||
struct fuse_file *ff = file->private_data;
|
||||
struct fuse_conn *fc = get_fuse_conn(inode);
|
||||
struct fuse_open_out *outarg = &ff->args->open_outarg;
|
||||
struct fuse_backing *fb;
|
||||
u64 backing_id;
|
||||
int err;
|
||||
|
||||
/* Check allowed conditions for file open in passthrough mode */
|
||||
|
|
@ -175,18 +177,39 @@ static int fuse_file_passthrough_open(struct inode *inode, struct file *file)
|
|||
if (ff->open_flags & ~FOPEN_PASSTHROUGH_MASK)
|
||||
return fuse_EIO("conflicting open flags");
|
||||
|
||||
fb = fuse_passthrough_open(file, ff->args->open_outarg.backing_id);
|
||||
if (IS_ERR(fb))
|
||||
return PTR_ERR(fb);
|
||||
if (!fc->backing_id_64) {
|
||||
if (outarg->backing_id_64 != 0)
|
||||
return fuse_EIO("64 bit backing ID set");
|
||||
|
||||
if (outarg->backing_id <= 0)
|
||||
return fuse_EIO("invalid backing ID");
|
||||
|
||||
backing_id = outarg->backing_id;
|
||||
} else {
|
||||
if (outarg->backing_id != 0)
|
||||
return fuse_EIO("32 bit backing ID set");
|
||||
|
||||
backing_id = outarg->backing_id_64;
|
||||
}
|
||||
fb = fuse_backing_lookup(fc, backing_id);
|
||||
if (!fb)
|
||||
return fuse_EIO("backing not found");
|
||||
|
||||
err = fuse_passthrough_open(file, fb);
|
||||
if (err)
|
||||
goto backing_put;
|
||||
|
||||
/* First passthrough file open denies caching inode io mode */
|
||||
err = fuse_file_uncached_io_open(inode, ff, fb);
|
||||
if (!err)
|
||||
return 0;
|
||||
if (err)
|
||||
goto passthrough_release;
|
||||
|
||||
return 0;
|
||||
|
||||
passthrough_release:
|
||||
fuse_passthrough_release(ff, fb);
|
||||
backing_put:
|
||||
fuse_backing_put(fb);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -163,41 +163,25 @@ int fuse_passthrough_fadvise(struct fuse_file *ff, loff_t offset, loff_t len, in
|
|||
|
||||
/*
|
||||
* Setup passthrough to a backing file.
|
||||
*
|
||||
* Returns an fb object with elevated refcount to be stored in fuse inode.
|
||||
*/
|
||||
struct fuse_backing *fuse_passthrough_open(struct file *file, int backing_id)
|
||||
int fuse_passthrough_open(struct file *file, struct fuse_backing *fb)
|
||||
{
|
||||
struct fuse_file *ff = file->private_data;
|
||||
struct fuse_conn *fc = ff->fm->fc;
|
||||
struct fuse_backing *fb = NULL;
|
||||
struct file *backing_file;
|
||||
|
||||
if (fc->backing_id_64)
|
||||
return ERR_PTR(fuse_EIO("incompatible backing version"));
|
||||
|
||||
if (backing_id <= 0)
|
||||
return ERR_PTR(fuse_EIO("invalid backing_id"));
|
||||
|
||||
fb = fuse_backing_lookup(fc, backing_id);
|
||||
if (!fb)
|
||||
return ERR_PTR(fuse_EIO("backing not found"));
|
||||
|
||||
/* Allocate backing file per fuse file to store fuse path */
|
||||
backing_file = backing_file_open(file, file->f_flags,
|
||||
&fb->file->f_path, fb->cred);
|
||||
if (IS_ERR(backing_file)) {
|
||||
fuse_backing_put(fb);
|
||||
return ERR_PTR(fuse_EIO("failed to open backing file (%ld)", PTR_ERR(backing_file)));
|
||||
}
|
||||
if (IS_ERR(backing_file))
|
||||
return fuse_EIO("failed to open backing file (%ld)", PTR_ERR(backing_file));
|
||||
|
||||
ff->passthrough = backing_file;
|
||||
ff->cred = get_cred(fb->cred);
|
||||
|
||||
pr_debug("%s: backing_id=%d, fb=0x%p, backing_file=0x%p\n", __func__,
|
||||
backing_id, fb, ff->passthrough);
|
||||
pr_debug("%s: backing_id=%llu, fb=0x%p, backing_file=0x%p\n", __func__,
|
||||
fb->backing_id, fb, ff->passthrough);
|
||||
|
||||
return fb;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void fuse_passthrough_release(struct fuse_file *ff, struct fuse_backing *fb)
|
||||
|
|
|
|||
|
|
@ -254,6 +254,7 @@
|
|||
* - add FUSE_PASSTHROUGH_V2
|
||||
* - add FUSE_DEV_IOC_BACKING_CREATE, struct fuse_backing_create_in
|
||||
* - add FUSE_NOTIFY_BACKING_REMOVE, struct fuse_notify_backing_remove_out
|
||||
* - add backing_id_64 to fuse_open_out
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_FUSE_H
|
||||
|
|
@ -841,6 +842,7 @@ struct fuse_open_out {
|
|||
uint64_t fh;
|
||||
uint32_t open_flags;
|
||||
int32_t backing_id;
|
||||
uint64_t backing_id_64;
|
||||
};
|
||||
|
||||
struct fuse_release_in {
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user