Blame view
fs/nilfs2/ioctl.c
35.6 KB
ae98043f5 nilfs2: convert t... |
1 |
// SPDX-License-Identifier: GPL-2.0+ |
7942b919f nilfs2: ioctl ope... |
2 3 4 5 6 |
/* * ioctl.c - NILFS ioctl operations. * * Copyright (C) 2007, 2008 Nippon Telegraph and Telephone Corporation. * |
4b420ab4e nilfs2: clean up ... |
7 |
* Written by Koji Sato. |
7942b919f nilfs2: ioctl ope... |
8 9 10 11 |
*/ #include <linux/fs.h> #include <linux/wait.h> |
5a0e3ad6a include cleanup: ... |
12 |
#include <linux/slab.h> |
7942b919f nilfs2: ioctl ope... |
13 14 |
#include <linux/capability.h> /* capable() */ #include <linux/uaccess.h> /* copy_from_user(), copy_to_user() */ |
4f6b82883 nilfs2: fix lock ... |
15 |
#include <linux/vmalloc.h> |
828b1c50a nilfs2: add compa... |
16 |
#include <linux/compat.h> /* compat_ptr() */ |
2a79f17e4 vfs: mnt_drop_wri... |
17 |
#include <linux/mount.h> /* mnt_want_write_file(), mnt_drop_write_file() */ |
ae191838b nilfs2: optimize ... |
18 |
#include <linux/buffer_head.h> |
7942b919f 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 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 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 nilfs2: fix gc fa... |
48 |
__u64 *, int, |
7942b919f nilfs2: ioctl ope... |
49 50 51 |
void *, size_t, size_t)) { void *buf; |
dc498d09b nilfs2: use fixed... |
52 |
void __user *base = (void __user *)(unsigned long)argv->v_base; |
3358b4aaa nilfs2: fix probl... |
53 |
size_t maxmembs, total, n; |
7942b919f nilfs2: ioctl ope... |
54 55 |
ssize_t nr; int ret, i; |
b028fcfc4 nilfs2: fix gc fa... |
56 |
__u64 pos, ppos; |
7942b919f nilfs2: ioctl ope... |
57 58 59 |
if (argv->v_nmembs == 0) return 0; |
3358b4aaa nilfs2: fix probl... |
60 61 |
if (argv->v_size > PAGE_SIZE) return -EINVAL; |
4b15d6171 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 nilfs2: fix probl... |
69 70 |
buf = (void *)__get_free_pages(GFP_NOFS, 0); if (unlikely(!buf)) |
7942b919f nilfs2: ioctl ope... |
71 |
return -ENOMEM; |
3358b4aaa nilfs2: fix probl... |
72 |
maxmembs = PAGE_SIZE / argv->v_size; |
7942b919f nilfs2: ioctl ope... |
73 74 75 |
ret = 0; total = 0; |
b028fcfc4 nilfs2: fix gc fa... |
76 |
pos = argv->v_index; |
7942b919f 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 nilfs2: use fixed... |
81 82 |
copy_from_user(buf, base + argv->v_size * i, argv->v_size * n)) { |
7942b919f nilfs2: ioctl ope... |
83 84 85 |
ret = -EFAULT; break; } |
b028fcfc4 nilfs2: fix gc fa... |
86 |
ppos = pos; |
8acfbf093 nilfs2: clean up ... |
87 |
nr = dofunc(nilfs, &pos, argv->v_flags, buf, argv->v_size, |
b028fcfc4 nilfs2: fix gc fa... |
88 |
n); |
7942b919f nilfs2: ioctl ope... |
89 90 91 92 93 |
if (nr < 0) { ret = nr; break; } if ((dir & _IOC_READ) && |
dc498d09b nilfs2: use fixed... |
94 95 |
copy_to_user(base + argv->v_size * i, buf, argv->v_size * nr)) { |
7942b919f nilfs2: ioctl ope... |
96 97 98 99 |
ret = -EFAULT; break; } total += nr; |
b028fcfc4 nilfs2: fix gc fa... |
100 101 102 103 |
if ((size_t)nr < n) break; if (pos == ppos) pos += n; |
7942b919f nilfs2: ioctl ope... |
104 105 |
} argv->v_nmembs = total; |
3358b4aaa nilfs2: fix probl... |
106 |
free_pages((unsigned long)buf, 0); |
7942b919f nilfs2: ioctl ope... |
107 108 |
return ret; } |
d623a9420 nilfs2: add comme... |
109 110 111 |
/** * nilfs_ioctl_getflags - ioctl to support lsattr */ |
cde98f0f8 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 nilfs2: add comme... |
118 119 120 |
/** * nilfs_ioctl_setflags - ioctl to support chattr */ |
cde98f0f8 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 userns: rename is... |
127 |
if (!inode_owner_or_capable(inode)) |
cde98f0f8 nilfs2: implement... |
128 129 130 131 |
return -EACCES; if (get_user(flags, (int __user *)argp)) return -EFAULT; |
a561be710 switch a bunch of... |
132 |
ret = mnt_want_write_file(filp); |
cde98f0f8 nilfs2: implement... |
133 134 135 136 |
if (ret) return ret; flags = nilfs_mask_flags(inode->i_mode, flags); |
5955102c9 wrappers for ->i_... |
137 |
inode_lock(inode); |
cde98f0f8 nilfs2: implement... |
138 139 |
oldflags = NILFS_I(inode)->i_flags; |
5aca28421 vfs: create a gen... |
140 141 |
ret = vfs_ioc_setflags_prepare(inode, oldflags, flags); if (ret) |
cde98f0f8 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 fs: Replace CURRE... |
152 |
inode->i_ctime = current_time(inode); |
cde98f0f8 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 wrappers for ->i_... |
159 |
inode_unlock(inode); |
2a79f17e4 vfs: mnt_drop_wri... |
160 |
mnt_drop_write_file(filp); |
cde98f0f8 nilfs2: implement... |
161 162 |
return ret; } |
d623a9420 nilfs2: add comme... |
163 164 165 |
/** * nilfs_ioctl_getversion - get info about a file's version (generation number) */ |
cde98f0f8 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 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 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 nilfs2: get rid o... |
192 |
struct the_nilfs *nilfs = inode->i_sb->s_fs_info; |
7942b919f 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 nilfs2: use mnt_w... |
199 |
|
a561be710 switch a bunch of... |
200 |
ret = mnt_want_write_file(filp); |
7512487e6 nilfs2: use mnt_w... |
201 202 203 204 |
if (ret) return ret; ret = -EFAULT; |
7942b919f nilfs2: ioctl ope... |
205 |
if (copy_from_user(&cpmode, argp, sizeof(cpmode))) |
7512487e6 nilfs2: use mnt_w... |
206 |
goto out; |
7942b919f nilfs2: ioctl ope... |
207 |
|
572d8b394 nilfs2: fix deadl... |
208 |
mutex_lock(&nilfs->ns_snapshot_mount_mutex); |
7512487e6 nilfs2: use mnt_w... |
209 |
|
7942b919f nilfs2: ioctl ope... |
210 211 |
nilfs_transaction_begin(inode->i_sb, &ti, 0); ret = nilfs_cpfile_change_cpmode( |
e3154e974 nilfs2: get rid o... |
212 |
nilfs->ns_cpfile, cpmode.cm_cno, cpmode.cm_mode); |
7512487e6 nilfs2: use mnt_w... |
213 |
if (unlikely(ret < 0)) |
47420c799 nilfs2: avoid dou... |
214 |
nilfs_transaction_abort(inode->i_sb); |
7512487e6 nilfs2: use mnt_w... |
215 216 |
else nilfs_transaction_commit(inode->i_sb); /* never fails */ |
572d8b394 nilfs2: fix deadl... |
217 |
mutex_unlock(&nilfs->ns_snapshot_mount_mutex); |
7512487e6 nilfs2: use mnt_w... |
218 |
out: |
2a79f17e4 vfs: mnt_drop_wri... |
219 |
mnt_drop_write_file(filp); |
7942b919f nilfs2: ioctl ope... |
220 221 |
return ret; } |
d623a9420 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 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 nilfs2: get rid o... |
245 |
struct the_nilfs *nilfs = inode->i_sb->s_fs_info; |
7942b919f 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 nilfs2: use mnt_w... |
252 |
|
a561be710 switch a bunch of... |
253 |
ret = mnt_want_write_file(filp); |
7512487e6 nilfs2: use mnt_w... |
254 255 256 257 |
if (ret) return ret; ret = -EFAULT; |
7942b919f nilfs2: ioctl ope... |
258 |
if (copy_from_user(&cno, argp, sizeof(cno))) |
7512487e6 nilfs2: use mnt_w... |
259 |
goto out; |
7942b919f nilfs2: ioctl ope... |
260 261 |
nilfs_transaction_begin(inode->i_sb, &ti, 0); |
e3154e974 nilfs2: get rid o... |
262 |
ret = nilfs_cpfile_delete_checkpoint(nilfs->ns_cpfile, cno); |
7512487e6 nilfs2: use mnt_w... |
263 |
if (unlikely(ret < 0)) |
47420c799 nilfs2: avoid dou... |
264 |
nilfs_transaction_abort(inode->i_sb); |
7512487e6 nilfs2: use mnt_w... |
265 266 267 |
else nilfs_transaction_commit(inode->i_sb); /* never fails */ out: |
2a79f17e4 vfs: mnt_drop_wri... |
268 |
mnt_drop_write_file(filp); |
7942b919f nilfs2: ioctl ope... |
269 270 |
return ret; } |
d623a9420 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 nilfs2: ioctl ope... |
286 |
static ssize_t |
b028fcfc4 nilfs2: fix gc fa... |
287 |
nilfs_ioctl_do_get_cpinfo(struct the_nilfs *nilfs, __u64 *posp, int flags, |
7942b919f nilfs2: ioctl ope... |
288 289 |
void *buf, size_t size, size_t nmembs) { |
7942b919f nilfs2: ioctl ope... |
290 |
int ret; |
47420c799 nilfs2: avoid dou... |
291 |
down_read(&nilfs->ns_segctor_sem); |
47eb6b9c8 nilfs2: fix possi... |
292 |
ret = nilfs_cpfile_get_cpinfo(nilfs->ns_cpfile, posp, flags, buf, |
003ff182f nilfs2: allow fut... |
293 |
size, nmembs); |
47420c799 nilfs2: avoid dou... |
294 |
up_read(&nilfs->ns_segctor_sem); |
7942b919f nilfs2: ioctl ope... |
295 296 |
return ret; } |
d623a9420 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 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 nilfs2: get rid o... |
321 |
struct the_nilfs *nilfs = inode->i_sb->s_fs_info; |
7942b919f nilfs2: ioctl ope... |
322 |
struct nilfs_cpstat cpstat; |
7942b919f nilfs2: ioctl ope... |
323 |
int ret; |
47420c799 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 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 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 nilfs2: ioctl ope... |
349 |
static ssize_t |
b028fcfc4 nilfs2: fix gc fa... |
350 |
nilfs_ioctl_do_get_suinfo(struct the_nilfs *nilfs, __u64 *posp, int flags, |
7942b919f nilfs2: ioctl ope... |
351 352 |
void *buf, size_t size, size_t nmembs) { |
7942b919f nilfs2: ioctl ope... |
353 |
int ret; |
47420c799 nilfs2: avoid dou... |
354 |
down_read(&nilfs->ns_segctor_sem); |
003ff182f nilfs2: allow fut... |
355 356 |
ret = nilfs_sufile_get_suinfo(nilfs->ns_sufile, *posp, buf, size, nmembs); |
47420c799 nilfs2: avoid dou... |
357 |
up_read(&nilfs->ns_segctor_sem); |
7942b919f nilfs2: ioctl ope... |
358 359 |
return ret; } |
d623a9420 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 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 nilfs2: get rid o... |
384 |
struct the_nilfs *nilfs = inode->i_sb->s_fs_info; |
7942b919f nilfs2: ioctl ope... |
385 |
struct nilfs_sustat sustat; |
7942b919f nilfs2: ioctl ope... |
386 |
int ret; |
47420c799 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 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 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 nilfs2: ioctl ope... |
412 |
static ssize_t |
b028fcfc4 nilfs2: fix gc fa... |
413 |
nilfs_ioctl_do_get_vinfo(struct the_nilfs *nilfs, __u64 *posp, int flags, |
7942b919f nilfs2: ioctl ope... |
414 415 |
void *buf, size_t size, size_t nmembs) { |
7942b919f nilfs2: ioctl ope... |
416 |
int ret; |
47420c799 nilfs2: avoid dou... |
417 |
down_read(&nilfs->ns_segctor_sem); |
365e215ce nilfs2: unfold ni... |
418 |
ret = nilfs_dat_get_vinfo(nilfs->ns_dat, buf, size, nmembs); |
47420c799 nilfs2: avoid dou... |
419 |
up_read(&nilfs->ns_segctor_sem); |
7942b919f nilfs2: ioctl ope... |
420 421 |
return ret; } |
d623a9420 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 nilfs2: ioctl ope... |
437 |
static ssize_t |
b028fcfc4 nilfs2: fix gc fa... |
438 |
nilfs_ioctl_do_get_bdescs(struct the_nilfs *nilfs, __u64 *posp, int flags, |
7942b919f nilfs2: ioctl ope... |
439 440 |
void *buf, size_t size, size_t nmembs) { |
365e215ce nilfs2: unfold ni... |
441 |
struct nilfs_bmap *bmap = NILFS_I(nilfs->ns_dat)->i_bmap; |
7942b919f nilfs2: ioctl ope... |
442 443 |
struct nilfs_bdesc *bdescs = buf; int ret, i; |
47eb6b9c8 nilfs2: fix possi... |
444 |
down_read(&nilfs->ns_segctor_sem); |
7942b919f 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 nilfs2: fix possi... |
451 452 |
if (ret != -ENOENT) { up_read(&nilfs->ns_segctor_sem); |
7942b919f nilfs2: ioctl ope... |
453 |
return ret; |
47eb6b9c8 nilfs2: fix possi... |
454 |
} |
7942b919f nilfs2: ioctl ope... |
455 456 457 |
bdescs[i].bd_blocknr = 0; } } |
47eb6b9c8 nilfs2: fix possi... |
458 |
up_read(&nilfs->ns_segctor_sem); |
7942b919f nilfs2: ioctl ope... |
459 460 |
return nmembs; } |
d623a9420 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 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 nilfs2: get rid o... |
487 |
struct the_nilfs *nilfs = inode->i_sb->s_fs_info; |
7942b919f nilfs2: ioctl ope... |
488 |
struct nilfs_argv argv; |
7942b919f nilfs2: ioctl ope... |
489 490 491 492 |
int ret; if (copy_from_user(&argv, argp, sizeof(argv))) return -EFAULT; |
83aca8f48 nilfs2: check siz... |
493 494 |
if (argv.v_size != sizeof(struct nilfs_bdesc)) return -EINVAL; |
7942b919f nilfs2: ioctl ope... |
495 496 |
ret = nilfs_ioctl_wrap_copy(nilfs, &argv, _IOC_DIR(cmd), nilfs_ioctl_do_get_bdescs); |
47420c799 nilfs2: avoid dou... |
497 498 |
if (ret < 0) return ret; |
7942b919f nilfs2: ioctl ope... |
499 500 501 502 503 |
if (copy_to_user(argp, &argv, sizeof(argv))) ret = -EFAULT; return ret; } |
d623a9420 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 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 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 nilfs2: ioctl ope... |
549 550 |
return ret; } |
5399dd1fc nilfs2: fix kerne... |
551 |
if (unlikely(!list_empty(&bh->b_assoc_buffers))) { |
a1d0747a3 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 nilfs2: fix kerne... |
560 561 562 |
brelse(bh); return -EEXIST; } |
7942b919f nilfs2: ioctl ope... |
563 564 565 |
list_add_tail(&bh->b_assoc_buffers, buffers); return 0; } |
d623a9420 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 nilfs2: remove ow... |
579 |
static int nilfs_ioctl_move_blocks(struct super_block *sb, |
4f6b82883 nilfs2: fix lock ... |
580 |
struct nilfs_argv *argv, void *buf) |
7942b919f nilfs2: ioctl ope... |
581 |
{ |
4f6b82883 nilfs2: fix lock ... |
582 |
size_t nmembs = argv->v_nmembs; |
e3154e974 nilfs2: get rid o... |
583 |
struct the_nilfs *nilfs = sb->s_fs_info; |
7942b919f 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 nilfs2: remove ow... |
595 |
inode = nilfs_iget_for_gc(sb, ino, cno); |
103cfcf52 nilfs2: nilfs_ige... |
596 597 |
if (IS_ERR(inode)) { ret = PTR_ERR(inode); |
7942b919f nilfs2: ioctl ope... |
598 599 |
goto failed; } |
947b10ae0 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 nilfs2: ioctl ope... |
610 611 612 |
do { ret = nilfs_ioctl_move_inode_block(inode, vdesc, &buffers); |
263d90cef nilfs2: remove ow... |
613 614 |
if (unlikely(ret < 0)) { iput(inode); |
7942b919f nilfs2: ioctl ope... |
615 |
goto failed; |
263d90cef nilfs2: remove ow... |
616 |
} |
7942b919f nilfs2: ioctl ope... |
617 618 619 |
vdesc++; } while (++i < nmembs && vdesc->vd_ino == ino && vdesc->vd_cno == cno); |
263d90cef nilfs2: remove ow... |
620 621 |
iput(inode); /* The inode still remains in GC inode list */ |
7942b919f 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 nilfs2: fix kerne... |
627 |
WARN_ON(ret == -EEXIST); |
7942b919f nilfs2: ioctl ope... |
628 629 630 |
goto failed; } list_del_init(&bh->b_assoc_buffers); |
7942b919f 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 nilfs2: ioctl ope... |
638 639 640 641 |
brelse(bh); } return ret; } |
d623a9420 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 nilfs2: fix lock ... |
661 662 |
static int nilfs_ioctl_delete_checkpoints(struct the_nilfs *nilfs, struct nilfs_argv *argv, void *buf) |
7942b919f nilfs2: ioctl ope... |
663 |
{ |
4f6b82883 nilfs2: fix lock ... |
664 |
size_t nmembs = argv->v_nmembs; |
7942b919f 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 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 nilfs2: fix lock ... |
695 696 |
static int nilfs_ioctl_free_vblocknrs(struct the_nilfs *nilfs, struct nilfs_argv *argv, void *buf) |
7942b919f nilfs2: ioctl ope... |
697 |
{ |
4f6b82883 nilfs2: fix lock ... |
698 699 |
size_t nmembs = argv->v_nmembs; int ret; |
7942b919f nilfs2: ioctl ope... |
700 |
|
365e215ce nilfs2: unfold ni... |
701 |
ret = nilfs_dat_freev(nilfs->ns_dat, buf, nmembs); |
7942b919f nilfs2: ioctl ope... |
702 703 704 |
return (ret < 0) ? ret : nmembs; } |
d623a9420 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 nilfs2: fix lock ... |
723 724 |
static int nilfs_ioctl_mark_blocks_dirty(struct the_nilfs *nilfs, struct nilfs_argv *argv, void *buf) |
7942b919f nilfs2: ioctl ope... |
725 |
{ |
4f6b82883 nilfs2: fix lock ... |
726 |
size_t nmembs = argv->v_nmembs; |
365e215ce nilfs2: unfold ni... |
727 |
struct nilfs_bmap *bmap = NILFS_I(nilfs->ns_dat)->i_bmap; |
7942b919f nilfs2: ioctl ope... |
728 |
struct nilfs_bdesc *bdescs = buf; |
24e20ead2 nilfs2: get rid o... |
729 |
struct buffer_head *bh; |
7942b919f 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 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 nilfs2: replace B... |
751 |
WARN_ON(ret == -ENOENT); |
7942b919f nilfs2: ioctl ope... |
752 753 |
return ret; } |
24e20ead2 nilfs2: get rid o... |
754 755 756 |
mark_buffer_dirty(bh); nilfs_mdt_mark_dirty(nilfs->ns_dat); put_bh(bh); |
7942b919f 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 nilfs2: replace B... |
761 |
WARN_ON(ret == -ENOENT); |
7942b919f nilfs2: ioctl ope... |
762 763 764 765 766 767 |
return ret; } } } return nmembs; } |
7942b919f nilfs2: ioctl ope... |
768 |
int nilfs_ioctl_prepare_clean_segments(struct the_nilfs *nilfs, |
4f6b82883 nilfs2: fix lock ... |
769 |
struct nilfs_argv *argv, void **kbufs) |
7942b919f nilfs2: ioctl ope... |
770 |
{ |
1f5abe7e7 nilfs2: replace B... |
771 |
const char *msg; |
4f6b82883 nilfs2: fix lock ... |
772 |
int ret; |
7942b919f nilfs2: ioctl ope... |
773 |
|
4f6b82883 nilfs2: fix lock ... |
774 |
ret = nilfs_ioctl_delete_checkpoints(nilfs, &argv[1], kbufs[1]); |
1f5abe7e7 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 nilfs2: fix lock ... |
783 |
ret = nilfs_ioctl_free_vblocknrs(nilfs, &argv[2], kbufs[2]); |
1f5abe7e7 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 nilfs2: fix lock ... |
792 |
ret = nilfs_ioctl_mark_blocks_dirty(nilfs, &argv[3], kbufs[3]); |
1f5abe7e7 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 nilfs2: ioctl ope... |
800 |
return 0; |
1f5abe7e7 nilfs2: replace B... |
801 |
failed: |
a1d0747a3 nilfs2: use a mor... |
802 |
nilfs_err(nilfs->ns_sb, "error %d preparing GC: %s", ret, msg); |
7942b919f nilfs2: ioctl ope... |
803 804 |
return ret; } |
d623a9420 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 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 nilfs2: fix lock ... |
822 |
struct nilfs_argv argv[5]; |
33e189bd5 nilfs2: Storage c... |
823 |
static const size_t argsz[5] = { |
4f6b82883 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 nilfs2: ioctl ope... |
835 836 |
if (!capable(CAP_SYS_ADMIN)) return -EPERM; |
4f6b82883 nilfs2: fix lock ... |
837 |
|
a561be710 switch a bunch of... |
838 |
ret = mnt_want_write_file(filp); |
7512487e6 nilfs2: use mnt_w... |
839 840 841 842 |
if (ret) return ret; ret = -EFAULT; |
4f6b82883 nilfs2: fix lock ... |
843 |
if (copy_from_user(argv, argp, sizeof(argv))) |
7512487e6 nilfs2: use mnt_w... |
844 |
goto out; |
4f6b82883 nilfs2: fix lock ... |
845 |
|
7512487e6 nilfs2: use mnt_w... |
846 |
ret = -EINVAL; |
4f6b82883 nilfs2: fix lock ... |
847 848 |
nsegs = argv[4].v_nmembs; if (argv[4].v_size != argsz[4]) |
7512487e6 nilfs2: use mnt_w... |
849 |
goto out; |
1ecd3c7ea nilfs2: avoid ove... |
850 851 |
if (nsegs > UINT_MAX / sizeof(__u64)) goto out; |
7512487e6 nilfs2: use mnt_w... |
852 |
|
4f6b82883 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 nilfs2: use mnt_w... |
860 861 862 863 |
if (IS_ERR(kbufs[4])) { ret = PTR_ERR(kbufs[4]); goto out; } |
e3154e974 nilfs2: get rid o... |
864 |
nilfs = inode->i_sb->s_fs_info; |
4f6b82883 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 nilfs2: potential... |
873 874 |
if (argv[n].v_nmembs >= UINT_MAX / argv[n].v_size) goto out_free; |
4f6b82883 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 nilfs2: shorten f... |
893 |
/* |
263d90cef nilfs2: remove ow... |
894 |
* nilfs_ioctl_move_blocks() will call nilfs_iget_for_gc(), |
1cf58fa84 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 nilfs2: remove ow... |
903 |
ret = nilfs_ioctl_move_blocks(inode->i_sb, &argv[0], kbufs[0]); |
feee880fa nilfs2: reduce ba... |
904 |
if (ret < 0) { |
a1d0747a3 nilfs2: use a mor... |
905 |
nilfs_err(inode->i_sb, |
feee880fa nilfs2: reduce ba... |
906 907 908 |
"error %d preparing GC: cannot read source blocks", ret); } else { |
a9bae1895 nilfs2: fix fix v... |
909 910 |
if (nilfs_sb_need_update(nilfs)) set_nilfs_discontinued(nilfs); |
1cf58fa84 nilfs2: shorten f... |
911 |
ret = nilfs_clean_segments(inode->i_sb, argv, kbufs); |
a9bae1895 nilfs2: fix fix v... |
912 |
} |
1cf58fa84 nilfs2: shorten f... |
913 |
|
263d90cef nilfs2: remove ow... |
914 |
nilfs_remove_all_gcinodes(nilfs); |
1cf58fa84 nilfs2: shorten f... |
915 |
clear_nilfs_gc_running(nilfs); |
4f6b82883 nilfs2: fix lock ... |
916 |
|
7512487e6 nilfs2: use mnt_w... |
917 |
out_free: |
d50468536 nilfs2: fix memor... |
918 |
while (--n >= 0) |
4f6b82883 nilfs2: fix lock ... |
919 920 |
vfree(kbufs[n]); kfree(kbufs[4]); |
7512487e6 nilfs2: use mnt_w... |
921 |
out: |
2a79f17e4 vfs: mnt_drop_wri... |
922 |
mnt_drop_write_file(filp); |
4f6b82883 nilfs2: fix lock ... |
923 |
return ret; |
7942b919f nilfs2: ioctl ope... |
924 |
} |
d623a9420 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 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 nilfs2: add reade... |
957 |
struct the_nilfs *nilfs; |
7942b919f nilfs2: ioctl ope... |
958 959 960 961 |
ret = nilfs_construct_segment(inode->i_sb); if (ret < 0) return ret; |
11475975d nilfs2: flush dis... |
962 |
nilfs = inode->i_sb->s_fs_info; |
e2c7617ae nilfs2: add missi... |
963 964 965 |
ret = nilfs_flush_device(nilfs); if (ret < 0) return ret; |
11475975d nilfs2: flush dis... |
966 |
|
7942b919f nilfs2: ioctl ope... |
967 |
if (argp != NULL) { |
0d561f12b nilfs2: add reade... |
968 969 970 |
down_read(&nilfs->ns_segctor_sem); cno = nilfs->ns_cno - 1; up_read(&nilfs->ns_segctor_sem); |
7942b919f nilfs2: ioctl ope... |
971 972 973 974 975 |
if (copy_to_user(argp, &cno, sizeof(cno))) return -EFAULT; } return 0; } |
d623a9420 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 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 switch a bunch of... |
992 |
ret = mnt_want_write_file(filp); |
4e33f9eab 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 vfs: mnt_drop_wri... |
1003 |
mnt_drop_write_file(filp); |
4e33f9eab nilfs2: implement... |
1004 1005 1006 |
out: return ret; } |
d623a9420 nilfs2: add comme... |
1007 |
/** |
f9f32c44e 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 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 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 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 nilfs2: fix possi... |
1113 1114 |
static int nilfs_ioctl_get_info(struct inode *inode, struct file *filp, unsigned int cmd, void __user *argp, |
83aca8f48 nilfs2: check siz... |
1115 |
size_t membsz, |
47eb6b9c8 nilfs2: fix possi... |
1116 1117 1118 1119 1120 |
ssize_t (*dofunc)(struct the_nilfs *, __u64 *, int, void *, size_t, size_t)) { |
e3154e974 nilfs2: get rid o... |
1121 |
struct the_nilfs *nilfs = inode->i_sb->s_fs_info; |
47eb6b9c8 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 nilfs2: allow fut... |
1127 |
if (argv.v_size < membsz) |
83aca8f48 nilfs2: check siz... |
1128 |
return -EINVAL; |
47eb6b9c8 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 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 nilfs2: use unloc... |
1225 |
long nilfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) |
7942b919f nilfs2: ioctl ope... |
1226 |
{ |
496ad9aa8 new helper: file_... |
1227 |
struct inode *inode = file_inode(filp); |
753234007 nilfs2: fix a wro... |
1228 |
void __user *argp = (void __user *)arg; |
7942b919f nilfs2: ioctl ope... |
1229 1230 |
switch (cmd) { |
cde98f0f8 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 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 nilfs2: fix possi... |
1242 |
return nilfs_ioctl_get_info(inode, filp, cmd, argp, |
83aca8f48 nilfs2: check siz... |
1243 |
sizeof(struct nilfs_cpinfo), |
47eb6b9c8 nilfs2: fix possi... |
1244 |
nilfs_ioctl_do_get_cpinfo); |
7942b919f 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 nilfs2: fix possi... |
1248 |
return nilfs_ioctl_get_info(inode, filp, cmd, argp, |
83aca8f48 nilfs2: check siz... |
1249 |
sizeof(struct nilfs_suinfo), |
47eb6b9c8 nilfs2: fix possi... |
1250 |
nilfs_ioctl_do_get_suinfo); |
2cc88f3a5 nilfs2: implement... |
1251 1252 |
case NILFS_IOCTL_SET_SUINFO: return nilfs_ioctl_set_suinfo(inode, filp, cmd, argp); |
7942b919f 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 nilfs2: fix possi... |
1256 |
return nilfs_ioctl_get_info(inode, filp, cmd, argp, |
83aca8f48 nilfs2: check siz... |
1257 |
sizeof(struct nilfs_vinfo), |
47eb6b9c8 nilfs2: fix possi... |
1258 |
nilfs_ioctl_do_get_vinfo); |
7942b919f 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 nilfs2: ioctl ope... |
1263 1264 |
case NILFS_IOCTL_SYNC: return nilfs_ioctl_sync(inode, filp, cmd, argp); |
4e33f9eab nilfs2: implement... |
1265 1266 |
case NILFS_IOCTL_RESIZE: return nilfs_ioctl_resize(inode, filp, argp); |
619205da5 nilfs2: add ioctl... |
1267 1268 |
case NILFS_IOCTL_SET_ALLOC_RANGE: return nilfs_ioctl_set_alloc_range(inode, argp); |
f9f32c44e nilfs2: add FITRI... |
1269 1270 |
case FITRIM: return nilfs_ioctl_trim_fs(inode, argp); |
7942b919f nilfs2: ioctl ope... |
1271 1272 1273 1274 |
default: return -ENOTTY; } } |
828b1c50a 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 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 nilfs2: implement... |
1294 |
case NILFS_IOCTL_SET_SUINFO: |
695c60f21 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 fs: compat_ioctl:... |
1302 |
case FITRIM: |
695c60f21 nilfs2: unbreak c... |
1303 |
break; |
828b1c50a nilfs2: add compa... |
1304 1305 1306 1307 1308 1309 |
default: return -ENOIOCTLCMD; } return nilfs_ioctl(filp, cmd, (unsigned long)compat_ptr(arg)); } #endif |