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