Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 263d90ce authored by Ryusuke Konishi's avatar Ryusuke Konishi
Browse files

nilfs2: remove own inode hash used for GC



This uses inode hash function that vfs provides instead of the own
hash table for caching gc inodes.  This finally removes the own inode
hash from nilfs.

Signed-off-by: default avatarRyusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>
parent 5e19a995
Loading
Loading
Loading
Loading
+25 −115
Original line number Diff line number Diff line
@@ -28,13 +28,6 @@
 * gcinodes), and this file provides lookup function of the dummy
 * inodes and their buffer read function.
 *
 * Since NILFS2 keeps up multiple checkpoints/snapshots across GC, it
 * has to treat blocks that belong to a same file but have different
 * checkpoint numbers.  To avoid interference among generations, dummy
 * inodes are managed separately from actual inodes, and their lookup
 * function (nilfs_gc_iget) is designed to be specified with a
 * checkpoint number argument as well as an inode number.
 *
 * Buffers and pages held by the dummy inodes will be released each
 * time after they are copied to a new log.  Dirty blocks made on the
 * current generation and the blocks to be moved by GC never overlap
@@ -180,124 +173,41 @@ int nilfs_gccache_wait_and_mark_dirty(struct buffer_head *bh)
	return 0;
}

/*
 * nilfs_init_gccache() - allocate and initialize gc_inode hash table
 * @nilfs - the_nilfs
 *
 * Return Value: On success, 0.
 * On error, a negative error code is returned.
 */
int nilfs_init_gccache(struct the_nilfs *nilfs)
int nilfs_init_gcinode(struct inode *inode)
{
	int loop;

	BUG_ON(nilfs->ns_gc_inodes_h);

	INIT_LIST_HEAD(&nilfs->ns_gc_inodes);

	nilfs->ns_gc_inodes_h =
		kmalloc(sizeof(struct hlist_head) * NILFS_GCINODE_HASH_SIZE,
			GFP_NOFS);
	if (nilfs->ns_gc_inodes_h == NULL)
		return -ENOMEM;

	for (loop = 0; loop < NILFS_GCINODE_HASH_SIZE; loop++)
		INIT_HLIST_HEAD(&nilfs->ns_gc_inodes_h[loop]);
	return 0;
}

/*
 * nilfs_destroy_gccache() - free gc_inode hash table
 * @nilfs - the nilfs
 */
void nilfs_destroy_gccache(struct the_nilfs *nilfs)
{
	if (nilfs->ns_gc_inodes_h) {
		nilfs_remove_all_gcinode(nilfs);
		kfree(nilfs->ns_gc_inodes_h);
		nilfs->ns_gc_inodes_h = NULL;
	}
}

