17942b919SKoji Sato /* 27942b919SKoji Sato * ioctl.c - NILFS ioctl operations. 37942b919SKoji Sato * 47942b919SKoji Sato * Copyright (C) 2007, 2008 Nippon Telegraph and Telephone Corporation. 57942b919SKoji Sato * 67942b919SKoji Sato * This program is free software; you can redistribute it and/or modify 77942b919SKoji Sato * it under the terms of the GNU General Public License as published by 87942b919SKoji Sato * the Free Software Foundation; either version 2 of the License, or 97942b919SKoji Sato * (at your option) any later version. 107942b919SKoji Sato * 117942b919SKoji Sato * This program is distributed in the hope that it will be useful, 127942b919SKoji Sato * but WITHOUT ANY WARRANTY; without even the implied warranty of 137942b919SKoji Sato * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 147942b919SKoji Sato * GNU General Public License for more details. 157942b919SKoji Sato * 167942b919SKoji Sato * You should have received a copy of the GNU General Public License 177942b919SKoji Sato * along with this program; if not, write to the Free Software 187942b919SKoji Sato * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 197942b919SKoji Sato * 207942b919SKoji Sato * Written by Koji Sato <koji@osrg.net>. 217942b919SKoji Sato */ 227942b919SKoji Sato 237942b919SKoji Sato #include <linux/fs.h> 247942b919SKoji Sato #include <linux/wait.h> 255a0e3ad6STejun Heo #include <linux/slab.h> 267942b919SKoji Sato #include <linux/capability.h> /* capable() */ 277942b919SKoji Sato #include <linux/uaccess.h> /* copy_from_user(), copy_to_user() */ 284f6b8288SRyusuke Konishi #include <linux/vmalloc.h> 297512487eSRyusuke Konishi #include <linux/mount.h> /* mnt_want_write(), mnt_drop_write() */ 307942b919SKoji Sato #include <linux/nilfs2_fs.h> 317942b919SKoji Sato #include "nilfs.h" 327942b919SKoji Sato #include "segment.h" 337942b919SKoji Sato #include "bmap.h" 347942b919SKoji Sato #include "cpfile.h" 357942b919SKoji Sato #include "sufile.h" 367942b919SKoji Sato #include "dat.h" 377942b919SKoji Sato 387942b919SKoji Sato 397942b919SKoji Sato static int nilfs_ioctl_wrap_copy(struct the_nilfs *nilfs, 407942b919SKoji Sato struct nilfs_argv *argv, int dir, 417942b919SKoji Sato ssize_t (*dofunc)(struct the_nilfs *, 42b028fcfcSRyusuke Konishi __u64 *, int, 437942b919SKoji Sato void *, size_t, size_t)) 447942b919SKoji Sato { 457942b919SKoji Sato void *buf; 46dc498d09SRyusuke Konishi void __user *base = (void __user *)(unsigned long)argv->v_base; 473358b4aaSRyusuke Konishi size_t maxmembs, total, n; 487942b919SKoji Sato ssize_t nr; 497942b919SKoji Sato int ret, i; 50b028fcfcSRyusuke Konishi __u64 pos, ppos; 517942b919SKoji Sato 527942b919SKoji Sato if (argv->v_nmembs == 0) 537942b919SKoji Sato return 0; 547942b919SKoji Sato 553358b4aaSRyusuke Konishi if (argv->v_size > PAGE_SIZE) 563358b4aaSRyusuke Konishi return -EINVAL; 573358b4aaSRyusuke Konishi 583358b4aaSRyusuke Konishi buf = (void *)__get_free_pages(GFP_NOFS, 0); 593358b4aaSRyusuke Konishi if (unlikely(!buf)) 607942b919SKoji Sato return -ENOMEM; 613358b4aaSRyusuke Konishi maxmembs = PAGE_SIZE / argv->v_size; 627942b919SKoji Sato 637942b919SKoji Sato ret = 0; 647942b919SKoji Sato total = 0; 65b028fcfcSRyusuke Konishi pos = argv->v_index; 667942b919SKoji Sato for (i = 0; i < argv->v_nmembs; i += n) { 677942b919SKoji Sato n = (argv->v_nmembs - i < maxmembs) ? 687942b919SKoji Sato argv->v_nmembs - i : maxmembs; 697942b919SKoji Sato if ((dir & _IOC_WRITE) && 70dc498d09SRyusuke Konishi copy_from_user(buf, base + argv->v_size * i, 717942b919SKoji Sato argv->v_size * n)) { 727942b919SKoji Sato ret = -EFAULT; 737942b919SKoji Sato break; 747942b919SKoji Sato } 75b028fcfcSRyusuke Konishi ppos = pos; 768acfbf09SPekka Enberg nr = dofunc(nilfs, &pos, argv->v_flags, buf, argv->v_size, 77b028fcfcSRyusuke Konishi n); 787942b919SKoji Sato if (nr < 0) { 797942b919SKoji Sato ret = nr; 807942b919SKoji Sato break; 817942b919SKoji Sato } 827942b919SKoji Sato if ((dir & _IOC_READ) && 83dc498d09SRyusuke Konishi copy_to_user(base + argv->v_size * i, buf, 84dc498d09SRyusuke Konishi argv->v_size * nr)) { 857942b919SKoji Sato ret = -EFAULT; 867942b919SKoji Sato break; 877942b919SKoji Sato } 887942b919SKoji Sato total += nr; 89b028fcfcSRyusuke Konishi if ((size_t)nr < n) 90b028fcfcSRyusuke Konishi break; 91b028fcfcSRyusuke Konishi if (pos == ppos) 92b028fcfcSRyusuke Konishi pos += n; 937942b919SKoji Sato } 947942b919SKoji Sato argv->v_nmembs = total; 957942b919SKoji Sato 963358b4aaSRyusuke Konishi free_pages((unsigned long)buf, 0); 977942b919SKoji Sato return ret; 987942b919SKoji Sato } 997942b919SKoji Sato 1007942b919SKoji Sato static int nilfs_ioctl_change_cpmode(struct inode *inode, struct file *filp, 1017942b919SKoji Sato unsigned int cmd, void __user *argp) 1027942b919SKoji Sato { 103c1ea985cSRyusuke Konishi struct the_nilfs *nilfs = NILFS_SB(inode->i_sb)->s_nilfs; 104c1ea985cSRyusuke Konishi struct inode *cpfile = nilfs->ns_cpfile; 1057942b919SKoji Sato struct nilfs_transaction_info ti; 1067942b919SKoji Sato struct nilfs_cpmode cpmode; 1077942b919SKoji Sato int ret; 1087942b919SKoji Sato 1097942b919SKoji Sato if (!capable(CAP_SYS_ADMIN)) 1107942b919SKoji Sato return -EPERM; 1117512487eSRyusuke Konishi 1127512487eSRyusuke Konishi ret = mnt_want_write(filp->f_path.mnt); 1137512487eSRyusuke Konishi if (ret) 1147512487eSRyusuke Konishi return ret; 1157512487eSRyusuke Konishi 1167512487eSRyusuke Konishi ret = -EFAULT; 1177942b919SKoji Sato if (copy_from_user(&cpmode, argp, sizeof(cpmode))) 1187512487eSRyusuke Konishi goto out; 1197942b919SKoji Sato 120348fe8daSRyusuke Konishi down_read(&inode->i_sb->s_umount); 1217512487eSRyusuke Konishi 1227942b919SKoji Sato nilfs_transaction_begin(inode->i_sb, &ti, 0); 1237942b919SKoji Sato ret = nilfs_cpfile_change_cpmode( 1247942b919SKoji Sato cpfile, cpmode.cm_cno, cpmode.cm_mode); 1257512487eSRyusuke Konishi if (unlikely(ret < 0)) 12647420c79SRyusuke Konishi nilfs_transaction_abort(inode->i_sb); 1277512487eSRyusuke Konishi else 12847420c79SRyusuke Konishi nilfs_transaction_commit(inode->i_sb); /* never fails */ 1297512487eSRyusuke Konishi 130348fe8daSRyusuke Konishi up_read(&inode->i_sb->s_umount); 1317512487eSRyusuke Konishi out: 1327512487eSRyusuke Konishi mnt_drop_write(filp->f_path.mnt); 1337942b919SKoji Sato return ret; 1347942b919SKoji Sato } 1357942b919SKoji Sato 1367942b919SKoji Sato static int 1377942b919SKoji Sato nilfs_ioctl_delete_checkpoint(struct inode *inode, struct file *filp, 1387942b919SKoji Sato unsigned int cmd, void __user *argp) 1397942b919SKoji Sato { 1407942b919SKoji Sato struct inode *cpfile = NILFS_SB(inode->i_sb)->s_nilfs->ns_cpfile; 1417942b919SKoji Sato struct nilfs_transaction_info ti; 1427942b919SKoji Sato __u64 cno; 1437942b919SKoji Sato int ret; 1447942b919SKoji Sato 1457942b919SKoji Sato if (!capable(CAP_SYS_ADMIN)) 1467942b919SKoji Sato return -EPERM; 1477512487eSRyusuke Konishi 1487512487eSRyusuke Konishi ret = mnt_want_write(filp->f_path.mnt); 1497512487eSRyusuke Konishi if (ret) 1507512487eSRyusuke Konishi return ret; 1517512487eSRyusuke Konishi 1527512487eSRyusuke Konishi ret = -EFAULT; 1537942b919SKoji Sato if (copy_from_user(&cno, argp, sizeof(cno))) 1547512487eSRyusuke Konishi goto out; 1557942b919SKoji Sato 1567942b919SKoji Sato nilfs_transaction_begin(inode->i_sb, &ti, 0); 1577942b919SKoji Sato ret = nilfs_cpfile_delete_checkpoint(cpfile, cno); 1587512487eSRyusuke Konishi if (unlikely(ret < 0)) 15947420c79SRyusuke Konishi nilfs_transaction_abort(inode->i_sb); 1607512487eSRyusuke Konishi else 16147420c79SRyusuke Konishi nilfs_transaction_commit(inode->i_sb); /* never fails */ 1627512487eSRyusuke Konishi out: 1637512487eSRyusuke Konishi mnt_drop_write(filp->f_path.mnt); 1647942b919SKoji Sato return ret; 1657942b919SKoji Sato } 1667942b919SKoji Sato 1677942b919SKoji Sato static ssize_t 168b028fcfcSRyusuke Konishi nilfs_ioctl_do_get_cpinfo(struct the_nilfs *nilfs, __u64 *posp, int flags, 1697942b919SKoji Sato void *buf, size_t size, size_t nmembs) 1707942b919SKoji Sato { 1717942b919SKoji Sato int ret; 1727942b919SKoji Sato 17347420c79SRyusuke Konishi down_read(&nilfs->ns_segctor_sem); 17447eb6b9cSRyusuke Konishi ret = nilfs_cpfile_get_cpinfo(nilfs->ns_cpfile, posp, flags, buf, 175003ff182SRyusuke Konishi size, nmembs); 17647420c79SRyusuke Konishi up_read(&nilfs->ns_segctor_sem); 1777942b919SKoji Sato return ret; 1787942b919SKoji Sato } 1797942b919SKoji Sato 1807942b919SKoji Sato static int nilfs_ioctl_get_cpstat(struct inode *inode, struct file *filp, 1817942b919SKoji Sato unsigned int cmd, void __user *argp) 1827942b919SKoji Sato { 18347420c79SRyusuke Konishi struct the_nilfs *nilfs = NILFS_SB(inode->i_sb)->s_nilfs; 1847942b919SKoji Sato struct nilfs_cpstat cpstat; 1857942b919SKoji Sato int ret; 1867942b919SKoji Sato 18747420c79SRyusuke Konishi down_read(&nilfs->ns_segctor_sem); 18847420c79SRyusuke Konishi ret = nilfs_cpfile_get_stat(nilfs->ns_cpfile, &cpstat); 18947420c79SRyusuke Konishi up_read(&nilfs->ns_segctor_sem); 1907942b919SKoji Sato if (ret < 0) 1917942b919SKoji Sato return ret; 1927942b919SKoji Sato 1937942b919SKoji Sato if (copy_to_user(argp, &cpstat, sizeof(cpstat))) 1947942b919SKoji Sato ret = -EFAULT; 1957942b919SKoji Sato return ret; 1967942b919SKoji Sato } 1977942b919SKoji Sato 1987942b919SKoji Sato static ssize_t 199b028fcfcSRyusuke Konishi nilfs_ioctl_do_get_suinfo(struct the_nilfs *nilfs, __u64 *posp, int flags, 2007942b919SKoji Sato void *buf, size_t size, size_t nmembs) 2017942b919SKoji Sato { 2027942b919SKoji Sato int ret; 2037942b919SKoji Sato 20447420c79SRyusuke Konishi down_read(&nilfs->ns_segctor_sem); 205003ff182SRyusuke Konishi ret = nilfs_sufile_get_suinfo(nilfs->ns_sufile, *posp, buf, size, 206003ff182SRyusuke Konishi nmembs); 20747420c79SRyusuke Konishi up_read(&nilfs->ns_segctor_sem); 2087942b919SKoji Sato return ret; 2097942b919SKoji Sato } 2107942b919SKoji Sato 2117942b919SKoji Sato static int nilfs_ioctl_get_sustat(struct inode *inode, struct file *filp, 2127942b919SKoji Sato unsigned int cmd, void __user *argp) 2137942b919SKoji Sato { 21447420c79SRyusuke Konishi struct the_nilfs *nilfs = NILFS_SB(inode->i_sb)->s_nilfs; 2157942b919SKoji Sato struct nilfs_sustat sustat; 2167942b919SKoji Sato int ret; 2177942b919SKoji Sato 21847420c79SRyusuke Konishi down_read(&nilfs->ns_segctor_sem); 21947420c79SRyusuke Konishi ret = nilfs_sufile_get_stat(nilfs->ns_sufile, &sustat); 22047420c79SRyusuke Konishi up_read(&nilfs->ns_segctor_sem); 2217942b919SKoji Sato if (ret < 0) 2227942b919SKoji Sato return ret; 2237942b919SKoji Sato 2247942b919SKoji Sato if (copy_to_user(argp, &sustat, sizeof(sustat))) 2257942b919SKoji Sato ret = -EFAULT; 2267942b919SKoji Sato return ret; 2277942b919SKoji Sato } 2287942b919SKoji Sato 2297942b919SKoji Sato static ssize_t 230b028fcfcSRyusuke Konishi nilfs_ioctl_do_get_vinfo(struct the_nilfs *nilfs, __u64 *posp, int flags, 2317942b919SKoji Sato void *buf, size_t size, size_t nmembs) 2327942b919SKoji Sato { 2337942b919SKoji Sato int ret; 2347942b919SKoji Sato 23547420c79SRyusuke Konishi down_read(&nilfs->ns_segctor_sem); 236003ff182SRyusuke Konishi ret = nilfs_dat_get_vinfo(nilfs_dat_inode(nilfs), buf, size, nmembs); 23747420c79SRyusuke Konishi up_read(&nilfs->ns_segctor_sem); 2387942b919SKoji Sato return ret; 2397942b919SKoji Sato } 2407942b919SKoji Sato 2417942b919SKoji Sato static ssize_t 242b028fcfcSRyusuke Konishi nilfs_ioctl_do_get_bdescs(struct the_nilfs *nilfs, __u64 *posp, int flags, 2437942b919SKoji Sato void *buf, size_t size, size_t nmembs) 2447942b919SKoji Sato { 2457942b919SKoji Sato struct inode *dat = nilfs_dat_inode(nilfs); 2467942b919SKoji Sato struct nilfs_bmap *bmap = NILFS_I(dat)->i_bmap; 2477942b919SKoji Sato struct nilfs_bdesc *bdescs = buf; 2487942b919SKoji Sato int ret, i; 2497942b919SKoji Sato 25047eb6b9cSRyusuke Konishi down_read(&nilfs->ns_segctor_sem); 2517942b919SKoji Sato for (i = 0; i < nmembs; i++) { 2527942b919SKoji Sato ret = nilfs_bmap_lookup_at_level(bmap, 2537942b919SKoji Sato bdescs[i].bd_offset, 2547942b919SKoji Sato bdescs[i].bd_level + 1, 2557942b919SKoji Sato &bdescs[i].bd_blocknr); 2567942b919SKoji Sato if (ret < 0) { 25747eb6b9cSRyusuke Konishi if (ret != -ENOENT) { 25847eb6b9cSRyusuke Konishi up_read(&nilfs->ns_segctor_sem); 2597942b919SKoji Sato return ret; 26047eb6b9cSRyusuke Konishi } 2617942b919SKoji Sato bdescs[i].bd_blocknr = 0; 2627942b919SKoji Sato } 2637942b919SKoji Sato } 26447eb6b9cSRyusuke Konishi up_read(&nilfs->ns_segctor_sem); 2657942b919SKoji Sato return nmembs; 2667942b919SKoji Sato } 2677942b919SKoji Sato 2687942b919SKoji Sato static int nilfs_ioctl_get_bdescs(struct inode *inode, struct file *filp, 2697942b919SKoji Sato unsigned int cmd, void __user *argp) 2707942b919SKoji Sato { 2717942b919SKoji Sato struct the_nilfs *nilfs = NILFS_SB(inode->i_sb)->s_nilfs; 2727942b919SKoji Sato struct nilfs_argv argv; 2737942b919SKoji Sato int ret; 2747942b919SKoji Sato 2757942b919SKoji Sato if (copy_from_user(&argv, argp, sizeof(argv))) 2767942b919SKoji Sato return -EFAULT; 2777942b919SKoji Sato 27883aca8f4SRyusuke Konishi if (argv.v_size != sizeof(struct nilfs_bdesc)) 27983aca8f4SRyusuke Konishi return -EINVAL; 28083aca8f4SRyusuke Konishi 2817942b919SKoji Sato ret = nilfs_ioctl_wrap_copy(nilfs, &argv, _IOC_DIR(cmd), 2827942b919SKoji Sato nilfs_ioctl_do_get_bdescs); 28347420c79SRyusuke Konishi if (ret < 0) 28447420c79SRyusuke Konishi return ret; 2857942b919SKoji Sato 2867942b919SKoji Sato if (copy_to_user(argp, &argv, sizeof(argv))) 2877942b919SKoji Sato ret = -EFAULT; 2887942b919SKoji Sato return ret; 2897942b919SKoji Sato } 2907942b919SKoji Sato 2917942b919SKoji Sato static int nilfs_ioctl_move_inode_block(struct inode *inode, 2927942b919SKoji Sato struct nilfs_vdesc *vdesc, 2937942b919SKoji Sato struct list_head *buffers) 2947942b919SKoji Sato { 2957942b919SKoji Sato struct buffer_head *bh; 2967942b919SKoji Sato int ret; 2977942b919SKoji Sato 2987942b919SKoji Sato if (vdesc->vd_flags == 0) 2997942b919SKoji Sato ret = nilfs_gccache_submit_read_data( 3007942b919SKoji Sato inode, vdesc->vd_offset, vdesc->vd_blocknr, 3017942b919SKoji Sato vdesc->vd_vblocknr, &bh); 3027942b919SKoji Sato else 3037942b919SKoji Sato ret = nilfs_gccache_submit_read_node( 3047942b919SKoji Sato inode, vdesc->vd_blocknr, vdesc->vd_vblocknr, &bh); 3057942b919SKoji Sato 3067942b919SKoji Sato if (unlikely(ret < 0)) { 3077942b919SKoji Sato if (ret == -ENOENT) 3087942b919SKoji Sato printk(KERN_CRIT 3097942b919SKoji Sato "%s: invalid virtual block address (%s): " 3107942b919SKoji Sato "ino=%llu, cno=%llu, offset=%llu, " 3117942b919SKoji Sato "blocknr=%llu, vblocknr=%llu\n", 3127942b919SKoji Sato __func__, vdesc->vd_flags ? "node" : "data", 3137942b919SKoji Sato (unsigned long long)vdesc->vd_ino, 3147942b919SKoji Sato (unsigned long long)vdesc->vd_cno, 3157942b919SKoji Sato (unsigned long long)vdesc->vd_offset, 3167942b919SKoji Sato (unsigned long long)vdesc->vd_blocknr, 3177942b919SKoji Sato (unsigned long long)vdesc->vd_vblocknr); 3187942b919SKoji Sato return ret; 3197942b919SKoji Sato } 3205399dd1fSRyusuke Konishi if (unlikely(!list_empty(&bh->b_assoc_buffers))) { 3215399dd1fSRyusuke Konishi printk(KERN_CRIT "%s: conflicting %s buffer: ino=%llu, " 3225399dd1fSRyusuke Konishi "cno=%llu, offset=%llu, blocknr=%llu, vblocknr=%llu\n", 3235399dd1fSRyusuke Konishi __func__, vdesc->vd_flags ? "node" : "data", 3245399dd1fSRyusuke Konishi (unsigned long long)vdesc->vd_ino, 3255399dd1fSRyusuke Konishi (unsigned long long)vdesc->vd_cno, 3265399dd1fSRyusuke Konishi (unsigned long long)vdesc->vd_offset, 3275399dd1fSRyusuke Konishi (unsigned long long)vdesc->vd_blocknr, 3285399dd1fSRyusuke Konishi (unsigned long long)vdesc->vd_vblocknr); 3295399dd1fSRyusuke Konishi brelse(bh); 3305399dd1fSRyusuke Konishi return -EEXIST; 3315399dd1fSRyusuke Konishi } 3327942b919SKoji Sato list_add_tail(&bh->b_assoc_buffers, buffers); 3337942b919SKoji Sato return 0; 3347942b919SKoji Sato } 3357942b919SKoji Sato 336263d90ceSRyusuke Konishi static int nilfs_ioctl_move_blocks(struct super_block *sb, 3374f6b8288SRyusuke Konishi struct nilfs_argv *argv, void *buf) 3387942b919SKoji Sato { 3394f6b8288SRyusuke Konishi size_t nmembs = argv->v_nmembs; 340947b10aeSRyusuke Konishi struct the_nilfs *nilfs = NILFS_SB(sb)->s_nilfs; 3417942b919SKoji Sato struct inode *inode; 3427942b919SKoji Sato struct nilfs_vdesc *vdesc; 3437942b919SKoji Sato struct buffer_head *bh, *n; 3447942b919SKoji Sato LIST_HEAD(buffers); 3457942b919SKoji Sato ino_t ino; 3467942b919SKoji Sato __u64 cno; 3477942b919SKoji Sato int i, ret; 3487942b919SKoji Sato 3497942b919SKoji Sato for (i = 0, vdesc = buf; i < nmembs; ) { 3507942b919SKoji Sato ino = vdesc->vd_ino; 3517942b919SKoji Sato cno = vdesc->vd_cno; 352263d90ceSRyusuke Konishi inode = nilfs_iget_for_gc(sb, ino, cno); 353103cfcf5SDan Carpenter if (IS_ERR(inode)) { 354103cfcf5SDan Carpenter ret = PTR_ERR(inode); 3557942b919SKoji Sato goto failed; 3567942b919SKoji Sato } 357947b10aeSRyusuke Konishi if (list_empty(&NILFS_I(inode)->i_dirty)) { 358947b10aeSRyusuke Konishi /* 359947b10aeSRyusuke Konishi * Add the inode to GC inode list. Garbage Collection 360947b10aeSRyusuke Konishi * is serialized and no two processes manipulate the 361947b10aeSRyusuke Konishi * list simultaneously. 362947b10aeSRyusuke Konishi */ 363947b10aeSRyusuke Konishi igrab(inode); 364947b10aeSRyusuke Konishi list_add(&NILFS_I(inode)->i_dirty, 365947b10aeSRyusuke Konishi &nilfs->ns_gc_inodes); 366947b10aeSRyusuke Konishi } 367947b10aeSRyusuke Konishi 3687942b919SKoji Sato do { 3697942b919SKoji Sato ret = nilfs_ioctl_move_inode_block(inode, vdesc, 3707942b919SKoji Sato &buffers); 371263d90ceSRyusuke Konishi if (unlikely(ret < 0)) { 372263d90ceSRyusuke Konishi iput(inode); 3737942b919SKoji Sato goto failed; 374263d90ceSRyusuke Konishi } 3757942b919SKoji Sato vdesc++; 3767942b919SKoji Sato } while (++i < nmembs && 3777942b919SKoji Sato vdesc->vd_ino == ino && vdesc->vd_cno == cno); 378263d90ceSRyusuke Konishi 379263d90ceSRyusuke Konishi iput(inode); /* The inode still remains in GC inode list */ 3807942b919SKoji Sato } 3817942b919SKoji Sato 3827942b919SKoji Sato list_for_each_entry_safe(bh, n, &buffers, b_assoc_buffers) { 3837942b919SKoji Sato ret = nilfs_gccache_wait_and_mark_dirty(bh); 3847942b919SKoji Sato if (unlikely(ret < 0)) { 3855399dd1fSRyusuke Konishi WARN_ON(ret == -EEXIST); 3867942b919SKoji Sato goto failed; 3877942b919SKoji Sato } 3887942b919SKoji Sato list_del_init(&bh->b_assoc_buffers); 3897942b919SKoji Sato brelse(bh); 3907942b919SKoji Sato } 3917942b919SKoji Sato return nmembs; 3927942b919SKoji Sato 3937942b919SKoji Sato failed: 3947942b919SKoji Sato list_for_each_entry_safe(bh, n, &buffers, b_assoc_buffers) { 3957942b919SKoji Sato list_del_init(&bh->b_assoc_buffers); 3967942b919SKoji Sato brelse(bh); 3977942b919SKoji Sato } 3987942b919SKoji Sato return ret; 3997942b919SKoji Sato } 4007942b919SKoji Sato 4014f6b8288SRyusuke Konishi static int nilfs_ioctl_delete_checkpoints(struct the_nilfs *nilfs, 4024f6b8288SRyusuke Konishi struct nilfs_argv *argv, void *buf) 4037942b919SKoji Sato { 4044f6b8288SRyusuke Konishi size_t nmembs = argv->v_nmembs; 4057942b919SKoji Sato struct inode *cpfile = nilfs->ns_cpfile; 4067942b919SKoji Sato struct nilfs_period *periods = buf; 4077942b919SKoji Sato int ret, i; 4087942b919SKoji Sato 4097942b919SKoji Sato for (i = 0; i < nmembs; i++) { 4107942b919SKoji Sato ret = nilfs_cpfile_delete_checkpoints( 4117942b919SKoji Sato cpfile, periods[i].p_start, periods[i].p_end); 4127942b919SKoji Sato if (ret < 0) 4137942b919SKoji Sato return ret; 4147942b919SKoji Sato } 4157942b919SKoji Sato return nmembs; 4167942b919SKoji Sato } 4177942b919SKoji Sato 4184f6b8288SRyusuke Konishi static int nilfs_ioctl_free_vblocknrs(struct the_nilfs *nilfs, 4194f6b8288SRyusuke Konishi struct nilfs_argv *argv, void *buf) 4207942b919SKoji Sato { 4214f6b8288SRyusuke Konishi size_t nmembs = argv->v_nmembs; 4224f6b8288SRyusuke Konishi int ret; 4237942b919SKoji Sato 4244f6b8288SRyusuke Konishi ret = nilfs_dat_freev(nilfs_dat_inode(nilfs), buf, nmembs); 4257942b919SKoji Sato 4267942b919SKoji Sato return (ret < 0) ? ret : nmembs; 4277942b919SKoji Sato } 4287942b919SKoji Sato 4294f6b8288SRyusuke Konishi static int nilfs_ioctl_mark_blocks_dirty(struct the_nilfs *nilfs, 4304f6b8288SRyusuke Konishi struct nilfs_argv *argv, void *buf) 4317942b919SKoji Sato { 4324f6b8288SRyusuke Konishi size_t nmembs = argv->v_nmembs; 4337942b919SKoji Sato struct inode *dat = nilfs_dat_inode(nilfs); 4347942b919SKoji Sato struct nilfs_bmap *bmap = NILFS_I(dat)->i_bmap; 4357942b919SKoji Sato struct nilfs_bdesc *bdescs = buf; 4367942b919SKoji Sato int ret, i; 4377942b919SKoji Sato 4387942b919SKoji Sato for (i = 0; i < nmembs; i++) { 4397942b919SKoji Sato /* XXX: use macro or inline func to check liveness */ 4407942b919SKoji Sato ret = nilfs_bmap_lookup_at_level(bmap, 4417942b919SKoji Sato bdescs[i].bd_offset, 4427942b919SKoji Sato bdescs[i].bd_level + 1, 4437942b919SKoji Sato &bdescs[i].bd_blocknr); 4447942b919SKoji Sato if (ret < 0) { 4457942b919SKoji Sato if (ret != -ENOENT) 4467942b919SKoji Sato return ret; 4477942b919SKoji Sato bdescs[i].bd_blocknr = 0; 4487942b919SKoji Sato } 4497942b919SKoji Sato if (bdescs[i].bd_blocknr != bdescs[i].bd_oblocknr) 4507942b919SKoji Sato /* skip dead block */ 4517942b919SKoji Sato continue; 4527942b919SKoji Sato if (bdescs[i].bd_level == 0) { 4537942b919SKoji Sato ret = nilfs_mdt_mark_block_dirty(dat, 4547942b919SKoji Sato bdescs[i].bd_offset); 4557942b919SKoji Sato if (ret < 0) { 4561f5abe7eSRyusuke Konishi WARN_ON(ret == -ENOENT); 4577942b919SKoji Sato return ret; 4587942b919SKoji Sato } 4597942b919SKoji Sato } else { 4607942b919SKoji Sato ret = nilfs_bmap_mark(bmap, bdescs[i].bd_offset, 4617942b919SKoji Sato bdescs[i].bd_level); 4627942b919SKoji Sato if (ret < 0) { 4631f5abe7eSRyusuke Konishi WARN_ON(ret == -ENOENT); 4647942b919SKoji Sato return ret; 4657942b919SKoji Sato } 4667942b919SKoji Sato } 4677942b919SKoji Sato } 4687942b919SKoji Sato return nmembs; 4697942b919SKoji Sato } 4707942b919SKoji Sato 4717942b919SKoji Sato int nilfs_ioctl_prepare_clean_segments(struct the_nilfs *nilfs, 4724f6b8288SRyusuke Konishi struct nilfs_argv *argv, void **kbufs) 4737942b919SKoji Sato { 4741f5abe7eSRyusuke Konishi const char *msg; 4754f6b8288SRyusuke Konishi int ret; 4767942b919SKoji Sato 4774f6b8288SRyusuke Konishi ret = nilfs_ioctl_delete_checkpoints(nilfs, &argv[1], kbufs[1]); 4781f5abe7eSRyusuke Konishi if (ret < 0) { 4791f5abe7eSRyusuke Konishi /* 4801f5abe7eSRyusuke Konishi * can safely abort because checkpoints can be removed 4811f5abe7eSRyusuke Konishi * independently. 4821f5abe7eSRyusuke Konishi */ 4831f5abe7eSRyusuke Konishi msg = "cannot delete checkpoints"; 4841f5abe7eSRyusuke Konishi goto failed; 4851f5abe7eSRyusuke Konishi } 4864f6b8288SRyusuke Konishi ret = nilfs_ioctl_free_vblocknrs(nilfs, &argv[2], kbufs[2]); 4871f5abe7eSRyusuke Konishi if (ret < 0) { 4881f5abe7eSRyusuke Konishi /* 4891f5abe7eSRyusuke Konishi * can safely abort because DAT file is updated atomically 4901f5abe7eSRyusuke Konishi * using a copy-on-write technique. 4911f5abe7eSRyusuke Konishi */ 4921f5abe7eSRyusuke Konishi msg = "cannot delete virtual blocks from DAT file"; 4931f5abe7eSRyusuke Konishi goto failed; 4941f5abe7eSRyusuke Konishi } 4954f6b8288SRyusuke Konishi ret = nilfs_ioctl_mark_blocks_dirty(nilfs, &argv[3], kbufs[3]); 4961f5abe7eSRyusuke Konishi if (ret < 0) { 4971f5abe7eSRyusuke Konishi /* 4981f5abe7eSRyusuke Konishi * can safely abort because the operation is nondestructive. 4991f5abe7eSRyusuke Konishi */ 5001f5abe7eSRyusuke Konishi msg = "cannot mark copying blocks dirty"; 5011f5abe7eSRyusuke Konishi goto failed; 5021f5abe7eSRyusuke Konishi } 5037942b919SKoji Sato return 0; 5047942b919SKoji Sato 5051f5abe7eSRyusuke Konishi failed: 5061f5abe7eSRyusuke Konishi printk(KERN_ERR "NILFS: GC failed during preparation: %s: err=%d\n", 5071f5abe7eSRyusuke Konishi msg, ret); 5087942b919SKoji Sato return ret; 5097942b919SKoji Sato } 5107942b919SKoji Sato 5117942b919SKoji Sato static int nilfs_ioctl_clean_segments(struct inode *inode, struct file *filp, 5127942b919SKoji Sato unsigned int cmd, void __user *argp) 5137942b919SKoji Sato { 5144f6b8288SRyusuke Konishi struct nilfs_argv argv[5]; 51533e189bdSTobias Klauser static const size_t argsz[5] = { 5164f6b8288SRyusuke Konishi sizeof(struct nilfs_vdesc), 5174f6b8288SRyusuke Konishi sizeof(struct nilfs_period), 5184f6b8288SRyusuke Konishi sizeof(__u64), 5194f6b8288SRyusuke Konishi sizeof(struct nilfs_bdesc), 5204f6b8288SRyusuke Konishi sizeof(__u64), 5214f6b8288SRyusuke Konishi }; 5224f6b8288SRyusuke Konishi void __user *base; 5234f6b8288SRyusuke Konishi void *kbufs[5]; 5244f6b8288SRyusuke Konishi struct the_nilfs *nilfs; 5254f6b8288SRyusuke Konishi size_t len, nsegs; 5264f6b8288SRyusuke Konishi int n, ret; 5274f6b8288SRyusuke Konishi 5287942b919SKoji Sato if (!capable(CAP_SYS_ADMIN)) 5297942b919SKoji Sato return -EPERM; 5304f6b8288SRyusuke Konishi 5317512487eSRyusuke Konishi ret = mnt_want_write(filp->f_path.mnt); 5327512487eSRyusuke Konishi if (ret) 5337512487eSRyusuke Konishi return ret; 5344f6b8288SRyusuke Konishi 5357512487eSRyusuke Konishi ret = -EFAULT; 5367512487eSRyusuke Konishi if (copy_from_user(argv, argp, sizeof(argv))) 5377512487eSRyusuke Konishi goto out; 5387512487eSRyusuke Konishi 5397512487eSRyusuke Konishi ret = -EINVAL; 5404f6b8288SRyusuke Konishi nsegs = argv[4].v_nmembs; 5414f6b8288SRyusuke Konishi if (argv[4].v_size != argsz[4]) 5427512487eSRyusuke Konishi goto out; 5437512487eSRyusuke Konishi 5444f6b8288SRyusuke Konishi /* 5454f6b8288SRyusuke Konishi * argv[4] points to segment numbers this ioctl cleans. We 5464f6b8288SRyusuke Konishi * use kmalloc() for its buffer because memory used for the 5474f6b8288SRyusuke Konishi * segment numbers is enough small. 5484f6b8288SRyusuke Konishi */ 5494f6b8288SRyusuke Konishi kbufs[4] = memdup_user((void __user *)(unsigned long)argv[4].v_base, 5504f6b8288SRyusuke Konishi nsegs * sizeof(__u64)); 5517512487eSRyusuke Konishi if (IS_ERR(kbufs[4])) { 5527512487eSRyusuke Konishi ret = PTR_ERR(kbufs[4]); 5537512487eSRyusuke Konishi goto out; 5547512487eSRyusuke Konishi } 5554f6b8288SRyusuke Konishi nilfs = NILFS_SB(inode->i_sb)->s_nilfs; 5564f6b8288SRyusuke Konishi 5574f6b8288SRyusuke Konishi for (n = 0; n < 4; n++) { 5584f6b8288SRyusuke Konishi ret = -EINVAL; 5594f6b8288SRyusuke Konishi if (argv[n].v_size != argsz[n]) 5604f6b8288SRyusuke Konishi goto out_free; 5614f6b8288SRyusuke Konishi 5624f6b8288SRyusuke Konishi if (argv[n].v_nmembs > nsegs * nilfs->ns_blocks_per_segment) 5634f6b8288SRyusuke Konishi goto out_free; 5644f6b8288SRyusuke Konishi 5654f6b8288SRyusuke Konishi len = argv[n].v_size * argv[n].v_nmembs; 5664f6b8288SRyusuke Konishi base = (void __user *)(unsigned long)argv[n].v_base; 5674f6b8288SRyusuke Konishi if (len == 0) { 5684f6b8288SRyusuke Konishi kbufs[n] = NULL; 5694f6b8288SRyusuke Konishi continue; 5704f6b8288SRyusuke Konishi } 5714f6b8288SRyusuke Konishi 5724f6b8288SRyusuke Konishi kbufs[n] = vmalloc(len); 5734f6b8288SRyusuke Konishi if (!kbufs[n]) { 5744f6b8288SRyusuke Konishi ret = -ENOMEM; 5754f6b8288SRyusuke Konishi goto out_free; 5764f6b8288SRyusuke Konishi } 5774f6b8288SRyusuke Konishi if (copy_from_user(kbufs[n], base, len)) { 5784f6b8288SRyusuke Konishi ret = -EFAULT; 5794f6b8288SRyusuke Konishi vfree(kbufs[n]); 5804f6b8288SRyusuke Konishi goto out_free; 5814f6b8288SRyusuke Konishi } 5824f6b8288SRyusuke Konishi } 5834f6b8288SRyusuke Konishi 5841cf58fa8SJiro SEKIBA /* 585263d90ceSRyusuke Konishi * nilfs_ioctl_move_blocks() will call nilfs_iget_for_gc(), 5861cf58fa8SJiro SEKIBA * which will operates an inode list without blocking. 5871cf58fa8SJiro SEKIBA * To protect the list from concurrent operations, 5881cf58fa8SJiro SEKIBA * nilfs_ioctl_move_blocks should be atomic operation. 5891cf58fa8SJiro SEKIBA */ 5901cf58fa8SJiro SEKIBA if (test_and_set_bit(THE_NILFS_GC_RUNNING, &nilfs->ns_flags)) { 5911cf58fa8SJiro SEKIBA ret = -EBUSY; 5921cf58fa8SJiro SEKIBA goto out_free; 5931cf58fa8SJiro SEKIBA } 5941cf58fa8SJiro SEKIBA 5955beb6e0bSRyusuke Konishi vfs_check_frozen(inode->i_sb, SB_FREEZE_WRITE); 5965beb6e0bSRyusuke Konishi 597263d90ceSRyusuke Konishi ret = nilfs_ioctl_move_blocks(inode->i_sb, &argv[0], kbufs[0]); 5981cf58fa8SJiro SEKIBA if (ret < 0) 5991cf58fa8SJiro SEKIBA printk(KERN_ERR "NILFS: GC failed during preparation: " 6001cf58fa8SJiro SEKIBA "cannot read source blocks: err=%d\n", ret); 6011cf58fa8SJiro SEKIBA else 6024f6b8288SRyusuke Konishi ret = nilfs_clean_segments(inode->i_sb, argv, kbufs); 6034f6b8288SRyusuke Konishi 604263d90ceSRyusuke Konishi nilfs_remove_all_gcinodes(nilfs); 6051cf58fa8SJiro SEKIBA clear_nilfs_gc_running(nilfs); 6061cf58fa8SJiro SEKIBA 6074f6b8288SRyusuke Konishi out_free: 608d5046853SRyusuke Konishi while (--n >= 0) 6094f6b8288SRyusuke Konishi vfree(kbufs[n]); 6104f6b8288SRyusuke Konishi kfree(kbufs[4]); 6117512487eSRyusuke Konishi out: 6127512487eSRyusuke Konishi mnt_drop_write(filp->f_path.mnt); 6134f6b8288SRyusuke Konishi return ret; 6147942b919SKoji Sato } 6157942b919SKoji Sato 6167942b919SKoji Sato static int nilfs_ioctl_sync(struct inode *inode, struct file *filp, 6177942b919SKoji Sato unsigned int cmd, void __user *argp) 6187942b919SKoji Sato { 6197942b919SKoji Sato __u64 cno; 6207942b919SKoji Sato int ret; 6210d561f12SJiro SEKIBA struct the_nilfs *nilfs; 6227942b919SKoji Sato 6237942b919SKoji Sato ret = nilfs_construct_segment(inode->i_sb); 6247942b919SKoji Sato if (ret < 0) 6257942b919SKoji Sato return ret; 6267942b919SKoji Sato 6277942b919SKoji Sato if (argp != NULL) { 6280d561f12SJiro SEKIBA nilfs = NILFS_SB(inode->i_sb)->s_nilfs; 6290d561f12SJiro SEKIBA down_read(&nilfs->ns_segctor_sem); 6300d561f12SJiro SEKIBA cno = nilfs->ns_cno - 1; 6310d561f12SJiro SEKIBA up_read(&nilfs->ns_segctor_sem); 6327942b919SKoji Sato if (copy_to_user(argp, &cno, sizeof(cno))) 6337942b919SKoji Sato return -EFAULT; 6347942b919SKoji Sato } 6357942b919SKoji Sato return 0; 6367942b919SKoji Sato } 6377942b919SKoji Sato 63847eb6b9cSRyusuke Konishi static int nilfs_ioctl_get_info(struct inode *inode, struct file *filp, 63947eb6b9cSRyusuke Konishi unsigned int cmd, void __user *argp, 64083aca8f4SRyusuke Konishi size_t membsz, 64147eb6b9cSRyusuke Konishi ssize_t (*dofunc)(struct the_nilfs *, 64247eb6b9cSRyusuke Konishi __u64 *, int, 64347eb6b9cSRyusuke Konishi void *, size_t, size_t)) 64447eb6b9cSRyusuke Konishi 64547eb6b9cSRyusuke Konishi { 64647eb6b9cSRyusuke Konishi struct the_nilfs *nilfs = NILFS_SB(inode->i_sb)->s_nilfs; 64747eb6b9cSRyusuke Konishi struct nilfs_argv argv; 64847eb6b9cSRyusuke Konishi int ret; 64947eb6b9cSRyusuke Konishi 65047eb6b9cSRyusuke Konishi if (copy_from_user(&argv, argp, sizeof(argv))) 65147eb6b9cSRyusuke Konishi return -EFAULT; 65247eb6b9cSRyusuke Konishi 653003ff182SRyusuke Konishi if (argv.v_size < membsz) 65483aca8f4SRyusuke Konishi return -EINVAL; 65583aca8f4SRyusuke Konishi 65647eb6b9cSRyusuke Konishi ret = nilfs_ioctl_wrap_copy(nilfs, &argv, _IOC_DIR(cmd), dofunc); 65747eb6b9cSRyusuke Konishi if (ret < 0) 65847eb6b9cSRyusuke Konishi return ret; 65947eb6b9cSRyusuke Konishi 66047eb6b9cSRyusuke Konishi if (copy_to_user(argp, &argv, sizeof(argv))) 66147eb6b9cSRyusuke Konishi ret = -EFAULT; 66247eb6b9cSRyusuke Konishi return ret; 66347eb6b9cSRyusuke Konishi } 66447eb6b9cSRyusuke Konishi 6657a946193SRyusuke Konishi long nilfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) 6667942b919SKoji Sato { 6677a946193SRyusuke Konishi struct inode *inode = filp->f_dentry->d_inode; 66875323400SLi Hong void __user *argp = (void __user *)arg; 6697942b919SKoji Sato 6707942b919SKoji Sato switch (cmd) { 6717942b919SKoji Sato case NILFS_IOCTL_CHANGE_CPMODE: 6727942b919SKoji Sato return nilfs_ioctl_change_cpmode(inode, filp, cmd, argp); 6737942b919SKoji Sato case NILFS_IOCTL_DELETE_CHECKPOINT: 6747942b919SKoji Sato return nilfs_ioctl_delete_checkpoint(inode, filp, cmd, argp); 6757942b919SKoji Sato case NILFS_IOCTL_GET_CPINFO: 67647eb6b9cSRyusuke Konishi return nilfs_ioctl_get_info(inode, filp, cmd, argp, 67783aca8f4SRyusuke Konishi sizeof(struct nilfs_cpinfo), 67847eb6b9cSRyusuke Konishi nilfs_ioctl_do_get_cpinfo); 6797942b919SKoji Sato case NILFS_IOCTL_GET_CPSTAT: 6807942b919SKoji Sato return nilfs_ioctl_get_cpstat(inode, filp, cmd, argp); 6817942b919SKoji Sato case NILFS_IOCTL_GET_SUINFO: 68247eb6b9cSRyusuke Konishi return nilfs_ioctl_get_info(inode, filp, cmd, argp, 68383aca8f4SRyusuke Konishi sizeof(struct nilfs_suinfo), 68447eb6b9cSRyusuke Konishi nilfs_ioctl_do_get_suinfo); 6857942b919SKoji Sato case NILFS_IOCTL_GET_SUSTAT: 6867942b919SKoji Sato return nilfs_ioctl_get_sustat(inode, filp, cmd, argp); 6877942b919SKoji Sato case NILFS_IOCTL_GET_VINFO: 68847eb6b9cSRyusuke Konishi return nilfs_ioctl_get_info(inode, filp, cmd, argp, 68983aca8f4SRyusuke Konishi sizeof(struct nilfs_vinfo), 69047eb6b9cSRyusuke Konishi nilfs_ioctl_do_get_vinfo); 6917942b919SKoji Sato case NILFS_IOCTL_GET_BDESCS: 6927942b919SKoji Sato return nilfs_ioctl_get_bdescs(inode, filp, cmd, argp); 6937942b919SKoji Sato case NILFS_IOCTL_CLEAN_SEGMENTS: 6947942b919SKoji Sato return nilfs_ioctl_clean_segments(inode, filp, cmd, argp); 6957942b919SKoji Sato case NILFS_IOCTL_SYNC: 6967942b919SKoji Sato return nilfs_ioctl_sync(inode, filp, cmd, argp); 6977942b919SKoji Sato default: 6987942b919SKoji Sato return -ENOTTY; 6997942b919SKoji Sato } 7007942b919SKoji Sato } 701