Blame view

fs/nilfs2/ioctl.c 35.6 KB
ae98043f5   Ryusuke Konishi   nilfs2: convert t...
1
  // SPDX-License-Identifier: GPL-2.0+
7942b919f   Koji Sato   nilfs2: ioctl ope...
2
3
4
5
6
  /*
   * ioctl.c - NILFS ioctl operations.
   *
   * Copyright (C) 2007, 2008 Nippon Telegraph and Telephone Corporation.
   *
4b420ab4e   Ryusuke Konishi   nilfs2: clean up ...
7
   * Written by Koji Sato.
7942b919f   Koji Sato   nilfs2: ioctl ope...
8
9
10
11
   */
  
  #include <linux/fs.h>
  #include <linux/wait.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
12
  #include <linux/slab.h>
7942b919f   Koji Sato   nilfs2: ioctl ope...
13
14
  #include <linux/capability.h>	/* capable() */
  #include <linux/uaccess.h>	/* copy_from_user(), copy_to_user() */
4f6b82883   Ryusuke Konishi   nilfs2: fix lock ...
15
  #include <linux/vmalloc.h>
828b1c50a   Ryusuke Konishi   nilfs2: add compa...
16
  #include <linux/compat.h>	/* compat_ptr() */
2a79f17e4   Al Viro   vfs: mnt_drop_wri...
17
  #include <linux/mount.h>	/* mnt_want_write_file(), mnt_drop_write_file() */
ae191838b   Ryusuke Konishi   nilfs2: optimize ...
18
  #include <linux/buffer_head.h>
7942b919f   Koji Sato   nilfs2: ioctl ope...
19
20
21
22
23
24
  #include "nilfs.h"
  #include "segment.h"
  #include "bmap.h"
  #include "cpfile.h"
  #include "sufile.h"
  #include "dat.h"
d623a9420   Vyacheslav Dubeyko   nilfs2: add comme...
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
  /**
   * nilfs_ioctl_wrap_copy - wrapping function of get/set metadata info
   * @nilfs: nilfs object
   * @argv: vector of arguments from userspace
   * @dir: set of direction flags
   * @dofunc: concrete function of get/set metadata info
   *
   * Description: nilfs_ioctl_wrap_copy() gets/sets metadata info by means of
   * calling dofunc() function on the basis of @argv argument.
   *
   * Return Value: On success, 0 is returned and requested metadata info
   * is copied into userspace. On error, one of the following
   * negative error codes is returned.
   *
   * %-EINVAL - Invalid arguments from userspace.
   *
   * %-ENOMEM - Insufficient amount of memory available.
   *
   * %-EFAULT - Failure during execution of requested operation.
   */
7942b919f   Koji Sato   nilfs2: ioctl ope...
45
46
47
  static int nilfs_ioctl_wrap_copy(struct the_nilfs *nilfs,
  				 struct nilfs_argv *argv, int dir,
  				 ssize_t (*dofunc)(struct the_nilfs *,
b028fcfc4   Ryusuke Konishi   nilfs2: fix gc fa...
48
  						   __u64 *, int,
7942b919f   Koji Sato   nilfs2: ioctl ope...
49
50
51
  						   void *, size_t, size_t))
  {
  	void *buf;
dc498d09b   Ryusuke Konishi   nilfs2: use fixed...
52
  	void __user *base = (void __user *)(unsigned long)argv->v_base;
3358b4aaa   Ryusuke Konishi   nilfs2: fix probl...
53
  	size_t maxmembs, total, n;
7942b919f   Koji Sato   nilfs2: ioctl ope...
54
55
  	ssize_t nr;
  	int ret, i;
b028fcfc4   Ryusuke Konishi   nilfs2: fix gc fa...
56
  	__u64 pos, ppos;
7942b919f   Koji Sato   nilfs2: ioctl ope...
57
58
59
  
  	if (argv->v_nmembs == 0)
  		return 0;
3358b4aaa   Ryusuke Konishi   nilfs2: fix probl...
60
61
  	if (argv->v_size > PAGE_SIZE)
  		return -EINVAL;
4b15d6171   Wenliang Fan   fs/nilfs2: fix in...
62
63
64
65
66
67
68
  	/*
  	 * Reject pairs of a start item position (argv->v_index) and a
  	 * total count (argv->v_nmembs) which leads position 'pos' to
  	 * overflow by the increment at the end of the loop.
  	 */
  	if (argv->v_index > ~(__u64)0 - argv->v_nmembs)
  		return -EINVAL;
3358b4aaa   Ryusuke Konishi   nilfs2: fix probl...
69
70
  	buf = (void *)__get_free_pages(GFP_NOFS, 0);
  	if (unlikely(!buf))
7942b919f   Koji Sato   nilfs2: ioctl ope...
71
  		return -ENOMEM;
3358b4aaa   Ryusuke Konishi   nilfs2: fix probl...
72
  	maxmembs = PAGE_SIZE / argv->v_size;
7942b919f   Koji Sato   nilfs2: ioctl ope...
73
74
75
  
  	ret = 0;
  	total = 0;
b028fcfc4   Ryusuke Konishi   nilfs2: fix gc fa...
76
  	pos = argv->v_index;
7942b919f   Koji Sato   nilfs2: ioctl ope...
77
78
79
80
  	for (i = 0; i < argv->v_nmembs; i += n) {
  		n = (argv->v_nmembs - i < maxmembs) ?
  			argv->v_nmembs - i : maxmembs;
  		if ((dir & _IOC_WRITE) &&
dc498d09b   Ryusuke Konishi   nilfs2: use fixed...
81
82
  		    copy_from_user(buf, base + argv->v_size * i,
  				   argv->v_size * n)) {
7942b919f   Koji Sato   nilfs2: ioctl ope...
83
84
85
  			ret = -EFAULT;
  			break;
  		}
b028fcfc4   Ryusuke Konishi   nilfs2: fix gc fa...
86
  		ppos = pos;
8acfbf093   Pekka Enberg   nilfs2: clean up ...
87
  		nr = dofunc(nilfs, &pos, argv->v_flags, buf, argv->v_size,
b028fcfc4   Ryusuke Konishi   nilfs2: fix gc fa...
88
  			       n);
7942b919f   Koji Sato   nilfs2: ioctl ope...
89
90
91
92
93
  		if (nr < 0) {
  			ret = nr;
  			break;
  		}
  		if ((dir & _IOC_READ) &&
dc498d09b   Ryusuke Konishi   nilfs2: use fixed...
94
95
  		    copy_to_user(base + argv->v_size * i, buf,
  				 argv->v_size * nr)) {
7942b919f   Koji Sato   nilfs2: ioctl ope...
96
97
98
99
  			ret = -EFAULT;
  			break;
  		}
  		total += nr;
b028fcfc4   Ryusuke Konishi   nilfs2: fix gc fa...
100
101
102
103
  		if ((size_t)nr < n)
  			break;
  		if (pos == ppos)
  			pos += n;
7942b919f   Koji Sato   nilfs2: ioctl ope...
104
105
  	}
  	argv->v_nmembs = total;
3358b4aaa   Ryusuke Konishi   nilfs2: fix probl...
106
  	free_pages((unsigned long)buf, 0);
7942b919f   Koji Sato   nilfs2: ioctl ope...
107
108
  	return ret;
  }
d623a9420   Vyacheslav Dubeyko   nilfs2: add comme...
109
110
111
  /**
   * nilfs_ioctl_getflags - ioctl to support lsattr
   */
cde98f0f8   Ryusuke Konishi   nilfs2: implement...
112
113
114
115
116
117
  static int nilfs_ioctl_getflags(struct inode *inode, void __user *argp)
  {
  	unsigned int flags = NILFS_I(inode)->i_flags & FS_FL_USER_VISIBLE;
  
  	return put_user(flags, (int __user *)argp);
  }
d623a9420   Vyacheslav Dubeyko   nilfs2: add comme...
118
119
120
  /**
   * nilfs_ioctl_setflags - ioctl to support chattr
   */
cde98f0f8   Ryusuke Konishi   nilfs2: implement...
121
122
123
124
125
126
  static int nilfs_ioctl_setflags(struct inode *inode, struct file *filp,
  				void __user *argp)
  {
  	struct nilfs_transaction_info ti;
  	unsigned int flags, oldflags;
  	int ret;
2e1496707   Serge E. Hallyn   userns: rename is...
127
  	if (!inode_owner_or_capable(inode))
cde98f0f8   Ryusuke Konishi   nilfs2: implement...
128
129
130
131
  		return -EACCES;
  
  	if (get_user(flags, (int __user *)argp))
  		return -EFAULT;
a561be710   Al Viro   switch a bunch of...
132
  	ret = mnt_want_write_file(filp);
cde98f0f8   Ryusuke Konishi   nilfs2: implement...
133
134
135
136
  	if (ret)
  		return ret;
  
  	flags = nilfs_mask_flags(inode->i_mode, flags);
5955102c9   Al Viro   wrappers for ->i_...
137
  	inode_lock(inode);
cde98f0f8   Ryusuke Konishi   nilfs2: implement...
138
139
  
  	oldflags = NILFS_I(inode)->i_flags;
5aca28421   Darrick J. Wong   vfs: create a gen...
140
141
  	ret = vfs_ioc_setflags_prepare(inode, oldflags, flags);
  	if (ret)
cde98f0f8   Ryusuke Konishi   nilfs2: implement...
142
143
144
145
146
147
148
149
150
151
  		goto out;
  
  	ret = nilfs_transaction_begin(inode->i_sb, &ti, 0);
  	if (ret)
  		goto out;
  
  	NILFS_I(inode)->i_flags = (oldflags & ~FS_FL_USER_MODIFIABLE) |
  		(flags & FS_FL_USER_MODIFIABLE);
  
  	nilfs_set_inode_flags(inode);
078cd8279   Deepa Dinamani   fs: Replace CURRE...
152
  	inode->i_ctime = current_time(inode);
cde98f0f8   Ryusuke Konishi   nilfs2: implement...
153
154
155
156
157
158
  	if (IS_SYNC(inode))
  		nilfs_set_transaction_flag(NILFS_TI_SYNC);
  
  	nilfs_mark_inode_dirty(inode);
  	ret = nilfs_transaction_commit(inode->i_sb);
  out:
5955102c9   Al Viro   wrappers for ->i_...
159
  	inode_unlock(inode);
2a79f17e4   Al Viro   vfs: mnt_drop_wri...
160
  	mnt_drop_write_file(filp);
cde98f0f8   Ryusuke Konishi   nilfs2: implement...
161
162
  	return ret;
  }
