2 * This Cplant(TM) source code is the property of Sandia National
5 * This Cplant(TM) source code is copyrighted by Sandia National
8 * The redistribution of this Cplant(TM) source code is subject to the
9 * terms of the GNU Lesser General Public License
10 * (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html)
12 * Cplant(TM) Copyright 1998-2004 Sandia Corporation.
13 * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
14 * license for use of this work by or on behalf of the US Government.
15 * Export of this program may require a license from the United States
20 * This library is free software; you can redistribute it and/or
21 * modify it under the terms of the GNU Lesser General Public
22 * License as published by the Free Software Foundation; either
23 * version 2.1 of the License, or (at your option) any later version.
25 * This library is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
28 * Lesser General Public License for more details.
30 * You should have received a copy of the GNU Lesser General Public
31 * License along with this library; if not, write to the Free Software
32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
34 * Questions or comments about this library should be sent to:
37 * Sandia National Laboratories, New Mexico
39 * Albuquerque, NM 87185-1110
49 #include <sys/types.h>
51 #include <sys/queue.h>
57 * Extent-vector IO support.
61 * Arguments to IO vector enumerator callback when used by _sysio_doio().
63 struct doio_helper_args {
64 ssize_t (*f)(void *, size_t, _SYSIO_OFF_T, void *); /* base func */
65 void *arg; /* caller arg */
69 * General help validating strided-IO vectors.
71 * A driver may call this to make sure underflow/overflow of an off_t can't
72 * occur and overflow of a ssize_t can't occur when writing. The sum
73 * of the reconciled transfer length is returned or some appropriate
74 * error depending on underflow/overflow.
76 * The following algorithm assumes:
78 * a) sizeof(size_t) >= sizeof(ssize_t)
79 * b) 2's complement arithmetic
80 * c) The compiler won't optimize away code because it's developers
81 * believed that something with an undefined result in `C' can't happen.
84 _sysio_validx(const struct intnl_xtvec *xtv, size_t xtvlen,
85 const struct iovec *iov, size_t iovlen,
90 struct intnl_xtvec xtvec;
93 if (!(xtvlen && iovlen))
97 xtvec.xtv_len = iovec.iov_len = 0;
99 while (!xtvec.xtv_len) {
107 if (xtvec.xtv_off < 0)
113 while (!iovec.iov_len) {
127 if ((size_t )cc > xtvec.xtv_len)
131 off = xtvec.xtv_off + cc;
132 if (xtvec.xtv_off && off <= xtvec.xtv_off)
133 return off < 0 ? -EINVAL : -EOVERFLOW;
138 if (acc && (cc <= acc))
141 } while (xtvec.xtv_len && iovlen);
142 } while ((xtvlen || xtvec.xtv_len) && iovlen);
149 _sysio_enumerate_extents(const struct intnl_xtvec *xtv, size_t xtvlen,
150 const struct iovec *iov, size_t iovlen,
151 ssize_t (*f)(const struct iovec *, int,
157 ssize_t acc, tmp, cc;
159 struct intnl_xtvec xtvec;
160 const struct iovec *start;
169 * Coalesce contiguous extent vector entries.
171 off = xtvec.xtv_off = xtv->xtv_off;
172 off += xtvec.xtv_len = xtv->xtv_len;
173 while (++xtv, --xtvlen) {
174 if (off != xtv->xtv_off) {
187 xtvec.xtv_len += xtv->xtv_len;
189 while (xtvec.xtv_len) {
192 if (iovec.iov_len > xtvec.xtv_len)
193 iovec.iov_len = xtvec.xtv_len;
204 iovec.iov_base = (char *)iovec.iov_base + cc;
205 iovec.iov_len = tmp - cc;
207 if (acc && tmp <= acc)
208 abort(); /* paranoia */
214 if (iov->iov_len > n) {
228 remain = xtvec.xtv_len - n;
230 (*f)(start, iov - start,
241 if (acc && tmp <= acc)
242 abort(); /* paranoia */
247 return acc; /* short */
249 return acc; /* short out */
258 _sysio_enumerate_iovec(const struct iovec *iov, size_t count,
261 ssize_t (*f)(void *, size_t, _SYSIO_OFF_T, void *),
274 for (indx = 0; n && indx < count; indx++) {
275 if (iov[indx].iov_len < n) {
276 cc = (ssize_t )iov[indx].iov_len;
285 if (acc && cc <= acc)
298 iov->iov_len < (size_t )limit
301 cc = (*f)(iov->iov_base, n, off, arg);
309 remain = iov->iov_len - cc;
311 if (acc && cc <= acc)
312 abort(); /* bad driver! */
314 if (remain || !limit)
315 break; /* short/limited read */
322 _sysio_doio_helper(const struct iovec *iov, int count,
325 struct doio_helper_args *args)
328 return _sysio_enumerate_iovec(iov, count,
335 * A meta-driver for the whole strided-io process. Appropriate when
336 * the driver can't handle anything but simple p{read,write}-like
340 _sysio_doio(const struct intnl_xtvec *xtv, size_t xtvlen,
341 const struct iovec *iov, size_t iovlen,
342 ssize_t (*f)(void *, size_t, _SYSIO_OFF_T, void *),
345 struct doio_helper_args arguments;
349 return _sysio_enumerate_extents(xtv, xtvlen,
351 (ssize_t (*)(const struct iovec *, int,
354 void *))_sysio_doio_helper,