]> git.neil.brown.name Git - LaFS.git/commitdiff
Ensure lafs_orphan_release doesn't block too much
authorNeilBrown <neilb@suse.de>
Sat, 14 Aug 2010 01:16:04 +0000 (11:16 +1000)
committerNeilBrown <neilb@suse.de>
Sat, 14 Aug 2010 01:16:04 +0000 (11:16 +1000)
Make sure orphan->i_mutex isn't held for long
periods, and ensure that orphan_abort doesn't block in
erase_dblock.

Signed-off-by: NeilBrown <neilb@suse.de>
orphan.c

index b514c1c79fee6b993e5ddecb73b2c0309b95d1cf..c0bbf450c02bc28e897bb2addc8c5b4f094ebd3b 100644 (file)
--- a/orphan.c
+++ b/orphan.c
@@ -113,9 +113,10 @@ static int orphan_prepare(struct fs *fs, int async)
        mutex_lock_nested(&fs->orphans->i_mutex, I_MUTEX_QUOTA);
        bnum = (om->nextfree + om->reserved) >>
                (fs->blocksize_bits-4);
-
        b = lafs_get_block(fs->orphans, bnum, NULL, GFP_KERNEL,
                           MKREF(orphan_reserve));
+       om->reserved++;
+       mutex_unlock(&fs->orphans->i_mutex);
        if (b) {
                if (async)
                        err = lafs_read_block_async(b);
@@ -123,11 +124,13 @@ static int orphan_prepare(struct fs *fs, int async)
                        err = lafs_read_block(b);
                if (err)
                        putdref(b, MKREF(orphan_reserve));
-               else
-                       om->reserved++;
        } else
                err = -ENOMEM;
-       mutex_unlock(&fs->orphans->i_mutex);
+       if (err) {
+               mutex_lock_nested(&fs->orphans->i_mutex, I_MUTEX_QUOTA);
+               om->reserved--;
+               mutex_unlock(&fs->orphans->i_mutex);
+       }
        lafs_iolock_written(&b->b);
        set_bit(B_PinPending, &b->b.flags);
        lafs_iounlock_block(&b->b);
@@ -216,8 +219,10 @@ static void orphan_abort(struct fs *fs)
         */
        if ((om->nextfree + om->reserved) <=
            (bnum << (fs->blocksize_bits-4))
-               )
+               ) {
+               LAFS_BUG(!test_bit(B_PinPending, &b->b.flags), &b->b);
                lafs_erase_dblock(b);
+       }
 
        putdref(b, MKREF(orphan_reserve));
 }
@@ -308,6 +313,10 @@ int lafs_make_orphan_nb(struct fs *fs, struct datablock *db, struct inode *ino)
  * so we can try again later.
  * All IO requests here must be async as we run from the cleaner
  * thread.
+ * We can block in orphan->i_mutex or even in erase_dblock in
+ * orphan_abort, but i_mutex is only held for very short periods
+ * like a spinlock, and erase_dblock should not block as the block
+ * should be PinPending;
  */
 void lafs_orphan_release(struct fs *fs, struct datablock *b, struct inode *ino)
 {