d623a9420   Vyacheslav Dubeyko   nilfs2: add comme...
163
164
165
  /**
   * nilfs_ioctl_getversion - get info about a file's version (generation number)
   */
cde98f0f8   Ryusuke Konishi   nilfs2: implement...
166
167
168
169
  static int nilfs_ioctl_getversion(struct inode *inode, void __user *argp)
  {
  	return put_user(inode->i_generation, (int __user *)argp);
  }
d623a9420   Vyacheslav Dubeyko   nilfs2: add comme...
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
  /**
   * nilfs_ioctl_change_cpmode - change checkpoint mode (checkpoint/snapshot)
   * @inode: inode object
   * @filp: file object
   * @cmd: ioctl's request code
   * @argp: pointer on argument from userspace
   *
   * Description: nilfs_ioctl_change_cpmode() function changes mode of
   * given checkpoint between checkpoint and snapshot state. This ioctl
   * is used in chcp and mkcp utilities.
   *
   * Return Value: On success, 0 is returned and mode of a checkpoint is
   * changed. On error, one of the following negative error codes
   * is returned.
   *
   * %-EPERM - Operation not permitted.
   *
   * %-EFAULT - Failure during checkpoint mode changing.
   */
7942b919f   Koji Sato   nilfs2: ioctl ope...
189
190
191
  static int nilfs_ioctl_change_cpmode(struct inode *inode, struct file *filp,
  				     unsigned int cmd, void __user *argp)
  {
e3154e974   Ryusuke Konishi   nilfs2: get rid o...
192
  	struct the_nilfs *nilfs = inode->i_sb->s_fs_info;
7942b919f   Koji Sato   nilfs2: ioctl ope...
193
194
195
196
197
198
  	struct nilfs_transaction_info ti;
  	struct nilfs_cpmode cpmode;
  	int ret;
  
  	if (!capable(CAP_SYS_ADMIN))
  		return -EPERM;
7512487e6   Ryusuke Konishi   nilfs2: use mnt_w...
199

a561be710   Al Viro   switch a bunch of...
200
  	ret = mnt_want_write_file(filp);
7512487e6   Ryusuke Konishi   nilfs2: use mnt_w...
201
202
203
204
  	if (ret)
  		return ret;
  
  	ret = -EFAULT;
7942b919f   Koji Sato   nilfs2: ioctl ope...
205
  	if (copy_from_user(&cpmode, argp, sizeof(cpmode)))
7512487e6   Ryusuke Konishi   nilfs2: use mnt_w...
206
  		goto out;
7942b919f   Koji Sato   nilfs2: ioctl ope...
207

572d8b394   Ryusuke Konishi   nilfs2: fix deadl...
208
  	mutex_lock(&nilfs->ns_snapshot_mount_mutex);
7512487e6   Ryusuke Konishi   nilfs2: use mnt_w...
209

7942b919f   Koji Sato   nilfs2: ioctl ope...
210
211
  	nilfs_transaction_begin(inode->i_sb, &ti, 0);
  	ret = nilfs_cpfile_change_cpmode(
e3154e974   Ryusuke Konishi   nilfs2: get rid o...
212
  		nilfs->ns_cpfile, cpmode.cm_cno, cpmode.cm_mode);
7512487e6   Ryusuke Konishi   nilfs2: use mnt_w...
213
  	if (unlikely(ret < 0))
47420c799   Ryusuke Konishi   nilfs2: avoid dou...
214
  		nilfs_transaction_abort(inode->i_sb);
7512487e6   Ryusuke Konishi   nilfs2: use mnt_w...
215
216
  	else
  		nilfs_transaction_commit(inode->i_sb); /* never fails */
572d8b394   Ryusuke Konishi   nilfs2: fix deadl...
217
  	mutex_unlock(&nilfs->ns_snapshot_mount_mutex);
7512487e6   Ryusuke Konishi   nilfs2: use mnt_w...
218
  out:
2a79f17e4   Al Viro   vfs: mnt_drop_wri...
219
  	mnt_drop_write_file(filp);
7942b919f   Koji Sato   nilfs2: ioctl ope...
220
221
  	return ret;
  }
d623a9420   Vyacheslav Dubeyko   nilfs2: add comme...
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
  /**
   * nilfs_ioctl_delete_checkpoint - remove checkpoint
   * @inode: inode object
   * @filp: file object
   * @cmd: ioctl's request code
   * @argp: pointer on argument from userspace
   *
   * Description: nilfs_ioctl_delete_checkpoint() function removes
   * checkpoint from NILFS2 file system. This ioctl is used in rmcp
   * utility.
   *
   * Return Value: On success, 0 is returned and a checkpoint is
   * removed. On error, one of the following negative error codes
   * is returned.
   *
   * %-EPERM - Operation not permitted.
   *
   * %-EFAULT - Failure during checkpoint removing.
   */
7942b919f   Koji Sato   nilfs2: ioctl ope...
241
242
243
244
  static int
  nilfs_ioctl_delete_checkpoint(struct inode *inode, struct file *filp,
  			      unsigned int cmd, void __user *argp)
  {
e3154e974   Ryusuke Konishi   nilfs2: get rid o...
245
  	struct the_nilfs *nilfs = inode->i_sb->s_fs_info;
7942b919f   Koji Sato   nilfs2: ioctl ope...
246
247
248
249
250
251
  	struct nilfs_transaction_info ti;
  	__u64 cno;
  	int ret;
  
  	if (!capable(CAP_SYS_ADMIN))
  		return -EPERM;
7512487e6   Ryusuke Konishi   nilfs2: use mnt_w...
252

a561be710   Al Viro   switch a bunch of...
253
  	ret = mnt_want_write_file(filp);
7512487e6   Ryusuke Konishi   nilfs2: use mnt_w...
254
255
256
257
  	if (ret)
  		return ret;
  
  	ret = -EFAULT;
7942b919f   Koji Sato   nilfs2: ioctl ope...
258
  	if (copy_from_user(&cno, argp, sizeof(cno)))
7512487e6   Ryusuke Konishi   nilfs2: use mnt_w...
259
  		goto out;
7942b919f   Koji Sato   nilfs2: ioctl ope...
260
261
  
  	nilfs_transaction_begin(inode->i_sb, &ti, 0);
e3154e974   Ryusuke Konishi   nilfs2: get rid o...
262
  	ret = nilfs_cpfile_delete_checkpoint(nilfs->ns_cpfile, cno);
7512487e6   Ryusuke Konishi   nilfs2: use mnt_w...
263
  	if (unlikely(ret < 0))
47420c799   Ryusuke Konishi   nilfs2: avoid dou...
264
  		nilfs_transaction_abort(inode->i_sb);
7512487e6   Ryusuke Konishi   nilfs2: use mnt_w...
265
266
267
  	else
  		nilfs_transaction_commit(inode->i_sb); /* never fails */
  out:
2a79f17e4   Al Viro   vfs: mnt_drop_wri...
268
  	mnt_drop_write_file(filp);
7942b919f   Koji Sato   nilfs2: ioctl ope...
269
270
  	return ret;
  }
d623a9420   Vyacheslav Dubeyko   nilfs2: add comme...
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
  /**
   * nilfs_ioctl_do_get_cpinfo - callback method getting info about checkpoints
   * @nilfs: nilfs object
   * @posp: pointer on array of checkpoint's numbers
   * @flags: checkpoint mode (checkpoint or snapshot)
   * @buf: buffer for storing checkponts' info
   * @size: size in bytes of one checkpoint info item in array
   * @nmembs: number of checkpoints in array (numbers and infos)
   *
   * Description: nilfs_ioctl_do_get_cpinfo() function returns info about
   * requested checkpoints. The NILFS_IOCTL_GET_CPINFO ioctl is used in
   * lscp utility and by nilfs_cleanerd daemon.
   *
   * Return value: count of nilfs_cpinfo structures in output buffer.
   */
7942b919f   Koji Sato   nilfs2: ioctl ope...
286
  static ssize_t
b028fcfc4   Ryusuke Konishi   nilfs2: fix gc fa...
287
  nilfs_ioctl_do_get_cpinfo(struct the_nilfs *nilfs, __u64 *posp, int flags,
7942b919f   Koji Sato   nilfs2: ioctl ope...
288
289
  			  void *buf, size_t size, size_t nmembs)
  {
7942b919f   Koji Sato   nilfs2: ioctl ope...
290
  	int ret;
47420c799   Ryusuke Konishi   nilfs2: avoid dou...
291
  	down_read(&nilfs->ns_segctor_sem);
47eb6b9c8   Ryusuke Konishi   nilfs2: fix possi...
292
  	ret = nilfs_cpfile_get_cpinfo(nilfs->ns_cpfile, posp, flags, buf,
003ff182f   Ryusuke Konishi   nilfs2: allow fut...
293
  				      size, nmembs);
47420c799   Ryusuke Konishi   nilfs2: avoid dou...
294
  	up_read(&nilfs->ns_segctor_sem);
7942b919f   Koji Sato   nilfs2: ioctl ope...
295
296
  	return ret;
  }
