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