blob: 3aad6413aba440b45c81272be741fb44550d6d8e [file] [log] [blame]
Koji Sato7942b912009-04-06 19:01:41 -07001/*
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>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090025#include <linux/slab.h>
Koji Sato7942b912009-04-06 19:01:41 -070026#include <linux/capability.h> /* capable() */
27#include <linux/uaccess.h> /* copy_from_user(), copy_to_user() */
Ryusuke Konishi4f6b8282009-05-10 22:41:43 +090028#include <linux/vmalloc.h>
Ryusuke Konishi75124872010-01-26 13:59:40 +090029#include <linux/mount.h> /* mnt_want_write(), mnt_drop_write() */
Koji Sato7942b912009-04-06 19:01:41 -070030#include <linux/nilfs2_fs.h>
31#include "nilfs.h"
32#include "segment.h"
33#include "bmap.h"
34#include "cpfile.h"
35#include "sufile.h"
36#include "dat.h"
37
38
Koji Sato7942b912009-04-06 19:01:41 -070039static int nilfs_ioctl_wrap_copy(struct the_nilfs *nilfs,
40 struct nilfs_argv *argv, int dir,
41 ssize_t (*dofunc)(struct the_nilfs *,
Ryusuke Konishib028fcf2009-04-06 19:01:47 -070042 __u64 *, int,
Koji Sato7942b912009-04-06 19:01:41 -070043 void *, size_t, size_t))
44{
45 void *buf;
Ryusuke Konishidc498d02009-04-06 19:01:52 -070046 void __user *base = (void __user *)(unsigned long)argv->v_base;
Ryusuke Konishi3358b4a2009-04-06 19:01:43 -070047 size_t maxmembs, total, n;
Koji Sato7942b912009-04-06 19:01:41 -070048 ssize_t nr;
49 int ret, i;
Ryusuke Konishib028fcf2009-04-06 19:01:47 -070050 __u64 pos, ppos;
Koji Sato7942b912009-04-06 19:01:41 -070051
52 if (argv->v_nmembs == 0)
53 return 0;
54
Ryusuke Konishi3358b4a2009-04-06 19:01:43 -070055 if (argv->v_size > PAGE_SIZE)
56 return -EINVAL;
57
58 buf = (void *)__get_free_pages(GFP_NOFS, 0);
59 if (unlikely(!buf))
Koji Sato7942b912009-04-06 19:01:41 -070060 return -ENOMEM;
Ryusuke Konishi3358b4a2009-04-06 19:01:43 -070061 maxmembs = PAGE_SIZE / argv->v_size;
Koji Sato7942b912009-04-06 19:01:41 -070062
63 ret = 0;
64 total = 0;
Ryusuke Konishib028fcf2009-04-06 19:01:47 -070065 pos = argv->v_index;
Koji Sato7942b912009-04-06 19:01:41 -070066 for (i = 0; i < argv->v_nmembs; i += n) {
67 n = (argv->v_nmembs - i < maxmembs) ?
68 argv->v_nmembs - i : maxmembs;
69 if ((dir & _IOC_WRITE) &&
Ryusuke Konishidc498d02009-04-06 19:01:52 -070070 copy_from_user(buf, base + argv->v_size * i,
71 argv->v_size * n)) {
Koji Sato7942b912009-04-06 19:01:41 -070072 ret = -EFAULT;
73 break;
74 }
Ryusuke Konishib028fcf2009-04-06 19:01:47 -070075 ppos = pos;
Pekka Enberg8acfbf02009-04-06 19:01:49 -070076 nr = dofunc(nilfs, &pos, argv->v_flags, buf, argv->v_size,
Ryusuke Konishib028fcf2009-04-06 19:01:47 -070077 n);
Koji Sato7942b912009-04-06 19:01:41 -070078 if (nr < 0) {
79 ret = nr;
80 break;
81 }
82 if ((dir & _IOC_READ) &&
Ryusuke Konishidc498d02009-04-06 19:01:52 -070083 copy_to_user(base + argv->v_size * i, buf,
84 argv->v_size * nr)) {
Koji Sato7942b912009-04-06 19:01:41 -070085 ret = -EFAULT;
86 break;
87 }
88 total += nr;
Ryusuke Konishib028fcf2009-04-06 19:01:47 -070089 if ((size_t)nr < n)
90 break;
91 if (pos == ppos)
92 pos += n;
Koji Sato7942b912009-04-06 19:01:41 -070093 }
94 argv->v_nmembs = total;
95
Ryusuke Konishi3358b4a2009-04-06 19:01:43 -070096 free_pages((unsigned long)buf, 0);
Koji Sato7942b912009-04-06 19:01:41 -070097 return ret;
98}
99
Ryusuke Konishicde98f02011-01-20 02:09:53 +0900100static int nilfs_ioctl_getflags(struct inode *inode, void __user *argp)
101{
102 unsigned int flags = NILFS_I(inode)->i_flags & FS_FL_USER_VISIBLE;
103
104 return put_user(flags, (int __user *)argp);
105}
106
107static int nilfs_ioctl_setflags(struct inode *inode, struct file *filp,
108 void __user *argp)
109{
110 struct nilfs_transaction_info ti;
111 unsigned int flags, oldflags;
112 int ret;
113
114 if (!is_owner_or_cap(inode))
115 return -EACCES;
116
117 if (get_user(flags, (int __user *)argp))
118 return -EFAULT;
119
120 ret = mnt_want_write(filp->f_path.mnt);
121 if (ret)
122 return ret;
123
124 flags = nilfs_mask_flags(inode->i_mode, flags);
125
126 mutex_lock(&inode->i_mutex);
127
128 oldflags = NILFS_I(inode)->i_flags;
129
130 /*
131 * The IMMUTABLE and APPEND_ONLY flags can only be changed by the
132 * relevant capability.
133 */
134 ret = -EPERM;
135 if (((flags ^ oldflags) & (FS_APPEND_FL | FS_IMMUTABLE_FL)) &&
136 !capable(CAP_LINUX_IMMUTABLE))
137 goto out;
138
139 ret = nilfs_transaction_begin(inode->i_sb, &ti, 0);
140 if (ret)
141 goto out;
142
143 NILFS_I(inode)->i_flags = (oldflags & ~FS_FL_USER_MODIFIABLE) |
144 (flags & FS_FL_USER_MODIFIABLE);
145
146 nilfs_set_inode_flags(inode);
147 inode->i_ctime = CURRENT_TIME;
148 if (IS_SYNC(inode))
149 nilfs_set_transaction_flag(NILFS_TI_SYNC);
150
151 nilfs_mark_inode_dirty(inode);
152 ret = nilfs_transaction_commit(inode->i_sb);
153out:
154 mutex_unlock(&inode->i_mutex);
155 mnt_drop_write(filp->f_path.mnt);
156 return ret;
157}
158
159static int nilfs_ioctl_getversion(struct inode *inode, void __user *argp)
160{
161 return put_user(inode->i_generation, (int __user *)argp);
162}
163
Koji Sato7942b912009-04-06 19:01:41 -0700164static int nilfs_ioctl_change_cpmode(struct inode *inode, struct file *filp,
165 unsigned int cmd, void __user *argp)
166{
Ryusuke Konishic1ea9852009-11-12 00:13:32 +0900167 struct the_nilfs *nilfs = NILFS_SB(inode->i_sb)->s_nilfs;
168 struct inode *cpfile = nilfs->ns_cpfile;
Koji Sato7942b912009-04-06 19:01:41 -0700169 struct nilfs_transaction_info ti;
170 struct nilfs_cpmode cpmode;
171 int ret;
172
173 if (!capable(CAP_SYS_ADMIN))
174 return -EPERM;
Ryusuke Konishi75124872010-01-26 13:59:40 +0900175
176 ret = mnt_want_write(filp->f_path.mnt);
177 if (ret)
178 return ret;
179
180 ret = -EFAULT;
Koji Sato7942b912009-04-06 19:01:41 -0700181 if (copy_from_user(&cpmode, argp, sizeof(cpmode)))
Ryusuke Konishi75124872010-01-26 13:59:40 +0900182 goto out;
Koji Sato7942b912009-04-06 19:01:41 -0700183
Ryusuke Konishi348fe8d2010-09-09 02:07:56 +0900184 down_read(&inode->i_sb->s_umount);
Ryusuke Konishi75124872010-01-26 13:59:40 +0900185
Koji Sato7942b912009-04-06 19:01:41 -0700186 nilfs_transaction_begin(inode->i_sb, &ti, 0);
187 ret = nilfs_cpfile_change_cpmode(
188 cpfile, cpmode.cm_cno, cpmode.cm_mode);
Ryusuke Konishi75124872010-01-26 13:59:40 +0900189 if (unlikely(ret < 0))
Ryusuke Konishi47420c72009-04-06 19:01:45 -0700190 nilfs_transaction_abort(inode->i_sb);
Ryusuke Konishi75124872010-01-26 13:59:40 +0900191 else
192 nilfs_transaction_commit(inode->i_sb); /* never fails */
193
Ryusuke Konishi348fe8d2010-09-09 02:07:56 +0900194 up_read(&inode->i_sb->s_umount);
Ryusuke Konishi75124872010-01-26 13:59:40 +0900195out:
196 mnt_drop_write(filp->f_path.mnt);
Koji Sato7942b912009-04-06 19:01:41 -0700197 return ret;
198}
199
200static int
201nilfs_ioctl_delete_checkpoint(struct inode *inode, struct file *filp,
202 unsigned int cmd, void __user *argp)
203{
204 struct inode *cpfile = NILFS_SB(inode->i_sb)->s_nilfs->ns_cpfile;
205 struct nilfs_transaction_info ti;
206 __u64 cno;
207 int ret;
208
209 if (!capable(CAP_SYS_ADMIN))
210 return -EPERM;
Ryusuke Konishi75124872010-01-26 13:59:40 +0900211
212 ret = mnt_want_write(filp->f_path.mnt);
213 if (ret)
214 return ret;
215
216 ret = -EFAULT;
Koji Sato7942b912009-04-06 19:01:41 -0700217 if (copy_from_user(&cno, argp, sizeof(cno)))
Ryusuke Konishi75124872010-01-26 13:59:40 +0900218 goto out;
Koji Sato7942b912009-04-06 19:01:41 -0700219
220 nilfs_transaction_begin(inode->i_sb, &ti, 0);
221 ret = nilfs_cpfile_delete_checkpoint(cpfile, cno);
Ryusuke Konishi75124872010-01-26 13:59:40 +0900222 if (unlikely(ret < 0))
Ryusuke Konishi47420c72009-04-06 19:01:45 -0700223 nilfs_transaction_abort(inode->i_sb);
Ryusuke Konishi75124872010-01-26 13:59:40 +0900224 else
225 nilfs_transaction_commit(inode->i_sb); /* never fails */
226out:
227 mnt_drop_write(filp->f_path.mnt);
Koji Sato7942b912009-04-06 19:01:41 -0700228 return ret;
229}
230
231static ssize_t
Ryusuke Konishib028fcf2009-04-06 19:01:47 -0700232nilfs_ioctl_do_get_cpinfo(struct the_nilfs *nilfs, __u64 *posp, int flags,
Koji Sato7942b912009-04-06 19:01:41 -0700233 void *buf, size_t size, size_t nmembs)
234{
Koji Sato7942b912009-04-06 19:01:41 -0700235 int ret;
236
Ryusuke Konishi47420c72009-04-06 19:01:45 -0700237 down_read(&nilfs->ns_segctor_sem);
Ryusuke Konishi47eb6b92009-04-30 02:21:00 +0900238 ret = nilfs_cpfile_get_cpinfo(nilfs->ns_cpfile, posp, flags, buf,
Ryusuke Konishi003ff182009-05-12 03:58:47 +0900239 size, nmembs);
Ryusuke Konishi47420c72009-04-06 19:01:45 -0700240 up_read(&nilfs->ns_segctor_sem);
Koji Sato7942b912009-04-06 19:01:41 -0700241 return ret;
242}
243
244static int nilfs_ioctl_get_cpstat(struct inode *inode, struct file *filp,
245 unsigned int cmd, void __user *argp)
246{
Ryusuke Konishi47420c72009-04-06 19:01:45 -0700247 struct the_nilfs *nilfs = NILFS_SB(inode->i_sb)->s_nilfs;
Koji Sato7942b912009-04-06 19:01:41 -0700248 struct nilfs_cpstat cpstat;
Koji Sato7942b912009-04-06 19:01:41 -0700249 int ret;
250
Ryusuke Konishi47420c72009-04-06 19:01:45 -0700251 down_read(&nilfs->ns_segctor_sem);
252 ret = nilfs_cpfile_get_stat(nilfs->ns_cpfile, &cpstat);
253 up_read(&nilfs->ns_segctor_sem);
Koji Sato7942b912009-04-06 19:01:41 -0700254 if (ret < 0)
255 return ret;
256
257 if (copy_to_user(argp, &cpstat, sizeof(cpstat)))
258 ret = -EFAULT;
259 return ret;
260}
261
262static ssize_t
Ryusuke Konishib028fcf2009-04-06 19:01:47 -0700263nilfs_ioctl_do_get_suinfo(struct the_nilfs *nilfs, __u64 *posp, int flags,
Koji Sato7942b912009-04-06 19:01:41 -0700264 void *buf, size_t size, size_t nmembs)
265{
Koji Sato7942b912009-04-06 19:01:41 -0700266 int ret;
267
Ryusuke Konishi47420c72009-04-06 19:01:45 -0700268 down_read(&nilfs->ns_segctor_sem);
Ryusuke Konishi003ff182009-05-12 03:58:47 +0900269 ret = nilfs_sufile_get_suinfo(nilfs->ns_sufile, *posp, buf, size,
270 nmembs);
Ryusuke Konishi47420c72009-04-06 19:01:45 -0700271 up_read(&nilfs->ns_segctor_sem);
Koji Sato7942b912009-04-06 19:01:41 -0700272 return ret;
273}
274
275static int nilfs_ioctl_get_sustat(struct inode *inode, struct file *filp,
276 unsigned int cmd, void __user *argp)
277{
Ryusuke Konishi47420c72009-04-06 19:01:45 -0700278 struct the_nilfs *nilfs = NILFS_SB(inode->i_sb)->s_nilfs;
Koji Sato7942b912009-04-06 19:01:41 -0700279 struct nilfs_sustat sustat;
Koji Sato7942b912009-04-06 19:01:41 -0700280 int ret;
281
Ryusuke Konishi47420c72009-04-06 19:01:45 -0700282 down_read(&nilfs->ns_segctor_sem);
283 ret = nilfs_sufile_get_stat(nilfs->ns_sufile, &sustat);
284 up_read(&nilfs->ns_segctor_sem);
Koji Sato7942b912009-04-06 19:01:41 -0700285 if (ret < 0)
286 return ret;
287
288 if (copy_to_user(argp, &sustat, sizeof(sustat)))
289 ret = -EFAULT;
290 return ret;
291}
292
293static ssize_t
Ryusuke Konishib028fcf2009-04-06 19:01:47 -0700294nilfs_ioctl_do_get_vinfo(struct the_nilfs *nilfs, __u64 *posp, int flags,
Koji Sato7942b912009-04-06 19:01:41 -0700295 void *buf, size_t size, size_t nmembs)
296{
Koji Sato7942b912009-04-06 19:01:41 -0700297 int ret;
298
Ryusuke Konishi47420c72009-04-06 19:01:45 -0700299 down_read(&nilfs->ns_segctor_sem);
Ryusuke Konishi365e2152010-12-27 00:07:30 +0900300 ret = nilfs_dat_get_vinfo(nilfs->ns_dat, buf, size, nmembs);
Ryusuke Konishi47420c72009-04-06 19:01:45 -0700301 up_read(&nilfs->ns_segctor_sem);
Koji Sato7942b912009-04-06 19:01:41 -0700302 return ret;
303}
304
305static ssize_t
Ryusuke Konishib028fcf2009-04-06 19:01:47 -0700306nilfs_ioctl_do_get_bdescs(struct the_nilfs *nilfs, __u64 *posp, int flags,
Koji Sato7942b912009-04-06 19:01:41 -0700307 void *buf, size_t size, size_t nmembs)
308{
Ryusuke Konishi365e2152010-12-27 00:07:30 +0900309 struct nilfs_bmap *bmap = NILFS_I(nilfs->ns_dat)->i_bmap;
Koji Sato7942b912009-04-06 19:01:41 -0700310 struct nilfs_bdesc *bdescs = buf;
311 int ret, i;
312
Ryusuke Konishi47eb6b92009-04-30 02:21:00 +0900313 down_read(&nilfs->ns_segctor_sem);
Koji Sato7942b912009-04-06 19:01:41 -0700314 for (i = 0; i < nmembs; i++) {
315 ret = nilfs_bmap_lookup_at_level(bmap,
316 bdescs[i].bd_offset,
317 bdescs[i].bd_level + 1,
318 &bdescs[i].bd_blocknr);
319 if (ret < 0) {
Ryusuke Konishi47eb6b92009-04-30 02:21:00 +0900320 if (ret != -ENOENT) {
321 up_read(&nilfs->ns_segctor_sem);
Koji Sato7942b912009-04-06 19:01:41 -0700322 return ret;
Ryusuke Konishi47eb6b92009-04-30 02:21:00 +0900323 }
Koji Sato7942b912009-04-06 19:01:41 -0700324 bdescs[i].bd_blocknr = 0;
325 }
326 }
Ryusuke Konishi47eb6b92009-04-30 02:21:00 +0900327 up_read(&nilfs->ns_segctor_sem);
Koji Sato7942b912009-04-06 19:01:41 -0700328 return nmembs;
329}
330
331static int nilfs_ioctl_get_bdescs(struct inode *inode, struct file *filp,
332 unsigned int cmd, void __user *argp)
333{
334 struct the_nilfs *nilfs = NILFS_SB(inode->i_sb)->s_nilfs;
335 struct nilfs_argv argv;
Koji Sato7942b912009-04-06 19:01:41 -0700336 int ret;
337
338 if (copy_from_user(&argv, argp, sizeof(argv)))
339 return -EFAULT;
340
Ryusuke Konishi83aca8f2009-05-11 23:24:47 +0900341 if (argv.v_size != sizeof(struct nilfs_bdesc))
342 return -EINVAL;
343
Koji Sato7942b912009-04-06 19:01:41 -0700344 ret = nilfs_ioctl_wrap_copy(nilfs, &argv, _IOC_DIR(cmd),
345 nilfs_ioctl_do_get_bdescs);
Ryusuke Konishi47420c72009-04-06 19:01:45 -0700346 if (ret < 0)
347 return ret;
Koji Sato7942b912009-04-06 19:01:41 -0700348
349 if (copy_to_user(argp, &argv, sizeof(argv)))
350 ret = -EFAULT;
351 return ret;
352}
353
354static int nilfs_ioctl_move_inode_block(struct inode *inode,
355 struct nilfs_vdesc *vdesc,
356 struct list_head *buffers)
357{
358 struct buffer_head *bh;
359 int ret;
360
361 if (vdesc->vd_flags == 0)
362 ret = nilfs_gccache_submit_read_data(
363 inode, vdesc->vd_offset, vdesc->vd_blocknr,
364 vdesc->vd_vblocknr, &bh);
365 else
366 ret = nilfs_gccache_submit_read_node(
367 inode, vdesc->vd_blocknr, vdesc->vd_vblocknr, &bh);
368
369 if (unlikely(ret < 0)) {
370 if (ret == -ENOENT)
371 printk(KERN_CRIT
372 "%s: invalid virtual block address (%s): "
373 "ino=%llu, cno=%llu, offset=%llu, "
374 "blocknr=%llu, vblocknr=%llu\n",
375 __func__, vdesc->vd_flags ? "node" : "data",
376 (unsigned long long)vdesc->vd_ino,
377 (unsigned long long)vdesc->vd_cno,
378 (unsigned long long)vdesc->vd_offset,
379 (unsigned long long)vdesc->vd_blocknr,
380 (unsigned long long)vdesc->vd_vblocknr);
381 return ret;
382 }
Ryusuke Konishi5399dd12009-11-07 18:45:16 +0900383 if (unlikely(!list_empty(&bh->b_assoc_buffers))) {
384 printk(KERN_CRIT "%s: conflicting %s buffer: ino=%llu, "
385 "cno=%llu, offset=%llu, blocknr=%llu, vblocknr=%llu\n",
386 __func__, vdesc->vd_flags ? "node" : "data",
387 (unsigned long long)vdesc->vd_ino,
388 (unsigned long long)vdesc->vd_cno,
389 (unsigned long long)vdesc->vd_offset,
390 (unsigned long long)vdesc->vd_blocknr,
391 (unsigned long long)vdesc->vd_vblocknr);
392 brelse(bh);
393 return -EEXIST;
394 }
Koji Sato7942b912009-04-06 19:01:41 -0700395 list_add_tail(&bh->b_assoc_buffers, buffers);
396 return 0;
397}
398
Ryusuke Konishi263d90c2010-08-20 19:06:11 +0900399static int nilfs_ioctl_move_blocks(struct super_block *sb,
Ryusuke Konishi4f6b8282009-05-10 22:41:43 +0900400 struct nilfs_argv *argv, void *buf)
Koji Sato7942b912009-04-06 19:01:41 -0700401{
Ryusuke Konishi4f6b8282009-05-10 22:41:43 +0900402 size_t nmembs = argv->v_nmembs;
Ryusuke Konishi947b10a2010-12-16 09:57:57 +0900403 struct the_nilfs *nilfs = NILFS_SB(sb)->s_nilfs;
Koji Sato7942b912009-04-06 19:01:41 -0700404 struct inode *inode;
405 struct nilfs_vdesc *vdesc;
406 struct buffer_head *bh, *n;
407 LIST_HEAD(buffers);
408 ino_t ino;
409 __u64 cno;
410 int i, ret;
411
412 for (i = 0, vdesc = buf; i < nmembs; ) {
413 ino = vdesc->vd_ino;
414 cno = vdesc->vd_cno;
Ryusuke Konishi263d90c2010-08-20 19:06:11 +0900415 inode = nilfs_iget_for_gc(sb, ino, cno);
Dan Carpenter103cfcf2010-11-23 09:26:02 +0300416 if (IS_ERR(inode)) {
417 ret = PTR_ERR(inode);
Koji Sato7942b912009-04-06 19:01:41 -0700418 goto failed;
419 }
Ryusuke Konishi947b10a2010-12-16 09:57:57 +0900420 if (list_empty(&NILFS_I(inode)->i_dirty)) {
421 /*
422 * Add the inode to GC inode list. Garbage Collection
423 * is serialized and no two processes manipulate the
424 * list simultaneously.
425 */
426 igrab(inode);
427 list_add(&NILFS_I(inode)->i_dirty,
428 &nilfs->ns_gc_inodes);
429 }
430
Koji Sato7942b912009-04-06 19:01:41 -0700431 do {
432 ret = nilfs_ioctl_move_inode_block(inode, vdesc,
433 &buffers);
Ryusuke Konishi263d90c2010-08-20 19:06:11 +0900434 if (unlikely(ret < 0)) {
435 iput(inode);
Koji Sato7942b912009-04-06 19:01:41 -0700436 goto failed;
Ryusuke Konishi263d90c2010-08-20 19:06:11 +0900437 }
Koji Sato7942b912009-04-06 19:01:41 -0700438 vdesc++;
439 } while (++i < nmembs &&
440 vdesc->vd_ino == ino && vdesc->vd_cno == cno);
Ryusuke Konishi263d90c2010-08-20 19:06:11 +0900441
442 iput(inode); /* The inode still remains in GC inode list */
Koji Sato7942b912009-04-06 19:01:41 -0700443 }
444
445 list_for_each_entry_safe(bh, n, &buffers, b_assoc_buffers) {
446 ret = nilfs_gccache_wait_and_mark_dirty(bh);
447 if (unlikely(ret < 0)) {
Ryusuke Konishi5399dd12009-11-07 18:45:16 +0900448 WARN_ON(ret == -EEXIST);
Koji Sato7942b912009-04-06 19:01:41 -0700449 goto failed;
450 }
451 list_del_init(&bh->b_assoc_buffers);
Koji Sato7942b912009-04-06 19:01:41 -0700452 brelse(bh);
453 }
454 return nmembs;
455
456 failed:
457 list_for_each_entry_safe(bh, n, &buffers, b_assoc_buffers) {
458 list_del_init(&bh->b_assoc_buffers);
Koji Sato7942b912009-04-06 19:01:41 -0700459 brelse(bh);
460 }
461 return ret;
462}
463
Ryusuke Konishi4f6b8282009-05-10 22:41:43 +0900464static int nilfs_ioctl_delete_checkpoints(struct the_nilfs *nilfs,
465 struct nilfs_argv *argv, void *buf)
Koji Sato7942b912009-04-06 19:01:41 -0700466{
Ryusuke Konishi4f6b8282009-05-10 22:41:43 +0900467 size_t nmembs = argv->v_nmembs;
Koji Sato7942b912009-04-06 19:01:41 -0700468 struct inode *cpfile = nilfs->ns_cpfile;
469 struct nilfs_period *periods = buf;
470 int ret, i;
471
472 for (i = 0; i < nmembs; i++) {
473 ret = nilfs_cpfile_delete_checkpoints(
474 cpfile, periods[i].p_start, periods[i].p_end);
475 if (ret < 0)
476 return ret;
477 }
478 return nmembs;
479}
480
Ryusuke Konishi4f6b8282009-05-10 22:41:43 +0900481static int nilfs_ioctl_free_vblocknrs(struct the_nilfs *nilfs,
482 struct nilfs_argv *argv, void *buf)
Koji Sato7942b912009-04-06 19:01:41 -0700483{
Ryusuke Konishi4f6b8282009-05-10 22:41:43 +0900484 size_t nmembs = argv->v_nmembs;
485 int ret;
Koji Sato7942b912009-04-06 19:01:41 -0700486
Ryusuke Konishi365e2152010-12-27 00:07:30 +0900487 ret = nilfs_dat_freev(nilfs->ns_dat, buf, nmembs);
Koji Sato7942b912009-04-06 19:01:41 -0700488
489 return (ret < 0) ? ret : nmembs;
490}
491
Ryusuke Konishi4f6b8282009-05-10 22:41:43 +0900492static int nilfs_ioctl_mark_blocks_dirty(struct the_nilfs *nilfs,
493 struct nilfs_argv *argv, void *buf)
Koji Sato7942b912009-04-06 19:01:41 -0700494{
Ryusuke Konishi4f6b8282009-05-10 22:41:43 +0900495 size_t nmembs = argv->v_nmembs;
Ryusuke Konishi365e2152010-12-27 00:07:30 +0900496 struct nilfs_bmap *bmap = NILFS_I(nilfs->ns_dat)->i_bmap;
Koji Sato7942b912009-04-06 19:01:41 -0700497 struct nilfs_bdesc *bdescs = buf;
498 int ret, i;
499
500 for (i = 0; i < nmembs; i++) {
501 /* XXX: use macro or inline func to check liveness */
502 ret = nilfs_bmap_lookup_at_level(bmap,
503 bdescs[i].bd_offset,
504 bdescs[i].bd_level + 1,
505 &bdescs[i].bd_blocknr);
506 if (ret < 0) {
507 if (ret != -ENOENT)
508 return ret;
509 bdescs[i].bd_blocknr = 0;
510 }
511 if (bdescs[i].bd_blocknr != bdescs[i].bd_oblocknr)
512 /* skip dead block */
513 continue;
514 if (bdescs[i].bd_level == 0) {
Ryusuke Konishi365e2152010-12-27 00:07:30 +0900515 ret = nilfs_mdt_mark_block_dirty(nilfs->ns_dat,
Koji Sato7942b912009-04-06 19:01:41 -0700516 bdescs[i].bd_offset);
517 if (ret < 0) {
Ryusuke Konishi1f5abe72009-04-06 19:01:55 -0700518 WARN_ON(ret == -ENOENT);
Koji Sato7942b912009-04-06 19:01:41 -0700519 return ret;
520 }
521 } else {
522 ret = nilfs_bmap_mark(bmap, bdescs[i].bd_offset,
523 bdescs[i].bd_level);
524 if (ret < 0) {
Ryusuke Konishi1f5abe72009-04-06 19:01:55 -0700525 WARN_ON(ret == -ENOENT);
Koji Sato7942b912009-04-06 19:01:41 -0700526 return ret;
527 }
528 }
529 }
530 return nmembs;
531}
532
Koji Sato7942b912009-04-06 19:01:41 -0700533int nilfs_ioctl_prepare_clean_segments(struct the_nilfs *nilfs,
Ryusuke Konishi4f6b8282009-05-10 22:41:43 +0900534 struct nilfs_argv *argv, void **kbufs)
Koji Sato7942b912009-04-06 19:01:41 -0700535{
Ryusuke Konishi1f5abe72009-04-06 19:01:55 -0700536 const char *msg;
Ryusuke Konishi4f6b8282009-05-10 22:41:43 +0900537 int ret;
Koji Sato7942b912009-04-06 19:01:41 -0700538
Ryusuke Konishi4f6b8282009-05-10 22:41:43 +0900539 ret = nilfs_ioctl_delete_checkpoints(nilfs, &argv[1], kbufs[1]);
Ryusuke Konishi1f5abe72009-04-06 19:01:55 -0700540 if (ret < 0) {
541 /*
542 * can safely abort because checkpoints can be removed
543 * independently.
544 */
545 msg = "cannot delete checkpoints";
546 goto failed;
547 }
Ryusuke Konishi4f6b8282009-05-10 22:41:43 +0900548 ret = nilfs_ioctl_free_vblocknrs(nilfs, &argv[2], kbufs[2]);
Ryusuke Konishi1f5abe72009-04-06 19:01:55 -0700549 if (ret < 0) {
550 /*
551 * can safely abort because DAT file is updated atomically
552 * using a copy-on-write technique.
553 */
554 msg = "cannot delete virtual blocks from DAT file";
555 goto failed;
556 }
Ryusuke Konishi4f6b8282009-05-10 22:41:43 +0900557 ret = nilfs_ioctl_mark_blocks_dirty(nilfs, &argv[3], kbufs[3]);
Ryusuke Konishi1f5abe72009-04-06 19:01:55 -0700558 if (ret < 0) {
559 /*
560 * can safely abort because the operation is nondestructive.
561 */
562 msg = "cannot mark copying blocks dirty";
563 goto failed;
564 }
Koji Sato7942b912009-04-06 19:01:41 -0700565 return 0;
566
Ryusuke Konishi1f5abe72009-04-06 19:01:55 -0700567 failed:
Ryusuke Konishi1f5abe72009-04-06 19:01:55 -0700568 printk(KERN_ERR "NILFS: GC failed during preparation: %s: err=%d\n",
569 msg, ret);
Koji Sato7942b912009-04-06 19:01:41 -0700570 return ret;
571}
572
573static int nilfs_ioctl_clean_segments(struct inode *inode, struct file *filp,
574 unsigned int cmd, void __user *argp)
575{
Ryusuke Konishi4f6b8282009-05-10 22:41:43 +0900576 struct nilfs_argv argv[5];
Tobias Klauser33e189b2009-12-23 13:57:47 +0100577 static const size_t argsz[5] = {
Ryusuke Konishi4f6b8282009-05-10 22:41:43 +0900578 sizeof(struct nilfs_vdesc),
579 sizeof(struct nilfs_period),
580 sizeof(__u64),
581 sizeof(struct nilfs_bdesc),
582 sizeof(__u64),
583 };
584 void __user *base;
585 void *kbufs[5];
586 struct the_nilfs *nilfs;
587 size_t len, nsegs;
588 int n, ret;
589
Koji Sato7942b912009-04-06 19:01:41 -0700590 if (!capable(CAP_SYS_ADMIN))
591 return -EPERM;
Ryusuke Konishi4f6b8282009-05-10 22:41:43 +0900592
Ryusuke Konishi75124872010-01-26 13:59:40 +0900593 ret = mnt_want_write(filp->f_path.mnt);
594 if (ret)
595 return ret;
Ryusuke Konishi4f6b8282009-05-10 22:41:43 +0900596
Ryusuke Konishi75124872010-01-26 13:59:40 +0900597 ret = -EFAULT;
598 if (copy_from_user(argv, argp, sizeof(argv)))
599 goto out;
600
601 ret = -EINVAL;
Ryusuke Konishi4f6b8282009-05-10 22:41:43 +0900602 nsegs = argv[4].v_nmembs;
603 if (argv[4].v_size != argsz[4])
Ryusuke Konishi75124872010-01-26 13:59:40 +0900604 goto out;
605
Ryusuke Konishi4f6b8282009-05-10 22:41:43 +0900606 /*
607 * argv[4] points to segment numbers this ioctl cleans. We
608 * use kmalloc() for its buffer because memory used for the
609 * segment numbers is enough small.
610 */
611 kbufs[4] = memdup_user((void __user *)(unsigned long)argv[4].v_base,
612 nsegs * sizeof(__u64));
Ryusuke Konishi75124872010-01-26 13:59:40 +0900613 if (IS_ERR(kbufs[4])) {
614 ret = PTR_ERR(kbufs[4]);
615 goto out;
616 }
Ryusuke Konishi4f6b8282009-05-10 22:41:43 +0900617 nilfs = NILFS_SB(inode->i_sb)->s_nilfs;
618
619 for (n = 0; n < 4; n++) {
620 ret = -EINVAL;
621 if (argv[n].v_size != argsz[n])
622 goto out_free;
623
624 if (argv[n].v_nmembs > nsegs * nilfs->ns_blocks_per_segment)
625 goto out_free;
626
627 len = argv[n].v_size * argv[n].v_nmembs;
628 base = (void __user *)(unsigned long)argv[n].v_base;
629 if (len == 0) {
630 kbufs[n] = NULL;
631 continue;
632 }
633
634 kbufs[n] = vmalloc(len);
635 if (!kbufs[n]) {
636 ret = -ENOMEM;
637 goto out_free;
638 }
639 if (copy_from_user(kbufs[n], base, len)) {
640 ret = -EFAULT;
641 vfree(kbufs[n]);
642 goto out_free;
643 }
644 }
645
Jiro SEKIBA1cf58fa2009-09-03 22:24:17 +0900646 /*
Ryusuke Konishi263d90c2010-08-20 19:06:11 +0900647 * nilfs_ioctl_move_blocks() will call nilfs_iget_for_gc(),
Jiro SEKIBA1cf58fa2009-09-03 22:24:17 +0900648 * which will operates an inode list without blocking.
649 * To protect the list from concurrent operations,
650 * nilfs_ioctl_move_blocks should be atomic operation.
651 */
652 if (test_and_set_bit(THE_NILFS_GC_RUNNING, &nilfs->ns_flags)) {
653 ret = -EBUSY;
654 goto out_free;
655 }
656
Ryusuke Konishi5beb6e02010-09-20 18:19:06 +0900657 vfs_check_frozen(inode->i_sb, SB_FREEZE_WRITE);
658
Ryusuke Konishi263d90c2010-08-20 19:06:11 +0900659 ret = nilfs_ioctl_move_blocks(inode->i_sb, &argv[0], kbufs[0]);
Jiro SEKIBA1cf58fa2009-09-03 22:24:17 +0900660 if (ret < 0)
661 printk(KERN_ERR "NILFS: GC failed during preparation: "
662 "cannot read source blocks: err=%d\n", ret);
663 else
664 ret = nilfs_clean_segments(inode->i_sb, argv, kbufs);
665
Ryusuke Konishi263d90c2010-08-20 19:06:11 +0900666 nilfs_remove_all_gcinodes(nilfs);
Jiro SEKIBA1cf58fa2009-09-03 22:24:17 +0900667 clear_nilfs_gc_running(nilfs);
Ryusuke Konishi4f6b8282009-05-10 22:41:43 +0900668
Ryusuke Konishi75124872010-01-26 13:59:40 +0900669out_free:
Ryusuke Konishid5046852009-05-22 20:36:21 +0900670 while (--n >= 0)
Ryusuke Konishi4f6b8282009-05-10 22:41:43 +0900671 vfree(kbufs[n]);
672 kfree(kbufs[4]);
Ryusuke Konishi75124872010-01-26 13:59:40 +0900673out:
674 mnt_drop_write(filp->f_path.mnt);
Ryusuke Konishi4f6b8282009-05-10 22:41:43 +0900675 return ret;
Koji Sato7942b912009-04-06 19:01:41 -0700676}
677
678static int nilfs_ioctl_sync(struct inode *inode, struct file *filp,
679 unsigned int cmd, void __user *argp)
680{
681 __u64 cno;
682 int ret;
Jiro SEKIBA0d561f12010-02-20 19:47:49 +0900683 struct the_nilfs *nilfs;
Koji Sato7942b912009-04-06 19:01:41 -0700684
685 ret = nilfs_construct_segment(inode->i_sb);
686 if (ret < 0)
687 return ret;
688
689 if (argp != NULL) {
Jiro SEKIBA0d561f12010-02-20 19:47:49 +0900690 nilfs = NILFS_SB(inode->i_sb)->s_nilfs;
691 down_read(&nilfs->ns_segctor_sem);
692 cno = nilfs->ns_cno - 1;
693 up_read(&nilfs->ns_segctor_sem);
Koji Sato7942b912009-04-06 19:01:41 -0700694 if (copy_to_user(argp, &cno, sizeof(cno)))
695 return -EFAULT;
696 }
697 return 0;
698}
699
Ryusuke Konishi47eb6b92009-04-30 02:21:00 +0900700static int nilfs_ioctl_get_info(struct inode *inode, struct file *filp,
701 unsigned int cmd, void __user *argp,
Ryusuke Konishi83aca8f2009-05-11 23:24:47 +0900702 size_t membsz,
Ryusuke Konishi47eb6b92009-04-30 02:21:00 +0900703 ssize_t (*dofunc)(struct the_nilfs *,
704 __u64 *, int,
705 void *, size_t, size_t))
706
707{
708 struct the_nilfs *nilfs = NILFS_SB(inode->i_sb)->s_nilfs;
709 struct nilfs_argv argv;
710 int ret;
711
712 if (copy_from_user(&argv, argp, sizeof(argv)))
713 return -EFAULT;
714
Ryusuke Konishi003ff182009-05-12 03:58:47 +0900715 if (argv.v_size < membsz)
Ryusuke Konishi83aca8f2009-05-11 23:24:47 +0900716 return -EINVAL;
717
Ryusuke Konishi47eb6b92009-04-30 02:21:00 +0900718 ret = nilfs_ioctl_wrap_copy(nilfs, &argv, _IOC_DIR(cmd), dofunc);
719 if (ret < 0)
720 return ret;
721
722 if (copy_to_user(argp, &argv, sizeof(argv)))
723 ret = -EFAULT;
724 return ret;
725}
726
Ryusuke Konishi7a946192009-04-06 19:01:53 -0700727long nilfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
Koji Sato7942b912009-04-06 19:01:41 -0700728{
Ryusuke Konishi7a946192009-04-06 19:01:53 -0700729 struct inode *inode = filp->f_dentry->d_inode;
Li Hong75323402010-03-31 15:41:00 +0800730 void __user *argp = (void __user *)arg;
Koji Sato7942b912009-04-06 19:01:41 -0700731
732 switch (cmd) {
Ryusuke Konishicde98f02011-01-20 02:09:53 +0900733 case FS_IOC_GETFLAGS:
734 return nilfs_ioctl_getflags(inode, argp);
735 case FS_IOC_SETFLAGS:
736 return nilfs_ioctl_setflags(inode, filp, argp);
737 case FS_IOC_GETVERSION:
738 return nilfs_ioctl_getversion(inode, argp);
Koji Sato7942b912009-04-06 19:01:41 -0700739 case NILFS_IOCTL_CHANGE_CPMODE:
740 return nilfs_ioctl_change_cpmode(inode, filp, cmd, argp);
741 case NILFS_IOCTL_DELETE_CHECKPOINT:
742 return nilfs_ioctl_delete_checkpoint(inode, filp, cmd, argp);
743 case NILFS_IOCTL_GET_CPINFO:
Ryusuke Konishi47eb6b92009-04-30 02:21:00 +0900744 return nilfs_ioctl_get_info(inode, filp, cmd, argp,
Ryusuke Konishi83aca8f2009-05-11 23:24:47 +0900745 sizeof(struct nilfs_cpinfo),
Ryusuke Konishi47eb6b92009-04-30 02:21:00 +0900746 nilfs_ioctl_do_get_cpinfo);
Koji Sato7942b912009-04-06 19:01:41 -0700747 case NILFS_IOCTL_GET_CPSTAT:
748 return nilfs_ioctl_get_cpstat(inode, filp, cmd, argp);
749 case NILFS_IOCTL_GET_SUINFO:
Ryusuke Konishi47eb6b92009-04-30 02:21:00 +0900750 return nilfs_ioctl_get_info(inode, filp, cmd, argp,
Ryusuke Konishi83aca8f2009-05-11 23:24:47 +0900751 sizeof(struct nilfs_suinfo),
Ryusuke Konishi47eb6b92009-04-30 02:21:00 +0900752 nilfs_ioctl_do_get_suinfo);
Koji Sato7942b912009-04-06 19:01:41 -0700753 case NILFS_IOCTL_GET_SUSTAT:
754 return nilfs_ioctl_get_sustat(inode, filp, cmd, argp);
755 case NILFS_IOCTL_GET_VINFO:
Ryusuke Konishi47eb6b92009-04-30 02:21:00 +0900756 return nilfs_ioctl_get_info(inode, filp, cmd, argp,
Ryusuke Konishi83aca8f2009-05-11 23:24:47 +0900757 sizeof(struct nilfs_vinfo),
Ryusuke Konishi47eb6b92009-04-30 02:21:00 +0900758 nilfs_ioctl_do_get_vinfo);
Koji Sato7942b912009-04-06 19:01:41 -0700759 case NILFS_IOCTL_GET_BDESCS:
760 return nilfs_ioctl_get_bdescs(inode, filp, cmd, argp);
761 case NILFS_IOCTL_CLEAN_SEGMENTS:
762 return nilfs_ioctl_clean_segments(inode, filp, cmd, argp);
Koji Sato7942b912009-04-06 19:01:41 -0700763 case NILFS_IOCTL_SYNC:
764 return nilfs_ioctl_sync(inode, filp, cmd, argp);
765 default:
766 return -ENOTTY;
767 }
768}