Signed tag for a set of bugfixes for vboxsf for 5.14
This patch series adds support for the atomic_open directory-inode op to vboxsf. Note this is not just an enhancement this also fixes an actual issue which users are hitting, see the commit message of the "boxsf: Add support for the atomic_open directory-inode" patch. -----BEGIN PGP SIGNATURE----- iQFIBAABCAAyFiEEuvA7XScYQRpenhd+kuxHeUQDJ9wFAmDTLTsUHGhkZWdvZWRl QHJlZGhhdC5jb20ACgkQkuxHeUQDJ9ytCAf8DjQurYh0B+E5i9pFL1hLgS715rnD 4qu8GT7+DF/9Yj8Mpg7aS/v1GNwjWBE506Fj6bc8E3s637OrflBiqqtFM6a/jcfP i3RDtfCiTD9jeDT5OPhV4esuQvXnQ63ldXFSHf1TxaNb4Be8OmACibnSvslyC+Eb YhKtMRH+oKeQfob3rbTJBglkDRe1KUuA2zGPBuYheaLLaYSHrj1xSRCoGY6mJMBJ pP5FCT/nOsgxD6zej3/aa57put9kZoYVlu1TLnCfkggzuirL+82/pABC3ZYTtsM8 jeby97djOI/fufIlVD1yX7q+kzyVWj3ouparoAKsu5TDSmmIRYnfu/RlNA== =yFXG -----END PGP SIGNATURE----- Merge tag 'vboxsf-v5.14-1' of git://git.kernel.org/pub/scm/linux/kernel/git/hansg/linux Pull vboxsf fixes from Hans de Goede: "This adds support for the atomic_open directory-inode op to vboxsf. Note this is not just an enhancement this also fixes an actual issue which users are hitting, see the commit message of the "boxsf: Add support for the atomic_open directory-inode" patch" * tag 'vboxsf-v5.14-1' of git://git.kernel.org/pub/scm/linux/kernel/git/hansg/linux: vboxsf: Add support for the atomic_open directory-inode op vboxsf: Add vboxsf_[create|release]_sf_handle() helpers vboxsf: Make vboxsf_dir_create() return the handle for the created file vboxsf: Honor excl flag to the dir-inode create op
This commit is contained in:
commit
40226a3d96
|
@ -253,7 +253,7 @@ static int vboxsf_dir_instantiate(struct inode *parent, struct dentry *dentry,
|
|||
}
|
||||
|
||||
static int vboxsf_dir_create(struct inode *parent, struct dentry *dentry,
|
||||
umode_t mode, int is_dir)
|
||||
umode_t mode, bool is_dir, bool excl, u64 *handle_ret)
|
||||
{
|
||||
struct vboxsf_inode *sf_parent_i = VBOXSF_I(parent);
|
||||
struct vboxsf_sbi *sbi = VBOXSF_SBI(parent->i_sb);
|
||||
|
@ -261,10 +261,12 @@ static int vboxsf_dir_create(struct inode *parent, struct dentry *dentry,
|
|||
int err;
|
||||
|
||||
params.handle = SHFL_HANDLE_NIL;
|
||||
params.create_flags = SHFL_CF_ACT_CREATE_IF_NEW |
|
||||
SHFL_CF_ACT_FAIL_IF_EXISTS |
|
||||
SHFL_CF_ACCESS_READWRITE |
|
||||
(is_dir ? SHFL_CF_DIRECTORY : 0);
|
||||
params.create_flags = SHFL_CF_ACT_CREATE_IF_NEW | SHFL_CF_ACCESS_READWRITE;
|
||||
if (is_dir)
|
||||
params.create_flags |= SHFL_CF_DIRECTORY;
|
||||
if (excl)
|
||||
params.create_flags |= SHFL_CF_ACT_FAIL_IF_EXISTS;
|
||||
|
||||
params.info.attr.mode = (mode & 0777) |
|
||||
(is_dir ? SHFL_TYPE_DIRECTORY : SHFL_TYPE_FILE);
|
||||
params.info.attr.additional = SHFLFSOBJATTRADD_NOTHING;
|
||||
|
@ -276,30 +278,81 @@ static int vboxsf_dir_create(struct inode *parent, struct dentry *dentry,
|
|||
if (params.result != SHFL_FILE_CREATED)
|
||||
return -EPERM;
|
||||
|
||||
vboxsf_close(sbi->root, params.handle);
|
||||
|
||||
err = vboxsf_dir_instantiate(parent, dentry, ¶ms.info);
|
||||
if (err)
|
||||
return err;
|
||||
goto out;
|
||||
|
||||
/* parent directory access/change time changed */
|
||||
sf_parent_i->force_restat = 1;
|
||||
|
||||
return 0;
|
||||
out:
|
||||
if (err == 0 && handle_ret)
|
||||
*handle_ret = params.handle;
|
||||
else
|
||||
vboxsf_close(sbi->root, params.handle);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int vboxsf_dir_mkfile(struct user_namespace *mnt_userns,
|
||||
struct inode *parent, struct dentry *dentry,
|
||||
umode_t mode, bool excl)
|
||||
{
|
||||
return vboxsf_dir_create(parent, dentry, mode, 0);
|
||||
return vboxsf_dir_create(parent, dentry, mode, false, excl, NULL);
|
||||
}
|
||||
|
||||
static int vboxsf_dir_mkdir(struct user_namespace *mnt_userns,
|
||||
struct inode *parent, struct dentry *dentry,
|
||||
umode_t mode)
|
||||
{
|
||||
return vboxsf_dir_create(parent, dentry, mode, 1);
|
||||
return vboxsf_dir_create(parent, dentry, mode, true, true, NULL);
|
||||
}
|
||||
|
||||
static int vboxsf_dir_atomic_open(struct inode *parent, struct dentry *dentry,
|
||||
struct file *file, unsigned int flags, umode_t mode)
|
||||
{
|
||||
struct vboxsf_sbi *sbi = VBOXSF_SBI(parent->i_sb);
|
||||
struct vboxsf_handle *sf_handle;
|
||||
struct dentry *res = NULL;
|
||||
u64 handle;
|
||||
int err;
|
||||
|
||||
if (d_in_lookup(dentry)) {
|
||||
res = vboxsf_dir_lookup(parent, dentry, 0);
|
||||
if (IS_ERR(res))
|
||||
return PTR_ERR(res);
|
||||
|
||||
if (res)
|
||||
dentry = res;
|
||||
}
|
||||
|
||||
/* Only creates */
|
||||
if (!(flags & O_CREAT) || d_really_is_positive(dentry))
|
||||
return finish_no_open(file, res);
|
||||
|
||||
err = vboxsf_dir_create(parent, dentry, mode, false, flags & O_EXCL, &handle);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
sf_handle = vboxsf_create_sf_handle(d_inode(dentry), handle, SHFL_CF_ACCESS_READWRITE);
|
||||
if (IS_ERR(sf_handle)) {
|
||||
vboxsf_close(sbi->root, handle);
|
||||
err = PTR_ERR(sf_handle);
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = finish_open(file, dentry, generic_file_open);
|
||||
if (err) {
|
||||
/* This also closes the handle passed to vboxsf_create_sf_handle() */
|
||||
vboxsf_release_sf_handle(d_inode(dentry), sf_handle);
|
||||
goto out;
|
||||
}
|
||||
|
||||
file->private_data = sf_handle;
|
||||
file->f_mode |= FMODE_CREATED;
|
||||
out:
|
||||
dput(res);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int vboxsf_dir_unlink(struct inode *parent, struct dentry *dentry)
|
||||
|
@ -422,6 +475,7 @@ const struct inode_operations vboxsf_dir_iops = {
|
|||
.lookup = vboxsf_dir_lookup,
|
||||
.create = vboxsf_dir_mkfile,
|
||||
.mkdir = vboxsf_dir_mkdir,
|
||||
.atomic_open = vboxsf_dir_atomic_open,
|
||||
.rmdir = vboxsf_dir_unlink,
|
||||
.unlink = vboxsf_dir_unlink,
|
||||
.rename = vboxsf_dir_rename,
|
||||
|
|
|
@ -20,18 +20,40 @@ struct vboxsf_handle {
|
|||
struct list_head head;
|
||||
};
|
||||
|
||||
static int vboxsf_file_open(struct inode *inode, struct file *file)
|
||||
struct vboxsf_handle *vboxsf_create_sf_handle(struct inode *inode,
|
||||
u64 handle, u32 access_flags)
|
||||
{
|
||||
struct vboxsf_inode *sf_i = VBOXSF_I(inode);
|
||||
struct vboxsf_handle *sf_handle;
|
||||
|
||||
sf_handle = kmalloc(sizeof(*sf_handle), GFP_KERNEL);
|
||||
if (!sf_handle)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
/* the host may have given us different attr then requested */
|
||||
sf_i->force_restat = 1;
|
||||
|
||||
/* init our handle struct and add it to the inode's handles list */
|
||||
sf_handle->handle = handle;
|
||||
sf_handle->root = VBOXSF_SBI(inode->i_sb)->root;
|
||||
sf_handle->access_flags = access_flags;
|
||||
kref_init(&sf_handle->refcount);
|
||||
|
||||
mutex_lock(&sf_i->handle_list_mutex);
|
||||
list_add(&sf_handle->head, &sf_i->handle_list);
|
||||
mutex_unlock(&sf_i->handle_list_mutex);
|
||||
|
||||
return sf_handle;
|
||||
}
|
||||
|
||||
static int vboxsf_file_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct vboxsf_sbi *sbi = VBOXSF_SBI(inode->i_sb);
|
||||
struct shfl_createparms params = {};
|
||||
struct vboxsf_handle *sf_handle;
|
||||
u32 access_flags = 0;
|
||||
int err;
|
||||
|
||||
sf_handle = kmalloc(sizeof(*sf_handle), GFP_KERNEL);
|
||||
if (!sf_handle)
|
||||
return -ENOMEM;
|
||||
|
||||
/*
|
||||
* We check the value of params.handle afterwards to find out if
|
||||
* the call succeeded or failed, as the API does not seem to cleanly
|
||||
|
@ -83,24 +105,15 @@ static int vboxsf_file_open(struct inode *inode, struct file *file)
|
|||
err = vboxsf_create_at_dentry(file_dentry(file), ¶ms);
|
||||
if (err == 0 && params.handle == SHFL_HANDLE_NIL)
|
||||
err = (params.result == SHFL_FILE_EXISTS) ? -EEXIST : -ENOENT;
|
||||
if (err) {
|
||||
kfree(sf_handle);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
sf_handle = vboxsf_create_sf_handle(inode, params.handle, access_flags);
|
||||
if (IS_ERR(sf_handle)) {
|
||||
vboxsf_close(sbi->root, params.handle);
|
||||
return PTR_ERR(sf_handle);
|
||||
}
|
||||
|
||||
/* the host may have given us different attr then requested */
|
||||
sf_i->force_restat = 1;
|
||||
|
||||
/* init our handle struct and add it to the inode's handles list */
|
||||
sf_handle->handle = params.handle;
|
||||
sf_handle->root = VBOXSF_SBI(inode->i_sb)->root;
|
||||
sf_handle->access_flags = access_flags;
|
||||
kref_init(&sf_handle->refcount);
|
||||
|
||||
mutex_lock(&sf_i->handle_list_mutex);
|
||||
list_add(&sf_handle->head, &sf_i->handle_list);
|
||||
mutex_unlock(&sf_i->handle_list_mutex);
|
||||
|
||||
file->private_data = sf_handle;
|
||||
return 0;
|
||||
}
|
||||
|
@ -114,22 +127,26 @@ static void vboxsf_handle_release(struct kref *refcount)
|
|||
kfree(sf_handle);
|
||||
}
|
||||
|
||||
static int vboxsf_file_release(struct inode *inode, struct file *file)
|
||||
void vboxsf_release_sf_handle(struct inode *inode, struct vboxsf_handle *sf_handle)
|
||||
{
|
||||
struct vboxsf_inode *sf_i = VBOXSF_I(inode);
|
||||
struct vboxsf_handle *sf_handle = file->private_data;
|
||||
|
||||
/*
|
||||
* When a file is closed on our (the guest) side, we want any subsequent
|
||||
* accesses done on the host side to see all changes done from our side.
|
||||
*/
|
||||
filemap_write_and_wait(inode->i_mapping);
|
||||
|
||||
mutex_lock(&sf_i->handle_list_mutex);
|
||||
list_del(&sf_handle->head);
|
||||
mutex_unlock(&sf_i->handle_list_mutex);
|
||||
|
||||
kref_put(&sf_handle->refcount, vboxsf_handle_release);
|
||||
}
|
||||
|
||||
static int vboxsf_file_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
/*
|
||||
* When a file is closed on our (the guest) side, we want any subsequent
|
||||
* accesses done on the host side to see all changes done from our side.
|
||||
*/
|
||||
filemap_write_and_wait(inode->i_mapping);
|
||||
|
||||
vboxsf_release_sf_handle(inode, file->private_data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
#define VBOXSF_SBI(sb) ((struct vboxsf_sbi *)(sb)->s_fs_info)
|
||||
#define VBOXSF_I(i) container_of(i, struct vboxsf_inode, vfs_inode)
|
||||
|
||||
struct vboxsf_handle;
|
||||
|
||||
struct vboxsf_options {
|
||||
unsigned long ttl;
|
||||
kuid_t uid;
|
||||
|
@ -80,6 +82,11 @@ extern const struct file_operations vboxsf_reg_fops;
|
|||
extern const struct address_space_operations vboxsf_reg_aops;
|
||||
extern const struct dentry_operations vboxsf_dentry_ops;
|
||||
|
||||
/* from file.c */
|
||||
struct vboxsf_handle *vboxsf_create_sf_handle(struct inode *inode,
|
||||
u64 handle, u32 access_flags);
|
||||
void vboxsf_release_sf_handle(struct inode *inode, struct vboxsf_handle *sf_handle);
|
||||
|
||||
/* from utils.c */
|
||||
struct inode *vboxsf_new_inode(struct super_block *sb);
|
||||
int vboxsf_init_inode(struct vboxsf_sbi *sbi, struct inode *inode,
|
||||
|
|
Loading…
Reference in New Issue