Using get_active_super will not work properly if the fs (like btrfs) does not save its s_bdev with the device it is on. Also it does not provide the entire picture, since an filesystem can be contained on multiple disks (again like btrfs). Fortunately we now have a bd_super field in struct block_device were a pointer to the superblock sitting on top of the block device can be stored. Filesystems using the vfs helper mount_bdev (the ext filesystems, xfs, etc) and gfs2 already do this (for the former it is a freebie), so for these there is no need to iterate through the list of superblocks; we can get the superblock directly from ->bd_super which is more efficient and what this patch implements. A multi-device filesystem (once again lile btrfs) can use that field to store a pointer to the superblock for each block device in its storage pool. By doing so it would get_active_super and, by extension, thaw_bdev initiated freezes working. Thanks go to Josef Bacik and Christoph Hellwig for initiating this effort to fix btrfs and for suggesting the solution implemented here, respectively. Cc: linux-fsdevel@xxxxxxxxxxxxxxx Cc: linux-btrfs@xxxxxxxxxxxxxxx Cc: Josef Bacik <jbacik@xxxxxxxxxxxx> Cc: Eric Sandeen <sandeen@xxxxxxxxxx> Cc: Christoph Hellwig <hch@xxxxxxxxxxxxx> Cc: Dave Chinner <dchinner@xxxxxxxxxx> Cc: Jan Kara <jack@xxxxxxx> Cc: Luiz Capitulino <lcapitulino@xxxxxxxxxx> Cc: Chris Mason <chris.mason@xxxxxxxxxxxx> Signed-off-by: Fernando Luis Vazquez Cao <fernando@xxxxxxxxxxxxx> --- diff -urNp linux-3.8-rc1-orig/fs/super.c linux-3.8-rc1/fs/super.c --- linux-3.8-rc1-orig/fs/super.c 2012-12-25 16:35:43.100018000 +0900 +++ linux-3.8-rc1/fs/super.c 2012-12-25 16:36:22.312018000 +0900 @@ -632,26 +632,29 @@ struct super_block *get_super(struct blo return NULL; spin_lock(&sb_lock); + if ((sb = bdev->bd_super) != NULL) + goto out_found; rescan: list_for_each_entry(sb, &super_blocks, s_list) { if (hlist_unhashed(&sb->s_instances)) continue; - if (sb->s_bdev == bdev) { - sb->s_count++; - spin_unlock(&sb_lock); - down_read(&sb->s_umount); - /* still alive? */ - if (sb->s_root && (sb->s_flags & MS_BORN)) - return sb; - up_read(&sb->s_umount); - /* nope, got unmounted */ - spin_lock(&sb_lock); - __put_super(sb); - goto rescan; - } + if (sb->s_bdev == bdev) + goto out_found; } spin_unlock(&sb_lock); return NULL; +out_found: + sb->s_count++; + spin_unlock(&sb_lock); + down_read(&sb->s_umount); + /* still alive? */ + if (sb->s_root && (sb->s_flags & MS_BORN)) + return sb; + up_read(&sb->s_umount); + /* nope, got unmounted */ + spin_lock(&sb_lock); + __put_super(sb); + goto rescan; } EXPORT_SYMBOL(get_super); @@ -696,18 +699,22 @@ struct super_block *get_active_super(str restart: spin_lock(&sb_lock); + if ((sb = bdev->bd_super) != NULL) + goto out_grabsuper; list_for_each_entry(sb, &super_blocks, s_list) { if (hlist_unhashed(&sb->s_instances)) continue; - if (sb->s_bdev == bdev) { - if (grab_super(sb)) /* drops sb_lock */ - return sb; - else - goto restart; - } + if (sb->s_bdev == bdev) + goto out_grabsuper; } spin_unlock(&sb_lock); return NULL; + +out_grabsuper: + if (grab_super(sb)) /* drops sb_lock */ + return sb; + else + goto restart; } struct super_block *user_get_super(dev_t dev) -- To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html