]> nv-tegra.nvidia Code Review - linux-2.6.git/blobdiff - drivers/s390/char/tape_char.c
Merge branch 'for-rmk/samsung6' of git://git.fluff.org/bjdooks/linux into devel-stable
[linux-2.6.git] / drivers / s390 / char / tape_char.c
index b47e20d3d1da9a2dad66d7034ce79ff218f5aad7..539045acaad42875e03f7225f0249b55251c8e30 100644 (file)
  *              Martin Schwidefsky <schwidefsky@de.ibm.com>
  */
 
+#define KMSG_COMPONENT "tape"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/proc_fs.h>
 #include <linux/mtio.h>
 #include <linux/smp_lock.h>
+#include <linux/compat.h>
 
 #include <asm/uaccess.h>
 
@@ -33,18 +37,20 @@ static ssize_t tapechar_read(struct file *, char __user *, size_t, loff_t *);
 static ssize_t tapechar_write(struct file *, const char __user *, size_t, loff_t *);
 static int tapechar_open(struct inode *,struct file *);
 static int tapechar_release(struct inode *,struct file *);
-static int tapechar_ioctl(struct inode *, struct file *, unsigned int,
-                         unsigned long);
-static long tapechar_compat_ioctl(struct file *, unsigned int,
-                         unsigned long);
+static long tapechar_ioctl(struct file *, unsigned int, unsigned long);
+#ifdef CONFIG_COMPAT
+static long tapechar_compat_ioctl(struct file *, unsigned int, unsigned long);
+#endif
 
 static const struct file_operations tape_fops =
 {
        .owner = THIS_MODULE,
        .read = tapechar_read,
        .write = tapechar_write,
-       .ioctl = tapechar_ioctl,
+       .unlocked_ioctl = tapechar_ioctl,
+#ifdef CONFIG_COMPAT
        .compat_ioctl = tapechar_compat_ioctl,
+#endif
        .open = tapechar_open,
        .release = tapechar_release,
 };
@@ -284,26 +290,20 @@ tapechar_open (struct inode *inode, struct file *filp)
        if (imajor(filp->f_path.dentry->d_inode) != tapechar_major)
                return -ENODEV;
 
-       lock_kernel();
        minor = iminor(filp->f_path.dentry->d_inode);
-       device = tape_get_device(minor / TAPE_MINORS_PER_DEV);
+       device = tape_find_device(minor / TAPE_MINORS_PER_DEV);
        if (IS_ERR(device)) {
-               DBF_EVENT(3, "TCHAR:open: tape_get_device() failed\n");
-               rc = PTR_ERR(device);
-               goto out;
+               DBF_EVENT(3, "TCHAR:open: tape_find_device() failed\n");
+               return PTR_ERR(device);
        }
 
-
        rc = tape_open(device);
        if (rc == 0) {
                filp->private_data = device;
-               rc = nonseekable_open(inode, filp);
-       }
-       else
+               nonseekable_open(inode, filp);
+       } else
                tape_put_device(device);
 
-out:
-       unlock_kernel();
        return rc;
 }
 
@@ -340,7 +340,8 @@ tapechar_release(struct inode *inode, struct file *filp)
                device->char_data.idal_buf = NULL;
        }
        tape_release(device);
-       filp->private_data = tape_put_device(device);
+       filp->private_data = NULL;
+       tape_put_device(device);
 
        return 0;
 }
@@ -349,16 +350,11 @@ tapechar_release(struct inode *inode, struct file *filp)
  * Tape device io controls.
  */
 static int
-tapechar_ioctl(struct inode *inp, struct file *filp,
-              unsigned int no, unsigned long data)
+__tapechar_ioctl(struct tape_device *device,
+                unsigned int no, unsigned long data)
 {
-       struct tape_device *device;
        int rc;
 
-       DBF_EVENT(6, "TCHAR:ioct\n");
-
-       device = (struct tape_device *) filp->private_data;
-
        if (no == MTIOCTOP) {
                struct mtop op;
 
@@ -450,22 +446,45 @@ tapechar_ioctl(struct inode *inp, struct file *filp,
        return device->discipline->ioctl_fn(device, no, data);
 }
 
+static long
+tapechar_ioctl(struct file *filp, unsigned int no, unsigned long data)
+{
+       struct tape_device *device;
+       long rc;
+
+       DBF_EVENT(6, "TCHAR:ioct\n");
+
+       device = (struct tape_device *) filp->private_data;
+       mutex_lock(&device->mutex);
+       rc = __tapechar_ioctl(device, no, data);
+       mutex_unlock(&device->mutex);
+       return rc;
+}
+
+#ifdef CONFIG_COMPAT
 static long
 tapechar_compat_ioctl(struct file *filp, unsigned int no, unsigned long data)
 {
        struct tape_device *device = filp->private_data;
        int rval = -ENOIOCTLCMD;
+       unsigned long argp;
 
+       /* The 'arg' argument of any ioctl function may only be used for
+        * pointers because of the compat pointer conversion.
+        * Consider this when adding new ioctls.
+        */
+       argp = (unsigned long) compat_ptr(data);
        if (device->discipline->ioctl_fn) {
-               lock_kernel();
-               rval = device->discipline->ioctl_fn(device, no, data);
-               unlock_kernel();
+               mutex_lock(&device->mutex);
+               rval = device->discipline->ioctl_fn(device, no, argp);
+               mutex_unlock(&device->mutex);
                if (rval == -EINVAL)
                        rval = -ENOIOCTLCMD;
        }
 
        return rval;
 }
+#endif /* CONFIG_COMPAT */
 
 /*
  * Initialize character device frontend.