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 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 (unlikely(inode == NULL)) { 353 ret = -ENOMEM; 354 goto failed; 355 } 356 do { 357 ret = nilfs_ioctl_move_inode_block(inode, vdesc, 358 &buffers); 359 if (unlikely(ret < 0)) { 360 iput(inode); 361 goto failed; 362 } 363 vdesc++; 364 } while (++i < nmembs && 365 vdesc->vd_ino == ino && vdesc->vd_cno == cno); 366 367 iput(inode); /* The inode still remains in GC inode list */ 368 } 369 370 list_for_each_entry_safe(bh, n, &buffers, b_assoc_buffers) { 371 ret = nilfs_gccache_wait_and_mark_dirty(bh); 372 if (unlikely(ret < 0)) { 373 WARN_ON(ret == -EEXIST); 374 goto failed; 375 } 376 list_del_init(&bh->b_assoc_buffers); 377 brelse(bh); 378 } 379 return nmembs; 380 381 failed: 382 list_for_each_entry_safe(bh, n, &buffers, b_assoc_buffers) { 383 list_del_init(&bh->b_assoc_buffers); 384 brelse(bh); 385 } 386 return ret; 387 } 388 389 static int nilfs_ioctl_delete_checkpoints(struct the_nilfs *nilfs, 390 struct nilfs_argv *argv, void *buf) 391 { 392 size_t nmembs = argv->v_nmembs; 393 struct inode *cpfile = nilfs->ns_cpfile; 394 struct nilfs_period *periods = buf; 395 int ret, i; 396 397 for (i = 0; i < nmembs; i++) { 398 ret = nilfs_cpfile_delete_checkpoints( 399 cpfile, periods[i].p_start, periods[i].p_end); 400 if (ret < 0) 401 return ret; 402 } 403 return nmembs; 404 } 405 406 static int nilfs_ioctl_free_vblocknrs(struct the_nilfs *nilfs, 407 struct nilfs_argv *argv, void *buf) 408 { 409 size_t nmembs = argv->v_nmembs; 410 int ret; 411 412 ret = nilfs_dat_freev(nilfs_dat_inode(nilfs), buf, nmembs); 413 414 return (ret < 0) ? ret : nmembs; 415 } 416 417 static int nilfs_ioctl_mark_blocks_dirty(struct the_nilfs *nilfs, 418 struct nilfs_argv *argv, void *buf) 419 { 420 size_t nmembs = argv->v_nmembs; 421 struct inode *dat = nilfs_dat_inode(nilfs); 422 struct nilfs_bmap *bmap = NILFS_I(dat)->i_bmap; 423 struct nilfs_bdesc *bdescs = buf; 424 int ret, i; 425 426 for (i = 0; i < nmembs; i++) { 427 /* XXX: use macro or inline func to check liveness */ 428 ret = nilfs_bmap_lookup_at_level(bmap, 429 bdescs[i].bd_offset, 430 bdescs[i].bd_level + 1, 431 &bdescs[i].bd_blocknr); 432 if (ret < 0) { 433 if (ret != -ENOENT) 434 return ret; 435 bdescs[i].bd_blocknr = 0; 436 } 437 if (bdescs[i].bd_blocknr != bdescs[i].bd_oblocknr) 438 /* skip dead block */ 439 continue; 440 if (bdescs[i].bd_level == 0) { 441 ret = nilfs_mdt_mark_block_dirty(dat, 442 bdescs[i].bd_offset); 443 if (ret < 0) { 444 WARN_ON(ret == -ENOENT); 445 return ret; 446 } 447 } else { 448 ret = nilfs_bmap_mark(bmap, bdescs[i].bd_offset, 449 bdescs[i].bd_level); 450 if (ret < 0) { 451 WARN_ON(ret == -ENOENT); 452 return ret; 453 } 454 } 455 } 456 return nmembs; 457 } 458 459 int nilfs_ioctl_prepare_clean_segments(struct the_nilfs *nilfs, 460 struct nilfs_argv *argv, void **kbufs) 461 { 462 const char *msg; 463 int ret; 464 465 ret = nilfs_ioctl_delete_checkpoints(nilfs, &argv[1], kbufs[1]); 466 if (ret < 0) { 467 /* 468 * can safely abort because checkpoints can be removed 469 * independently. 470 */ 471 msg = "cannot delete checkpoints"; 472 goto failed; 473 } 474 ret = nilfs_ioctl_free_vblocknrs(nilfs, &argv[2], kbufs[2]); 475 if (ret < 0) { 476 /* 477 * can safely abort because DAT file is updated atomically 478 * using a copy-on-write technique. 479 */ 480 msg = "cannot delete virtual blocks from DAT file"; 481 goto failed; 482 } 483 ret = nilfs_ioctl_mark_blocks_dirty(nilfs, &argv[3], kbufs[3]); 484 if (ret < 0) { 485 /* 486 * can safely abort because the operation is nondestructive. 487 */ 488 msg = "cannot mark copying blocks dirty"; 489 goto failed; 490 } 491 return 0; 492 493 failed: 494 printk(KERN_ERR "NILFS: GC failed during preparation: %s: err=%d\n", 495 msg, ret); 496 return ret; 497 } 498 499 static int nilfs_ioctl_clean_segments(struct inode *inode, struct file *filp, 500 unsigned int cmd, void __user *argp) 501 { 502 struct nilfs_argv argv[5]; 503 static const size_t argsz[5] = { 504 sizeof(struct nilfs_vdesc), 505 sizeof(struct nilfs_period), 506 sizeof(__u64), 507 sizeof(struct nilfs_bdesc), 508 sizeof(__u64), 509 }; 510 void __user *base; 511 void *kbufs[5]; 512 struct the_nilfs *nilfs; 513 size_t len, nsegs; 514 int n, ret; 515 516 if (!capable(CAP_SYS_ADMIN)) 517 return -EPERM; 518 519 ret = mnt_want_write(filp->f_path.mnt); 520 if (ret) 521 return ret; 522 523 ret = -EFAULT; 524 if (copy_from_user(argv, argp, sizeof(argv))) 525 goto out; 526 527 ret = -EINVAL; 528 nsegs = argv[4].v_nmembs; 529 if (argv[4].v_size != argsz[4]) 530 goto out; 531 532 /* 533 * argv[4] points to segment numbers this ioctl cleans. We 534 * use kmalloc() for its buffer because memory used for the 535 * segment numbers is enough small. 536 */ 537 kbufs[4] = memdup_user((void __user *)(unsigned long)argv[4].v_base, 538 nsegs * sizeof(__u64)); 539 if (IS_ERR(kbufs[4])) { 540 ret = PTR_ERR(kbufs[4]); 541 goto out; 542 } 543 nilfs = NILFS_SB(inode->i_sb)->s_nilfs; 544 545 for (n = 0; n < 4; n++) { 546 ret = -EINVAL; 547 if (argv[n].v_size != argsz[n]) 548 goto out_free; 549 550 if (argv[n].v_nmembs > nsegs * nilfs->ns_blocks_per_segment) 551 goto out_free; 552 553 len = argv[n].v_size * argv[n].v_nmembs; 554 base = (void __user *)(unsigned long)argv[n].v_base; 555 if (len == 0) { 556 kbufs[n] = NULL; 557 continue; 558 } 559 560 kbufs[n] = vmalloc(len); 561 if (!kbufs[n]) { 562 ret = -ENOMEM; 563 goto out_free; 564 } 565 if (copy_from_user(kbufs[n], base, len)) { 566 ret = -EFAULT; 567 vfree(kbufs[n]); 568 goto out_free; 569 } 570 } 571 572 /* 573 * nilfs_ioctl_move_blocks() will call nilfs_iget_for_gc(), 574 * which will operates an inode list without blocking. 575 * To protect the list from concurrent operations, 576 * nilfs_ioctl_move_blocks should be atomic operation. 577 */ 578 if (test_and_set_bit(THE_NILFS_GC_RUNNING, &nilfs->ns_flags)) { 579 ret = -EBUSY; 580 goto out_free; 581 } 582 583 vfs_check_frozen(inode->i_sb, SB_FREEZE_WRITE); 584 585 ret = nilfs_ioctl_move_blocks(inode->i_sb, &argv[0], kbufs[0]); 586 if (ret < 0) 587 printk(KERN_ERR "NILFS: GC failed during preparation: " 588 "cannot read source blocks: err=%d\n", ret); 589 else 590 ret = nilfs_clean_segments(inode->i_sb, argv, kbufs); 591 592 nilfs_remove_all_gcinodes(nilfs); 593 clear_nilfs_gc_running(nilfs); 594 595 out_free: 596 while (--n >= 0) 597 vfree(kbufs[n]); 598 kfree(kbufs[4]); 599 out: 600 mnt_drop_write(filp->f_path.mnt); 601 return ret; 602 } 603 604 static int nilfs_ioctl_sync(struct inode *inode, struct file *filp, 605 unsigned int cmd, void __user *argp) 606 { 607 __u64 cno; 608 int ret; 609 struct the_nilfs *nilfs; 610 611 ret = nilfs_construct_segment(inode->i_sb); 612 if (ret < 0) 613 return ret; 614 615 if (argp != NULL) { 616 nilfs = NILFS_SB(inode->i_sb)->s_nilfs; 617 down_read(&nilfs->ns_segctor_sem); 618 cno = nilfs->ns_cno - 1; 619 up_read(&nilfs->ns_segctor_sem); 620 if (copy_to_user(argp, &cno, sizeof(cno))) 621 return -EFAULT; 622 } 623 return 0; 624 } 625 626 static int nilfs_ioctl_get_info(struct inode *inode, struct file *filp, 627 unsigned int cmd, void __user *argp, 628 size_t membsz, 629 ssize_t (*dofunc)(struct the_nilfs *, 630 __u64 *, int, 631 void *, size_t, size_t)) 632 633 { 634 struct the_nilfs *nilfs = NILFS_SB(inode->i_sb)->s_nilfs; 635 struct nilfs_argv argv; 636 int ret; 637 638 if (copy_from_user(&argv, argp, sizeof(argv))) 639 return -EFAULT; 640 641 if (argv.v_size < membsz) 642 return -EINVAL; 643 644 ret = nilfs_ioctl_wrap_copy(nilfs, &argv, _IOC_DIR(cmd), dofunc); 645 if (ret < 0) 646 return ret; 647 648 if (copy_to_user(argp, &argv, sizeof(argv))) 649 ret = -EFAULT; 650 return ret; 651 } 652 653 long nilfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) 654 { 655 struct inode *inode = filp->f_dentry->d_inode; 656 void __user *argp = (void __user *)arg; 657 658 switch (cmd) { 659 case NILFS_IOCTL_CHANGE_CPMODE: 660 return nilfs_ioctl_change_cpmode(inode, filp, cmd, argp); 661 case NILFS_IOCTL_DELETE_CHECKPOINT: 662 return nilfs_ioctl_delete_checkpoint(inode, filp, cmd, argp); 663 case NILFS_IOCTL_GET_CPINFO: 664 return nilfs_ioctl_get_info(inode, filp, cmd, argp, 665 sizeof(struct nilfs_cpinfo), 666 nilfs_ioctl_do_get_cpinfo); 667 case NILFS_IOCTL_GET_CPSTAT: 668 return nilfs_ioctl_get_cpstat(inode, filp, cmd, argp); 669 case NILFS_IOCTL_GET_SUINFO: 670 return nilfs_ioctl_get_info(inode, filp, cmd, argp, 671 sizeof(struct nilfs_suinfo), 672 nilfs_ioctl_do_get_suinfo); 673 case NILFS_IOCTL_GET_SUSTAT: 674 return nilfs_ioctl_get_sustat(inode, filp, cmd, argp); 675 case NILFS_IOCTL_GET_VINFO: 676 return nilfs_ioctl_get_info(inode, filp, cmd, argp, 677 sizeof(struct nilfs_vinfo), 678 nilfs_ioctl_do_get_vinfo); 679 case NILFS_IOCTL_GET_BDESCS: 680 return nilfs_ioctl_get_bdescs(inode, filp, cmd, argp); 681 case NILFS_IOCTL_CLEAN_SEGMENTS: 682 return nilfs_ioctl_clean_segments(inode, filp, cmd, argp); 683 case NILFS_IOCTL_SYNC: 684 return nilfs_ioctl_sync(inode, filp, cmd, argp); 685 default: 686 return -ENOTTY; 687 } 688 } 689