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 | 3 | * Copyright (C) 2001 Jens Axboe <axboe@suse.de> |
| 4 | 4 | */ |
| 5 | +#include <linux/compat.h> | |
| 5 | 6 | #include <linux/kernel.h> |
| 6 | 7 | #include <linux/errno.h> |
| 7 | 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 | 328 | struct iov_iter i; |
| 328 | 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 | 339 | hdr->dxferp, hdr->iovec_count, |
| 332 | 340 | 0, &iov, &i); |
| 333 | 341 | if (ret < 0) |
| @@ -542,6 +550,122 @@ static inline int blk_send_start_stop(struct request_queue *q, · 208 unmodified lines | ||
| 542 | 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 | 669 | int scsi_cmd_ioctl(struct request_queue *q, struct gendisk *bd_disk, fmode_t mode, |
| 546 | 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 | 705 | case SG_IO: { |
| 582 | 706 | struct sg_io_hdr hdr; |
| 583 | 707 | |
| 584 | − err = -EFAULT; | |
| 585 | − if (copy_from_user(&hdr, arg, sizeof(hdr))) | |
| 708 | + err = get_sg_io_hdr(&hdr, arg); | |
| 709 | + if (err) | |
| 586 | 710 | break; |
| 587 | 711 | err = sg_io(q, bd_disk, &hdr, mode); |
| 588 | 712 | if (err == -EFAULT) |
| 589 | 713 | break; |
| 590 | 714 | |
| 591 | − if (copy_to_user(arg, &hdr, sizeof(hdr))) | |
| 715 | + if (put_sg_io_hdr(&hdr, arg)) | |
| 592 | 716 | err = -EFAULT; |
| 593 | 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 | 447 | retval = -ENOMEM; |
| 448 | 448 | goto free_old_hdr; |
| 449 | 449 | } |
| 450 | − retval =__copy_from_user | |
| 451 | − (new_hdr, buf, SZ_SG_IO_HDR); | |
| 450 | + retval = get_sg_io_hdr(new_hdr, buf); | |
| 452 | 451 | req_pack_id = new_hdr->pack_id; |
| 453 | 452 | kfree(new_hdr); |
| 454 | 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 | 589 | if (hp->masked_status || hp->host_status || hp->driver_status) |
| 591 | 590 | hp->info |= SG_INFO_CHECK; |
| 592 | − if (copy_to_user(buf, hp, SZ_SG_IO_HDR)) { | |
| 593 | − err = -EFAULT; | |
| 594 | − goto err_out; | |
| 595 | − } | |
| 591 | + err = put_sg_io_hdr(hp, buf); | |
| 596 | 592 | err_out: |
| 597 | 593 | err2 = sg_finish_rem_req(srp); |
| 598 | 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 | 732 | srp->sg_io_owned = sg_io_owned; |
| 737 | 733 | hp = &srp->header; |
| 738 | − if (__copy_from_user(hp, buf, SZ_SG_IO_HDR)) { | |
| 734 | + if (get_sg_io_hdr(hp, buf)) { | |
| 739 | 735 | sg_remove_request(sfp, srp); |
| 740 | 736 | return -EFAULT; |
| 741 | 737 | } |
| @@ -1797,7 +1793,14 @@ sg_start_req(Sg_request *srp, unsigned char *cmd) · 1055 unmodified lines | ||
| 1797 | 1793 | struct iovec *iov = NULL; |
| 1798 | 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 | 1804 | if (res < 0) |
| 1802 | 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 | 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 | 67 | struct compat_sg_req_info { /* used by SG_GET_REQUEST_TABLE ioctl() */ |
| 213 | 68 | char req_state; |
| 214 | 69 | char orphan; |
| @@ -358,6 +213,7 @@ COMPATIBLE_IOCTL(SCSI_IOCTL_GET_PCI) · 143 unmodified lines | ||
| 358 | 213 | #endif |
| 359 | 214 | #ifdef CONFIG_BLOCK |
| 360 | 215 | /* SG stuff */ |
| 216 | +COMPATIBLE_IOCTL(SG_IO) | |
| 361 | 217 | COMPATIBLE_IOCTL(SG_SET_TIMEOUT) |
| 362 | 218 | COMPATIBLE_IOCTL(SG_GET_TIMEOUT) |
| 363 | 219 | COMPATIBLE_IOCTL(SG_EMULATED_HOST) |
| @@ -435,8 +291,6 @@ static long do_ioctl_trans(unsigned int cmd, · 71 unmodified lines | ||
| 435 | 291 | case PPPIOCSACTIVE32: |
| 436 | 292 | return ppp_sock_fprog_ioctl_trans(file, cmd, argp); |
| 437 | 293 | #ifdef CONFIG_BLOCK |
| 438 | − case SG_IO: | |
| 439 | − return sg_ioctl_trans(file, cmd, argp); | |
| 440 | 294 | case SG_GET_REQUEST_TABLE: |
| 441 | 295 | return sg_grt_trans(file, cmd, argp); |
| 442 | 296 | #endif |
| @@ -870,6 +870,8 @@ extern int scsi_cmd_ioctl(struct request_queue *, struct gendisk *, fmode_t, · 869 unmodified lines | ||
| 870 | 870 | unsigned int, void __user *); |
| 871 | 871 | extern int sg_scsi_ioctl(struct request_queue *, struct gendisk *, fmode_t, |
| 872 | 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 | 876 | extern int blk_queue_enter(struct request_queue *q, blk_mq_req_flags_t flags); |
| 875 | 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 | 1678 | *iov = p == *iov ? NULL : p; |
| 1679 | 1679 | return n; |
| 1680 | 1680 | } |
| 1681 | +EXPORT_SYMBOL(compat_import_iovec); | |
| 1681 | 1682 | #endif |
| 1682 | 1683 | |
| 1683 | 1684 | int import_single_range(int rw, void __user *buf, size_t len, |