home *** CD-ROM | disk | FTP | other *** search
/ ftp.parl.clemson.edu / 2015-02-07.ftp.parl.clemson.edu.tar / ftp.parl.clemson.edu / pub / pvfs2 / orangefs-2.8.3-20110323.tar.gz / orangefs-2.8.3-20110323.tar / orangefs / patches / posix-ext / posix-readwritex.patch < prev    next >
Text File  |  2008-01-07  |  29KB  |  899 lines

  1. diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/arch/i386/kernel/syscall_table.S vanilla-new/arch/i386/kernel/syscall_table.S
  2. --- vanilla/arch/i386/kernel/syscall_table.S    2006-05-24 16:19:07.000000000 -0500
  3. +++ vanilla-new/arch/i386/kernel/syscall_table.S    2006-05-24 16:31:20.000000000 -0500
  4. @@ -320,3 +320,5 @@
  5.      .long sys_fstatlite64
  6.      .long sys_getdents_plus
  7.      .long sys_getdents64_plus /* 320 */
  8. +    .long sys_readx
  9. +    .long sys_writex
  10. diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/arch/ia64/kernel/entry.S vanilla-new/arch/ia64/kernel/entry.S
  11. --- vanilla/arch/ia64/kernel/entry.S    2006-05-24 16:19:07.000000000 -0500
  12. +++ vanilla-new/arch/ia64/kernel/entry.S    2006-05-24 16:32:28.000000000 -0500
  13. @@ -1626,5 +1626,7 @@
  14.      data8 sys_newfstatlite
  15.      data8 sys_getdents_plus
  16.      data8 sys_getdents64_plus
  17. +    data8 sys_readx
  18. +    data8 sys_writex
  19.  
  20.      .org sys_call_table + 8*NR_syscalls    // guard against failures to increase NR_syscalls
  21. diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/arch/powerpc/kernel/systbl.S vanilla-new/arch/powerpc/kernel/systbl.S
  22. --- vanilla/arch/powerpc/kernel/systbl.S    2006-05-24 16:19:07.000000000 -0500
  23. +++ vanilla-new/arch/powerpc/kernel/systbl.S    2006-05-24 16:34:44.000000000 -0500
  24. @@ -329,3 +329,5 @@
  25.  SYSCALL(newfstatlite)
  26.  SYSCALL(sys_getdents_plus)
  27.  SYSCALL(sys_getdents64_plus)
  28. +SYSCALL(sys_readx)
  29. +SYSCALL(sys_writex)
  30. diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/arch/x86_64/ia32/ia32entry.S vanilla-new/arch/x86_64/ia32/ia32entry.S
  31. --- vanilla/arch/x86_64/ia32/ia32entry.S    2006-05-24 16:19:07.000000000 -0500
  32. +++ vanilla-new/arch/x86_64/ia32/ia32entry.S    2006-05-24 16:32:01.000000000 -0500
  33. @@ -698,6 +698,8 @@
  34.      .quad sys32_fstatlite64
  35.      .quad sys_ni_syscall   /* getdents_plus */
  36.      .quad sys_ni_syscall   /* getdents64_plus */
  37. +    .quad compat_sys_readx 
  38. +    .quad compat_sys_writex
  39.  ia32_syscall_end:        
  40.      .rept IA32_NR_syscalls-(ia32_syscall_end-ia32_sys_call_table)/8
  41.          .quad ni_syscall
  42. diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/fs/compat.c vanilla-new/fs/compat.c
  43. --- vanilla/fs/compat.c    2006-05-09 18:53:48.000000000 -0500
  44. +++ vanilla-new/fs/compat.c    2006-05-24 16:26:00.000000000 -0500
  45. @@ -1344,6 +1344,322 @@
  46.      return ret;
  47.  }
  48.  
  49. +static ssize_t compat_do_readx_writex(int type, struct file *file,
  50. +                   const struct compat_iovec __user * uvector,
  51. +                   unsigned long nr_segs, 
  52. +                     const struct compat_xtvec __user * xtuvector,
  53. +                     unsigned long xtnr_segs)
  54. +{
  55. +    typedef ssize_t (*io_fn_t)(struct file *, char __user *, size_t, loff_t *);
  56. +    typedef ssize_t (*iov_fn_t)(struct file *, const struct iovec *, unsigned long, loff_t *);
  57. +    typedef ssize_t (*iox_fn_t)(struct file *, const struct iovec *, unsigned long, 
  58. +            const struct xtvec *, unsigned long);
  59. +
  60. +    compat_ssize_t tot_len, tot_xtlen;
  61. +    struct iovec iovstack[UIO_FASTIOV];
  62. +    struct iovec *iov=iovstack;
  63. +    struct xtvec xtvstack[UIO_FASTIOV];
  64. +    struct xtvec *xtv=xtvstack;
  65. +    ssize_t ret;
  66. +    int seg;
  67. +    io_fn_t fn = NULL;
  68. +    iov_fn_t fnv = NULL;
  69. +    iox_fn_t fnx = NULL;
  70. +
  71. +    /*
  72. +     * readx does not make much sense if nr_segs <= 0 (OR) xtnr_segs <= 0
  73. +     * We return 0 similar to how readv/writev do.
  74. +     */
  75. +    ret = 0;
  76. +    if (nr_segs == 0 || xtnr_segs == 0)
  77. +        goto out;
  78. +
  79. +    /*
  80. +     * First get the "struct iovec" from user memory and
  81. +     * verify all the pointers
  82. +     */
  83. +    ret = -EINVAL;
  84. +    if ((nr_segs > UIO_MAXIOV) || (nr_segs <= 0))
  85. +        goto out;
  86. +    if ((xtnr_segs > UIO_MAXIOV) || (xtnr_segs <= 0))
  87. +        goto out;
  88. +    if (!file->f_op)
  89. +        goto out;
  90. +    if (nr_segs > UIO_FASTIOV) {
  91. +        ret = -ENOMEM;
  92. +        iov = kmalloc(nr_segs * sizeof(struct iovec), GFP_KERNEL);
  93. +        if (!iov)
  94. +            goto out;
  95. +    }
  96. +    if (xtnr_segs > UIO_FASTIOV) {
  97. +        ret = -ENOMEM;
  98. +        xtv = kmalloc(xtnr_segs * sizeof(struct xtvec), GFP_KERNEL);
  99. +        if (!xtv) {
  100. +            goto out;
  101. +        }
  102. +    }
  103. +    ret = -EFAULT;
  104. +    if (!access_ok(VERIFY_READ, uvector, nr_segs * sizeof(*uvector)))
  105. +        goto out;
  106. +    if (!access_ok(VERIFY_READ, xtuvector, xtnr_segs * sizeof(*xtuvector)))
  107. +        goto out;
  108. +
  109. +    /*
  110. +     * Single unix specification:
  111. +     * We should -EINVAL if an element length is not >= 0 and fitting an
  112. +     * ssize_t.  The total length is fitting an ssize_t
  113. +     *
  114. +     * Be careful here because iov_len is a size_t not an ssize_t
  115. +     */
  116. +    tot_len = 0;
  117. +    ret = -EINVAL;
  118. +    for (seg = 0; seg < nr_segs; seg++) {
  119. +        compat_ssize_t tmp = tot_len, len;
  120. +        compat_uptr_t buf;
  121. +
  122. +        if (__get_user(len, &uvector->iov_len) ||
  123. +                __get_user(buf, &uvector->iov_base)) {
  124. +            ret = -EFAULT;
  125. +            goto out;
  126. +        }
  127. +        if (len < 0)    /* size_t not fitting an compat_ssize_t .. */
  128. +            goto out;
  129. +        tot_len += len;
  130. +        if (tot_len < tmp) /* maths overflow on the compat_ssize_t */
  131. +            goto out;
  132. +        iov[seg].iov_base = compat_ptr(buf);
  133. +        iov[seg].iov_len  = (compat_size_t) len;
  134. +        uvector++;
  135. +    }
  136. +    if (tot_len == 0) {
  137. +        ret = 0;
  138. +        goto out;
  139. +    }
  140. +    tot_xtlen = 0;
  141. +    ret = -EINVAL;
  142. +    for (seg = 0; seg < xtnr_segs; seg++) {
  143. +        compat_ssize_t tmp = tot_xtlen, len;
  144. +        compat_off_t off;
  145. +        loff_t foff;
  146. +
  147. +        if (__get_user(off, &xtuvector->xtv_off) ||
  148. +                __get_user(len, &xtuvector->xtv_len)) {
  149. +            ret = -EFAULT;
  150. +            goto out;
  151. +        }
  152. +        if (len < 0)    /* size_t not fitting an compat_ssize_t .. */
  153. +            goto out;
  154. +        if (off < 0)   /* off_t not fitting an loff_t */
  155. +            goto out;
  156. +        tot_xtlen += len;
  157. +        if (tot_xtlen < tmp) /* overflow on the compat_ssize_t */
  158. +            goto out;
  159. +        foff = (loff_t) off;
  160. +        ret = rw_verify_area(type, file, &foff, len);
  161. +        if (ret < 0)
  162. +            goto out;
  163. +        xtv[seg].xtv_off = (compat_off_t) off;
  164. +        xtv[seg].xtv_len = (compat_size_t) len;
  165. +        xtuvector++;
  166. +    }
  167. +    /* if sizes of file and mem don't match up, error out */
  168. +    if (tot_xtlen != tot_len) {
  169. +        ret = -EINVAL;
  170. +        goto out;
  171. +    }
  172. +
  173. +    if (type == READ) {
  174. +        fn = (io_fn_t)file->f_op->read;
  175. +        fnv = (iov_fn_t)file->f_op->readv;
  176. +        fnx = (iox_fn_t)file->f_op->readx;
  177. +    } else {
  178. +        fn = (io_fn_t)file->f_op->write;
  179. +        fnv = (iov_fn_t)file->f_op->writev;
  180. +        fnx = (iox_fn_t)file->f_op->writex;
  181. +    }
  182. +    /* if we had a scatter-gather callback in memory and file, go for it */
  183. +    if (fnx) {
  184. +        ret = fnx(file, iov, nr_segs, xtv, xtnr_segs);
  185. +        goto out;
  186. +    }
  187. +    /* else try to do it by hand using readv/writev operations */
  188. +    else if (fnv) {
  189. +        unsigned long xtiov_index = 0, op_iov_index = 0, iov_index = 0;
  190. +        struct iovec *op_iov = NULL, *copied_iovector = NULL;
  191. +        struct xtvec *copied_xtvector = NULL;
  192. +
  193. +        ret = -ENOMEM;
  194. +        op_iov = (struct iovec *) kmalloc(nr_segs * sizeof(struct iovec), GFP_KERNEL);
  195. +        if (!op_iov) 
  196. +            goto err_out1;
  197. +        copied_iovector = (struct iovec *) kmalloc(nr_segs * sizeof(struct iovec), GFP_KERNEL);
  198. +        if (!copied_iovector) 
  199. +            goto err_out1;
  200. +        copied_xtvector = (struct xtvec *) kmalloc(xtnr_segs * sizeof(struct xtvec), GFP_KERNEL);
  201. +        if (!copied_xtvector)
  202. +            goto err_out1;
  203. +        memcpy(copied_iovector, iov, nr_segs * sizeof(struct iovec));
  204. +        memcpy(copied_xtvector, xtv, xtnr_segs * sizeof(struct xtvec));
  205. +        ret = 0;
  206. +        iov_index = 0;
  207. +        for (xtiov_index = 0; xtiov_index < xtnr_segs; xtiov_index++) {
  208. +            loff_t pos;
  209. +            ssize_t nr, tot_nr;
  210. +
  211. +            pos = copied_xtvector[xtiov_index].xtv_off;
  212. +            op_iov_index = 0;
  213. +            tot_nr = 0;
  214. +            
  215. +            /* Finish an entire stream and .. */
  216. +            while (copied_xtvector[xtiov_index].xtv_len > 0) {
  217. +                size_t min_len;
  218. +                if (unlikely((iov_index >= nr_segs) || (op_iov_index >= nr_segs))) {
  219. +                    printk(KERN_ERR "iov_index %ld or op_iov_index %ld cannot exceed number of iov segments (%ld)\n",
  220. +                            iov_index, op_iov_index, nr_segs);
  221. +                    ret = -EINVAL;
  222. +                    goto err_out1;
  223. +                }
  224. +                min_len = min(copied_xtvector[xtiov_index].xtv_len, copied_iovector[iov_index].iov_len);
  225. +                op_iov[op_iov_index].iov_base = copied_iovector[iov_index].iov_base;
  226. +                op_iov[op_iov_index++].iov_len = min_len;
  227. +                copied_xtvector[xtiov_index].xtv_len -= min_len;
  228. +                copied_iovector[iov_index].iov_len -= min_len;
  229. +                copied_iovector[iov_index].iov_base += min_len;
  230. +                tot_nr += min_len;
  231. +                /* Advance memory stream if we have exhausted it */
  232. +                if (copied_iovector[iov_index].iov_len <= 0) {
  233. +                    iov_index++;
  234. +                }
  235. +            }
  236. +            /* .. issue a vectored operation for that region */
  237. +            nr = fnv(file, op_iov, op_iov_index, &pos);
  238. +            if (nr < 0) {
  239. +                if (!ret) ret = nr;
  240. +                break;
  241. +            }
  242. +            ret += nr;
  243. +            if (nr != tot_nr)
  244. +                break;
  245. +        }
  246. +err_out1:
  247. +        kfree(op_iov);
  248. +        kfree(copied_iovector);
  249. +        kfree(copied_xtvector);
  250. +        goto out;
  251. +    }
  252. +    /* Do it by hand, with plain read/write operations */
  253. +    else {
  254. +        unsigned long mem_ct = 0, str_ct = 0;
  255. +        struct xtvec *copied_xtvector = NULL;
  256. +        struct iovec *copied_iovector = NULL;
  257. +
  258. +        ret = -ENOMEM;
  259. +        copied_iovector = (struct iovec *) kmalloc(nr_segs * sizeof(struct iovec), GFP_KERNEL);
  260. +        if (!copied_iovector)
  261. +            goto err_out2;
  262. +        copied_xtvector = (struct xtvec *) kmalloc(xtnr_segs * sizeof(struct xtvec), GFP_KERNEL);
  263. +        if (!copied_xtvector)
  264. +            goto err_out2;
  265. +        memcpy(copied_iovector, iov, nr_segs * sizeof(struct iovec));
  266. +        memcpy(copied_xtvector, xtv, xtnr_segs * sizeof(struct xtvec));
  267. +
  268. +        ret = 0;
  269. +        mem_ct = 0;
  270. +        str_ct = 0;
  271. +        while ((mem_ct < nr_segs) && (str_ct < xtnr_segs)) {
  272. +            size_t min_len;
  273. +            loff_t pos;
  274. +            ssize_t nr;
  275. +            void __user *base;
  276. +
  277. +            pos = copied_xtvector[str_ct].xtv_off;
  278. +            base = copied_iovector[mem_ct].iov_base;
  279. +            min_len = min(copied_xtvector[str_ct].xtv_len, copied_iovector[mem_ct].iov_len);
  280. +            copied_xtvector[str_ct].xtv_len -= min_len;
  281. +            copied_xtvector[str_ct].xtv_off += min_len;
  282. +            copied_iovector[mem_ct].iov_len -= min_len;
  283. +            copied_iovector[mem_ct].iov_base += min_len;
  284. +            if (copied_iovector[mem_ct].iov_len <= 0)
  285. +                mem_ct++;
  286. +            if (copied_xtvector[str_ct].xtv_len <= 0)
  287. +                str_ct++;
  288. +            /* Issue the smallest region that is contiguous in memory and on file */
  289. +            nr = fn(file, base, min_len, &pos);
  290. +            if (nr < 0) {
  291. +                if (!ret) ret = nr;
  292. +                break;
  293. +            }
  294. +            ret += nr;
  295. +            if (nr != min_len)
  296. +                break;
  297. +        }
  298. +err_out2:
  299. +        kfree(copied_xtvector);
  300. +        kfree(copied_iovector);
  301. +    }
  302. +out:
  303. +    if (iov != iovstack)
  304. +        kfree(iov);
  305. +    if (xtv != xtvstack)
  306. +        kfree(xtv);
  307. +    if ((ret + (type == READ)) > 0) {
  308. +        if (type == READ)
  309. +            fsnotify_access(file->f_dentry);
  310. +        else
  311. +            fsnotify_modify(file->f_dentry);
  312. +    }
  313. +    return ret;
  314. +}
  315. +
  316. +asmlinkage ssize_t
  317. +compat_sys_readx(unsigned long fd, const struct compat_iovec __user *vec, unsigned long vlen,
  318. +        const struct compat_xtvec __user *xtv, unsigned long xtvlen)
  319. +{
  320. +    struct file *file;
  321. +    ssize_t ret = -EBADF;
  322. +
  323. +    file = fget(fd);
  324. +    if (!file)
  325. +        return -EBADF;
  326. +
  327. +    if (!(file->f_mode & FMODE_READ))
  328. +        goto out;
  329. +
  330. +    ret = -EINVAL;
  331. +    if (!file->f_op || (!file->f_op->readx && !file->f_op->readv && !file->f_op->read))
  332. +        goto out;
  333. +
  334. +    ret = compat_do_readx_writex(READ, file, vec, vlen, xtv, xtvlen);
  335. +
  336. +out:
  337. +    fput(file);
  338. +    return ret;
  339. +}
  340. +
  341. +asmlinkage ssize_t
  342. +compat_sys_writex(unsigned long fd, const struct compat_iovec __user *vec, unsigned long vlen,
  343. +        const struct compat_xtvec __user *xtv, unsigned long xtvlen)
  344. +{
  345. +    struct file *file;
  346. +    ssize_t ret = -EBADF;
  347. +
  348. +    file = fget(fd);
  349. +    if (!file)
  350. +        return -EBADF;
  351. +    if (!(file->f_mode & FMODE_WRITE))
  352. +        goto out;
  353. +
  354. +    ret = -EINVAL;
  355. +    if (!file->f_op || (!file->f_op->writex && !file->f_op->writev && !file->f_op->write))
  356. +        goto out;
  357. +
  358. +    ret = compat_do_readx_writex(WRITE, file, vec, vlen, xtv, xtvlen);
  359. +
  360. +out:
  361. +    fput(file);
  362. +    return ret;
  363. +}
  364. +
  365.  /*
  366.   * Exactly like fs/open.c:sys_open(), except that it doesn't set the
  367.   * O_LARGEFILE flag.
  368. diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/fs/read_write.c vanilla-new/fs/read_write.c
  369. --- vanilla/fs/read_write.c    2006-03-19 23:53:29.000000000 -0600
  370. +++ vanilla-new/fs/read_write.c    2006-05-24 16:22:20.000000000 -0500
  371. @@ -374,6 +374,8 @@
  372.      return ret;
  373.  }
  374.  
  375. +EXPORT_SYMBOL_GPL(sys_write);
  376. +
  377.  asmlinkage ssize_t sys_pread64(unsigned int fd, char __user *buf,
  378.                   size_t count, loff_t pos)
  379.  {
  380. @@ -636,6 +638,334 @@
  381.      return ret;
  382.  }
  383.  
  384. +static ssize_t do_readx_writex(int type, struct file *file,
  385. +                   const struct iovec __user * uvector,
  386. +                   unsigned long nr_segs, 
  387. +                     const struct xtvec __user * xtuvector,
  388. +                     unsigned long xtnr_segs)
  389. +{
  390. +    typedef ssize_t (*io_fn_t)(struct file *, char __user *, size_t, loff_t *);
  391. +    typedef ssize_t (*iov_fn_t)(struct file *, const struct iovec *, unsigned long, loff_t *);
  392. +    typedef ssize_t (*iox_fn_t)(struct file *, const struct iovec *, unsigned long, 
  393. +            const struct xtvec *, unsigned long);
  394. +
  395. +    size_t tot_len, tot_xtlen;
  396. +    struct iovec iovstack[UIO_FASTIOV];
  397. +    struct iovec *iov=iovstack;
  398. +    struct xtvec xtvstack[UIO_FASTIOV];
  399. +    struct xtvec *xtv=xtvstack;
  400. +    ssize_t ret;
  401. +    int seg;
  402. +    io_fn_t fn = NULL;
  403. +    iov_fn_t fnv = NULL;
  404. +    iox_fn_t fnx = NULL;
  405. +
  406. +    /*
  407. +     * readx does not make much sense if nr_segs <= 0 (OR) xtnr_segs <= 0
  408. +     * We return 0 similar to how readv/writev do.
  409. +     */
  410. +    ret = 0;
  411. +    if (nr_segs == 0 || xtnr_segs == 0)
  412. +        goto out;
  413. +
  414. +    /*
  415. +     * First get the "struct iovec" from user memory and
  416. +     * verify all the pointers
  417. +     */
  418. +    ret = -EINVAL;
  419. +    if ((nr_segs > UIO_MAXIOV) || (nr_segs <= 0))
  420. +        goto out;
  421. +    if ((xtnr_segs > UIO_MAXIOV) || (xtnr_segs <= 0))
  422. +        goto out;
  423. +    if (!file->f_op)
  424. +        goto out;
  425. +    if (nr_segs > UIO_FASTIOV) {
  426. +        ret = -ENOMEM;
  427. +        iov = kmalloc(nr_segs * sizeof(struct iovec), GFP_KERNEL);
  428. +        if (!iov)
  429. +            goto out;
  430. +    }
  431. +    if (xtnr_segs > UIO_FASTIOV) {
  432. +        ret = -ENOMEM;
  433. +        xtv = kmalloc(xtnr_segs * sizeof(struct xtvec), GFP_KERNEL);
  434. +        if (!xtv) {
  435. +            goto out;
  436. +        }
  437. +    }
  438. +    ret = -EFAULT;
  439. +    if (copy_from_user(iov, uvector, nr_segs * sizeof(*uvector)))
  440. +        goto out;
  441. +    if (copy_from_user(xtv, xtuvector, xtnr_segs * sizeof(*xtuvector)))
  442. +        goto out;
  443. +
  444. +    /*
  445. +     * Single unix specification:
  446. +     * We should -EINVAL if an element length is not >= 0 and fitting an
  447. +     * ssize_t.  The total length is fitting an ssize_t
  448. +     *
  449. +     * Be careful here because iov_len is a size_t not an ssize_t
  450. +     */
  451. +    tot_len = 0;
  452. +    ret = -EINVAL;
  453. +    for (seg = 0; seg < nr_segs; seg++) {
  454. +        void __user *buf = iov[seg].iov_base;
  455. +        ssize_t len = (ssize_t)iov[seg].iov_len;
  456. +
  457. +        if (len < 0)    /* size_t not fitting an ssize_t .. */
  458. +            goto out;
  459. +        if (unlikely(!access_ok(vrfy_dir(type), buf, len)))
  460. +            goto Efault;
  461. +        tot_len += len;
  462. +        if ((ssize_t)tot_len < 0) /* maths overflow on the ssize_t */
  463. +            goto out;
  464. +    }
  465. +    if (tot_len == 0) {
  466. +        ret = 0;
  467. +        goto out;
  468. +    }
  469. +    tot_xtlen = 0;
  470. +    ret = -EINVAL;
  471. +    for (seg = 0; seg < xtnr_segs; seg++) {
  472. +        loff_t off = (loff_t) xtv[seg].xtv_off;
  473. +        ssize_t len = (ssize_t)xtv[seg].xtv_len;
  474. +
  475. +        if (len < 0)    /* size_t not fitting an ssize_t .. */
  476. +            goto out;
  477. +        if (off < 0)   /* off_t not fitting an loff_t */
  478. +            goto out;
  479. +        tot_xtlen += len;
  480. +        if ((ssize_t)tot_xtlen < 0) /* overflow on the ssize_t */
  481. +            goto out;
  482. +        ret = rw_verify_area(type, file, &off, len);
  483. +        if (ret < 0)
  484. +            goto out;
  485. +    }
  486. +    /* if sizes of file and mem don't match up, error out */
  487. +    if (tot_xtlen != tot_len) {
  488. +        ret = -EINVAL;
  489. +        goto out;
  490. +    }
  491. +
  492. +    ret = security_file_permission(file, type == READ ? MAY_READ : MAY_WRITE);
  493. +    if (ret)
  494. +        goto out;
  495. +
  496. +    if (type == READ) {
  497. +        fn = (io_fn_t)file->f_op->read;
  498. +        fnv = (iov_fn_t)file->f_op->readv;
  499. +        fnx = (iox_fn_t)file->f_op->readx;
  500. +    } else {
  501. +        fn = (io_fn_t)file->f_op->write;
  502. +        fnv = (iov_fn_t)file->f_op->writev;
  503. +        fnx = (iox_fn_t)file->f_op->writex;
  504. +    }
  505. +    /* if we had a scatter-gather callback in memory and file, go for it */
  506. +    if (fnx) {
  507. +        ret = fnx(file, iov, nr_segs, xtv, xtnr_segs);
  508. +        goto out;
  509. +    }
  510. +    /* else try to do it by hand using readv/writev operations */
  511. +    else if (fnv) {
  512. +        unsigned long xtiov_index = 0, op_iov_index = 0, iov_index = 0;
  513. +        struct iovec *op_iov = NULL, *copied_iovector = NULL;
  514. +        struct xtvec *copied_xtvector = NULL;
  515. +
  516. +        ret = -ENOMEM;
  517. +        op_iov = (struct iovec *) kmalloc(nr_segs * sizeof(struct iovec), GFP_KERNEL);
  518. +        if (!op_iov) 
  519. +            goto err_out1;
  520. +        copied_iovector = (struct iovec *) kmalloc(nr_segs * sizeof(struct iovec), GFP_KERNEL);
  521. +        if (!copied_iovector) 
  522. +            goto err_out1;
  523. +        copied_xtvector = (struct xtvec *) kmalloc(xtnr_segs * sizeof(struct xtvec), GFP_KERNEL);
  524. +        if (!copied_xtvector)
  525. +            goto err_out1;
  526. +        memcpy(copied_iovector, iov, nr_segs * sizeof(struct iovec));
  527. +        memcpy(copied_xtvector, xtv, xtnr_segs * sizeof(struct xtvec));
  528. +        ret = 0;
  529. +        iov_index = 0;
  530. +        for (xtiov_index = 0; xtiov_index < xtnr_segs; xtiov_index++) {
  531. +            loff_t pos;
  532. +            ssize_t nr, tot_nr;
  533. +
  534. +            pos = copied_xtvector[xtiov_index].xtv_off;
  535. +            op_iov_index = 0;
  536. +            tot_nr = 0;
  537. +            
  538. +            /* Finish an entire stream and .. */
  539. +            while (copied_xtvector[xtiov_index].xtv_len > 0) {
  540. +                size_t min_len;
  541. +                if (unlikely((iov_index >= nr_segs) || (op_iov_index >= nr_segs))) {
  542. +                    printk(KERN_ERR "iov_index %ld or op_iov_index %ld cannot exceed number of iov segments (%ld)\n",
  543. +                            iov_index, op_iov_index, nr_segs);
  544. +                    ret = -EINVAL;
  545. +                    goto err_out1;
  546. +                }
  547. +                min_len = min(copied_xtvector[xtiov_index].xtv_len, copied_iovector[iov_index].iov_len);
  548. +                op_iov[op_iov_index].iov_base = copied_iovector[iov_index].iov_base;
  549. +                op_iov[op_iov_index++].iov_len = min_len;
  550. +                copied_xtvector[xtiov_index].xtv_len -= min_len;
  551. +                copied_iovector[iov_index].iov_len -= min_len;
  552. +                copied_iovector[iov_index].iov_base += min_len;
  553. +                tot_nr += min_len;
  554. +                /* Advance memory stream if we have exhausted it */
  555. +                if (copied_iovector[iov_index].iov_len <= 0) {
  556. +                    iov_index++;
  557. +                }
  558. +            }
  559. +            /* .. issue a vectored operation for that region */
  560. +            nr = fnv(file, op_iov, op_iov_index, &pos);
  561. +            if (nr < 0) {
  562. +                if (!ret) ret = nr;
  563. +                break;
  564. +            }
  565. +            ret += nr;
  566. +            if (nr != tot_nr)
  567. +                break;
  568. +        }
  569. +err_out1:
  570. +        kfree(op_iov);
  571. +        kfree(copied_iovector);
  572. +        kfree(copied_xtvector);
  573. +        goto out;
  574. +    }
  575. +    /* Do it by hand, with plain read/write operations */
  576. +    else {
  577. +        unsigned long mem_ct = 0, str_ct = 0;
  578. +        struct xtvec *copied_xtvector = NULL;
  579. +        struct iovec *copied_iovector = NULL;
  580. +
  581. +        ret = -ENOMEM;
  582. +        copied_iovector = (struct iovec *) kmalloc(nr_segs * sizeof(struct iovec), GFP_KERNEL);
  583. +        if (!copied_iovector)
  584. +            goto err_out2;
  585. +        copied_xtvector = (struct xtvec *) kmalloc(xtnr_segs * sizeof(struct xtvec), GFP_KERNEL);
  586. +        if (!copied_xtvector)
  587. +            goto err_out2;
  588. +        memcpy(copied_iovector, iov, nr_segs * sizeof(struct iovec));
  589. +        memcpy(copied_xtvector, xtv, xtnr_segs * sizeof(struct xtvec));
  590. +
  591. +        ret = 0;
  592. +        mem_ct = 0;
  593. +        str_ct = 0;
  594. +        while ((mem_ct < nr_segs) && (str_ct < xtnr_segs)) {
  595. +            size_t min_len;
  596. +            loff_t pos;
  597. +            ssize_t nr;
  598. +            void __user *base;
  599. +
  600. +            pos = copied_xtvector[str_ct].xtv_off;
  601. +            base = copied_iovector[mem_ct].iov_base;
  602. +            min_len = min(copied_xtvector[str_ct].xtv_len, copied_iovector[mem_ct].iov_len);
  603. +            copied_xtvector[str_ct].xtv_len -= min_len;
  604. +            copied_xtvector[str_ct].xtv_off += min_len;
  605. +            copied_iovector[mem_ct].iov_len -= min_len;
  606. +            copied_iovector[mem_ct].iov_base += min_len;
  607. +            if (copied_iovector[mem_ct].iov_len <= 0)
  608. +                mem_ct++;
  609. +            if (copied_xtvector[str_ct].xtv_len <= 0)
  610. +                str_ct++;
  611. +            /* Issue the smallest region that is contiguous in memory and on file */
  612. +            nr = fn(file, base, min_len, &pos);
  613. +            if (nr < 0) {
  614. +                if (!ret) ret = nr;
  615. +                break;
  616. +            }
  617. +            ret += nr;
  618. +            if (nr != min_len)
  619. +                break;
  620. +        }
  621. +err_out2:
  622. +        kfree(copied_xtvector);
  623. +        kfree(copied_iovector);
  624. +    }
  625. +out:
  626. +    if (iov != iovstack)
  627. +        kfree(iov);
  628. +    if (xtv != xtvstack)
  629. +        kfree(xtv);
  630. +    if ((ret + (type == READ)) > 0) {
  631. +        if (type == READ)
  632. +            fsnotify_access(file->f_dentry);
  633. +        else
  634. +            fsnotify_modify(file->f_dentry);
  635. +    }
  636. +    return ret;
  637. +Efault:
  638. +    ret = -EFAULT;
  639. +    goto out;
  640. +}
  641. +
  642. +ssize_t vfs_readx(struct file *file, const struct iovec __user *vec,
  643. +          unsigned long vlen, const struct xtvec __user *xtvec, unsigned long xtvlen)
  644. +{
  645. +    if (!(file->f_mode & FMODE_READ))
  646. +        return -EBADF;
  647. +    if (!file->f_op || (!file->f_op->readx && !file->f_op->readv && !file->f_op->read))
  648. +        return -EINVAL;
  649. +
  650. +    return do_readx_writex(READ, file, vec, vlen, xtvec, xtvlen);
  651. +}
  652. +
  653. +EXPORT_SYMBOL_GPL(vfs_readx);
  654. +
  655. +ssize_t vfs_writex(struct file *file, const struct iovec __user *vec,
  656. +           unsigned long vlen, const struct xtvec __user *xtvec, unsigned long xtvlen)
  657. +{
  658. +    if (!(file->f_mode & FMODE_WRITE))
  659. +        return -EBADF;
  660. +    if (!file->f_op || (!file->f_op->writex && !file->f_op->writev && !file->f_op->write))
  661. +        return -EINVAL;
  662. +
  663. +    return do_readx_writex(WRITE, file, vec, vlen, xtvec, xtvlen);
  664. +}
  665. +
  666. +EXPORT_SYMBOL_GPL(vfs_writex);
  667. +
  668. +asmlinkage ssize_t sys_readx(unsigned long fd,
  669. +                const struct iovec __user *vec,
  670. +                unsigned long vlen,
  671. +                const struct xtvec __user *xtvec,
  672. +                unsigned long xtvlen)
  673. +{
  674. +    struct file *file;
  675. +    ssize_t ret = -EBADF;
  676. +    int fput_needed;
  677. +
  678. +    file = fget_light(fd, &fput_needed);
  679. +    if (file) {
  680. +        ret = vfs_readx(file, vec, vlen, xtvec, xtvlen);
  681. +        fput_light(file, fput_needed);
  682. +    }
  683. +
  684. +    if (ret > 0)
  685. +        current->rchar += ret;
  686. +    current->syscr++;
  687. +    return ret;
  688. +}
  689. +
  690. +asmlinkage ssize_t sys_writex(unsigned long fd,
  691. +                const struct iovec __user *vec,
  692. +                unsigned long vlen,
  693. +                const struct xtvec __user *xtvec,
  694. +                unsigned long xtvlen)
  695. +{
  696. +    struct file *file;
  697. +    ssize_t ret = -EBADF;
  698. +    int fput_needed;
  699. +
  700. +    file = fget_light(fd, &fput_needed);
  701. +    if (file) {
  702. +        ret = vfs_writex(file, vec, vlen, xtvec, xtvlen);
  703. +        fput_light(file, fput_needed);
  704. +    }
  705. +
  706. +    if (ret > 0)
  707. +        current->wchar += ret;
  708. +    current->syscw++;
  709. +    return ret;
  710. +}
  711. +
  712.  static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos,
  713.                 size_t count, loff_t max)
  714.  {
  715. diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/include/asm-i386/unistd.h vanilla-new/include/asm-i386/unistd.h
  716. --- vanilla/include/asm-i386/unistd.h    2006-05-24 16:19:07.000000000 -0500
  717. +++ vanilla-new/include/asm-i386/unistd.h    2006-05-24 16:27:28.000000000 -0500
  718. @@ -326,8 +326,10 @@
  719.  #define __NR_fstatlite64 318
  720.  #define __NR_getdents_plus 319
  721.  #define __NR_getdents64_plus 320
  722. +#define __NR_readx      321
  723. +#define __NR_writex     322
  724.  
  725. -#define NR_syscalls 321
  726. +#define NR_syscalls 323
  727.  
  728.  /*
  729.   * user-visible error numbers are in the range -1 - -128: see
  730. diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/include/asm-ia64/unistd.h vanilla-new/include/asm-ia64/unistd.h
  731. --- vanilla/include/asm-ia64/unistd.h    2006-05-24 16:19:07.000000000 -0500
  732. +++ vanilla-new/include/asm-ia64/unistd.h    2006-05-24 16:29:19.000000000 -0500
  733. @@ -292,12 +292,14 @@
  734.  #define __NR_fstatlite     1301
  735.  #define __NR_getdents_plus 1302
  736.  #define __NR_getdents64_plus 1303
  737. +#define __NR_readx         1304
  738. +#define __NR_writex        1305
  739.  
  740.  #ifdef __KERNEL__
  741.  
  742.  #include <linux/config.h>
  743.  
  744. -#define NR_syscalls            280 /* length of syscall table */
  745. +#define NR_syscalls            282 /* length of syscall table */
  746.  
  747.  #define __ARCH_WANT_SYS_RT_SIGACTION
  748.  
  749. diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/include/asm-powerpc/unistd.h vanilla-new/include/asm-powerpc/unistd.h
  750. --- vanilla/include/asm-powerpc/unistd.h    2006-05-24 16:19:07.000000000 -0500
  751. +++ vanilla-new/include/asm-powerpc/unistd.h    2006-05-24 16:30:04.000000000 -0500
  752. @@ -308,8 +308,10 @@
  753.  #define __NR_fstatlite     287
  754.  #define __NR_getdents_plus 288
  755.  #define __NR_getdents64_plus 289
  756. +#define __NR_readx         290
  757. +#define __NR_writex        291
  758.  
  759. -#define __NR_syscalls        290
  760. +#define __NR_syscalls        292
  761.  
  762.  #ifdef __KERNEL__
  763.  #define __NR__exit __NR_exit
  764. diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/include/asm-x86_64/unistd.h vanilla-new/include/asm-x86_64/unistd.h
  765. --- vanilla/include/asm-x86_64/unistd.h    2006-05-24 16:19:07.000000000 -0500
  766. +++ vanilla-new/include/asm-x86_64/unistd.h    2006-05-24 16:28:26.000000000 -0500
  767. @@ -619,8 +619,12 @@
  768.  __SYSCALL(__NR_getdents_plus, sys_getdents_plus)
  769.  #define __NR_getdents64_plus 279
  770.  __SYSCALL(__NR_getdents64_plus, sys_getdents64_plus)
  771. +#define __NR_readx  280
  772. +__SYSCALL(__NR_readx, sys_readx)
  773. +#define __NR_writex 281
  774. +__SYSCALL(__NR_writex, sys_writex)
  775.  
  776. -#define __NR_syscall_max __NR_getdents64_plus
  777. +#define __NR_syscall_max __NR_writex
  778.  
  779.  #ifndef __NO_STUBS
  780.  
  781. diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/include/linux/compat.h vanilla-new/include/linux/compat.h
  782. --- vanilla/include/linux/compat.h    2006-05-09 18:53:48.000000000 -0500
  783. +++ vanilla-new/include/linux/compat.h    2006-05-24 16:26:29.000000000 -0500
  784. @@ -61,6 +61,11 @@
  785.      compat_size_t    iov_len;
  786.  };
  787.  
  788. +struct compat_xtvec {
  789. +    compat_off_t  xtv_off;
  790. +    compat_size_t xtv_len;
  791. +};
  792. +
  793.  struct compat_rlimit {
  794.      compat_ulong_t    rlim_cur;
  795.      compat_ulong_t    rlim_max;
  796. @@ -141,6 +146,13 @@
  797.  asmlinkage ssize_t compat_sys_writev(unsigned long fd,
  798.          const struct compat_iovec __user *vec, unsigned long vlen);
  799.  
  800. +asmlinkage ssize_t compat_sys_readx(unsigned long fd,
  801. +        const struct compat_iovec __user *vec, unsigned long vlen,
  802. +        const struct compat_xtvec __user *xtvec, unsigned long xtvlen);
  803. +asmlinkage ssize_t compat_sys_writex(unsigned long fd,
  804. +        const struct compat_iovec __user *vec, unsigned long vlen,
  805. +        const struct compat_xtvec __user *xtvec, unsigned long xtvlen);
  806. +
  807.  int compat_do_execve(char * filename, compat_uptr_t __user *argv,
  808.              compat_uptr_t __user *envp, struct pt_regs * regs);
  809.  
  810. diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/include/linux/fs.h vanilla-new/include/linux/fs.h
  811. --- vanilla/include/linux/fs.h    2006-05-24 16:19:07.000000000 -0500
  812. +++ vanilla-new/include/linux/fs.h    2006-05-24 16:20:15.000000000 -0500
  813. @@ -226,6 +226,7 @@
  814.  
  815.  struct hd_geometry;
  816.  struct iovec;
  817. +struct xtvec;
  818.  struct nameidata;
  819.  struct kiocb;
  820.  struct pipe_inode_info;
  821. @@ -1048,6 +1049,8 @@
  822.      int (*lock) (struct file *, int, struct file_lock *);
  823.      ssize_t (*readv) (struct file *, const struct iovec *, unsigned long, loff_t *);
  824.      ssize_t (*writev) (struct file *, const struct iovec *, unsigned long, loff_t *);
  825. +    ssize_t (*readx) (struct file *, const struct iovec *, unsigned long, const struct xtvec *, unsigned long);
  826. +    ssize_t (*writex) (struct file *, const struct iovec *, unsigned long, const struct xtvec *, unsigned long);
  827.      ssize_t (*sendfile) (struct file *, loff_t *, size_t, read_actor_t, void *);
  828.      ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
  829.      unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
  830. @@ -1092,6 +1095,11 @@
  831.          unsigned long, loff_t *);
  832.  extern ssize_t vfs_writev(struct file *, const struct iovec __user *,
  833.          unsigned long, loff_t *);
  834. +extern ssize_t vfs_readx(struct file *, const struct iovec __user *,
  835. +        unsigned long, const struct xtvec __user *, unsigned long);
  836. +extern ssize_t vfs_writex(struct file *, const struct iovec __user *,
  837. +        unsigned long, const struct xtvec __user *, unsigned long);
  838. +
  839.  
  840.  /*
  841.   * NOTE: write_inode, delete_inode, clear_inode, put_inode can be called
  842. diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/include/linux/syscalls.h vanilla-new/include/linux/syscalls.h
  843. --- vanilla/include/linux/syscalls.h    2006-05-24 16:19:07.000000000 -0500
  844. +++ vanilla-new/include/linux/syscalls.h    2006-05-24 16:23:31.000000000 -0500
  845. @@ -17,6 +17,7 @@
  846.  struct iocb;
  847.  struct io_event;
  848.  struct iovec;
  849. +struct xtvec;
  850.  struct itimerspec;
  851.  struct itimerval;
  852.  struct kexec_segment;
  853. @@ -402,6 +403,16 @@
  854.  asmlinkage ssize_t sys_writev(unsigned long fd,
  855.                  const struct iovec __user *vec,
  856.                  unsigned long vlen);
  857. +asmlinkage ssize_t sys_readx(unsigned long fd,
  858. +                const struct iovec __user *vec,
  859. +                unsigned long vlen,
  860. +                const struct xtvec __user *xtvec,
  861. +                unsigned long xtvlen);
  862. +asmlinkage ssize_t sys_writex(unsigned long fd,
  863. +                const struct iovec __user *vec,
  864. +                unsigned long vlen,
  865. +                const struct xtvec __user *xtvec,
  866. +                unsigned long xtvlen);
  867.  asmlinkage ssize_t sys_pread64(unsigned int fd, char __user *buf,
  868.                  size_t count, loff_t pos);
  869.  asmlinkage ssize_t sys_pwrite64(unsigned int fd, const char __user *buf,
  870. diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/include/linux/uio.h vanilla-new/include/linux/uio.h
  871. --- vanilla/include/linux/uio.h    2006-03-19 23:53:29.000000000 -0600
  872. +++ vanilla-new/include/linux/uio.h    2006-05-24 16:24:20.000000000 -0500
  873. @@ -23,6 +23,12 @@
  874.      __kernel_size_t iov_len; /* Must be size_t (1003.1g) */
  875.  };
  876.  
  877. +struct xtvec 
  878. +{
  879. +    __kernel_off_t xtv_off;  /* must be off_t */
  880. +    __kernel_size_t xtv_len; /* must be size_t */
  881. +};
  882. +
  883.  #ifdef __KERNEL__
  884.  
  885.  struct kvec {
  886. @@ -30,6 +36,12 @@
  887.      size_t iov_len;
  888.  };
  889.  
  890. +struct kxtvec
  891. +{
  892. +    off_t xtv_off;
  893. +    size_t xtv_len;
  894. +};
  895. +
  896.  #endif
  897.  
  898.  /*
  899.