d623a9420   Vyacheslav Dubeyko   nilfs2: add comme...
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
  /**
   * nilfs_ioctl_get_cpstat - get checkpoints statistics
   * @inode: inode object
   * @filp: file object
   * @cmd: ioctl's request code
   * @argp: pointer on argument from userspace
   *
   * Description: nilfs_ioctl_get_cpstat() returns information about checkpoints.
   * The NILFS_IOCTL_GET_CPSTAT ioctl is used by lscp, rmcp utilities
   * and by nilfs_cleanerd daemon.
   *
   * Return Value: On success, 0 is returned, and checkpoints information is
   * copied into userspace pointer @argp. On error, one of the following
   * negative error codes is returned.
   *
   * %-EIO - I/O error.
   *
   * %-ENOMEM - Insufficient amount of memory available.
   *
   * %-EFAULT - Failure during getting checkpoints statistics.
   */
7942b919f   Koji Sato   nilfs2: ioctl ope...
318
319
320
  static int nilfs_ioctl_get_cpstat(struct inode *inode, struct file *filp,
  				  unsigned int cmd, void __user *argp)
  {
e3154e974   Ryusuke Konishi   nilfs2: get rid o...
321
  	struct the_nilfs *nilfs = inode->i_sb->s_fs_info;
7942b919f   Koji Sato   nilfs2: ioctl ope...
322
  	struct nilfs_cpstat cpstat;
7942b919f   Koji Sato   nilfs2: ioctl ope...
323
  	int ret;
47420c799   Ryusuke Konishi   nilfs2: avoid dou...
324
325
326
  	down_read(&nilfs->ns_segctor_sem);
  	ret = nilfs_cpfile_get_stat(nilfs->ns_cpfile, &cpstat);
  	up_read(&nilfs->ns_segctor_sem);
7942b919f   Koji Sato   nilfs2: ioctl ope...
327
328
329
330
331
332
333
  	if (ret < 0)
  		return ret;
  
  	if (copy_to_user(argp, &cpstat, sizeof(cpstat)))
  		ret = -EFAULT;
  	return ret;
  }
d623a9420   Vyacheslav Dubeyko   nilfs2: add comme...
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
  /**
   * nilfs_ioctl_do_get_suinfo - callback method getting segment usage info
   * @nilfs: nilfs object
   * @posp: pointer on array of segment numbers
   * @flags: *not used*
   * @buf: buffer for storing suinfo array
   * @size: size in bytes of one suinfo item in array
   * @nmembs: count of segment numbers and suinfos in array
   *
   * Description: nilfs_ioctl_do_get_suinfo() function returns segment usage
   * info about requested segments. The NILFS_IOCTL_GET_SUINFO ioctl is used
   * in lssu, nilfs_resize utilities and by nilfs_cleanerd daemon.
   *
   * Return value: count of nilfs_suinfo structures in output buffer.
   */
7942b919f   Koji Sato   nilfs2: ioctl ope...
349
  static ssize_t
b028fcfc4   Ryusuke Konishi   nilfs2: fix gc fa...
350
  nilfs_ioctl_do_get_suinfo(struct the_nilfs *nilfs, __u64 *posp, int flags,
7942b919f   Koji Sato   nilfs2: ioctl ope...
351
352
  			  void *buf, size_t size, size_t nmembs)
  {
7942b919f   Koji Sato   nilfs2: ioctl ope...
353
  	int ret;
47420c799   Ryusuke Konishi   nilfs2: avoid dou...
354
  	down_read(&nilfs->ns_segctor_sem);
003ff182f   Ryusuke Konishi   nilfs2: allow fut...
355
356
  	ret = nilfs_sufile_get_suinfo(nilfs->ns_sufile, *posp, buf, size,
  				      nmembs);
47420c799   Ryusuke Konishi   nilfs2: avoid dou...
357
  	up_read(&nilfs->ns_segctor_sem);
7942b919f   Koji Sato   nilfs2: ioctl ope...
358
359
  	return ret;
  }
d623a9420   Vyacheslav Dubeyko   nilfs2: add comme...
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
  /**
   * nilfs_ioctl_get_sustat - get segment usage statistics
   * @inode: inode object
   * @filp: file object
   * @cmd: ioctl's request code
   * @argp: pointer on argument from userspace
   *
   * Description: nilfs_ioctl_get_sustat() returns segment usage statistics.
   * The NILFS_IOCTL_GET_SUSTAT ioctl is used in lssu, nilfs_resize utilities
   * and by nilfs_cleanerd daemon.
   *
   * Return Value: On success, 0 is returned, and segment usage information is
   * copied into userspace pointer @argp. On error, one of the following
   * negative error codes is returned.
   *
   * %-EIO - I/O error.
   *
   * %-ENOMEM - Insufficient amount of memory available.
   *
   * %-EFAULT - Failure during getting segment usage statistics.
   */
7942b919f   Koji Sato   nilfs2: ioctl ope...
381
382
383
  static int nilfs_ioctl_get_sustat(struct inode *inode, struct file *filp,
  				  unsigned int cmd, void __user *argp)
  {
e3154e974   Ryusuke Konishi   nilfs2: get rid o...
384
  	struct the_nilfs *nilfs = inode->i_sb->s_fs_info;
7942b919f   Koji Sato   nilfs2: ioctl ope...
385
  	struct nilfs_sustat sustat;
7942b919f   Koji Sato   nilfs2: ioctl ope...
386
  	int ret;
47420c799   Ryusuke Konishi   nilfs2: avoid dou...
387
388
389
  	down_read(&nilfs->ns_segctor_sem);
  	ret = nilfs_sufile_get_stat(nilfs->ns_sufile, &sustat);
  	up_read(&nilfs->ns_segctor_sem);
7942b919f   Koji Sato   nilfs2: ioctl ope...
390
391
392
393
394
395
396
  	if (ret < 0)
  		return ret;
  
  	if (copy_to_user(argp, &sustat, sizeof(sustat)))
  		ret = -EFAULT;
  	return ret;
  }
d623a9420   Vyacheslav Dubeyko   nilfs2: add comme...
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
  /**
   * nilfs_ioctl_do_get_vinfo - callback method getting virtual blocks info
   * @nilfs: nilfs object
   * @posp: *not used*
   * @flags: *not used*
   * @buf: buffer for storing array of nilfs_vinfo structures
   * @size: size in bytes of one vinfo item in array
   * @nmembs: count of vinfos in array
   *
   * Description: nilfs_ioctl_do_get_vinfo() function returns information
   * on virtual block addresses. The NILFS_IOCTL_GET_VINFO ioctl is used
   * by nilfs_cleanerd daemon.
   *
   * Return value: count of nilfs_vinfo structures in output buffer.
   */
7942b919f   Koji Sato   nilfs2: ioctl ope...
412
  static ssize_t
b028fcfc4   Ryusuke Konishi   nilfs2: fix gc fa...
413
  nilfs_ioctl_do_get_vinfo(struct the_nilfs *nilfs, __u64 *posp, int flags,
7942b919f   Koji Sato   nilfs2: ioctl ope...
414
415
  			 void *buf, size_t size, size_t nmembs)
  {
7942b919f   Koji Sato   nilfs2: ioctl ope...
416
  	int ret;
47420c799   Ryusuke Konishi   nilfs2: avoid dou...
417
  	down_read(&nilfs->ns_segctor_sem);
365e215ce   Ryusuke Konishi   nilfs2: unfold ni...
418
  	ret = nilfs_dat_get_vinfo(nilfs->ns_dat, buf, size, nmembs);
47420c799   Ryusuke Konishi   nilfs2: avoid dou...
419
  	up_read(&nilfs->ns_segctor_sem);
7942b919f   Koji Sato   nilfs2: ioctl ope...
420
421
  	return ret;
  }
d623a9420   Vyacheslav Dubeyko   nilfs2: add comme...
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
  /**
   * nilfs_ioctl_do_get_bdescs - callback method getting disk block descriptors
   * @nilfs: nilfs object
   * @posp: *not used*
   * @flags: *not used*
   * @buf: buffer for storing array of nilfs_bdesc structures
   * @size: size in bytes of one bdesc item in array
   * @nmembs: count of bdescs in array
   *
   * Description: nilfs_ioctl_do_get_bdescs() function returns information
   * about descriptors of disk block numbers. The NILFS_IOCTL_GET_BDESCS ioctl
   * is used by nilfs_cleanerd daemon.
   *
   * Return value: count of nilfs_bdescs structures in output buffer.
   */
7942b919f   Koji Sato   nilfs2: ioctl ope...
437
  static ssize_t
b028fcfc4   Ryusuke Konishi   nilfs2: fix gc fa...
438
  nilfs_ioctl_do_get_bdescs(struct the_nilfs *nilfs, __u64 *posp, int flags,
7942b919f   Koji Sato   nilfs2: ioctl ope...
439
440
  			  void *buf, size_t size, size_t nmembs)
  {
365e215ce   Ryusuke Konishi   nilfs2: unfold ni...
441
  	struct nilfs_bmap *bmap = NILFS_I(nilfs->ns_dat)->i_bmap;
7942b919f   Koji Sato   nilfs2: ioctl ope...
442
443
  	struct nilfs_bdesc *bdescs = buf;
  	int ret, i;
47eb6b9c8   Ryusuke Konishi   nilfs2: fix possi...
444
  	down_read(&nilfs->ns_segctor_sem);
7942b919f   Koji Sato   nilfs2: ioctl ope...
445
446
447
448
449
450
  	for (i = 0; i < nmembs; i++) {
  		ret = nilfs_bmap_lookup_at_level(bmap,
  						 bdescs[i].bd_offset,
  						 bdescs[i].bd_level + 1,
  						 &bdescs[i].bd_blocknr);
  		if (ret < 0) {
47eb6b9c8   Ryusuke Konishi   nilfs2: fix possi...
451
452
  			if (ret != -ENOENT) {
  				up_read(&nilfs->ns_segctor_sem);
7942b919f   Koji Sato   nilfs2: ioctl ope...
453
  				return ret;
47eb6b9c8   Ryusuke Konishi   nilfs2: fix possi...
454
  			}
7942b919f   Koji Sato   nilfs2: ioctl ope...
455
456
457
  			bdescs[i].bd_blocknr = 0;
  		}
  	}
47eb6b9c8   Ryusuke Konishi   nilfs2: fix possi...
458
  	up_read(&nilfs->ns_segctor_sem);
7942b919f   Koji Sato   nilfs2: ioctl ope...
459
460
  	return nmembs;
  }
