compat_ioctl: move SG_GET_REQUEST_TABLE handling
SG_GET_REQUEST_TABLE is now the last ioctl command that needs a conversion handler. This is only used in a single file, so the implementation should be there. I'm trying to simplify it in the process, to get rid of the compat_alloc_user_space() and extra copy, by adding a put_compat_request_table() function instead, which copies the data in the right format to user space. Cc: linux-scsi@vger.kernel.org Cc: Doug Gilbert <dgilbert@interlog.com> Cc: "James E.J. Bottomley" <jejb@linux.ibm.com> Cc: "Martin K. Petersen" <martin.petersen@oracle.com> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
This commit is contained in:
@@ -889,6 +889,33 @@ sg_fill_request_table(Sg_fd *sfp, sg_req_info_t *rinfo)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
struct compat_sg_req_info { /* used by SG_GET_REQUEST_TABLE ioctl() */
|
||||
char req_state;
|
||||
char orphan;
|
||||
char sg_io_owned;
|
||||
char problem;
|
||||
int pack_id;
|
||||
compat_uptr_t usr_ptr;
|
||||
unsigned int duration;
|
||||
int unused;
|
||||
};
|
||||
|
||||
static int put_compat_request_table(struct compat_sg_req_info __user *o,
|
||||
struct sg_req_info *rinfo)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < SG_MAX_QUEUE; i++) {
|
||||
if (copy_to_user(o + i, rinfo + i, offsetof(sg_req_info_t, usr_ptr)) ||
|
||||
put_user((uintptr_t)rinfo[i].usr_ptr, &o[i].usr_ptr) ||
|
||||
put_user(rinfo[i].duration, &o[i].duration) ||
|
||||
put_user(rinfo[i].unused, &o[i].unused))
|
||||
return -EFAULT;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static long
|
||||
sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg)
|
||||
{
|
||||
@@ -1069,9 +1096,7 @@ sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg)
|
||||
val = (sdp->device ? 1 : 0);
|
||||
return put_user(val, ip);
|
||||
case SG_GET_REQUEST_TABLE:
|
||||
if (!access_ok(p, SZ_SG_REQ_INFO * SG_MAX_QUEUE))
|
||||
return -EFAULT;
|
||||
else {
|
||||
{
|
||||
sg_req_info_t *rinfo;
|
||||
|
||||
rinfo = kcalloc(SG_MAX_QUEUE, SZ_SG_REQ_INFO,
|
||||
@@ -1081,8 +1106,13 @@ sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg)
|
||||
read_lock_irqsave(&sfp->rq_list_lock, iflags);
|
||||
sg_fill_request_table(sfp, rinfo);
|
||||
read_unlock_irqrestore(&sfp->rq_list_lock, iflags);
|
||||
result = __copy_to_user(p, rinfo,
|
||||
SZ_SG_REQ_INFO * SG_MAX_QUEUE);
|
||||
#ifdef CONFIG_COMPAT
|
||||
if (in_compat_syscall())
|
||||
result = put_compat_request_table(p, rinfo);
|
||||
else
|
||||
#endif
|
||||
result = copy_to_user(p, rinfo,
|
||||
SZ_SG_REQ_INFO * SG_MAX_QUEUE);
|
||||
result = result ? -EFAULT : 0;
|
||||
kfree(rinfo);
|
||||
return result;
|
||||
|
Reference in New Issue
Block a user