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_dat_inode(nilfs), 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 inode *dat = nilfs_dat_inode(nilfs); 246 struct nilfs_bmap *bmap = NILFS_I(dat)->i_bmap; 247 struct nilfs_bdesc *bdescs = buf; 248 int ret, i; 249 250 down_read(&nilfs->ns_segctor_sem); 251 for (i = 0; i < nmembs; i++) { 252 ret = nilfs_bmap_lookup_at_level(bmap, 253 bdescs[i].bd_offset, 254 bdescs[i].bd_level + 1, 255 &bdescs[i].bd_blocknr); 256 if (ret < 0) { 257 if (ret != -ENOENT) { 258 up_read(&nilfs->ns_segctor_sem); 259 return ret; 260 } 261 bdescs[i].bd_blocknr = 0; 262 } 263 } 264 up_read(&nilfs->ns_segctor_sem); 265 return nmembs; 266 } 267 268 static int nilfs_ioctl_get_bdescs(struct inode *inode, struct file *filp, 269 unsigned int cmd, void __user *argp) 270 { 271 struct the_nilfs *nilfs = NILFS_SB(inode->i_sb)->s_nilfs; 272 struct nilfs_argv argv; 273 int ret; 274 275 if (copy_from_user(&argv, argp, sizeof(argv))) 276 return -EFAULT; 277 278 if (argv.v_size != sizeof(struct nilfs_bdesc)) 279 return -EINVAL; 280 281 ret = nilfs_ioctl_wrap_copy(nilfs, &argv, _IOC_DIR(cmd), 282 nilfs_ioctl_do_get_bdescs); 283 if (ret < 0) 284 return ret; 285 286 if (copy_to_user(argp, &argv, sizeof(argv))) 287 ret = -EFAULT; 288 return ret; 289 } 290 291 static int nilfs_ioctl_move_inode_block(struct inode *inode, 292 struct nilfs_vdesc *vdesc, 293 struct list_head *buffers) 294 { 295 struct buffer_head *bh; 296 int ret; 297 298 if (vdesc->vd_flags == 0) 299 ret = nilfs_gccache_submit_read_data( 300 inode, vdesc->vd_offset, vdesc->vd_blocknr, 301 vdesc->vd_vblocknr, &bh); 302 else 303 ret = nilfs_gccache_submit_read_node( 304 inode, vdesc->vd_blocknr, vdesc->vd_vblocknr, &bh); 305 306 if (unlikely(ret < 0)) { 307 if (ret == -ENOENT) 308 printk(KERN_CRIT 309 "%s: invalid virtual block address (%s): " 310 "ino=%llu, cno=%llu, offset=%llu, " 311 "blocknr=%llu, vblocknr=%llu\n", 312 __func__, vdesc->vd_flags ? "node" : "data", 313 (unsigned long long)vdesc->vd_ino, 314 (unsigned long long)vdesc->vd_cno, 315 (unsigned long long)vdesc->vd_offset, 316 (unsigned long long)vdesc->vd_blocknr, 317 (unsigned long long)vdesc->vd_vblocknr); 318 return ret; 319 } 320 if (unlikely(!list_empty(&bh->b_assoc_buffers))) { 321 printk(KERN_CRIT "%s: conflicting %s buffer: ino=%llu, " 322 "cno=%llu, offset=%llu, blocknr=%llu, vblocknr=%llu\n", 323 __func__, vdesc->vd_flags ? "node" : "data", 324 (unsigned long long)vdesc->vd_ino, 325 (unsigned long long)vdesc->vd_cno, 326 (unsigned long long)vdesc->vd_offset, 327 (unsigned long long)vdesc->vd_blocknr, 328 (unsigned long long)vdesc->vd_vblocknr); 329 brelse(bh); 330 return -EEXIST; 331 } 332 list_add_tail(&bh->b_assoc_buffers, buffers); 333 return 0; 334 } 335 336 static int nilfs_ioctl_move_blocks(struct super_block *sb, 337 struct nilfs_argv *argv, void *buf) 338 { 339 size_t nmembs = argv->v_nmembs; 340 struct the_nilfs *nilfs = NILFS_SB(sb)->s_nilfs; 341 struct inode *inode; 342 struct nilfs_vdesc *vdesc; 343 struct buffer_head *bh, *n; 344 LIST_HEAD(buffers); 345 ino_t ino; 346 __u64 cno; 347 int i, ret; 348 349 for (i = 0, vdesc = buf; i < nmembs; ) { 350 ino = vdesc->vd_ino; 351 cno = vdesc->vd_cno; 352 inode = nilfs_iget_for_gc(sb, ino, cno); 353 if (IS_ERR(inode)) { 354 ret = PTR_ERR(inode); 355 goto failed; 356 } 357 if (list_empty(&NILFS_I(inode)->i_dirty)) { 358 /* 359 * Add the inode to GC inode list. Garbage Collection 360 * is serialized and no two processes manipulate the 361 * list simultaneously. 362 */ 363 igrab(inode); 364 list_add(&NILFS_I(inode)->i_dirty, 365 &nilfs->ns_gc_inodes); 366 } 367 368 do { 369 ret = nilfs_ioctl_move_inode_block(inode, vdesc, 370 &buffers); 371 if (unlikely(ret < 0)) { 372 iput(inode); 373 goto failed; 374 } 375 vdesc++; 376 } while (++i < nmembs && 377 vdesc->vd_ino == ino && vdesc->vd_cno == cno); 378 379 iput(inode); /* The inode still remains in GC inode list */ 380 } 381 382 list_for_each_entry_safe(bh, n, &buffers, b_assoc_buffers) { 383 ret = nilfs_gccache_wait_and_mark_dirty(bh); 384 if (unlikely(ret < 0)) { 385 WARN_ON(ret == -EEXIST); 386 goto failed; 387 } 388 list_del_init(&bh->b_assoc_buffers); 389 brelse(bh); 390 } 391 return nmembs; 392 393 failed: 394 list_for_each_entry_safe(bh, n, &buffers, b_assoc_buffers) { 395 list_del_init(&bh->b_assoc_buffers); 396 brelse(bh); 397 } 398 return ret; 399 } 400 401 static int nilfs_ioctl_delete_checkpoints(struct the_nilfs *nilfs, 402 struct nilfs_argv *argv, void *buf) 403 { 404 size_t nmembs = argv->v_nmembs; 405 struct inode *cpfile = nilfs->ns_cpfile; 406 struct nilfs_period *periods = buf; 407 int ret, i; 408 409 for (i = 0; i < nmembs; i++) { 410 ret = nilfs_cpfile_delete_checkpoints( 411 cpfile, periods[i].p_start, periods[i].p_end); 412 if (ret < 0) 413 return ret; 414 } 415 return nmembs; 416 } 417 418 static int nilfs_ioctl_free_vblocknrs(struct the_nilfs *nilfs, 419 struct nilfs_argv *argv, void *buf) 420 { 421 size_t nmembs = argv->v_nmembs; 422 int ret; 423 424 ret = nilfs_dat_freev(nilfs_dat_inode(nilfs), buf, nmembs); 425 426 return (ret < 0) ? ret : nmembs; 427 } 428 429 static int nilfs_ioctl_mark_blocks_dirty(struct the_nilfs *nilfs, 430 struct nilfs_argv *argv, void *buf) 431 { 432 size_t nmembs = argv->v_nmembs; 433 struct inode *dat = nilfs_dat_inode(nilfs); 434 struct nilfs_bmap *bmap = NILFS_I(dat)->i_bmap; 435 struct nilfs_bdesc *bdescs = buf; 436 int ret, i; 437 438 for (i = 0; i < nmembs; i++) { 439 /* XXX: use macro or inline func to check liveness */ 440 ret = nilfs_bmap_lookup_at_level(bmap, 441 bdescs[i].bd_offset, 442 bdescs[i].bd_level + 1, 443 &bdescs[i].bd_blocknr); 444 if (ret < 0) { 445 if (ret != -ENOENT) 446 return ret; 447 bdescs[i].bd_blocknr = 0; 448 } 449 if (bdescs[i].bd_blocknr != bdescs[i].bd_oblocknr) 450 /* skip dead block */ 451 continue; 452 if (bdescs[i].bd_level == 0) { 453 ret = nilfs_mdt_mark_block_dirty(dat, 454 bdescs[i].bd_offset); 455 if (ret < 0) { 456 WARN_ON(ret == -ENOENT); 457 return ret; 458 } 459 } else { 460 ret = nilfs_bmap_mark(bmap, bdescs[i].bd_offset, 461 bdescs[i].bd_level); 462 if (ret < 0) { 463 WARN_ON(ret == -ENOENT); 464 return ret; 465 } 466 } 467 } 468 return nmembs; 469 } 470 471 int nilfs_ioctl_prepare_clean_segments(struct the_nilfs *nilfs, 472 struct nilfs_argv *argv, void **kbufs) 473 { 474 const char *msg; 475 int ret; 476 477 ret = nilfs_ioctl_delete_checkpoints(nilfs, &argv[1], kbufs[1]); 478 if (ret < 0) { 479 /* 480 * can safely abort because checkpoints can be removed 481 * independently. 482 */ 483 msg = "cannot delete checkpoints"; 484 goto failed; 485 } 486 ret = nilfs_ioctl_free_vblocknrs(nilfs, &argv[2], kbufs[2]); 487 if (ret < 0) { 488 /* 489 * can safely abort because DAT file is updated atomically 490 * using a copy-on-write technique. 491 */ 492 msg = "cannot delete virtual blocks from DAT file"; 493 goto failed; 494 } 495 ret = nilfs_ioctl_mark_blocks_dirty(nilfs, &argv[3], kbufs[3]); 496 if (ret < 0) { 497 /* 498 * can safely abort because the operation is nondestructive. 499 */ 500 msg = "cannot mark copying blocks dirty"; 501 goto failed; 502 } 503 return 0; 504 505 failed: 506 printk(KERN_ERR "NILFS: GC failed during preparation: %s: err=%d\n", 507 msg, ret); 508 return ret; 509 } 510 511 static int nilfs_ioctl_clean_segments(struct inode *inode, struct file *filp, 512 unsigned int cmd, void __user *argp) 513 { 514 struct nilfs_argv argv[5]; 515 static const size_t argsz[5] = { 516 sizeof(struct nilfs_vdesc), 517 sizeof(struct nilfs_period), 518 sizeof(__u64), 519 sizeof(struct nilfs_bdesc), 520 sizeof(__u64), 521 }; 522 void __user *base; 523 void *kbufs[5]; 524 struct the_nilfs *nilfs; 525 size_t len, nsegs; 526 int n, ret; 527 528 if (!capable(CAP_SYS_ADMIN)) 529 return -EPERM; 530 531 ret = mnt_want_write(filp->f_path.mnt); 532 if (ret) 533 return ret; 534 535 ret = -EFAULT; 536 if (copy_from_user(argv, argp, sizeof(argv))) 537 goto out; 538 539 ret = -EINVAL; 540 nsegs = argv[4].v_nmembs; 541 if (argv[4].v_size != argsz[4]) 542 goto out; 543 544 /* 545 * argv[4] points to segment numbers this ioctl cleans. We 546 * use kmalloc() for its buffer because memory used for the 547 * segment numbers is enough small. 548 */ 549 kbufs[4] = memdup_user((void __user *)(unsigned long)argv[4].v_base, 550 nsegs * sizeof(__u64)); 551 if (IS_ERR(kbufs[4])) { 552 ret = PTR_ERR(kbufs[4]); 553 goto out; 554 } 555 nilfs = NILFS_SB(inode->i_sb)->s_nilfs; 556 557 for (n = 0; n < 4; n++) { 558 ret = -EINVAL; 559 if (argv[n].v_size != argsz[n]) 560 goto out_free; 561 562 if (argv[n].v_nmembs > nsegs * nilfs->ns_blocks_per_segment) 563 goto out_free; 564 565 len = argv[n].v_size * argv[n].v_nmembs; 566 base = (void __user *)(unsigned long)argv[n].v_base; 567 if (len == 0) { 568 kbufs[n] = NULL; 569 continue; 570 } 571 572 kbufs[n] = vmalloc(len); 573 if (!kbufs[n]) { 574 ret = -ENOMEM; 575 goto out_free; 576 } 577 if (copy_from_user(kbufs[n], base, len)) { 578 ret = -EFAULT; 579 vfree(kbufs[n]); 580 goto out_free; 581 } 582 } 583 584 /* 585 * nilfs_ioctl_move_blocks() will call nilfs_iget_for_gc(), 586 * which will operates an inode list without blocking. 587 * To protect the list from concurrent operations, 588 * nilfs_ioctl_move_blocks should be atomic operation. 589 */ 590 if (test_and_set_bit(THE_NILFS_GC_RUNNING, &nilfs->ns_flags)) { 591 ret = -EBUSY; 592 goto out_free; 593 } 594 595 vfs_check_frozen(inode->i_sb, SB_FREEZE_WRITE); 596 597 ret = nilfs_ioctl_move_blocks(inode->i_sb, &argv[0], kbufs[0]); 598 if (ret < 0) 599 printk(KERN_ERR "NILFS: GC failed during preparation: " 600 "cannot read source blocks: err=%d\n", ret); 601 else 602 ret = nilfs_clean_segments(inode->i_sb, argv, kbufs); 603 604 nilfs_remove_all_gcinodes(nilfs); 605 clear_nilfs_gc_running(nilfs); 606 607 out_free: 608 while (--n >= 0) 609 vfree(kbufs[n]); 610 kfree(kbufs[4]); 611 out: 612 mnt_drop_write(filp->f_path.mnt); 613 return ret; 614 } 615 616 static int nilfs_ioctl_sync(struct inode *inode, struct file *filp, 617 unsigned int cmd, void __user *argp) 618 { 619 __u64 cno; 620 int ret; 621 struct the_nilfs *nilfs; 622 623 ret = nilfs_construct_segment(inode->i_sb); 624 if (ret < 0) 625 return ret; 626 627 if (argp != NULL) { 628 nilfs = NILFS_SB(inode->i_sb)->s_nilfs; 629 down_read(&nilfs->ns_segctor_sem); 630 cno = nilfs->ns_cno - 1; 631 up_read(&nilfs->ns_segctor_sem); 632 if (copy_to_user(argp, &cno, sizeof(cno))) 633 return -EFAULT; 634 } 635 return 0; 636 } 637 638 static int nilfs_ioctl_get_info(struct inode *inode, struct file *filp, 639 unsigned int cmd, void __user *argp, 640 size_t membsz, 641 ssize_t (*dofunc)(struct the_nilfs *, 642 __u64 *, int, 643 void *, size_t, size_t)) 644 645 { 646 struct the_nilfs *nilfs = NILFS_SB(inode->i_sb)->s_nilfs; 647 struct nilfs_argv argv; 648 int ret; 649 650 if (copy_from_user(&argv, argp, sizeof(argv))) 651 return -EFAULT; 652 653 if (argv.v_size < membsz) 654 return -EINVAL; 655 656 ret = nilfs_ioctl_wrap_copy(nilfs, &argv, _IOC_DIR(cmd), dofunc); 657 if (ret < 0) 658 return ret; 659 660 if (copy_to_user(argp, &argv, sizeof(argv))) 661 ret = -EFAULT; 662 return ret; 663 } 664 665 long nilfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) 666 { 667 struct inode *inode = filp->f_dentry->d_inode; 668 void __user *argp = (void __user *)arg; 669 670 switch (cmd) { 671 case NILFS_IOCTL_CHANGE_CPMODE: 672 return nilfs_ioctl_change_cpmode(inode, filp, cmd, argp); 673 case NILFS_IOCTL_DELETE_CHECKPOINT: 674 return nilfs_ioctl_delete_checkpoint(inode, filp, cmd, argp); 675 case NILFS_IOCTL_GET_CPINFO: 676 return nilfs_ioctl_get_info(inode, filp, cmd, argp, 677 sizeof(struct nilfs_cpinfo), 678 nilfs_ioctl_do_get_cpinfo); 679 case NILFS_IOCTL_GET_CPSTAT: 680 return nilfs_ioctl_get_cpstat(inode, filp, cmd, argp); 681 case NILFS_IOCTL_GET_SUINFO: 682 return nilfs_ioctl_get_info(inode, filp, cmd, argp, 683 sizeof(struct nilfs_suinfo), 684 nilfs_ioctl_do_get_suinfo); 685 case NILFS_IOCTL_GET_SUSTAT: 686 return nilfs_ioctl_get_sustat(inode, filp, cmd, argp); 687 case NILFS_IOCTL_GET_VINFO: 688 return nilfs_ioctl_get_info(inode, filp, cmd, argp, 689 sizeof(struct nilfs_vinfo), 690 nilfs_ioctl_do_get_vinfo); 691 case NILFS_IOCTL_GET_BDESCS: 692 return nilfs_ioctl_get_bdescs(inode, filp, cmd, argp); 693 case NILFS_IOCTL_CLEAN_SEGMENTS: 694 return nilfs_ioctl_clean_segments(inode, filp, cmd, argp); 695 case NILFS_IOCTL_SYNC: 696 return nilfs_ioctl_sync(inode, filp, cmd, argp); 697 default: 698 return -ENOTTY; 699 } 700 } 701