2 * ioctl.c - NILFS ioctl operations.
4 * Copyright (C) 2007, 2008 Nippon Telegraph and Telephone Corporation.
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.
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.
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
20 * Written by Koji Sato <koji@osrg.net>.
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>
37 #define KMALLOC_SIZE_MIN 4096 /* 4KB */
38 #define KMALLOC_SIZE_MAX 131072 /* 128 KB */
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
*,
44 void *, size_t, size_t))
47 size_t ksize
, maxmembs
, total
, n
;
51 if (argv
->v_nmembs
== 0)
54 for (ksize
= KMALLOC_SIZE_MAX
; ksize
>= KMALLOC_SIZE_MIN
; ksize
/= 2) {
55 buf
= kmalloc(ksize
, GFP_NOFS
);
59 if (ksize
< KMALLOC_SIZE_MIN
)
61 maxmembs
= ksize
/ argv
->v_size
;
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
) &&
70 (void __user
*)argv
->v_base
+ argv
->v_size
* i
,
75 nr
= (*dofunc
)(nilfs
, argv
->v_index
+ i
, argv
->v_flags
, buf
,
81 if ((dir
& _IOC_READ
) &&
83 (void __user
*)argv
->v_base
+ argv
->v_size
* i
,
84 buf
, argv
->v_size
* nr
)) {
90 argv
->v_nmembs
= total
;
96 static int nilfs_ioctl_change_cpmode(struct inode
*inode
, struct file
*filp
,
97 unsigned int cmd
, void __user
*argp
)
99 struct inode
*cpfile
= NILFS_SB(inode
->i_sb
)->s_nilfs
->ns_cpfile
;
100 struct nilfs_transaction_info ti
;
101 struct nilfs_cpmode cpmode
;
104 if (!capable(CAP_SYS_ADMIN
))
106 if (copy_from_user(&cpmode
, argp
, sizeof(cpmode
)))
109 nilfs_transaction_begin(inode
->i_sb
, &ti
, 0);
110 ret
= nilfs_cpfile_change_cpmode(
111 cpfile
, cpmode
.cm_cno
, cpmode
.cm_mode
);
112 nilfs_transaction_end(inode
->i_sb
, !ret
);
117 nilfs_ioctl_delete_checkpoint(struct inode
*inode
, struct file
*filp
,
118 unsigned int cmd
, void __user
*argp
)
120 struct inode
*cpfile
= NILFS_SB(inode
->i_sb
)->s_nilfs
->ns_cpfile
;
121 struct nilfs_transaction_info ti
;
125 if (!capable(CAP_SYS_ADMIN
))
127 if (copy_from_user(&cno
, argp
, sizeof(cno
)))
130 nilfs_transaction_begin(inode
->i_sb
, &ti
, 0);
131 ret
= nilfs_cpfile_delete_checkpoint(cpfile
, cno
);
132 nilfs_transaction_end(inode
->i_sb
, !ret
);
137 nilfs_ioctl_do_get_cpinfo(struct the_nilfs
*nilfs
, int index
, int flags
,
138 void *buf
, size_t size
, size_t nmembs
)
140 return nilfs_cpfile_get_cpinfo(nilfs
->ns_cpfile
, index
, flags
, buf
,
144 static int nilfs_ioctl_get_cpinfo(struct inode
*inode
, struct file
*filp
,
145 unsigned int cmd
, void __user
*argp
)
147 struct the_nilfs
*nilfs
= NILFS_SB(inode
->i_sb
)->s_nilfs
;
148 struct nilfs_argv argv
;
149 struct nilfs_transaction_info ti
;
152 if (copy_from_user(&argv
, argp
, sizeof(argv
)))
155 nilfs_transaction_begin(inode
->i_sb
, &ti
, 0);
156 ret
= nilfs_ioctl_wrap_copy(nilfs
, &argv
, _IOC_DIR(cmd
),
157 nilfs_ioctl_do_get_cpinfo
);
158 nilfs_transaction_end(inode
->i_sb
, 0);
160 if (copy_to_user(argp
, &argv
, sizeof(argv
)))
165 static int nilfs_ioctl_get_cpstat(struct inode
*inode
, struct file
*filp
,
166 unsigned int cmd
, void __user
*argp
)
168 struct inode
*cpfile
= NILFS_SB(inode
->i_sb
)->s_nilfs
->ns_cpfile
;
169 struct nilfs_cpstat cpstat
;
170 struct nilfs_transaction_info ti
;
173 nilfs_transaction_begin(inode
->i_sb
, &ti
, 0);
174 ret
= nilfs_cpfile_get_stat(cpfile
, &cpstat
);
175 nilfs_transaction_end(inode
->i_sb
, 0);
179 if (copy_to_user(argp
, &cpstat
, sizeof(cpstat
)))
185 nilfs_ioctl_do_get_suinfo(struct the_nilfs
*nilfs
, int index
, int flags
,
186 void *buf
, size_t size
, size_t nmembs
)
188 return nilfs_sufile_get_suinfo(nilfs
->ns_sufile
, index
, buf
, nmembs
);
191 static int nilfs_ioctl_get_suinfo(struct inode
*inode
, struct file
*filp
,
192 unsigned int cmd
, void __user
*argp
)
194 struct the_nilfs
*nilfs
= NILFS_SB(inode
->i_sb
)->s_nilfs
;
195 struct nilfs_argv argv
;
196 struct nilfs_transaction_info ti
;
199 if (copy_from_user(&argv
, argp
, sizeof(argv
)))
202 nilfs_transaction_begin(inode
->i_sb
, &ti
, 0);
203 ret
= nilfs_ioctl_wrap_copy(nilfs
, &argv
, _IOC_DIR(cmd
),
204 nilfs_ioctl_do_get_suinfo
);
205 nilfs_transaction_end(inode
->i_sb
, 0);
207 if (copy_to_user(argp
, &argv
, sizeof(argv
)))
212 static int nilfs_ioctl_get_sustat(struct inode
*inode
, struct file
*filp
,
213 unsigned int cmd
, void __user
*argp
)
215 struct inode
*sufile
= NILFS_SB(inode
->i_sb
)->s_nilfs
->ns_sufile
;
216 struct nilfs_sustat sustat
;
217 struct nilfs_transaction_info ti
;
220 nilfs_transaction_begin(inode
->i_sb
, &ti
, 0);
221 ret
= nilfs_sufile_get_stat(sufile
, &sustat
);
222 nilfs_transaction_end(inode
->i_sb
, 0);
226 if (copy_to_user(argp
, &sustat
, sizeof(sustat
)))
232 nilfs_ioctl_do_get_vinfo(struct the_nilfs
*nilfs
, int index
, int flags
,
233 void *buf
, size_t size
, size_t nmembs
)
235 return nilfs_dat_get_vinfo(nilfs_dat_inode(nilfs
), buf
, nmembs
);
238 static int nilfs_ioctl_get_vinfo(struct inode
*inode
, struct file
*filp
,
239 unsigned int cmd
, void __user
*argp
)
241 struct the_nilfs
*nilfs
= NILFS_SB(inode
->i_sb
)->s_nilfs
;
242 struct nilfs_argv argv
;
243 struct nilfs_transaction_info ti
;
246 if (copy_from_user(&argv
, argp
, sizeof(argv
)))
249 nilfs_transaction_begin(inode
->i_sb
, &ti
, 0);
250 ret
= nilfs_ioctl_wrap_copy(nilfs
, &argv
, _IOC_DIR(cmd
),
251 nilfs_ioctl_do_get_vinfo
);
252 nilfs_transaction_end(inode
->i_sb
, 0);
254 if (copy_to_user(argp
, &argv
, sizeof(argv
)))
260 nilfs_ioctl_do_get_bdescs(struct the_nilfs
*nilfs
, int index
, int flags
,
261 void *buf
, size_t size
, size_t nmembs
)
263 struct inode
*dat
= nilfs_dat_inode(nilfs
);
264 struct nilfs_bmap
*bmap
= NILFS_I(dat
)->i_bmap
;
265 struct nilfs_bdesc
*bdescs
= buf
;
268 for (i
= 0; i
< nmembs
; i
++) {
269 ret
= nilfs_bmap_lookup_at_level(bmap
,
271 bdescs
[i
].bd_level
+ 1,
272 &bdescs
[i
].bd_blocknr
);
276 bdescs
[i
].bd_blocknr
= 0;
282 static int nilfs_ioctl_get_bdescs(struct inode
*inode
, struct file
*filp
,
283 unsigned int cmd
, void __user
*argp
)
285 struct the_nilfs
*nilfs
= NILFS_SB(inode
->i_sb
)->s_nilfs
;
286 struct nilfs_argv argv
;
287 struct nilfs_transaction_info ti
;
290 if (copy_from_user(&argv
, argp
, sizeof(argv
)))
293 nilfs_transaction_begin(inode
->i_sb
, &ti
, 0);
294 ret
= nilfs_ioctl_wrap_copy(nilfs
, &argv
, _IOC_DIR(cmd
),
295 nilfs_ioctl_do_get_bdescs
);
296 nilfs_transaction_end(inode
->i_sb
, 0);
298 if (copy_to_user(argp
, &argv
, sizeof(argv
)))
303 static int nilfs_ioctl_move_inode_block(struct inode
*inode
,
304 struct nilfs_vdesc
*vdesc
,
305 struct list_head
*buffers
)
307 struct buffer_head
*bh
;
310 if (vdesc
->vd_flags
== 0)
311 ret
= nilfs_gccache_submit_read_data(
312 inode
, vdesc
->vd_offset
, vdesc
->vd_blocknr
,
313 vdesc
->vd_vblocknr
, &bh
);
315 ret
= nilfs_gccache_submit_read_node(
316 inode
, vdesc
->vd_blocknr
, vdesc
->vd_vblocknr
, &bh
);
318 if (unlikely(ret
< 0)) {
321 "%s: invalid virtual block address (%s): "
322 "ino=%llu, cno=%llu, offset=%llu, "
323 "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
);
332 bh
->b_private
= vdesc
;
333 list_add_tail(&bh
->b_assoc_buffers
, buffers
);
338 nilfs_ioctl_do_move_blocks(struct the_nilfs
*nilfs
, int index
, int flags
,
339 void *buf
, size_t size
, size_t nmembs
)
342 struct nilfs_vdesc
*vdesc
;
343 struct buffer_head
*bh
, *n
;
349 for (i
= 0, vdesc
= buf
; i
< nmembs
; ) {
352 inode
= nilfs_gc_iget(nilfs
, ino
, cno
);
353 if (unlikely(inode
== NULL
)) {
358 ret
= nilfs_ioctl_move_inode_block(inode
, vdesc
,
360 if (unlikely(ret
< 0))
363 } while (++i
< nmembs
&&
364 vdesc
->vd_ino
== ino
&& vdesc
->vd_cno
== cno
);
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 if (ret
== -EEXIST
) {
371 vdesc
= bh
->b_private
;
373 "%s: conflicting %s buffer: "
374 "ino=%llu, cno=%llu, offset=%llu, "
375 "blocknr=%llu, vblocknr=%llu\n",
377 vdesc
->vd_flags
? "node" : "data",
378 (unsigned long long)vdesc
->vd_ino
,
379 (unsigned long long)vdesc
->vd_cno
,
380 (unsigned long long)vdesc
->vd_offset
,
381 (unsigned long long)vdesc
->vd_blocknr
,
382 (unsigned long long)vdesc
->vd_vblocknr
);
386 list_del_init(&bh
->b_assoc_buffers
);
387 bh
->b_private
= NULL
;
393 list_for_each_entry_safe(bh
, n
, &buffers
, b_assoc_buffers
) {
394 list_del_init(&bh
->b_assoc_buffers
);
395 bh
->b_private
= NULL
;
401 static inline int nilfs_ioctl_move_blocks(struct the_nilfs
*nilfs
,
402 struct nilfs_argv
*argv
,
405 return nilfs_ioctl_wrap_copy(nilfs
, argv
, dir
,
406 nilfs_ioctl_do_move_blocks
);
410 nilfs_ioctl_do_delete_checkpoints(struct the_nilfs
*nilfs
, int index
,
411 int flags
, void *buf
, size_t size
,
414 struct inode
*cpfile
= nilfs
->ns_cpfile
;
415 struct nilfs_period
*periods
= buf
;
418 for (i
= 0; i
< nmembs
; i
++) {
419 ret
= nilfs_cpfile_delete_checkpoints(
420 cpfile
, periods
[i
].p_start
, periods
[i
].p_end
);
427 static inline int nilfs_ioctl_delete_checkpoints(struct the_nilfs
*nilfs
,
428 struct nilfs_argv
*argv
,
431 return nilfs_ioctl_wrap_copy(nilfs
, argv
, dir
,
432 nilfs_ioctl_do_delete_checkpoints
);
436 nilfs_ioctl_do_free_vblocknrs(struct the_nilfs
*nilfs
, int index
, int flags
,
437 void *buf
, size_t size
, size_t nmembs
)
439 int ret
= nilfs_dat_freev(nilfs_dat_inode(nilfs
), buf
, nmembs
);
441 return (ret
< 0) ? ret
: nmembs
;
444 static inline int nilfs_ioctl_free_vblocknrs(struct the_nilfs
*nilfs
,
445 struct nilfs_argv
*argv
,
448 return nilfs_ioctl_wrap_copy(nilfs
, argv
, dir
,
449 nilfs_ioctl_do_free_vblocknrs
);
453 nilfs_ioctl_do_mark_blocks_dirty(struct the_nilfs
*nilfs
, int index
, int flags
,
454 void *buf
, size_t size
, size_t nmembs
)
456 struct inode
*dat
= nilfs_dat_inode(nilfs
);
457 struct nilfs_bmap
*bmap
= NILFS_I(dat
)->i_bmap
;
458 struct nilfs_bdesc
*bdescs
= buf
;
461 for (i
= 0; i
< nmembs
; i
++) {
462 /* XXX: use macro or inline func to check liveness */
463 ret
= nilfs_bmap_lookup_at_level(bmap
,
465 bdescs
[i
].bd_level
+ 1,
466 &bdescs
[i
].bd_blocknr
);
470 bdescs
[i
].bd_blocknr
= 0;
472 if (bdescs
[i
].bd_blocknr
!= bdescs
[i
].bd_oblocknr
)
473 /* skip dead block */
475 if (bdescs
[i
].bd_level
== 0) {
476 ret
= nilfs_mdt_mark_block_dirty(dat
,
477 bdescs
[i
].bd_offset
);
479 BUG_ON(ret
== -ENOENT
);
483 ret
= nilfs_bmap_mark(bmap
, bdescs
[i
].bd_offset
,
486 BUG_ON(ret
== -ENOENT
);
494 static inline int nilfs_ioctl_mark_blocks_dirty(struct the_nilfs
*nilfs
,
495 struct nilfs_argv
*argv
,
498 return nilfs_ioctl_wrap_copy(nilfs
, argv
, dir
,
499 nilfs_ioctl_do_mark_blocks_dirty
);
503 nilfs_ioctl_do_free_segments(struct the_nilfs
*nilfs
, int index
, int flags
,
504 void *buf
, size_t size
, size_t nmembs
)
506 struct nilfs_sb_info
*sbi
= nilfs_get_writer(nilfs
);
510 ret
= nilfs_segctor_add_segments_to_be_freed(
511 NILFS_SC(sbi
), buf
, nmembs
);
512 nilfs_put_writer(nilfs
);
514 return (ret
< 0) ? ret
: nmembs
;
517 static inline int nilfs_ioctl_free_segments(struct the_nilfs
*nilfs
,
518 struct nilfs_argv
*argv
,
521 return nilfs_ioctl_wrap_copy(nilfs
, argv
, dir
,
522 nilfs_ioctl_do_free_segments
);
525 int nilfs_ioctl_prepare_clean_segments(struct the_nilfs
*nilfs
,
528 struct nilfs_argv argv
[5];
531 if (copy_from_user(argv
, argp
, sizeof(argv
)))
535 ret
= nilfs_ioctl_move_blocks(nilfs
, &argv
[0], dir
);
538 ret
= nilfs_ioctl_delete_checkpoints(nilfs
, &argv
[1], dir
);
541 ret
= nilfs_ioctl_free_vblocknrs(nilfs
, &argv
[2], dir
);
544 ret
= nilfs_ioctl_mark_blocks_dirty(nilfs
, &argv
[3], dir
);
547 ret
= nilfs_ioctl_free_segments(nilfs
, &argv
[4], dir
);
554 BUG(); /* XXX: not implemented yet */
556 BUG();/* XXX: not implemented yet */
558 BUG();/* XXX: not implemented yet */
560 nilfs_remove_all_gcinode(nilfs
);
564 static int nilfs_ioctl_clean_segments(struct inode
*inode
, struct file
*filp
,
565 unsigned int cmd
, void __user
*argp
)
569 if (!capable(CAP_SYS_ADMIN
))
572 ret
= nilfs_clean_segments(inode
->i_sb
, argp
);
573 clear_nilfs_cond_nongc_write(NILFS_SB(inode
->i_sb
)->s_nilfs
);
577 static int nilfs_ioctl_test_cond(struct the_nilfs
*nilfs
, int cond
)
579 return (cond
& NILFS_TIMEDWAIT_SEG_WRITE
) &&
580 nilfs_cond_nongc_write(nilfs
);
583 static void nilfs_ioctl_clear_cond(struct the_nilfs
*nilfs
, int cond
)
585 if (cond
& NILFS_TIMEDWAIT_SEG_WRITE
)
586 clear_nilfs_cond_nongc_write(nilfs
);
589 static int nilfs_ioctl_timedwait(struct inode
*inode
, struct file
*filp
,
590 unsigned int cmd
, void __user
*argp
)
592 struct the_nilfs
*nilfs
= NILFS_SB(inode
->i_sb
)->s_nilfs
;
593 struct nilfs_wait_cond wc
;
596 if (!capable(CAP_SYS_ADMIN
))
598 if (copy_from_user(&wc
, argp
, sizeof(wc
)))
603 wait_event_interruptible_timeout(
604 nilfs
->ns_cleanerd_wq
,
605 nilfs_ioctl_test_cond(nilfs
, wc
.wc_cond
),
606 timespec_to_jiffies(&wc
.wc_timeout
)) :
607 wait_event_interruptible(
608 nilfs
->ns_cleanerd_wq
,
609 nilfs_ioctl_test_cond(nilfs
, wc
.wc_cond
));
611 nilfs_ioctl_clear_cond(nilfs
, wc
.wc_cond
);
614 jiffies_to_timespec(ret
, &wc
.wc_timeout
);
615 if (copy_to_user(argp
, &wc
, sizeof(wc
)))
622 return wc
.wc_flags
? -ETIME
: 0;
625 static int nilfs_ioctl_sync(struct inode
*inode
, struct file
*filp
,
626 unsigned int cmd
, void __user
*argp
)
631 ret
= nilfs_construct_segment(inode
->i_sb
);
636 cno
= NILFS_SB(inode
->i_sb
)->s_nilfs
->ns_cno
- 1;
637 if (copy_to_user(argp
, &cno
, sizeof(cno
)))
643 int nilfs_ioctl(struct inode
*inode
, struct file
*filp
, unsigned int cmd
,
646 void __user
*argp
= (void * __user
*)arg
;
649 case NILFS_IOCTL_CHANGE_CPMODE
:
650 return nilfs_ioctl_change_cpmode(inode
, filp
, cmd
, argp
);
651 case NILFS_IOCTL_DELETE_CHECKPOINT
:
652 return nilfs_ioctl_delete_checkpoint(inode
, filp
, cmd
, argp
);
653 case NILFS_IOCTL_GET_CPINFO
:
654 return nilfs_ioctl_get_cpinfo(inode
, filp
, cmd
, argp
);
655 case NILFS_IOCTL_GET_CPSTAT
:
656 return nilfs_ioctl_get_cpstat(inode
, filp
, cmd
, argp
);
657 case NILFS_IOCTL_GET_SUINFO
:
658 return nilfs_ioctl_get_suinfo(inode
, filp
, cmd
, argp
);
659 case NILFS_IOCTL_GET_SUSTAT
:
660 return nilfs_ioctl_get_sustat(inode
, filp
, cmd
, argp
);
661 case NILFS_IOCTL_GET_VINFO
:
662 /* XXX: rename to ??? */
663 return nilfs_ioctl_get_vinfo(inode
, filp
, cmd
, argp
);
664 case NILFS_IOCTL_GET_BDESCS
:
665 return nilfs_ioctl_get_bdescs(inode
, filp
, cmd
, argp
);
666 case NILFS_IOCTL_CLEAN_SEGMENTS
:
667 return nilfs_ioctl_clean_segments(inode
, filp
, cmd
, argp
);
668 case NILFS_IOCTL_TIMEDWAIT
:
669 return nilfs_ioctl_timedwait(inode
, filp
, cmd
, argp
);
670 case NILFS_IOCTL_SYNC
:
671 return nilfs_ioctl_sync(inode
, filp
, cmd
, argp
);
679 #include <linux/compat.h>
681 static int nilfs_compat_locked_ioctl(struct inode
*inode
, struct file
*filp
,
682 unsigned int cmd
, unsigned long arg
)
687 ret
= nilfs_ioctl(inode
, filp
, cmd
, arg
);
693 nilfs_compat_ioctl_uargv32_to_uargv(struct nilfs_argv32 __user
*uargv32
,
694 struct nilfs_argv __user
*uargv
)
697 compat_size_t nmembs
, size
;
698 compat_int_t index
, flags
;
700 if (get_user(base
, &uargv32
->v_base
) ||
701 put_user(compat_ptr(base
), &uargv
->v_base
) ||
702 get_user(nmembs
, &uargv32
->v_nmembs
) ||
703 put_user(nmembs
, &uargv
->v_nmembs
) ||
704 get_user(size
, &uargv32
->v_size
) ||
705 put_user(size
, &uargv
->v_size
) ||
706 get_user(index
, &uargv32
->v_index
) ||
707 put_user(index
, &uargv
->v_index
) ||
708 get_user(flags
, &uargv32
->v_flags
) ||
709 put_user(flags
, &uargv
->v_flags
))
715 nilfs_compat_ioctl_uargv_to_uargv32(struct nilfs_argv __user
*uargv
,
716 struct nilfs_argv32 __user
*uargv32
)
720 if (get_user(nmembs
, &uargv
->v_nmembs
) ||
721 put_user(nmembs
, &uargv32
->v_nmembs
))
727 nilfs_compat_ioctl_get_by_argv(struct inode
*inode
, struct file
*filp
,
728 unsigned int cmd
, unsigned long arg
)
730 struct nilfs_argv __user
*uargv
;
731 struct nilfs_argv32 __user
*uargv32
;
734 uargv
= compat_alloc_user_space(sizeof(struct nilfs_argv
));
735 uargv32
= compat_ptr(arg
);
736 ret
= nilfs_compat_ioctl_uargv32_to_uargv(uargv32
, uargv
);
740 ret
= nilfs_compat_locked_ioctl(inode
, filp
, cmd
, (unsigned long)uargv
);
744 return nilfs_compat_ioctl_uargv_to_uargv32(uargv
, uargv32
);
748 nilfs_compat_ioctl_change_cpmode(struct inode
*inode
, struct file
*filp
,
749 unsigned int cmd
, unsigned long arg
)
751 struct nilfs_cpmode __user
*ucpmode
;
752 struct nilfs_cpmode32 __user
*ucpmode32
;
755 ucpmode
= compat_alloc_user_space(sizeof(struct nilfs_cpmode
));
756 ucpmode32
= compat_ptr(arg
);
757 if (copy_in_user(&ucpmode
->cm_cno
, &ucpmode32
->cm_cno
,
759 get_user(mode
, &ucpmode32
->cm_mode
) ||
760 put_user(mode
, &ucpmode
->cm_mode
))
763 return nilfs_compat_locked_ioctl(
764 inode
, filp
, cmd
, (unsigned long)ucpmode
);
769 nilfs_compat_ioctl_delete_checkpoint(struct inode
*inode
, struct file
*filp
,
770 unsigned int cmd
, unsigned long arg
)
772 return nilfs_compat_locked_ioctl(inode
, filp
, cmd
, arg
);
776 nilfs_compat_ioctl_get_cpinfo(struct inode
*inode
, struct file
*filp
,
777 unsigned int cmd
, unsigned long arg
)
779 return nilfs_compat_ioctl_get_by_argv(inode
, filp
, cmd
, arg
);
783 nilfs_compat_ioctl_get_cpstat(struct inode
*inode
, struct file
*filp
,
784 unsigned int cmd
, unsigned long arg
)
786 return nilfs_compat_locked_ioctl(inode
, filp
, cmd
, arg
);
790 nilfs_compat_ioctl_get_suinfo(struct inode
*inode
, struct file
*filp
,
791 unsigned int cmd
, unsigned long arg
)
793 return nilfs_compat_ioctl_get_by_argv(inode
, filp
, cmd
, arg
);
797 nilfs_compat_ioctl_get_sustat(struct inode
*inode
, struct file
*filp
,
798 unsigned int cmd
, unsigned long arg
)
800 struct nilfs_sustat __user
*usustat
;
801 struct nilfs_sustat32 __user
*usustat32
;
802 time_t ctime
, nongc_ctime
;
805 usustat
= compat_alloc_user_space(sizeof(struct nilfs_sustat
));
806 ret
= nilfs_compat_locked_ioctl(inode
, filp
, cmd
,
807 (unsigned long)usustat
);
811 usustat32
= compat_ptr(arg
);
812 if (copy_in_user(&usustat32
->ss_nsegs
, &usustat
->ss_nsegs
,
814 copy_in_user(&usustat32
->ss_ncleansegs
, &usustat
->ss_ncleansegs
,
816 copy_in_user(&usustat32
->ss_ndirtysegs
, &usustat
->ss_ndirtysegs
,
818 get_user(ctime
, &usustat
->ss_ctime
) ||
819 put_user(ctime
, &usustat32
->ss_ctime
) ||
820 get_user(nongc_ctime
, &usustat
->ss_nongc_ctime
) ||
821 put_user(nongc_ctime
, &usustat32
->ss_nongc_ctime
))
827 nilfs_compat_ioctl_get_vinfo(struct inode
*inode
, struct file
*filp
,
828 unsigned int cmd
, unsigned long arg
)
830 return nilfs_compat_ioctl_get_by_argv(inode
, filp
, cmd
, arg
);
834 nilfs_compat_ioctl_get_bdescs(struct inode
*inode
, struct file
*filp
,
835 unsigned int cmd
, unsigned long arg
)
837 return nilfs_compat_ioctl_get_by_argv(inode
, filp
, cmd
, arg
);
841 nilfs_compat_ioctl_clean_segments(struct inode
*inode
, struct file
*filp
,
842 unsigned int cmd
, unsigned long arg
)
844 struct nilfs_argv __user
*uargv
;
845 struct nilfs_argv32 __user
*uargv32
;
848 uargv
= compat_alloc_user_space(sizeof(struct nilfs_argv
) * 5);
849 uargv32
= compat_ptr(arg
);
850 for (i
= 0; i
< 5; i
++) {
851 ret
= nilfs_compat_ioctl_uargv32_to_uargv(&uargv32
[i
],
856 return nilfs_compat_locked_ioctl(
857 inode
, filp
, cmd
, (unsigned long)uargv
);
861 nilfs_compat_ioctl_timedwait(struct inode
*inode
, struct file
*filp
,
862 unsigned int cmd
, unsigned long arg
)
864 struct nilfs_wait_cond __user
*uwcond
;
865 struct nilfs_wait_cond32 __user
*uwcond32
;
867 int cond
, flags
, ret
;
869 uwcond
= compat_alloc_user_space(sizeof(struct nilfs_wait_cond
));
870 uwcond32
= compat_ptr(arg
);
871 if (get_user(cond
, &uwcond32
->wc_cond
) ||
872 put_user(cond
, &uwcond
->wc_cond
) ||
873 get_user(flags
, &uwcond32
->wc_flags
) ||
874 put_user(flags
, &uwcond
->wc_flags
) ||
875 get_user(ts
.tv_sec
, &uwcond32
->wc_timeout
.tv_sec
) ||
876 get_user(ts
.tv_nsec
, &uwcond32
->wc_timeout
.tv_nsec
) ||
877 put_user(ts
.tv_sec
, &uwcond
->wc_timeout
.tv_sec
) ||
878 put_user(ts
.tv_nsec
, &uwcond
->wc_timeout
.tv_nsec
))
881 ret
= nilfs_compat_locked_ioctl(inode
, filp
, cmd
,
882 (unsigned long)uwcond
);
886 if (get_user(ts
.tv_sec
, &uwcond
->wc_timeout
.tv_sec
) ||
887 get_user(ts
.tv_nsec
, &uwcond
->wc_timeout
.tv_nsec
) ||
888 put_user(ts
.tv_sec
, &uwcond32
->wc_timeout
.tv_sec
) ||
889 put_user(ts
.tv_nsec
, &uwcond32
->wc_timeout
.tv_nsec
))
895 static int nilfs_compat_ioctl_sync(struct inode
*inode
, struct file
*filp
,
896 unsigned int cmd
, unsigned long arg
)
898 return nilfs_compat_locked_ioctl(inode
, filp
, cmd
, arg
);
901 long nilfs_compat_ioctl(struct file
*filp
, unsigned int cmd
, unsigned long arg
)
903 struct inode
*inode
= filp
->f_dentry
->d_inode
;
906 case NILFS_IOCTL32_CHANGE_CPMODE
:
907 return nilfs_compat_ioctl_change_cpmode(
908 inode
, filp
, NILFS_IOCTL_CHANGE_CPMODE
, arg
);
909 case NILFS_IOCTL_DELETE_CHECKPOINT
:
910 return nilfs_compat_ioctl_delete_checkpoint(
911 inode
, filp
, cmd
, arg
);
912 case NILFS_IOCTL32_GET_CPINFO
:
913 return nilfs_compat_ioctl_get_cpinfo(
914 inode
, filp
, NILFS_IOCTL_GET_CPINFO
, arg
);
915 case NILFS_IOCTL_GET_CPSTAT
:
916 return nilfs_compat_ioctl_get_cpstat(inode
, filp
, cmd
, arg
);
917 case NILFS_IOCTL32_GET_SUINFO
:
918 return nilfs_compat_ioctl_get_suinfo(
919 inode
, filp
, NILFS_IOCTL_GET_SUINFO
, arg
);
920 case NILFS_IOCTL32_GET_SUSTAT
:
921 return nilfs_compat_ioctl_get_sustat(
922 inode
, filp
, NILFS_IOCTL_GET_SUSTAT
, arg
);
923 case NILFS_IOCTL32_GET_VINFO
:
924 return nilfs_compat_ioctl_get_vinfo(
925 inode
, filp
, NILFS_IOCTL_GET_VINFO
, arg
);
926 case NILFS_IOCTL32_GET_BDESCS
:
927 return nilfs_compat_ioctl_get_bdescs(
928 inode
, filp
, NILFS_IOCTL_GET_BDESCS
, arg
);
929 case NILFS_IOCTL32_CLEAN_SEGMENTS
:
930 return nilfs_compat_ioctl_clean_segments(
931 inode
, filp
, NILFS_IOCTL_CLEAN_SEGMENTS
, arg
);
932 case NILFS_IOCTL32_TIMEDWAIT
:
933 return nilfs_compat_ioctl_timedwait(
934 inode
, filp
, NILFS_IOCTL_TIMEDWAIT
, arg
);
935 case NILFS_IOCTL_SYNC
:
936 return nilfs_compat_ioctl_sync(inode
, filp
, cmd
, arg
);