From: Benjamin Marzinski <bmarzins@redhat.com> Date: Mon, 8 Jun 2009 18:05:32 -0500 Subject: [gfs2] get gfs2meta superblock correctly Message-id: 20090608230532.GI9501@ether.msp.redhat.com O-Subject: [RHEL-5.4 PATCH] BZ#504086 gfs2: Get gfs2meta superblock correctly. Bugzilla: 504086 RH-Acked-by: Steven Whitehouse <swhiteho@redhat.com> RH-Acked-by: Bob Peterson <rpeterso@redhat.com> The way gfs2 grabbed the superblock was incorrect. It did not follow the common locking scheme and it also didn't lock the s_umount rw semaphore. This caused a problem were once a gfs2meta filesystem was mounted, unmounts would hang. This patch makes gfs2 use the sget() to get an active reference to the superblock. This fix is already upstream: http://git.kernel.org/?p=linux/kernel/git/steve/gfs2-2.6-nmw.git;a=commitdiff;h=f6d03139d745198b434f65a28aabed524f415a4c This patch has been tested with multiple mount/unmount combinations. Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com> diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index 6f833c3..b0e9fea 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -1101,9 +1101,20 @@ static int gfs2_get_sb(struct file_system_type *fs_type, int flags, return get_sb_bdev(fs_type, flags, dev_name, data, fill_super, mnt); } +static int test_meta_super(struct super_block *s, void *ptr) +{ + struct block_device *bdev = ptr; + return (bdev == s->s_bdev); +} + +static int set_meta_super(struct super_block *s, void *ptr) +{ + return -EINVAL; +} + static struct super_block *get_gfs2_sb(const char *dev_name) { - struct super_block *sb; + struct super_block *s; struct nameidata nd; int error; @@ -1111,30 +1122,27 @@ static struct super_block *get_gfs2_sb(const char *dev_name) if (error) { printk(KERN_WARNING "GFS2: path_lookup on %s returned error %d\n", dev_name, error); - return NULL; + return ERR_PTR(-ENOENT); } - sb = nd.dentry->d_inode->i_sb; - if (sb && (sb->s_type == &gfs2_fs_type)) - atomic_inc(&sb->s_active); - else - sb = NULL; + s = sget(&gfs2_fs_type, test_meta_super, set_meta_super, + nd.dentry->d_inode->i_sb->s_bdev); path_release(&nd); - return sb; + return s; } static int gfs2_get_sb_meta(struct file_system_type *fs_type, int flags, const char *dev_name, void *data, struct vfsmount *mnt) { - struct super_block *sb = NULL; + struct super_block *s; struct gfs2_sbd *sdp; - sb = get_gfs2_sb(dev_name); - if (!sb) { + s = get_gfs2_sb(dev_name); + if (IS_ERR(s)) { printk(KERN_WARNING "GFS2: gfs2 mount does not exist\n"); - return -ENOENT; + return PTR_ERR(s); } - sdp = (struct gfs2_sbd*) sb->s_fs_info; - mnt->mnt_sb = sb; + sdp = s->s_fs_info; + mnt->mnt_sb = s; mnt->mnt_root = dget(sdp->sd_master_dir); return 0; }