On Tue, 21 Jan 2014 15:00:30 +0100, Andreas Rohner wrote:
> With this ioctl the segment usage information in the SUFILE can be
> updated from userspace.
>
> This is useful, because it allows the userspace GC to modify and update
> segment usage entries for specific segments, which enables it to avoid
> unnecessary write operations.
>
> If a segment needs to be cleaned, but there is no or very little free
> space to be gained, the cleaning operation basically degrades to
> needless expensive copying of data. In the end the only thing that
> changes is the location of the data and a timestamp in the segment usage
> info. With this ioctl the GC can skip the copying and update the segment
> usage entries directly instead.
>
> Signed-off-by: Andreas Rohner <[email protected]>
> ---
> fs/nilfs2/ioctl.c | 50
> +++++++++++++++++++++++++++++++++++++++++++++++
> include/linux/nilfs2_fs.h | 2 ++
> 2 files changed, 52 insertions(+)
>
> diff --git a/fs/nilfs2/ioctl.c b/fs/nilfs2/ioctl.c
> index b44bdb2..c6a3faf 100644
> --- a/fs/nilfs2/ioctl.c
> +++ b/fs/nilfs2/ioctl.c
> @@ -273,6 +273,13 @@ nilfs_ioctl_do_get_suinfo(struct the_nilfs *nilfs, __u64
> *posp, int flags,
> return ret;
> }
>
> +static ssize_t
> +nilfs_ioctl_do_set_suinfo(struct the_nilfs *nilfs, __u64 *posp, int flags,
> + void *buf, size_t size, size_t nmembs)
> +{
> + return nilfs_sufile_set_suinfo(nilfs->ns_sufile, buf, size, nmembs);
> +}
> +
> static int nilfs_ioctl_get_sustat(struct inode *inode, struct file *filp,
> unsigned int cmd, void __user *argp)
> {
> @@ -767,6 +774,44 @@ out:
> return ret;
> }
>
> +static int nilfs_ioctl_set_info(struct inode *inode, struct file *filp,
> + unsigned int cmd, void __user *argp,
> + size_t membsz,
> + ssize_t (*dofunc)(struct the_nilfs *,
> + __u64 *, int,
> + void *, size_t, size_t))
> +{
> + struct the_nilfs *nilfs = inode->i_sb->s_fs_info;
> + struct nilfs_transaction_info ti;
> + struct nilfs_argv argv;
> + int ret;
> +
> + if (!capable(CAP_SYS_ADMIN))
> + return -EPERM;
> +
> + ret = mnt_want_write_file(filp);
> + if (ret)
> + return ret;
> +
> + ret = -EFAULT;
> + if (copy_from_user(&argv, argp, sizeof(argv)))
> + goto out;
> +
> + if (argv.v_size < membsz)
> + return -EINVAL;
> +
> + nilfs_transaction_begin(inode->i_sb, &ti, 0);
> + ret = nilfs_ioctl_wrap_copy(nilfs, &argv, _IOC_DIR(cmd), dofunc);
Hmm, we have a problem here.
nilfs_ioctl_wrap_copy() cannot be used between
nilfs_transcation_begin() and nilfs_transaction_end() since
nilfs_ioctl_wrap_copy() calls copy_from_user() and/or copy_to_user().
Unfortunately there is a lock order restriction for these functions.
Let's use vmalloc() like nilfs_ioctl_clean_segments(). The following
is a sample code for this:
size_t len;
void __user *base;
void *kbuf;
int ret;
...
ret = -EINVAL;
if (argv.v_size < sizeof(struct nilfs_suinfo_update))
goto out;
< range check of argv.v_nmembs >
len = argv.v_size * argv.v_nmembs;
base = (void __user *)(unsigned long)argv.v_base;
kbuf = vmalloc(len);
if (!kbuf) {
ret = -ENOMEM;
goto out;
}
if (copy_from_user(kbuf, base, len)) {
ret = -EFAULT;
goto out_free;
}
nilfs_transaction_begin(inode->i_sb, &ti, 0);
ret = < call nilfs_sufile_set_suinfo > ;
if (unlikely(ret < 0))
nilfs_transcation_abort(inode->i_sb);
else
nilfs_transcation_commit(inode->i_sb);
out_free:
vfree(kbuf);
out:
mnt_drop_write_file(filp);
...
Thanks,
Ryusuke Konishi
> + if (unlikely(ret < 0))
> + nilfs_transaction_abort(inode->i_sb);
> + else
> + nilfs_transaction_commit(inode->i_sb); /* never fails */
> +
> +out:
> + mnt_drop_write_file(filp);
> + return ret;
> +}
> +
> static int nilfs_ioctl_get_info(struct inode *inode, struct file *filp,
> unsigned int cmd, void __user *argp,
> size_t membsz,
> @@ -820,6 +865,10 @@ long nilfs_ioctl(struct file *filp, unsigned int cmd,
> unsigned long arg)
> return nilfs_ioctl_get_info(inode, filp, cmd, argp,
> sizeof(struct nilfs_suinfo),
> nilfs_ioctl_do_get_suinfo);
> + case NILFS_IOCTL_SET_SUINFO:
> + return nilfs_ioctl_set_info(inode, filp, cmd, argp,
> + sizeof(struct nilfs_suinfo_update),
> + nilfs_ioctl_do_set_suinfo);
> case NILFS_IOCTL_GET_SUSTAT:
> return nilfs_ioctl_get_sustat(inode, filp, cmd, argp);
> case NILFS_IOCTL_GET_VINFO:
> @@ -859,6 +908,7 @@ long nilfs_compat_ioctl(struct file *filp, unsigned int
> cmd, unsigned long arg)
> case NILFS_IOCTL_GET_CPINFO:
> case NILFS_IOCTL_GET_CPSTAT:
> case NILFS_IOCTL_GET_SUINFO:
> + case NILFS_IOCTL_SET_SUINFO:
> case NILFS_IOCTL_GET_SUSTAT:
> case NILFS_IOCTL_GET_VINFO:
> case NILFS_IOCTL_GET_BDESCS:
> diff --git a/include/linux/nilfs2_fs.h b/include/linux/nilfs2_fs.h
> index 2ee1594..528e2c5 100644
> --- a/include/linux/nilfs2_fs.h
> +++ b/include/linux/nilfs2_fs.h
> @@ -902,5 +902,7 @@ struct nilfs_bdesc {
> _IOW(NILFS_IOCTL_IDENT, 0x8B, __u64)
> #define NILFS_IOCTL_SET_ALLOC_RANGE \
> _IOW(NILFS_IOCTL_IDENT, 0x8C, __u64[2])
> +#define NILFS_IOCTL_SET_SUINFO \
> + _IOW(NILFS_IOCTL_IDENT, 0x8D, struct nilfs_argv)
>
> #endif /* _LINUX_NILFS_FS_H */
> --
> 1.8.5.3
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-nilfs" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
--
To unsubscribe from this list: send the line "unsubscribe linux-nilfs" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html