fs/nilfs2: fix integer overflow in nilfs_ioctl_wrap_copy()
[deliverable/linux.git] / fs / nilfs2 / ioctl.c
CommitLineData
7942b919
KS
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>
5a0e3ad6 25#include <linux/slab.h>
7942b919
KS
26#include <linux/capability.h> /* capable() */
27#include <linux/uaccess.h> /* copy_from_user(), copy_to_user() */
4f6b8288 28#include <linux/vmalloc.h>
828b1c50 29#include <linux/compat.h> /* compat_ptr() */
2a79f17e 30#include <linux/mount.h> /* mnt_want_write_file(), mnt_drop_write_file() */
ae191838 31#include <linux/buffer_head.h>
7942b919
KS
32#include <linux/nilfs2_fs.h>
33#include "nilfs.h"
34#include "segment.h"
35#include "bmap.h"
36#include "cpfile.h"
37#include "sufile.h"
38#include "dat.h"
39
40
7942b919
KS
41static int nilfs_ioctl_wrap_copy(struct the_nilfs *nilfs,
42 struct nilfs_argv *argv, int dir,
43 ssize_t (*dofunc)(struct the_nilfs *,
b028fcfc 44 __u64 *, int,
7942b919
KS
45 void *, size_t, size_t))
46{
47 void *buf;
dc498d09 48 void __user *base = (void __user *)(unsigned long)argv->v_base;
3358b4aa 49 size_t maxmembs, total, n;
7942b919
KS
50 ssize_t nr;
51 int ret, i;
b028fcfc 52 __u64 pos, ppos;
7942b919
KS
53
54 if (argv->v_nmembs == 0)
55 return 0;
56
3358b4aa
RK
57 if (argv->v_size > PAGE_SIZE)
58 return -EINVAL;
59
4b15d617
WF
60 /*
61 * Reject pairs of a start item position (argv->v_index) and a
62 * total count (argv->v_nmembs) which leads position 'pos' to
63 * overflow by the increment at the end of the loop.
64 */
65 if (argv->v_index > ~(__u64)0 - argv->v_nmembs)
66 return -EINVAL;
67
3358b4aa
RK
68 buf = (void *)__get_free_pages(GFP_NOFS, 0);
69 if (unlikely(!buf))
7942b919 70 return -ENOMEM;
3358b4aa 71 maxmembs = PAGE_SIZE / argv->v_size;
7942b919
KS
72
73 ret = 0;
74 total = 0;
b028fcfc 75 pos = argv->v_index;
7942b919
KS
76 for (i = 0; i < argv->v_nmembs; i += n) {
77 n = (argv->v_nmembs - i < maxmembs) ?
78 argv->v_nmembs - i : maxmembs;
79 if ((dir & _IOC_WRITE) &&
dc498d09
RK
80 copy_from_user(buf, base + argv->v_size * i,
81 argv->v_size * n)) {
7942b919
KS
82 ret = -EFAULT;
83 break;
84 }
b028fcfc 85 ppos = pos;
8acfbf09 86 nr = dofunc(nilfs, &pos, argv->v_flags, buf, argv->v_size,
b028fcfc 87 n);
7942b919
KS
88 if (nr < 0) {
89 ret = nr;
90 break;
91 }
92 if ((dir & _IOC_READ) &&
dc498d09
RK
93 copy_to_user(base + argv->v_size * i, buf,
94 argv->v_size * nr)) {
7942b919
KS
95 ret = -EFAULT;
96 break;
97 }
98 total += nr;
b028fcfc
RK
99 if ((size_t)nr < n)
100 break;
101 if (pos == ppos)
102 pos += n;
7942b919
KS
103 }
104 argv->v_nmembs = total;
105
3358b4aa 106 free_pages((unsigned long)buf, 0);
7942b919
KS
107 return ret;
108}
109
cde98f0f
RK
110static int nilfs_ioctl_getflags(struct inode *inode, void __user *argp)
111{
112 unsigned int flags = NILFS_I(inode)->i_flags & FS_FL_USER_VISIBLE;
113
114 return put_user(flags, (int __user *)argp);
115}
116
117static int nilfs_ioctl_setflags(struct inode *inode, struct file *filp,
118 void __user *argp)
119{
120 struct nilfs_transaction_info ti;
121 unsigned int flags, oldflags;
122 int ret;
123
2e149670 124 if (!inode_owner_or_capable(inode))
cde98f0f
RK
125 return -EACCES;
126
127 if (get_user(flags, (int __user *)argp))
128 return -EFAULT;
129
a561be71 130 ret = mnt_want_write_file(filp);
cde98f0f
RK
131 if (ret)
132 return ret;
133
134 flags = nilfs_mask_flags(inode->i_mode, flags);
135
136 mutex_lock(&inode->i_mutex);
137
138 oldflags = NILFS_I(inode)->i_flags;
139
140 /*
141 * The IMMUTABLE and APPEND_ONLY flags can only be changed by the
142 * relevant capability.
143 */
144 ret = -EPERM;
145 if (((flags ^ oldflags) & (FS_APPEND_FL | FS_IMMUTABLE_FL)) &&
146 !capable(CAP_LINUX_IMMUTABLE))
147 goto out;
148
149 ret = nilfs_transaction_begin(inode->i_sb, &ti, 0);
150 if (ret)
151 goto out;
152
153 NILFS_I(inode)->i_flags = (oldflags & ~FS_FL_USER_MODIFIABLE) |
154 (flags & FS_FL_USER_MODIFIABLE);
155
156 nilfs_set_inode_flags(inode);
157 inode->i_ctime = CURRENT_TIME;
158 if (IS_SYNC(inode))
159 nilfs_set_transaction_flag(NILFS_TI_SYNC);
160
161 nilfs_mark_inode_dirty(inode);
162 ret = nilfs_transaction_commit(inode->i_sb);
163out:
164 mutex_unlock(&inode->i_mutex);
2a79f17e 165 mnt_drop_write_file(filp);
cde98f0f
RK
166 return ret;
167}
168
169static int nilfs_ioctl_getversion(struct inode *inode, void __user *argp)
170{
171 return put_user(inode->i_generation, (int __user *)argp);
172}
173
7942b919
KS
174static int nilfs_ioctl_change_cpmode(struct inode *inode, struct file *filp,
175 unsigned int cmd, void __user *argp)
176{
e3154e97 177 struct the_nilfs *nilfs = inode->i_sb->s_fs_info;
7942b919
KS
178 struct nilfs_transaction_info ti;
179 struct nilfs_cpmode cpmode;
180 int ret;
181
182 if (!capable(CAP_SYS_ADMIN))
183 return -EPERM;
7512487e 184
a561be71 185 ret = mnt_want_write_file(filp);
7512487e
RK
186 if (ret)
187 return ret;
188
189 ret = -EFAULT;
7942b919 190 if (copy_from_user(&cpmode, argp, sizeof(cpmode)))
7512487e 191 goto out;
7942b919 192
572d8b39 193 mutex_lock(&nilfs->ns_snapshot_mount_mutex);
7512487e 194
7942b919
KS
195 nilfs_transaction_begin(inode->i_sb, &ti, 0);
196 ret = nilfs_cpfile_change_cpmode(
e3154e97 197 nilfs->ns_cpfile, cpmode.cm_cno, cpmode.cm_mode);
7512487e 198 if (unlikely(ret < 0))
47420c79 199 nilfs_transaction_abort(inode->i_sb);
7512487e
RK
200 else
201 nilfs_transaction_commit(inode->i_sb); /* never fails */
202
572d8b39 203 mutex_unlock(&nilfs->ns_snapshot_mount_mutex);
7512487e 204out:
2a79f17e 205 mnt_drop_write_file(filp);
7942b919
KS
206 return ret;
207}
208
209static int
210nilfs_ioctl_delete_checkpoint(struct inode *inode, struct file *filp,
211 unsigned int cmd, void __user *argp)
212{
e3154e97 213 struct the_nilfs *nilfs = inode->i_sb->s_fs_info;
7942b919
KS
214 struct nilfs_transaction_info ti;
215 __u64 cno;
216 int ret;
217
218 if (!capable(CAP_SYS_ADMIN))
219 return -EPERM;
7512487e 220
a561be71 221 ret = mnt_want_write_file(filp);
7512487e
RK
222 if (ret)
223 return ret;
224
225 ret = -EFAULT;
7942b919 226 if (copy_from_user(&cno, argp, sizeof(cno)))
7512487e 227 goto out;
7942b919
KS
228
229 nilfs_transaction_begin(inode->i_sb, &ti, 0);
e3154e97 230 ret = nilfs_cpfile_delete_checkpoint(nilfs->ns_cpfile, cno);
7512487e 231 if (unlikely(ret < 0))
47420c79 232 nilfs_transaction_abort(inode->i_sb);
7512487e
RK
233 else
234 nilfs_transaction_commit(inode->i_sb); /* never fails */
235out:
2a79f17e 236 mnt_drop_write_file(filp);
7942b919
KS
237 return ret;
238}
239
240static ssize_t
b028fcfc 241nilfs_ioctl_do_get_cpinfo(struct the_nilfs *nilfs, __u64 *posp, int flags,
7942b919
KS
242 void *buf, size_t size, size_t nmembs)
243{
7942b919
KS
244 int ret;
245
47420c79 246 down_read(&nilfs->ns_segctor_sem);
47eb6b9c 247 ret = nilfs_cpfile_get_cpinfo(nilfs->ns_cpfile, posp, flags, buf,
003ff182 248 size, nmembs);
47420c79 249 up_read(&nilfs->ns_segctor_sem);
7942b919
KS
250 return ret;
251}
252
253static int nilfs_ioctl_get_cpstat(struct inode *inode, struct file *filp,
254 unsigned int cmd, void __user *argp)
255{
e3154e97 256 struct the_nilfs *nilfs = inode->i_sb->s_fs_info;
7942b919 257 struct nilfs_cpstat cpstat;
7942b919
KS
258 int ret;
259
47420c79
RK
260 down_read(&nilfs->ns_segctor_sem);
261 ret = nilfs_cpfile_get_stat(nilfs->ns_cpfile, &cpstat);
262 up_read(&nilfs->ns_segctor_sem);
7942b919
KS
263 if (ret < 0)
264 return ret;
265
266 if (copy_to_user(argp, &cpstat, sizeof(cpstat)))
267 ret = -EFAULT;
268 return ret;
269}
270
271static ssize_t
b028fcfc 272nilfs_ioctl_do_get_suinfo(struct the_nilfs *nilfs, __u64 *posp, int flags,
7942b919
KS
273 void *buf, size_t size, size_t nmembs)
274{
7942b919
KS
275 int ret;
276
47420c79 277 down_read(&nilfs->ns_segctor_sem);
003ff182
RK
278 ret = nilfs_sufile_get_suinfo(nilfs->ns_sufile, *posp, buf, size,
279 nmembs);
47420c79 280 up_read(&nilfs->ns_segctor_sem);
7942b919
KS
281 return ret;
282}
283
284static int nilfs_ioctl_get_sustat(struct inode *inode, struct file *filp,
285 unsigned int cmd, void __user *argp)
286{
e3154e97 287 struct the_nilfs *nilfs = inode->i_sb->s_fs_info;
7942b919 288 struct nilfs_sustat sustat;
7942b919
KS
289 int ret;
290
47420c79
RK
291 down_read(&nilfs->ns_segctor_sem);
292 ret = nilfs_sufile_get_stat(nilfs->ns_sufile, &sustat);
293 up_read(&nilfs->ns_segctor_sem);
7942b919
KS
294 if (ret < 0)
295 return ret;
296
297 if (copy_to_user(argp, &sustat, sizeof(sustat)))
298 ret = -EFAULT;
299 return ret;
300}
301
302static ssize_t
b028fcfc 303nilfs_ioctl_do_get_vinfo(struct the_nilfs *nilfs, __u64 *posp, int flags,
7942b919
KS
304 void *buf, size_t size, size_t nmembs)
305{
7942b919
KS
306 int ret;
307
47420c79 308 down_read(&nilfs->ns_segctor_sem);
365e215c 309 ret = nilfs_dat_get_vinfo(nilfs->ns_dat, buf, size, nmembs);
47420c79 310 up_read(&nilfs->ns_segctor_sem);
7942b919
KS
311 return ret;
312}
313
314static ssize_t
b028fcfc 315nilfs_ioctl_do_get_bdescs(struct the_nilfs *nilfs, __u64 *posp, int flags,
7942b919
KS
316 void *buf, size_t size, size_t nmembs)
317{
365e215c 318 struct nilfs_bmap *bmap = NILFS_I(nilfs->ns_dat)->i_bmap;
7942b919
KS
319 struct nilfs_bdesc *bdescs = buf;
320 int ret, i;
321
47eb6b9c 322 down_read(&nilfs->ns_segctor_sem);
7942b919
KS
323 for (i = 0; i < nmembs; i++) {
324 ret = nilfs_bmap_lookup_at_level(bmap,
325 bdescs[i].bd_offset,
326 bdescs[i].bd_level + 1,
327 &bdescs[i].bd_blocknr);
328 if (ret < 0) {
47eb6b9c
RK
329 if (ret != -ENOENT) {
330 up_read(&nilfs->ns_segctor_sem);
7942b919 331 return ret;
47eb6b9c 332 }
7942b919
KS
333 bdescs[i].bd_blocknr = 0;
334 }
335 }
47eb6b9c 336 up_read(&nilfs->ns_segctor_sem);
7942b919
KS
337 return nmembs;
338}
339
340static int nilfs_ioctl_get_bdescs(struct inode *inode, struct file *filp,
341 unsigned int cmd, void __user *argp)
342{
e3154e97 343 struct the_nilfs *nilfs = inode->i_sb->s_fs_info;
7942b919 344 struct nilfs_argv argv;
7942b919
KS
345 int ret;
346
347 if (copy_from_user(&argv, argp, sizeof(argv)))
348 return -EFAULT;
349
83aca8f4
RK
350 if (argv.v_size != sizeof(struct nilfs_bdesc))
351 return -EINVAL;
352
7942b919
KS
353 ret = nilfs_ioctl_wrap_copy(nilfs, &argv, _IOC_DIR(cmd),
354 nilfs_ioctl_do_get_bdescs);
47420c79
RK
355 if (ret < 0)
356 return ret;
7942b919
KS
357
358 if (copy_to_user(argp, &argv, sizeof(argv)))
359 ret = -EFAULT;
360 return ret;
361}
362
363static int nilfs_ioctl_move_inode_block(struct inode *inode,
364 struct nilfs_vdesc *vdesc,
365 struct list_head *buffers)
366{
367 struct buffer_head *bh;
368 int ret;
369
370 if (vdesc->vd_flags == 0)
371 ret = nilfs_gccache_submit_read_data(
372 inode, vdesc->vd_offset, vdesc->vd_blocknr,
373 vdesc->vd_vblocknr, &bh);
374 else
375 ret = nilfs_gccache_submit_read_node(
376 inode, vdesc->vd_blocknr, vdesc->vd_vblocknr, &bh);
377
378 if (unlikely(ret < 0)) {
379 if (ret == -ENOENT)
380 printk(KERN_CRIT
381 "%s: invalid virtual block address (%s): "
382 "ino=%llu, cno=%llu, offset=%llu, "
383 "blocknr=%llu, vblocknr=%llu\n",
384 __func__, vdesc->vd_flags ? "node" : "data",
385 (unsigned long long)vdesc->vd_ino,
386 (unsigned long long)vdesc->vd_cno,
387 (unsigned long long)vdesc->vd_offset,
388 (unsigned long long)vdesc->vd_blocknr,
389 (unsigned long long)vdesc->vd_vblocknr);
390 return ret;
391 }
5399dd1f
RK
392 if (unlikely(!list_empty(&bh->b_assoc_buffers))) {
393 printk(KERN_CRIT "%s: conflicting %s buffer: ino=%llu, "
394 "cno=%llu, offset=%llu, blocknr=%llu, vblocknr=%llu\n",
395 __func__, vdesc->vd_flags ? "node" : "data",
396 (unsigned long long)vdesc->vd_ino,
397 (unsigned long long)vdesc->vd_cno,
398 (unsigned long long)vdesc->vd_offset,
399 (unsigned long long)vdesc->vd_blocknr,
400 (unsigned long long)vdesc->vd_vblocknr);
401 brelse(bh);
402 return -EEXIST;
403 }
7942b919
KS
404 list_add_tail(&bh->b_assoc_buffers, buffers);
405 return 0;
406}
407
263d90ce 408static int nilfs_ioctl_move_blocks(struct super_block *sb,
4f6b8288 409 struct nilfs_argv *argv, void *buf)
7942b919 410{
4f6b8288 411 size_t nmembs = argv->v_nmembs;
e3154e97 412 struct the_nilfs *nilfs = sb->s_fs_info;
7942b919
KS
413 struct inode *inode;
414 struct nilfs_vdesc *vdesc;
415 struct buffer_head *bh, *n;
416 LIST_HEAD(buffers);
417 ino_t ino;
418 __u64 cno;
419 int i, ret;
420
421 for (i = 0, vdesc = buf; i < nmembs; ) {
422 ino = vdesc->vd_ino;
423 cno = vdesc->vd_cno;
263d90ce 424 inode = nilfs_iget_for_gc(sb, ino, cno);
103cfcf5
DC
425 if (IS_ERR(inode)) {
426 ret = PTR_ERR(inode);
7942b919
KS
427 goto failed;
428 }
947b10ae
RK
429 if (list_empty(&NILFS_I(inode)->i_dirty)) {
430 /*
431 * Add the inode to GC inode list. Garbage Collection
432 * is serialized and no two processes manipulate the
433 * list simultaneously.
434 */
435 igrab(inode);
436 list_add(&NILFS_I(inode)->i_dirty,
437 &nilfs->ns_gc_inodes);
438 }
439
7942b919
KS
440 do {
441 ret = nilfs_ioctl_move_inode_block(inode, vdesc,
442 &buffers);
263d90ce
RK
443 if (unlikely(ret < 0)) {
444 iput(inode);
7942b919 445 goto failed;
263d90ce 446 }
7942b919
KS
447 vdesc++;
448 } while (++i < nmembs &&
449 vdesc->vd_ino == ino && vdesc->vd_cno == cno);
263d90ce
RK
450
451 iput(inode); /* The inode still remains in GC inode list */
7942b919
KS
452 }
453
454 list_for_each_entry_safe(bh, n, &buffers, b_assoc_buffers) {
455 ret = nilfs_gccache_wait_and_mark_dirty(bh);
456 if (unlikely(ret < 0)) {
5399dd1f 457 WARN_ON(ret == -EEXIST);
7942b919
KS
458 goto failed;
459 }
460 list_del_init(&bh->b_assoc_buffers);
7942b919
KS
461 brelse(bh);
462 }
463 return nmembs;
464
465 failed:
466 list_for_each_entry_safe(bh, n, &buffers, b_assoc_buffers) {
467 list_del_init(&bh->b_assoc_buffers);
7942b919
KS
468 brelse(bh);
469 }
470 return ret;
471}
472
4f6b8288
RK
473static int nilfs_ioctl_delete_checkpoints(struct the_nilfs *nilfs,
474 struct nilfs_argv *argv, void *buf)
7942b919 475{
4f6b8288 476 size_t nmembs = argv->v_nmembs;
7942b919
KS
477 struct inode *cpfile = nilfs->ns_cpfile;
478 struct nilfs_period *periods = buf;
479 int ret, i;
480
481 for (i = 0; i < nmembs; i++) {
482 ret = nilfs_cpfile_delete_checkpoints(
483 cpfile, periods[i].p_start, periods[i].p_end);
484 if (ret < 0)
485 return ret;
486 }
487 return nmembs;
488}
489
4f6b8288
RK
490static int nilfs_ioctl_free_vblocknrs(struct the_nilfs *nilfs,
491 struct nilfs_argv *argv, void *buf)
7942b919 492{
4f6b8288
RK
493 size_t nmembs = argv->v_nmembs;
494 int ret;
7942b919 495
365e215c 496 ret = nilfs_dat_freev(nilfs->ns_dat, buf, nmembs);
7942b919
KS
497
498 return (ret < 0) ? ret : nmembs;
499}
500
4f6b8288
RK
501static int nilfs_ioctl_mark_blocks_dirty(struct the_nilfs *nilfs,
502 struct nilfs_argv *argv, void *buf)
7942b919 503{
4f6b8288 504 size_t nmembs = argv->v_nmembs;
365e215c 505 struct nilfs_bmap *bmap = NILFS_I(nilfs->ns_dat)->i_bmap;
7942b919
KS
506 struct nilfs_bdesc *bdescs = buf;
507 int ret, i;
508
509 for (i = 0; i < nmembs; i++) {
510 /* XXX: use macro or inline func to check liveness */
511 ret = nilfs_bmap_lookup_at_level(bmap,
512 bdescs[i].bd_offset,
513 bdescs[i].bd_level + 1,
514 &bdescs[i].bd_blocknr);
515 if (ret < 0) {
516 if (ret != -ENOENT)
517 return ret;
518 bdescs[i].bd_blocknr = 0;
519 }
520 if (bdescs[i].bd_blocknr != bdescs[i].bd_oblocknr)
521 /* skip dead block */
522 continue;
523 if (bdescs[i].bd_level == 0) {
365e215c 524 ret = nilfs_mdt_mark_block_dirty(nilfs->ns_dat,
7942b919
KS
525 bdescs[i].bd_offset);
526 if (ret < 0) {
1f5abe7e 527 WARN_ON(ret == -ENOENT);
7942b919
KS
528 return ret;
529 }
530 } else {
531 ret = nilfs_bmap_mark(bmap, bdescs[i].bd_offset,
532 bdescs[i].bd_level);
533 if (ret < 0) {
1f5abe7e 534 WARN_ON(ret == -ENOENT);
7942b919
KS
535 return ret;
536 }
537 }
538 }
539 return nmembs;
540}
541
7942b919 542int nilfs_ioctl_prepare_clean_segments(struct the_nilfs *nilfs,
4f6b8288 543 struct nilfs_argv *argv, void **kbufs)
7942b919 544{
1f5abe7e 545 const char *msg;
4f6b8288 546 int ret;
7942b919 547
4f6b8288 548 ret = nilfs_ioctl_delete_checkpoints(nilfs, &argv[1], kbufs[1]);
1f5abe7e
RK
549 if (ret < 0) {
550 /*
551 * can safely abort because checkpoints can be removed
552 * independently.
553 */
554 msg = "cannot delete checkpoints";
555 goto failed;
556 }
4f6b8288 557 ret = nilfs_ioctl_free_vblocknrs(nilfs, &argv[2], kbufs[2]);
1f5abe7e
RK
558 if (ret < 0) {
559 /*
560 * can safely abort because DAT file is updated atomically
561 * using a copy-on-write technique.
562 */
563 msg = "cannot delete virtual blocks from DAT file";
564 goto failed;
565 }
4f6b8288 566 ret = nilfs_ioctl_mark_blocks_dirty(nilfs, &argv[3], kbufs[3]);
1f5abe7e
RK
567 if (ret < 0) {
568 /*
569 * can safely abort because the operation is nondestructive.
570 */
571 msg = "cannot mark copying blocks dirty";
572 goto failed;
573 }
7942b919
KS
574 return 0;
575
1f5abe7e 576 failed:
1f5abe7e
RK
577 printk(KERN_ERR "NILFS: GC failed during preparation: %s: err=%d\n",
578 msg, ret);
7942b919
KS
579 return ret;
580}
581
582static int nilfs_ioctl_clean_segments(struct inode *inode, struct file *filp,
583 unsigned int cmd, void __user *argp)
584{
4f6b8288 585 struct nilfs_argv argv[5];
33e189bd 586 static const size_t argsz[5] = {
4f6b8288
RK
587 sizeof(struct nilfs_vdesc),
588 sizeof(struct nilfs_period),
589 sizeof(__u64),
590 sizeof(struct nilfs_bdesc),
591 sizeof(__u64),
592 };
593 void __user *base;
594 void *kbufs[5];
595 struct the_nilfs *nilfs;
596 size_t len, nsegs;
597 int n, ret;
598
7942b919
KS
599 if (!capable(CAP_SYS_ADMIN))
600 return -EPERM;
4f6b8288 601
a561be71 602 ret = mnt_want_write_file(filp);
7512487e
RK
603 if (ret)
604 return ret;
605
606 ret = -EFAULT;
4f6b8288 607 if (copy_from_user(argv, argp, sizeof(argv)))
7512487e 608 goto out;
4f6b8288 609
7512487e 610 ret = -EINVAL;
4f6b8288
RK
611 nsegs = argv[4].v_nmembs;
612 if (argv[4].v_size != argsz[4])
7512487e 613 goto out;
1ecd3c7e
XW
614 if (nsegs > UINT_MAX / sizeof(__u64))
615 goto out;
7512487e 616
4f6b8288
RK
617 /*
618 * argv[4] points to segment numbers this ioctl cleans. We
619 * use kmalloc() for its buffer because memory used for the
620 * segment numbers is enough small.
621 */
622 kbufs[4] = memdup_user((void __user *)(unsigned long)argv[4].v_base,
623 nsegs * sizeof(__u64));
7512487e
RK
624 if (IS_ERR(kbufs[4])) {
625 ret = PTR_ERR(kbufs[4]);
626 goto out;
627 }
e3154e97 628 nilfs = inode->i_sb->s_fs_info;
4f6b8288
RK
629
630 for (n = 0; n < 4; n++) {
631 ret = -EINVAL;
632 if (argv[n].v_size != argsz[n])
633 goto out_free;
634
635 if (argv[n].v_nmembs > nsegs * nilfs->ns_blocks_per_segment)
636 goto out_free;
637
481fe17e
HC
638 if (argv[n].v_nmembs >= UINT_MAX / argv[n].v_size)
639 goto out_free;
640
4f6b8288
RK
641 len = argv[n].v_size * argv[n].v_nmembs;
642 base = (void __user *)(unsigned long)argv[n].v_base;
643 if (len == 0) {
644 kbufs[n] = NULL;
645 continue;
646 }
647
648 kbufs[n] = vmalloc(len);
649 if (!kbufs[n]) {
650 ret = -ENOMEM;
651 goto out_free;
652 }
653 if (copy_from_user(kbufs[n], base, len)) {
654 ret = -EFAULT;
655 vfree(kbufs[n]);
656 goto out_free;
657 }
658 }
659
1cf58fa8 660 /*
263d90ce 661 * nilfs_ioctl_move_blocks() will call nilfs_iget_for_gc(),
1cf58fa8
JS
662 * which will operates an inode list without blocking.
663 * To protect the list from concurrent operations,
664 * nilfs_ioctl_move_blocks should be atomic operation.
665 */
666 if (test_and_set_bit(THE_NILFS_GC_RUNNING, &nilfs->ns_flags)) {
667 ret = -EBUSY;
668 goto out_free;
669 }
670
263d90ce 671 ret = nilfs_ioctl_move_blocks(inode->i_sb, &argv[0], kbufs[0]);
1cf58fa8
JS
672 if (ret < 0)
673 printk(KERN_ERR "NILFS: GC failed during preparation: "
674 "cannot read source blocks: err=%d\n", ret);
a9bae189
VD
675 else {
676 if (nilfs_sb_need_update(nilfs))
677 set_nilfs_discontinued(nilfs);
1cf58fa8 678 ret = nilfs_clean_segments(inode->i_sb, argv, kbufs);
a9bae189 679 }
1cf58fa8 680
263d90ce 681 nilfs_remove_all_gcinodes(nilfs);
1cf58fa8 682 clear_nilfs_gc_running(nilfs);
4f6b8288 683
7512487e 684out_free:
d5046853 685 while (--n >= 0)
4f6b8288
RK
686 vfree(kbufs[n]);
687 kfree(kbufs[4]);
7512487e 688out:
2a79f17e 689 mnt_drop_write_file(filp);
4f6b8288 690 return ret;
7942b919
KS
691}
692
693static int nilfs_ioctl_sync(struct inode *inode, struct file *filp,
694 unsigned int cmd, void __user *argp)
695{
696 __u64 cno;
697 int ret;
0d561f12 698 struct the_nilfs *nilfs;
7942b919
KS
699
700 ret = nilfs_construct_segment(inode->i_sb);
701 if (ret < 0)
702 return ret;
703
11475975
RK
704 nilfs = inode->i_sb->s_fs_info;
705 if (nilfs_test_opt(nilfs, BARRIER)) {
706 ret = blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL, NULL);
707 if (ret == -EIO)
708 return ret;
709 }
710
7942b919 711 if (argp != NULL) {
0d561f12
JS
712 down_read(&nilfs->ns_segctor_sem);
713 cno = nilfs->ns_cno - 1;
714 up_read(&nilfs->ns_segctor_sem);
7942b919
KS
715 if (copy_to_user(argp, &cno, sizeof(cno)))
716 return -EFAULT;
717 }
718 return 0;
719}
720
4e33f9ea
RK
721static int nilfs_ioctl_resize(struct inode *inode, struct file *filp,
722 void __user *argp)
723{
724 __u64 newsize;
725 int ret = -EPERM;
726
727 if (!capable(CAP_SYS_ADMIN))
728 goto out;
729
a561be71 730 ret = mnt_want_write_file(filp);
4e33f9ea
RK
731 if (ret)
732 goto out;
733
734 ret = -EFAULT;
735 if (copy_from_user(&newsize, argp, sizeof(newsize)))
736 goto out_drop_write;
737
738 ret = nilfs_resize_fs(inode->i_sb, newsize);
739
740out_drop_write:
2a79f17e 741 mnt_drop_write_file(filp);
4e33f9ea
RK
742out:
743 return ret;
744}
745
619205da
RK
746static int nilfs_ioctl_set_alloc_range(struct inode *inode, void __user *argp)
747{
748 struct the_nilfs *nilfs = inode->i_sb->s_fs_info;
749 __u64 range[2];
750 __u64 minseg, maxseg;
751 unsigned long segbytes;
752 int ret = -EPERM;
753
754 if (!capable(CAP_SYS_ADMIN))
755 goto out;
756
757 ret = -EFAULT;
758 if (copy_from_user(range, argp, sizeof(__u64[2])))
759 goto out;
760
761 ret = -ERANGE;
762 if (range[1] > i_size_read(inode->i_sb->s_bdev->bd_inode))
763 goto out;
764
765 segbytes = nilfs->ns_blocks_per_segment * nilfs->ns_blocksize;
766
767 minseg = range[0] + segbytes - 1;
768 do_div(minseg, segbytes);
769 maxseg = NILFS_SB2_OFFSET_BYTES(range[1]);
770 do_div(maxseg, segbytes);
771 maxseg--;
772
773 ret = nilfs_sufile_set_alloc_range(nilfs->ns_sufile, minseg, maxseg);
774out:
775 return ret;
776}
777
47eb6b9c
RK
778static int nilfs_ioctl_get_info(struct inode *inode, struct file *filp,
779 unsigned int cmd, void __user *argp,
83aca8f4 780 size_t membsz,
47eb6b9c
RK
781 ssize_t (*dofunc)(struct the_nilfs *,
782 __u64 *, int,
783 void *, size_t, size_t))
784
785{
e3154e97 786 struct the_nilfs *nilfs = inode->i_sb->s_fs_info;
47eb6b9c
RK
787 struct nilfs_argv argv;
788 int ret;
789
790 if (copy_from_user(&argv, argp, sizeof(argv)))
791 return -EFAULT;
792
003ff182 793 if (argv.v_size < membsz)
83aca8f4
RK
794 return -EINVAL;
795
47eb6b9c
RK
796 ret = nilfs_ioctl_wrap_copy(nilfs, &argv, _IOC_DIR(cmd), dofunc);
797 if (ret < 0)
798 return ret;
799
800 if (copy_to_user(argp, &argv, sizeof(argv)))
801 ret = -EFAULT;
802 return ret;
803}
804
7a946193 805long nilfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
7942b919 806{
496ad9aa 807 struct inode *inode = file_inode(filp);
75323400 808 void __user *argp = (void __user *)arg;
7942b919
KS
809
810 switch (cmd) {
cde98f0f
RK
811 case FS_IOC_GETFLAGS:
812 return nilfs_ioctl_getflags(inode, argp);
813 case FS_IOC_SETFLAGS:
814 return nilfs_ioctl_setflags(inode, filp, argp);
815 case FS_IOC_GETVERSION:
816 return nilfs_ioctl_getversion(inode, argp);
7942b919
KS
817 case NILFS_IOCTL_CHANGE_CPMODE:
818 return nilfs_ioctl_change_cpmode(inode, filp, cmd, argp);
819 case NILFS_IOCTL_DELETE_CHECKPOINT:
820 return nilfs_ioctl_delete_checkpoint(inode, filp, cmd, argp);
821 case NILFS_IOCTL_GET_CPINFO:
47eb6b9c 822 return nilfs_ioctl_get_info(inode, filp, cmd, argp,
83aca8f4 823 sizeof(struct nilfs_cpinfo),
47eb6b9c 824 nilfs_ioctl_do_get_cpinfo);
7942b919
KS
825 case NILFS_IOCTL_GET_CPSTAT:
826 return nilfs_ioctl_get_cpstat(inode, filp, cmd, argp);
827 case NILFS_IOCTL_GET_SUINFO:
47eb6b9c 828 return nilfs_ioctl_get_info(inode, filp, cmd, argp,
83aca8f4 829 sizeof(struct nilfs_suinfo),
47eb6b9c 830 nilfs_ioctl_do_get_suinfo);
7942b919
KS
831 case NILFS_IOCTL_GET_SUSTAT:
832 return nilfs_ioctl_get_sustat(inode, filp, cmd, argp);
833 case NILFS_IOCTL_GET_VINFO:
47eb6b9c 834 return nilfs_ioctl_get_info(inode, filp, cmd, argp,
83aca8f4 835 sizeof(struct nilfs_vinfo),
47eb6b9c 836 nilfs_ioctl_do_get_vinfo);
7942b919
KS
837 case NILFS_IOCTL_GET_BDESCS:
838 return nilfs_ioctl_get_bdescs(inode, filp, cmd, argp);
839 case NILFS_IOCTL_CLEAN_SEGMENTS:
840 return nilfs_ioctl_clean_segments(inode, filp, cmd, argp);
7942b919
KS
841 case NILFS_IOCTL_SYNC:
842 return nilfs_ioctl_sync(inode, filp, cmd, argp);
4e33f9ea
RK
843 case NILFS_IOCTL_RESIZE:
844 return nilfs_ioctl_resize(inode, filp, argp);
619205da
RK
845 case NILFS_IOCTL_SET_ALLOC_RANGE:
846 return nilfs_ioctl_set_alloc_range(inode, argp);
7942b919
KS
847 default:
848 return -ENOTTY;
849 }
850}
828b1c50
RK
851
852#ifdef CONFIG_COMPAT
853long nilfs_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
854{
855 switch (cmd) {
856 case FS_IOC32_GETFLAGS:
857 cmd = FS_IOC_GETFLAGS;
858 break;
859 case FS_IOC32_SETFLAGS:
860 cmd = FS_IOC_SETFLAGS;
861 break;
862 case FS_IOC32_GETVERSION:
863 cmd = FS_IOC_GETVERSION;
864 break;
695c60f2
TM
865 case NILFS_IOCTL_CHANGE_CPMODE:
866 case NILFS_IOCTL_DELETE_CHECKPOINT:
867 case NILFS_IOCTL_GET_CPINFO:
868 case NILFS_IOCTL_GET_CPSTAT:
869 case NILFS_IOCTL_GET_SUINFO:
870 case NILFS_IOCTL_GET_SUSTAT:
871 case NILFS_IOCTL_GET_VINFO:
872 case NILFS_IOCTL_GET_BDESCS:
873 case NILFS_IOCTL_CLEAN_SEGMENTS:
874 case NILFS_IOCTL_SYNC:
875 case NILFS_IOCTL_RESIZE:
876 case NILFS_IOCTL_SET_ALLOC_RANGE:
877 break;
828b1c50
RK
878 default:
879 return -ENOIOCTLCMD;
880 }
881 return nilfs_ioctl(filp, cmd, (unsigned long)compat_ptr(arg));
882}
883#endif
This page took 0.474012 seconds and 5 git commands to generate.