d623a9420   Vyacheslav Dubeyko   nilfs2: add comme...
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
  /**
   * nilfs_ioctl_get_bdescs - get disk block descriptors
   * @inode: inode object
   * @filp: file object
   * @cmd: ioctl's request code
   * @argp: pointer on argument from userspace
   *
   * Description: nilfs_ioctl_do_get_bdescs() function returns information
   * about descriptors of disk block numbers. The NILFS_IOCTL_GET_BDESCS ioctl
   * is used by nilfs_cleanerd daemon.
   *
   * Return Value: On success, 0 is returned, and disk block descriptors are
   * copied into userspace pointer @argp. On error, one of the following
   * negative error codes is returned.
   *
   * %-EINVAL - Invalid arguments from userspace.
   *
   * %-EIO - I/O error.
   *
   * %-ENOMEM - Insufficient amount of memory available.
   *
   * %-EFAULT - Failure during getting disk block descriptors.
   */
7942b919f   Koji Sato   nilfs2: ioctl ope...
484
485
486
  static int nilfs_ioctl_get_bdescs(struct inode *inode, struct file *filp,
  				  unsigned int cmd, void __user *argp)
  {
e3154e974   Ryusuke Konishi   nilfs2: get rid o...
487
  	struct the_nilfs *nilfs = inode->i_sb->s_fs_info;
7942b919f   Koji Sato   nilfs2: ioctl ope...
488
  	struct nilfs_argv argv;
7942b919f   Koji Sato   nilfs2: ioctl ope...
489
490
491
492
  	int ret;
  
  	if (copy_from_user(&argv, argp, sizeof(argv)))
  		return -EFAULT;
83aca8f48   Ryusuke Konishi   nilfs2: check siz...
493
494
  	if (argv.v_size != sizeof(struct nilfs_bdesc))
  		return -EINVAL;
7942b919f   Koji Sato   nilfs2: ioctl ope...
495
496
  	ret = nilfs_ioctl_wrap_copy(nilfs, &argv, _IOC_DIR(cmd),
  				    nilfs_ioctl_do_get_bdescs);
47420c799   Ryusuke Konishi   nilfs2: avoid dou...
497
498
  	if (ret < 0)
  		return ret;
7942b919f   Koji Sato   nilfs2: ioctl ope...
499
500
501
502
503
  
  	if (copy_to_user(argp, &argv, sizeof(argv)))
  		ret = -EFAULT;
  	return ret;
  }
d623a9420   Vyacheslav Dubeyko   nilfs2: add comme...
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
  /**
   * nilfs_ioctl_move_inode_block - prepare data/node block for moving by GC
   * @inode: inode object
   * @vdesc: descriptor of virtual block number
   * @buffers: list of moving buffers
   *
   * Description: nilfs_ioctl_move_inode_block() function registers data/node
   * buffer in the GC pagecache and submit read request.
   *
   * Return Value: On success, 0 is returned. On error, one of the following
   * negative error codes is returned.
   *
   * %-EIO - I/O error.
   *
   * %-ENOMEM - Insufficient amount of memory available.
   *
   * %-ENOENT - Requested block doesn't exist.
   *
   * %-EEXIST - Blocks conflict is detected.
   */
7942b919f   Koji Sato   nilfs2: ioctl ope...
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
  static int nilfs_ioctl_move_inode_block(struct inode *inode,
  					struct nilfs_vdesc *vdesc,
  					struct list_head *buffers)
  {
  	struct buffer_head *bh;
  	int ret;
  
  	if (vdesc->vd_flags == 0)
  		ret = nilfs_gccache_submit_read_data(
  			inode, vdesc->vd_offset, vdesc->vd_blocknr,
  			vdesc->vd_vblocknr, &bh);
  	else
  		ret = nilfs_gccache_submit_read_node(
  			inode, vdesc->vd_blocknr, vdesc->vd_vblocknr, &bh);
  
  	if (unlikely(ret < 0)) {
  		if (ret == -ENOENT)
a1d0747a3   Joe Perches   nilfs2: use a mor...
541
542
543
544
545
546
547
548
  			nilfs_crit(inode->i_sb,
  				   "%s: invalid virtual block address (%s): ino=%llu, cno=%llu, offset=%llu, blocknr=%llu, vblocknr=%llu",
  				   __func__, vdesc->vd_flags ? "node" : "data",
  				   (unsigned long long)vdesc->vd_ino,
  				   (unsigned long long)vdesc->vd_cno,
  				   (unsigned long long)vdesc->vd_offset,
  				   (unsigned long long)vdesc->vd_blocknr,
  				   (unsigned long long)vdesc->vd_vblocknr);
7942b919f   Koji Sato   nilfs2: ioctl ope...
549
550
  		return ret;
  	}
5399dd1fc   Ryusuke Konishi   nilfs2: fix kerne...
551
  	if (unlikely(!list_empty(&bh->b_assoc_buffers))) {
a1d0747a3   Joe Perches   nilfs2: use a mor...
552
553
554
555
556
557
558
559
  		nilfs_crit(inode->i_sb,
  			   "%s: conflicting %s buffer: ino=%llu, cno=%llu, offset=%llu, blocknr=%llu, vblocknr=%llu",
  			   __func__, vdesc->vd_flags ? "node" : "data",
  			   (unsigned long long)vdesc->vd_ino,
  			   (unsigned long long)vdesc->vd_cno,
  			   (unsigned long long)vdesc->vd_offset,
  			   (unsigned long long)vdesc->vd_blocknr,
  			   (unsigned long long)vdesc->vd_vblocknr);
5399dd1fc   Ryusuke Konishi   nilfs2: fix kerne...
560
561
562
  		brelse(bh);
  		return -EEXIST;
  	}
7942b919f   Koji Sato   nilfs2: ioctl ope...
563
564
565
  	list_add_tail(&bh->b_assoc_buffers, buffers);
  	return 0;
  }
d623a9420   Vyacheslav Dubeyko   nilfs2: add comme...
566
567
568
569
570
571
572
573
574
575
576
577
578
  /**
   * nilfs_ioctl_move_blocks - move valid inode's blocks during garbage collection
   * @sb: superblock object
   * @argv: vector of arguments from userspace
   * @buf: array of nilfs_vdesc structures
   *
   * Description: nilfs_ioctl_move_blocks() function reads valid data/node
   * blocks that garbage collector specified with the array of nilfs_vdesc
   * structures and stores them into page caches of GC inodes.
   *
   * Return Value: Number of processed nilfs_vdesc structures or
   * error code, otherwise.
   */
263d90cef   Ryusuke Konishi   nilfs2: remove ow...
579
  static int nilfs_ioctl_move_blocks(struct super_block *sb,
4f6b82883   Ryusuke Konishi   nilfs2: fix lock ...
580
  				   struct nilfs_argv *argv, void *buf)
7942b919f   Koji Sato   nilfs2: ioctl ope...
581
  {
4f6b82883   Ryusuke Konishi   nilfs2: fix lock ...
582
  	size_t nmembs = argv->v_nmembs;
e3154e974   Ryusuke Konishi   nilfs2: get rid o...
583
  	struct the_nilfs *nilfs = sb->s_fs_info;
7942b919f   Koji Sato   nilfs2: ioctl ope...
584
585
586
587
588
589
590
591
592
593
594
  	struct inode *inode;
  	struct nilfs_vdesc *vdesc;
  	struct buffer_head *bh, *n;
  	LIST_HEAD(buffers);
  	ino_t ino;
  	__u64 cno;
  	int i, ret;
  
  	for (i = 0, vdesc = buf; i < nmembs; ) {
  		ino = vdesc->vd_ino;
  		cno = vdesc->vd_cno;
263d90cef   Ryusuke Konishi   nilfs2: remove ow...
595
  		inode = nilfs_iget_for_gc(sb, ino, cno);
103cfcf52   Dan Carpenter   nilfs2: nilfs_ige...
596
597
  		if (IS_ERR(inode)) {
  			ret = PTR_ERR(inode);
7942b919f   Koji Sato   nilfs2: ioctl ope...
598
599
  			goto failed;
  		}
947b10ae0   Ryusuke Konishi   nilfs2: fix regre...
600
601
602
603
604
605
606
607
608
609
  		if (list_empty(&NILFS_I(inode)->i_dirty)) {
  			/*
  			 * Add the inode to GC inode list. Garbage Collection
  			 * is serialized and no two processes manipulate the
  			 * list simultaneously.
  			 */
  			igrab(inode);
  			list_add(&NILFS_I(inode)->i_dirty,
  				 &nilfs->ns_gc_inodes);
  		}
7942b919f   Koji Sato   nilfs2: ioctl ope...
610
611
612
  		do {
  			ret = nilfs_ioctl_move_inode_block(inode, vdesc,
  							   &buffers);
263d90cef   Ryusuke Konishi   nilfs2: remove ow...
613
614
  			if (unlikely(ret < 0)) {
  				iput(inode);
7942b919f   Koji Sato   nilfs2: ioctl ope...
615
  				goto failed;
263d90cef   Ryusuke Konishi   nilfs2: remove ow...
616
  			}
7942b919f   Koji Sato   nilfs2: ioctl ope...
617
618
619
  			vdesc++;
  		} while (++i < nmembs &&
  			 vdesc->vd_ino == ino && vdesc->vd_cno == cno);
263d90cef   Ryusuke Konishi   nilfs2: remove ow...
620
621
  
  		iput(inode); /* The inode still remains in GC inode list */
7942b919f   Koji Sato   nilfs2: ioctl ope...
622
623
624
625
626
  	}
  
  	list_for_each_entry_safe(bh, n, &buffers, b_assoc_buffers) {
  		ret = nilfs_gccache_wait_and_mark_dirty(bh);
  		if (unlikely(ret < 0)) {
5399dd1fc   Ryusuke Konishi   nilfs2: fix kerne...
627
  			WARN_ON(ret == -EEXIST);
7942b919f   Koji Sato   nilfs2: ioctl ope...
628
629
630
  			goto failed;
  		}
  		list_del_init(&bh->b_assoc_buffers);
7942b919f   Koji Sato   nilfs2: ioctl ope...
631
632
633
634
635
636
637
  		brelse(bh);
  	}
  	return nmembs;
  
   failed:
  	list_for_each_entry_safe(bh, n, &buffers, b_assoc_buffers) {
  		list_del_init(&bh->b_assoc_buffers);
7942b919f   Koji Sato   nilfs2: ioctl ope...
638
639
640
641
  		brelse(bh);
  	}
  	return ret;
  }
