From: NeilBrown Date: Sat, 14 Aug 2010 05:01:34 +0000 (+1000) Subject: Use a new flag to identify blocks being processed by the cleaner. X-Git-Url: http://git.neil.brown.name/?a=commitdiff_plain;h=b8f0eb4ee25d9aa71d1e6d64118648bcb79127f0;p=LaFS.git Use a new flag to identify blocks being processed by the cleaner. This will help future patch which will unify cleaning and orphans list_heads, and make is clear when a refcount is being help. Signed-off-by: NeilBrown --- diff --git a/clean.c b/clean.c index 806f9cf..aff7c95 100644 --- a/clean.c +++ b/clean.c @@ -291,11 +291,13 @@ static int try_clean(struct fs *fs, struct toclean *tc) if (b == NULL) break; - if (list_empty(&b->cleaning)) { - list_add_tail(&b->cleaning, &tc->cleaning); + if (!test_and_set_bit(B_Cleaning, &b->b.flags)) { getdref(b, MKREF(cleaning)); igrab(ino); } + if (list_empty(&b->cleaning)) + list_add_tail(&b->cleaning, &tc->cleaning); + /* FIXME do I need a memory barrier. to ensure truncate * sees the not-list_empty, and we see i_size? */ @@ -304,8 +306,10 @@ static int try_clean(struct fs *fs, struct toclean *tc) ((loff_t)bnum << ino->i_blkbits) >= i_size_read(ino))) { list_del_init(&b->cleaning); - putdref(b, MKREF(cleaning)); - iput(ino); + if (test_and_clear_bit(B_Cleaning, &b->b.flags)) { + putdref(b, MKREF(cleaning)); + iput(ino); + } } putdref(b, MKREF(cleaning)); } @@ -361,10 +365,12 @@ static int try_clean(struct fs *fs, struct toclean *tc) */ done_cleaning: list_del_init(&b->cleaning); - ino = b->b.inode; - putdref(b, MKREF(cleaning)); + if (test_and_clear_bit(B_Cleaning, &b->b.flags)) { + ino = b->b.inode; + putdref(b, MKREF(cleaning)); + iput(ino); + } putref(cb, MKREF(clean2)); - iput(ino); if (rv) goto out; } @@ -380,8 +386,9 @@ void lafs_unclean(struct datablock *db) if (!list_empty_careful(&db->cleaning)) { struct fs *fs = fs_from_inode(db->b.inode); mutex_lock(&fs->cleaner.lock); - if (!list_empty(&db->cleaning)) { + if (!list_empty(&db->cleaning)) list_del_init(&db->cleaning); + if (test_and_clear_bit(B_Cleaning, &db->b.flags)) { putdref(db, MKREF(cleaning)); iput(db->b.inode); if (test_and_clear_bit(B_Async, &db->b.flags)) { diff --git a/state.h b/state.h index 0c10615..01b03d3 100644 --- a/state.h +++ b/state.h @@ -433,7 +433,7 @@ struct indexblock { #define dblk(__bl) container_of(__bl, struct datablock, b) enum { - /* NOTE: 31 flags in used. Need to overlap 'data' with 'index' if + /* NOTE: 32 flags in used. Need to overlap 'data' with 'index' if * we need much more */ /* First flags that are meaningful for both Data and Index blocks @@ -472,7 +472,7 @@ enum { B_PhysValid, /* ->physaddr is correct */ /* Flags that are only relevant for Data Block - * currently 6 */ + * currently 7 */ B_PinPending, /* set on data blocks while checkpoint_locked if we might * want to mark them dirty @@ -487,8 +487,11 @@ enum { B_HaveWriteback,/* We own the page writeback flag and when all blocks * are unlocked we should clear it. */ B_Claimed, /* Used for exclusive allocation of inodes */ + B_Cleaning, /* Used by cleaner to track which blocks it has a + * reference on already. */ + /* Flags that are only relevant for Index Blocks - * currently 2 */ + * currently 3 */ B_OnFree, /* index block on the free list */ B_PrimaryRef, /* This indexblock has not been incorporated into the * parent, and so can only be found by being a sibling