18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * ioctl.c - NILFS ioctl operations. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2007, 2008 Nippon Telegraph and Telephone Corporation. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Written by Koji Sato. 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/fs.h> 118c2ecf20Sopenharmony_ci#include <linux/wait.h> 128c2ecf20Sopenharmony_ci#include <linux/slab.h> 138c2ecf20Sopenharmony_ci#include <linux/capability.h> /* capable() */ 148c2ecf20Sopenharmony_ci#include <linux/uaccess.h> /* copy_from_user(), copy_to_user() */ 158c2ecf20Sopenharmony_ci#include <linux/vmalloc.h> 168c2ecf20Sopenharmony_ci#include <linux/compat.h> /* compat_ptr() */ 178c2ecf20Sopenharmony_ci#include <linux/mount.h> /* mnt_want_write_file(), mnt_drop_write_file() */ 188c2ecf20Sopenharmony_ci#include <linux/buffer_head.h> 198c2ecf20Sopenharmony_ci#include "nilfs.h" 208c2ecf20Sopenharmony_ci#include "segment.h" 218c2ecf20Sopenharmony_ci#include "bmap.h" 228c2ecf20Sopenharmony_ci#include "cpfile.h" 238c2ecf20Sopenharmony_ci#include "sufile.h" 248c2ecf20Sopenharmony_ci#include "dat.h" 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci/** 278c2ecf20Sopenharmony_ci * nilfs_ioctl_wrap_copy - wrapping function of get/set metadata info 288c2ecf20Sopenharmony_ci * @nilfs: nilfs object 298c2ecf20Sopenharmony_ci * @argv: vector of arguments from userspace 308c2ecf20Sopenharmony_ci * @dir: set of direction flags 318c2ecf20Sopenharmony_ci * @dofunc: concrete function of get/set metadata info 328c2ecf20Sopenharmony_ci * 338c2ecf20Sopenharmony_ci * Description: nilfs_ioctl_wrap_copy() gets/sets metadata info by means of 348c2ecf20Sopenharmony_ci * calling dofunc() function on the basis of @argv argument. 358c2ecf20Sopenharmony_ci * 368c2ecf20Sopenharmony_ci * Return Value: On success, 0 is returned and requested metadata info 378c2ecf20Sopenharmony_ci * is copied into userspace. On error, one of the following 388c2ecf20Sopenharmony_ci * negative error codes is returned. 398c2ecf20Sopenharmony_ci * 408c2ecf20Sopenharmony_ci * %-EINVAL - Invalid arguments from userspace. 418c2ecf20Sopenharmony_ci * 428c2ecf20Sopenharmony_ci * %-ENOMEM - Insufficient amount of memory available. 438c2ecf20Sopenharmony_ci * 448c2ecf20Sopenharmony_ci * %-EFAULT - Failure during execution of requested operation. 458c2ecf20Sopenharmony_ci */ 468c2ecf20Sopenharmony_cistatic int nilfs_ioctl_wrap_copy(struct the_nilfs *nilfs, 478c2ecf20Sopenharmony_ci struct nilfs_argv *argv, int dir, 488c2ecf20Sopenharmony_ci ssize_t (*dofunc)(struct the_nilfs *, 498c2ecf20Sopenharmony_ci __u64 *, int, 508c2ecf20Sopenharmony_ci void *, size_t, size_t)) 518c2ecf20Sopenharmony_ci{ 528c2ecf20Sopenharmony_ci void *buf; 538c2ecf20Sopenharmony_ci void __user *base = (void __user *)(unsigned long)argv->v_base; 548c2ecf20Sopenharmony_ci size_t maxmembs, total, n; 558c2ecf20Sopenharmony_ci ssize_t nr; 568c2ecf20Sopenharmony_ci int ret, i; 578c2ecf20Sopenharmony_ci __u64 pos, ppos; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci if (argv->v_nmembs == 0) 608c2ecf20Sopenharmony_ci return 0; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci if (argv->v_size > PAGE_SIZE) 638c2ecf20Sopenharmony_ci return -EINVAL; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci /* 668c2ecf20Sopenharmony_ci * Reject pairs of a start item position (argv->v_index) and a 678c2ecf20Sopenharmony_ci * total count (argv->v_nmembs) which leads position 'pos' to 688c2ecf20Sopenharmony_ci * overflow by the increment at the end of the loop. 698c2ecf20Sopenharmony_ci */ 708c2ecf20Sopenharmony_ci if (argv->v_index > ~(__u64)0 - argv->v_nmembs) 718c2ecf20Sopenharmony_ci return -EINVAL; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci buf = (void *)get_zeroed_page(GFP_NOFS); 748c2ecf20Sopenharmony_ci if (unlikely(!buf)) 758c2ecf20Sopenharmony_ci return -ENOMEM; 768c2ecf20Sopenharmony_ci maxmembs = PAGE_SIZE / argv->v_size; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci ret = 0; 798c2ecf20Sopenharmony_ci total = 0; 808c2ecf20Sopenharmony_ci pos = argv->v_index; 818c2ecf20Sopenharmony_ci for (i = 0; i < argv->v_nmembs; i += n) { 828c2ecf20Sopenharmony_ci n = (argv->v_nmembs - i < maxmembs) ? 838c2ecf20Sopenharmony_ci argv->v_nmembs - i : maxmembs; 848c2ecf20Sopenharmony_ci if ((dir & _IOC_WRITE) && 858c2ecf20Sopenharmony_ci copy_from_user(buf, base + argv->v_size * i, 868c2ecf20Sopenharmony_ci argv->v_size * n)) { 878c2ecf20Sopenharmony_ci ret = -EFAULT; 888c2ecf20Sopenharmony_ci break; 898c2ecf20Sopenharmony_ci } 908c2ecf20Sopenharmony_ci ppos = pos; 918c2ecf20Sopenharmony_ci nr = dofunc(nilfs, &pos, argv->v_flags, buf, argv->v_size, 928c2ecf20Sopenharmony_ci n); 938c2ecf20Sopenharmony_ci if (nr < 0) { 948c2ecf20Sopenharmony_ci ret = nr; 958c2ecf20Sopenharmony_ci break; 968c2ecf20Sopenharmony_ci } 978c2ecf20Sopenharmony_ci if ((dir & _IOC_READ) && 988c2ecf20Sopenharmony_ci copy_to_user(base + argv->v_size * i, buf, 998c2ecf20Sopenharmony_ci argv->v_size * nr)) { 1008c2ecf20Sopenharmony_ci ret = -EFAULT; 1018c2ecf20Sopenharmony_ci break; 1028c2ecf20Sopenharmony_ci } 1038c2ecf20Sopenharmony_ci total += nr; 1048c2ecf20Sopenharmony_ci if ((size_t)nr < n) 1058c2ecf20Sopenharmony_ci break; 1068c2ecf20Sopenharmony_ci if (pos == ppos) 1078c2ecf20Sopenharmony_ci pos += n; 1088c2ecf20Sopenharmony_ci } 1098c2ecf20Sopenharmony_ci argv->v_nmembs = total; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci free_pages((unsigned long)buf, 0); 1128c2ecf20Sopenharmony_ci return ret; 1138c2ecf20Sopenharmony_ci} 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci/** 1168c2ecf20Sopenharmony_ci * nilfs_ioctl_getflags - ioctl to support lsattr 1178c2ecf20Sopenharmony_ci */ 1188c2ecf20Sopenharmony_cistatic int nilfs_ioctl_getflags(struct inode *inode, void __user *argp) 1198c2ecf20Sopenharmony_ci{ 1208c2ecf20Sopenharmony_ci unsigned int flags = NILFS_I(inode)->i_flags & FS_FL_USER_VISIBLE; 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci return put_user(flags, (int __user *)argp); 1238c2ecf20Sopenharmony_ci} 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci/** 1268c2ecf20Sopenharmony_ci * nilfs_ioctl_setflags - ioctl to support chattr 1278c2ecf20Sopenharmony_ci */ 1288c2ecf20Sopenharmony_cistatic int nilfs_ioctl_setflags(struct inode *inode, struct file *filp, 1298c2ecf20Sopenharmony_ci void __user *argp) 1308c2ecf20Sopenharmony_ci{ 1318c2ecf20Sopenharmony_ci struct nilfs_transaction_info ti; 1328c2ecf20Sopenharmony_ci unsigned int flags, oldflags; 1338c2ecf20Sopenharmony_ci int ret; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci if (!inode_owner_or_capable(inode)) 1368c2ecf20Sopenharmony_ci return -EACCES; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci if (get_user(flags, (int __user *)argp)) 1398c2ecf20Sopenharmony_ci return -EFAULT; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci ret = mnt_want_write_file(filp); 1428c2ecf20Sopenharmony_ci if (ret) 1438c2ecf20Sopenharmony_ci return ret; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci flags = nilfs_mask_flags(inode->i_mode, flags); 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci inode_lock(inode); 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci oldflags = NILFS_I(inode)->i_flags; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci ret = vfs_ioc_setflags_prepare(inode, oldflags, flags); 1528c2ecf20Sopenharmony_ci if (ret) 1538c2ecf20Sopenharmony_ci goto out; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci ret = nilfs_transaction_begin(inode->i_sb, &ti, 0); 1568c2ecf20Sopenharmony_ci if (ret) 1578c2ecf20Sopenharmony_ci goto out; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci NILFS_I(inode)->i_flags = (oldflags & ~FS_FL_USER_MODIFIABLE) | 1608c2ecf20Sopenharmony_ci (flags & FS_FL_USER_MODIFIABLE); 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci nilfs_set_inode_flags(inode); 1638c2ecf20Sopenharmony_ci inode->i_ctime = current_time(inode); 1648c2ecf20Sopenharmony_ci if (IS_SYNC(inode)) 1658c2ecf20Sopenharmony_ci nilfs_set_transaction_flag(NILFS_TI_SYNC); 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci nilfs_mark_inode_dirty(inode); 1688c2ecf20Sopenharmony_ci ret = nilfs_transaction_commit(inode->i_sb); 1698c2ecf20Sopenharmony_ciout: 1708c2ecf20Sopenharmony_ci inode_unlock(inode); 1718c2ecf20Sopenharmony_ci mnt_drop_write_file(filp); 1728c2ecf20Sopenharmony_ci return ret; 1738c2ecf20Sopenharmony_ci} 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci/** 1768c2ecf20Sopenharmony_ci * nilfs_ioctl_getversion - get info about a file's version (generation number) 1778c2ecf20Sopenharmony_ci */ 1788c2ecf20Sopenharmony_cistatic int nilfs_ioctl_getversion(struct inode *inode, void __user *argp) 1798c2ecf20Sopenharmony_ci{ 1808c2ecf20Sopenharmony_ci return put_user(inode->i_generation, (int __user *)argp); 1818c2ecf20Sopenharmony_ci} 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci/** 1848c2ecf20Sopenharmony_ci * nilfs_ioctl_change_cpmode - change checkpoint mode (checkpoint/snapshot) 1858c2ecf20Sopenharmony_ci * @inode: inode object 1868c2ecf20Sopenharmony_ci * @filp: file object 1878c2ecf20Sopenharmony_ci * @cmd: ioctl's request code 1888c2ecf20Sopenharmony_ci * @argp: pointer on argument from userspace 1898c2ecf20Sopenharmony_ci * 1908c2ecf20Sopenharmony_ci * Description: nilfs_ioctl_change_cpmode() function changes mode of 1918c2ecf20Sopenharmony_ci * given checkpoint between checkpoint and snapshot state. This ioctl 1928c2ecf20Sopenharmony_ci * is used in chcp and mkcp utilities. 1938c2ecf20Sopenharmony_ci * 1948c2ecf20Sopenharmony_ci * Return Value: On success, 0 is returned and mode of a checkpoint is 1958c2ecf20Sopenharmony_ci * changed. On error, one of the following negative error codes 1968c2ecf20Sopenharmony_ci * is returned. 1978c2ecf20Sopenharmony_ci * 1988c2ecf20Sopenharmony_ci * %-EPERM - Operation not permitted. 1998c2ecf20Sopenharmony_ci * 2008c2ecf20Sopenharmony_ci * %-EFAULT - Failure during checkpoint mode changing. 2018c2ecf20Sopenharmony_ci */ 2028c2ecf20Sopenharmony_cistatic int nilfs_ioctl_change_cpmode(struct inode *inode, struct file *filp, 2038c2ecf20Sopenharmony_ci unsigned int cmd, void __user *argp) 2048c2ecf20Sopenharmony_ci{ 2058c2ecf20Sopenharmony_ci struct the_nilfs *nilfs = inode->i_sb->s_fs_info; 2068c2ecf20Sopenharmony_ci struct nilfs_transaction_info ti; 2078c2ecf20Sopenharmony_ci struct nilfs_cpmode cpmode; 2088c2ecf20Sopenharmony_ci int ret; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci if (!capable(CAP_SYS_ADMIN)) 2118c2ecf20Sopenharmony_ci return -EPERM; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci ret = mnt_want_write_file(filp); 2148c2ecf20Sopenharmony_ci if (ret) 2158c2ecf20Sopenharmony_ci return ret; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci ret = -EFAULT; 2188c2ecf20Sopenharmony_ci if (copy_from_user(&cpmode, argp, sizeof(cpmode))) 2198c2ecf20Sopenharmony_ci goto out; 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci mutex_lock(&nilfs->ns_snapshot_mount_mutex); 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci nilfs_transaction_begin(inode->i_sb, &ti, 0); 2248c2ecf20Sopenharmony_ci ret = nilfs_cpfile_change_cpmode( 2258c2ecf20Sopenharmony_ci nilfs->ns_cpfile, cpmode.cm_cno, cpmode.cm_mode); 2268c2ecf20Sopenharmony_ci if (unlikely(ret < 0)) 2278c2ecf20Sopenharmony_ci nilfs_transaction_abort(inode->i_sb); 2288c2ecf20Sopenharmony_ci else 2298c2ecf20Sopenharmony_ci nilfs_transaction_commit(inode->i_sb); /* never fails */ 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci mutex_unlock(&nilfs->ns_snapshot_mount_mutex); 2328c2ecf20Sopenharmony_ciout: 2338c2ecf20Sopenharmony_ci mnt_drop_write_file(filp); 2348c2ecf20Sopenharmony_ci return ret; 2358c2ecf20Sopenharmony_ci} 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci/** 2388c2ecf20Sopenharmony_ci * nilfs_ioctl_delete_checkpoint - remove checkpoint 2398c2ecf20Sopenharmony_ci * @inode: inode object 2408c2ecf20Sopenharmony_ci * @filp: file object 2418c2ecf20Sopenharmony_ci * @cmd: ioctl's request code 2428c2ecf20Sopenharmony_ci * @argp: pointer on argument from userspace 2438c2ecf20Sopenharmony_ci * 2448c2ecf20Sopenharmony_ci * Description: nilfs_ioctl_delete_checkpoint() function removes 2458c2ecf20Sopenharmony_ci * checkpoint from NILFS2 file system. This ioctl is used in rmcp 2468c2ecf20Sopenharmony_ci * utility. 2478c2ecf20Sopenharmony_ci * 2488c2ecf20Sopenharmony_ci * Return Value: On success, 0 is returned and a checkpoint is 2498c2ecf20Sopenharmony_ci * removed. On error, one of the following negative error codes 2508c2ecf20Sopenharmony_ci * is returned. 2518c2ecf20Sopenharmony_ci * 2528c2ecf20Sopenharmony_ci * %-EPERM - Operation not permitted. 2538c2ecf20Sopenharmony_ci * 2548c2ecf20Sopenharmony_ci * %-EFAULT - Failure during checkpoint removing. 2558c2ecf20Sopenharmony_ci */ 2568c2ecf20Sopenharmony_cistatic int 2578c2ecf20Sopenharmony_cinilfs_ioctl_delete_checkpoint(struct inode *inode, struct file *filp, 2588c2ecf20Sopenharmony_ci unsigned int cmd, void __user *argp) 2598c2ecf20Sopenharmony_ci{ 2608c2ecf20Sopenharmony_ci struct the_nilfs *nilfs = inode->i_sb->s_fs_info; 2618c2ecf20Sopenharmony_ci struct nilfs_transaction_info ti; 2628c2ecf20Sopenharmony_ci __u64 cno; 2638c2ecf20Sopenharmony_ci int ret; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci if (!capable(CAP_SYS_ADMIN)) 2668c2ecf20Sopenharmony_ci return -EPERM; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci ret = mnt_want_write_file(filp); 2698c2ecf20Sopenharmony_ci if (ret) 2708c2ecf20Sopenharmony_ci return ret; 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci ret = -EFAULT; 2738c2ecf20Sopenharmony_ci if (copy_from_user(&cno, argp, sizeof(cno))) 2748c2ecf20Sopenharmony_ci goto out; 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci nilfs_transaction_begin(inode->i_sb, &ti, 0); 2778c2ecf20Sopenharmony_ci ret = nilfs_cpfile_delete_checkpoint(nilfs->ns_cpfile, cno); 2788c2ecf20Sopenharmony_ci if (unlikely(ret < 0)) 2798c2ecf20Sopenharmony_ci nilfs_transaction_abort(inode->i_sb); 2808c2ecf20Sopenharmony_ci else 2818c2ecf20Sopenharmony_ci nilfs_transaction_commit(inode->i_sb); /* never fails */ 2828c2ecf20Sopenharmony_ciout: 2838c2ecf20Sopenharmony_ci mnt_drop_write_file(filp); 2848c2ecf20Sopenharmony_ci return ret; 2858c2ecf20Sopenharmony_ci} 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci/** 2888c2ecf20Sopenharmony_ci * nilfs_ioctl_do_get_cpinfo - callback method getting info about checkpoints 2898c2ecf20Sopenharmony_ci * @nilfs: nilfs object 2908c2ecf20Sopenharmony_ci * @posp: pointer on array of checkpoint's numbers 2918c2ecf20Sopenharmony_ci * @flags: checkpoint mode (checkpoint or snapshot) 2928c2ecf20Sopenharmony_ci * @buf: buffer for storing checkponts' info 2938c2ecf20Sopenharmony_ci * @size: size in bytes of one checkpoint info item in array 2948c2ecf20Sopenharmony_ci * @nmembs: number of checkpoints in array (numbers and infos) 2958c2ecf20Sopenharmony_ci * 2968c2ecf20Sopenharmony_ci * Description: nilfs_ioctl_do_get_cpinfo() function returns info about 2978c2ecf20Sopenharmony_ci * requested checkpoints. The NILFS_IOCTL_GET_CPINFO ioctl is used in 2988c2ecf20Sopenharmony_ci * lscp utility and by nilfs_cleanerd daemon. 2998c2ecf20Sopenharmony_ci * 3008c2ecf20Sopenharmony_ci * Return value: count of nilfs_cpinfo structures in output buffer. 3018c2ecf20Sopenharmony_ci */ 3028c2ecf20Sopenharmony_cistatic ssize_t 3038c2ecf20Sopenharmony_cinilfs_ioctl_do_get_cpinfo(struct the_nilfs *nilfs, __u64 *posp, int flags, 3048c2ecf20Sopenharmony_ci void *buf, size_t size, size_t nmembs) 3058c2ecf20Sopenharmony_ci{ 3068c2ecf20Sopenharmony_ci int ret; 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci down_read(&nilfs->ns_segctor_sem); 3098c2ecf20Sopenharmony_ci ret = nilfs_cpfile_get_cpinfo(nilfs->ns_cpfile, posp, flags, buf, 3108c2ecf20Sopenharmony_ci size, nmembs); 3118c2ecf20Sopenharmony_ci up_read(&nilfs->ns_segctor_sem); 3128c2ecf20Sopenharmony_ci return ret; 3138c2ecf20Sopenharmony_ci} 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci/** 3168c2ecf20Sopenharmony_ci * nilfs_ioctl_get_cpstat - get checkpoints statistics 3178c2ecf20Sopenharmony_ci * @inode: inode object 3188c2ecf20Sopenharmony_ci * @filp: file object 3198c2ecf20Sopenharmony_ci * @cmd: ioctl's request code 3208c2ecf20Sopenharmony_ci * @argp: pointer on argument from userspace 3218c2ecf20Sopenharmony_ci * 3228c2ecf20Sopenharmony_ci * Description: nilfs_ioctl_get_cpstat() returns information about checkpoints. 3238c2ecf20Sopenharmony_ci * The NILFS_IOCTL_GET_CPSTAT ioctl is used by lscp, rmcp utilities 3248c2ecf20Sopenharmony_ci * and by nilfs_cleanerd daemon. 3258c2ecf20Sopenharmony_ci * 3268c2ecf20Sopenharmony_ci * Return Value: On success, 0 is returned, and checkpoints information is 3278c2ecf20Sopenharmony_ci * copied into userspace pointer @argp. On error, one of the following 3288c2ecf20Sopenharmony_ci * negative error codes is returned. 3298c2ecf20Sopenharmony_ci * 3308c2ecf20Sopenharmony_ci * %-EIO - I/O error. 3318c2ecf20Sopenharmony_ci * 3328c2ecf20Sopenharmony_ci * %-ENOMEM - Insufficient amount of memory available. 3338c2ecf20Sopenharmony_ci * 3348c2ecf20Sopenharmony_ci * %-EFAULT - Failure during getting checkpoints statistics. 3358c2ecf20Sopenharmony_ci */ 3368c2ecf20Sopenharmony_cistatic int nilfs_ioctl_get_cpstat(struct inode *inode, struct file *filp, 3378c2ecf20Sopenharmony_ci unsigned int cmd, void __user *argp) 3388c2ecf20Sopenharmony_ci{ 3398c2ecf20Sopenharmony_ci struct the_nilfs *nilfs = inode->i_sb->s_fs_info; 3408c2ecf20Sopenharmony_ci struct nilfs_cpstat cpstat; 3418c2ecf20Sopenharmony_ci int ret; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci down_read(&nilfs->ns_segctor_sem); 3448c2ecf20Sopenharmony_ci ret = nilfs_cpfile_get_stat(nilfs->ns_cpfile, &cpstat); 3458c2ecf20Sopenharmony_ci up_read(&nilfs->ns_segctor_sem); 3468c2ecf20Sopenharmony_ci if (ret < 0) 3478c2ecf20Sopenharmony_ci return ret; 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci if (copy_to_user(argp, &cpstat, sizeof(cpstat))) 3508c2ecf20Sopenharmony_ci ret = -EFAULT; 3518c2ecf20Sopenharmony_ci return ret; 3528c2ecf20Sopenharmony_ci} 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci/** 3558c2ecf20Sopenharmony_ci * nilfs_ioctl_do_get_suinfo - callback method getting segment usage info 3568c2ecf20Sopenharmony_ci * @nilfs: nilfs object 3578c2ecf20Sopenharmony_ci * @posp: pointer on array of segment numbers 3588c2ecf20Sopenharmony_ci * @flags: *not used* 3598c2ecf20Sopenharmony_ci * @buf: buffer for storing suinfo array 3608c2ecf20Sopenharmony_ci * @size: size in bytes of one suinfo item in array 3618c2ecf20Sopenharmony_ci * @nmembs: count of segment numbers and suinfos in array 3628c2ecf20Sopenharmony_ci * 3638c2ecf20Sopenharmony_ci * Description: nilfs_ioctl_do_get_suinfo() function returns segment usage 3648c2ecf20Sopenharmony_ci * info about requested segments. The NILFS_IOCTL_GET_SUINFO ioctl is used 3658c2ecf20Sopenharmony_ci * in lssu, nilfs_resize utilities and by nilfs_cleanerd daemon. 3668c2ecf20Sopenharmony_ci * 3678c2ecf20Sopenharmony_ci * Return value: count of nilfs_suinfo structures in output buffer. 3688c2ecf20Sopenharmony_ci */ 3698c2ecf20Sopenharmony_cistatic ssize_t 3708c2ecf20Sopenharmony_cinilfs_ioctl_do_get_suinfo(struct the_nilfs *nilfs, __u64 *posp, int flags, 3718c2ecf20Sopenharmony_ci void *buf, size_t size, size_t nmembs) 3728c2ecf20Sopenharmony_ci{ 3738c2ecf20Sopenharmony_ci int ret; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci down_read(&nilfs->ns_segctor_sem); 3768c2ecf20Sopenharmony_ci ret = nilfs_sufile_get_suinfo(nilfs->ns_sufile, *posp, buf, size, 3778c2ecf20Sopenharmony_ci nmembs); 3788c2ecf20Sopenharmony_ci up_read(&nilfs->ns_segctor_sem); 3798c2ecf20Sopenharmony_ci return ret; 3808c2ecf20Sopenharmony_ci} 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci/** 3838c2ecf20Sopenharmony_ci * nilfs_ioctl_get_sustat - get segment usage statistics 3848c2ecf20Sopenharmony_ci * @inode: inode object 3858c2ecf20Sopenharmony_ci * @filp: file object 3868c2ecf20Sopenharmony_ci * @cmd: ioctl's request code 3878c2ecf20Sopenharmony_ci * @argp: pointer on argument from userspace 3888c2ecf20Sopenharmony_ci * 3898c2ecf20Sopenharmony_ci * Description: nilfs_ioctl_get_sustat() returns segment usage statistics. 3908c2ecf20Sopenharmony_ci * The NILFS_IOCTL_GET_SUSTAT ioctl is used in lssu, nilfs_resize utilities 3918c2ecf20Sopenharmony_ci * and by nilfs_cleanerd daemon. 3928c2ecf20Sopenharmony_ci * 3938c2ecf20Sopenharmony_ci * Return Value: On success, 0 is returned, and segment usage information is 3948c2ecf20Sopenharmony_ci * copied into userspace pointer @argp. On error, one of the following 3958c2ecf20Sopenharmony_ci * negative error codes is returned. 3968c2ecf20Sopenharmony_ci * 3978c2ecf20Sopenharmony_ci * %-EIO - I/O error. 3988c2ecf20Sopenharmony_ci * 3998c2ecf20Sopenharmony_ci * %-ENOMEM - Insufficient amount of memory available. 4008c2ecf20Sopenharmony_ci * 4018c2ecf20Sopenharmony_ci * %-EFAULT - Failure during getting segment usage statistics. 4028c2ecf20Sopenharmony_ci */ 4038c2ecf20Sopenharmony_cistatic int nilfs_ioctl_get_sustat(struct inode *inode, struct file *filp, 4048c2ecf20Sopenharmony_ci unsigned int cmd, void __user *argp) 4058c2ecf20Sopenharmony_ci{ 4068c2ecf20Sopenharmony_ci struct the_nilfs *nilfs = inode->i_sb->s_fs_info; 4078c2ecf20Sopenharmony_ci struct nilfs_sustat sustat; 4088c2ecf20Sopenharmony_ci int ret; 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci down_read(&nilfs->ns_segctor_sem); 4118c2ecf20Sopenharmony_ci ret = nilfs_sufile_get_stat(nilfs->ns_sufile, &sustat); 4128c2ecf20Sopenharmony_ci up_read(&nilfs->ns_segctor_sem); 4138c2ecf20Sopenharmony_ci if (ret < 0) 4148c2ecf20Sopenharmony_ci return ret; 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci if (copy_to_user(argp, &sustat, sizeof(sustat))) 4178c2ecf20Sopenharmony_ci ret = -EFAULT; 4188c2ecf20Sopenharmony_ci return ret; 4198c2ecf20Sopenharmony_ci} 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci/** 4228c2ecf20Sopenharmony_ci * nilfs_ioctl_do_get_vinfo - callback method getting virtual blocks info 4238c2ecf20Sopenharmony_ci * @nilfs: nilfs object 4248c2ecf20Sopenharmony_ci * @posp: *not used* 4258c2ecf20Sopenharmony_ci * @flags: *not used* 4268c2ecf20Sopenharmony_ci * @buf: buffer for storing array of nilfs_vinfo structures 4278c2ecf20Sopenharmony_ci * @size: size in bytes of one vinfo item in array 4288c2ecf20Sopenharmony_ci * @nmembs: count of vinfos in array 4298c2ecf20Sopenharmony_ci * 4308c2ecf20Sopenharmony_ci * Description: nilfs_ioctl_do_get_vinfo() function returns information 4318c2ecf20Sopenharmony_ci * on virtual block addresses. The NILFS_IOCTL_GET_VINFO ioctl is used 4328c2ecf20Sopenharmony_ci * by nilfs_cleanerd daemon. 4338c2ecf20Sopenharmony_ci * 4348c2ecf20Sopenharmony_ci * Return value: count of nilfs_vinfo structures in output buffer. 4358c2ecf20Sopenharmony_ci */ 4368c2ecf20Sopenharmony_cistatic ssize_t 4378c2ecf20Sopenharmony_cinilfs_ioctl_do_get_vinfo(struct the_nilfs *nilfs, __u64 *posp, int flags, 4388c2ecf20Sopenharmony_ci void *buf, size_t size, size_t nmembs) 4398c2ecf20Sopenharmony_ci{ 4408c2ecf20Sopenharmony_ci int ret; 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci down_read(&nilfs->ns_segctor_sem); 4438c2ecf20Sopenharmony_ci ret = nilfs_dat_get_vinfo(nilfs->ns_dat, buf, size, nmembs); 4448c2ecf20Sopenharmony_ci up_read(&nilfs->ns_segctor_sem); 4458c2ecf20Sopenharmony_ci return ret; 4468c2ecf20Sopenharmony_ci} 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci/** 4498c2ecf20Sopenharmony_ci * nilfs_ioctl_do_get_bdescs - callback method getting disk block descriptors 4508c2ecf20Sopenharmony_ci * @nilfs: nilfs object 4518c2ecf20Sopenharmony_ci * @posp: *not used* 4528c2ecf20Sopenharmony_ci * @flags: *not used* 4538c2ecf20Sopenharmony_ci * @buf: buffer for storing array of nilfs_bdesc structures 4548c2ecf20Sopenharmony_ci * @size: size in bytes of one bdesc item in array 4558c2ecf20Sopenharmony_ci * @nmembs: count of bdescs in array 4568c2ecf20Sopenharmony_ci * 4578c2ecf20Sopenharmony_ci * Description: nilfs_ioctl_do_get_bdescs() function returns information 4588c2ecf20Sopenharmony_ci * about descriptors of disk block numbers. The NILFS_IOCTL_GET_BDESCS ioctl 4598c2ecf20Sopenharmony_ci * is used by nilfs_cleanerd daemon. 4608c2ecf20Sopenharmony_ci * 4618c2ecf20Sopenharmony_ci * Return value: count of nilfs_bdescs structures in output buffer. 4628c2ecf20Sopenharmony_ci */ 4638c2ecf20Sopenharmony_cistatic ssize_t 4648c2ecf20Sopenharmony_cinilfs_ioctl_do_get_bdescs(struct the_nilfs *nilfs, __u64 *posp, int flags, 4658c2ecf20Sopenharmony_ci void *buf, size_t size, size_t nmembs) 4668c2ecf20Sopenharmony_ci{ 4678c2ecf20Sopenharmony_ci struct nilfs_bmap *bmap = NILFS_I(nilfs->ns_dat)->i_bmap; 4688c2ecf20Sopenharmony_ci struct nilfs_bdesc *bdescs = buf; 4698c2ecf20Sopenharmony_ci int ret, i; 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci down_read(&nilfs->ns_segctor_sem); 4728c2ecf20Sopenharmony_ci for (i = 0; i < nmembs; i++) { 4738c2ecf20Sopenharmony_ci ret = nilfs_bmap_lookup_at_level(bmap, 4748c2ecf20Sopenharmony_ci bdescs[i].bd_offset, 4758c2ecf20Sopenharmony_ci bdescs[i].bd_level + 1, 4768c2ecf20Sopenharmony_ci &bdescs[i].bd_blocknr); 4778c2ecf20Sopenharmony_ci if (ret < 0) { 4788c2ecf20Sopenharmony_ci if (ret != -ENOENT) { 4798c2ecf20Sopenharmony_ci up_read(&nilfs->ns_segctor_sem); 4808c2ecf20Sopenharmony_ci return ret; 4818c2ecf20Sopenharmony_ci } 4828c2ecf20Sopenharmony_ci bdescs[i].bd_blocknr = 0; 4838c2ecf20Sopenharmony_ci } 4848c2ecf20Sopenharmony_ci } 4858c2ecf20Sopenharmony_ci up_read(&nilfs->ns_segctor_sem); 4868c2ecf20Sopenharmony_ci return nmembs; 4878c2ecf20Sopenharmony_ci} 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci/** 4908c2ecf20Sopenharmony_ci * nilfs_ioctl_get_bdescs - get disk block descriptors 4918c2ecf20Sopenharmony_ci * @inode: inode object 4928c2ecf20Sopenharmony_ci * @filp: file object 4938c2ecf20Sopenharmony_ci * @cmd: ioctl's request code 4948c2ecf20Sopenharmony_ci * @argp: pointer on argument from userspace 4958c2ecf20Sopenharmony_ci * 4968c2ecf20Sopenharmony_ci * Description: nilfs_ioctl_do_get_bdescs() function returns information 4978c2ecf20Sopenharmony_ci * about descriptors of disk block numbers. The NILFS_IOCTL_GET_BDESCS ioctl 4988c2ecf20Sopenharmony_ci * is used by nilfs_cleanerd daemon. 4998c2ecf20Sopenharmony_ci * 5008c2ecf20Sopenharmony_ci * Return Value: On success, 0 is returned, and disk block descriptors are 5018c2ecf20Sopenharmony_ci * copied into userspace pointer @argp. On error, one of the following 5028c2ecf20Sopenharmony_ci * negative error codes is returned. 5038c2ecf20Sopenharmony_ci * 5048c2ecf20Sopenharmony_ci * %-EINVAL - Invalid arguments from userspace. 5058c2ecf20Sopenharmony_ci * 5068c2ecf20Sopenharmony_ci * %-EIO - I/O error. 5078c2ecf20Sopenharmony_ci * 5088c2ecf20Sopenharmony_ci * %-ENOMEM - Insufficient amount of memory available. 5098c2ecf20Sopenharmony_ci * 5108c2ecf20Sopenharmony_ci * %-EFAULT - Failure during getting disk block descriptors. 5118c2ecf20Sopenharmony_ci */ 5128c2ecf20Sopenharmony_cistatic int nilfs_ioctl_get_bdescs(struct inode *inode, struct file *filp, 5138c2ecf20Sopenharmony_ci unsigned int cmd, void __user *argp) 5148c2ecf20Sopenharmony_ci{ 5158c2ecf20Sopenharmony_ci struct the_nilfs *nilfs = inode->i_sb->s_fs_info; 5168c2ecf20Sopenharmony_ci struct nilfs_argv argv; 5178c2ecf20Sopenharmony_ci int ret; 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci if (copy_from_user(&argv, argp, sizeof(argv))) 5208c2ecf20Sopenharmony_ci return -EFAULT; 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci if (argv.v_size != sizeof(struct nilfs_bdesc)) 5238c2ecf20Sopenharmony_ci return -EINVAL; 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci ret = nilfs_ioctl_wrap_copy(nilfs, &argv, _IOC_DIR(cmd), 5268c2ecf20Sopenharmony_ci nilfs_ioctl_do_get_bdescs); 5278c2ecf20Sopenharmony_ci if (ret < 0) 5288c2ecf20Sopenharmony_ci return ret; 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci if (copy_to_user(argp, &argv, sizeof(argv))) 5318c2ecf20Sopenharmony_ci ret = -EFAULT; 5328c2ecf20Sopenharmony_ci return ret; 5338c2ecf20Sopenharmony_ci} 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci/** 5368c2ecf20Sopenharmony_ci * nilfs_ioctl_move_inode_block - prepare data/node block for moving by GC 5378c2ecf20Sopenharmony_ci * @inode: inode object 5388c2ecf20Sopenharmony_ci * @vdesc: descriptor of virtual block number 5398c2ecf20Sopenharmony_ci * @buffers: list of moving buffers 5408c2ecf20Sopenharmony_ci * 5418c2ecf20Sopenharmony_ci * Description: nilfs_ioctl_move_inode_block() function registers data/node 5428c2ecf20Sopenharmony_ci * buffer in the GC pagecache and submit read request. 5438c2ecf20Sopenharmony_ci * 5448c2ecf20Sopenharmony_ci * Return Value: On success, 0 is returned. On error, one of the following 5458c2ecf20Sopenharmony_ci * negative error codes is returned. 5468c2ecf20Sopenharmony_ci * 5478c2ecf20Sopenharmony_ci * %-EIO - I/O error. 5488c2ecf20Sopenharmony_ci * 5498c2ecf20Sopenharmony_ci * %-ENOMEM - Insufficient amount of memory available. 5508c2ecf20Sopenharmony_ci * 5518c2ecf20Sopenharmony_ci * %-ENOENT - Requested block doesn't exist. 5528c2ecf20Sopenharmony_ci * 5538c2ecf20Sopenharmony_ci * %-EEXIST - Blocks conflict is detected. 5548c2ecf20Sopenharmony_ci */ 5558c2ecf20Sopenharmony_cistatic int nilfs_ioctl_move_inode_block(struct inode *inode, 5568c2ecf20Sopenharmony_ci struct nilfs_vdesc *vdesc, 5578c2ecf20Sopenharmony_ci struct list_head *buffers) 5588c2ecf20Sopenharmony_ci{ 5598c2ecf20Sopenharmony_ci struct buffer_head *bh; 5608c2ecf20Sopenharmony_ci int ret; 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci if (vdesc->vd_flags == 0) 5638c2ecf20Sopenharmony_ci ret = nilfs_gccache_submit_read_data( 5648c2ecf20Sopenharmony_ci inode, vdesc->vd_offset, vdesc->vd_blocknr, 5658c2ecf20Sopenharmony_ci vdesc->vd_vblocknr, &bh); 5668c2ecf20Sopenharmony_ci else 5678c2ecf20Sopenharmony_ci ret = nilfs_gccache_submit_read_node( 5688c2ecf20Sopenharmony_ci inode, vdesc->vd_blocknr, vdesc->vd_vblocknr, &bh); 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci if (unlikely(ret < 0)) { 5718c2ecf20Sopenharmony_ci if (ret == -ENOENT) 5728c2ecf20Sopenharmony_ci nilfs_crit(inode->i_sb, 5738c2ecf20Sopenharmony_ci "%s: invalid virtual block address (%s): ino=%llu, cno=%llu, offset=%llu, blocknr=%llu, vblocknr=%llu", 5748c2ecf20Sopenharmony_ci __func__, vdesc->vd_flags ? "node" : "data", 5758c2ecf20Sopenharmony_ci (unsigned long long)vdesc->vd_ino, 5768c2ecf20Sopenharmony_ci (unsigned long long)vdesc->vd_cno, 5778c2ecf20Sopenharmony_ci (unsigned long long)vdesc->vd_offset, 5788c2ecf20Sopenharmony_ci (unsigned long long)vdesc->vd_blocknr, 5798c2ecf20Sopenharmony_ci (unsigned long long)vdesc->vd_vblocknr); 5808c2ecf20Sopenharmony_ci return ret; 5818c2ecf20Sopenharmony_ci } 5828c2ecf20Sopenharmony_ci if (unlikely(!list_empty(&bh->b_assoc_buffers))) { 5838c2ecf20Sopenharmony_ci nilfs_crit(inode->i_sb, 5848c2ecf20Sopenharmony_ci "%s: conflicting %s buffer: ino=%llu, cno=%llu, offset=%llu, blocknr=%llu, vblocknr=%llu", 5858c2ecf20Sopenharmony_ci __func__, vdesc->vd_flags ? "node" : "data", 5868c2ecf20Sopenharmony_ci (unsigned long long)vdesc->vd_ino, 5878c2ecf20Sopenharmony_ci (unsigned long long)vdesc->vd_cno, 5888c2ecf20Sopenharmony_ci (unsigned long long)vdesc->vd_offset, 5898c2ecf20Sopenharmony_ci (unsigned long long)vdesc->vd_blocknr, 5908c2ecf20Sopenharmony_ci (unsigned long long)vdesc->vd_vblocknr); 5918c2ecf20Sopenharmony_ci brelse(bh); 5928c2ecf20Sopenharmony_ci return -EEXIST; 5938c2ecf20Sopenharmony_ci } 5948c2ecf20Sopenharmony_ci list_add_tail(&bh->b_assoc_buffers, buffers); 5958c2ecf20Sopenharmony_ci return 0; 5968c2ecf20Sopenharmony_ci} 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci/** 5998c2ecf20Sopenharmony_ci * nilfs_ioctl_move_blocks - move valid inode's blocks during garbage collection 6008c2ecf20Sopenharmony_ci * @sb: superblock object 6018c2ecf20Sopenharmony_ci * @argv: vector of arguments from userspace 6028c2ecf20Sopenharmony_ci * @buf: array of nilfs_vdesc structures 6038c2ecf20Sopenharmony_ci * 6048c2ecf20Sopenharmony_ci * Description: nilfs_ioctl_move_blocks() function reads valid data/node 6058c2ecf20Sopenharmony_ci * blocks that garbage collector specified with the array of nilfs_vdesc 6068c2ecf20Sopenharmony_ci * structures and stores them into page caches of GC inodes. 6078c2ecf20Sopenharmony_ci * 6088c2ecf20Sopenharmony_ci * Return Value: Number of processed nilfs_vdesc structures or 6098c2ecf20Sopenharmony_ci * error code, otherwise. 6108c2ecf20Sopenharmony_ci */ 6118c2ecf20Sopenharmony_cistatic int nilfs_ioctl_move_blocks(struct super_block *sb, 6128c2ecf20Sopenharmony_ci struct nilfs_argv *argv, void *buf) 6138c2ecf20Sopenharmony_ci{ 6148c2ecf20Sopenharmony_ci size_t nmembs = argv->v_nmembs; 6158c2ecf20Sopenharmony_ci struct the_nilfs *nilfs = sb->s_fs_info; 6168c2ecf20Sopenharmony_ci struct inode *inode; 6178c2ecf20Sopenharmony_ci struct nilfs_vdesc *vdesc; 6188c2ecf20Sopenharmony_ci struct buffer_head *bh, *n; 6198c2ecf20Sopenharmony_ci LIST_HEAD(buffers); 6208c2ecf20Sopenharmony_ci ino_t ino; 6218c2ecf20Sopenharmony_ci __u64 cno; 6228c2ecf20Sopenharmony_ci int i, ret; 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci for (i = 0, vdesc = buf; i < nmembs; ) { 6258c2ecf20Sopenharmony_ci ino = vdesc->vd_ino; 6268c2ecf20Sopenharmony_ci cno = vdesc->vd_cno; 6278c2ecf20Sopenharmony_ci inode = nilfs_iget_for_gc(sb, ino, cno); 6288c2ecf20Sopenharmony_ci if (IS_ERR(inode)) { 6298c2ecf20Sopenharmony_ci ret = PTR_ERR(inode); 6308c2ecf20Sopenharmony_ci goto failed; 6318c2ecf20Sopenharmony_ci } 6328c2ecf20Sopenharmony_ci if (list_empty(&NILFS_I(inode)->i_dirty)) { 6338c2ecf20Sopenharmony_ci /* 6348c2ecf20Sopenharmony_ci * Add the inode to GC inode list. Garbage Collection 6358c2ecf20Sopenharmony_ci * is serialized and no two processes manipulate the 6368c2ecf20Sopenharmony_ci * list simultaneously. 6378c2ecf20Sopenharmony_ci */ 6388c2ecf20Sopenharmony_ci igrab(inode); 6398c2ecf20Sopenharmony_ci list_add(&NILFS_I(inode)->i_dirty, 6408c2ecf20Sopenharmony_ci &nilfs->ns_gc_inodes); 6418c2ecf20Sopenharmony_ci } 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci do { 6448c2ecf20Sopenharmony_ci ret = nilfs_ioctl_move_inode_block(inode, vdesc, 6458c2ecf20Sopenharmony_ci &buffers); 6468c2ecf20Sopenharmony_ci if (unlikely(ret < 0)) { 6478c2ecf20Sopenharmony_ci iput(inode); 6488c2ecf20Sopenharmony_ci goto failed; 6498c2ecf20Sopenharmony_ci } 6508c2ecf20Sopenharmony_ci vdesc++; 6518c2ecf20Sopenharmony_ci } while (++i < nmembs && 6528c2ecf20Sopenharmony_ci vdesc->vd_ino == ino && vdesc->vd_cno == cno); 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci iput(inode); /* The inode still remains in GC inode list */ 6558c2ecf20Sopenharmony_ci } 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci list_for_each_entry_safe(bh, n, &buffers, b_assoc_buffers) { 6588c2ecf20Sopenharmony_ci ret = nilfs_gccache_wait_and_mark_dirty(bh); 6598c2ecf20Sopenharmony_ci if (unlikely(ret < 0)) { 6608c2ecf20Sopenharmony_ci WARN_ON(ret == -EEXIST); 6618c2ecf20Sopenharmony_ci goto failed; 6628c2ecf20Sopenharmony_ci } 6638c2ecf20Sopenharmony_ci list_del_init(&bh->b_assoc_buffers); 6648c2ecf20Sopenharmony_ci brelse(bh); 6658c2ecf20Sopenharmony_ci } 6668c2ecf20Sopenharmony_ci return nmembs; 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ci failed: 6698c2ecf20Sopenharmony_ci list_for_each_entry_safe(bh, n, &buffers, b_assoc_buffers) { 6708c2ecf20Sopenharmony_ci list_del_init(&bh->b_assoc_buffers); 6718c2ecf20Sopenharmony_ci brelse(bh); 6728c2ecf20Sopenharmony_ci } 6738c2ecf20Sopenharmony_ci return ret; 6748c2ecf20Sopenharmony_ci} 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_ci/** 6778c2ecf20Sopenharmony_ci * nilfs_ioctl_delete_checkpoints - delete checkpoints 6788c2ecf20Sopenharmony_ci * @nilfs: nilfs object 6798c2ecf20Sopenharmony_ci * @argv: vector of arguments from userspace 6808c2ecf20Sopenharmony_ci * @buf: array of periods of checkpoints numbers 6818c2ecf20Sopenharmony_ci * 6828c2ecf20Sopenharmony_ci * Description: nilfs_ioctl_delete_checkpoints() function deletes checkpoints 6838c2ecf20Sopenharmony_ci * in the period from p_start to p_end, excluding p_end itself. The checkpoints 6848c2ecf20Sopenharmony_ci * which have been already deleted are ignored. 6858c2ecf20Sopenharmony_ci * 6868c2ecf20Sopenharmony_ci * Return Value: Number of processed nilfs_period structures or 6878c2ecf20Sopenharmony_ci * error code, otherwise. 6888c2ecf20Sopenharmony_ci * 6898c2ecf20Sopenharmony_ci * %-EIO - I/O error. 6908c2ecf20Sopenharmony_ci * 6918c2ecf20Sopenharmony_ci * %-ENOMEM - Insufficient amount of memory available. 6928c2ecf20Sopenharmony_ci * 6938c2ecf20Sopenharmony_ci * %-EINVAL - invalid checkpoints. 6948c2ecf20Sopenharmony_ci */ 6958c2ecf20Sopenharmony_cistatic int nilfs_ioctl_delete_checkpoints(struct the_nilfs *nilfs, 6968c2ecf20Sopenharmony_ci struct nilfs_argv *argv, void *buf) 6978c2ecf20Sopenharmony_ci{ 6988c2ecf20Sopenharmony_ci size_t nmembs = argv->v_nmembs; 6998c2ecf20Sopenharmony_ci struct inode *cpfile = nilfs->ns_cpfile; 7008c2ecf20Sopenharmony_ci struct nilfs_period *periods = buf; 7018c2ecf20Sopenharmony_ci int ret, i; 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_ci for (i = 0; i < nmembs; i++) { 7048c2ecf20Sopenharmony_ci ret = nilfs_cpfile_delete_checkpoints( 7058c2ecf20Sopenharmony_ci cpfile, periods[i].p_start, periods[i].p_end); 7068c2ecf20Sopenharmony_ci if (ret < 0) 7078c2ecf20Sopenharmony_ci return ret; 7088c2ecf20Sopenharmony_ci } 7098c2ecf20Sopenharmony_ci return nmembs; 7108c2ecf20Sopenharmony_ci} 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ci/** 7138c2ecf20Sopenharmony_ci * nilfs_ioctl_free_vblocknrs - free virtual block numbers 7148c2ecf20Sopenharmony_ci * @nilfs: nilfs object 7158c2ecf20Sopenharmony_ci * @argv: vector of arguments from userspace 7168c2ecf20Sopenharmony_ci * @buf: array of virtual block numbers 7178c2ecf20Sopenharmony_ci * 7188c2ecf20Sopenharmony_ci * Description: nilfs_ioctl_free_vblocknrs() function frees 7198c2ecf20Sopenharmony_ci * the virtual block numbers specified by @buf and @argv->v_nmembs. 7208c2ecf20Sopenharmony_ci * 7218c2ecf20Sopenharmony_ci * Return Value: Number of processed virtual block numbers or 7228c2ecf20Sopenharmony_ci * error code, otherwise. 7238c2ecf20Sopenharmony_ci * 7248c2ecf20Sopenharmony_ci * %-EIO - I/O error. 7258c2ecf20Sopenharmony_ci * 7268c2ecf20Sopenharmony_ci * %-ENOMEM - Insufficient amount of memory available. 7278c2ecf20Sopenharmony_ci * 7288c2ecf20Sopenharmony_ci * %-ENOENT - The virtual block number have not been allocated. 7298c2ecf20Sopenharmony_ci */ 7308c2ecf20Sopenharmony_cistatic int nilfs_ioctl_free_vblocknrs(struct the_nilfs *nilfs, 7318c2ecf20Sopenharmony_ci struct nilfs_argv *argv, void *buf) 7328c2ecf20Sopenharmony_ci{ 7338c2ecf20Sopenharmony_ci size_t nmembs = argv->v_nmembs; 7348c2ecf20Sopenharmony_ci int ret; 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci ret = nilfs_dat_freev(nilfs->ns_dat, buf, nmembs); 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ci return (ret < 0) ? ret : nmembs; 7398c2ecf20Sopenharmony_ci} 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci/** 7428c2ecf20Sopenharmony_ci * nilfs_ioctl_mark_blocks_dirty - mark blocks dirty 7438c2ecf20Sopenharmony_ci * @nilfs: nilfs object 7448c2ecf20Sopenharmony_ci * @argv: vector of arguments from userspace 7458c2ecf20Sopenharmony_ci * @buf: array of block descriptors 7468c2ecf20Sopenharmony_ci * 7478c2ecf20Sopenharmony_ci * Description: nilfs_ioctl_mark_blocks_dirty() function marks 7488c2ecf20Sopenharmony_ci * metadata file or data blocks as dirty. 7498c2ecf20Sopenharmony_ci * 7508c2ecf20Sopenharmony_ci * Return Value: Number of processed block descriptors or 7518c2ecf20Sopenharmony_ci * error code, otherwise. 7528c2ecf20Sopenharmony_ci * 7538c2ecf20Sopenharmony_ci * %-ENOMEM - Insufficient memory available. 7548c2ecf20Sopenharmony_ci * 7558c2ecf20Sopenharmony_ci * %-EIO - I/O error 7568c2ecf20Sopenharmony_ci * 7578c2ecf20Sopenharmony_ci * %-ENOENT - the specified block does not exist (hole block) 7588c2ecf20Sopenharmony_ci */ 7598c2ecf20Sopenharmony_cistatic int nilfs_ioctl_mark_blocks_dirty(struct the_nilfs *nilfs, 7608c2ecf20Sopenharmony_ci struct nilfs_argv *argv, void *buf) 7618c2ecf20Sopenharmony_ci{ 7628c2ecf20Sopenharmony_ci size_t nmembs = argv->v_nmembs; 7638c2ecf20Sopenharmony_ci struct nilfs_bmap *bmap = NILFS_I(nilfs->ns_dat)->i_bmap; 7648c2ecf20Sopenharmony_ci struct nilfs_bdesc *bdescs = buf; 7658c2ecf20Sopenharmony_ci struct buffer_head *bh; 7668c2ecf20Sopenharmony_ci int ret, i; 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci for (i = 0; i < nmembs; i++) { 7698c2ecf20Sopenharmony_ci /* XXX: use macro or inline func to check liveness */ 7708c2ecf20Sopenharmony_ci ret = nilfs_bmap_lookup_at_level(bmap, 7718c2ecf20Sopenharmony_ci bdescs[i].bd_offset, 7728c2ecf20Sopenharmony_ci bdescs[i].bd_level + 1, 7738c2ecf20Sopenharmony_ci &bdescs[i].bd_blocknr); 7748c2ecf20Sopenharmony_ci if (ret < 0) { 7758c2ecf20Sopenharmony_ci if (ret != -ENOENT) 7768c2ecf20Sopenharmony_ci return ret; 7778c2ecf20Sopenharmony_ci bdescs[i].bd_blocknr = 0; 7788c2ecf20Sopenharmony_ci } 7798c2ecf20Sopenharmony_ci if (bdescs[i].bd_blocknr != bdescs[i].bd_oblocknr) 7808c2ecf20Sopenharmony_ci /* skip dead block */ 7818c2ecf20Sopenharmony_ci continue; 7828c2ecf20Sopenharmony_ci if (bdescs[i].bd_level == 0) { 7838c2ecf20Sopenharmony_ci ret = nilfs_mdt_get_block(nilfs->ns_dat, 7848c2ecf20Sopenharmony_ci bdescs[i].bd_offset, 7858c2ecf20Sopenharmony_ci false, NULL, &bh); 7868c2ecf20Sopenharmony_ci if (unlikely(ret)) { 7878c2ecf20Sopenharmony_ci WARN_ON(ret == -ENOENT); 7888c2ecf20Sopenharmony_ci return ret; 7898c2ecf20Sopenharmony_ci } 7908c2ecf20Sopenharmony_ci mark_buffer_dirty(bh); 7918c2ecf20Sopenharmony_ci nilfs_mdt_mark_dirty(nilfs->ns_dat); 7928c2ecf20Sopenharmony_ci put_bh(bh); 7938c2ecf20Sopenharmony_ci } else { 7948c2ecf20Sopenharmony_ci ret = nilfs_bmap_mark(bmap, bdescs[i].bd_offset, 7958c2ecf20Sopenharmony_ci bdescs[i].bd_level); 7968c2ecf20Sopenharmony_ci if (ret < 0) { 7978c2ecf20Sopenharmony_ci WARN_ON(ret == -ENOENT); 7988c2ecf20Sopenharmony_ci return ret; 7998c2ecf20Sopenharmony_ci } 8008c2ecf20Sopenharmony_ci } 8018c2ecf20Sopenharmony_ci } 8028c2ecf20Sopenharmony_ci return nmembs; 8038c2ecf20Sopenharmony_ci} 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ciint nilfs_ioctl_prepare_clean_segments(struct the_nilfs *nilfs, 8068c2ecf20Sopenharmony_ci struct nilfs_argv *argv, void **kbufs) 8078c2ecf20Sopenharmony_ci{ 8088c2ecf20Sopenharmony_ci const char *msg; 8098c2ecf20Sopenharmony_ci int ret; 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_ci ret = nilfs_ioctl_delete_checkpoints(nilfs, &argv[1], kbufs[1]); 8128c2ecf20Sopenharmony_ci if (ret < 0) { 8138c2ecf20Sopenharmony_ci /* 8148c2ecf20Sopenharmony_ci * can safely abort because checkpoints can be removed 8158c2ecf20Sopenharmony_ci * independently. 8168c2ecf20Sopenharmony_ci */ 8178c2ecf20Sopenharmony_ci msg = "cannot delete checkpoints"; 8188c2ecf20Sopenharmony_ci goto failed; 8198c2ecf20Sopenharmony_ci } 8208c2ecf20Sopenharmony_ci ret = nilfs_ioctl_free_vblocknrs(nilfs, &argv[2], kbufs[2]); 8218c2ecf20Sopenharmony_ci if (ret < 0) { 8228c2ecf20Sopenharmony_ci /* 8238c2ecf20Sopenharmony_ci * can safely abort because DAT file is updated atomically 8248c2ecf20Sopenharmony_ci * using a copy-on-write technique. 8258c2ecf20Sopenharmony_ci */ 8268c2ecf20Sopenharmony_ci msg = "cannot delete virtual blocks from DAT file"; 8278c2ecf20Sopenharmony_ci goto failed; 8288c2ecf20Sopenharmony_ci } 8298c2ecf20Sopenharmony_ci ret = nilfs_ioctl_mark_blocks_dirty(nilfs, &argv[3], kbufs[3]); 8308c2ecf20Sopenharmony_ci if (ret < 0) { 8318c2ecf20Sopenharmony_ci /* 8328c2ecf20Sopenharmony_ci * can safely abort because the operation is nondestructive. 8338c2ecf20Sopenharmony_ci */ 8348c2ecf20Sopenharmony_ci msg = "cannot mark copying blocks dirty"; 8358c2ecf20Sopenharmony_ci goto failed; 8368c2ecf20Sopenharmony_ci } 8378c2ecf20Sopenharmony_ci return 0; 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_ci failed: 8408c2ecf20Sopenharmony_ci nilfs_err(nilfs->ns_sb, "error %d preparing GC: %s", ret, msg); 8418c2ecf20Sopenharmony_ci return ret; 8428c2ecf20Sopenharmony_ci} 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci/** 8458c2ecf20Sopenharmony_ci * nilfs_ioctl_clean_segments - clean segments 8468c2ecf20Sopenharmony_ci * @inode: inode object 8478c2ecf20Sopenharmony_ci * @filp: file object 8488c2ecf20Sopenharmony_ci * @cmd: ioctl's request code 8498c2ecf20Sopenharmony_ci * @argp: pointer on argument from userspace 8508c2ecf20Sopenharmony_ci * 8518c2ecf20Sopenharmony_ci * Description: nilfs_ioctl_clean_segments() function makes garbage 8528c2ecf20Sopenharmony_ci * collection operation in the environment of requested parameters 8538c2ecf20Sopenharmony_ci * from userspace. The NILFS_IOCTL_CLEAN_SEGMENTS ioctl is used by 8548c2ecf20Sopenharmony_ci * nilfs_cleanerd daemon. 8558c2ecf20Sopenharmony_ci * 8568c2ecf20Sopenharmony_ci * Return Value: On success, 0 is returned or error code, otherwise. 8578c2ecf20Sopenharmony_ci */ 8588c2ecf20Sopenharmony_cistatic int nilfs_ioctl_clean_segments(struct inode *inode, struct file *filp, 8598c2ecf20Sopenharmony_ci unsigned int cmd, void __user *argp) 8608c2ecf20Sopenharmony_ci{ 8618c2ecf20Sopenharmony_ci struct nilfs_argv argv[5]; 8628c2ecf20Sopenharmony_ci static const size_t argsz[5] = { 8638c2ecf20Sopenharmony_ci sizeof(struct nilfs_vdesc), 8648c2ecf20Sopenharmony_ci sizeof(struct nilfs_period), 8658c2ecf20Sopenharmony_ci sizeof(__u64), 8668c2ecf20Sopenharmony_ci sizeof(struct nilfs_bdesc), 8678c2ecf20Sopenharmony_ci sizeof(__u64), 8688c2ecf20Sopenharmony_ci }; 8698c2ecf20Sopenharmony_ci void __user *base; 8708c2ecf20Sopenharmony_ci void *kbufs[5]; 8718c2ecf20Sopenharmony_ci struct the_nilfs *nilfs; 8728c2ecf20Sopenharmony_ci size_t len, nsegs; 8738c2ecf20Sopenharmony_ci int n, ret; 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_ci if (!capable(CAP_SYS_ADMIN)) 8768c2ecf20Sopenharmony_ci return -EPERM; 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci ret = mnt_want_write_file(filp); 8798c2ecf20Sopenharmony_ci if (ret) 8808c2ecf20Sopenharmony_ci return ret; 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_ci ret = -EFAULT; 8838c2ecf20Sopenharmony_ci if (copy_from_user(argv, argp, sizeof(argv))) 8848c2ecf20Sopenharmony_ci goto out; 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ci ret = -EINVAL; 8878c2ecf20Sopenharmony_ci nsegs = argv[4].v_nmembs; 8888c2ecf20Sopenharmony_ci if (argv[4].v_size != argsz[4]) 8898c2ecf20Sopenharmony_ci goto out; 8908c2ecf20Sopenharmony_ci if (nsegs > UINT_MAX / sizeof(__u64)) 8918c2ecf20Sopenharmony_ci goto out; 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_ci /* 8948c2ecf20Sopenharmony_ci * argv[4] points to segment numbers this ioctl cleans. We 8958c2ecf20Sopenharmony_ci * use kmalloc() for its buffer because memory used for the 8968c2ecf20Sopenharmony_ci * segment numbers is enough small. 8978c2ecf20Sopenharmony_ci */ 8988c2ecf20Sopenharmony_ci kbufs[4] = memdup_user((void __user *)(unsigned long)argv[4].v_base, 8998c2ecf20Sopenharmony_ci nsegs * sizeof(__u64)); 9008c2ecf20Sopenharmony_ci if (IS_ERR(kbufs[4])) { 9018c2ecf20Sopenharmony_ci ret = PTR_ERR(kbufs[4]); 9028c2ecf20Sopenharmony_ci goto out; 9038c2ecf20Sopenharmony_ci } 9048c2ecf20Sopenharmony_ci nilfs = inode->i_sb->s_fs_info; 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_ci for (n = 0; n < 4; n++) { 9078c2ecf20Sopenharmony_ci ret = -EINVAL; 9088c2ecf20Sopenharmony_ci if (argv[n].v_size != argsz[n]) 9098c2ecf20Sopenharmony_ci goto out_free; 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_ci if (argv[n].v_nmembs > nsegs * nilfs->ns_blocks_per_segment) 9128c2ecf20Sopenharmony_ci goto out_free; 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_ci if (argv[n].v_nmembs >= UINT_MAX / argv[n].v_size) 9158c2ecf20Sopenharmony_ci goto out_free; 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_ci len = argv[n].v_size * argv[n].v_nmembs; 9188c2ecf20Sopenharmony_ci base = (void __user *)(unsigned long)argv[n].v_base; 9198c2ecf20Sopenharmony_ci if (len == 0) { 9208c2ecf20Sopenharmony_ci kbufs[n] = NULL; 9218c2ecf20Sopenharmony_ci continue; 9228c2ecf20Sopenharmony_ci } 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_ci kbufs[n] = vmalloc(len); 9258c2ecf20Sopenharmony_ci if (!kbufs[n]) { 9268c2ecf20Sopenharmony_ci ret = -ENOMEM; 9278c2ecf20Sopenharmony_ci goto out_free; 9288c2ecf20Sopenharmony_ci } 9298c2ecf20Sopenharmony_ci if (copy_from_user(kbufs[n], base, len)) { 9308c2ecf20Sopenharmony_ci ret = -EFAULT; 9318c2ecf20Sopenharmony_ci vfree(kbufs[n]); 9328c2ecf20Sopenharmony_ci goto out_free; 9338c2ecf20Sopenharmony_ci } 9348c2ecf20Sopenharmony_ci } 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_ci /* 9378c2ecf20Sopenharmony_ci * nilfs_ioctl_move_blocks() will call nilfs_iget_for_gc(), 9388c2ecf20Sopenharmony_ci * which will operates an inode list without blocking. 9398c2ecf20Sopenharmony_ci * To protect the list from concurrent operations, 9408c2ecf20Sopenharmony_ci * nilfs_ioctl_move_blocks should be atomic operation. 9418c2ecf20Sopenharmony_ci */ 9428c2ecf20Sopenharmony_ci if (test_and_set_bit(THE_NILFS_GC_RUNNING, &nilfs->ns_flags)) { 9438c2ecf20Sopenharmony_ci ret = -EBUSY; 9448c2ecf20Sopenharmony_ci goto out_free; 9458c2ecf20Sopenharmony_ci } 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ci ret = nilfs_ioctl_move_blocks(inode->i_sb, &argv[0], kbufs[0]); 9488c2ecf20Sopenharmony_ci if (ret < 0) { 9498c2ecf20Sopenharmony_ci nilfs_err(inode->i_sb, 9508c2ecf20Sopenharmony_ci "error %d preparing GC: cannot read source blocks", 9518c2ecf20Sopenharmony_ci ret); 9528c2ecf20Sopenharmony_ci } else { 9538c2ecf20Sopenharmony_ci if (nilfs_sb_need_update(nilfs)) 9548c2ecf20Sopenharmony_ci set_nilfs_discontinued(nilfs); 9558c2ecf20Sopenharmony_ci ret = nilfs_clean_segments(inode->i_sb, argv, kbufs); 9568c2ecf20Sopenharmony_ci } 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_ci nilfs_remove_all_gcinodes(nilfs); 9598c2ecf20Sopenharmony_ci clear_nilfs_gc_running(nilfs); 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_ciout_free: 9628c2ecf20Sopenharmony_ci while (--n >= 0) 9638c2ecf20Sopenharmony_ci vfree(kbufs[n]); 9648c2ecf20Sopenharmony_ci kfree(kbufs[4]); 9658c2ecf20Sopenharmony_ciout: 9668c2ecf20Sopenharmony_ci mnt_drop_write_file(filp); 9678c2ecf20Sopenharmony_ci return ret; 9688c2ecf20Sopenharmony_ci} 9698c2ecf20Sopenharmony_ci 9708c2ecf20Sopenharmony_ci/** 9718c2ecf20Sopenharmony_ci * nilfs_ioctl_sync - make a checkpoint 9728c2ecf20Sopenharmony_ci * @inode: inode object 9738c2ecf20Sopenharmony_ci * @filp: file object 9748c2ecf20Sopenharmony_ci * @cmd: ioctl's request code 9758c2ecf20Sopenharmony_ci * @argp: pointer on argument from userspace 9768c2ecf20Sopenharmony_ci * 9778c2ecf20Sopenharmony_ci * Description: nilfs_ioctl_sync() function constructs a logical segment 9788c2ecf20Sopenharmony_ci * for checkpointing. This function guarantees that all modified data 9798c2ecf20Sopenharmony_ci * and metadata are written out to the device when it successfully 9808c2ecf20Sopenharmony_ci * returned. 9818c2ecf20Sopenharmony_ci * 9828c2ecf20Sopenharmony_ci * Return Value: On success, 0 is retured. On errors, one of the following 9838c2ecf20Sopenharmony_ci * negative error code is returned. 9848c2ecf20Sopenharmony_ci * 9858c2ecf20Sopenharmony_ci * %-EROFS - Read only filesystem. 9868c2ecf20Sopenharmony_ci * 9878c2ecf20Sopenharmony_ci * %-EIO - I/O error 9888c2ecf20Sopenharmony_ci * 9898c2ecf20Sopenharmony_ci * %-ENOSPC - No space left on device (only in a panic state). 9908c2ecf20Sopenharmony_ci * 9918c2ecf20Sopenharmony_ci * %-ERESTARTSYS - Interrupted. 9928c2ecf20Sopenharmony_ci * 9938c2ecf20Sopenharmony_ci * %-ENOMEM - Insufficient memory available. 9948c2ecf20Sopenharmony_ci * 9958c2ecf20Sopenharmony_ci * %-EFAULT - Failure during execution of requested operation. 9968c2ecf20Sopenharmony_ci */ 9978c2ecf20Sopenharmony_cistatic int nilfs_ioctl_sync(struct inode *inode, struct file *filp, 9988c2ecf20Sopenharmony_ci unsigned int cmd, void __user *argp) 9998c2ecf20Sopenharmony_ci{ 10008c2ecf20Sopenharmony_ci __u64 cno; 10018c2ecf20Sopenharmony_ci int ret; 10028c2ecf20Sopenharmony_ci struct the_nilfs *nilfs; 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_ci ret = nilfs_construct_segment(inode->i_sb); 10058c2ecf20Sopenharmony_ci if (ret < 0) 10068c2ecf20Sopenharmony_ci return ret; 10078c2ecf20Sopenharmony_ci 10088c2ecf20Sopenharmony_ci nilfs = inode->i_sb->s_fs_info; 10098c2ecf20Sopenharmony_ci ret = nilfs_flush_device(nilfs); 10108c2ecf20Sopenharmony_ci if (ret < 0) 10118c2ecf20Sopenharmony_ci return ret; 10128c2ecf20Sopenharmony_ci 10138c2ecf20Sopenharmony_ci if (argp != NULL) { 10148c2ecf20Sopenharmony_ci down_read(&nilfs->ns_segctor_sem); 10158c2ecf20Sopenharmony_ci cno = nilfs->ns_cno - 1; 10168c2ecf20Sopenharmony_ci up_read(&nilfs->ns_segctor_sem); 10178c2ecf20Sopenharmony_ci if (copy_to_user(argp, &cno, sizeof(cno))) 10188c2ecf20Sopenharmony_ci return -EFAULT; 10198c2ecf20Sopenharmony_ci } 10208c2ecf20Sopenharmony_ci return 0; 10218c2ecf20Sopenharmony_ci} 10228c2ecf20Sopenharmony_ci 10238c2ecf20Sopenharmony_ci/** 10248c2ecf20Sopenharmony_ci * nilfs_ioctl_resize - resize NILFS2 volume 10258c2ecf20Sopenharmony_ci * @inode: inode object 10268c2ecf20Sopenharmony_ci * @filp: file object 10278c2ecf20Sopenharmony_ci * @argp: pointer on argument from userspace 10288c2ecf20Sopenharmony_ci * 10298c2ecf20Sopenharmony_ci * Return Value: On success, 0 is returned or error code, otherwise. 10308c2ecf20Sopenharmony_ci */ 10318c2ecf20Sopenharmony_cistatic int nilfs_ioctl_resize(struct inode *inode, struct file *filp, 10328c2ecf20Sopenharmony_ci void __user *argp) 10338c2ecf20Sopenharmony_ci{ 10348c2ecf20Sopenharmony_ci __u64 newsize; 10358c2ecf20Sopenharmony_ci int ret = -EPERM; 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_ci if (!capable(CAP_SYS_ADMIN)) 10388c2ecf20Sopenharmony_ci goto out; 10398c2ecf20Sopenharmony_ci 10408c2ecf20Sopenharmony_ci ret = mnt_want_write_file(filp); 10418c2ecf20Sopenharmony_ci if (ret) 10428c2ecf20Sopenharmony_ci goto out; 10438c2ecf20Sopenharmony_ci 10448c2ecf20Sopenharmony_ci ret = -EFAULT; 10458c2ecf20Sopenharmony_ci if (copy_from_user(&newsize, argp, sizeof(newsize))) 10468c2ecf20Sopenharmony_ci goto out_drop_write; 10478c2ecf20Sopenharmony_ci 10488c2ecf20Sopenharmony_ci ret = nilfs_resize_fs(inode->i_sb, newsize); 10498c2ecf20Sopenharmony_ci 10508c2ecf20Sopenharmony_ciout_drop_write: 10518c2ecf20Sopenharmony_ci mnt_drop_write_file(filp); 10528c2ecf20Sopenharmony_ciout: 10538c2ecf20Sopenharmony_ci return ret; 10548c2ecf20Sopenharmony_ci} 10558c2ecf20Sopenharmony_ci 10568c2ecf20Sopenharmony_ci/** 10578c2ecf20Sopenharmony_ci * nilfs_ioctl_trim_fs() - trim ioctl handle function 10588c2ecf20Sopenharmony_ci * @inode: inode object 10598c2ecf20Sopenharmony_ci * @argp: pointer on argument from userspace 10608c2ecf20Sopenharmony_ci * 10618c2ecf20Sopenharmony_ci * Decription: nilfs_ioctl_trim_fs is the FITRIM ioctl handle function. It 10628c2ecf20Sopenharmony_ci * checks the arguments from userspace and calls nilfs_sufile_trim_fs, which 10638c2ecf20Sopenharmony_ci * performs the actual trim operation. 10648c2ecf20Sopenharmony_ci * 10658c2ecf20Sopenharmony_ci * Return Value: On success, 0 is returned or negative error code, otherwise. 10668c2ecf20Sopenharmony_ci */ 10678c2ecf20Sopenharmony_cistatic int nilfs_ioctl_trim_fs(struct inode *inode, void __user *argp) 10688c2ecf20Sopenharmony_ci{ 10698c2ecf20Sopenharmony_ci struct the_nilfs *nilfs = inode->i_sb->s_fs_info; 10708c2ecf20Sopenharmony_ci struct request_queue *q = bdev_get_queue(nilfs->ns_bdev); 10718c2ecf20Sopenharmony_ci struct fstrim_range range; 10728c2ecf20Sopenharmony_ci int ret; 10738c2ecf20Sopenharmony_ci 10748c2ecf20Sopenharmony_ci if (!capable(CAP_SYS_ADMIN)) 10758c2ecf20Sopenharmony_ci return -EPERM; 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_ci if (!blk_queue_discard(q)) 10788c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 10798c2ecf20Sopenharmony_ci 10808c2ecf20Sopenharmony_ci if (copy_from_user(&range, argp, sizeof(range))) 10818c2ecf20Sopenharmony_ci return -EFAULT; 10828c2ecf20Sopenharmony_ci 10838c2ecf20Sopenharmony_ci range.minlen = max_t(u64, range.minlen, q->limits.discard_granularity); 10848c2ecf20Sopenharmony_ci 10858c2ecf20Sopenharmony_ci down_read(&nilfs->ns_segctor_sem); 10868c2ecf20Sopenharmony_ci ret = nilfs_sufile_trim_fs(nilfs->ns_sufile, &range); 10878c2ecf20Sopenharmony_ci up_read(&nilfs->ns_segctor_sem); 10888c2ecf20Sopenharmony_ci 10898c2ecf20Sopenharmony_ci if (ret < 0) 10908c2ecf20Sopenharmony_ci return ret; 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_ci if (copy_to_user(argp, &range, sizeof(range))) 10938c2ecf20Sopenharmony_ci return -EFAULT; 10948c2ecf20Sopenharmony_ci 10958c2ecf20Sopenharmony_ci return 0; 10968c2ecf20Sopenharmony_ci} 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_ci/** 10998c2ecf20Sopenharmony_ci * nilfs_ioctl_set_alloc_range - limit range of segments to be allocated 11008c2ecf20Sopenharmony_ci * @inode: inode object 11018c2ecf20Sopenharmony_ci * @argp: pointer on argument from userspace 11028c2ecf20Sopenharmony_ci * 11038c2ecf20Sopenharmony_ci * Decription: nilfs_ioctl_set_alloc_range() function defines lower limit 11048c2ecf20Sopenharmony_ci * of segments in bytes and upper limit of segments in bytes. 11058c2ecf20Sopenharmony_ci * The NILFS_IOCTL_SET_ALLOC_RANGE is used by nilfs_resize utility. 11068c2ecf20Sopenharmony_ci * 11078c2ecf20Sopenharmony_ci * Return Value: On success, 0 is returned or error code, otherwise. 11088c2ecf20Sopenharmony_ci */ 11098c2ecf20Sopenharmony_cistatic int nilfs_ioctl_set_alloc_range(struct inode *inode, void __user *argp) 11108c2ecf20Sopenharmony_ci{ 11118c2ecf20Sopenharmony_ci struct the_nilfs *nilfs = inode->i_sb->s_fs_info; 11128c2ecf20Sopenharmony_ci __u64 range[2]; 11138c2ecf20Sopenharmony_ci __u64 minseg, maxseg; 11148c2ecf20Sopenharmony_ci unsigned long segbytes; 11158c2ecf20Sopenharmony_ci int ret = -EPERM; 11168c2ecf20Sopenharmony_ci 11178c2ecf20Sopenharmony_ci if (!capable(CAP_SYS_ADMIN)) 11188c2ecf20Sopenharmony_ci goto out; 11198c2ecf20Sopenharmony_ci 11208c2ecf20Sopenharmony_ci ret = -EFAULT; 11218c2ecf20Sopenharmony_ci if (copy_from_user(range, argp, sizeof(__u64[2]))) 11228c2ecf20Sopenharmony_ci goto out; 11238c2ecf20Sopenharmony_ci 11248c2ecf20Sopenharmony_ci ret = -ERANGE; 11258c2ecf20Sopenharmony_ci if (range[1] > i_size_read(inode->i_sb->s_bdev->bd_inode)) 11268c2ecf20Sopenharmony_ci goto out; 11278c2ecf20Sopenharmony_ci 11288c2ecf20Sopenharmony_ci segbytes = nilfs->ns_blocks_per_segment * nilfs->ns_blocksize; 11298c2ecf20Sopenharmony_ci 11308c2ecf20Sopenharmony_ci minseg = range[0] + segbytes - 1; 11318c2ecf20Sopenharmony_ci do_div(minseg, segbytes); 11328c2ecf20Sopenharmony_ci 11338c2ecf20Sopenharmony_ci if (range[1] < 4096) 11348c2ecf20Sopenharmony_ci goto out; 11358c2ecf20Sopenharmony_ci 11368c2ecf20Sopenharmony_ci maxseg = NILFS_SB2_OFFSET_BYTES(range[1]); 11378c2ecf20Sopenharmony_ci if (maxseg < segbytes) 11388c2ecf20Sopenharmony_ci goto out; 11398c2ecf20Sopenharmony_ci 11408c2ecf20Sopenharmony_ci do_div(maxseg, segbytes); 11418c2ecf20Sopenharmony_ci maxseg--; 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_ci ret = nilfs_sufile_set_alloc_range(nilfs->ns_sufile, minseg, maxseg); 11448c2ecf20Sopenharmony_ciout: 11458c2ecf20Sopenharmony_ci return ret; 11468c2ecf20Sopenharmony_ci} 11478c2ecf20Sopenharmony_ci 11488c2ecf20Sopenharmony_ci/** 11498c2ecf20Sopenharmony_ci * nilfs_ioctl_get_info - wrapping function of get metadata info 11508c2ecf20Sopenharmony_ci * @inode: inode object 11518c2ecf20Sopenharmony_ci * @filp: file object 11528c2ecf20Sopenharmony_ci * @cmd: ioctl's request code 11538c2ecf20Sopenharmony_ci * @argp: pointer on argument from userspace 11548c2ecf20Sopenharmony_ci * @membsz: size of an item in bytes 11558c2ecf20Sopenharmony_ci * @dofunc: concrete function of getting metadata info 11568c2ecf20Sopenharmony_ci * 11578c2ecf20Sopenharmony_ci * Description: nilfs_ioctl_get_info() gets metadata info by means of 11588c2ecf20Sopenharmony_ci * calling dofunc() function. 11598c2ecf20Sopenharmony_ci * 11608c2ecf20Sopenharmony_ci * Return Value: On success, 0 is returned and requested metadata info 11618c2ecf20Sopenharmony_ci * is copied into userspace. On error, one of the following 11628c2ecf20Sopenharmony_ci * negative error codes is returned. 11638c2ecf20Sopenharmony_ci * 11648c2ecf20Sopenharmony_ci * %-EINVAL - Invalid arguments from userspace. 11658c2ecf20Sopenharmony_ci * 11668c2ecf20Sopenharmony_ci * %-ENOMEM - Insufficient amount of memory available. 11678c2ecf20Sopenharmony_ci * 11688c2ecf20Sopenharmony_ci * %-EFAULT - Failure during execution of requested operation. 11698c2ecf20Sopenharmony_ci */ 11708c2ecf20Sopenharmony_cistatic int nilfs_ioctl_get_info(struct inode *inode, struct file *filp, 11718c2ecf20Sopenharmony_ci unsigned int cmd, void __user *argp, 11728c2ecf20Sopenharmony_ci size_t membsz, 11738c2ecf20Sopenharmony_ci ssize_t (*dofunc)(struct the_nilfs *, 11748c2ecf20Sopenharmony_ci __u64 *, int, 11758c2ecf20Sopenharmony_ci void *, size_t, size_t)) 11768c2ecf20Sopenharmony_ci 11778c2ecf20Sopenharmony_ci{ 11788c2ecf20Sopenharmony_ci struct the_nilfs *nilfs = inode->i_sb->s_fs_info; 11798c2ecf20Sopenharmony_ci struct nilfs_argv argv; 11808c2ecf20Sopenharmony_ci int ret; 11818c2ecf20Sopenharmony_ci 11828c2ecf20Sopenharmony_ci if (copy_from_user(&argv, argp, sizeof(argv))) 11838c2ecf20Sopenharmony_ci return -EFAULT; 11848c2ecf20Sopenharmony_ci 11858c2ecf20Sopenharmony_ci if (argv.v_size < membsz) 11868c2ecf20Sopenharmony_ci return -EINVAL; 11878c2ecf20Sopenharmony_ci 11888c2ecf20Sopenharmony_ci ret = nilfs_ioctl_wrap_copy(nilfs, &argv, _IOC_DIR(cmd), dofunc); 11898c2ecf20Sopenharmony_ci if (ret < 0) 11908c2ecf20Sopenharmony_ci return ret; 11918c2ecf20Sopenharmony_ci 11928c2ecf20Sopenharmony_ci if (copy_to_user(argp, &argv, sizeof(argv))) 11938c2ecf20Sopenharmony_ci ret = -EFAULT; 11948c2ecf20Sopenharmony_ci return ret; 11958c2ecf20Sopenharmony_ci} 11968c2ecf20Sopenharmony_ci 11978c2ecf20Sopenharmony_ci/** 11988c2ecf20Sopenharmony_ci * nilfs_ioctl_set_suinfo - set segment usage info 11998c2ecf20Sopenharmony_ci * @inode: inode object 12008c2ecf20Sopenharmony_ci * @filp: file object 12018c2ecf20Sopenharmony_ci * @cmd: ioctl's request code 12028c2ecf20Sopenharmony_ci * @argp: pointer on argument from userspace 12038c2ecf20Sopenharmony_ci * 12048c2ecf20Sopenharmony_ci * Description: Expects an array of nilfs_suinfo_update structures 12058c2ecf20Sopenharmony_ci * encapsulated in nilfs_argv and updates the segment usage info 12068c2ecf20Sopenharmony_ci * according to the flags in nilfs_suinfo_update. 12078c2ecf20Sopenharmony_ci * 12088c2ecf20Sopenharmony_ci * Return Value: On success, 0 is returned. On error, one of the 12098c2ecf20Sopenharmony_ci * following negative error codes is returned. 12108c2ecf20Sopenharmony_ci * 12118c2ecf20Sopenharmony_ci * %-EPERM - Not enough permissions 12128c2ecf20Sopenharmony_ci * 12138c2ecf20Sopenharmony_ci * %-EFAULT - Error copying input data 12148c2ecf20Sopenharmony_ci * 12158c2ecf20Sopenharmony_ci * %-EIO - I/O error. 12168c2ecf20Sopenharmony_ci * 12178c2ecf20Sopenharmony_ci * %-ENOMEM - Insufficient amount of memory available. 12188c2ecf20Sopenharmony_ci * 12198c2ecf20Sopenharmony_ci * %-EINVAL - Invalid values in input (segment number, flags or nblocks) 12208c2ecf20Sopenharmony_ci */ 12218c2ecf20Sopenharmony_cistatic int nilfs_ioctl_set_suinfo(struct inode *inode, struct file *filp, 12228c2ecf20Sopenharmony_ci unsigned int cmd, void __user *argp) 12238c2ecf20Sopenharmony_ci{ 12248c2ecf20Sopenharmony_ci struct the_nilfs *nilfs = inode->i_sb->s_fs_info; 12258c2ecf20Sopenharmony_ci struct nilfs_transaction_info ti; 12268c2ecf20Sopenharmony_ci struct nilfs_argv argv; 12278c2ecf20Sopenharmony_ci size_t len; 12288c2ecf20Sopenharmony_ci void __user *base; 12298c2ecf20Sopenharmony_ci void *kbuf; 12308c2ecf20Sopenharmony_ci int ret; 12318c2ecf20Sopenharmony_ci 12328c2ecf20Sopenharmony_ci if (!capable(CAP_SYS_ADMIN)) 12338c2ecf20Sopenharmony_ci return -EPERM; 12348c2ecf20Sopenharmony_ci 12358c2ecf20Sopenharmony_ci ret = mnt_want_write_file(filp); 12368c2ecf20Sopenharmony_ci if (ret) 12378c2ecf20Sopenharmony_ci return ret; 12388c2ecf20Sopenharmony_ci 12398c2ecf20Sopenharmony_ci ret = -EFAULT; 12408c2ecf20Sopenharmony_ci if (copy_from_user(&argv, argp, sizeof(argv))) 12418c2ecf20Sopenharmony_ci goto out; 12428c2ecf20Sopenharmony_ci 12438c2ecf20Sopenharmony_ci ret = -EINVAL; 12448c2ecf20Sopenharmony_ci if (argv.v_size < sizeof(struct nilfs_suinfo_update)) 12458c2ecf20Sopenharmony_ci goto out; 12468c2ecf20Sopenharmony_ci 12478c2ecf20Sopenharmony_ci if (argv.v_nmembs > nilfs->ns_nsegments) 12488c2ecf20Sopenharmony_ci goto out; 12498c2ecf20Sopenharmony_ci 12508c2ecf20Sopenharmony_ci if (argv.v_nmembs >= UINT_MAX / argv.v_size) 12518c2ecf20Sopenharmony_ci goto out; 12528c2ecf20Sopenharmony_ci 12538c2ecf20Sopenharmony_ci len = argv.v_size * argv.v_nmembs; 12548c2ecf20Sopenharmony_ci if (!len) { 12558c2ecf20Sopenharmony_ci ret = 0; 12568c2ecf20Sopenharmony_ci goto out; 12578c2ecf20Sopenharmony_ci } 12588c2ecf20Sopenharmony_ci 12598c2ecf20Sopenharmony_ci base = (void __user *)(unsigned long)argv.v_base; 12608c2ecf20Sopenharmony_ci kbuf = vmalloc(len); 12618c2ecf20Sopenharmony_ci if (!kbuf) { 12628c2ecf20Sopenharmony_ci ret = -ENOMEM; 12638c2ecf20Sopenharmony_ci goto out; 12648c2ecf20Sopenharmony_ci } 12658c2ecf20Sopenharmony_ci 12668c2ecf20Sopenharmony_ci if (copy_from_user(kbuf, base, len)) { 12678c2ecf20Sopenharmony_ci ret = -EFAULT; 12688c2ecf20Sopenharmony_ci goto out_free; 12698c2ecf20Sopenharmony_ci } 12708c2ecf20Sopenharmony_ci 12718c2ecf20Sopenharmony_ci nilfs_transaction_begin(inode->i_sb, &ti, 0); 12728c2ecf20Sopenharmony_ci ret = nilfs_sufile_set_suinfo(nilfs->ns_sufile, kbuf, argv.v_size, 12738c2ecf20Sopenharmony_ci argv.v_nmembs); 12748c2ecf20Sopenharmony_ci if (unlikely(ret < 0)) 12758c2ecf20Sopenharmony_ci nilfs_transaction_abort(inode->i_sb); 12768c2ecf20Sopenharmony_ci else 12778c2ecf20Sopenharmony_ci nilfs_transaction_commit(inode->i_sb); /* never fails */ 12788c2ecf20Sopenharmony_ci 12798c2ecf20Sopenharmony_ciout_free: 12808c2ecf20Sopenharmony_ci vfree(kbuf); 12818c2ecf20Sopenharmony_ciout: 12828c2ecf20Sopenharmony_ci mnt_drop_write_file(filp); 12838c2ecf20Sopenharmony_ci return ret; 12848c2ecf20Sopenharmony_ci} 12858c2ecf20Sopenharmony_ci 12868c2ecf20Sopenharmony_cilong nilfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) 12878c2ecf20Sopenharmony_ci{ 12888c2ecf20Sopenharmony_ci struct inode *inode = file_inode(filp); 12898c2ecf20Sopenharmony_ci void __user *argp = (void __user *)arg; 12908c2ecf20Sopenharmony_ci 12918c2ecf20Sopenharmony_ci switch (cmd) { 12928c2ecf20Sopenharmony_ci case FS_IOC_GETFLAGS: 12938c2ecf20Sopenharmony_ci return nilfs_ioctl_getflags(inode, argp); 12948c2ecf20Sopenharmony_ci case FS_IOC_SETFLAGS: 12958c2ecf20Sopenharmony_ci return nilfs_ioctl_setflags(inode, filp, argp); 12968c2ecf20Sopenharmony_ci case FS_IOC_GETVERSION: 12978c2ecf20Sopenharmony_ci return nilfs_ioctl_getversion(inode, argp); 12988c2ecf20Sopenharmony_ci case NILFS_IOCTL_CHANGE_CPMODE: 12998c2ecf20Sopenharmony_ci return nilfs_ioctl_change_cpmode(inode, filp, cmd, argp); 13008c2ecf20Sopenharmony_ci case NILFS_IOCTL_DELETE_CHECKPOINT: 13018c2ecf20Sopenharmony_ci return nilfs_ioctl_delete_checkpoint(inode, filp, cmd, argp); 13028c2ecf20Sopenharmony_ci case NILFS_IOCTL_GET_CPINFO: 13038c2ecf20Sopenharmony_ci return nilfs_ioctl_get_info(inode, filp, cmd, argp, 13048c2ecf20Sopenharmony_ci sizeof(struct nilfs_cpinfo), 13058c2ecf20Sopenharmony_ci nilfs_ioctl_do_get_cpinfo); 13068c2ecf20Sopenharmony_ci case NILFS_IOCTL_GET_CPSTAT: 13078c2ecf20Sopenharmony_ci return nilfs_ioctl_get_cpstat(inode, filp, cmd, argp); 13088c2ecf20Sopenharmony_ci case NILFS_IOCTL_GET_SUINFO: 13098c2ecf20Sopenharmony_ci return nilfs_ioctl_get_info(inode, filp, cmd, argp, 13108c2ecf20Sopenharmony_ci sizeof(struct nilfs_suinfo), 13118c2ecf20Sopenharmony_ci nilfs_ioctl_do_get_suinfo); 13128c2ecf20Sopenharmony_ci case NILFS_IOCTL_SET_SUINFO: 13138c2ecf20Sopenharmony_ci return nilfs_ioctl_set_suinfo(inode, filp, cmd, argp); 13148c2ecf20Sopenharmony_ci case NILFS_IOCTL_GET_SUSTAT: 13158c2ecf20Sopenharmony_ci return nilfs_ioctl_get_sustat(inode, filp, cmd, argp); 13168c2ecf20Sopenharmony_ci case NILFS_IOCTL_GET_VINFO: 13178c2ecf20Sopenharmony_ci return nilfs_ioctl_get_info(inode, filp, cmd, argp, 13188c2ecf20Sopenharmony_ci sizeof(struct nilfs_vinfo), 13198c2ecf20Sopenharmony_ci nilfs_ioctl_do_get_vinfo); 13208c2ecf20Sopenharmony_ci case NILFS_IOCTL_GET_BDESCS: 13218c2ecf20Sopenharmony_ci return nilfs_ioctl_get_bdescs(inode, filp, cmd, argp); 13228c2ecf20Sopenharmony_ci case NILFS_IOCTL_CLEAN_SEGMENTS: 13238c2ecf20Sopenharmony_ci return nilfs_ioctl_clean_segments(inode, filp, cmd, argp); 13248c2ecf20Sopenharmony_ci case NILFS_IOCTL_SYNC: 13258c2ecf20Sopenharmony_ci return nilfs_ioctl_sync(inode, filp, cmd, argp); 13268c2ecf20Sopenharmony_ci case NILFS_IOCTL_RESIZE: 13278c2ecf20Sopenharmony_ci return nilfs_ioctl_resize(inode, filp, argp); 13288c2ecf20Sopenharmony_ci case NILFS_IOCTL_SET_ALLOC_RANGE: 13298c2ecf20Sopenharmony_ci return nilfs_ioctl_set_alloc_range(inode, argp); 13308c2ecf20Sopenharmony_ci case FITRIM: 13318c2ecf20Sopenharmony_ci return nilfs_ioctl_trim_fs(inode, argp); 13328c2ecf20Sopenharmony_ci default: 13338c2ecf20Sopenharmony_ci return -ENOTTY; 13348c2ecf20Sopenharmony_ci } 13358c2ecf20Sopenharmony_ci} 13368c2ecf20Sopenharmony_ci 13378c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT 13388c2ecf20Sopenharmony_cilong nilfs_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) 13398c2ecf20Sopenharmony_ci{ 13408c2ecf20Sopenharmony_ci switch (cmd) { 13418c2ecf20Sopenharmony_ci case FS_IOC32_GETFLAGS: 13428c2ecf20Sopenharmony_ci cmd = FS_IOC_GETFLAGS; 13438c2ecf20Sopenharmony_ci break; 13448c2ecf20Sopenharmony_ci case FS_IOC32_SETFLAGS: 13458c2ecf20Sopenharmony_ci cmd = FS_IOC_SETFLAGS; 13468c2ecf20Sopenharmony_ci break; 13478c2ecf20Sopenharmony_ci case FS_IOC32_GETVERSION: 13488c2ecf20Sopenharmony_ci cmd = FS_IOC_GETVERSION; 13498c2ecf20Sopenharmony_ci break; 13508c2ecf20Sopenharmony_ci case NILFS_IOCTL_CHANGE_CPMODE: 13518c2ecf20Sopenharmony_ci case NILFS_IOCTL_DELETE_CHECKPOINT: 13528c2ecf20Sopenharmony_ci case NILFS_IOCTL_GET_CPINFO: 13538c2ecf20Sopenharmony_ci case NILFS_IOCTL_GET_CPSTAT: 13548c2ecf20Sopenharmony_ci case NILFS_IOCTL_GET_SUINFO: 13558c2ecf20Sopenharmony_ci case NILFS_IOCTL_SET_SUINFO: 13568c2ecf20Sopenharmony_ci case NILFS_IOCTL_GET_SUSTAT: 13578c2ecf20Sopenharmony_ci case NILFS_IOCTL_GET_VINFO: 13588c2ecf20Sopenharmony_ci case NILFS_IOCTL_GET_BDESCS: 13598c2ecf20Sopenharmony_ci case NILFS_IOCTL_CLEAN_SEGMENTS: 13608c2ecf20Sopenharmony_ci case NILFS_IOCTL_SYNC: 13618c2ecf20Sopenharmony_ci case NILFS_IOCTL_RESIZE: 13628c2ecf20Sopenharmony_ci case NILFS_IOCTL_SET_ALLOC_RANGE: 13638c2ecf20Sopenharmony_ci case FITRIM: 13648c2ecf20Sopenharmony_ci break; 13658c2ecf20Sopenharmony_ci default: 13668c2ecf20Sopenharmony_ci return -ENOIOCTLCMD; 13678c2ecf20Sopenharmony_ci } 13688c2ecf20Sopenharmony_ci return nilfs_ioctl(filp, cmd, (unsigned long)compat_ptr(arg)); 13698c2ecf20Sopenharmony_ci} 13708c2ecf20Sopenharmony_ci#endif 1371