]> git.neil.brown.name Git - LaFS.git/commitdiff
lafs_refile: factor out check for unpinnable data blocks.
authorNeilBrown <neilb@suse.de>
Wed, 15 Sep 2010 04:57:02 +0000 (14:57 +1000)
committerNeilBrown <neilb@suse.de>
Wed, 15 Sep 2010 04:57:02 +0000 (14:57 +1000)
Data blocks can be unpinned while refcounts are still present.

Factor that case out into a stand-alone test.

We still test for datablocks being unpinnable in the 'refcnt==0'
case as PinPending might have only just been cleared.

This leaves a large bulk of tests all of which depend on
refcnt reaching zero which can be improved in a subsequent patch.

Signed-off-by: NeilBrown <neilb@suse.de>
index.c
lafs.h

diff --git a/index.c b/index.c
index ec8fa9d8f816922a5f6469cafad83199cb53035f..ebef16781d4f293963a6b307448ccb4a6d9ca51c 100644 (file)
--- a/index.c
+++ b/index.c
@@ -876,6 +876,7 @@ void lafs_refile(struct block *b, int dec)
        if (!b)
                return;
 
+       fs = fs_from_inode(b->inode);
        check_consistency(b);
 
 /* To (mostly) avoid recursion, we have a loop which may
@@ -892,6 +893,36 @@ void lafs_refile(struct block *b, int dec)
 
                set_lru(b);
 
+               if (test_bit(B_Pinned, &b->flags) &&
+                   !test_bit(B_Index, &b->flags) &&
+                   !test_bit(B_PinPending, &b->flags) &&
+                   !test_bit(B_Dirty, &b->flags) &&
+                   !test_bit(B_Realloc, &b->flags)
+                       ) {
+                       /* Don't need to be Pinned any more */
+                       /* FIXME do I need to lock access to ->parent */
+                       lafs_checkpoint_lock(fs);
+                       ph = !!test_bit(B_Phase1, &b->flags);
+                       if (test_and_clear_bit(B_Pinned, &b->flags)) {
+                               if (test_bit(B_Dirty, &b->flags) ||
+                                   test_bit(B_Realloc, &b->flags) ||
+                                   test_bit(B_PinPending, &b->flags))
+                                       /* lost a race */
+                                       set_phase(b, ph);
+                               else if (!test_bit(B_Root, &b->flags)) {
+                                       struct block *nb;
+                                       atomic_dec(&b->parent->pincnt[ph]);
+                                       nb = &b->parent->b;
+                                       if (next_parent != nb) {
+                                               LAFS_BUG(next_parent, b);
+                                               next_parent = nb;
+                                               atomic_inc(&nb->refcnt);
+                                       }
+                               }
+                       }
+                       lafs_checkpoint_unlock(fs);
+               }
+
                spin_lock(&lafs_hash_lock);
 
                /* PinPending disappears with the last non-lru reference,
@@ -901,18 +932,17 @@ void lafs_refile(struct block *b, int dec)
                        clear_bit(B_PinPending, &b->flags);
 
                ph = !!test_bit(B_Phase1, &b->flags);
-               fs = fs_from_inode(b->inode);
                /* See if we still need to be pinned */
                /* FIXME need some locking here ... */
                if (test_bit(B_Pinned, &b->flags) &&
                    !test_bit(B_PinPending, &b->flags) &&
                    !test_bit(B_Dirty, &b->flags) &&
                    !test_bit(B_Realloc, &b->flags) &&
+                   atomic_read(&b->refcnt) == dec &&
                    (!test_bit(B_Index, &b->flags) ||
                     (iblk(b)->uninc_table.pending_cnt == 0 &&
                      iblk(b)->uninc == NULL &&
                      iblk(b)->uninc_next == NULL &&
-                     atomic_read(&b->refcnt) == dec &&
                      atomic_read(&iblk(b)->pincnt[0]) == 0 &&
                      atomic_read(&iblk(b)->pincnt[1]) == 0))
                        ) {
diff --git a/lafs.h b/lafs.h
index 082d67b4a4094c47c30f3c4af6401eea8dec1fd3..c1a0e9a4a0a1881eadcc68b950bf8d1e2c3cd04b 100644 (file)
--- a/lafs.h
+++ b/lafs.h
@@ -365,6 +365,7 @@ static inline int set_phase(struct block *b, int ph)
        else
                clear_bit(B_Phase1, &b->flags);
 
+       /* FIXME do I need to lock access to ->parent */
        if (!test_and_set_bit(B_Pinned, &b->flags) &&
            b->parent) {
                atomic_inc(&b->parent->pincnt[ph]);