// SPDX-License-Identifier: GPL-2.0+ /* * NILFS ioctl operations. * * Copyright (C) 2007, 2008 Nippon Telegraph and Telephone Corporation. * * Written by Koji Sato. */ #include <linux/fs.h> #include <linux/wait.h> #include <linux/slab.h> #include <linux/capability.h> /* capable() */ #include <linux/uaccess.h> /* copy_from_user(), copy_to_user() */ #include <linux/vmalloc.h> #include <linux/compat.h> /* compat_ptr() */ #include <linux/mount.h> /* mnt_want_write_file(), mnt_drop_write_file() */ #include <linux/buffer_head.h> #include <linux/fileattr.h> #include "nilfs.h" #include "segment.h" #include "bmap.h" #include "cpfile.h" #include "sufile.h" #include "dat.h" /** * nilfs_ioctl_wrap_copy - wrapping function of get/set metadata info * @nilfs: nilfs object * @argv: vector of arguments from userspace * @dir: set of direction flags * @dofunc: concrete function of get/set metadata info * * Description: nilfs_ioctl_wrap_copy() gets/sets metadata info by means of * calling dofunc() function on the basis of @argv argument. * * Return Value: On success, 0 is returned and requested metadata info * is copied into userspace. On error, one of the following * negative error codes is returned. * * %-EINVAL - Invalid arguments from userspace. * * %-ENOMEM - Insufficient amount of memory available. * * %-EFAULT - Failure during execution of requested operation. */ static int nilfs_ioctl_wrap_copy(struct the_nilfs *nilfs, struct nilfs_argv *argv, int dir, ssize_t (*dofunc)(struct the_nilfs *, __u64 *, int, void *, size_t, size_t)) { … } /** * nilfs_fileattr_get - ioctl to support lsattr */ int nilfs_fileattr_get(struct dentry *dentry, struct fileattr *fa) { … } /** * nilfs_fileattr_set - ioctl to support chattr */ int nilfs_fileattr_set(struct mnt_idmap *idmap, struct dentry *dentry, struct fileattr *fa) { … } /** * nilfs_ioctl_getversion - get info about a file's version (generation number) */ static int nilfs_ioctl_getversion(struct inode *inode, void __user *argp) { … } /** * nilfs_ioctl_change_cpmode - change checkpoint mode (checkpoint/snapshot) * @inode: inode object * @filp: file object * @cmd: ioctl's request code * @argp: pointer on argument from userspace * * Description: nilfs_ioctl_change_cpmode() function changes mode of * given checkpoint between checkpoint and snapshot state. This ioctl * is used in chcp and mkcp utilities. * * Return Value: On success, 0 is returned and mode of a checkpoint is * changed. On error, one of the following negative error codes * is returned. * * %-EPERM - Operation not permitted. * * %-EFAULT - Failure during checkpoint mode changing. */ static int nilfs_ioctl_change_cpmode(struct inode *inode, struct file *filp, unsigned int cmd, void __user *argp) { … } /** * nilfs_ioctl_delete_checkpoint - remove checkpoint * @inode: inode object * @filp: file object * @cmd: ioctl's request code * @argp: pointer on argument from userspace * * Description: nilfs_ioctl_delete_checkpoint() function removes * checkpoint from NILFS2 file system. This ioctl is used in rmcp * utility. * * Return Value: On success, 0 is returned and a checkpoint is * removed. On error, one of the following negative error codes * is returned. * * %-EPERM - Operation not permitted. * * %-EFAULT - Failure during checkpoint removing. */ static int nilfs_ioctl_delete_checkpoint(struct inode *inode, struct file *filp, unsigned int cmd, void __user *argp) { … } /** * nilfs_ioctl_do_get_cpinfo - callback method getting info about checkpoints * @nilfs: nilfs object * @posp: pointer on array of checkpoint's numbers * @flags: checkpoint mode (checkpoint or snapshot) * @buf: buffer for storing checkponts' info * @size: size in bytes of one checkpoint info item in array * @nmembs: number of checkpoints in array (numbers and infos) * * Description: nilfs_ioctl_do_get_cpinfo() function returns info about * requested checkpoints. The NILFS_IOCTL_GET_CPINFO ioctl is used in * lscp utility and by nilfs_cleanerd daemon. * * Return value: count of nilfs_cpinfo structures in output buffer. */ static ssize_t nilfs_ioctl_do_get_cpinfo(struct the_nilfs *nilfs, __u64 *posp, int flags, void *buf, size_t size, size_t nmembs) { … } /** * nilfs_ioctl_get_cpstat - get checkpoints statistics * @inode: inode object * @filp: file object * @cmd: ioctl's request code * @argp: pointer on argument from userspace * * Description: nilfs_ioctl_get_cpstat() returns information about checkpoints. * The NILFS_IOCTL_GET_CPSTAT ioctl is used by lscp, rmcp utilities * and by nilfs_cleanerd daemon. * * Return Value: On success, 0 is returned, and checkpoints information is * copied into userspace pointer @argp. On error, one of the following * negative error codes is returned. * * %-EIO - I/O error. * * %-ENOMEM - Insufficient amount of memory available. * * %-EFAULT - Failure during getting checkpoints statistics. */ static int nilfs_ioctl_get_cpstat(struct inode *inode, struct file *filp, unsigned int cmd, void __user *argp) { … } /** * nilfs_ioctl_do_get_suinfo - callback method getting segment usage info * @nilfs: nilfs object * @posp: pointer on array of segment numbers * @flags: *not used* * @buf: buffer for storing suinfo array * @size: size in bytes of one suinfo item in array * @nmembs: count of segment numbers and suinfos in array * * Description: nilfs_ioctl_do_get_suinfo() function returns segment usage * info about requested segments. The NILFS_IOCTL_GET_SUINFO ioctl is used * in lssu, nilfs_resize utilities and by nilfs_cleanerd daemon. * * Return value: count of nilfs_suinfo structures in output buffer. */ static ssize_t nilfs_ioctl_do_get_suinfo(struct the_nilfs *nilfs, __u64 *posp, int flags, void *buf, size_t size, size_t nmembs) { … } /** * nilfs_ioctl_get_sustat - get segment usage statistics * @inode: inode object * @filp: file object * @cmd: ioctl's request code * @argp: pointer on argument from userspace * * Description: nilfs_ioctl_get_sustat() returns segment usage statistics. * The NILFS_IOCTL_GET_SUSTAT ioctl is used in lssu, nilfs_resize utilities * and by nilfs_cleanerd daemon. * * Return Value: On success, 0 is returned, and segment usage information is * copied into userspace pointer @argp. On error, one of the following * negative error codes is returned. * * %-EIO - I/O error. * * %-ENOMEM - Insufficient amount of memory available. * * %-EFAULT - Failure during getting segment usage statistics. */ static int nilfs_ioctl_get_sustat(struct inode *inode, struct file *filp, unsigned int cmd, void __user *argp) { … } /** * nilfs_ioctl_do_get_vinfo - callback method getting virtual blocks info * @nilfs: nilfs object * @posp: *not used* * @flags: *not used* * @buf: buffer for storing array of nilfs_vinfo structures * @size: size in bytes of one vinfo item in array * @nmembs: count of vinfos in array * * Description: nilfs_ioctl_do_get_vinfo() function returns information * on virtual block addresses. The NILFS_IOCTL_GET_VINFO ioctl is used * by nilfs_cleanerd daemon. * * Return value: count of nilfs_vinfo structures in output buffer. */ static ssize_t nilfs_ioctl_do_get_vinfo(struct the_nilfs *nilfs, __u64 *posp, int flags, void *buf, size_t size, size_t nmembs) { … } /** * nilfs_ioctl_do_get_bdescs - callback method getting disk block descriptors * @nilfs: nilfs object * @posp: *not used* * @flags: *not used* * @buf: buffer for storing array of nilfs_bdesc structures * @size: size in bytes of one bdesc item in array * @nmembs: count of bdescs in array * * Description: nilfs_ioctl_do_get_bdescs() function returns information * about descriptors of disk block numbers. The NILFS_IOCTL_GET_BDESCS ioctl * is used by nilfs_cleanerd daemon. * * Return value: count of nilfs_bdescs structures in output buffer. */ static ssize_t nilfs_ioctl_do_get_bdescs(struct the_nilfs *nilfs, __u64 *posp, int flags, void *buf, size_t size, size_t nmembs) { … } /** * nilfs_ioctl_get_bdescs - get disk block descriptors * @inode: inode object * @filp: file object * @cmd: ioctl's request code * @argp: pointer on argument from userspace * * Description: nilfs_ioctl_do_get_bdescs() function returns information * about descriptors of disk block numbers. The NILFS_IOCTL_GET_BDESCS ioctl * is used by nilfs_cleanerd daemon. * * Return Value: On success, 0 is returned, and disk block descriptors are * copied into userspace pointer @argp. On error, one of the following * negative error codes is returned. * * %-EINVAL - Invalid arguments from userspace. * * %-EIO - I/O error. * * %-ENOMEM - Insufficient amount of memory available. * * %-EFAULT - Failure during getting disk block descriptors. */ static int nilfs_ioctl_get_bdescs(struct inode *inode, struct file *filp, unsigned int cmd, void __user *argp) { … } /** * nilfs_ioctl_move_inode_block - prepare data/node block for moving by GC * @inode: inode object * @vdesc: descriptor of virtual block number * @buffers: list of moving buffers * * Description: nilfs_ioctl_move_inode_block() function registers data/node * buffer in the GC pagecache and submit read request. * * Return Value: On success, 0 is returned. On error, one of the following * negative error codes is returned. * * %-EIO - I/O error. * * %-ENOMEM - Insufficient amount of memory available. * * %-ENOENT - Requested block doesn't exist. * * %-EEXIST - Blocks conflict is detected. */ static int nilfs_ioctl_move_inode_block(struct inode *inode, struct nilfs_vdesc *vdesc, struct list_head *buffers) { … } /** * nilfs_ioctl_move_blocks - move valid inode's blocks during garbage collection * @sb: superblock object * @argv: vector of arguments from userspace * @buf: array of nilfs_vdesc structures * * Description: nilfs_ioctl_move_blocks() function reads valid data/node * blocks that garbage collector specified with the array of nilfs_vdesc * structures and stores them into page caches of GC inodes. * * Return Value: Number of processed nilfs_vdesc structures or * error code, otherwise. */ static int nilfs_ioctl_move_blocks(struct super_block *sb, struct nilfs_argv *argv, void *buf) { … } /** * nilfs_ioctl_delete_checkpoints - delete checkpoints * @nilfs: nilfs object * @argv: vector of arguments from userspace * @buf: array of periods of checkpoints numbers * * Description: nilfs_ioctl_delete_checkpoints() function deletes checkpoints * in the period from p_start to p_end, excluding p_end itself. The checkpoints * which have been already deleted are ignored. * * Return Value: Number of processed nilfs_period structures or * error code, otherwise. * * %-EIO - I/O error. * * %-ENOMEM - Insufficient amount of memory available. * * %-EINVAL - invalid checkpoints. */ static int nilfs_ioctl_delete_checkpoints(struct the_nilfs *nilfs, struct nilfs_argv *argv, void *buf) { … } /** * nilfs_ioctl_free_vblocknrs - free virtual block numbers * @nilfs: nilfs object * @argv: vector of arguments from userspace * @buf: array of virtual block numbers * * Description: nilfs_ioctl_free_vblocknrs() function frees * the virtual block numbers specified by @buf and @argv->v_nmembs. * * Return Value: Number of processed virtual block numbers or * error code, otherwise. * * %-EIO - I/O error. * * %-ENOMEM - Insufficient amount of memory available. * * %-ENOENT - The virtual block number have not been allocated. */ static int nilfs_ioctl_free_vblocknrs(struct the_nilfs *nilfs, struct nilfs_argv *argv, void *buf) { … } /** * nilfs_ioctl_mark_blocks_dirty - mark blocks dirty * @nilfs: nilfs object * @argv: vector of arguments from userspace * @buf: array of block descriptors * * Description: nilfs_ioctl_mark_blocks_dirty() function marks * metadata file or data blocks as dirty. * * Return Value: Number of processed block descriptors or * error code, otherwise. * * %-ENOMEM - Insufficient memory available. * * %-EIO - I/O error * * %-ENOENT - the specified block does not exist (hole block) */ static int nilfs_ioctl_mark_blocks_dirty(struct the_nilfs *nilfs, struct nilfs_argv *argv, void *buf) { … } int nilfs_ioctl_prepare_clean_segments(struct the_nilfs *nilfs, struct nilfs_argv *argv, void **kbufs) { … } /** * nilfs_ioctl_clean_segments - clean segments * @inode: inode object * @filp: file object * @cmd: ioctl's request code * @argp: pointer on argument from userspace * * Description: nilfs_ioctl_clean_segments() function makes garbage * collection operation in the environment of requested parameters * from userspace. The NILFS_IOCTL_CLEAN_SEGMENTS ioctl is used by * nilfs_cleanerd daemon. * * Return Value: On success, 0 is returned or error code, otherwise. */ static int nilfs_ioctl_clean_segments(struct inode *inode, struct file *filp, unsigned int cmd, void __user *argp) { … } /** * nilfs_ioctl_sync - make a checkpoint * @inode: inode object * @filp: file object * @cmd: ioctl's request code * @argp: pointer on argument from userspace * * Description: nilfs_ioctl_sync() function constructs a logical segment * for checkpointing. This function guarantees that all modified data * and metadata are written out to the device when it successfully * returned. * * Return Value: On success, 0 is retured. On errors, one of the following * negative error code is returned. * * %-EROFS - Read only filesystem. * * %-EIO - I/O error * * %-ENOSPC - No space left on device (only in a panic state). * * %-ERESTARTSYS - Interrupted. * * %-ENOMEM - Insufficient memory available. * * %-EFAULT - Failure during execution of requested operation. */ static int nilfs_ioctl_sync(struct inode *inode, struct file *filp, unsigned int cmd, void __user *argp) { … } /** * nilfs_ioctl_resize - resize NILFS2 volume * @inode: inode object * @filp: file object * @argp: pointer on argument from userspace * * Return Value: On success, 0 is returned or error code, otherwise. */ static int nilfs_ioctl_resize(struct inode *inode, struct file *filp, void __user *argp) { … } /** * nilfs_ioctl_trim_fs() - trim ioctl handle function * @inode: inode object * @argp: pointer on argument from userspace * * Description: nilfs_ioctl_trim_fs is the FITRIM ioctl handle function. It * checks the arguments from userspace and calls nilfs_sufile_trim_fs, which * performs the actual trim operation. * * Return Value: On success, 0 is returned or negative error code, otherwise. */ static int nilfs_ioctl_trim_fs(struct inode *inode, void __user *argp) { … } /** * nilfs_ioctl_set_alloc_range - limit range of segments to be allocated * @inode: inode object * @argp: pointer on argument from userspace * * Description: nilfs_ioctl_set_alloc_range() function defines lower limit * of segments in bytes and upper limit of segments in bytes. * The NILFS_IOCTL_SET_ALLOC_RANGE is used by nilfs_resize utility. * * Return Value: On success, 0 is returned or error code, otherwise. */ static int nilfs_ioctl_set_alloc_range(struct inode *inode, void __user *argp) { … } /** * nilfs_ioctl_get_info - wrapping function of get metadata info * @inode: inode object * @filp: file object * @cmd: ioctl's request code * @argp: pointer on argument from userspace * @membsz: size of an item in bytes * @dofunc: concrete function of getting metadata info * * Description: nilfs_ioctl_get_info() gets metadata info by means of * calling dofunc() function. * * Return Value: On success, 0 is returned and requested metadata info * is copied into userspace. On error, one of the following * negative error codes is returned. * * %-EINVAL - Invalid arguments from userspace. * * %-ENOMEM - Insufficient amount of memory available. * * %-EFAULT - Failure during execution of requested operation. */ static int nilfs_ioctl_get_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)) { … } /** * nilfs_ioctl_set_suinfo - set segment usage info * @inode: inode object * @filp: file object * @cmd: ioctl's request code * @argp: pointer on argument from userspace * * Description: Expects an array of nilfs_suinfo_update structures * encapsulated in nilfs_argv and updates the segment usage info * according to the flags in nilfs_suinfo_update. * * Return Value: On success, 0 is returned. On error, one of the * following negative error codes is returned. * * %-EPERM - Not enough permissions * * %-EFAULT - Error copying input data * * %-EIO - I/O error. * * %-ENOMEM - Insufficient amount of memory available. * * %-EINVAL - Invalid values in input (segment number, flags or nblocks) */ static int nilfs_ioctl_set_suinfo(struct inode *inode, struct file *filp, unsigned int cmd, void __user *argp) { … } long nilfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { … } #ifdef CONFIG_COMPAT long nilfs_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { … } #endif