diff options
author | Stefan Richter <stefanr@s5r6.in-berlin.de> | 2008-08-16 00:11:48 +0200 |
---|---|---|
committer | Stefan Richter <stefanr@s5r6.in-berlin.de> | 2008-10-15 22:21:08 +0200 |
commit | 10963ea1bd966ba46a46178c4d6abcdf3c23538d (patch) | |
tree | d11eb5adbca18c9570c28fff4dffe0f7d4d1da1c | |
parent | ed6ffd08084c68e9c3911e27706dec9d4c9a4175 (diff) |
ieee1394: raw1394: replace BKL by local mutex, make ioctl() and mmap() thread-safe
This removes the last usage of the Big Kernel Lock from the ieee1394
stack, i.e. from raw1394's (unlocked_)ioctl and compat_ioctl.
The ioctl()s don't need to take the BKL, but they need to be serialized
per struct file *. In particular, accesses to ->iso_state need to be
serial. We simply use a blocking mutex for this purpose because
libraw1394 does not use O_NONBLOCK. In practice, there is no lock
contention anyway because most if not all libraw1394 clients use a
libraw1394 handle only in a single thread.
mmap() also accesses ->iso_state. Until now this was unprotected
against concurrent changes by ioctls. Fix this bug while we are at it.
Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
-rw-r--r-- | drivers/ieee1394/raw1394-private.h | 1 | ||||
-rw-r--r-- | drivers/ieee1394/raw1394.c | 23 |
2 files changed, 18 insertions, 6 deletions
diff --git a/drivers/ieee1394/raw1394-private.h b/drivers/ieee1394/raw1394-private.h index a06aaad5b44..7a225a40598 100644 --- a/drivers/ieee1394/raw1394-private.h +++ b/drivers/ieee1394/raw1394-private.h @@ -22,6 +22,7 @@ enum raw1394_iso_state { RAW1394_ISO_INACTIVE = 0, struct file_info { struct list_head list; + struct mutex state_mutex; enum { opened, initialized, connected } state; unsigned int protocol_version; diff --git a/drivers/ieee1394/raw1394.c b/drivers/ieee1394/raw1394.c index 6fa9e4a2184..975ed7062aa 100644 --- a/drivers/ieee1394/raw1394.c +++ b/drivers/ieee1394/raw1394.c @@ -34,6 +34,7 @@ #include <linux/fs.h> #include <linux/poll.h> #include <linux/module.h> +#include <linux/mutex.h> #include <linux/init.h> #include <linux/interrupt.h> #include <linux/vmalloc.h> @@ -2541,11 +2542,18 @@ static int raw1394_read_cycle_timer(struct file_info *fi, void __user * uaddr) static int raw1394_mmap(struct file *file, struct vm_area_struct *vma) { struct file_info *fi = file->private_data; + int ret; + + mutex_lock(&fi->state_mutex); if (fi->iso_state == RAW1394_ISO_INACTIVE) - return -EINVAL; + ret = -EINVAL; + else + ret = dma_region_mmap(&fi->iso_handle->data_buf, file, vma); + + mutex_unlock(&fi->state_mutex); - return dma_region_mmap(&fi->iso_handle->data_buf, file, vma); + return ret; } /* ioctl is only used for rawiso operations */ @@ -2659,10 +2667,12 @@ static long do_raw1394_ioctl(struct file *file, unsigned int cmd, static long raw1394_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { + struct file_info *fi = file->private_data; long ret; - lock_kernel(); + + mutex_lock(&fi->state_mutex); ret = do_raw1394_ioctl(file, cmd, arg); - unlock_kernel(); + mutex_unlock(&fi->state_mutex); return ret; } @@ -2724,7 +2734,7 @@ static long raw1394_compat_ioctl(struct file *file, void __user *argp = (void __user *)arg; long err; - lock_kernel(); + mutex_lock(&fi->state_mutex); switch (cmd) { /* These requests have same format as long as 'int' has same size. */ case RAW1394_IOC_ISO_RECV_INIT: @@ -2757,7 +2767,7 @@ static long raw1394_compat_ioctl(struct file *file, err = -EINVAL; break; } - unlock_kernel(); + mutex_unlock(&fi->state_mutex); return err; } @@ -2791,6 +2801,7 @@ static int raw1394_open(struct inode *inode, struct file *file) fi->notification = (u8) RAW1394_NOTIFY_ON; /* busreset notification */ INIT_LIST_HEAD(&fi->list); + mutex_init(&fi->state_mutex); fi->state = opened; INIT_LIST_HEAD(&fi->req_pending); INIT_LIST_HEAD(&fi->req_complete); |