static struct inode *alloc_gcinode(struct the_nilfs *nilfs, ino_t ino,
				   __u64 cno)
{
	struct inode *inode;
	struct nilfs_inode_info *ii;

	inode = nilfs_mdt_new_common(nilfs, NULL, ino);
	if (!inode)
		return NULL;
	struct nilfs_inode_info *ii = NILFS_I(inode);
	struct the_nilfs *nilfs = NILFS_SB(inode->i_sb)->s_nilfs;
	int ret;

	if (nilfs_mdt_init(inode, nilfs, GFP_NOFS, 0) < 0) {
		nilfs_destroy_inode(inode);
		return NULL;
	}
	inode->i_op = NULL;
	inode->i_fop = NULL;
	ret = nilfs_mdt_init(inode, nilfs, GFP_NOFS, 0);
	if (!ret) {
		inode->i_mapping->a_ops = &def_gcinode_aops;

	ii = NILFS_I(inode);
	ii->i_cno = cno;
		ii->i_flags = 0;
	ii->i_state = 1 << NILFS_I_GCINODE;
	ii->i_bh = NULL;
		nilfs_bmap_init_gc(ii->i_bmap);

	return inode;
}

static unsigned long ihash(ino_t ino, __u64 cno)
{
	return hash_long((unsigned long)((ino << 2) + cno),
			 NILFS_GCINODE_HASH_BITS);
}

		/*
 * nilfs_gc_iget() - find or create gc inode with specified (ino,cno)
		 * Add the inode to GC inode list. Garbage Collection
		 * is serialized and no two processes manipulate the
		 * list simultaneously.
		 */
struct inode *nilfs_gc_iget(struct the_nilfs *nilfs, ino_t ino, __u64 cno)
{
	struct hlist_head *head = nilfs->ns_gc_inodes_h + ihash(ino, cno);
	struct hlist_node *node;
	struct inode *inode;

	hlist_for_each_entry(inode, node, head, i_hash) {
		if (inode->i_ino == ino && NILFS_I(inode)->i_cno == cno)
			return inode;
	}

	inode = alloc_gcinode(nilfs, ino, cno);
	if (likely(inode)) {
		hlist_add_head(&inode->i_hash, head);
		igrab(inode);
		list_add(&NILFS_I(inode)->i_dirty, &nilfs->ns_gc_inodes);
	}
	return inode;
}

/*
 * nilfs_clear_gcinode() - clear and free a gc inode
 */
void nilfs_clear_gcinode(struct inode *inode)
{
	nilfs_mdt_destroy(inode);
	return ret;
}

/*
 * nilfs_remove_all_gcinode() - remove all inodes from the_nilfs
/**
 * nilfs_remove_all_gcinodes() - remove all unprocessed gc inodes
 */
void nilfs_remove_all_gcinode(struct the_nilfs *nilfs)
void nilfs_remove_all_gcinodes(struct the_nilfs *nilfs)
{
	struct hlist_head *head = nilfs->ns_gc_inodes_h;
	struct hlist_node *node, *n;
	struct inode *inode;
	int loop;
	struct list_head *head = &nilfs->ns_gc_inodes;
	struct nilfs_inode_info *ii;

	for (loop = 0; loop < NILFS_GCINODE_HASH_SIZE; loop++, head++) {
		hlist_for_each_entry_safe(inode, node, n, head, i_hash) {
			hlist_del_init(&inode->i_hash);
			list_del_init(&NILFS_I(inode)->i_dirty);
			nilfs_clear_gcinode(inode); /* might sleep */
		}
	while (!list_empty(head)) {
		ii = list_first_entry(head, struct nilfs_inode_info, i_dirty);
		list_del_init(&ii->i_dirty);
		iput(&ii->vfs_inode);
	}
}
+22 −0
Original line number Diff line number Diff line
@@ -527,6 +527,28 @@ struct inode *nilfs_iget(struct super_block *sb, unsigned long ino)
	return inode;
}

struct inode *nilfs_iget_for_gc(struct super_block *sb, unsigned long ino,
				__u64 cno)
{
	struct nilfs_iget_args args = { .ino = ino, .cno = cno, .for_gc = 1 };
	struct inode *inode;
	int err;

	inode = iget5_locked(sb, ino, nilfs_iget_test, nilfs_iget_set, &args);
	if (unlikely(!inode))
		return ERR_PTR(-ENOMEM);
	if (!(inode->i_state & I_NEW))
		return inode;

	err = nilfs_init_gcinode(inode);
	if (unlikely(err)) {
		iget_failed(inode);
		return ERR_PTR(err);
	}
	unlock_new_inode(inode);
	return inode;
}

void nilfs_write_inode_common(struct inode *inode,
			      struct nilfs_inode *raw_inode, int has_bmap)
{
+10 −7
Original line number Diff line number Diff line
@@ -333,7 +333,7 @@ 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;
@@ -348,7 +348,7 @@ 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);
		inode = nilfs_iget_for_gc(sb, ino, cno);
		if (unlikely(inode == NULL)) {
			ret = -ENOMEM;
			goto failed;
@@ -356,11 +356,15 @@ static int nilfs_ioctl_move_blocks(struct the_nilfs *nilfs,
		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) {
@@ -566,7 +570,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.
@@ -576,15 +580,14 @@ 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]);
	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:
+4 −5
Original line number Diff line number Diff line
@@ -248,6 +248,8 @@ extern void nilfs_set_inode_flags(struct inode *);
extern int nilfs_read_inode_common(struct inode *, struct nilfs_inode *);
extern void nilfs_write_inode_common(struct inode *, struct nilfs_inode *, int);
extern struct inode *nilfs_iget(struct super_block *, unsigned long);
extern struct inode *nilfs_iget_for_gc(struct super_block *sb,
				       unsigned long ino, __u64 cno);
extern void nilfs_update_inode(struct inode *, struct buffer_head *);
extern void nilfs_truncate(struct inode *);
extern void nilfs_evict_inode(struct inode *);
@@ -292,11 +294,8 @@ int nilfs_gccache_submit_read_data(struct inode *, sector_t, sector_t, __u64,
int nilfs_gccache_submit_read_node(struct inode *, sector_t, __u64,
				   struct buffer_head **);
int nilfs_gccache_wait_and_mark_dirty(struct buffer_head *);
int nilfs_init_gccache(struct the_nilfs *);
void nilfs_destroy_gccache(struct the_nilfs *);
void nilfs_clear_gcinode(struct inode *);
struct inode *nilfs_gc_iget(struct the_nilfs *, ino_t, __u64);
void nilfs_remove_all_gcinode(struct the_nilfs *);
int nilfs_init_gcinode(struct inode *inode);
void nilfs_remove_all_gcinodes(struct the_nilfs *nilfs);

/* gcdat.c */
int nilfs_init_gcdat_inode(struct the_nilfs *);
+1 −2
Original line number Diff line number Diff line
@@ -2451,9 +2451,8 @@ nilfs_remove_written_gcinodes(struct the_nilfs *nilfs, struct list_head *head)
	list_for_each_entry_safe(ii, n, head, i_dirty) {
		if (!test_bit(NILFS_I_UPDATED, &ii->i_state))
			continue;
		hlist_del_init(&ii->vfs_inode.i_hash);
		list_del_init(&ii->i_dirty);
		nilfs_clear_gcinode(&ii->vfs_inode);
		iput(&ii->vfs_inode);
	}
}

Loading