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