iovec.c revision b4bf07771faaf959b0a916d35b1b930c030e30a8
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * iovec manipulation routines. 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * modify it under the terms of the GNU General Public License 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * as published by the Free Software Foundation; either version 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2 of the License, or (at your option) any later version. 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Fixes: 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Andrew Lunn : Errors in iovec copying. 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Pedro Roque : Added memcpy_fromiovecend and 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * csum_..._fromiovecend. 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Andi Kleen : fixed error handling for 2.1 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Alexey Kuznetsov: 2.1 optimisations 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Andi Kleen : Fix csum*fromiovecend for IPv6. 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h> 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h> 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mm.h> 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/net.h> 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/in6.h> 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/uaccess.h> 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/byteorder.h> 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/checksum.h> 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/sock.h> 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Verify iovec. The caller must ensure that the iovec is big enough 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to hold the message iovec. 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 34e49332bd12e92da2df6d002f857ec62675ba2648Jesper Juhl * Save time not doing access_ok. copy_*_user will make this work 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * in any case. 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3843db362d3adda9e0a915ddb9a8d1a41186e19179Maciej Żenczykowskiint verify_iovec(struct msghdr *m, struct iovec *iov, struct sockaddr_storage *address, int mode) 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 408acfe468b0384e834a303f08ebc4953d72fb690aDavid S. Miller int size, ct, err; 414ec93edb14fe5fdee9fae6335f2cbba204627eacYOSHIFUJI Hideaki 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (m->msg_namelen) { 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mode == VERIFY_READ) { 44a700d8be733bd593ea4797dfde17aed4f35213c0Namhyung Kim void __user *namep; 45a700d8be733bd593ea4797dfde17aed4f35213c0Namhyung Kim namep = (void __user __force *) m->msg_name; 46a700d8be733bd593ea4797dfde17aed4f35213c0Namhyung Kim err = move_addr_to_kernel(namep, m->msg_namelen, 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds address); 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err < 0) 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds m->msg_name = address; 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds m->msg_name = NULL; 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds size = m->msg_iovlen * sizeof(struct iovec); 57a700d8be733bd593ea4797dfde17aed4f35213c0Namhyung Kim if (copy_from_user(iov, (void __user __force *) m->msg_iov, size)) 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds m->msg_iov = iov; 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = 0; 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (ct = 0; ct < m->msg_iovlen; ct++) { 648acfe468b0384e834a303f08ebc4953d72fb690aDavid S. Miller size_t len = iov[ct].iov_len; 658acfe468b0384e834a303f08ebc4953d72fb690aDavid S. Miller 668acfe468b0384e834a303f08ebc4953d72fb690aDavid S. Miller if (len > INT_MAX - err) { 678acfe468b0384e834a303f08ebc4953d72fb690aDavid S. Miller len = INT_MAX - err; 688acfe468b0384e834a303f08ebc4953d72fb690aDavid S. Miller iov[ct].iov_len = len; 698acfe468b0384e834a303f08ebc4953d72fb690aDavid S. Miller } 708acfe468b0384e834a303f08ebc4953d72fb690aDavid S. Miller err += len; 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copy kernel to iovec. Returns -EFAULT on error. 780a1ec07a67bd8b0033dace237249654d015efa21Michael S. Tsirkin */ 790a1ec07a67bd8b0033dace237249654d015efa21Michael S. Tsirkin 800a1ec07a67bd8b0033dace237249654d015efa21Michael S. Tsirkinint memcpy_toiovecend(const struct iovec *iov, unsigned char *kdata, 810a1ec07a67bd8b0033dace237249654d015efa21Michael S. Tsirkin int offset, int len) 820a1ec07a67bd8b0033dace237249654d015efa21Michael S. Tsirkin{ 830a1ec07a67bd8b0033dace237249654d015efa21Michael S. Tsirkin int copy; 840a1ec07a67bd8b0033dace237249654d015efa21Michael S. Tsirkin for (; len > 0; ++iov) { 850a1ec07a67bd8b0033dace237249654d015efa21Michael S. Tsirkin /* Skip over the finished iovecs */ 860a1ec07a67bd8b0033dace237249654d015efa21Michael S. Tsirkin if (unlikely(offset >= iov->iov_len)) { 870a1ec07a67bd8b0033dace237249654d015efa21Michael S. Tsirkin offset -= iov->iov_len; 880a1ec07a67bd8b0033dace237249654d015efa21Michael S. Tsirkin continue; 890a1ec07a67bd8b0033dace237249654d015efa21Michael S. Tsirkin } 900a1ec07a67bd8b0033dace237249654d015efa21Michael S. Tsirkin copy = min_t(unsigned int, iov->iov_len - offset, len); 912faef52b72958b8b1c08e927b9b0691c314cf6f4Sridhar Samudrala if (copy_to_user(iov->iov_base + offset, kdata, copy)) 920a1ec07a67bd8b0033dace237249654d015efa21Michael S. Tsirkin return -EFAULT; 932faef52b72958b8b1c08e927b9b0691c314cf6f4Sridhar Samudrala offset = 0; 940a1ec07a67bd8b0033dace237249654d015efa21Michael S. Tsirkin kdata += copy; 950a1ec07a67bd8b0033dace237249654d015efa21Michael S. Tsirkin len -= copy; 960a1ec07a67bd8b0033dace237249654d015efa21Michael S. Tsirkin } 970a1ec07a67bd8b0033dace237249654d015efa21Michael S. Tsirkin 980a1ec07a67bd8b0033dace237249654d015efa21Michael S. Tsirkin return 0; 990a1ec07a67bd8b0033dace237249654d015efa21Michael S. Tsirkin} 1009e34a5b51684bc90ac827ec4ba339f3892632eacEric DumazetEXPORT_SYMBOL(memcpy_toiovecend); 1010a1ec07a67bd8b0033dace237249654d015efa21Michael S. Tsirkin 1020a1ec07a67bd8b0033dace237249654d015efa21Michael S. Tsirkin/* 1036f26c9a7555e5bcca3560919db9b852015077daeMichael S. Tsirkin * Copy iovec from kernel. Returns -EFAULT on error. 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1056f26c9a7555e5bcca3560919db9b852015077daeMichael S. Tsirkin 1066f26c9a7555e5bcca3560919db9b852015077daeMichael S. Tsirkinint memcpy_fromiovecend(unsigned char *kdata, const struct iovec *iov, 1076f26c9a7555e5bcca3560919db9b852015077daeMichael S. Tsirkin int offset, int len) 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Skip over the finished iovecs */ 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (offset >= iov->iov_len) { 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds offset -= iov->iov_len; 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iov++; 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (len > 0) { 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 __user *base = iov->iov_base + offset; 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int copy = min_t(unsigned int, len, iov->iov_len - offset); 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds offset = 0; 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (copy_from_user(kdata, base, copy)) 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds len -= copy; 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kdata += copy; 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iov++; 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1299e34a5b51684bc90ac827ec4ba339f3892632eacEric DumazetEXPORT_SYMBOL(memcpy_fromiovecend); 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * And now for the all-in-one: copy and checksum from a user iovec 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * directly to a datagram 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Calls to csum_partial but the last must be in 32 bit chunks 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ip_build_xmit must ensure that when fragmenting only the last 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * call to this function will be unaligned also. 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint csum_partial_copy_fromiovecend(unsigned char *kdata, struct iovec *iov, 14044bb93633f57a55979f3c2589b10fd6a2bfc7c08Al Viro int offset, unsigned int len, __wsum *csump) 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 14244bb93633f57a55979f3c2589b10fd6a2bfc7c08Al Viro __wsum csum = *csump; 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int partial_cnt = 0, err = 0; 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Skip over the finished iovecs */ 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (offset >= iov->iov_len) { 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds offset -= iov->iov_len; 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iov++; 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (len > 0) { 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 __user *base = iov->iov_base + offset; 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int copy = min_t(unsigned int, len, iov->iov_len - offset); 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds offset = 0; 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* There is a remnant from previous iov. */ 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (partial_cnt) { 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int par_len = 4 - partial_cnt; 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* iov component is too short ... */ 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (par_len > copy) { 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (copy_from_user(kdata, base, copy)) 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out_fault; 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kdata += copy; 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds base += copy; 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds partial_cnt += copy; 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds len -= copy; 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iov++; 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (len) 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *csump = csum_partial(kdata - partial_cnt, 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds partial_cnt, csum); 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (copy_from_user(kdata, base, par_len)) 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out_fault; 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds csum = csum_partial(kdata - partial_cnt, 4, csum); 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kdata += par_len; 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds base += par_len; 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds copy -= par_len; 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds len -= par_len; 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds partial_cnt = 0; 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (len > copy) { 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds partial_cnt = copy % 4; 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (partial_cnt) { 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds copy -= partial_cnt; 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (copy_from_user(kdata + copy, base + copy, 1914ec93edb14fe5fdee9fae6335f2cbba204627eacYOSHIFUJI Hideaki partial_cnt)) 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out_fault; 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (copy) { 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds csum = csum_and_copy_from_user(base, kdata, copy, 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds csum, &err); 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds len -= copy + partial_cnt; 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kdata += copy + partial_cnt; 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iov++; 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2064ec93edb14fe5fdee9fae6335f2cbba204627eacYOSHIFUJI Hideaki *csump = csum; 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout: 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout_fault: 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = -EFAULT; 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(csum_partial_copy_fromiovecend); 215b4bf07771faaf959b0a916d35b1b930c030e30a8Jason Wang 216b4bf07771faaf959b0a916d35b1b930c030e30a8Jason Wangunsigned long iov_pages(const struct iovec *iov, int offset, 217b4bf07771faaf959b0a916d35b1b930c030e30a8Jason Wang unsigned long nr_segs) 218b4bf07771faaf959b0a916d35b1b930c030e30a8Jason Wang{ 219b4bf07771faaf959b0a916d35b1b930c030e30a8Jason Wang unsigned long seg, base; 220b4bf07771faaf959b0a916d35b1b930c030e30a8Jason Wang int pages = 0, len, size; 221b4bf07771faaf959b0a916d35b1b930c030e30a8Jason Wang 222b4bf07771faaf959b0a916d35b1b930c030e30a8Jason Wang while (nr_segs && (offset >= iov->iov_len)) { 223b4bf07771faaf959b0a916d35b1b930c030e30a8Jason Wang offset -= iov->iov_len; 224b4bf07771faaf959b0a916d35b1b930c030e30a8Jason Wang ++iov; 225b4bf07771faaf959b0a916d35b1b930c030e30a8Jason Wang --nr_segs; 226b4bf07771faaf959b0a916d35b1b930c030e30a8Jason Wang } 227b4bf07771faaf959b0a916d35b1b930c030e30a8Jason Wang 228b4bf07771faaf959b0a916d35b1b930c030e30a8Jason Wang for (seg = 0; seg < nr_segs; seg++) { 229b4bf07771faaf959b0a916d35b1b930c030e30a8Jason Wang base = (unsigned long)iov[seg].iov_base + offset; 230b4bf07771faaf959b0a916d35b1b930c030e30a8Jason Wang len = iov[seg].iov_len - offset; 231b4bf07771faaf959b0a916d35b1b930c030e30a8Jason Wang size = ((base & ~PAGE_MASK) + len + ~PAGE_MASK) >> PAGE_SHIFT; 232b4bf07771faaf959b0a916d35b1b930c030e30a8Jason Wang pages += size; 233b4bf07771faaf959b0a916d35b1b930c030e30a8Jason Wang offset = 0; 234b4bf07771faaf959b0a916d35b1b930c030e30a8Jason Wang } 235b4bf07771faaf959b0a916d35b1b930c030e30a8Jason Wang 236b4bf07771faaf959b0a916d35b1b930c030e30a8Jason Wang return pages; 237b4bf07771faaf959b0a916d35b1b930c030e30a8Jason Wang} 238b4bf07771faaf959b0a916d35b1b930c030e30a8Jason WangEXPORT_SYMBOL(iov_pages); 239