diff options
| -rw-r--r-- | fs/nilfs2/ioctl.c | 281 | ||||
| -rw-r--r-- | fs/nilfs2/mdt.c | 15 | ||||
| -rw-r--r-- | fs/nilfs2/nilfs.h | 3 | ||||
| -rw-r--r-- | fs/nilfs2/page.c | 3 | ||||
| -rw-r--r-- | fs/nilfs2/recovery.c | 6 | ||||
| -rw-r--r-- | fs/nilfs2/segment.c | 5 | ||||
| -rw-r--r-- | fs/nilfs2/segment.h | 3 |
7 files changed, 167 insertions, 149 deletions
diff --git a/fs/nilfs2/ioctl.c b/fs/nilfs2/ioctl.c index 108d281ebca5..50ff3f2cdf24 100644 --- a/fs/nilfs2/ioctl.c +++ b/fs/nilfs2/ioctl.c | |||
| @@ -25,6 +25,7 @@ | |||
| 25 | #include <linux/smp_lock.h> /* lock_kernel(), unlock_kernel() */ | 25 | #include <linux/smp_lock.h> /* lock_kernel(), unlock_kernel() */ |
| 26 | #include <linux/capability.h> /* capable() */ | 26 | #include <linux/capability.h> /* capable() */ |
| 27 | #include <linux/uaccess.h> /* copy_from_user(), copy_to_user() */ | 27 | #include <linux/uaccess.h> /* copy_from_user(), copy_to_user() */ |
| 28 | #include <linux/vmalloc.h> | ||
| 28 | #include <linux/nilfs2_fs.h> | 29 | #include <linux/nilfs2_fs.h> |
| 29 | #include "nilfs.h" | 30 | #include "nilfs.h" |
| 30 | #include "segment.h" | 31 | #include "segment.h" |
| @@ -147,29 +148,12 @@ static ssize_t | |||
| 147 | nilfs_ioctl_do_get_cpinfo(struct the_nilfs *nilfs, __u64 *posp, int flags, | 148 | nilfs_ioctl_do_get_cpinfo(struct the_nilfs *nilfs, __u64 *posp, int flags, |
| 148 | void *buf, size_t size, size_t nmembs) | 149 | void *buf, size_t size, size_t nmembs) |
| 149 | { | 150 | { |
| 150 | return nilfs_cpfile_get_cpinfo(nilfs->ns_cpfile, posp, flags, buf, | ||
| 151 | nmembs); | ||
| 152 | } | ||
| 153 | |||
| 154 | static int nilfs_ioctl_get_cpinfo(struct inode *inode, struct file *filp, | ||
| 155 | unsigned int cmd, void __user *argp) | ||
| 156 | { | ||
| 157 | struct the_nilfs *nilfs = NILFS_SB(inode->i_sb)->s_nilfs; | ||
| 158 | struct nilfs_argv argv; | ||
| 159 | int ret; | 151 | int ret; |
| 160 | 152 | ||
| 161 | if (copy_from_user(&argv, argp, sizeof(argv))) | ||
| 162 | return -EFAULT; | ||
| 163 | |||
| 164 | down_read(&nilfs->ns_segctor_sem); | 153 | down_read(&nilfs->ns_segctor_sem); |
| 165 | ret = nilfs_ioctl_wrap_copy(nilfs, &argv, _IOC_DIR(cmd), | 154 | ret = nilfs_cpfile_get_cpinfo(nilfs->ns_cpfile, posp, flags, buf, |
| 166 | nilfs_ioctl_do_get_cpinfo); | 155 | nmembs); |
| 167 | up_read(&nilfs->ns_segctor_sem); | 156 | up_read(&nilfs->ns_segctor_sem); |
| 168 | if (ret < 0) | ||
| 169 | return ret; | ||
| 170 | |||
| 171 | if (copy_to_user(argp, &argv, sizeof(argv))) | ||
| 172 | ret = -EFAULT; | ||
| 173 | return ret; | 157 | return ret; |
| 174 | } | 158 | } |
| 175 | 159 | ||
| @@ -195,28 +179,11 @@ static ssize_t | |||
| 195 | nilfs_ioctl_do_get_suinfo(struct the_nilfs *nilfs, __u64 *posp, int flags, | 179 | nilfs_ioctl_do_get_suinfo(struct the_nilfs *nilfs, __u64 *posp, int flags, |
| 196 | void *buf, size_t size, size_t nmembs) | 180 | void *buf, size_t size, size_t nmembs) |
| 197 | { | 181 | { |
| 198 | return nilfs_sufile_get_suinfo(nilfs->ns_sufile, *posp, buf, nmembs); | ||
| 199 | } | ||
| 200 | |||
| 201 | static int nilfs_ioctl_get_suinfo(struct inode *inode, struct file *filp, | ||
| 202 | unsigned int cmd, void __user *argp) | ||
| 203 | { | ||
| 204 | struct the_nilfs *nilfs = NILFS_SB(inode->i_sb)->s_nilfs; | ||
| 205 | struct nilfs_argv argv; | ||
| 206 | int ret; | 182 | int ret; |
| 207 | 183 | ||
| 208 | if (copy_from_user(&argv, argp, sizeof(argv))) | ||
| 209 | return -EFAULT; | ||
| 210 | |||
| 211 | down_read(&nilfs->ns_segctor_sem); | 184 | down_read(&nilfs->ns_segctor_sem); |
| 212 | ret = nilfs_ioctl_wrap_copy(nilfs, &argv, _IOC_DIR(cmd), | 185 | ret = nilfs_sufile_get_suinfo(nilfs->ns_sufile, *posp, buf, nmembs); |
| 213 | nilfs_ioctl_do_get_suinfo); | ||
| 214 | up_read(&nilfs->ns_segctor_sem); | 186 | up_read(&nilfs->ns_segctor_sem); |
| 215 | if (ret < 0) | ||
| 216 | return ret; | ||
| 217 | |||
| 218 | if (copy_to_user(argp, &argv, sizeof(argv))) | ||
| 219 | ret = -EFAULT; | ||
| 220 | return ret; | 187 | return ret; |
| 221 | } | 188 | } |
| 222 | 189 | ||
| @@ -242,28 +209,11 @@ static ssize_t | |||
| 242 | nilfs_ioctl_do_get_vinfo(struct the_nilfs *nilfs, __u64 *posp, int flags, | 209 | nilfs_ioctl_do_get_vinfo(struct the_nilfs *nilfs, __u64 *posp, int flags, |
| 243 | void *buf, size_t size, size_t nmembs) | 210 | void *buf, size_t size, size_t nmembs) |
| 244 | { | 211 | { |
| 245 | return nilfs_dat_get_vinfo(nilfs_dat_inode(nilfs), buf, nmembs); | ||
| 246 | } | ||
| 247 | |||
| 248 | static int nilfs_ioctl_get_vinfo(struct inode *inode, struct file *filp, | ||
| 249 | unsigned int cmd, void __user *argp) | ||
| 250 | { | ||
| 251 | struct the_nilfs *nilfs = NILFS_SB(inode->i_sb)->s_nilfs; | ||
| 252 | struct nilfs_argv argv; | ||
| 253 | int ret; | 212 | int ret; |
| 254 | 213 | ||
| 255 | if (copy_from_user(&argv, argp, sizeof(argv))) | ||
| 256 | return -EFAULT; | ||
| 257 | |||
| 258 | down_read(&nilfs->ns_segctor_sem); | 214 | down_read(&nilfs->ns_segctor_sem); |
| 259 | ret = nilfs_ioctl_wrap_copy(nilfs, &argv, _IOC_DIR(cmd), | 215 | ret = nilfs_dat_get_vinfo(nilfs_dat_inode(nilfs), buf, nmembs); |
| 260 | nilfs_ioctl_do_get_vinfo); | ||
| 261 | up_read(&nilfs->ns_segctor_sem); | 216 | up_read(&nilfs->ns_segctor_sem); |
| 262 | if (ret < 0) | ||
| 263 | return ret; | ||
| 264 | |||
| 265 | if (copy_to_user(argp, &argv, sizeof(argv))) | ||
| 266 | ret = -EFAULT; | ||
| 267 | return ret; | 217 | return ret; |
| 268 | } | 218 | } |
| 269 | 219 | ||
| @@ -276,17 +226,21 @@ nilfs_ioctl_do_get_bdescs(struct the_nilfs *nilfs, __u64 *posp, int flags, | |||
| 276 | struct nilfs_bdesc *bdescs = buf; | 226 | struct nilfs_bdesc *bdescs = buf; |
| 277 | int ret, i; | 227 | int ret, i; |
| 278 | 228 | ||
| 229 | down_read(&nilfs->ns_segctor_sem); | ||
| 279 | for (i = 0; i < nmembs; i++) { | 230 | for (i = 0; i < nmembs; i++) { |
| 280 | ret = nilfs_bmap_lookup_at_level(bmap, | 231 | ret = nilfs_bmap_lookup_at_level(bmap, |
| 281 | bdescs[i].bd_offset, | 232 | bdescs[i].bd_offset, |
| 282 | bdescs[i].bd_level + 1, | 233 | bdescs[i].bd_level + 1, |
| 283 | &bdescs[i].bd_blocknr); | 234 | &bdescs[i].bd_blocknr); |
| 284 | if (ret < 0) { | 235 | if (ret < 0) { |
| 285 | if (ret != -ENOENT) | 236 | if (ret != -ENOENT) { |
| 237 | up_read(&nilfs->ns_segctor_sem); | ||
| 286 | return ret; | 238 | return ret; |
| 239 | } | ||
| 287 | bdescs[i].bd_blocknr = 0; | 240 | bdescs[i].bd_blocknr = 0; |
| 288 | } | 241 | } |
| 289 | } | 242 | } |
| 243 | up_read(&nilfs->ns_segctor_sem); | ||
| 290 | return nmembs; | 244 | return nmembs; |
| 291 | } | 245 | } |
| 292 | 246 | ||
| @@ -300,10 +254,11 @@ static int nilfs_ioctl_get_bdescs(struct inode *inode, struct file *filp, | |||
| 300 | if (copy_from_user(&argv, argp, sizeof(argv))) | 254 | if (copy_from_user(&argv, argp, sizeof(argv))) |
| 301 | return -EFAULT; | 255 | return -EFAULT; |
| 302 | 256 | ||
| 303 | down_read(&nilfs->ns_segctor_sem); | 257 | if (argv.v_size != sizeof(struct nilfs_bdesc)) |
| 258 | return -EINVAL; | ||
| 259 | |||
| 304 | ret = nilfs_ioctl_wrap_copy(nilfs, &argv, _IOC_DIR(cmd), | 260 | ret = nilfs_ioctl_wrap_copy(nilfs, &argv, _IOC_DIR(cmd), |
| 305 | nilfs_ioctl_do_get_bdescs); | 261 | nilfs_ioctl_do_get_bdescs); |
| 306 | up_read(&nilfs->ns_segctor_sem); | ||
| 307 | if (ret < 0) | 262 | if (ret < 0) |
| 308 | return ret; | 263 | return ret; |
| 309 | 264 | ||
| @@ -346,10 +301,10 @@ static int nilfs_ioctl_move_inode_block(struct inode *inode, | |||
| 346 | return 0; | 301 | return 0; |
| 347 | } | 302 | } |
| 348 | 303 | ||
| 349 | static ssize_t | 304 | static int nilfs_ioctl_move_blocks(struct the_nilfs *nilfs, |
| 350 | nilfs_ioctl_do_move_blocks(struct the_nilfs *nilfs, __u64 *posp, int flags, | 305 | struct nilfs_argv *argv, void *buf) |
| 351 | void *buf, size_t size, size_t nmembs) | ||
| 352 | { | 306 | { |
| 307 | size_t nmembs = argv->v_nmembs; | ||
| 353 | struct inode *inode; | 308 | struct inode *inode; |
| 354 | struct nilfs_vdesc *vdesc; | 309 | struct nilfs_vdesc *vdesc; |
| 355 | struct buffer_head *bh, *n; | 310 | struct buffer_head *bh, *n; |
| @@ -410,19 +365,10 @@ nilfs_ioctl_do_move_blocks(struct the_nilfs *nilfs, __u64 *posp, int flags, | |||
| 410 | return ret; | 365 | return ret; |
| 411 | } | 366 | } |
| 412 | 367 | ||
| 413 | static inline int nilfs_ioctl_move_blocks(struct the_nilfs *nilfs, | 368 | static int nilfs_ioctl_delete_checkpoints(struct the_nilfs *nilfs, |
| 414 | struct nilfs_argv *argv, | 369 | struct nilfs_argv *argv, void *buf) |
| 415 | int dir) | ||
| 416 | { | ||
| 417 | return nilfs_ioctl_wrap_copy(nilfs, argv, dir, | ||
| 418 | nilfs_ioctl_do_move_blocks); | ||
| 419 | } | ||
| 420 | |||
| 421 | static ssize_t | ||
| 422 | nilfs_ioctl_do_delete_checkpoints(struct the_nilfs *nilfs, __u64 *posp, | ||
| 423 | int flags, void *buf, size_t size, | ||
| 424 | size_t nmembs) | ||
| 425 | { | 370 | { |
| 371 | size_t nmembs = argv->v_nmembs; | ||
| 426 | struct inode *cpfile = nilfs->ns_cpfile; | 372 | struct inode *cpfile = nilfs->ns_cpfile; |
| 427 | struct nilfs_period *periods = buf; | 373 | struct nilfs_period *periods = buf; |
| 428 | int ret, i; | 374 | int ret, i; |
| @@ -436,36 +382,21 @@ nilfs_ioctl_do_delete_checkpoints(struct the_nilfs *nilfs, __u64 *posp, | |||
| 436 | return nmembs; | 382 | return nmembs; |
| 437 | } | 383 | } |
| 438 | 384 | ||
| 439 | static inline int nilfs_ioctl_delete_checkpoints(struct the_nilfs *nilfs, | 385 | static int nilfs_ioctl_free_vblocknrs(struct the_nilfs *nilfs, |
| 440 | struct nilfs_argv *argv, | 386 | struct nilfs_argv *argv, void *buf) |
| 441 | int dir) | ||
| 442 | { | 387 | { |
| 443 | return nilfs_ioctl_wrap_copy(nilfs, argv, dir, | 388 | size_t nmembs = argv->v_nmembs; |
| 444 | nilfs_ioctl_do_delete_checkpoints); | 389 | int ret; |
| 445 | } | ||
| 446 | 390 | ||
| 447 | static ssize_t | 391 | ret = nilfs_dat_freev(nilfs_dat_inode(nilfs), buf, nmembs); |
| 448 | nilfs_ioctl_do_free_vblocknrs(struct the_nilfs *nilfs, __u64 *posp, int flags, | ||
| 449 | void *buf, size_t size, size_t nmembs) | ||
| 450 | { | ||
| 451 | int ret = nilfs_dat_freev(nilfs_dat_inode(nilfs), buf, nmembs); | ||
| 452 | 392 | ||
| 453 | return (ret < 0) ? ret : nmembs; | 393 | return (ret < 0) ? ret : nmembs; |
| 454 | } | 394 | } |
| 455 | 395 | ||
| 456 | static inline int nilfs_ioctl_free_vblocknrs(struct the_nilfs *nilfs, | 396 | static int nilfs_ioctl_mark_blocks_dirty(struct the_nilfs *nilfs, |
| 457 | struct nilfs_argv *argv, | 397 | struct nilfs_argv *argv, void *buf) |
| 458 | int dir) | ||
| 459 | { | ||
| 460 | return nilfs_ioctl_wrap_copy(nilfs, argv, dir, | ||
| 461 | nilfs_ioctl_do_free_vblocknrs); | ||
| 462 | } | ||
| 463 | |||
| 464 | static ssize_t | ||
| 465 | nilfs_ioctl_do_mark_blocks_dirty(struct the_nilfs *nilfs, __u64 *posp, | ||
| 466 | int flags, void *buf, size_t size, | ||
| 467 | size_t nmembs) | ||
| 468 | { | 398 | { |
| 399 | size_t nmembs = argv->v_nmembs; | ||
| 469 | struct inode *dat = nilfs_dat_inode(nilfs); | 400 | struct inode *dat = nilfs_dat_inode(nilfs); |
| 470 | struct nilfs_bmap *bmap = NILFS_I(dat)->i_bmap; | 401 | struct nilfs_bmap *bmap = NILFS_I(dat)->i_bmap; |
| 471 | struct nilfs_bdesc *bdescs = buf; | 402 | struct nilfs_bdesc *bdescs = buf; |
| @@ -504,55 +435,37 @@ nilfs_ioctl_do_mark_blocks_dirty(struct the_nilfs *nilfs, __u64 *posp, | |||
| 504 | return nmembs; | 435 | return nmembs; |
| 505 | } | 436 | } |
| 506 | 437 | ||
| 507 | static inline int nilfs_ioctl_mark_blocks_dirty(struct the_nilfs *nilfs, | 438 | static int nilfs_ioctl_free_segments(struct the_nilfs *nilfs, |
| 508 | struct nilfs_argv *argv, | 439 | struct nilfs_argv *argv, void *buf) |
| 509 | int dir) | ||
| 510 | { | 440 | { |
| 511 | return nilfs_ioctl_wrap_copy(nilfs, argv, dir, | 441 | size_t nmembs = argv->v_nmembs; |
| 512 | nilfs_ioctl_do_mark_blocks_dirty); | 442 | struct nilfs_sb_info *sbi = nilfs->ns_writer; |
| 513 | } | ||
| 514 | |||
| 515 | static ssize_t | ||
| 516 | nilfs_ioctl_do_free_segments(struct the_nilfs *nilfs, __u64 *posp, int flags, | ||
| 517 | void *buf, size_t size, size_t nmembs) | ||
| 518 | { | ||
| 519 | struct nilfs_sb_info *sbi = nilfs_get_writer(nilfs); | ||
| 520 | int ret; | 443 | int ret; |
| 521 | 444 | ||
| 522 | if (unlikely(!sbi)) | 445 | if (unlikely(!sbi)) { |
| 446 | /* never happens because called for a writable mount */ | ||
| 447 | WARN_ON(1); | ||
| 523 | return -EROFS; | 448 | return -EROFS; |
| 449 | } | ||
| 524 | ret = nilfs_segctor_add_segments_to_be_freed( | 450 | ret = nilfs_segctor_add_segments_to_be_freed( |
| 525 | NILFS_SC(sbi), buf, nmembs); | 451 | NILFS_SC(sbi), buf, nmembs); |
| 526 | nilfs_put_writer(nilfs); | ||
| 527 | 452 | ||
| 528 | return (ret < 0) ? ret : nmembs; | 453 | return (ret < 0) ? ret : nmembs; |
| 529 | } | 454 | } |
| 530 | 455 | ||
| 531 | static inline int nilfs_ioctl_free_segments(struct the_nilfs *nilfs, | ||
| 532 | struct nilfs_argv *argv, | ||
| 533 | int dir) | ||
| 534 | { | ||
| 535 | return nilfs_ioctl_wrap_copy(nilfs, argv, dir, | ||
| 536 | nilfs_ioctl_do_free_segments); | ||
| 537 | } | ||
| 538 | |||
| 539 | int nilfs_ioctl_prepare_clean_segments(struct the_nilfs *nilfs, | 456 | int nilfs_ioctl_prepare_clean_segments(struct the_nilfs *nilfs, |
| 540 | void __user *argp) | 457 | struct nilfs_argv *argv, void **kbufs) |
| 541 | { | 458 | { |
| 542 | struct nilfs_argv argv[5]; | ||
| 543 | const char *msg; | 459 | const char *msg; |
| 544 | int dir, ret; | 460 | int ret; |
| 545 | |||
| 546 | if (copy_from_user(argv, argp, sizeof(argv))) | ||
| 547 | return -EFAULT; | ||
| 548 | 461 | ||
| 549 | dir = _IOC_WRITE; | 462 | ret = nilfs_ioctl_move_blocks(nilfs, &argv[0], kbufs[0]); |
| 550 | ret = nilfs_ioctl_move_blocks(nilfs, &argv[0], dir); | ||
| 551 | if (ret < 0) { | 463 | if (ret < 0) { |
| 552 | msg = "cannot read source blocks"; | 464 | msg = "cannot read source blocks"; |
| 553 | goto failed; | 465 | goto failed; |
| 554 | } | 466 | } |
| 555 | ret = nilfs_ioctl_delete_checkpoints(nilfs, &argv[1], dir); | 467 | |
| 468 | ret = nilfs_ioctl_delete_checkpoints(nilfs, &argv[1], kbufs[1]); | ||
| 556 | if (ret < 0) { | 469 | if (ret < 0) { |
| 557 | /* | 470 | /* |
| 558 | * can safely abort because checkpoints can be removed | 471 | * can safely abort because checkpoints can be removed |
| @@ -561,7 +474,7 @@ int nilfs_ioctl_prepare_clean_segments(struct the_nilfs *nilfs, | |||
| 561 | msg = "cannot delete checkpoints"; | 474 | msg = "cannot delete checkpoints"; |
| 562 | goto failed; | 475 | goto failed; |
| 563 | } | 476 | } |
| 564 | ret = nilfs_ioctl_free_vblocknrs(nilfs, &argv[2], dir); | 477 | ret = nilfs_ioctl_free_vblocknrs(nilfs, &argv[2], kbufs[2]); |
| 565 | if (ret < 0) { | 478 | if (ret < 0) { |
| 566 | /* | 479 | /* |
| 567 | * can safely abort because DAT file is updated atomically | 480 | * can safely abort because DAT file is updated atomically |
| @@ -570,7 +483,7 @@ int nilfs_ioctl_prepare_clean_segments(struct the_nilfs *nilfs, | |||
| 570 | msg = "cannot delete virtual blocks from DAT file"; | 483 | msg = "cannot delete virtual blocks from DAT file"; |
| 571 | goto failed; | 484 | goto failed; |
| 572 | } | 485 | } |
| 573 | ret = nilfs_ioctl_mark_blocks_dirty(nilfs, &argv[3], dir); | 486 | ret = nilfs_ioctl_mark_blocks_dirty(nilfs, &argv[3], kbufs[3]); |
| 574 | if (ret < 0) { | 487 | if (ret < 0) { |
| 575 | /* | 488 | /* |
| 576 | * can safely abort because the operation is nondestructive. | 489 | * can safely abort because the operation is nondestructive. |
| @@ -578,7 +491,7 @@ int nilfs_ioctl_prepare_clean_segments(struct the_nilfs *nilfs, | |||
| 578 | msg = "cannot mark copying blocks dirty"; | 491 | msg = "cannot mark copying blocks dirty"; |
| 579 | goto failed; | 492 | goto failed; |
| 580 | } | 493 | } |
| 581 | ret = nilfs_ioctl_free_segments(nilfs, &argv[4], dir); | 494 | ret = nilfs_ioctl_free_segments(nilfs, &argv[4], kbufs[4]); |
| 582 | if (ret < 0) { | 495 | if (ret < 0) { |
| 583 | /* | 496 | /* |
| 584 | * can safely abort because this operation is atomic. | 497 | * can safely abort because this operation is atomic. |
| @@ -598,9 +511,75 @@ int nilfs_ioctl_prepare_clean_segments(struct the_nilfs *nilfs, | |||
| 598 | static int nilfs_ioctl_clean_segments(struct inode *inode, struct file *filp, | 511 | static int nilfs_ioctl_clean_segments(struct inode *inode, struct file *filp, |
| 599 | unsigned int cmd, void __user *argp) | 512 | unsigned int cmd, void __user *argp) |
| 600 | { | 513 | { |
| 514 | struct nilfs_argv argv[5]; | ||
| 515 | const static size_t argsz[5] = { | ||
| 516 | sizeof(struct nilfs_vdesc), | ||
| 517 | sizeof(struct nilfs_period), | ||
| 518 | sizeof(__u64), | ||
| 519 | sizeof(struct nilfs_bdesc), | ||
| 520 | sizeof(__u64), | ||
| 521 | }; | ||
| 522 | void __user *base; | ||
| 523 | void *kbufs[5]; | ||
| 524 | struct the_nilfs *nilfs; | ||
| 525 | size_t len, nsegs; | ||
| 526 | int n, ret; | ||
| 527 | |||
| 601 | if (!capable(CAP_SYS_ADMIN)) | 528 | if (!capable(CAP_SYS_ADMIN)) |
| 602 | return -EPERM; | 529 | return -EPERM; |
| 603 | return nilfs_clean_segments(inode->i_sb, argp); | 530 | |
| 531 | if (copy_from_user(argv, argp, sizeof(argv))) | ||
| 532 | return -EFAULT; | ||
| 533 | |||
| 534 | nsegs = argv[4].v_nmembs; | ||
| 535 | if (argv[4].v_size != argsz[4]) | ||
| 536 | return -EINVAL; | ||
| 537 | /* | ||
| 538 | * argv[4] points to segment numbers this ioctl cleans. We | ||
| 539 | * use kmalloc() for its buffer because memory used for the | ||
| 540 | * segment numbers is enough small. | ||
| 541 | */ | ||
| 542 | kbufs[4] = memdup_user((void __user *)(unsigned long)argv[4].v_base, | ||
| 543 | nsegs * sizeof(__u64)); | ||
| 544 | if (IS_ERR(kbufs[4])) | ||
| 545 | return PTR_ERR(kbufs[4]); | ||
| 546 | |||
| 547 | nilfs = NILFS_SB(inode->i_sb)->s_nilfs; | ||
| 548 | |||
| 549 | for (n = 0; n < 4; n++) { | ||
| 550 | ret = -EINVAL; | ||
| 551 | if (argv[n].v_size != argsz[n]) | ||
| 552 | goto out_free; | ||
| 553 | |||
| 554 | if (argv[n].v_nmembs > nsegs * nilfs->ns_blocks_per_segment) | ||
| 555 | goto out_free; | ||
| 556 | |||
| 557 | len = argv[n].v_size * argv[n].v_nmembs; | ||
| 558 | base = (void __user *)(unsigned long)argv[n].v_base; | ||
| 559 | if (len == 0) { | ||
| 560 | kbufs[n] = NULL; | ||
| 561 | continue; | ||
| 562 | } | ||
| 563 | |||
| 564 | kbufs[n] = vmalloc(len); | ||
| 565 | if (!kbufs[n]) { | ||
| 566 | ret = -ENOMEM; | ||
| 567 | goto out_free; | ||
| 568 | } | ||
| 569 | if (copy_from_user(kbufs[n], base, len)) { | ||
| 570 | ret = -EFAULT; | ||
| 571 | vfree(kbufs[n]); | ||
| 572 | goto out_free; | ||
| 573 | } | ||
| 574 | } | ||
| 575 | |||
| 576 | ret = nilfs_clean_segments(inode->i_sb, argv, kbufs); | ||
| 577 | |||
| 578 | out_free: | ||
| 579 | while (--n > 0) | ||
| 580 | vfree(kbufs[n]); | ||
| 581 | kfree(kbufs[4]); | ||
| 582 | return ret; | ||
| 604 | } | 583 | } |
| 605 | 584 | ||
| 606 | static int nilfs_ioctl_sync(struct inode *inode, struct file *filp, | 585 | static int nilfs_ioctl_sync(struct inode *inode, struct file *filp, |
| @@ -621,6 +600,33 @@ static int nilfs_ioctl_sync(struct inode *inode, struct file *filp, | |||
| 621 | return 0; | 600 | return 0; |
| 622 | } | 601 | } |
| 623 | 602 | ||
| 603 | static int nilfs_ioctl_get_info(struct inode *inode, struct file *filp, | ||
| 604 | unsigned int cmd, void __user *argp, | ||
| 605 | size_t membsz, | ||
| 606 | ssize_t (*dofunc)(struct the_nilfs *, | ||
| 607 | __u64 *, int, | ||
| 608 | void *, size_t, size_t)) | ||
| 609 | |||
| 610 | { | ||
| 611 | struct the_nilfs *nilfs = NILFS_SB(inode->i_sb)->s_nilfs; | ||
| 612 | struct nilfs_argv argv; | ||
| 613 | int ret; | ||
| 614 | |||
| 615 | if (copy_from_user(&argv, argp, sizeof(argv))) | ||
| 616 | return -EFAULT; | ||
| 617 | |||
| 618 | if (argv.v_size != membsz) | ||
| 619 | return -EINVAL; | ||
| 620 | |||
| 621 | ret = nilfs_ioctl_wrap_copy(nilfs, &argv, _IOC_DIR(cmd), dofunc); | ||
| 622 | if (ret < 0) | ||
| 623 | return ret; | ||
| 624 | |||
| 625 | if (copy_to_user(argp, &argv, sizeof(argv))) | ||
| 626 | ret = -EFAULT; | ||
| 627 | return ret; | ||
| 628 | } | ||
| 629 | |||
| 624 | long nilfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) | 630 | long nilfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) |
| 625 | { | 631 | { |
| 626 | struct inode *inode = filp->f_dentry->d_inode; | 632 | struct inode *inode = filp->f_dentry->d_inode; |
| @@ -632,16 +638,21 @@ long nilfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) | |||
| 632 | case NILFS_IOCTL_DELETE_CHECKPOINT: | 638 | case NILFS_IOCTL_DELETE_CHECKPOINT: |
| 633 | return nilfs_ioctl_delete_checkpoint(inode, filp, cmd, argp); | 639 | return nilfs_ioctl_delete_checkpoint(inode, filp, cmd, argp); |
| 634 | case NILFS_IOCTL_GET_CPINFO: | 640 | case NILFS_IOCTL_GET_CPINFO: |
| 635 | return nilfs_ioctl_get_cpinfo(inode, filp, cmd, argp); | 641 | return nilfs_ioctl_get_info(inode, filp, cmd, argp, |
| 642 | sizeof(struct nilfs_cpinfo), | ||
| 643 | nilfs_ioctl_do_get_cpinfo); | ||
| 636 | case NILFS_IOCTL_GET_CPSTAT: | 644 | case NILFS_IOCTL_GET_CPSTAT: |
| 637 | return nilfs_ioctl_get_cpstat(inode, filp, cmd, argp); | 645 | return nilfs_ioctl_get_cpstat(inode, filp, cmd, argp); |
| 638 | case NILFS_IOCTL_GET_SUINFO: | 646 | case NILFS_IOCTL_GET_SUINFO: |
| 639 | return nilfs_ioctl_get_suinfo(inode, filp, cmd, argp); | 647 | return nilfs_ioctl_get_info(inode, filp, cmd, argp, |
| 648 | sizeof(struct nilfs_suinfo), | ||
| 649 | nilfs_ioctl_do_get_suinfo); | ||
| 640 | case NILFS_IOCTL_GET_SUSTAT: | 650 | case NILFS_IOCTL_GET_SUSTAT: |
| 641 | return nilfs_ioctl_get_sustat(inode, filp, cmd, argp); | 651 | return nilfs_ioctl_get_sustat(inode, filp, cmd, argp); |
| 642 | case NILFS_IOCTL_GET_VINFO: | 652 | case NILFS_IOCTL_GET_VINFO: |
| 643 | /* XXX: rename to ??? */ | 653 | return nilfs_ioctl_get_info(inode, filp, cmd, argp, |
| 644 | return nilfs_ioctl_get_vinfo(inode, filp, cmd, argp); | 654 | sizeof(struct nilfs_vinfo), |
| 655 | nilfs_ioctl_do_get_vinfo); | ||
| 645 | case NILFS_IOCTL_GET_BDESCS: | 656 | case NILFS_IOCTL_GET_BDESCS: |
| 646 | return nilfs_ioctl_get_bdescs(inode, filp, cmd, argp); | 657 | return nilfs_ioctl_get_bdescs(inode, filp, cmd, argp); |
| 647 | case NILFS_IOCTL_CLEAN_SEGMENTS: | 658 | case NILFS_IOCTL_CLEAN_SEGMENTS: |
diff --git a/fs/nilfs2/mdt.c b/fs/nilfs2/mdt.c index 47dd815433fd..bb78745a0e30 100644 --- a/fs/nilfs2/mdt.c +++ b/fs/nilfs2/mdt.c | |||
| @@ -77,19 +77,22 @@ static int nilfs_mdt_create_block(struct inode *inode, unsigned long block, | |||
| 77 | void *)) | 77 | void *)) |
| 78 | { | 78 | { |
| 79 | struct the_nilfs *nilfs = NILFS_MDT(inode)->mi_nilfs; | 79 | struct the_nilfs *nilfs = NILFS_MDT(inode)->mi_nilfs; |
| 80 | struct nilfs_sb_info *writer = NULL; | ||
| 81 | struct super_block *sb = inode->i_sb; | 80 | struct super_block *sb = inode->i_sb; |
| 82 | struct nilfs_transaction_info ti; | 81 | struct nilfs_transaction_info ti; |
| 83 | struct buffer_head *bh; | 82 | struct buffer_head *bh; |
| 84 | int err; | 83 | int err; |
| 85 | 84 | ||
| 86 | if (!sb) { | 85 | if (!sb) { |
| 87 | writer = nilfs_get_writer(nilfs); | 86 | /* |
| 88 | if (!writer) { | 87 | * Make sure this function is not called from any |
| 88 | * read-only context. | ||
| 89 | */ | ||
| 90 | if (!nilfs->ns_writer) { | ||
| 91 | WARN_ON(1); | ||
| 89 | err = -EROFS; | 92 | err = -EROFS; |
| 90 | goto out; | 93 | goto out; |
| 91 | } | 94 | } |
| 92 | sb = writer->s_super; | 95 | sb = nilfs->ns_writer->s_super; |
| 93 | } | 96 | } |
| 94 | 97 | ||
| 95 | nilfs_transaction_begin(sb, &ti, 0); | 98 | nilfs_transaction_begin(sb, &ti, 0); |
| @@ -127,8 +130,6 @@ static int nilfs_mdt_create_block(struct inode *inode, unsigned long block, | |||
| 127 | err = nilfs_transaction_commit(sb); | 130 | err = nilfs_transaction_commit(sb); |
| 128 | else | 131 | else |
| 129 | nilfs_transaction_abort(sb); | 132 | nilfs_transaction_abort(sb); |
| 130 | if (writer) | ||
| 131 | nilfs_put_writer(nilfs); | ||
| 132 | out: | 133 | out: |
| 133 | return err; | 134 | return err; |
| 134 | } | 135 | } |
| @@ -299,7 +300,7 @@ int nilfs_mdt_delete_block(struct inode *inode, unsigned long block) | |||
| 299 | int err; | 300 | int err; |
| 300 | 301 | ||
| 301 | err = nilfs_bmap_delete(ii->i_bmap, block); | 302 | err = nilfs_bmap_delete(ii->i_bmap, block); |
| 302 | if (likely(!err)) { | 303 | if (!err || err == -ENOENT) { |
| 303 | nilfs_mdt_mark_dirty(inode); | 304 | nilfs_mdt_mark_dirty(inode); |
| 304 | nilfs_mdt_forget_block(inode, block); | 305 | nilfs_mdt_forget_block(inode, block); |
| 305 | } | 306 | } |
diff --git a/fs/nilfs2/nilfs.h b/fs/nilfs2/nilfs.h index 3d0c18a16db1..da6fc0bba2e5 100644 --- a/fs/nilfs2/nilfs.h +++ b/fs/nilfs2/nilfs.h | |||
| @@ -236,7 +236,8 @@ extern int nilfs_sync_file(struct file *, struct dentry *, int); | |||
| 236 | 236 | ||
| 237 | /* ioctl.c */ | 237 | /* ioctl.c */ |
| 238 | long nilfs_ioctl(struct file *, unsigned int, unsigned long); | 238 | long nilfs_ioctl(struct file *, unsigned int, unsigned long); |
| 239 | int nilfs_ioctl_prepare_clean_segments(struct the_nilfs *, void __user *); | 239 | int nilfs_ioctl_prepare_clean_segments(struct the_nilfs *, struct nilfs_argv *, |
| 240 | void **); | ||
| 240 | 241 | ||
| 241 | /* inode.c */ | 242 | /* inode.c */ |
| 242 | extern struct inode *nilfs_new_inode(struct inode *, int); | 243 | extern struct inode *nilfs_new_inode(struct inode *, int); |
diff --git a/fs/nilfs2/page.c b/fs/nilfs2/page.c index 1bfbba9c0e9a..a2692bbc7b50 100644 --- a/fs/nilfs2/page.c +++ b/fs/nilfs2/page.c | |||
| @@ -128,7 +128,8 @@ void nilfs_forget_buffer(struct buffer_head *bh) | |||
| 128 | 128 | ||
| 129 | lock_buffer(bh); | 129 | lock_buffer(bh); |
| 130 | clear_buffer_nilfs_volatile(bh); | 130 | clear_buffer_nilfs_volatile(bh); |
| 131 | if (test_clear_buffer_dirty(bh) && nilfs_page_buffers_clean(page)) | 131 | clear_buffer_dirty(bh); |
| 132 | if (nilfs_page_buffers_clean(page)) | ||
| 132 | __nilfs_clear_page_dirty(page); | 133 | __nilfs_clear_page_dirty(page); |
| 133 | 134 | ||
| 134 | clear_buffer_uptodate(bh); | 135 | clear_buffer_uptodate(bh); |
diff --git a/fs/nilfs2/recovery.c b/fs/nilfs2/recovery.c index 4fc081e47d70..57afa9d24061 100644 --- a/fs/nilfs2/recovery.c +++ b/fs/nilfs2/recovery.c | |||
| @@ -407,6 +407,7 @@ void nilfs_dispose_segment_list(struct list_head *head) | |||
| 407 | } | 407 | } |
| 408 | 408 | ||
| 409 | static int nilfs_prepare_segment_for_recovery(struct the_nilfs *nilfs, | 409 | static int nilfs_prepare_segment_for_recovery(struct the_nilfs *nilfs, |
| 410 | struct nilfs_sb_info *sbi, | ||
| 410 | struct nilfs_recovery_info *ri) | 411 | struct nilfs_recovery_info *ri) |
| 411 | { | 412 | { |
| 412 | struct list_head *head = &ri->ri_used_segments; | 413 | struct list_head *head = &ri->ri_used_segments; |
| @@ -421,6 +422,7 @@ static int nilfs_prepare_segment_for_recovery(struct the_nilfs *nilfs, | |||
| 421 | segnum[2] = ri->ri_segnum; | 422 | segnum[2] = ri->ri_segnum; |
| 422 | segnum[3] = ri->ri_nextnum; | 423 | segnum[3] = ri->ri_nextnum; |
| 423 | 424 | ||
| 425 | nilfs_attach_writer(nilfs, sbi); | ||
| 424 | /* | 426 | /* |
| 425 | * Releasing the next segment of the latest super root. | 427 | * Releasing the next segment of the latest super root. |
| 426 | * The next segment is invalidated by this recovery. | 428 | * The next segment is invalidated by this recovery. |
| @@ -459,10 +461,10 @@ static int nilfs_prepare_segment_for_recovery(struct the_nilfs *nilfs, | |||
| 459 | nilfs->ns_pseg_offset = 0; | 461 | nilfs->ns_pseg_offset = 0; |
| 460 | nilfs->ns_seg_seq = ri->ri_seq + 2; | 462 | nilfs->ns_seg_seq = ri->ri_seq + 2; |
| 461 | nilfs->ns_nextnum = nilfs->ns_segnum = segnum[0]; | 463 | nilfs->ns_nextnum = nilfs->ns_segnum = segnum[0]; |
| 462 | return 0; | ||
| 463 | 464 | ||
| 464 | failed: | 465 | failed: |
| 465 | /* No need to recover sufile because it will be destroyed on error */ | 466 | /* No need to recover sufile because it will be destroyed on error */ |
| 467 | nilfs_detach_writer(nilfs, sbi); | ||
| 466 | return err; | 468 | return err; |
| 467 | } | 469 | } |
| 468 | 470 | ||
| @@ -728,7 +730,7 @@ int nilfs_recover_logical_segments(struct the_nilfs *nilfs, | |||
| 728 | goto failed; | 730 | goto failed; |
| 729 | 731 | ||
| 730 | if (ri->ri_need_recovery == NILFS_RECOVERY_ROLLFORWARD_DONE) { | 732 | if (ri->ri_need_recovery == NILFS_RECOVERY_ROLLFORWARD_DONE) { |
| 731 | err = nilfs_prepare_segment_for_recovery(nilfs, ri); | 733 | err = nilfs_prepare_segment_for_recovery(nilfs, sbi, ri); |
| 732 | if (unlikely(err)) { | 734 | if (unlikely(err)) { |
| 733 | printk(KERN_ERR "NILFS: Error preparing segments for " | 735 | printk(KERN_ERR "NILFS: Error preparing segments for " |
| 734 | "recovery.\n"); | 736 | "recovery.\n"); |
diff --git a/fs/nilfs2/segment.c b/fs/nilfs2/segment.c index fb70ec3be20e..22c7f65c2403 100644 --- a/fs/nilfs2/segment.c +++ b/fs/nilfs2/segment.c | |||
| @@ -2589,7 +2589,8 @@ nilfs_remove_written_gcinodes(struct the_nilfs *nilfs, struct list_head *head) | |||
| 2589 | } | 2589 | } |
| 2590 | } | 2590 | } |
| 2591 | 2591 | ||
| 2592 | int nilfs_clean_segments(struct super_block *sb, void __user *argp) | 2592 | int nilfs_clean_segments(struct super_block *sb, struct nilfs_argv *argv, |
| 2593 | void **kbufs) | ||
| 2593 | { | 2594 | { |
| 2594 | struct nilfs_sb_info *sbi = NILFS_SB(sb); | 2595 | struct nilfs_sb_info *sbi = NILFS_SB(sb); |
| 2595 | struct nilfs_sc_info *sci = NILFS_SC(sbi); | 2596 | struct nilfs_sc_info *sci = NILFS_SC(sbi); |
| @@ -2606,7 +2607,7 @@ int nilfs_clean_segments(struct super_block *sb, void __user *argp) | |||
| 2606 | err = nilfs_init_gcdat_inode(nilfs); | 2607 | err = nilfs_init_gcdat_inode(nilfs); |
| 2607 | if (unlikely(err)) | 2608 | if (unlikely(err)) |
| 2608 | goto out_unlock; | 2609 | goto out_unlock; |
| 2609 | err = nilfs_ioctl_prepare_clean_segments(nilfs, argp); | 2610 | err = nilfs_ioctl_prepare_clean_segments(nilfs, argv, kbufs); |
| 2610 | if (unlikely(err)) | 2611 | if (unlikely(err)) |
| 2611 | goto out_unlock; | 2612 | goto out_unlock; |
| 2612 | 2613 | ||
diff --git a/fs/nilfs2/segment.h b/fs/nilfs2/segment.h index a98fc1ed0bbb..476bdd5df5be 100644 --- a/fs/nilfs2/segment.h +++ b/fs/nilfs2/segment.h | |||
| @@ -222,7 +222,8 @@ extern int nilfs_construct_segment(struct super_block *); | |||
| 222 | extern int nilfs_construct_dsync_segment(struct super_block *, struct inode *, | 222 | extern int nilfs_construct_dsync_segment(struct super_block *, struct inode *, |
| 223 | loff_t, loff_t); | 223 | loff_t, loff_t); |
| 224 | extern void nilfs_flush_segment(struct super_block *, ino_t); | 224 | extern void nilfs_flush_segment(struct super_block *, ino_t); |
| 225 | extern int nilfs_clean_segments(struct super_block *, void __user *); | 225 | extern int nilfs_clean_segments(struct super_block *, struct nilfs_argv *, |
| 226 | void **); | ||
| 226 | 227 | ||
| 227 | extern int nilfs_segctor_add_segments_to_be_freed(struct nilfs_sc_info *, | 228 | extern int nilfs_segctor_add_segments_to_be_freed(struct nilfs_sc_info *, |
| 228 | __u64 *, size_t); | 229 | __u64 *, size_t); |
