diff options
Diffstat (limited to 'fs/nilfs2/ioctl.c')
| -rw-r--r-- | fs/nilfs2/ioctl.c | 23 |
1 files changed, 14 insertions, 9 deletions
diff --git a/fs/nilfs2/ioctl.c b/fs/nilfs2/ioctl.c index 0442ee3b394f..3e90f86d5bfe 100644 --- a/fs/nilfs2/ioctl.c +++ b/fs/nilfs2/ioctl.c | |||
| @@ -117,7 +117,7 @@ static int nilfs_ioctl_change_cpmode(struct inode *inode, struct file *filp, | |||
| 117 | if (copy_from_user(&cpmode, argp, sizeof(cpmode))) | 117 | if (copy_from_user(&cpmode, argp, sizeof(cpmode))) |
| 118 | goto out; | 118 | goto out; |
| 119 | 119 | ||
| 120 | mutex_lock(&nilfs->ns_mount_mutex); | 120 | down_read(&inode->i_sb->s_umount); |
| 121 | 121 | ||
| 122 | nilfs_transaction_begin(inode->i_sb, &ti, 0); | 122 | nilfs_transaction_begin(inode->i_sb, &ti, 0); |
| 123 | ret = nilfs_cpfile_change_cpmode( | 123 | ret = nilfs_cpfile_change_cpmode( |
| @@ -127,7 +127,7 @@ static int nilfs_ioctl_change_cpmode(struct inode *inode, struct file *filp, | |||
| 127 | else | 127 | else |
| 128 | nilfs_transaction_commit(inode->i_sb); /* never fails */ | 128 | nilfs_transaction_commit(inode->i_sb); /* never fails */ |
| 129 | 129 | ||
| 130 | mutex_unlock(&nilfs->ns_mount_mutex); | 130 | up_read(&inode->i_sb->s_umount); |
| 131 | out: | 131 | out: |
| 132 | mnt_drop_write(filp->f_path.mnt); | 132 | mnt_drop_write(filp->f_path.mnt); |
| 133 | return ret; | 133 | return ret; |
| @@ -333,7 +333,7 @@ static int nilfs_ioctl_move_inode_block(struct inode *inode, | |||
| 333 | return 0; | 333 | return 0; |
| 334 | } | 334 | } |
| 335 | 335 | ||
| 336 | static int nilfs_ioctl_move_blocks(struct the_nilfs *nilfs, | 336 | static int nilfs_ioctl_move_blocks(struct super_block *sb, |
| 337 | struct nilfs_argv *argv, void *buf) | 337 | struct nilfs_argv *argv, void *buf) |
| 338 | { | 338 | { |
| 339 | size_t nmembs = argv->v_nmembs; | 339 | size_t nmembs = argv->v_nmembs; |
| @@ -348,7 +348,7 @@ static int nilfs_ioctl_move_blocks(struct the_nilfs *nilfs, | |||
| 348 | for (i = 0, vdesc = buf; i < nmembs; ) { | 348 | for (i = 0, vdesc = buf; i < nmembs; ) { |
| 349 | ino = vdesc->vd_ino; | 349 | ino = vdesc->vd_ino; |
| 350 | cno = vdesc->vd_cno; | 350 | cno = vdesc->vd_cno; |
| 351 | inode = nilfs_gc_iget(nilfs, ino, cno); | 351 | inode = nilfs_iget_for_gc(sb, ino, cno); |
| 352 | if (unlikely(inode == NULL)) { | 352 | if (unlikely(inode == NULL)) { |
| 353 | ret = -ENOMEM; | 353 | ret = -ENOMEM; |
| 354 | goto failed; | 354 | goto failed; |
| @@ -356,11 +356,15 @@ static int nilfs_ioctl_move_blocks(struct the_nilfs *nilfs, | |||
| 356 | do { | 356 | do { |
| 357 | ret = nilfs_ioctl_move_inode_block(inode, vdesc, | 357 | ret = nilfs_ioctl_move_inode_block(inode, vdesc, |
| 358 | &buffers); | 358 | &buffers); |
| 359 | if (unlikely(ret < 0)) | 359 | if (unlikely(ret < 0)) { |
| 360 | iput(inode); | ||
| 360 | goto failed; | 361 | goto failed; |
| 362 | } | ||
| 361 | vdesc++; | 363 | vdesc++; |
| 362 | } while (++i < nmembs && | 364 | } while (++i < nmembs && |
| 363 | vdesc->vd_ino == ino && vdesc->vd_cno == cno); | 365 | vdesc->vd_ino == ino && vdesc->vd_cno == cno); |
| 366 | |||
| 367 | iput(inode); /* The inode still remains in GC inode list */ | ||
| 364 | } | 368 | } |
| 365 | 369 | ||
| 366 | list_for_each_entry_safe(bh, n, &buffers, b_assoc_buffers) { | 370 | list_for_each_entry_safe(bh, n, &buffers, b_assoc_buffers) { |
| @@ -566,7 +570,7 @@ static int nilfs_ioctl_clean_segments(struct inode *inode, struct file *filp, | |||
| 566 | } | 570 | } |
| 567 | 571 | ||
| 568 | /* | 572 | /* |
| 569 | * nilfs_ioctl_move_blocks() will call nilfs_gc_iget(), | 573 | * nilfs_ioctl_move_blocks() will call nilfs_iget_for_gc(), |
| 570 | * which will operates an inode list without blocking. | 574 | * which will operates an inode list without blocking. |
| 571 | * To protect the list from concurrent operations, | 575 | * To protect the list from concurrent operations, |
| 572 | * nilfs_ioctl_move_blocks should be atomic operation. | 576 | * nilfs_ioctl_move_blocks should be atomic operation. |
| @@ -576,15 +580,16 @@ static int nilfs_ioctl_clean_segments(struct inode *inode, struct file *filp, | |||
| 576 | goto out_free; | 580 | goto out_free; |
| 577 | } | 581 | } |
| 578 | 582 | ||
| 579 | ret = nilfs_ioctl_move_blocks(nilfs, &argv[0], kbufs[0]); | 583 | vfs_check_frozen(inode->i_sb, SB_FREEZE_WRITE); |
| 584 | |||
| 585 | ret = nilfs_ioctl_move_blocks(inode->i_sb, &argv[0], kbufs[0]); | ||
| 580 | if (ret < 0) | 586 | if (ret < 0) |
| 581 | printk(KERN_ERR "NILFS: GC failed during preparation: " | 587 | printk(KERN_ERR "NILFS: GC failed during preparation: " |
| 582 | "cannot read source blocks: err=%d\n", ret); | 588 | "cannot read source blocks: err=%d\n", ret); |
| 583 | else | 589 | else |
| 584 | ret = nilfs_clean_segments(inode->i_sb, argv, kbufs); | 590 | ret = nilfs_clean_segments(inode->i_sb, argv, kbufs); |
| 585 | 591 | ||
| 586 | if (ret < 0) | 592 | nilfs_remove_all_gcinodes(nilfs); |
| 587 | nilfs_remove_all_gcinode(nilfs); | ||
| 588 | clear_nilfs_gc_running(nilfs); | 593 | clear_nilfs_gc_running(nilfs); |
| 589 | 594 | ||
| 590 | out_free: | 595 | out_free: |
