From mboxrd@z Thu Jan 1 00:00:00 1970 From: Christoph Hellwig Subject: [PATCH] stale bdev reference in quotactl Date: Wed, 15 Jan 2003 22:42:48 -0500 Sender: linux-fsdevel-owner@vger.kernel.org Message-ID: <20030115224248.A8753@sgi.com> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Cc: linux-fsdevel@vger.kernel.org Return-path: To: torvalds@transmeta.com Content-Disposition: inline List-Id: linux-fsdevel.vger.kernel.org sys_quotacl tries to do a get_super on a struct block_device * to which it doesn't hold a reference (nor does it actually have to be non-NULL). As lookup bdev by name is a rather common operation I splitted out a new helper, lookup_bdev() that does this out of open_bdev_excl and switched quota.c to use it. lookup_bdev() holds a proper reference that needs to be dropped by bdput(), and it's well documented. --- 1.121/fs/block_dev.c Tue Jan 7 23:52:26 2003 +++ edited/fs/block_dev.c Wed Jan 15 20:51:33 2003 @@ -799,24 +799,20 @@ } /** - * open_bdev_excl - open a block device by name and set it up for use + * lookup_bdev - lookup a struct block_device by name * * @path: special file representing the block device - * @flags: %MS_RDONLY for opening read-only - * @kind: usage (same as the 4th paramter to blkdev_get) - * @holder: owner for exclusion * - * Open the blockdevice described by the special file at @path, claim it - * for the @holder and properly set it up for @kind usage. + * Get a reference to the blockdevice at @path in the current + * namespace if possible and return it. Return ERR_PTR(error) + * otherwise. */ -struct block_device *open_bdev_excl(const char *path, int flags, - int kind, void *holder) +struct block_device *lookup_bdev(const char *path) { - struct inode *inode; struct block_device *bdev; + struct inode *inode; struct nameidata nd; - mode_t mode = FMODE_READ; - int error = 0; + int error; if (!path || !*path) return ERR_PTR(-EINVAL); @@ -828,17 +824,44 @@ inode = nd.dentry->d_inode; error = -ENOTBLK; if (!S_ISBLK(inode->i_mode)) - goto path_release; + goto fail; error = -EACCES; if (nd.mnt->mnt_flags & MNT_NODEV) - goto path_release; + goto fail; error = bd_acquire(inode); if (error) - goto path_release; + goto fail; bdev = inode->i_bdev; - /* Done with lookups */ +out: path_release(&nd); + return bdev; +fail: + bdev = ERR_PTR(error); + goto out; +} + +/** + * open_bdev_excl - open a block device by name and set it up for use + * + * @path: special file representing the block device + * @flags: %MS_RDONLY for opening read-only + * @kind: usage (same as the 4th paramter to blkdev_get) + * @holder: owner for exclusion + * + * Open the blockdevice described by the special file at @path, claim it + * for the @holder and properly set it up for @kind usage. + */ +struct block_device *open_bdev_excl(const char *path, int flags, + int kind, void *holder) +{ + struct block_device *bdev; + mode_t mode = FMODE_READ; + int error = 0; + + bdev = lookup_bdev(path); + if (IS_ERR(bdev)) + return bdev; if (!(flags & MS_RDONLY)) mode |= FMODE_WRITE; @@ -856,10 +879,6 @@ blkdev_put: blkdev_put(bdev, BDEV_FS); - return ERR_PTR(error); - -path_release: - path_release(&nd); return ERR_PTR(error); } --- 1.10/fs/quota.c Wed Jan 1 03:44:36 2003 +++ edited/fs/quota.c Wed Jan 15 20:51:33 2003 @@ -102,35 +102,6 @@ return security_quotactl (cmd, type, id, sb); } -/* Resolve device pathname to superblock */ -static struct super_block *resolve_dev(const char *path) -{ - int ret; - mode_t mode; - struct nameidata nd; - struct block_device *bdev; - struct super_block *sb; - - ret = user_path_walk(path, &nd); - if (ret) - goto out; - - bdev = nd.dentry->d_inode->i_bdev; - mode = nd.dentry->d_inode->i_mode; - path_release(&nd); - - ret = -ENOTBLK; - if (!S_ISBLK(mode)) - goto out; - ret = -ENODEV; - sb = get_super(bdev); - if (!sb) - goto out; - return sb; -out: - return ERR_PTR(ret); -} - /* Copy parameters and call proper function */ static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id, caddr_t addr) { @@ -249,21 +220,24 @@ { uint cmds, type; struct super_block *sb = NULL; - int ret = -EINVAL; + struct block_device *bdev; + int ret = -ENODEV; cmds = cmd >> SUBCMDSHIFT; type = cmd & SUBCMDMASK; - if (IS_ERR(sb = resolve_dev(special))) { - ret = PTR_ERR(sb); - sb = NULL; - goto out; - } - if ((ret = check_quotactl_valid(sb, type, cmds, id)) < 0) - goto out; - ret = do_quotactl(sb, type, cmds, id, addr); -out: - if (sb) + bdev = lookup_bdev(special); + if (IS_ERR(bdev)) + return PTR_ERR(bdev); + sb = get_super(bdev); + bdput(bdev); + + if (sb) { + ret = check_quotactl_valid(sb, type, cmds, id); + if (ret >= 0) + ret = do_quotactl(sb, type, cmds, id, addr); drop_super(sb); + } + return ret; } --- 1.210/include/linux/fs.h Wed Jan 8 21:37:23 2003 +++ edited/include/linux/fs.h Wed Jan 15 20:51:33 2003 @@ -1103,6 +1100,7 @@ { return __bdevname(bdev->bd_dev); } +extern struct block_device *lookup_bdev(const char *); extern struct block_device *open_bdev_excl(const char *, int, int, void *); extern void close_bdev_excl(struct block_device *, int);