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