Skip to content

Commit 263d90c

Browse files
committed
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: Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>
1 parent 5e19a99 commit 263d90c

File tree

7 files changed

+64
-142
lines changed

7 files changed

+64
-142
lines changed

fs/nilfs2/gcinode.c

Lines changed: 25 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,6 @@
2828
* gcinodes), and this file provides lookup function of the dummy
2929
* inodes and their buffer read function.
3030
*
31-
* Since NILFS2 keeps up multiple checkpoints/snapshots across GC, it
32-
* has to treat blocks that belong to a same file but have different
33-
* checkpoint numbers. To avoid interference among generations, dummy
34-
* inodes are managed separately from actual inodes, and their lookup
35-
* function (nilfs_gc_iget) is designed to be specified with a
36-
* checkpoint number argument as well as an inode number.
37-
*
3831
* Buffers and pages held by the dummy inodes will be released each
3932
* time after they are copied to a new log. Dirty blocks made on the
4033
* 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)
180173
return 0;
181174
}
182175

183-
/*
184-
* nilfs_init_gccache() - allocate and initialize gc_inode hash table
185-
* @nilfs - the_nilfs
186-
*
187-
* Return Value: On success, 0.
188-
* On error, a negative error code is returned.
189-
*/
190-
int nilfs_init_gccache(struct the_nilfs *nilfs)
191-
{
192-
int loop;
193-
194-
BUG_ON(nilfs->ns_gc_inodes_h);
195-
196-
INIT_LIST_HEAD(&nilfs->ns_gc_inodes);
197-
198-
nilfs->ns_gc_inodes_h =
199-
kmalloc(sizeof(struct hlist_head) * NILFS_GCINODE_HASH_SIZE,
200-
GFP_NOFS);
201-
if (nilfs->ns_gc_inodes_h == NULL)
202-
return -ENOMEM;
203-
204-
for (loop = 0; loop < NILFS_GCINODE_HASH_SIZE; loop++)
205-
INIT_HLIST_HEAD(&nilfs->ns_gc_inodes_h[loop]);
206-
return 0;
207-
}
208-
209-
/*
210-
* nilfs_destroy_gccache() - free gc_inode hash table
211-
* @nilfs - the nilfs
212-
*/
213-
void nilfs_destroy_gccache(struct the_nilfs *nilfs)
176+
int nilfs_init_gcinode(struct inode *inode)
214177
{
215-
if (nilfs->ns_gc_inodes_h) {
216-
nilfs_remove_all_gcinode(nilfs);
217-
kfree(nilfs->ns_gc_inodes_h);
218-
nilfs->ns_gc_inodes_h = NULL;
219-
}
220-
}
221-
222-
static struct inode *alloc_gcinode(struct the_nilfs *nilfs, ino_t ino,
223-
__u64 cno)
224-
{
225-
struct inode *inode;
226-
struct nilfs_inode_info *ii;
227-
228-
inode = nilfs_mdt_new_common(nilfs, NULL, ino);
229-
if (!inode)
230-
return NULL;
231-
232-
if (nilfs_mdt_init(inode, nilfs, GFP_NOFS, 0) < 0) {
233-
nilfs_destroy_inode(inode);
234-
return NULL;
235-
}
236-
inode->i_op = NULL;
237-
inode->i_fop = NULL;
238-
inode->i_mapping->a_ops = &def_gcinode_aops;
239-
240-
ii = NILFS_I(inode);
241-
ii->i_cno = cno;
242-
ii->i_flags = 0;
243-
ii->i_state = 1 << NILFS_I_GCINODE;
244-
ii->i_bh = NULL;
245-
nilfs_bmap_init_gc(ii->i_bmap);
178+
struct nilfs_inode_info *ii = NILFS_I(inode);
179+
struct the_nilfs *nilfs = NILFS_SB(inode->i_sb)->s_nilfs;
180+
int ret;
246181

247-
return inode;
248-
}
182+
ret = nilfs_mdt_init(inode, nilfs, GFP_NOFS, 0);
183+
if (!ret) {
184+
inode->i_mapping->a_ops = &def_gcinode_aops;
249185

250-
static unsigned long ihash(ino_t ino, __u64 cno)
251-
{
252-
return hash_long((unsigned long)((ino << 2) + cno),
253-
NILFS_GCINODE_HASH_BITS);
254-
}
186+
ii->i_flags = 0;
187+
nilfs_bmap_init_gc(ii->i_bmap);
255188

256-
/*
257-
* nilfs_gc_iget() - find or create gc inode with specified (ino,cno)
258-
*/
259-
struct inode *nilfs_gc_iget(struct the_nilfs *nilfs, ino_t ino, __u64 cno)
260-
{
261-
struct hlist_head *head = nilfs->ns_gc_inodes_h + ihash(ino, cno);
262-
struct hlist_node *node;
263-
struct inode *inode;
264-
265-
hlist_for_each_entry(inode, node, head, i_hash) {
266-
if (inode->i_ino == ino && NILFS_I(inode)->i_cno == cno)
267-
return inode;
268-
}
269-
270-
inode = alloc_gcinode(nilfs, ino, cno);
271-
if (likely(inode)) {
272-
hlist_add_head(&inode->i_hash, head);
189+
/*
190+
* Add the inode to GC inode list. Garbage Collection
191+
* is serialized and no two processes manipulate the
192+
* list simultaneously.
193+
*/
194+
igrab(inode);
273195
list_add(&NILFS_I(inode)->i_dirty, &nilfs->ns_gc_inodes);
274196
}
275-
return inode;
276-
}
277-
278-
/*
279-
* nilfs_clear_gcinode() - clear and free a gc inode
280-
*/
281-
void nilfs_clear_gcinode(struct inode *inode)
282-
{
283-
nilfs_mdt_destroy(inode);
197+
return ret;
284198
}
285199

286-
/*
287-
* nilfs_remove_all_gcinode() - remove all inodes from the_nilfs
200+
/**
201+
* nilfs_remove_all_gcinodes() - remove all unprocessed gc inodes
288202
*/
289-
void nilfs_remove_all_gcinode(struct the_nilfs *nilfs)
203+
void nilfs_remove_all_gcinodes(struct the_nilfs *nilfs)
290204
{
291-
struct hlist_head *head = nilfs->ns_gc_inodes_h;
292-
struct hlist_node *node, *n;
293-
struct inode *inode;
294-
int loop;
205+
struct list_head *head = &nilfs->ns_gc_inodes;
206+
struct nilfs_inode_info *ii;
295207

296-
for (loop = 0; loop < NILFS_GCINODE_HASH_SIZE; loop++, head++) {
297-
hlist_for_each_entry_safe(inode, node, n, head, i_hash) {
298-
hlist_del_init(&inode->i_hash);
299-
list_del_init(&NILFS_I(inode)->i_dirty);
300-
nilfs_clear_gcinode(inode); /* might sleep */
301-
}
208+
while (!list_empty(head)) {
209+
ii = list_first_entry(head, struct nilfs_inode_info, i_dirty);
210+
list_del_init(&ii->i_dirty);
211+
iput(&ii->vfs_inode);
302212
}
303213
}

fs/nilfs2/inode.c

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -527,6 +527,28 @@ struct inode *nilfs_iget(struct super_block *sb, unsigned long ino)
527527
return inode;
528528
}
529529

530+
struct inode *nilfs_iget_for_gc(struct super_block *sb, unsigned long ino,
531+
__u64 cno)
532+
{
533+
struct nilfs_iget_args args = { .ino = ino, .cno = cno, .for_gc = 1 };
534+
struct inode *inode;
535+
int err;
536+
537+
inode = iget5_locked(sb, ino, nilfs_iget_test, nilfs_iget_set, &args);
538+
if (unlikely(!inode))
539+
return ERR_PTR(-ENOMEM);
540+
if (!(inode->i_state & I_NEW))
541+
return inode;
542+
543+
err = nilfs_init_gcinode(inode);
544+
if (unlikely(err)) {
545+
iget_failed(inode);
546+
return ERR_PTR(err);
547+
}
548+
unlock_new_inode(inode);
549+
return inode;
550+
}
551+
530552
void nilfs_write_inode_common(struct inode *inode,
531553
struct nilfs_inode *raw_inode, int has_bmap)
532554
{

fs/nilfs2/ioctl.c

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -333,7 +333,7 @@ static int nilfs_ioctl_move_inode_block(struct inode *inode,
333333
return 0;
334334
}
335335

336-
static int nilfs_ioctl_move_blocks(struct the_nilfs *nilfs,
336+
static int nilfs_ioctl_move_blocks(struct super_block *sb,
337337
struct nilfs_argv *argv, void *buf)
338338
{
339339
size_t nmembs = argv->v_nmembs;
@@ -348,19 +348,23 @@ static int nilfs_ioctl_move_blocks(struct the_nilfs *nilfs,
348348
for (i = 0, vdesc = buf; i < nmembs; ) {
349349
ino = vdesc->vd_ino;
350350
cno = vdesc->vd_cno;
351-
inode = nilfs_gc_iget(nilfs, ino, cno);
351+
inode = nilfs_iget_for_gc(sb, ino, cno);
352352
if (unlikely(inode == NULL)) {
353353
ret = -ENOMEM;
354354
goto failed;
355355
}
356356
do {
357357
ret = nilfs_ioctl_move_inode_block(inode, vdesc,
358358
&buffers);
359-
if (unlikely(ret < 0))
359+
if (unlikely(ret < 0)) {
360+
iput(inode);
360361
goto failed;
362+
}
361363
vdesc++;
362364
} while (++i < nmembs &&
363365
vdesc->vd_ino == ino && vdesc->vd_cno == cno);
366+
367+
iput(inode); /* The inode still remains in GC inode list */
364368
}
365369

366370
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,
566570
}
567571

568572
/*
569-
* nilfs_ioctl_move_blocks() will call nilfs_gc_iget(),
573+
* nilfs_ioctl_move_blocks() will call nilfs_iget_for_gc(),
570574
* which will operates an inode list without blocking.
571575
* To protect the list from concurrent operations,
572576
* nilfs_ioctl_move_blocks should be atomic operation.
@@ -576,15 +580,14 @@ static int nilfs_ioctl_clean_segments(struct inode *inode, struct file *filp,
576580
goto out_free;
577581
}
578582

579-
ret = nilfs_ioctl_move_blocks(nilfs, &argv[0], kbufs[0]);
583+
ret = nilfs_ioctl_move_blocks(inode->i_sb, &argv[0], kbufs[0]);
580584
if (ret < 0)
581585
printk(KERN_ERR "NILFS: GC failed during preparation: "
582586
"cannot read source blocks: err=%d\n", ret);
583587
else
584588
ret = nilfs_clean_segments(inode->i_sb, argv, kbufs);
585589

586-
if (ret < 0)
587-
nilfs_remove_all_gcinode(nilfs);
590+
nilfs_remove_all_gcinodes(nilfs);
588591
clear_nilfs_gc_running(nilfs);
589592

590593
out_free:

fs/nilfs2/nilfs.h

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,8 @@ extern void nilfs_set_inode_flags(struct inode *);
248248
extern int nilfs_read_inode_common(struct inode *, struct nilfs_inode *);
249249
extern void nilfs_write_inode_common(struct inode *, struct nilfs_inode *, int);
250250
extern struct inode *nilfs_iget(struct super_block *, unsigned long);
251+
extern struct inode *nilfs_iget_for_gc(struct super_block *sb,
252+
unsigned long ino, __u64 cno);
251253
extern void nilfs_update_inode(struct inode *, struct buffer_head *);
252254
extern void nilfs_truncate(struct inode *);
253255
extern void nilfs_evict_inode(struct inode *);
@@ -292,11 +294,8 @@ int nilfs_gccache_submit_read_data(struct inode *, sector_t, sector_t, __u64,
292294
int nilfs_gccache_submit_read_node(struct inode *, sector_t, __u64,
293295
struct buffer_head **);
294296
int nilfs_gccache_wait_and_mark_dirty(struct buffer_head *);
295-
int nilfs_init_gccache(struct the_nilfs *);
296-
void nilfs_destroy_gccache(struct the_nilfs *);
297-
void nilfs_clear_gcinode(struct inode *);
298-
struct inode *nilfs_gc_iget(struct the_nilfs *, ino_t, __u64);
299-
void nilfs_remove_all_gcinode(struct the_nilfs *);
297+
int nilfs_init_gcinode(struct inode *inode);
298+
void nilfs_remove_all_gcinodes(struct the_nilfs *nilfs);
300299

301300
/* gcdat.c */
302301
int nilfs_init_gcdat_inode(struct the_nilfs *);

fs/nilfs2/segment.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2451,9 +2451,8 @@ nilfs_remove_written_gcinodes(struct the_nilfs *nilfs, struct list_head *head)
24512451
list_for_each_entry_safe(ii, n, head, i_dirty) {
24522452
if (!test_bit(NILFS_I_UPDATED, &ii->i_state))
24532453
continue;
2454-
hlist_del_init(&ii->vfs_inode.i_hash);
24552454
list_del_init(&ii->i_dirty);
2456-
nilfs_clear_gcinode(&ii->vfs_inode);
2455+
iput(&ii->vfs_inode);
24572456
}
24582457
}
24592458

fs/nilfs2/the_nilfs.c

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,8 @@ static struct the_nilfs *alloc_nilfs(struct block_device *bdev)
8787
init_rwsem(&nilfs->ns_writer_sem);
8888
INIT_LIST_HEAD(&nilfs->ns_list);
8989
INIT_LIST_HEAD(&nilfs->ns_supers);
90+
INIT_LIST_HEAD(&nilfs->ns_gc_inodes);
9091
spin_lock_init(&nilfs->ns_last_segment_lock);
91-
nilfs->ns_gc_inodes_h = NULL;
9292
init_rwsem(&nilfs->ns_segctor_sem);
9393

9494
return nilfs;
@@ -164,7 +164,6 @@ void put_nilfs(struct the_nilfs *nilfs)
164164
nilfs_mdt_destroy(nilfs->ns_gc_dat);
165165
}
166166
if (nilfs_init(nilfs)) {
167-
nilfs_destroy_gccache(nilfs);
168167
brelse(nilfs->ns_sbh[0]);
169168
brelse(nilfs->ns_sbh[1]);
170169
}
@@ -736,11 +735,6 @@ int init_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi, char *data)
736735
if (err)
737736
goto failed_sbh;
738737

739-
/* Initialize gcinode cache */
740-
err = nilfs_init_gccache(nilfs);
741-
if (err)
742-
goto failed_sbh;
743-
744738
set_nilfs_init(nilfs);
745739
err = 0;
746740
out:

fs/nilfs2/the_nilfs.h

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,6 @@ enum {
8181
* @ns_sufile: segusage file inode
8282
* @ns_gc_dat: shadow inode of the DAT file inode for GC
8383
* @ns_gc_inodes: dummy inodes to keep live blocks
84-
* @ns_gc_inodes_h: hash list to keep dummy inode holding live blocks
8584
* @ns_blocksize_bits: bit length of block size
8685
* @ns_blocksize: block size
8786
* @ns_nsegments: number of segments in filesystem
@@ -165,9 +164,8 @@ struct the_nilfs {
165164
struct inode *ns_sufile;
166165
struct inode *ns_gc_dat;
167166

168-
/* GC inode list and hash table head */
167+
/* GC inode list */
169168
struct list_head ns_gc_inodes;
170-
struct hlist_head *ns_gc_inodes_h;
171169

172170
/* Disk layout information (static) */
173171
unsigned int ns_blocksize_bits;
@@ -182,9 +180,6 @@ struct the_nilfs {
182180
u32 ns_crc_seed;
183181
};
184182

185-
#define NILFS_GCINODE_HASH_BITS 8
186-
#define NILFS_GCINODE_HASH_SIZE (1<<NILFS_GCINODE_HASH_BITS)
187-
188183
#define THE_NILFS_FNS(bit, name) \
189184
static inline void set_nilfs_##name(struct the_nilfs *nilfs) \
190185
{ \

0 commit comments

Comments
 (0)