There are two code locations that implement the SG_IO ioctl: the old sg.c driver, and the generic scsi_ioctl helper that is in turn used by multiple drivers. To eradicate the old compat_ioctl conversion handler for the SG_IO command, I implement a readable pair of put_sg_io_hdr() /get_sg_io_hdr() helper functions that can be used for both compat and native mode, and then I call this from both drivers. For the iovec handling, there is already a compat_import_iovec() function that can simply be called in place of import_iovec(). To avoid having to pass the compat/native state through multiple indirections, I mark the SG_IO command itself as compatible in fs/compat_ioctl.c and use in_compat_syscall() to figure out where we are called from. As a side-effect of this, the sg.c driver now also accepts the 32-bit sg_io_hdr format in compat mode using the read/write interface, not just ioctl. This should improve compatiblity with old 32-bit binaries, but it would break if any application intentionally passes the 64-bit data structure in compat mode here. Steffen Maier helped debug an issue in an earlier version of this patch.
Unified · Split
| @@ -2,6 +2,7 @@ · 1 unmodified line | |||
| 2 | /* | 2 | /* |
| 3 | * Copyright (C) 2001 Jens Axboe <axboe@suse.de> | 3 | * Copyright (C) 2001 Jens Axboe <axboe@suse.de> |
| 4 | */ | 4 | */ |
| 5 | #include <linux/compat.h> | ||
| 5 | #include <linux/kernel.h> | 6 | #include <linux/kernel.h> |
| 6 | #include <linux/errno.h> | 7 | #include <linux/errno.h> |
| 7 | #include <linux/string.h> | 8 | #include <linux/string.h> |
| @@ -327,7 +328,14 @@ static int sg_io(struct request_queue *q, struct gendisk *bd_disk, · 319 unmodified lines | |||
| 327 | struct iov_iter i; | 328 | struct iov_iter i; |
| 328 | struct iovec *iov = NULL; | 329 | struct iovec *iov = NULL; |
| 329 | 330 | ||
| 330 | ret = import_iovec(rq_data_dir(rq), | 331 | #ifdef CONFIG_COMPAT |
| 332 | if (in_compat_syscall()) | ||
| 333 | ret = compat_import_iovec(rq_data_dir(rq), | ||
| 334 | hdr->dxferp, hdr->iovec_count, | ||
| 335 | 0, &iov, &i); | ||
| 336 | else | ||
| 337 | #endif | ||
| 338 | ret = import_iovec(rq_data_dir(rq), | ||
| 331 | hdr->dxferp, hdr->iovec_count, | 339 | hdr->dxferp, hdr->iovec_count, |
| 332 | 0, &iov, &i); | 340 | 0, &iov, &i); |
| 333 | if (ret < 0) | 341 | if (ret < 0) |
| @@ -542,6 +550,122 @@ static inline int blk_send_start_stop(struct request_queue *q, · 208 unmodified lines | |||
| 542 | return __blk_send_generic(q, bd_disk, GPCMD_START_STOP_UNIT, data); | 550 | return __blk_send_generic(q, bd_disk, GPCMD_START_STOP_UNIT, data); |
| 543 | } | 551 | } |
| 544 | 552 | ||
| 553 | #ifdef CONFIG_COMPAT | ||
| 554 | struct compat_sg_io_hdr { | ||
| 555 | compat_int_t interface_id; /* [i] 'S' for SCSI generic (required) */ | ||
| 556 | compat_int_t dxfer_direction; /* [i] data transfer direction */ | ||
| 557 | unsigned char cmd_len; /* [i] SCSI command length ( <= 16 bytes) */ | ||
| 558 | unsigned char mx_sb_len; /* [i] max length to write to sbp */ | ||
| 559 | unsigned short iovec_count; /* [i] 0 implies no scatter gather */ | ||
| 560 | compat_uint_t dxfer_len; /* [i] byte count of data transfer */ | ||
| 561 | compat_uint_t dxferp; /* [i], [*io] points to data transfer memory | ||
| 562 | or scatter gather list */ | ||
| 563 | compat_uptr_t cmdp; /* [i], [*i] points to command to perform */ | ||
| 564 | compat_uptr_t sbp; /* [i], [*o] points to sense_buffer memory */ | ||
| 565 | compat_uint_t timeout; /* [i] MAX_UINT->no timeout (unit: millisec) */ | ||
| 566 | compat_uint_t flags; /* [i] 0 -> default, see SG_FLAG... */ | ||
| 567 | compat_int_t pack_id; /* [i->o] unused internally (normally) */ | ||
| 568 | compat_uptr_t usr_ptr; /* [i->o] unused internally */ | ||
| 569 | unsigned char status; /* [o] scsi status */ | ||
| 570 | unsigned char masked_status; /* [o] shifted, masked scsi status */ | ||
| 571 | unsigned char msg_status; /* [o] messaging level data (optional) */ | ||
| 572 | unsigned char sb_len_wr; /* [o] byte count actually written to sbp */ | ||
| 573 | unsigned short host_status; /* [o] errors from host adapter */ | ||
| 574 | unsigned short driver_status; /* [o] errors from software driver */ | ||
| 575 | compat_int_t resid; /* [o] dxfer_len - actual_transferred */ | ||
| 576 | compat_uint_t duration; /* [o] time taken by cmd (unit: millisec) */ | ||
| 577 | compat_uint_t info; /* [o] auxiliary information */ | ||
| 578 | }; | ||
| 579 | #endif | ||
| 580 | |||
| 581 | int put_sg_io_hdr(const struct sg_io_hdr *hdr, void __user *argp) | ||
| 582 | { | ||
| 583 | #ifdef CONFIG_COMPAT | ||
| 584 | if (in_compat_syscall()) { | ||
| 585 | struct compat_sg_io_hdr hdr32 = { | ||
| 586 | .interface_id = hdr->interface_id, | ||
| 587 | .dxfer_direction = hdr->dxfer_direction, | ||
| 588 | .cmd_len = hdr->cmd_len, | ||
| 589 | .mx_sb_len = hdr->mx_sb_len, | ||
| 590 | .iovec_count = hdr->iovec_count, | ||
| 591 | .dxfer_len = hdr->dxfer_len, | ||
| 592 | .dxferp = (uintptr_t)hdr->dxferp, | ||
| 593 | .cmdp = (uintptr_t)hdr->cmdp, | ||
| 594 | .sbp = (uintptr_t)hdr->sbp, | ||
| 595 | .timeout = hdr->timeout, | ||
| 596 | .flags = hdr->flags, | ||
| 597 | .pack_id = hdr->pack_id, | ||
| 598 | .usr_ptr = (uintptr_t)hdr->usr_ptr, | ||
| 599 | .status = hdr->status, | ||
| 600 | .masked_status = hdr->masked_status, | ||
| 601 | .msg_status = hdr->msg_status, | ||
| 602 | .sb_len_wr = hdr->sb_len_wr, | ||
| 603 | .host_status = hdr->host_status, | ||
| 604 | .driver_status = hdr->driver_status, | ||
| 605 | .resid = hdr->resid, | ||
| 606 | .duration = hdr->duration, | ||
| 607 | .info = hdr->info, | ||
| 608 | }; | ||
| 609 | |||
| 610 | if (copy_to_user(argp, &hdr32, sizeof(hdr32))) | ||
| 611 | return -EFAULT; | ||
| 612 | |||
| 613 | return 0; | ||
| 614 | } | ||
| 615 | #endif | ||
| 616 | |||
| 617 | if (copy_to_user(argp, hdr, sizeof(*hdr))) | ||
| 618 | return -EFAULT; | ||
| 619 | |||
| 620 | return 0; | ||
| 621 | } | ||
| 622 | EXPORT_SYMBOL(put_sg_io_hdr); | ||
| 623 | |||
| 624 | int get_sg_io_hdr(struct sg_io_hdr *hdr, const void __user *argp) | ||
| 625 | { | ||
| 626 | #ifdef CONFIG_COMPAT | ||
| 627 | struct compat_sg_io_hdr hdr32; | ||
| 628 | |||
| 629 | if (in_compat_syscall()) { | ||
| 630 | if (copy_from_user(&hdr32, argp, sizeof(hdr32))) | ||
| 631 | return -EFAULT; | ||
| 632 | |||
| 633 | *hdr = (struct sg_io_hdr) { | ||
| 634 | .interface_id = hdr32.interface_id, | ||
| 635 | .dxfer_direction = hdr32.dxfer_direction, | ||
| 636 | .cmd_len = hdr32.cmd_len, | ||
| 637 | .mx_sb_len = hdr32.mx_sb_len, | ||
| 638 | .iovec_count = hdr32.iovec_count, | ||
| 639 | .dxfer_len = hdr32.dxfer_len, | ||
| 640 | .dxferp = compat_ptr(hdr32.dxferp), | ||
| 641 | .cmdp = compat_ptr(hdr32.cmdp), | ||
| 642 | .sbp = compat_ptr(hdr32.sbp), | ||
| 643 | .timeout = hdr32.timeout, | ||
| 644 | .flags = hdr32.flags, | ||
| 645 | .pack_id = hdr32.pack_id, | ||
| 646 | .usr_ptr = compat_ptr(hdr32.usr_ptr), | ||
| 647 | .status = hdr32.status, | ||
| 648 | .masked_status = hdr32.masked_status, | ||
| 649 | .msg_status = hdr32.msg_status, | ||
| 650 | .sb_len_wr = hdr32.sb_len_wr, | ||
| 651 | .host_status = hdr32.host_status, | ||
| 652 | .driver_status = hdr32.driver_status, | ||
| 653 | .resid = hdr32.resid, | ||
| 654 | .duration = hdr32.duration, | ||
| 655 | .info = hdr32.info, | ||
| 656 | }; | ||
| 657 | |||
| 658 | return 0; | ||
| 659 | } | ||
| 660 | #endif | ||
| 661 | |||
| 662 | if (copy_from_user(hdr, argp, sizeof(*hdr))) | ||
| 663 | return -EFAULT; | ||
| 664 | |||
| 665 | return 0; | ||
| 666 | } | ||
| 667 | EXPORT_SYMBOL(get_sg_io_hdr); | ||
| 668 | |||
| 545 | int scsi_cmd_ioctl(struct request_queue *q, struct gendisk *bd_disk, fmode_t mode, | 669 | int scsi_cmd_ioctl(struct request_queue *q, struct gendisk *bd_disk, fmode_t mode, |
| 546 | unsigned int cmd, void __user *arg) | 670 | unsigned int cmd, void __user *arg) |
| 547 | { | 671 | { |
| @@ -581,14 +705,14 @@ int scsi_cmd_ioctl(struct request_queue *q, struct gendisk *bd_disk, fmode_t mod · 33 unmodified lines | |||
| 581 | case SG_IO: { | 705 | case SG_IO: { |
| 582 | struct sg_io_hdr hdr; | 706 | struct sg_io_hdr hdr; |
| 583 | 707 | ||
| 584 | err = -EFAULT; | 708 | err = get_sg_io_hdr(&hdr, arg); |
| 585 | if (copy_from_user(&hdr, arg, sizeof(hdr))) | 709 | if (err) |
| 586 | break; | 710 | break; |
| 587 | err = sg_io(q, bd_disk, &hdr, mode); | 711 | err = sg_io(q, bd_disk, &hdr, mode); |
| 588 | if (err == -EFAULT) | 712 | if (err == -EFAULT) |
| 589 | break; | 713 | break; |
| 590 | 714 | ||
| 591 | if (copy_to_user(arg, &hdr, sizeof(hdr))) | 715 | if (put_sg_io_hdr(&hdr, arg)) |
| 592 | err = -EFAULT; | 716 | err = -EFAULT; |
| 593 | break; | 717 | break; |
| 594 | } | 718 | } |
| @@ -447,8 +447,7 @@ sg_read(struct file *filp, char __user *buf, size_t count, loff_t * ppos) · 446 unmodified lines | |||
| 447 | retval = -ENOMEM; | 447 | retval = -ENOMEM; |
| 448 | goto free_old_hdr; | 448 | goto free_old_hdr; |
| 449 | } | 449 | } |
| 450 | retval =__copy_from_user | 450 | retval = get_sg_io_hdr(new_hdr, buf); |
| 451 | (new_hdr, buf, SZ_SG_IO_HDR); | ||
| 452 | req_pack_id = new_hdr->pack_id; | 451 | req_pack_id = new_hdr->pack_id; |
| 453 | kfree(new_hdr); | 452 | kfree(new_hdr); |
| 454 | if (retval) { | 453 | if (retval) { |
| @@ -589,10 +588,7 @@ sg_new_read(Sg_fd * sfp, char __user *buf, size_t count, Sg_request * srp) · 134 unmodified lines | |||
| 589 | } | 588 | } |
| 590 | if (hp->masked_status || hp->host_status || hp->driver_status) | 589 | if (hp->masked_status || hp->host_status || hp->driver_status) |
| 591 | hp->info |= SG_INFO_CHECK; | 590 | hp->info |= SG_INFO_CHECK; |
| 592 | if (copy_to_user(buf, hp, SZ_SG_IO_HDR)) { | 591 | err = put_sg_io_hdr(hp, buf); |
| 593 | err = -EFAULT; | ||
| 594 | goto err_out; | ||
| 595 | } | ||
| 596 | err_out: | 592 | err_out: |
| 597 | err2 = sg_finish_rem_req(srp); | 593 | err2 = sg_finish_rem_req(srp); |
| 598 | sg_remove_request(sfp, srp); | 594 | sg_remove_request(sfp, srp); |
| @@ -735,7 +731,7 @@ sg_new_write(Sg_fd *sfp, struct file *file, const char __user *buf, · 136 unmodified lines | |||
| 735 | } | 731 | } |
| 736 | srp->sg_io_owned = sg_io_owned; | 732 | srp->sg_io_owned = sg_io_owned; |
| 737 | hp = &srp->header; | 733 | hp = &srp->header; |
| 738 | if (__copy_from_user(hp, buf, SZ_SG_IO_HDR)) { | 734 | if (get_sg_io_hdr(hp, buf)) { |
| 739 | sg_remove_request(sfp, srp); | 735 | sg_remove_request(sfp, srp); |
| 740 | return -EFAULT; | 736 | return -EFAULT; |
| 741 | } | 737 | } |
| @@ -1797,7 +1793,14 @@ sg_start_req(Sg_request *srp, unsigned char *cmd) · 1055 unmodified lines | |||
| 1797 | struct iovec *iov = NULL; | 1793 | struct iovec *iov = NULL; |
| 1798 | struct iov_iter i; | 1794 | struct iov_iter i; |
| 1799 | 1795 | ||
| 1800 | res = import_iovec(rw, hp->dxferp, iov_count, 0, &iov, &i); | 1796 | #ifdef CONFIG_COMPAT |
| 1797 | if (in_compat_syscall()) | ||
| 1798 | res = compat_import_iovec(rw, hp->dxferp, iov_count, | ||
| 1799 | 0, &iov, &i); | ||
| 1800 | else | ||
| 1801 | #endif | ||
| 1802 | res = import_iovec(rw, hp->dxferp, iov_count, | ||
| 1803 | 0, &iov, &i); | ||
| 1801 | if (res < 0) | 1804 | if (res < 0) |
| 1802 | return res; | 1805 | return res; |
| 1803 | 1806 | ||
| @@ -64,151 +64,6 @@ static int do_ioctl(struct file *file, unsigned int cmd, unsigned long arg) · 63 unmodified lines | |||
| 64 | } | 64 | } |
| 65 | 65 | ||
| 66 | #ifdef CONFIG_BLOCK | 66 | #ifdef CONFIG_BLOCK |
| 67 | typedef struct sg_io_hdr32 { | ||
| 68 | compat_int_t interface_id; /* [i] 'S' for SCSI generic (required) */ | ||
| 69 | compat_int_t dxfer_direction; /* [i] data transfer direction */ | ||
| 70 | unsigned char cmd_len; /* [i] SCSI command length ( <= 16 bytes) */ | ||
| 71 | unsigned char mx_sb_len; /* [i] max length to write to sbp */ | ||
| 72 | unsigned short iovec_count; /* [i] 0 implies no scatter gather */ | ||
| 73 | compat_uint_t dxfer_len; /* [i] byte count of data transfer */ | ||
| 74 | compat_uint_t dxferp; /* [i], [*io] points to data transfer memory | ||
| 75 | or scatter gather list */ | ||
| 76 | compat_uptr_t cmdp; /* [i], [*i] points to command to perform */ | ||
| 77 | compat_uptr_t sbp; /* [i], [*o] points to sense_buffer memory */ | ||
| 78 | compat_uint_t timeout; /* [i] MAX_UINT->no timeout (unit: millisec) */ | ||
| 79 | compat_uint_t flags; /* [i] 0 -> default, see SG_FLAG... */ | ||
| 80 | compat_int_t pack_id; /* [i->o] unused internally (normally) */ | ||
| 81 | compat_uptr_t usr_ptr; /* [i->o] unused internally */ | ||
| 82 | unsigned char status; /* [o] scsi status */ | ||
| 83 | unsigned char masked_status; /* [o] shifted, masked scsi status */ | ||
| 84 | unsigned char msg_status; /* [o] messaging level data (optional) */ | ||
| 85 | unsigned char sb_len_wr; /* [o] byte count actually written to sbp */ | ||
| 86 | unsigned short host_status; /* [o] errors from host adapter */ | ||
| 87 | unsigned short driver_status; /* [o] errors from software driver */ | ||
| 88 | compat_int_t resid; /* [o] dxfer_len - actual_transferred */ | ||
| 89 | compat_uint_t duration; /* [o] time taken by cmd (unit: millisec) */ | ||
| 90 | compat_uint_t info; /* [o] auxiliary information */ | ||
| 91 | } sg_io_hdr32_t; /* 64 bytes long (on sparc32) */ | ||
| 92 | |||
| 93 | typedef struct sg_iovec32 { | ||
| 94 | compat_uint_t iov_base; | ||
| 95 | compat_uint_t iov_len; | ||
| 96 | } sg_iovec32_t; | ||
| 97 | |||
| 98 | static int sg_build_iovec(sg_io_hdr_t __user *sgio, void __user *dxferp, u16 iovec_count) | ||
| 99 | { | ||
| 100 | sg_iovec_t __user *iov = (sg_iovec_t __user *) (sgio + 1); | ||
| 101 | sg_iovec32_t __user *iov32 = dxferp; | ||
| 102 | int i; | ||
| 103 | |||
| 104 | for (i = 0; i < iovec_count; i++) { | ||
| 105 | u32 base, len; | ||
| 106 | |||
| 107 | if (get_user(base, &iov32[i].iov_base) || | ||
| 108 | get_user(len, &iov32[i].iov_len) || | ||
| 109 | put_user(compat_ptr(base), &iov[i].iov_base) || | ||
| 110 | put_user(len, &iov[i].iov_len)) | ||
| 111 | return -EFAULT; | ||
| 112 | } | ||
| 113 | |||
| 114 | if (put_user(iov, &sgio->dxferp)) | ||
| 115 | return -EFAULT; | ||
| 116 | return 0; | ||
| 117 | } | ||
| 118 | |||
| 119 | static int sg_ioctl_trans(struct file *file, unsigned int cmd, | ||
| 120 | sg_io_hdr32_t __user *sgio32) | ||
| 121 | { | ||
| 122 | sg_io_hdr_t __user *sgio; | ||
| 123 | u16 iovec_count; | ||
| 124 | u32 data; | ||
| 125 | void __user *dxferp; | ||
| 126 | int err; | ||
| 127 | int interface_id; | ||
| 128 | |||
| 129 | if (get_user(interface_id, &sgio32->interface_id)) | ||
| 130 | return -EFAULT; | ||
| 131 | if (interface_id != 'S') | ||
| 132 | return do_ioctl(file, cmd, (unsigned long)sgio32); | ||
| 133 | |||
| 134 | if (get_user(iovec_count, &sgio32->iovec_count)) | ||
| 135 | return -EFAULT; | ||
| 136 | |||
| 137 | { | ||
| 138 | void __user *top = compat_alloc_user_space(0); | ||
| 139 | void __user *new = compat_alloc_user_space(sizeof(sg_io_hdr_t) + | ||
| 140 | (iovec_count * sizeof(sg_iovec_t))); | ||
| 141 | if (new > top) | ||
| 142 | return -EINVAL; | ||
| 143 | |||
| 144 | sgio = new; | ||
| 145 | } | ||
| 146 | |||
| 147 | /* Ok, now construct. */ | ||
| 148 | if (copy_in_user(&sgio->interface_id, &sgio32->interface_id, | ||
| 149 | (2 * sizeof(int)) + | ||
| 150 | (2 * sizeof(unsigned char)) + | ||
| 151 | (1 * sizeof(unsigned short)) + | ||
| 152 | (1 * sizeof(unsigned int)))) | ||
| 153 | return -EFAULT; | ||
| 154 | |||
| 155 | if (get_user(data, &sgio32->dxferp)) | ||
| 156 | return -EFAULT; | ||
| 157 | dxferp = compat_ptr(data); | ||
| 158 | if (iovec_count) { | ||
| 159 | if (sg_build_iovec(sgio, dxferp, iovec_count)) | ||
| 160 | return -EFAULT; | ||
| 161 | } else { | ||
| 162 | if (put_user(dxferp, &sgio->dxferp)) | ||
| 163 | return -EFAULT; | ||
| 164 | } | ||
| 165 | |||
| 166 | { | ||
| 167 | unsigned char __user *cmdp; | ||
| 168 | unsigned char __user *sbp; | ||
| 169 | |||
| 170 | if (get_user(data, &sgio32->cmdp)) | ||
| 171 | return -EFAULT; | ||
| 172 | cmdp = compat_ptr(data); | ||
| 173 | |||
| 174 | if (get_user(data, &sgio32->sbp)) | ||
| 175 | return -EFAULT; | ||
| 176 | sbp = compat_ptr(data); | ||
| 177 | |||
| 178 | if (put_user(cmdp, &sgio->cmdp) || | ||
| 179 | put_user(sbp, &sgio->sbp)) | ||
| 180 | return -EFAULT; | ||
| 181 | } | ||
| 182 | |||
| 183 | if (copy_in_user(&sgio->timeout, &sgio32->timeout, | ||
| 184 | 3 * sizeof(int))) | ||
| 185 | return -EFAULT; | ||
| 186 | |||
| 187 | if (get_user(data, &sgio32->usr_ptr)) | ||
| 188 | return -EFAULT; | ||
| 189 | if (put_user(compat_ptr(data), &sgio->usr_ptr)) | ||
| 190 | return -EFAULT; | ||
| 191 | |||
| 192 | err = do_ioctl(file, cmd, (unsigned long) sgio); | ||
| 193 | |||
| 194 | if (err >= 0) { | ||
| 195 | void __user *datap; | ||
| 196 | |||
| 197 | if (copy_in_user(&sgio32->pack_id, &sgio->pack_id, | ||
| 198 | sizeof(int)) || | ||
| 199 | get_user(datap, &sgio->usr_ptr) || | ||
| 200 | put_user((u32)(unsigned long)datap, | ||
| 201 | &sgio32->usr_ptr) || | ||
| 202 | copy_in_user(&sgio32->status, &sgio->status, | ||
| 203 | (4 * sizeof(unsigned char)) + | ||
| 204 | (2 * sizeof(unsigned short)) + | ||
| 205 | (3 * sizeof(int)))) | ||
| 206 | err = -EFAULT; | ||
| 207 | } | ||
| 208 | |||
| 209 | return err; | ||
| 210 | } | ||
| 211 | |||
| 212 | struct compat_sg_req_info { /* used by SG_GET_REQUEST_TABLE ioctl() */ | 67 | struct compat_sg_req_info { /* used by SG_GET_REQUEST_TABLE ioctl() */ |
| 213 | char req_state; | 68 | char req_state; |
| 214 | char orphan; | 69 | char orphan; |
| @@ -358,6 +213,7 @@ COMPATIBLE_IOCTL(SCSI_IOCTL_GET_PCI) · 143 unmodified lines | |||
| 358 | #endif | 213 | #endif |
| 359 | #ifdef CONFIG_BLOCK | 214 | #ifdef CONFIG_BLOCK |
| 360 | /* SG stuff */ | 215 | /* SG stuff */ |
| 216 | COMPATIBLE_IOCTL(SG_IO) | ||
| 361 | COMPATIBLE_IOCTL(SG_SET_TIMEOUT) | 217 | COMPATIBLE_IOCTL(SG_SET_TIMEOUT) |
| 362 | COMPATIBLE_IOCTL(SG_GET_TIMEOUT) | 218 | COMPATIBLE_IOCTL(SG_GET_TIMEOUT) |
| 363 | COMPATIBLE_IOCTL(SG_EMULATED_HOST) | 219 | COMPATIBLE_IOCTL(SG_EMULATED_HOST) |
| @@ -435,8 +291,6 @@ static long do_ioctl_trans(unsigned int cmd, · 71 unmodified lines | |||
| 435 | case PPPIOCSACTIVE32: | 291 | case PPPIOCSACTIVE32: |
| 436 | return ppp_sock_fprog_ioctl_trans(file, cmd, argp); | 292 | return ppp_sock_fprog_ioctl_trans(file, cmd, argp); |
| 437 | #ifdef CONFIG_BLOCK | 293 | #ifdef CONFIG_BLOCK |
| 438 | case SG_IO: | ||
| 439 | return sg_ioctl_trans(file, cmd, argp); | ||
| 440 | case SG_GET_REQUEST_TABLE: | 294 | case SG_GET_REQUEST_TABLE: |
| 441 | return sg_grt_trans(file, cmd, argp); | 295 | return sg_grt_trans(file, cmd, argp); |
| 442 | #endif | 296 | #endif |
| @@ -870,6 +870,8 @@ extern int scsi_cmd_ioctl(struct request_queue *, struct gendisk *, fmode_t, · 869 unmodified lines | |||
| 870 | unsigned int, void __user *); | 870 | unsigned int, void __user *); |
| 871 | extern int sg_scsi_ioctl(struct request_queue *, struct gendisk *, fmode_t, | 871 | extern int sg_scsi_ioctl(struct request_queue *, struct gendisk *, fmode_t, |
| 872 | struct scsi_ioctl_command __user *); | 872 | struct scsi_ioctl_command __user *); |
| 873 | extern int get_sg_io_hdr(struct sg_io_hdr *hdr, const void __user *argp); | ||
| 874 | extern int put_sg_io_hdr(const struct sg_io_hdr *hdr, void __user *argp); | ||
| 873 | 875 | ||
| 874 | extern int blk_queue_enter(struct request_queue *q, blk_mq_req_flags_t flags); | 876 | extern int blk_queue_enter(struct request_queue *q, blk_mq_req_flags_t flags); |
| 875 | extern void blk_queue_exit(struct request_queue *q); | 877 | extern void blk_queue_exit(struct request_queue *q); |
| @@ -1678,6 +1678,7 @@ ssize_t compat_import_iovec(int type, · 1677 unmodified lines | |||
| 1678 | *iov = p == *iov ? NULL : p; | 1678 | *iov = p == *iov ? NULL : p; |
| 1679 | return n; | 1679 | return n; |
| 1680 | } | 1680 | } |
| 1681 | EXPORT_SYMBOL(compat_import_iovec); | ||
| 1681 | #endif | 1682 | #endif |
| 1682 | 1683 | ||
| 1683 | int import_single_range(int rw, void __user *buf, size_t len, | 1684 | int import_single_range(int rw, void __user *buf, size_t len, |