1 /* 2 * ioctl.c - NILFS ioctl operations. 3 * 4 * Copyright (C) 2007, 2008 Nippon Telegraph and Telephone Corporation. 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 19 * 20 * Written by Koji Sato <koji@osrg.net>. 21 */ 22 23 #include <linux/fs.h> 24 #include <linux/wait.h> 25 #include <linux/slab.h> 26 #include <linux/capability.h> /* capable() */ 27 #include <linux/uaccess.h> /* copy_from_user(), copy_to_user() */ 28 #include <linux/vmalloc.h> 29 #include <linux/mount.h> /* mnt_want_write(), mnt_drop_write() */ 30 #include <linux/nilfs2_fs.h> 31 #include "nilfs.h" 32 #include "segment.h" 33 #include "bmap.h" 34 #include "cpfile.h" 35 #include "sufile.h" 36 #include "dat.h" 37 38 39 static int nilfs_ioctl_wrap_copy(struct the_nilfs *nilfs, 40 struct nilfs_argv *argv, int dir, 41 ssize_t (*dofunc)(struct the_nilfs *, 42 __u64 *, int, 43 void *, size_t, size_t)) 44 { 45 void *buf; 46 void __user *base = (void __user *)(unsigned long)argv->v_base; 47 size_t maxmembs, total, n; 48 ssize_t nr; 49 int ret, i; 50 __u64 pos, ppos; 51 52 if (argv->v_nmembs == 0) 53 return 0; 54 55 if (argv->v_size > PAGE_SIZE) 56 return -EINVAL; 57 58 buf = (void *)__get_free_pages(GFP_NOFS, 0); 59 if (unlikely(!buf)) 60 return -ENOMEM; 61 maxmembs = PAGE_SIZE / argv->v_size; 62 63 ret = 0; 64 total = 0; 65 pos = argv->v_index; 66 for (i = 0; i < argv->v_nmembs; i += n) { 67 n = (argv->v_nmembs - i < maxmembs) ? 68 argv->v_nmembs - i : maxmembs; 69 if ((dir & _IOC_WRITE) && 70 copy_from_user(buf, base + argv->v_size * i, 71 argv->v_size * n)) { 72 ret = -EFAULT; 73 break; 74 } 75 ppos = pos; 76 nr = dofunc(nilfs, &pos, argv->v_flags, buf, argv->v_size, 77 n); 78 if (nr < 0) { 79 ret = nr; 80 break; 81 } 82 if ((dir & _IOC_READ) && 83 copy_to_user(base + argv->v_size * i, buf, 84 argv->v_size * nr)) { 85 ret = -EFAULT; 86 break; 87 } 88 total += nr; 89 if ((size_t)nr < n) 90 break; 91 if (pos == ppos) 92 pos += n; 93 } 94 argv->v_nmembs = total; 95 96 free_pages((unsigned long)buf, 0); 97 return ret; 98 } 99 100 static int nilfs_ioctl_change_cpmode(struct inode *inode, struct file *filp, 101 unsigned int cmd, void __user *argp) 102 { 103 struct the_nilfs *nilfs = NILFS_SB(inode->i_sb)->s_nilfs; 104 struct inode *cpfile = nilfs->ns_cpfile; 105 struct nilfs_transaction_info ti; 106 struct nilfs_cpmode cpmode; 107 int ret; 108 109 if (!capable(CAP_SYS_ADMIN)) 110 return -EPERM; 111 112 ret = mnt_want_write(filp->f_path.mnt); 113 if (ret) 114 return ret; 115 116 ret = -EFAULT; 117 if (copy_from_user(&cpmode, argp, sizeof(cpmode))) 118 goto out; 119 120 down_read(&inode->i_sb->s_umount); 121 122 nilfs_transaction_begin(inode->i_sb, &ti, 0); 123 ret = nilfs_cpfile_change_cpmode( 124 cpfile, cpmode.cm_cno, cpmode.cm_mode); 125 if (unlikely(ret < 0)) 126 nilfs_transaction_abort(inode->i_sb); 127 else 128 nilfs_transaction_commit(inode->i_sb); /* never fails */ 129 130 up_read(&inode->i_sb->s_umount); 131 out: 132 mnt_drop_write(filp->f_path.mnt); 133 return ret; 134 } 135 136 static int 137 nilfs_ioctl_delete_checkpoint(struct inode *inode, struct file *filp, 138 unsigned int cmd, void __user *argp) 139 { 140 struct inode *cpfile = NILFS_SB(inode->i_sb)->s_nilfs->ns_cpfile; 141 struct nilfs_transaction_info ti; 142 __u64 cno; 143 int ret; 144 145 if (!capable(CAP_SYS_ADMIN)) 146 return -EPERM; 147 148 ret = mnt_want_write(filp->f_path.mnt); 149 if (ret) 150 return ret; 151 152 ret = -EFAULT; 153 if (copy_from_user(&cno, argp, sizeof(cno))) 154 goto out; 155 156 nilfs_transaction_begin(inode->i_sb, &ti, 0); 157 ret = nilfs_cpfile_delete_checkpoint(cpfile, cno); 158 if (unlikely(ret < 0)) 159 nilfs_transaction_abort(inode->i_sb); 160 else 161 nilfs_transaction_commit(inode->i_sb); /* never fails */ 162 out: 163 mnt_drop_write(filp->f_path.mnt); 164 return ret; 165 } 166 167 static ssize_t 168 nilfs_ioctl_do_get_cpinfo(struct the_nilfs *nilfs, __u64 *posp, int flags, 169 void *buf, size_t size, size_t nmembs) 170 { 171 int ret; 172 173 down_read(&nilfs->ns_segctor_sem); 174 ret = nilfs_cpfile_get_cpinfo(nilfs->ns_cpfile, posp, flags, buf, 175 size, nmembs); 176 up_read(&nilfs->ns_segctor_sem); 177 return ret; 178 } 179 180 static int nilfs_ioctl_get_cpstat(struct inode *inode, struct file *filp, 181 unsigned int cmd, void __user *argp) 182 { 183 struct the_nilfs *nilfs = NILFS_SB(inode->i_sb)->s_nilfs; 184 struct nilfs_cpstat cpstat; 185 int ret; 186 187 down_read(&nilfs->ns_segctor_sem); 188 ret = nilfs_cpfile_get_stat(nilfs->ns_cpfile, &cpstat); 189 up_read(&nilfs->ns_segctor_sem); 190 if (ret < 0) 191 return ret; 192 193 if (copy_to_user(argp, &cpstat, sizeof(cpstat))) 194 ret = -EFAULT; 195 return ret; 196 } 197 198 static ssize_t 199 nilfs_ioctl_do_get_suinfo(struct the_nilfs *nilfs, __u64 *posp, int flags, 200 void *buf, size_t size, size_t nmembs) 201 { 202 int ret; 203 204 down_read(&nilfs->ns_segctor_sem); 205 ret = nilfs_sufile_get_suinfo(nilfs->ns_sufile, *posp, buf, size, 206 nmembs); 207 up_read(&nilfs->ns_segctor_sem); 208 return ret; 209 } 210 211 static int nilfs_ioctl_get_sustat(struct inode *inode, struct file *filp, 212 unsigned int cmd, void __user *argp) 213 { 214 struct the_nilfs *nilfs = NILFS_SB(inode->i_sb)->s_nilfs; 215 struct nilfs_sustat sustat; 216 int ret; 217 218 down_read(&nilfs->ns_segctor_sem); 219 ret = nilfs_sufile_get_stat(nilfs->ns_sufile, &sustat); 220 up_read(&nilfs->ns_segctor_sem); 221 if (ret < 0) 222 return ret; 223 224 if (copy_to_user(argp, &sustat, sizeof(sustat))) 225 ret = -EFAULT; 226 return ret; 227 } 228 229 static ssize_t 230 nilfs_ioctl_do_get_vinfo(struct the_nilfs *nilfs, __u64 *posp, int flags, 231 void *buf, size_t size, size_t nmembs) 232 { 233 int ret; 234 235 down_read(&nilfs->ns_segctor_sem); 236 ret = nilfs_dat_get_vinfo(nilfs->ns_dat, buf, size, nmembs); 237 up_read(&nilfs->ns_segctor_sem); 238 return ret; 239 } 240 241 static ssize_t 242 nilfs_ioctl_do_get_bdescs(struct the_nilfs *nilfs, __u64 *posp, int flags, 243 void *buf, size_t size, size_t nmembs) 244 { 245 struct nilfs_bmap *bmap = NILFS_I(nilfs->ns_dat)->i_bmap; 246 struct nilfs_bdesc *bdescs = buf; 247 int ret, i; 248 249 down_read(&nilfs->ns_segctor_sem); 250 for (i = 0; i < nmembs; i++) { 251 ret = nilfs_bmap_lookup_at_level(bmap, 252 bdescs[i].bd_offset, 253 bdescs[i].bd_level + 1, 254 &bdescs[i].bd_blocknr); 255 if (ret < 0) { 256 if (ret != -ENOENT) { 257 up_read(&nilfs->ns_segctor_sem); 258 return ret; 259 } 260 bdescs[i].bd_blocknr = 0; 261 } 262 } 263 up_read(&nilfs->ns_segctor_sem); 264 return nmembs; 265 } 266 267 static int nilfs_ioctl_get_bdescs(struct inode *inode, struct file *filp, 268 unsigned int cmd, void __user *argp) 269 { 270 struct the_nilfs *nilfs = NILFS_SB(inode->i_sb)->s_nilfs; 271 struct nilfs_argv argv; 272 int ret; 273 274 if (copy_from_user(&argv, argp, sizeof(argv))) 275 return -EFAULT; 276 277 if (argv.v_size != sizeof(struct nilfs_bdesc)) 278 return -EINVAL; 279 280 ret = nilfs_ioctl_wrap_copy(nilfs, &argv, _IOC_DIR(cmd), 281 nilfs_ioctl_do_get_bdescs); 282 if (ret < 0) 283 return ret; 284 285 if (copy_to_user(argp, &argv, sizeof(argv))) 286 ret = -EFAULT; 287 return ret; 288 } 289 290 static int nilfs_ioctl_move_inode_block(struct inode *inode, 291 struct nilfs_vdesc *vdesc, 292 struct list_head *buffers) 293 { 294 struct buffer_head *bh; 295 int ret; 296 297 if (vdesc->vd_flags == 0) 298 ret = nilfs_gccache_submit_read_data( 299 inode, vdesc->vd_offset, vdesc->vd_blocknr, 300 vdesc->vd_vblocknr, &bh); 301 else 302 ret = nilfs_gccache_submit_read_node( 303 inode, vdesc->vd_blocknr, vdesc->vd_vblocknr, &bh); 304 305 if (unlikely(ret < 0)) { 306 if (ret == -ENOENT) 307 printk(KERN_CRIT 308 "%s: invalid virtual block address (%s): " 309 "ino=%llu, cno=%llu, offset=%llu, " 310 "blocknr=%llu, vblocknr=%llu\n", 311 __func__, vdesc->vd_flags ? "node" : "data", 312 (unsigned long long)vdesc->vd_ino, 313 (unsigned long long)vdesc->vd_cno, 314 (unsigned long long)vdesc->vd_offset, 315 (unsigned long long)vdesc->vd_blocknr, 316 (unsigned long long)vdesc->vd_vblocknr); 317 return ret; 318 } 319 if (unlikely(!list_empty(&bh->b_assoc_buffers))) { 320 printk(KERN_CRIT "%s: conflicting %s buffer: ino=%llu, " 321 "cno=%llu, offset=%llu, blocknr=%llu, vblocknr=%llu\n", 322 __func__, vdesc->vd_flags ? "node" : "data", 323 (unsigned long long)vdesc->vd_ino, 324 (unsigned long long)vdesc->vd_cno, 325 (unsigned long long)vdesc->vd_offset, 326 (unsigned long long)vdesc->vd_blocknr, 327 (unsigned long long)vdesc->vd_vblocknr); 328 brelse(bh); 329 return -EEXIST; 330 } 331 list_add_tail(&bh->b_assoc_buffers, buffers); 332 return 0; 333 } 334 335 static int nilfs_ioctl_move_blocks(struct super_block *sb, 336 struct nilfs_argv *argv, void *buf) 337 { 338 size_t nmembs = argv->v_nmembs; 339 struct the_nilfs *nilfs = NILFS_SB(sb)->s_nilfs; 340 struct inode *inode; 341 struct nilfs_vdesc *vdesc; 342 struct buffer_head *bh, *n; 343 LIST_HEAD(buffers); 344 ino_t ino; 345 __u64 cno; 346 int i, ret; 347 348 for (i = 0, vdesc = buf; i < nmembs; ) { 349 ino = vdesc->vd_ino; 350 cno = vdesc->vd_cno; 351 inode = nilfs_iget_for_gc(sb, ino, cno); 352 if (IS_ERR(inode)) { 353 ret = PTR_ERR(inode); 354 goto failed; 355 } 356 if (list_empty(&NILFS_I(inode)->i_dirty)) { 357 /* 358 * Add the inode to GC inode list. Garbage Collection 359 * is serialized and no two processes manipulate the 360 * list simultaneously. 361 */ 362 igrab(inode); 363 list_add(&NILFS_I(inode)->i_dirty, 364 &nilfs->ns_gc_inodes); 365 } 366 367 do { 368 ret = nilfs_ioctl_move_inode_block(inode, vdesc, 369 &buffers); 370 if (unlikely(ret < 0)) { 371 iput(inode); 372 goto failed; 373 } 374 vdesc++; 375 } while (++i < nmembs && 376 vdesc->vd_ino == ino && vdesc->vd_cno == cno); 377 378 iput(inode); /* The inode still remains in GC inode list */ 379 } 380 381 list_for_each_entry_safe(bh, n, &buffers, b_assoc_buffers) { 382 ret = nilfs_gccache_wait_and_mark_dirty(bh); 383 if (unlikely(ret < 0)) { 384 WARN_ON(ret == -EEXIST); 385 goto failed; 386 } 387 list_del_init(&bh->b_assoc_buffers); 388 brelse(bh); 389 } 390 return nmembs; 391 392 failed: 393 list_for_each_entry_safe(bh, n, &buffers, b_assoc_buffers) { 394 list_del_init(&bh->b_assoc_buffers); 395 brelse(bh); 396 } 397 return ret; 398 } 399 400 static int nilfs_ioctl_delete_checkpoints(struct the_nilfs *nilfs, 401 struct nilfs_argv *argv, void *buf) 402 { 403 size_t nmembs = argv->v_nmembs; 404 struct inode *cpfile = nilfs->ns_cpfile; 405 struct nilfs_period *periods = buf; 406 int ret, i; 407 408 for (i = 0; i < nmembs; i++) { 409 ret = nilfs_cpfile_delete_checkpoints( 410 cpfile, periods[i].p_start, periods[i].p_end); 411 if (ret < 0) 412 return ret; 413 } 414 return nmembs; 415 } 416 417 static int nilfs_ioctl_free_vblocknrs(struct the_nilfs *nilfs, 418 struct nilfs_argv *argv, void *buf) 419 { 420 size_t nmembs = argv->v_nmembs; 421 int ret; 422 423 ret = nilfs_dat_freev(nilfs->ns_dat, buf, nmembs); 424 425 return (ret < 0) ? ret : nmembs; 426 } 427 428 static int nilfs_ioctl_mark_blocks_dirty(struct the_nilfs *nilfs, 429 struct nilfs_argv *argv, void *buf) 430 { 431 size_t nmembs = argv->v_nmembs; 432 struct nilfs_bmap *bmap = NILFS_I(nilfs->ns_dat)->i_bmap; 433 struct nilfs_bdesc *bdescs = buf; 434 int ret, i; 435 436 for (i = 0; i < nmembs; i++) { 437 /* XXX: use macro or inline func to check liveness */ 438 ret = nilfs_bmap_lookup_at_level(bmap, 439 bdescs[i].bd_offset, 440 bdescs[i].bd_level + 1, 441 &bdescs[i].bd_blocknr); 442 if (ret < 0) { 443 if (ret != -ENOENT) 444 return ret; 445 bdescs[i].bd_blocknr = 0; 446 } 447 if (bdescs[i].bd_blocknr != bdescs[i].bd_oblocknr) 448 /* skip dead block */ 449 continue; 450 if (bdescs[i].bd_level == 0) { 451 ret = nilfs_mdt_mark_block_dirty(nilfs->ns_dat, 452 bdescs[i].bd_offset); 453 if (ret < 0) { 454 WARN_ON(ret == -ENOENT); 455 return ret; 456 } 457 } else { 458 ret = nilfs_bmap_mark(bmap, bdescs[i].bd_offset, 459 bdescs[i].bd_level); 460 if (ret < 0) { 461 WARN_ON(ret == -ENOENT); 462 return ret; 463 } 464 } 465 } 466 return nmembs; 467 } 468 469 int nilfs_ioctl_prepare_clean_segments(struct the_nilfs *nilfs, 470 struct nilfs_argv *argv, void **kbufs) 471 { 472 const char *msg; 473 int ret; 474 475 ret = nilfs_ioctl_delete_checkpoints(nilfs, &argv[1], kbufs[1]); 476 if (ret < 0) { 477 /* 478 * can safely abort because checkpoints can be removed 479 * independently. 480 */ 481 msg = "cannot delete checkpoints"; 482 goto failed; 483 } 484 ret = nilfs_ioctl_free_vblocknrs(nilfs, &argv[2], kbufs[2]); 485 if (ret < 0) { 486 /* 487 * can safely abort because DAT file is updated atomically 488 * using a copy-on-write technique. 489 */ 490 msg = "cannot delete virtual blocks from DAT file"; 491 goto failed; 492 } 493 ret = nilfs_ioctl_mark_blocks_dirty(nilfs, &argv[3], kbufs[3]); 494 if (ret < 0) { 495 /* 496 * can safely abort because the operation is nondestructive. 497 */ 498 msg = "cannot mark copying blocks dirty"; 499 goto failed; 500 } 501 return 0; 502 503 failed: 504 printk(KERN_ERR "NILFS: GC failed during preparation: %s: err=%d\n", 505 msg, ret); 506 return ret; 507 } 508 509 static int nilfs_ioctl_clean_segments(struct inode *inode, struct file *filp, 510 unsigned int cmd, void __user *argp) 511 { 512 struct nilfs_argv argv[5]; 513 static const size_t argsz[5] = { 514 sizeof(struct nilfs_vdesc), 515 sizeof(struct nilfs_period), 516 sizeof(__u64), 517 sizeof(struct nilfs_bdesc), 518 sizeof(__u64), 519 }; 520 void __user *base; 521 void *kbufs[5]; 522 struct the_nilfs *nilfs; 523 size_t len, nsegs; 524 int n, ret; 525 526 if (!capable(CAP_SYS_ADMIN)) 527 return -EPERM; 528 529 ret = mnt_want_write(filp->f_path.mnt); 530 if (ret) 531 return ret; 532 533 ret = -EFAULT; 534 if (copy_from_user(argv, argp, sizeof(argv))) 535 goto out; 536 537 ret = -EINVAL; 538 nsegs = argv[4].v_nmembs; 539 if (argv[4].v_size != argsz[4]) 540 goto out; 541 542 /* 543 * argv[4] points to segment numbers this ioctl cleans. We 544 * use kmalloc() for its buffer because memory used for the 545 * segment numbers is enough small. 546 */ 547 kbufs[4] = memdup_user((void __user *)(unsigned long)argv[4].v_base, 548 nsegs * sizeof(__u64)); 549 if (IS_ERR(kbufs[4])) { 550 ret = PTR_ERR(kbufs[4]); 551 goto out; 552 } 553 nilfs = NILFS_SB(inode->i_sb)->s_nilfs; 554 555 for (n = 0; n < 4; n++) { 556 ret = -EINVAL; 557 if (argv[n].v_size != argsz[n]) 558 goto out_free; 559 560 if (argv[n].v_nmembs > nsegs * nilfs->ns_blocks_per_segment) 561 goto out_free; 562 563 len = argv[n].v_size * argv[n].v_nmembs; 564 base = (void __user *)(unsigned long)argv[n].v_base; 565 if (len == 0) { 566 kbufs[n] = NULL; 567 continue; 568 } 569 570 kbufs[n] = vmalloc(len); 571 if (!kbufs[n]) { 572 ret = -ENOMEM; 573 goto out_free; 574 } 575 if (copy_from_user(kbufs[n], base, len)) { 576 ret = -EFAULT; 577 vfree(kbufs[n]); 578 goto out_free; 579 } 580 } 581 582 /* 583 * nilfs_ioctl_move_blocks() will call nilfs_iget_for_gc(), 584 * which will operates an inode list without blocking. 585 * To protect the list from concurrent operations, 586 * nilfs_ioctl_move_blocks should be atomic operation. 587 */ 588 if (test_and_set_bit(THE_NILFS_GC_RUNNING, &nilfs->ns_flags)) { 589 ret = -EBUSY; 590 goto out_free; 591 } 592 593 vfs_check_frozen(inode->i_sb, SB_FREEZE_WRITE); 594 595 ret = nilfs_ioctl_move_blocks(inode->i_sb, &argv[0], kbufs[0]); 596 if (ret < 0) 597 printk(KERN_ERR "NILFS: GC failed during preparation: " 598 "cannot read source blocks: err=%d\n", ret); 599 else 600 ret = nilfs_clean_segments(inode->i_sb, argv, kbufs); 601 602 nilfs_remove_all_gcinodes(nilfs); 603 clear_nilfs_gc_running(nilfs); 604 605 out_free: 606 while (--n >= 0) 607 vfree(kbufs[n]); 608 kfree(kbufs[4]); 609 out: 610 mnt_drop_write(filp->f_path.mnt); 611 return ret; 612 } 613 614 static int nilfs_ioctl_sync(struct inode *inode, struct file *filp, 615 unsigned int cmd, void __user *argp) 616 { 617 __u64 cno; 618 int ret; 619 struct the_nilfs *nilfs; 620 621 ret = nilfs_construct_segment(inode->i_sb); 622 if (ret < 0) 623 return ret; 624 625 if (argp != NULL) { 626 nilfs = NILFS_SB(inode->i_sb)->s_nilfs; 627 down_read(&nilfs->ns_segctor_sem); 628 cno = nilfs->ns_cno - 1; 629 up_read(&nilfs->ns_segctor_sem); 630 if (copy_to_user(argp, &cno, sizeof(cno))) 631 return -EFAULT; 632 } 633 return 0; 634 } 635 636 static int nilfs_ioctl_get_info(struct inode *inode, struct file *filp, 637 unsigned int cmd, void __user *argp, 638 size_t membsz, 639 ssize_t (*dofunc)(struct the_nilfs *, 640 __u64 *, int, 641 void *, size_t, size_t)) 642 643 { 644 struct the_nilfs *nilfs = NILFS_SB(inode->i_sb)->s_nilfs; 645 struct nilfs_argv argv; 646 int ret; 647 648 if (copy_from_user(&argv, argp, sizeof(argv))) 649 return -EFAULT; 650 651 if (argv.v_size < membsz) 652 return -EINVAL; 653 654 ret = nilfs_ioctl_wrap_copy(nilfs, &argv, _IOC_DIR(cmd), dofunc); 655 if (ret < 0) 656 return ret; 657 658 if (copy_to_user(argp, &argv, sizeof(argv))) 659 ret = -EFAULT; 660 return ret; 661 } 662 663 long nilfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) 664 { 665 struct inode *inode = filp->f_dentry->d_inode; 666 void __user *argp = (void __user *)arg; 667 668 switch (cmd) { 669 case NILFS_IOCTL_CHANGE_CPMODE: 670 return nilfs_ioctl_change_cpmode(inode, filp, cmd, argp); 671 case NILFS_IOCTL_DELETE_CHECKPOINT: 672 return nilfs_ioctl_delete_checkpoint(inode, filp, cmd, argp); 673 case NILFS_IOCTL_GET_CPINFO: 674 return nilfs_ioctl_get_info(inode, filp, cmd, argp, 675 sizeof(struct nilfs_cpinfo), 676 nilfs_ioctl_do_get_cpinfo); 677 case NILFS_IOCTL_GET_CPSTAT: 678 return nilfs_ioctl_get_cpstat(inode, filp, cmd, argp); 679 case NILFS_IOCTL_GET_SUINFO: 680 return nilfs_ioctl_get_info(inode, filp, cmd, argp, 681 sizeof(struct nilfs_suinfo), 682 nilfs_ioctl_do_get_suinfo); 683 case NILFS_IOCTL_GET_SUSTAT: 684 return nilfs_ioctl_get_sustat(inode, filp, cmd, argp); 685 case NILFS_IOCTL_GET_VINFO: 686 return nilfs_ioctl_get_info(inode, filp, cmd, argp, 687 sizeof(struct nilfs_vinfo), 688 nilfs_ioctl_do_get_vinfo); 689 case NILFS_IOCTL_GET_BDESCS: 690 return nilfs_ioctl_get_bdescs(inode, filp, cmd, argp); 691 case NILFS_IOCTL_CLEAN_SEGMENTS: 692 return nilfs_ioctl_clean_segments(inode, filp, cmd, argp); 693 case NILFS_IOCTL_SYNC: 694 return nilfs_ioctl_sync(inode, filp, cmd, argp); 695 default: 696 return -ENOTTY; 697 } 698 } 699