d623a9420   Vyacheslav Dubeyko   nilfs2: add comme...
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
  /**
   * nilfs_ioctl_delete_checkpoints - delete checkpoints
   * @nilfs: nilfs object
   * @argv: vector of arguments from userspace
   * @buf: array of periods of checkpoints numbers
   *
   * Description: nilfs_ioctl_delete_checkpoints() function deletes checkpoints
   * in the period from p_start to p_end, excluding p_end itself. The checkpoints
   * which have been already deleted are ignored.
   *
   * Return Value: Number of processed nilfs_period structures or
   * error code, otherwise.
   *
   * %-EIO - I/O error.
   *
   * %-ENOMEM - Insufficient amount of memory available.
   *
   * %-EINVAL - invalid checkpoints.
   */
4f6b82883   Ryusuke Konishi   nilfs2: fix lock ...
661
662
  static int nilfs_ioctl_delete_checkpoints(struct the_nilfs *nilfs,
  					  struct nilfs_argv *argv, void *buf)
7942b919f   Koji Sato   nilfs2: ioctl ope...
663
  {
4f6b82883   Ryusuke Konishi   nilfs2: fix lock ...
664
  	size_t nmembs = argv->v_nmembs;
7942b919f   Koji Sato   nilfs2: ioctl ope...
665
666
667
668
669
670
671
672
673
674
675
676
  	struct inode *cpfile = nilfs->ns_cpfile;
  	struct nilfs_period *periods = buf;
  	int ret, i;
  
  	for (i = 0; i < nmembs; i++) {
  		ret = nilfs_cpfile_delete_checkpoints(
  			cpfile, periods[i].p_start, periods[i].p_end);
  		if (ret < 0)
  			return ret;
  	}
  	return nmembs;
  }
d623a9420   Vyacheslav Dubeyko   nilfs2: add comme...
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
  /**
   * nilfs_ioctl_free_vblocknrs - free virtual block numbers
   * @nilfs: nilfs object
   * @argv: vector of arguments from userspace
   * @buf: array of virtual block numbers
   *
   * Description: nilfs_ioctl_free_vblocknrs() function frees
   * the virtual block numbers specified by @buf and @argv->v_nmembs.
   *
   * Return Value: Number of processed virtual block numbers or
   * error code, otherwise.
   *
   * %-EIO - I/O error.
   *
   * %-ENOMEM - Insufficient amount of memory available.
   *
   * %-ENOENT - The virtual block number have not been allocated.
   */
4f6b82883   Ryusuke Konishi   nilfs2: fix lock ...
695
696
  static int nilfs_ioctl_free_vblocknrs(struct the_nilfs *nilfs,
  				      struct nilfs_argv *argv, void *buf)
7942b919f   Koji Sato   nilfs2: ioctl ope...
697
  {
4f6b82883   Ryusuke Konishi   nilfs2: fix lock ...
698
699
  	size_t nmembs = argv->v_nmembs;
  	int ret;
7942b919f   Koji Sato   nilfs2: ioctl ope...
700

365e215ce   Ryusuke Konishi   nilfs2: unfold ni...
701
  	ret = nilfs_dat_freev(nilfs->ns_dat, buf, nmembs);
7942b919f   Koji Sato   nilfs2: ioctl ope...
702
703
704
  
  	return (ret < 0) ? ret : nmembs;
  }
d623a9420   Vyacheslav Dubeyko   nilfs2: add comme...
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
  /**
   * nilfs_ioctl_mark_blocks_dirty - mark blocks dirty
   * @nilfs: nilfs object
   * @argv: vector of arguments from userspace
   * @buf: array of block descriptors
   *
   * Description: nilfs_ioctl_mark_blocks_dirty() function marks
   * metadata file or data blocks as dirty.
   *
   * Return Value: Number of processed block descriptors or
   * error code, otherwise.
   *
   * %-ENOMEM - Insufficient memory available.
   *
   * %-EIO - I/O error
   *
   * %-ENOENT - the specified block does not exist (hole block)
   */
4f6b82883   Ryusuke Konishi   nilfs2: fix lock ...
723
724
  static int nilfs_ioctl_mark_blocks_dirty(struct the_nilfs *nilfs,
  					 struct nilfs_argv *argv, void *buf)
7942b919f   Koji Sato   nilfs2: ioctl ope...
725
  {
4f6b82883   Ryusuke Konishi   nilfs2: fix lock ...
726
  	size_t nmembs = argv->v_nmembs;
365e215ce   Ryusuke Konishi   nilfs2: unfold ni...
727
  	struct nilfs_bmap *bmap = NILFS_I(nilfs->ns_dat)->i_bmap;
7942b919f   Koji Sato   nilfs2: ioctl ope...
728
  	struct nilfs_bdesc *bdescs = buf;
24e20ead2   Ryusuke Konishi   nilfs2: get rid o...
729
  	struct buffer_head *bh;
7942b919f   Koji Sato   nilfs2: ioctl ope...
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
  	int ret, i;
  
  	for (i = 0; i < nmembs; i++) {
  		/* XXX: use macro or inline func to check liveness */
  		ret = nilfs_bmap_lookup_at_level(bmap,
  						 bdescs[i].bd_offset,
  						 bdescs[i].bd_level + 1,
  						 &bdescs[i].bd_blocknr);
  		if (ret < 0) {
  			if (ret != -ENOENT)
  				return ret;
  			bdescs[i].bd_blocknr = 0;
  		}
  		if (bdescs[i].bd_blocknr != bdescs[i].bd_oblocknr)
  			/* skip dead block */
  			continue;
  		if (bdescs[i].bd_level == 0) {
24e20ead2   Ryusuke Konishi   nilfs2: get rid o...
747
748
749
750
  			ret = nilfs_mdt_get_block(nilfs->ns_dat,
  						  bdescs[i].bd_offset,
  						  false, NULL, &bh);
  			if (unlikely(ret)) {
1f5abe7e7   Ryusuke Konishi   nilfs2: replace B...
751
  				WARN_ON(ret == -ENOENT);
7942b919f   Koji Sato   nilfs2: ioctl ope...
752
753
  				return ret;
  			}
24e20ead2   Ryusuke Konishi   nilfs2: get rid o...
754
755
756
  			mark_buffer_dirty(bh);
  			nilfs_mdt_mark_dirty(nilfs->ns_dat);
  			put_bh(bh);
7942b919f   Koji Sato   nilfs2: ioctl ope...
757
758
759
760
  		} else {
  			ret = nilfs_bmap_mark(bmap, bdescs[i].bd_offset,
  					      bdescs[i].bd_level);
  			if (ret < 0) {
1f5abe7e7   Ryusuke Konishi   nilfs2: replace B...
761
  				WARN_ON(ret == -ENOENT);
7942b919f   Koji Sato   nilfs2: ioctl ope...
762
763
764
765
766
767
  				return ret;
  			}
  		}
  	}
  	return nmembs;
  }
7942b919f   Koji Sato   nilfs2: ioctl ope...
768
  int nilfs_ioctl_prepare_clean_segments(struct the_nilfs *nilfs,
4f6b82883   Ryusuke Konishi   nilfs2: fix lock ...
769
  				       struct nilfs_argv *argv, void **kbufs)
