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.
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 *);
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);
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);
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;
}