]> git.hungrycats.org Git - linux/commitdiff
[PATCH] sync_fs deadlock fix
authorAndrew Morton <akpm@digeo.com>
Sat, 21 Dec 2002 09:06:54 +0000 (01:06 -0800)
committerLinus Torvalds <torvalds@home.transmeta.com>
Sat, 21 Dec 2002 09:06:54 +0000 (01:06 -0800)
Running a `mount -o remount' against ext3 deadlocks if there is heavy
write activity.  It's a sort of AB/BA deadlock caused by calling
log_wait_commit() under lock_super().  The caller holds lock_super()
and is waiting for a commit, but the commit cannot complete because
lock_super() is also used in the block allocator.

The way we fixed this in tha past is to drop the superblock lock inside
ext3.  The way this patch fixes it is to arrange for lock_super() to
not be held around the ->sync_fs() call.

Also: sync_filesystems is on the sys_sync() path and is racy wrt
unmount.  Check sb->s_root after taking sb->s_umount.

Documentation/filesystems/Locking
fs/buffer.c
fs/super.c

index fa7c6091b5d25bbab3d4f5232e03d5856f9e2396..9abe2264e50b77116ddd1745c0275edc6e7af343 100644 (file)
@@ -92,7 +92,7 @@ prototypes:
        void (*delete_inode) (struct inode *);
        void (*put_super) (struct super_block *);
        void (*write_super) (struct super_block *);
-       void (*sync_fs) (struct super_block *sb, int wait);
+       int (*sync_fs) (struct super_block *sb, int wait);
        int (*statfs) (struct super_block *, struct statfs *);
        int (*remount_fs) (struct super_block *, int *, char *);
        void (*clear_inode) (struct inode *);
index 29fc75687b8eb1b2570d134a51c5ca271f22f2f9..bbe4d3b780c52af26498b48667f7a4173e0e17b2 100644 (file)
@@ -221,9 +221,9 @@ int fsync_super(struct super_block *sb)
        lock_super(sb);
        if (sb->s_dirt && sb->s_op->write_super)
                sb->s_op->write_super(sb);
+       unlock_super(sb);
        if (sb->s_op->sync_fs)
                sb->s_op->sync_fs(sb, 1);
-       unlock_super(sb);
        sync_blockdev(sb->s_bdev);
        sync_inodes_sb(sb, 1);
 
index 0840ecf9590fcc87d118c905ead17df0cdfdde6f..4242b0c46fd134d1eb6ef303d732c7e46cab0ba1 100644 (file)
@@ -192,8 +192,6 @@ void generic_shutdown_super(struct super_block *sb)
 
                if (sop->write_super && sb->s_dirt)
                        sop->write_super(sb);
-               if (sop->sync_fs)
-                       sop->sync_fs(sb, 1);
                if (sop->put_super)
                        sop->put_super(sb);
 
@@ -327,11 +325,12 @@ restart:
                        continue;
                sb->s_need_sync_fs = 0;
                if (sb->s_flags & MS_RDONLY)
-                       continue;       /* hm.  Was remounted r/w meanwhile */
+                       continue;       /* hm.  Was remounted r/o meanwhile */
                sb->s_count++;
                spin_unlock(&sb_lock);
                down_read(&sb->s_umount);
-               sb->s_op->sync_fs(sb, wait);
+               if (sb->s_root)
+                       sb->s_op->sync_fs(sb, wait);
                drop_super(sb);
                goto restart;
        }