7942b919f   Koji Sato   nilfs2: ioctl ope...
770
  {
1f5abe7e7   Ryusuke Konishi   nilfs2: replace B...
771
  	const char *msg;
4f6b82883   Ryusuke Konishi   nilfs2: fix lock ...
772
  	int ret;
7942b919f   Koji Sato   nilfs2: ioctl ope...
773

4f6b82883   Ryusuke Konishi   nilfs2: fix lock ...
774
  	ret = nilfs_ioctl_delete_checkpoints(nilfs, &argv[1], kbufs[1]);
1f5abe7e7   Ryusuke Konishi   nilfs2: replace B...
775
776
777
778
779
780
781
782
  	if (ret < 0) {
  		/*
  		 * can safely abort because checkpoints can be removed
  		 * independently.
  		 */
  		msg = "cannot delete checkpoints";
  		goto failed;
  	}
4f6b82883   Ryusuke Konishi   nilfs2: fix lock ...
783
  	ret = nilfs_ioctl_free_vblocknrs(nilfs, &argv[2], kbufs[2]);
1f5abe7e7   Ryusuke Konishi   nilfs2: replace B...
784
785
786
787
788
789
790
791
  	if (ret < 0) {
  		/*
  		 * can safely abort because DAT file is updated atomically
  		 * using a copy-on-write technique.
  		 */
  		msg = "cannot delete virtual blocks from DAT file";
  		goto failed;
  	}
4f6b82883   Ryusuke Konishi   nilfs2: fix lock ...
792
  	ret = nilfs_ioctl_mark_blocks_dirty(nilfs, &argv[3], kbufs[3]);
1f5abe7e7   Ryusuke Konishi   nilfs2: replace B...
793
794
795
796
797
798
799
  	if (ret < 0) {
  		/*
  		 * can safely abort because the operation is nondestructive.
  		 */
  		msg = "cannot mark copying blocks dirty";
  		goto failed;
  	}
7942b919f   Koji Sato   nilfs2: ioctl ope...
800
  	return 0;
1f5abe7e7   Ryusuke Konishi   nilfs2: replace B...
801
   failed:
a1d0747a3   Joe Perches   nilfs2: use a mor...
802
  	nilfs_err(nilfs->ns_sb, "error %d preparing GC: %s", ret, msg);
7942b919f   Koji Sato   nilfs2: ioctl ope...
803
804
  	return ret;
  }
d623a9420   Vyacheslav Dubeyko   nilfs2: add comme...
805
806
807
808
809
810
811
812
813
814
815
816
817
818
  /**
   * nilfs_ioctl_clean_segments - clean segments
   * @inode: inode object
   * @filp: file object
   * @cmd: ioctl's request code
   * @argp: pointer on argument from userspace
   *
   * Description: nilfs_ioctl_clean_segments() function makes garbage
   * collection operation in the environment of requested parameters
   * from userspace. The NILFS_IOCTL_CLEAN_SEGMENTS ioctl is used by
   * nilfs_cleanerd daemon.
   *
   * Return Value: On success, 0 is returned or error code, otherwise.
   */
7942b919f   Koji Sato   nilfs2: ioctl ope...
819
820
821
  static int nilfs_ioctl_clean_segments(struct inode *inode, struct file *filp,
  				      unsigned int cmd, void __user *argp)
  {
4f6b82883   Ryusuke Konishi   nilfs2: fix lock ...
822
  	struct nilfs_argv argv[5];
33e189bd5   Tobias Klauser   nilfs2: Storage c...
823
  	static const size_t argsz[5] = {
4f6b82883   Ryusuke Konishi   nilfs2: fix lock ...
824
825
826
827
828
829
830
831
832
833
834
  		sizeof(struct nilfs_vdesc),
  		sizeof(struct nilfs_period),
  		sizeof(__u64),
  		sizeof(struct nilfs_bdesc),
  		sizeof(__u64),
  	};
  	void __user *base;
  	void *kbufs[5];
  	struct the_nilfs *nilfs;
  	size_t len, nsegs;
  	int n, ret;
7942b919f   Koji Sato   nilfs2: ioctl ope...
835
836
  	if (!capable(CAP_SYS_ADMIN))
  		return -EPERM;
4f6b82883   Ryusuke Konishi   nilfs2: fix lock ...
837

a561be710   Al Viro   switch a bunch of...
838
  	ret = mnt_want_write_file(filp);
7512487e6   Ryusuke Konishi   nilfs2: use mnt_w...
839
840
841
842
  	if (ret)
  		return ret;
  
  	ret = -EFAULT;
4f6b82883   Ryusuke Konishi   nilfs2: fix lock ...
843
  	if (copy_from_user(argv, argp, sizeof(argv)))
7512487e6   Ryusuke Konishi   nilfs2: use mnt_w...
844
  		goto out;
4f6b82883   Ryusuke Konishi   nilfs2: fix lock ...
845

7512487e6   Ryusuke Konishi   nilfs2: use mnt_w...
846
  	ret = -EINVAL;
4f6b82883   Ryusuke Konishi   nilfs2: fix lock ...
847
848
  	nsegs = argv[4].v_nmembs;
  	if (argv[4].v_size != argsz[4])
7512487e6   Ryusuke Konishi   nilfs2: use mnt_w...
849
  		goto out;
1ecd3c7ea   Xi Wang   nilfs2: avoid ove...
850
851
  	if (nsegs > UINT_MAX / sizeof(__u64))
  		goto out;
7512487e6   Ryusuke Konishi   nilfs2: use mnt_w...
852

4f6b82883   Ryusuke Konishi   nilfs2: fix lock ...
853
854
855
856
857
858
859
  	/*
  	 * argv[4] points to segment numbers this ioctl cleans.  We
  	 * use kmalloc() for its buffer because memory used for the
  	 * segment numbers is enough small.
  	 */
  	kbufs[4] = memdup_user((void __user *)(unsigned long)argv[4].v_base,
  			       nsegs * sizeof(__u64));
7512487e6   Ryusuke Konishi   nilfs2: use mnt_w...
860
861
862
863
  	if (IS_ERR(kbufs[4])) {
  		ret = PTR_ERR(kbufs[4]);
  		goto out;
  	}
e3154e974   Ryusuke Konishi   nilfs2: get rid o...
864
  	nilfs = inode->i_sb->s_fs_info;
4f6b82883   Ryusuke Konishi   nilfs2: fix lock ...
865
866
867
868
869
870
871
872
  
  	for (n = 0; n < 4; n++) {
  		ret = -EINVAL;
  		if (argv[n].v_size != argsz[n])
  			goto out_free;
  
  		if (argv[n].v_nmembs > nsegs * nilfs->ns_blocks_per_segment)
  			goto out_free;
481fe17e9   Haogang Chen   nilfs2: potential...
873
874
  		if (argv[n].v_nmembs >= UINT_MAX / argv[n].v_size)
  			goto out_free;
4f6b82883   Ryusuke Konishi   nilfs2: fix lock ...
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
  		len = argv[n].v_size * argv[n].v_nmembs;
  		base = (void __user *)(unsigned long)argv[n].v_base;
  		if (len == 0) {
  			kbufs[n] = NULL;
  			continue;
  		}
  
  		kbufs[n] = vmalloc(len);
  		if (!kbufs[n]) {
  			ret = -ENOMEM;
  			goto out_free;
  		}
  		if (copy_from_user(kbufs[n], base, len)) {
  			ret = -EFAULT;
  			vfree(kbufs[n]);
  			goto out_free;
  		}
  	}
1cf58fa84   Jiro SEKIBA   nilfs2: shorten f...
893
  	/*
263d90cef   Ryusuke Konishi   nilfs2: remove ow...
894
  	 * nilfs_ioctl_move_blocks() will call nilfs_iget_for_gc(),
1cf58fa84   Jiro SEKIBA   nilfs2: shorten f...
895
896
897
898
899
900
901
902
  	 * which will operates an inode list without blocking.
  	 * To protect the list from concurrent operations,
  	 * nilfs_ioctl_move_blocks should be atomic operation.
  	 */
  	if (test_and_set_bit(THE_NILFS_GC_RUNNING, &nilfs->ns_flags)) {
  		ret = -EBUSY;
  		goto out_free;
  	}
263d90cef   Ryusuke Konishi   nilfs2: remove ow...
903
  	ret = nilfs_ioctl_move_blocks(inode->i_sb, &argv[0], kbufs[0]);
feee880fa   Ryusuke Konishi   nilfs2: reduce ba...
904
  	if (ret < 0) {
a1d0747a3   Joe Perches   nilfs2: use a mor...
905
  		nilfs_err(inode->i_sb,
feee880fa   Ryusuke Konishi   nilfs2: reduce ba...
906
907
908
  			  "error %d preparing GC: cannot read source blocks",
  			  ret);
  	} else {
a9bae1895   Vyacheslav Dubeyko   nilfs2: fix fix v...
909
910
  		if (nilfs_sb_need_update(nilfs))
  			set_nilfs_discontinued(nilfs);
1cf58fa84   Jiro SEKIBA   nilfs2: shorten f...
911
  		ret = nilfs_clean_segments(inode->i_sb, argv, kbufs);
a9bae1895   Vyacheslav Dubeyko   nilfs2: fix fix v...
912
  	}
1cf58fa84   Jiro SEKIBA   nilfs2: shorten f...
913

263d90cef   Ryusuke Konishi   nilfs2: remove ow...
914
  	nilfs_remove_all_gcinodes(nilfs);
1cf58fa84   Jiro SEKIBA   nilfs2: shorten f...
915
  	clear_nilfs_gc_running(nilfs);
4f6b82883   Ryusuke Konishi   nilfs2: fix lock ...
916

7512487e6   Ryusuke Konishi   nilfs2: use mnt_w...
917
  out_free:
d50468536   Ryusuke Konishi   nilfs2: fix memor...
918
  	while (--n >= 0)
4f6b82883   Ryusuke Konishi   nilfs2: fix lock ...
919
920
  		vfree(kbufs[n]);
  	kfree(kbufs[4]);
7512487e6   Ryusuke Konishi   nilfs2: use mnt_w...
921
  out:
2a79f17e4   Al Viro   vfs: mnt_drop_wri...
922
  	mnt_drop_write_file(filp);
4f6b82883   Ryusuke Konishi   nilfs2: fix lock ...
923
  	return ret;
7942b919f   Koji Sato   nilfs2: ioctl ope...
924
  }
