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 40static 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 101static 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); 132out: 133 mnt_drop_write(filp->f_path.mnt); 134 return ret; 135} 136 137static int 138nilfs_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 */ 163out: 164 mnt_drop_write(filp->f_path.mnt); 165 return ret; 166} 167 168static ssize_t 169nilfs_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 181static 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 199static ssize_t 200nilfs_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 212static 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 230static ssize_t 231nilfs_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 242static ssize_t 243nilfs_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 269static 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 292static 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 337static 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 386static 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 403static 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 414static 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 ret = nilfs_bmap_lookup_at_level(bmap, 425 bdescs[i].bd_offset, 426 bdescs[i].bd_level + 1, 427 &bdescs[i].bd_blocknr); 428 if (ret < 0) { 429 if (ret != -ENOENT) 430 return ret; 431 bdescs[i].bd_blocknr = 0; 432 } 433 if (bdescs[i].bd_blocknr != bdescs[i].bd_oblocknr) 434 /* skip dead block */ 435 continue; 436 if (bdescs[i].bd_level == 0) { 437 ret = nilfs_mdt_mark_block_dirty(dat, 438 bdescs[i].bd_offset); 439 if (ret < 0) { 440 WARN_ON(ret == -ENOENT); 441 return ret; 442 } 443 } else { 444 ret = nilfs_bmap_mark(bmap, bdescs[i].bd_offset, 445 bdescs[i].bd_level); 446 if (ret < 0) { 447 WARN_ON(ret == -ENOENT); 448 return ret; 449 } 450 } 451 } 452 return nmembs; 453} 454 455int nilfs_ioctl_prepare_clean_segments(struct the_nilfs *nilfs, 456 struct nilfs_argv *argv, void **kbufs) 457{ 458 const char *msg; 459 int ret; 460 461 ret = nilfs_ioctl_delete_checkpoints(nilfs, &argv[1], kbufs[1]); 462 if (ret < 0) { 463 /* 464 * can safely abort because checkpoints can be removed 465 * independently. 466 */ 467 msg = "cannot delete checkpoints"; 468 goto failed; 469 } 470 ret = nilfs_ioctl_free_vblocknrs(nilfs, &argv[2], kbufs[2]); 471 if (ret < 0) { 472 /* 473 * can safely abort because DAT file is updated atomically 474 * using a copy-on-write technique. 475 */ 476 msg = "cannot delete virtual blocks from DAT file"; 477 goto failed; 478 } 479 ret = nilfs_ioctl_mark_blocks_dirty(nilfs, &argv[3], kbufs[3]); 480 if (ret < 0) { 481 /* 482 * can safely abort because the operation is nondestructive. 483 */ 484 msg = "cannot mark copying blocks dirty"; 485 goto failed; 486 } 487 return 0; 488 489 failed: 490 printk(KERN_ERR "NILFS: GC failed during preparation: %s: err=%d\n", 491 msg, ret); 492 return ret; 493} 494 495static int nilfs_ioctl_clean_segments(struct inode *inode, struct file *filp, 496 unsigned int cmd, void __user *argp) 497{ 498 struct nilfs_argv argv[5]; 499 static const size_t argsz[5] = { 500 sizeof(struct nilfs_vdesc), 501 sizeof(struct nilfs_period), 502 sizeof(__u64), 503 sizeof(struct nilfs_bdesc), 504 sizeof(__u64), 505 }; 506 void __user *base; 507 void *kbufs[5]; 508 struct the_nilfs *nilfs; 509 size_t len, nsegs; 510 int n, ret; 511 512 if (!capable(CAP_SYS_ADMIN)) 513 return -EPERM; 514 515 ret = mnt_want_write(filp->f_path.mnt); 516 if (ret) 517 return ret; 518 519 ret = -EFAULT; 520 if (copy_from_user(argv, argp, sizeof(argv))) 521 goto out; 522 523 ret = -EINVAL; 524 nsegs = argv[4].v_nmembs; 525 if (argv[4].v_size != argsz[4]) 526 goto out; 527 528 /* 529 * argv[4] points to segment numbers this ioctl cleans. We 530 * use kmalloc() for its buffer because memory used for the 531 * segment numbers is enough small. 532 */ 533 kbufs[4] = memdup_user((void __user *)(unsigned long)argv[4].v_base, 534 nsegs * sizeof(__u64)); 535 if (IS_ERR(kbufs[4])) { 536 ret = PTR_ERR(kbufs[4]); 537 goto out; 538 } 539 nilfs = NILFS_SB(inode->i_sb)->s_nilfs; 540 541 for (n = 0; n < 4; n++) { 542 ret = -EINVAL; 543 if (argv[n].v_size != argsz[n]) 544 goto out_free; 545 546 if (argv[n].v_nmembs > nsegs * nilfs->ns_blocks_per_segment) 547 goto out_free; 548 549 len = argv[n].v_size * argv[n].v_nmembs; 550 base = (void __user *)(unsigned long)argv[n].v_base; 551 if (len == 0) { 552 kbufs[n] = NULL; 553 continue; 554 } 555 556 kbufs[n] = vmalloc(len); 557 if (!kbufs[n]) { 558 ret = -ENOMEM; 559 goto out_free; 560 } 561 if (copy_from_user(kbufs[n], base, len)) { 562 ret = -EFAULT; 563 vfree(kbufs[n]); 564 goto out_free; 565 } 566 } 567 568 /* 569 * nilfs_ioctl_move_blocks() will call nilfs_gc_iget(), 570 * which will operates an inode list without blocking. 571 * To protect the list from concurrent operations, 572 * nilfs_ioctl_move_blocks should be atomic operation. 573 */ 574 if (test_and_set_bit(THE_NILFS_GC_RUNNING, &nilfs->ns_flags)) { 575 ret = -EBUSY; 576 goto out_free; 577 } 578 579 ret = nilfs_ioctl_move_blocks(nilfs, &argv[0], kbufs[0]); 580 if (ret < 0) 581 printk(KERN_ERR "NILFS: GC failed during preparation: " 582 "cannot read source blocks: err=%d\n", ret); 583 else 584 ret = nilfs_clean_segments(inode->i_sb, argv, kbufs); 585 586 if (ret < 0) 587 nilfs_remove_all_gcinode(nilfs); 588 clear_nilfs_gc_running(nilfs); 589 590out_free: 591 while (--n >= 0) 592 vfree(kbufs[n]); 593 kfree(kbufs[4]); 594out: 595 mnt_drop_write(filp->f_path.mnt); 596 return ret; 597} 598 599static int nilfs_ioctl_sync(struct inode *inode, struct file *filp, 600 unsigned int cmd, void __user *argp) 601{ 602 __u64 cno; 603 int ret; 604 struct the_nilfs *nilfs; 605 606 ret = nilfs_construct_segment(inode->i_sb); 607 if (ret < 0) 608 return ret; 609 610 if (argp != NULL) { 611 nilfs = NILFS_SB(inode->i_sb)->s_nilfs; 612 down_read(&nilfs->ns_segctor_sem); 613 cno = nilfs->ns_cno - 1; 614 up_read(&nilfs->ns_segctor_sem); 615 if (copy_to_user(argp, &cno, sizeof(cno))) 616 return -EFAULT; 617 } 618 return 0; 619} 620 621static int nilfs_ioctl_get_info(struct inode *inode, struct file *filp, 622 unsigned int cmd, void __user *argp, 623 size_t membsz, 624 ssize_t (*dofunc)(struct the_nilfs *, 625 __u64 *, int, 626 void *, size_t, size_t)) 627 628{ 629 struct the_nilfs *nilfs = NILFS_SB(inode->i_sb)->s_nilfs; 630 struct nilfs_argv argv; 631 int ret; 632 633 if (copy_from_user(&argv, argp, sizeof(argv))) 634 return -EFAULT; 635 636 if (argv.v_size < membsz) 637 return -EINVAL; 638 639 ret = nilfs_ioctl_wrap_copy(nilfs, &argv, _IOC_DIR(cmd), dofunc); 640 if (ret < 0) 641 return ret; 642 643 if (copy_to_user(argp, &argv, sizeof(argv))) 644 ret = -EFAULT; 645 return ret; 646} 647 648long nilfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) 649{ 650 struct inode *inode = filp->f_dentry->d_inode; 651 void __user *argp = (void __user *)arg; 652 653 switch (cmd) { 654 case NILFS_IOCTL_CHANGE_CPMODE: 655 return nilfs_ioctl_change_cpmode(inode, filp, cmd, argp); 656 case NILFS_IOCTL_DELETE_CHECKPOINT: 657 return nilfs_ioctl_delete_checkpoint(inode, filp, cmd, argp); 658 case NILFS_IOCTL_GET_CPINFO: 659 return nilfs_ioctl_get_info(inode, filp, cmd, argp, 660 sizeof(struct nilfs_cpinfo), 661 nilfs_ioctl_do_get_cpinfo); 662 case NILFS_IOCTL_GET_CPSTAT: 663 return nilfs_ioctl_get_cpstat(inode, filp, cmd, argp); 664 case NILFS_IOCTL_GET_SUINFO: 665 return nilfs_ioctl_get_info(inode, filp, cmd, argp, 666 sizeof(struct nilfs_suinfo), 667 nilfs_ioctl_do_get_suinfo); 668 case NILFS_IOCTL_GET_SUSTAT: 669 return nilfs_ioctl_get_sustat(inode, filp, cmd, argp); 670 case NILFS_IOCTL_GET_VINFO: 671 return nilfs_ioctl_get_info(inode, filp, cmd, argp, 672 sizeof(struct nilfs_vinfo), 673 nilfs_ioctl_do_get_vinfo); 674 case NILFS_IOCTL_GET_BDESCS: 675 return nilfs_ioctl_get_bdescs(inode, filp, cmd, argp); 676 case NILFS_IOCTL_CLEAN_SEGMENTS: 677 return nilfs_ioctl_clean_segments(inode, filp, cmd, argp); 678 case NILFS_IOCTL_SYNC: 679 return nilfs_ioctl_sync(inode, filp, cmd, argp); 680 default: 681 return -ENOTTY; 682 } 683} 684