#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() */
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(
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;
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;
}
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;
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;
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) {
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;
}
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;
/* 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);
}
/*
- * 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.
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: