]> git.neil.brown.name Git - LaFS.git/commitdiff
Improve lafs_run_orphans list handling.
authorNeilBrown <neilb@suse.de>
Wed, 2 Sep 2009 00:10:03 +0000 (10:10 +1000)
committerNeilBrown <neilb@suse.de>
Wed, 2 Sep 2009 00:10:03 +0000 (10:10 +1000)
Requiring the 'handle' routines to leave the orphan on the list and
then removing it if B_Orphan isn't set is not appropriate as we will
want to remove block while they still have B_Orphan set.
So do the list management differently to still ensure a single pass
through without needing the current block to hold our place.

orphan.c

index dd1c89764ed081093d9e4dadd3b13535f007a828..96405c29f5710f2097bcf31e762be8d2f941261d 100644 (file)
--- a/orphan.c
+++ b/orphan.c
@@ -430,14 +430,7 @@ void lafs_orphan_release(struct fs *fs, struct datablock *b)
        om->nextfree--;
        om->reserved++;
        clear_bit(B_Orphan, &b->b.flags);
-       /* NOTE we don't remove the block from the orphan
-        * list yet.  This allows lafs_run_orphans to keep
-        * track of the current location in the list.
-        * Any other called of handle_orphan must call
-        * drop_orphan afterwards.
-        * so don't: list_del_init(&b->orphans);
-        * and don't:   putdref(b, MKREF(orphan_list));
-        */
+       lafs_drop_orphan(fs, b);
 
        /* Now drop the reservation we just synthesised */
        orphan_abort(fs);
@@ -463,11 +456,25 @@ static struct mutex *orphan_mutex(struct datablock *db)
 
 long lafs_run_orphans(struct fs *fs)
 {
-       struct datablock *db, *next, *toput = NULL;
+       struct datablock *db;
+       struct list_head done;
+       if (list_empty_careful(&fs->pending_orphans))
+               return MAX_SCHEDULE_TIMEOUT;
+
+       INIT_LIST_HEAD(&done);
+       /* Now process the orphans.  Move each one to 'done',
+        * then handle it.  Those which remain on 'done' get
+        * moved back at the end.
+        */
 
        spin_lock(&fs->lock);
-       list_for_each_entry_safe(db, next, &fs->pending_orphans, orphans) {
-               struct mutex *mx = orphan_mutex(db);
+       while (!list_empty(&fs->pending_orphans)) {
+               struct mutex *mx;
+               db = list_entry(fs->pending_orphans.next,
+                               struct datablock,
+                               orphans);
+               list_move(&db->orphans, &done);
+               mx = orphan_mutex(db);
                if (!mx || !mutex_trylock(mx))
                        continue;
                spin_unlock(&fs->lock);
@@ -476,10 +483,6 @@ long lafs_run_orphans(struct fs *fs)
                 * while we own the mutex, so our reference to db is safe
                 */
 
-               if (toput) {
-                       putdref(toput, MKREF(orphan_list));
-                       toput = NULL;
-               }
                switch(LAFSI(db->b.inode)->type) {
                case TypeInodeFile:
                        lafs_inode_handle_orphan(db);
@@ -488,23 +491,16 @@ long lafs_run_orphans(struct fs *fs)
                        lafs_dir_handle_orphan(db);
                        break;
                }
+               mutex_unlock(mx);
 
-               spin_lock(&fs->lock);
-               /* the 'next' entry might have been deleted, so
-                * get the current value.  'db' cannot have been removed
-                * from the list as we held the mutex.
+               /* The block has either been put, or is still on
+                * 'done'.
                 */
-               mutex_unlock(mx);
-               next = list_entry(db->orphans.next, struct datablock,
-                                 orphans);
-               if (!test_bit(B_Orphan, &db->b.flags)) {
-                       list_del_init(&db->orphans);
-                       toput = db;
-               }
+               spin_lock(&fs->lock);
        }
+       list_splice(&done, &fs->pending_orphans);
        spin_unlock(&fs->lock);
-       if (toput)
-               putdref(toput, MKREF(orphan_list));
+
        if (list_empty(&fs->pending_orphans))
                /* unmount might be waiting... */
                wake_up(&fs->async_complete);