]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - fs/nilfs2/ioctl.c
Merge branch 'master' into tk71
[mv-sheeva.git] / fs / nilfs2 / ioctl.c
index f90a33d9a5b097c06038f614cbbcecb1abfab191..496738963fdbd029aa2a39723442020c5c4d9e93 100644 (file)
@@ -22,7 +22,6 @@
 
 #include <linux/fs.h>
 #include <linux/wait.h>
-#include <linux/smp_lock.h>    /* lock_kernel(), unlock_kernel() */
 #include <linux/slab.h>
 #include <linux/capability.h>  /* capable() */
 #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,
        if (copy_from_user(&cpmode, argp, sizeof(cpmode)))
                goto out;
 
-       mutex_lock(&nilfs->ns_mount_mutex);
+       down_read(&inode->i_sb->s_umount);
 
        nilfs_transaction_begin(inode->i_sb, &ti, 0);
        ret = nilfs_cpfile_change_cpmode(
@@ -128,7 +127,7 @@ static int nilfs_ioctl_change_cpmode(struct inode *inode, struct file *filp,
        else
                nilfs_transaction_commit(inode->i_sb); /* never fails */
 
-       mutex_unlock(&nilfs->ns_mount_mutex);
+       up_read(&inode->i_sb->s_umount);
 out:
        mnt_drop_write(filp->f_path.mnt);
        return ret;
@@ -234,7 +233,7 @@ nilfs_ioctl_do_get_vinfo(struct the_nilfs *nilfs, __u64 *posp, int flags,
        int ret;
 
        down_read(&nilfs->ns_segctor_sem);
-       ret = nilfs_dat_get_vinfo(nilfs_dat_inode(nilfs), buf, size, nmembs);
+       ret = nilfs_dat_get_vinfo(nilfs->ns_dat, buf, size, nmembs);
        up_read(&nilfs->ns_segctor_sem);
        return ret;
 }
@@ -243,8 +242,7 @@ static ssize_t
 nilfs_ioctl_do_get_bdescs(struct the_nilfs *nilfs, __u64 *posp, int flags,
                          void *buf, size_t size, size_t nmembs)
 {
-       struct inode *dat = nilfs_dat_inode(nilfs);
-       struct nilfs_bmap *bmap = NILFS_I(dat)->i_bmap;
+       struct nilfs_bmap *bmap = NILFS_I(nilfs->ns_dat)->i_bmap;
        struct nilfs_bdesc *bdescs = buf;
        int ret, i;
 
@@ -334,10 +332,11 @@ static int nilfs_ioctl_move_inode_block(struct inode *inode,
        return 0;
 }
 
-static int nilfs_ioctl_move_blocks(struct the_nilfs *nilfs,
+static int nilfs_ioctl_move_blocks(struct super_block *sb,
                                   struct nilfs_argv *argv, void *buf)
 {
        size_t nmembs = argv->v_nmembs;
+       struct the_nilfs *nilfs = NILFS_SB(sb)->s_nilfs;
        struct inode *inode;
        struct nilfs_vdesc *vdesc;
        struct buffer_head *bh, *n;
@@ -349,19 +348,34 @@ static int nilfs_ioctl_move_blocks(struct the_nilfs *nilfs,
        for (i = 0, vdesc = buf; i < nmembs; ) {
                ino = vdesc->vd_ino;
                cno = vdesc->vd_cno;
-               inode = nilfs_gc_iget(nilfs, ino, cno);
-               if (unlikely(inode == NULL)) {
-                       ret = -ENOMEM;
+               inode = nilfs_iget_for_gc(sb, ino, cno);
+               if (IS_ERR(inode)) {
+                       ret = PTR_ERR(inode);
                        goto failed;
                }
+               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);
+               }
+
                do {
                        ret = nilfs_ioctl_move_inode_block(inode, vdesc,
                                                           &buffers);
-                       if (unlikely(ret < 0))
+                       if (unlikely(ret < 0)) {
+                               iput(inode);
                                goto failed;
+                       }
                        vdesc++;
                } while (++i < nmembs &&
                         vdesc->vd_ino == ino && vdesc->vd_cno == cno);
+
+               iput(inode); /* The inode still remains in GC inode list */
        }
 
        list_for_each_entry_safe(bh, n, &buffers, b_assoc_buffers) {
@@ -406,7 +420,7 @@ static int nilfs_ioctl_free_vblocknrs(struct the_nilfs *nilfs,
        size_t nmembs = argv->v_nmembs;
        int ret;
 
-       ret = nilfs_dat_freev(nilfs_dat_inode(nilfs), buf, nmembs);
+       ret = nilfs_dat_freev(nilfs->ns_dat, buf, nmembs);
 
        return (ret < 0) ? ret : nmembs;
 }
@@ -415,8 +429,7 @@ static int nilfs_ioctl_mark_blocks_dirty(struct the_nilfs *nilfs,
                                         struct nilfs_argv *argv, void *buf)
 {
        size_t nmembs = argv->v_nmembs;
-       struct inode *dat = nilfs_dat_inode(nilfs);
-       struct nilfs_bmap *bmap = NILFS_I(dat)->i_bmap;
+       struct nilfs_bmap *bmap = NILFS_I(nilfs->ns_dat)->i_bmap;
        struct nilfs_bdesc *bdescs = buf;
        int ret, i;
 
@@ -435,7 +448,7 @@ static int nilfs_ioctl_mark_blocks_dirty(struct the_nilfs *nilfs,
                        /* skip dead block */
                        continue;
                if (bdescs[i].bd_level == 0) {
-                       ret = nilfs_mdt_mark_block_dirty(dat,
+                       ret = nilfs_mdt_mark_block_dirty(nilfs->ns_dat,
                                                         bdescs[i].bd_offset);
                        if (ret < 0) {
                                WARN_ON(ret == -ENOENT);
@@ -567,7 +580,7 @@ static int nilfs_ioctl_clean_segments(struct inode *inode, struct file *filp,
        }
 
        /*
-        * nilfs_ioctl_move_blocks() will call nilfs_gc_iget(),
+        * nilfs_ioctl_move_blocks() will call nilfs_iget_for_gc(),
         * which will operates an inode list without blocking.
         * To protect the list from concurrent operations,
         * nilfs_ioctl_move_blocks should be atomic operation.
@@ -577,15 +590,16 @@ static int nilfs_ioctl_clean_segments(struct inode *inode, struct file *filp,
                goto out_free;
        }
 
-       ret = nilfs_ioctl_move_blocks(nilfs, &argv[0], kbufs[0]);
+       vfs_check_frozen(inode->i_sb, SB_FREEZE_WRITE);
+
+       ret = nilfs_ioctl_move_blocks(inode->i_sb, &argv[0], kbufs[0]);
        if (ret < 0)
                printk(KERN_ERR "NILFS: GC failed during preparation: "
                        "cannot read source blocks: err=%d\n", ret);
        else
                ret = nilfs_clean_segments(inode->i_sb, argv, kbufs);
 
-       if (ret < 0)
-               nilfs_remove_all_gcinode(nilfs);
+       nilfs_remove_all_gcinodes(nilfs);
        clear_nilfs_gc_running(nilfs);
 
 out_free: