->compat_ioctl for 390 tape_char
PATCH 4/4 ->compat_ioctl for 390 tape_char
The only own ioctl, TAPE390_DISPLAY, is compat_clean, everything else is routed through common translation code.
drivers/s390/char/tape_char.c +18 -0
@@ -37,6 +37,8 @@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 struct file_operations tape_fops = {
@@ -44,6 +46,7 @@ .read = tapechar_read, .write = tapechar_write, .ioctl = tapechar_ioctl, + .compat_ioctl = tapechar_compat_ioctl, .open = tapechar_open, .release = tapechar_release, };
@@ -463,6 +466,21 @@return device->discipline->ioctl_fn (device, no, data); } +static long +tapechar_compat_ioctl (struct file *filp,unsigned int no,unsigned long data) +{ +struct tape_device *device = filp->private_data; +int rval = -ENOIOCTLCMD ; + +if (device->discipline->ioctl_fn) { +lock_kernel (); + rval = device->discipline->ioctl_fn (device, no, data); +unlock_kernel (); + } + +return rval; +} +/* * Initialize character device frontend. */
arch/s390/kernel/compat_ioctl.c +0 -3
@@ -42,9 +42,6 @@#include <linux/compat_ioctl.h> #define DECLARES #include "../../../fs/compat_ioctl.c" - -/* s390 only ioctls */ -COMPATIBLE_IOCTL(TAPE390_DISPLAY) };int ioctl_table_size =ARRAY_SIZE (ioctl_start);
Quoted 8 lines · Christoph Hellwig
The only own ioctl,
TAPE390_DISPLAY, iscompat_clean, everything else is routed through common translation code.drivers/s390/char/tape_char.c +3
-0+tapechar_compat_ioctl(struct file *filp, unsigned int no, unsigned long data) +{ + struct tape_device *device = filp->private_data;
drivers/s390/char/tape_char.c line 482
Quoted 10 lines
drivers/s390/char/tape_char.c +10
-0+ int rval = -ENOIOCTLCMD; + + if (device->discipline->ioctl_fn) { + lock_kernel(); + rval = device->discipline->ioctl_fn(device, no, data); + unlock_kernel(); + } + + return rval; +}
Hmm, isn't ->compat_ioctl called before the translation lookup? If so, this code would return -EINVAL from tape_34xx_ioctl and result in never entering the conversion for MTIO* at all.
The same problem seems to be in the other patches of this series, but I could also be mistaken.
BTW, I now have a set of 25 patches that moves all handlers from fs/compat_ioctl.c over to the respective drivers and subsystems, but I'm not sure how to best test that.
I intend to at least give it a test run on my Opteron for the whatever ioctls I normally use, but the rest is just guesswork. Christoph, can you review those patches?
Arnd <><
Quoted 1 line · Arnd Bergmann
Hmm, isn't ->compat_ioctl called before the translation lookup?
Yes.
Quoted 3 lines
If so,
this code would return-EINVALfromtape_34xx_ioctland result in never entering the conversion for MTIO* at all.
we return -ENOIOCTLCMD if we didn't have a valid compat ioctl, and in that case the vfs code will try to find it in the core translation table.
Quoted 6 lines
BTW, I now have a set of 25 patches that moves all handlers from
fs/compat_ioctl.cover to the respective drivers and subsystems, but I'm not sure how to best test that.
I intend to at least give it a test run on my Opteron for the whatever ioctls I normally use, but the rest is just guesswork. Christoph, can you review those patches?
I'm not sure moving everything from fs/compat_ioctl.c is a good idea. Everything that is just in a single driver or subsystem that has common ioctl code - sure. else it doesn't make a lot of sense.
Quoted 3 lines · Christoph Hellwig
we return
-ENOIOCTLCMDif we didn't have a valid compat ioctl, and in that case the vfs code will try to find it in the core translation table.
No, the function you wrote returns -ENOIOCTLCMD only if device->discipline->ioctl_fn is NULL, otherwise it returns the code it gets from that function, which is -EINVAL.
Quoted 3 lines
I'm not sure moving everything from
fs/compat_ioctl.cis a good idea. Everything that is just in a single driver or subsystem that has common ioctl code - sure. else it doesn't make a lot of sense.
It turns out that almost everything is a single driver, the exceptions are:
- tty ioctls: I move the conversion into drivers/char/tty_io.c with a relatively big switch() statement. All drivers implementing these use tty_operations.
- block ioctl: similar for drivers/block/ioctl.c
- net ioctl: similar for net/compat.c. I also add compat_ioctl methods for proto_ops.
- cdrom, tape, v4l: I create a new file that contains a compat_ioctl file operation that can be used in each driver, either by pointing directly to it or by calling it from their own compat_ioctl handler. The handlers end up calling f_op->ioctl() internally.
- file systems: many file systems implement EXT2_IOC_GETFLAGS etc. those are trivial to handle, so I duplicate the code for each of those file systems.
Arnd <><
Quoted 8 lines · Arnd Bergmann
Quoted 3 lines · Christoph Hellwig
we return
-ENOIOCTLCMDif we didn't have a valid compat ioctl, and in that case the vfs code will try to find it in the core translation table.No, the function you wrote returns
-ENOIOCTLCMDonly ifdevice->discipline->ioctl_fnis NULL, otherwise it returns the code it gets from that function, which is-EINVAL.
indeed. updated patch below that handles that case. I couldn't find a problem like that in the other patches.
drivers/s390/char/tape_char.c +20 -0
@@ -37,6 +37,8 @@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 struct file_operations tape_fops = {
@@ -44,6 +46,7 @@ .read = tapechar_read, .write = tapechar_write, .ioctl = tapechar_ioctl, + .compat_ioctl = tapechar_compat_ioctl, .open = tapechar_open, .release = tapechar_release, };
@@ -463,6 +466,23 @@return device->discipline->ioctl_fn (device, no, data); } +static long +tapechar_compat_ioctl (struct file *filp,unsigned int no,unsigned long data) +{ +struct tape_device *device = filp->private_data; +int rval = -ENOIOCTLCMD ; + +if (device->discipline->ioctl_fn) { +lock_kernel (); + rval = device->discipline->ioctl_fn (device, no, data); +unlock_kernel (); +if (rval == -EINVAL ) + rval = -ENOIOCTLCMD ; + } + +return rval; +} +/* * Initialize character device frontend. */
arch/s390/kernel/compat_ioctl.c +0 -3
@@ -42,9 +42,6 @@#include <linux/compat_ioctl.h> #define DECLARES #include "../../../fs/compat_ioctl.c" - -/* s390 only ioctls */ -COMPATIBLE_IOCTL(TAPE390_DISPLAY) };int ioctl_table_size =ARRAY_SIZE (ioctl_start);