[PATCH] BLOCK: Move the loop device ioctl compat stuff to the loop driver [try #6]

Move the loop device ioctl compat stuff from fs/compat_ioctl.c to the loop
driver so that the loop header file doesn't need to be included.

Signed-Off-By: David Howells <dhowells@redhat.com>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
This commit is contained in:
David Howells 2006-08-29 19:06:14 +01:00 committed by Jens Axboe
parent b71e8a4ce0
commit 863d5b822c
3 changed files with 160 additions and 74 deletions

View File

@ -66,6 +66,7 @@
#include <linux/swap.h> #include <linux/swap.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/loop.h> #include <linux/loop.h>
#include <linux/compat.h>
#include <linux/suspend.h> #include <linux/suspend.h>
#include <linux/writeback.h> #include <linux/writeback.h>
#include <linux/buffer_head.h> /* for invalidate_bdev() */ #include <linux/buffer_head.h> /* for invalidate_bdev() */
@ -1165,6 +1166,162 @@ static int lo_ioctl(struct inode * inode, struct file * file,
return err; return err;
} }
#ifdef CONFIG_COMPAT
struct compat_loop_info {
compat_int_t lo_number; /* ioctl r/o */
compat_dev_t lo_device; /* ioctl r/o */
compat_ulong_t lo_inode; /* ioctl r/o */
compat_dev_t lo_rdevice; /* ioctl r/o */
compat_int_t lo_offset;
compat_int_t lo_encrypt_type;
compat_int_t lo_encrypt_key_size; /* ioctl w/o */
compat_int_t lo_flags; /* ioctl r/o */
char lo_name[LO_NAME_SIZE];
unsigned char lo_encrypt_key[LO_KEY_SIZE]; /* ioctl w/o */
compat_ulong_t lo_init[2];
char reserved[4];
};
/*
* Transfer 32-bit compatibility structure in userspace to 64-bit loop info
* - noinlined to reduce stack space usage in main part of driver
*/
static noinline int
loop_info64_from_compat(const struct compat_loop_info *arg,
struct loop_info64 *info64)
{
struct compat_loop_info info;
if (copy_from_user(&info, arg, sizeof(info)))
return -EFAULT;
memset(info64, 0, sizeof(*info64));
info64->lo_number = info.lo_number;
info64->lo_device = info.lo_device;
info64->lo_inode = info.lo_inode;
info64->lo_rdevice = info.lo_rdevice;
info64->lo_offset = info.lo_offset;
info64->lo_sizelimit = 0;
info64->lo_encrypt_type = info.lo_encrypt_type;
info64->lo_encrypt_key_size = info.lo_encrypt_key_size;
info64->lo_flags = info.lo_flags;
info64->lo_init[0] = info.lo_init[0];
info64->lo_init[1] = info.lo_init[1];
if (info.lo_encrypt_type == LO_CRYPT_CRYPTOAPI)
memcpy(info64->lo_crypt_name, info.lo_name, LO_NAME_SIZE);
else
memcpy(info64->lo_file_name, info.lo_name, LO_NAME_SIZE);
memcpy(info64->lo_encrypt_key, info.lo_encrypt_key, LO_KEY_SIZE);
return 0;
}
/*
* Transfer 64-bit loop info to 32-bit compatibility structure in userspace
* - noinlined to reduce stack space usage in main part of driver
*/
static noinline int
loop_info64_to_compat(const struct loop_info64 *info64,
struct compat_loop_info __user *arg)
{
struct compat_loop_info info;
memset(&info, 0, sizeof(info));
info.lo_number = info64->lo_number;
info.lo_device = info64->lo_device;
info.lo_inode = info64->lo_inode;
info.lo_rdevice = info64->lo_rdevice;
info.lo_offset = info64->lo_offset;
info.lo_encrypt_type = info64->lo_encrypt_type;
info.lo_encrypt_key_size = info64->lo_encrypt_key_size;
info.lo_flags = info64->lo_flags;
info.lo_init[0] = info64->lo_init[0];
info.lo_init[1] = info64->lo_init[1];
if (info.lo_encrypt_type == LO_CRYPT_CRYPTOAPI)
memcpy(info.lo_name, info64->lo_crypt_name, LO_NAME_SIZE);
else
memcpy(info.lo_name, info64->lo_file_name, LO_NAME_SIZE);
memcpy(info.lo_encrypt_key, info64->lo_encrypt_key, LO_KEY_SIZE);
/* error in case values were truncated */
if (info.lo_device != info64->lo_device ||
info.lo_rdevice != info64->lo_rdevice ||
info.lo_inode != info64->lo_inode ||
info.lo_offset != info64->lo_offset ||
info.lo_init[0] != info64->lo_init[0] ||
info.lo_init[1] != info64->lo_init[1])
return -EOVERFLOW;
if (copy_to_user(arg, &info, sizeof(info)))
return -EFAULT;
return 0;
}
static int
loop_set_status_compat(struct loop_device *lo,
const struct compat_loop_info __user *arg)
{
struct loop_info64 info64;
int ret;
ret = loop_info64_from_compat(arg, &info64);
if (ret < 0)
return ret;
return loop_set_status(lo, &info64);
}
static int
loop_get_status_compat(struct loop_device *lo,
struct compat_loop_info __user *arg)
{
struct loop_info64 info64;
int err = 0;
if (!arg)
err = -EINVAL;
if (!err)
err = loop_get_status(lo, &info64);
if (!err)
err = loop_info64_to_compat(&info64, arg);
return err;
}
static long lo_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
struct inode *inode = file->f_dentry->d_inode;
struct loop_device *lo = inode->i_bdev->bd_disk->private_data;
int err;
lock_kernel();
switch(cmd) {
case LOOP_SET_STATUS:
mutex_lock(&lo->lo_ctl_mutex);
err = loop_set_status_compat(
lo, (const struct compat_loop_info __user *) arg);
mutex_unlock(&lo->lo_ctl_mutex);
break;
case LOOP_GET_STATUS:
mutex_lock(&lo->lo_ctl_mutex);
err = loop_get_status_compat(
lo, (struct compat_loop_info __user *) arg);
mutex_unlock(&lo->lo_ctl_mutex);
break;
case LOOP_CLR_FD:
case LOOP_GET_STATUS64:
case LOOP_SET_STATUS64:
arg = (unsigned long) compat_ptr(arg);
case LOOP_SET_FD:
case LOOP_CHANGE_FD:
err = lo_ioctl(inode, file, cmd, arg);
break;
default:
err = -ENOIOCTLCMD;
break;
}
unlock_kernel();
return err;
}
#endif
static int lo_open(struct inode *inode, struct file *file) static int lo_open(struct inode *inode, struct file *file)
{ {
struct loop_device *lo = inode->i_bdev->bd_disk->private_data; struct loop_device *lo = inode->i_bdev->bd_disk->private_data;
@ -1192,6 +1349,9 @@ static struct block_device_operations lo_fops = {
.open = lo_open, .open = lo_open,
.release = lo_release, .release = lo_release,
.ioctl = lo_ioctl, .ioctl = lo_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = lo_compat_ioctl,
#endif
}; };
/* /*

View File

@ -40,7 +40,6 @@
#include <linux/if_pppox.h> #include <linux/if_pppox.h>
#include <linux/mtio.h> #include <linux/mtio.h>
#include <linux/cdrom.h> #include <linux/cdrom.h>
#include <linux/loop.h>
#include <linux/auto_fs.h> #include <linux/auto_fs.h>
#include <linux/auto_fs4.h> #include <linux/auto_fs4.h>
#include <linux/tty.h> #include <linux/tty.h>
@ -1214,71 +1213,6 @@ static int cdrom_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long ar
return err; return err;
} }
struct loop_info32 {
compat_int_t lo_number; /* ioctl r/o */
compat_dev_t lo_device; /* ioctl r/o */
compat_ulong_t lo_inode; /* ioctl r/o */
compat_dev_t lo_rdevice; /* ioctl r/o */
compat_int_t lo_offset;
compat_int_t lo_encrypt_type;
compat_int_t lo_encrypt_key_size; /* ioctl w/o */
compat_int_t lo_flags; /* ioctl r/o */
char lo_name[LO_NAME_SIZE];
unsigned char lo_encrypt_key[LO_KEY_SIZE]; /* ioctl w/o */
compat_ulong_t lo_init[2];
char reserved[4];
};
static int loop_status(unsigned int fd, unsigned int cmd, unsigned long arg)
{
mm_segment_t old_fs = get_fs();
struct loop_info l;
struct loop_info32 __user *ul;
int err = -EINVAL;
ul = compat_ptr(arg);
switch(cmd) {
case LOOP_SET_STATUS:
err = get_user(l.lo_number, &ul->lo_number);
err |= __get_user(l.lo_device, &ul->lo_device);
err |= __get_user(l.lo_inode, &ul->lo_inode);
err |= __get_user(l.lo_rdevice, &ul->lo_rdevice);
err |= __copy_from_user(&l.lo_offset, &ul->lo_offset,
8 + (unsigned long)l.lo_init - (unsigned long)&l.lo_offset);
if (err) {
err = -EFAULT;
} else {
set_fs (KERNEL_DS);
err = sys_ioctl (fd, cmd, (unsigned long)&l);
set_fs (old_fs);
}
break;
case LOOP_GET_STATUS:
set_fs (KERNEL_DS);
err = sys_ioctl (fd, cmd, (unsigned long)&l);
set_fs (old_fs);
if (!err) {
err = put_user(l.lo_number, &ul->lo_number);
err |= __put_user(l.lo_device, &ul->lo_device);
err |= __put_user(l.lo_inode, &ul->lo_inode);
err |= __put_user(l.lo_rdevice, &ul->lo_rdevice);
err |= __copy_to_user(&ul->lo_offset, &l.lo_offset,
(unsigned long)l.lo_init - (unsigned long)&l.lo_offset);
if (err)
err = -EFAULT;
}
break;
default: {
static int count;
if (++count <= 20)
printk("%s: Unknown loop ioctl cmd, fd(%d) "
"cmd(%08x) arg(%08lx)\n",
__FUNCTION__, fd, cmd, arg);
}
}
return err;
}
#ifdef CONFIG_VT #ifdef CONFIG_VT
static int vt_check(struct file *file) static int vt_check(struct file *file)
@ -2808,8 +2742,6 @@ HANDLE_IOCTL(MTIOCGET32, mt_ioctl_trans)
HANDLE_IOCTL(MTIOCPOS32, mt_ioctl_trans) HANDLE_IOCTL(MTIOCPOS32, mt_ioctl_trans)
HANDLE_IOCTL(CDROMREADAUDIO, cdrom_ioctl_trans) HANDLE_IOCTL(CDROMREADAUDIO, cdrom_ioctl_trans)
HANDLE_IOCTL(CDROM_SEND_PACKET, cdrom_ioctl_trans) HANDLE_IOCTL(CDROM_SEND_PACKET, cdrom_ioctl_trans)
HANDLE_IOCTL(LOOP_SET_STATUS, loop_status)
HANDLE_IOCTL(LOOP_GET_STATUS, loop_status)
#define AUTOFS_IOC_SETTIMEOUT32 _IOWR(0x93,0x64,unsigned int) #define AUTOFS_IOC_SETTIMEOUT32 _IOWR(0x93,0x64,unsigned int)
HANDLE_IOCTL(AUTOFS_IOC_SETTIMEOUT32, ioc_settimeout) HANDLE_IOCTL(AUTOFS_IOC_SETTIMEOUT32, ioc_settimeout)
#ifdef CONFIG_VT #ifdef CONFIG_VT

View File

@ -395,12 +395,6 @@ COMPATIBLE_IOCTL(DVD_WRITE_STRUCT)
COMPATIBLE_IOCTL(DVD_AUTH) COMPATIBLE_IOCTL(DVD_AUTH)
/* pktcdvd */ /* pktcdvd */
COMPATIBLE_IOCTL(PACKET_CTRL_CMD) COMPATIBLE_IOCTL(PACKET_CTRL_CMD)
/* Big L */
ULONG_IOCTL(LOOP_SET_FD)
ULONG_IOCTL(LOOP_CHANGE_FD)
COMPATIBLE_IOCTL(LOOP_CLR_FD)
COMPATIBLE_IOCTL(LOOP_GET_STATUS64)
COMPATIBLE_IOCTL(LOOP_SET_STATUS64)
/* Big A */ /* Big A */
/* sparc only */ /* sparc only */
/* Big Q for sound/OSS */ /* Big Q for sound/OSS */