d623a9420   Vyacheslav Dubeyko   nilfs2: add comme...
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
  /**
   * nilfs_ioctl_sync - make a checkpoint
   * @inode: inode object
   * @filp: file object
   * @cmd: ioctl's request code
   * @argp: pointer on argument from userspace
   *
   * Description: nilfs_ioctl_sync() function constructs a logical segment
   * for checkpointing.  This function guarantees that all modified data
   * and metadata are written out to the device when it successfully
   * returned.
   *
   * Return Value: On success, 0 is retured. On errors, one of the following
   * negative error code is returned.
   *
   * %-EROFS - Read only filesystem.
   *
   * %-EIO - I/O error
   *
   * %-ENOSPC - No space left on device (only in a panic state).
   *
   * %-ERESTARTSYS - Interrupted.
   *
   * %-ENOMEM - Insufficient memory available.
   *
   * %-EFAULT - Failure during execution of requested operation.
   */
7942b919f   Koji Sato   nilfs2: ioctl ope...
952
953
954
955
956
  static int nilfs_ioctl_sync(struct inode *inode, struct file *filp,
  			    unsigned int cmd, void __user *argp)
  {
  	__u64 cno;
  	int ret;
0d561f12b   Jiro SEKIBA   nilfs2: add reade...
957
  	struct the_nilfs *nilfs;
7942b919f   Koji Sato   nilfs2: ioctl ope...
958
959
960
961
  
  	ret = nilfs_construct_segment(inode->i_sb);
  	if (ret < 0)
  		return ret;
11475975d   Ryusuke Konishi   nilfs2: flush dis...
962
  	nilfs = inode->i_sb->s_fs_info;
e2c7617ae   Andreas Rohner   nilfs2: add missi...
963
964
965
  	ret = nilfs_flush_device(nilfs);
  	if (ret < 0)
  		return ret;
11475975d   Ryusuke Konishi   nilfs2: flush dis...
966

7942b919f   Koji Sato   nilfs2: ioctl ope...
967
  	if (argp != NULL) {
0d561f12b   Jiro SEKIBA   nilfs2: add reade...
968
969
970
  		down_read(&nilfs->ns_segctor_sem);
  		cno = nilfs->ns_cno - 1;
  		up_read(&nilfs->ns_segctor_sem);
7942b919f   Koji Sato   nilfs2: ioctl ope...
971
972
973
974
975
  		if (copy_to_user(argp, &cno, sizeof(cno)))
  			return -EFAULT;
  	}
  	return 0;
  }
d623a9420   Vyacheslav Dubeyko   nilfs2: add comme...
976
977
978
979
980
981
982
983
  /**
   * nilfs_ioctl_resize - resize NILFS2 volume
   * @inode: inode object
   * @filp: file object
   * @argp: pointer on argument from userspace
   *
   * Return Value: On success, 0 is returned or error code, otherwise.
   */
4e33f9eab   Ryusuke Konishi   nilfs2: implement...
984
985
986
987
988
989
990
991
  static int nilfs_ioctl_resize(struct inode *inode, struct file *filp,
  			      void __user *argp)
  {
  	__u64 newsize;
  	int ret = -EPERM;
  
  	if (!capable(CAP_SYS_ADMIN))
  		goto out;
a561be710   Al Viro   switch a bunch of...
992
  	ret = mnt_want_write_file(filp);
4e33f9eab   Ryusuke Konishi   nilfs2: implement...
993
994
995
996
997
998
999
1000
1001
1002
  	if (ret)
  		goto out;
  
  	ret = -EFAULT;
  	if (copy_from_user(&newsize, argp, sizeof(newsize)))
  		goto out_drop_write;
  
  	ret = nilfs_resize_fs(inode->i_sb, newsize);
  
  out_drop_write:
2a79f17e4   Al Viro   vfs: mnt_drop_wri...
1003
  	mnt_drop_write_file(filp);
4e33f9eab   Ryusuke Konishi   nilfs2: implement...
1004
1005
1006
  out:
  	return ret;
  }
d623a9420   Vyacheslav Dubeyko   nilfs2: add comme...
1007
  /**
f9f32c44e   Andreas Rohner   nilfs2: add FITRI...
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
   * nilfs_ioctl_trim_fs() - trim ioctl handle function
   * @inode: inode object
   * @argp: pointer on argument from userspace
   *
   * Decription: nilfs_ioctl_trim_fs is the FITRIM ioctl handle function. It
   * checks the arguments from userspace and calls nilfs_sufile_trim_fs, which
   * performs the actual trim operation.
   *
   * Return Value: On success, 0 is returned or negative error code, otherwise.
   */
  static int nilfs_ioctl_trim_fs(struct inode *inode, void __user *argp)
  {
  	struct the_nilfs *nilfs = inode->i_sb->s_fs_info;
  	struct request_queue *q = bdev_get_queue(nilfs->ns_bdev);
  	struct fstrim_range range;
  	int ret;
  
  	if (!capable(CAP_SYS_ADMIN))
  		return -EPERM;
  
  	if (!blk_queue_discard(q))
  		return -EOPNOTSUPP;
  
  	if (copy_from_user(&range, argp, sizeof(range)))
  		return -EFAULT;
  
  	range.minlen = max_t(u64, range.minlen, q->limits.discard_granularity);
  
  	down_read(&nilfs->ns_segctor_sem);
  	ret = nilfs_sufile_trim_fs(nilfs->ns_sufile, &range);
  	up_read(&nilfs->ns_segctor_sem);
  
  	if (ret < 0)
  		return ret;
  
  	if (copy_to_user(argp, &range, sizeof(range)))
  		return -EFAULT;
  
  	return 0;
  }
  
  /**
d623a9420   Vyacheslav Dubeyko   nilfs2: add comme...
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
   * nilfs_ioctl_set_alloc_range - limit range of segments to be allocated
   * @inode: inode object
   * @argp: pointer on argument from userspace
   *
   * Decription: nilfs_ioctl_set_alloc_range() function defines lower limit
   * of segments in bytes and upper limit of segments in bytes.
   * The NILFS_IOCTL_SET_ALLOC_RANGE is used by nilfs_resize utility.
   *
   * Return Value: On success, 0 is returned or error code, otherwise.
   */
619205da5   Ryusuke Konishi   nilfs2: add ioctl...
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
  static int nilfs_ioctl_set_alloc_range(struct inode *inode, void __user *argp)
  {
  	struct the_nilfs *nilfs = inode->i_sb->s_fs_info;
  	__u64 range[2];
  	__u64 minseg, maxseg;
  	unsigned long segbytes;
  	int ret = -EPERM;
  
  	if (!capable(CAP_SYS_ADMIN))
  		goto out;
  
  	ret = -EFAULT;
  	if (copy_from_user(range, argp, sizeof(__u64[2])))
  		goto out;
  
  	ret = -ERANGE;
  	if (range[1] > i_size_read(inode->i_sb->s_bdev->bd_inode))
  		goto out;
  
  	segbytes = nilfs->ns_blocks_per_segment * nilfs->ns_blocksize;
  
  	minseg = range[0] + segbytes - 1;
  	do_div(minseg, segbytes);
  	maxseg = NILFS_SB2_OFFSET_BYTES(range[1]);
  	do_div(maxseg, segbytes);
  	maxseg--;
  
  	ret = nilfs_sufile_set_alloc_range(nilfs->ns_sufile, minseg, maxseg);
  out:
  	return ret;
  }
d623a9420   Vyacheslav Dubeyko   nilfs2: add comme...
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
  /**
   * nilfs_ioctl_get_info - wrapping function of get metadata info
   * @inode: inode object
   * @filp: file object
   * @cmd: ioctl's request code
   * @argp: pointer on argument from userspace
   * @membsz: size of an item in bytes
   * @dofunc: concrete function of getting metadata info
   *
   * Description: nilfs_ioctl_get_info() gets metadata info by means of
   * calling dofunc() function.
   *
   * Return Value: On success, 0 is returned and requested metadata info
   * is copied into userspace. On error, one of the following
   * negative error codes is returned.
   *
   * %-EINVAL - Invalid arguments from userspace.
   *
   * %-ENOMEM - Insufficient amount of memory available.
   *
   * %-EFAULT - Failure during execution of requested operation.
   */
47eb6b9c8   Ryusuke Konishi   nilfs2: fix possi...
1113
1114
  static int nilfs_ioctl_get_info(struct inode *inode, struct file *filp,
  				unsigned int cmd, void __user *argp,
83aca8f48   Ryusuke Konishi   nilfs2: check siz...
1115
  				size_t membsz,
47eb6b9c8   Ryusuke Konishi   nilfs2: fix possi...
1116
1117
1118
1119
1120
  				ssize_t (*dofunc)(struct the_nilfs *,
  						  __u64 *, int,
  						  void *, size_t, size_t))
  
  {
e3154e974   Ryusuke Konishi   nilfs2: get rid o...
1121
  	struct the_nilfs *nilfs = inode->i_sb->s_fs_info;
47eb6b9c8   Ryusuke Konishi   nilfs2: fix possi...
1122
1123
1124
1125
1126
  	struct nilfs_argv argv;
  	int ret;
  
  	if (copy_from_user(&argv, argp, sizeof(argv)))
  		return -EFAULT;
003ff182f   Ryusuke Konishi   nilfs2: allow fut...
1127
  	if (argv.v_size < membsz)
83aca8f48   Ryusuke Konishi   nilfs2: check siz...
1128
  		return -EINVAL;
47eb6b9c8   Ryusuke Konishi   nilfs2: fix possi...
1129
1130
1131
1132
1133
1134
1135
1136
  	ret = nilfs_ioctl_wrap_copy(nilfs, &argv, _IOC_DIR(cmd), dofunc);
  	if (ret < 0)
  		return ret;
  
  	if (copy_to_user(argp, &argv, sizeof(argv)))
  		ret = -EFAULT;
  	return ret;
  }
