Commit 0fff81de authored by Andrew Morton's avatar Andrew Morton Committed by James Bottomley

[PATCH] raw.c: dev_t cleanup and oops fix

Patch from Andries.Brouwer@cwi.nl

The next patch in the dev_t series eliminates the last applied use
of MAX_BLKDEV - only the definition in major.h remains.

Sneaky as I am, I combine this patch with the fix for an Oops:
On open, raw_open does
	filp->f_dentry->d_inode->i_mapping =
		bdev->bd_inode->i_mapping;
storing a pointer to bdev stuff.
But on release this pointer stayed, the block device is not
referenced anymore and disappears, and the next open references
undefined stuff.
I checked, and this can actually cause an Oops - scenario:

  # raw /dev/raw/raw12 /dev/hdf
  # dd if=/dev/raw/raw12 of=/dev/null bs=512 count=1
  # raw /dev/raw/raw12 0 0
  # dd if=/dev/raw/raw12 of=/dev/null bs=512 count=1

Oops.

More precisely the problem is that dentry_open does
file_ra_state_init(&f->f_ra, inode->i_mapping);
And file_ra_state_init uses mapping->backing_dev_info->ra_pages.
Ugly, to use so much information about the inode even before
the inode has been opened.

In the patch below I reset i_mapping upon release of the raw device.

akpm: I fixed a typo and exported default_backing_dev_info to GPL modules for
this.
parent 5c0d76c6
...@@ -19,14 +19,16 @@ ...@@ -19,14 +19,16 @@
#include <asm/uaccess.h> #include <asm/uaccess.h>
#define MAX_RAW_MINORS 256
struct raw_device_data { struct raw_device_data {
struct block_device *binding; struct block_device *binding;
int inuse; int inuse;
}; };
static struct raw_device_data raw_devices[256]; static struct raw_device_data raw_devices[MAX_RAW_MINORS];
static DECLARE_MUTEX(raw_mutex); static DECLARE_MUTEX(raw_mutex);
static struct file_operations raw_ctl_fops; static struct file_operations raw_ctl_fops; /* forward declaration */
/* /*
* Open/close code for raw IO. * Open/close code for raw IO.
...@@ -90,6 +92,11 @@ static int raw_release(struct inode *inode, struct file *filp) ...@@ -90,6 +92,11 @@ static int raw_release(struct inode *inode, struct file *filp)
bdev = raw_devices[minor].binding; bdev = raw_devices[minor].binding;
raw_devices[minor].inuse--; raw_devices[minor].inuse--;
up(&raw_mutex); up(&raw_mutex);
/* Here inode->i_mapping == bdev->bd_inode->i_mapping */
inode->i_mapping = &inode->i_data;
inode->i_mapping->backing_dev_info = &default_backing_dev_info;
bd_release(bdev); bd_release(bdev);
blkdev_put(bdev, BDEV_RAW); blkdev_put(bdev, BDEV_RAW);
return 0; return 0;
...@@ -130,11 +137,13 @@ raw_ctl_ioctl(struct inode *inode, struct file *filp, ...@@ -130,11 +137,13 @@ raw_ctl_ioctl(struct inode *inode, struct file *filp,
goto out; goto out;
err = -EINVAL; err = -EINVAL;
if (rq.raw_minor < 0 || rq.raw_minor > MINORMASK) if (rq.raw_minor < 0 || rq.raw_minor >= MAX_RAW_MINORS)
goto out; goto out;
rawdev = &raw_devices[rq.raw_minor]; rawdev = &raw_devices[rq.raw_minor];
if (command == RAW_SETBIND) { if (command == RAW_SETBIND) {
dev_t dev;
/* /*
* This is like making block devices, so demand the * This is like making block devices, so demand the
* same capability * same capability
...@@ -151,9 +160,10 @@ raw_ctl_ioctl(struct inode *inode, struct file *filp, ...@@ -151,9 +160,10 @@ raw_ctl_ioctl(struct inode *inode, struct file *filp,
*/ */
err = -EINVAL; err = -EINVAL;
dev = MKDEV(rq.block_major, rq.block_minor);
if ((rq.block_major == 0 && rq.block_minor != 0) || if ((rq.block_major == 0 && rq.block_minor != 0) ||
rq.block_major > MAX_BLKDEV || MAJOR(dev) != rq.block_major ||
rq.block_minor > MINORMASK) MINOR(dev) != rq.block_minor)
goto out; goto out;
down(&raw_mutex); down(&raw_mutex);
...@@ -170,10 +180,7 @@ raw_ctl_ioctl(struct inode *inode, struct file *filp, ...@@ -170,10 +180,7 @@ raw_ctl_ioctl(struct inode *inode, struct file *filp,
/* unbind */ /* unbind */
rawdev->binding = NULL; rawdev->binding = NULL;
} else { } else {
kdev_t kdev; rawdev->binding = bdget(dev);
kdev = mk_kdev(rq.block_major, rq.block_minor);
rawdev->binding = bdget(kdev_t_to_nr(kdev));
MOD_INC_USE_COUNT; MOD_INC_USE_COUNT;
} }
up(&raw_mutex); up(&raw_mutex);
......
...@@ -57,6 +57,7 @@ ...@@ -57,6 +57,7 @@
#include <linux/mount.h> #include <linux/mount.h>
#include <linux/ptrace.h> #include <linux/ptrace.h>
#include <linux/time.h> #include <linux/time.h>
#include <linux/backing-dev.h>
#include <asm/checksum.h> #include <asm/checksum.h>
#if defined(CONFIG_PROC_FS) #if defined(CONFIG_PROC_FS)
...@@ -367,6 +368,7 @@ EXPORT_SYMBOL_GPL(generic_file_direct_IO); ...@@ -367,6 +368,7 @@ EXPORT_SYMBOL_GPL(generic_file_direct_IO);
EXPORT_SYMBOL(generic_file_readv); EXPORT_SYMBOL(generic_file_readv);
EXPORT_SYMBOL(generic_file_writev); EXPORT_SYMBOL(generic_file_writev);
EXPORT_SYMBOL(iov_shorten); EXPORT_SYMBOL(iov_shorten);
EXPORT_SYMBOL_GPL(default_backing_dev_info);
/* tty routines */ /* tty routines */
EXPORT_SYMBOL(tty_wait_until_sent); EXPORT_SYMBOL(tty_wait_until_sent);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment