#include <stdlib.h>
#include <string.h>
#include <errno.h>
+#include <sched.h>
#include <assert.h>
-#include <sys/types.h>
#include <sys/uio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
#include <sys/queue.h>
#include "sysio.h"
-#include "inode.h"
#include "xtio.h"
+#include "inode.h"
+
+#if defined(REDSTORM)
+#include <catamount/do_iostats.h>
+#endif
-/*
- * Asynchronous IO context support.
- */
/*
- * Arguments to IO vector enumerator callback when used by _sysio_doio().
+ * Asynchronous IO context support.
*/
-struct doio_helper_args {
- ssize_t (*f)(void *, size_t, _SYSIO_OFF_T, void *); /* base func */
- void *arg; /* caller arg */
-};
/*
* List of all outstanding (in-flight) asynch IO requests tracked
IOCTX_INIT(ioctx,
0,
- (ioid_t )ioctx,
wr,
ino,
iov, iovlen,
* this implementation.
*/
struct ioctx *
-_sysio_ioctx_find(ioid_t id)
+_sysio_ioctx_find(void *id)
{
struct ioctx *ioctx;
for (ioctx = aioq.lh_first; ioctx; ioctx = ioctx->ioctx_link.le_next)
- if (ioctx->ioctx_id == id)
+ if (ioctx == id)
return ioctx;
return NULL;
}
/*
+ * Check if asynchronous IO operation is complete.
+ */
+int
+_sysio_ioctx_done(struct ioctx *ioctx)
+{
+
+ if (ioctx->ioctx_done)
+ return 1;
+ if (!(*ioctx->ioctx_ino->i_ops.inop_iodone)(ioctx))
+ return 0;
+ ioctx->ioctx_done = 1;
+ return 1;
+}
+
+/*
* Wait for asynchronous IO operation to complete, return status
* and dispose of the context.
*
/*
* Wait for async operation to complete.
*/
- while (!(ioctx->ioctx_done ||
- (*ioctx->ioctx_ino->i_ops.inop_iodone)(ioctx)))
- ;
+ while (!_sysio_ioctx_done(ioctx)) {
+#ifdef POSIX_PRIORITY_SCHEDULING
+ (void )sched_yield();
+#endif
+ }
/*
* Get status.
{
struct ioctx_callback *entry;
+
+ /* update IO stats */
+ _SYSIO_UPDACCT(ioctx->ioctx_write, ioctx->ioctx_cc);
+
/*
* Run the call-back queue.
*/
free(ioctx);
}
-
-/*
- * General help validating strided-IO vectors.
- *
- * A driver may call this to make sure underflow/overflow of an off_t can't
- * occur and overflow of a ssize_t can't occur when writing. The sum
- * of the reconciled transfer length is returned or some appropriate
- * error depending on underflow/overflow.
- *
- * The following algorithm assumes:
- *
- * a) sizeof(size_t) >= sizeof(ssize_t)
- * b) 2's complement arithmetic
- * c) The compiler won't optimize away code because it's developers
- * believed that something with an undefined result in `C' can't happen.
- */
-ssize_t
-_sysio_validx(const struct intnl_xtvec *xtv, size_t xtvlen,
- const struct iovec *iov, size_t iovlen,
- _SYSIO_OFF_T limit)
-{
- ssize_t acc, cc;
- struct iovec iovec;
- struct intnl_xtvec xtvec;
- _SYSIO_OFF_T off;
-
- if (!(xtvlen && iovlen))
- return -EINVAL;
-
- acc = 0;
- xtvec.xtv_len = iovec.iov_len = 0;
- do {
- while (!xtvec.xtv_len) {
- if (!xtvlen--)
- break;
- if (!xtv->xtv_len) {
- xtv++;
- continue;
- }
- xtvec = *xtv++;
- if (xtvec.xtv_off < 0)
- return -EINVAL;
- }
- if (!xtvec.xtv_len)
- break;
- do {
- while (!iovec.iov_len) {
- if (!iovlen--)
- break;
- if (!iov->iov_len) {
- iov++;
- continue;
- }
- iovec = *iov++;
- }
- if (!iovec.iov_len)
- break;
- cc = iovec.iov_len;
- if (cc < 0)
- return -EINVAL;
- if ((size_t )cc > xtvec.xtv_len)
- cc = xtvec.xtv_len;
- xtvec.xtv_len -= cc;
- iovec.iov_len -= cc;
- off = xtvec.xtv_off + cc;
- if (xtvec.xtv_off && off <= xtvec.xtv_off)
- return off < 0 ? -EINVAL : -EOVERFLOW;
- if (off > limit)
- return -EFBIG;
- xtvec.xtv_off = off;
- cc += acc;
- if (acc && (cc <= acc))
- return -EINVAL;
- acc = cc;
- } while (xtvec.xtv_len && iovlen);
- } while ((xtvlen || xtvec.xtv_len) && iovlen);
- return acc;
-}
-
-/*
- */
-ssize_t
-_sysio_enumerate_extents(const struct intnl_xtvec *xtv, size_t xtvlen,
- const struct iovec *iov, size_t iovlen,
- ssize_t (*f)(const struct iovec *, int,
- _SYSIO_OFF_T,
- ssize_t,
- void *),
- void *arg)
-{
- ssize_t acc, tmp, cc;
- struct iovec iovec;
- struct intnl_xtvec xtvec;
- const struct iovec *start;
- _SYSIO_OFF_T off;
- size_t n;
- size_t remain;
-
- acc = 0;
- iovec.iov_len = 0;
- while (xtvlen) {
- /*
- * Coalesce contiguous extent vector entries.
- */
- off = xtvec.xtv_off = xtv->xtv_off;
- off += xtvec.xtv_len = xtv->xtv_len;
- while (++xtv, --xtvlen) {
- if (off != xtv->xtv_off) {
- /*
- * Not contiguous.
- */
- break;
- }
- if (!xtv->xtv_len) {
- /*
- * Zero length.
- */
- continue;
- }
- off += xtv->xtv_len;
- xtvec.xtv_len += xtv->xtv_len;
- }
- while (xtvec.xtv_len) {
- if (iovec.iov_len) {
- tmp = iovec.iov_len;
- if (iovec.iov_len > xtvec.xtv_len) {
- iovec.iov_len = xtvec.xtv_len;
- }
- cc =
- (*f)(&iovec, 1,
- xtvec.xtv_off,
- xtvec.xtv_len,
- arg);
- if (cc <= 0) {
- if (acc)
- return acc;
- return cc;
- }
- iovec.iov_base = (char *)iovec.iov_base + cc;
- iovec.iov_len = tmp - cc;
- tmp = cc + acc;
- if (acc && tmp <= acc)
- abort(); /* paranoia */
- acc = tmp;
- } else {
- start = iov;
- n = xtvec.xtv_len;
- do {
- if (iov->iov_len > n) {
- /*
- * That'll do.
- */
- break;
- }
- n -= iov->iov_len;
- iov++;
- } while (--iovlen);
- if (iov == start) {
- iovec = *iov++;
-#if 0
- if (iovec.iov_len > n) {
- iovec.iov_len = n;
- }
-#endif
- continue;
- }
- remain = xtvec.xtv_len - n;
- cc =
- (*f)(start, iov - start,
- xtvec.xtv_off,
- xtvec.xtv_len - n,
- arg);
- if (cc <= 0) {
- if (acc)
- return acc;
- return cc;
- }
-
- tmp = cc + acc;
- if (acc && tmp <= acc)
- abort(); /* paranoia */
- acc = tmp;
-
- if (remain && !iovlen)
- return acc;
-
- remain -= cc;
- if (remain)
- return acc; /* short */
- }
- xtvec.xtv_off += cc;
- xtvec.xtv_len -= cc;
- }
- }
- return acc;
-}
-
-ssize_t
-_sysio_enumerate_iovec(const struct iovec *iov, size_t count,
- _SYSIO_OFF_T off,
- ssize_t limit,
- ssize_t (*f)(void *, size_t, _SYSIO_OFF_T, void *),
- void *arg)
-{
- ssize_t acc, cc;
- size_t n;
- unsigned indx;
- size_t remain;
-
- if (!count)
- return -EINVAL;
- assert(limit >= 0);
- acc = 0;
- n = limit;
- for (indx = 0; n && indx < count; indx++) {
- if (iov[indx].iov_len < n) {
- cc = (ssize_t )iov[indx].iov_len;
- if (cc < 0)
- return -EINVAL;
- } else
- cc = (ssize_t )n;
- if (!cc)
- continue;
- n -= cc;
- cc += acc;
- if (acc && cc <= acc)
- return -EINVAL;
- acc = cc;
- }
- if (!acc)
- return 0;
- acc = 0;
- do {
- if (!iov->iov_len) {
- iov++;
- continue;
- }
- n =
- iov->iov_len < (size_t )limit
- ? iov->iov_len
- : (size_t )limit;
- cc = (*f)(iov->iov_base, n, off, arg);
- if (cc <= 0) {
- if (acc)
- return acc;
- return cc;
- }
- off += cc;
- limit -= cc;
- remain = iov->iov_len - cc;
- cc += acc;
- if (acc && cc <= acc)
- abort(); /* bad driver! */
- acc = cc;
- if (remain || !limit)
- break; /* short/limited read */
- iov++;
- } while (--count);
- return acc;
-}
-
-static ssize_t
-_sysio_doio_helper(const struct iovec *iov, int count,
- _SYSIO_OFF_T off,
- ssize_t limit,
- struct doio_helper_args *args)
-{
-
- return _sysio_enumerate_iovec(iov, count,
- off, limit,
- args->f,
- args->arg);
-}
-
-/*
- * A meta-driver for the whole strided-io process. Appropriate when
- * the driver can't handle anything but simple p{read,write}-like
- * interface.
- */
-ssize_t
-_sysio_doio(const struct intnl_xtvec *xtv, size_t xtvlen,
- const struct iovec *iov, size_t iovlen,
- ssize_t (*f)(void *, size_t, _SYSIO_OFF_T, void *),
- void *arg)
-{
- struct doio_helper_args arguments;
-
- arguments.f = f;
- arguments.arg = arg;
- return _sysio_enumerate_extents(xtv, xtvlen,
- iov, iovlen,
- (ssize_t (*)(const struct iovec *, int,
- _SYSIO_OFF_T,
- ssize_t,
- void *))_sysio_doio_helper,
- &arguments);
-}