2cc88f3a5   Andreas Rohner   nilfs2: implement...
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
  /**
   * nilfs_ioctl_set_suinfo - set segment usage info
   * @inode: inode object
   * @filp: file object
   * @cmd: ioctl's request code
   * @argp: pointer on argument from userspace
   *
   * Description: Expects an array of nilfs_suinfo_update structures
   * encapsulated in nilfs_argv and updates the segment usage info
   * according to the flags in nilfs_suinfo_update.
   *
   * Return Value: On success, 0 is returned. On error, one of the
   * following negative error codes is returned.
   *
   * %-EPERM - Not enough permissions
   *
   * %-EFAULT - Error copying input data
   *
   * %-EIO - I/O error.
   *
   * %-ENOMEM - Insufficient amount of memory available.
   *
   * %-EINVAL - Invalid values in input (segment number, flags or nblocks)
   */
  static int nilfs_ioctl_set_suinfo(struct inode *inode, struct file *filp,
  				unsigned int cmd, void __user *argp)
  {
  	struct the_nilfs *nilfs = inode->i_sb->s_fs_info;
  	struct nilfs_transaction_info ti;
  	struct nilfs_argv argv;
  	size_t len;
  	void __user *base;
  	void *kbuf;
  	int ret;
  
  	if (!capable(CAP_SYS_ADMIN))
  		return -EPERM;
  
  	ret = mnt_want_write_file(filp);
  	if (ret)
  		return ret;
  
  	ret = -EFAULT;
  	if (copy_from_user(&argv, argp, sizeof(argv)))
  		goto out;
  
  	ret = -EINVAL;
  	if (argv.v_size < sizeof(struct nilfs_suinfo_update))
  		goto out;
  
  	if (argv.v_nmembs > nilfs->ns_nsegments)
  		goto out;
  
  	if (argv.v_nmembs >= UINT_MAX / argv.v_size)
  		goto out;
  
  	len = argv.v_size * argv.v_nmembs;
  	if (!len) {
  		ret = 0;
  		goto out;
  	}
  
  	base = (void __user *)(unsigned long)argv.v_base;
  	kbuf = vmalloc(len);
  	if (!kbuf) {
  		ret = -ENOMEM;
  		goto out;
  	}
  
  	if (copy_from_user(kbuf, base, len)) {
  		ret = -EFAULT;
  		goto out_free;
  	}
  
  	nilfs_transaction_begin(inode->i_sb, &ti, 0);
  	ret = nilfs_sufile_set_suinfo(nilfs->ns_sufile, kbuf, argv.v_size,
  			argv.v_nmembs);
  	if (unlikely(ret < 0))
  		nilfs_transaction_abort(inode->i_sb);
  	else
  		nilfs_transaction_commit(inode->i_sb); /* never fails */
  
  out_free:
  	vfree(kbuf);
  out:
  	mnt_drop_write_file(filp);
  	return ret;
  }
7a9461939   Ryusuke Konishi   nilfs2: use unloc...
1225
  long nilfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
7942b919f   Koji Sato   nilfs2: ioctl ope...
1226
  {
496ad9aa8   Al Viro   new helper: file_...
1227
  	struct inode *inode = file_inode(filp);
753234007   Li Hong   nilfs2: fix a wro...
1228
  	void __user *argp = (void __user *)arg;
7942b919f   Koji Sato   nilfs2: ioctl ope...
1229
1230
  
  	switch (cmd) {
cde98f0f8   Ryusuke Konishi   nilfs2: implement...
1231
1232
1233
1234
1235
1236
  	case FS_IOC_GETFLAGS:
  		return nilfs_ioctl_getflags(inode, argp);
  	case FS_IOC_SETFLAGS:
  		return nilfs_ioctl_setflags(inode, filp, argp);
  	case FS_IOC_GETVERSION:
  		return nilfs_ioctl_getversion(inode, argp);
7942b919f   Koji Sato   nilfs2: ioctl ope...
1237
1238
1239
1240
1241
  	case NILFS_IOCTL_CHANGE_CPMODE:
  		return nilfs_ioctl_change_cpmode(inode, filp, cmd, argp);
  	case NILFS_IOCTL_DELETE_CHECKPOINT:
  		return nilfs_ioctl_delete_checkpoint(inode, filp, cmd, argp);
  	case NILFS_IOCTL_GET_CPINFO:
47eb6b9c8   Ryusuke Konishi   nilfs2: fix possi...
1242
  		return nilfs_ioctl_get_info(inode, filp, cmd, argp,
83aca8f48   Ryusuke Konishi   nilfs2: check siz...
1243
  					    sizeof(struct nilfs_cpinfo),
47eb6b9c8   Ryusuke Konishi   nilfs2: fix possi...
1244
  					    nilfs_ioctl_do_get_cpinfo);
7942b919f   Koji Sato   nilfs2: ioctl ope...
1245
1246
1247
  	case NILFS_IOCTL_GET_CPSTAT:
  		return nilfs_ioctl_get_cpstat(inode, filp, cmd, argp);
  	case NILFS_IOCTL_GET_SUINFO:
47eb6b9c8   Ryusuke Konishi   nilfs2: fix possi...
1248
  		return nilfs_ioctl_get_info(inode, filp, cmd, argp,
83aca8f48   Ryusuke Konishi   nilfs2: check siz...
1249
  					    sizeof(struct nilfs_suinfo),
47eb6b9c8   Ryusuke Konishi   nilfs2: fix possi...
1250
  					    nilfs_ioctl_do_get_suinfo);
2cc88f3a5   Andreas Rohner   nilfs2: implement...
1251
1252
  	case NILFS_IOCTL_SET_SUINFO:
  		return nilfs_ioctl_set_suinfo(inode, filp, cmd, argp);
7942b919f   Koji Sato   nilfs2: ioctl ope...
1253
1254
1255
  	case NILFS_IOCTL_GET_SUSTAT:
  		return nilfs_ioctl_get_sustat(inode, filp, cmd, argp);
  	case NILFS_IOCTL_GET_VINFO:
47eb6b9c8   Ryusuke Konishi   nilfs2: fix possi...
1256
  		return nilfs_ioctl_get_info(inode, filp, cmd, argp,
83aca8f48   Ryusuke Konishi   nilfs2: check siz...
1257
  					    sizeof(struct nilfs_vinfo),
47eb6b9c8   Ryusuke Konishi   nilfs2: fix possi...
1258
  					    nilfs_ioctl_do_get_vinfo);
7942b919f   Koji Sato   nilfs2: ioctl ope...
1259
1260
1261
1262
  	case NILFS_IOCTL_GET_BDESCS:
  		return nilfs_ioctl_get_bdescs(inode, filp, cmd, argp);
  	case NILFS_IOCTL_CLEAN_SEGMENTS:
  		return nilfs_ioctl_clean_segments(inode, filp, cmd, argp);
7942b919f   Koji Sato   nilfs2: ioctl ope...
1263
1264
  	case NILFS_IOCTL_SYNC:
  		return nilfs_ioctl_sync(inode, filp, cmd, argp);
4e33f9eab   Ryusuke Konishi   nilfs2: implement...
1265
1266
  	case NILFS_IOCTL_RESIZE:
  		return nilfs_ioctl_resize(inode, filp, argp);
619205da5   Ryusuke Konishi   nilfs2: add ioctl...
1267
1268
  	case NILFS_IOCTL_SET_ALLOC_RANGE:
  		return nilfs_ioctl_set_alloc_range(inode, argp);
f9f32c44e   Andreas Rohner   nilfs2: add FITRI...
1269
1270
  	case FITRIM:
  		return nilfs_ioctl_trim_fs(inode, argp);
7942b919f   Koji Sato   nilfs2: ioctl ope...
1271
1272
1273
1274
  	default:
  		return -ENOTTY;
  	}
  }
828b1c50a   Ryusuke Konishi   nilfs2: add compa...
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
  
  #ifdef CONFIG_COMPAT
  long nilfs_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
  {
  	switch (cmd) {
  	case FS_IOC32_GETFLAGS:
  		cmd = FS_IOC_GETFLAGS;
  		break;
  	case FS_IOC32_SETFLAGS:
  		cmd = FS_IOC_SETFLAGS;
  		break;
  	case FS_IOC32_GETVERSION:
  		cmd = FS_IOC_GETVERSION;
  		break;
695c60f21   Thomas Meyer   nilfs2: unbreak c...
1289
1290
1291
1292
1293
  	case NILFS_IOCTL_CHANGE_CPMODE:
  	case NILFS_IOCTL_DELETE_CHECKPOINT:
  	case NILFS_IOCTL_GET_CPINFO:
  	case NILFS_IOCTL_GET_CPSTAT:
  	case NILFS_IOCTL_GET_SUINFO:
2cc88f3a5   Andreas Rohner   nilfs2: implement...
1294
  	case NILFS_IOCTL_SET_SUINFO:
695c60f21   Thomas Meyer   nilfs2: unbreak c...
1295
1296
1297
1298
1299
1300
1301
  	case NILFS_IOCTL_GET_SUSTAT:
  	case NILFS_IOCTL_GET_VINFO:
  	case NILFS_IOCTL_GET_BDESCS:
  	case NILFS_IOCTL_CLEAN_SEGMENTS:
  	case NILFS_IOCTL_SYNC:
  	case NILFS_IOCTL_RESIZE:
  	case NILFS_IOCTL_SET_ALLOC_RANGE:
314999dcb   Arnd Bergmann   fs: compat_ioctl:...
1302
  	case FITRIM:
695c60f21   Thomas Meyer   nilfs2: unbreak c...
1303
  		break;
828b1c50a   Ryusuke Konishi   nilfs2: add compa...
1304
1305
1306
1307
1308
1309
  	default:
  		return -ENOIOCTLCMD;
  	}
  	return nilfs_ioctl(filp, cmd, (unsigned long)compat_ptr(arg));
  }
  #endif