Home | History | Annotate | Download | only in common
      1  8615  Andrew /*
      2  8615  Andrew  * CDDL HEADER START
      3  8615  Andrew  *
      4  8615  Andrew  * The contents of this file are subject to the terms of the
      5  8615  Andrew  * Common Development and Distribution License (the "License").
      6  8615  Andrew  * You may not use this file except in compliance with the License.
      7  8615  Andrew  *
      8  8615  Andrew  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  8615  Andrew  * or http://www.opensolaris.org/os/licensing.
     10  8615  Andrew  * See the License for the specific language governing permissions
     11  8615  Andrew  * and limitations under the License.
     12  8615  Andrew  *
     13  8615  Andrew  * When distributing Covered Code, include this CDDL HEADER in each
     14  8615  Andrew  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  8615  Andrew  * If applicable, add the following below this CDDL HEADER, with the
     16  8615  Andrew  * fields enclosed by brackets "[]" replaced with your own identifying
     17  8615  Andrew  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  8615  Andrew  *
     19  8615  Andrew  * CDDL HEADER END
     20  8615  Andrew  */
     21  8615  Andrew /*
     22  8615  Andrew  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     23  8615  Andrew  * Use is subject to license terms.
     24  8615  Andrew  *
     25  8615  Andrew  * Portions Copyright 2008 Denis Cheng
     26  8615  Andrew  */
     27  8615  Andrew 
     28  8615  Andrew #include "config.h"
     29  8615  Andrew #include "filebench.h"
     30  8615  Andrew #include "flowop.h"
     31  8615  Andrew #include "threadflow.h" /* For aiolist definition */
     32  8615  Andrew 
     33  8615  Andrew #ifndef HAVE_OFF64_T
     34  8615  Andrew /*
     35  8615  Andrew  * We are probably on linux.
     36  8615  Andrew  * According to http://www.suse.de/~aj/linux_lfs.html, defining the
     37  8615  Andrew  * above, automatically changes type of off_t to off64_t. so let
     38  8615  Andrew  * us use only off_t as off64_t is not defined
     39  8615  Andrew  */
     40  9513  Andrew #define	off64_t off_t
     41  8615  Andrew #endif /* HAVE_OFF64_T */
     42  8615  Andrew 
     43  8615  Andrew #include <fcntl.h>
     44  8615  Andrew #include <stdio.h>
     45  8615  Andrew #include <stdlib.h>
     46  8615  Andrew #include <unistd.h>
     47  8615  Andrew #include <libgen.h>
     48  8615  Andrew #include <sys/mman.h>
     49  8615  Andrew #include <sys/stat.h>
     50  8615  Andrew #include <sys/types.h>
     51  8615  Andrew #include <sys/param.h>
     52  8615  Andrew #include <sys/resource.h>
     53  8615  Andrew 
     54  8615  Andrew #include "filebench.h"
     55  8615  Andrew #include "fsplug.h"
     56  8615  Andrew 
     57  8615  Andrew #ifdef HAVE_AIO
     58  8615  Andrew #include <aio.h>
     59  8615  Andrew #endif /* HAVE_AIO */
     60  8615  Andrew 
     61  8615  Andrew #ifdef HAVE_LIBAIO_H
     62  8615  Andrew #include <libaio.h>
     63  8615  Andrew #endif /* HAVE_LIBAIO_H */
     64  8615  Andrew 
     65  8615  Andrew #ifndef HAVE_AIOCB64_T
     66  8615  Andrew #define	aiocb64 aiocb
     67  8615  Andrew #endif /* HAVE_AIOCB64_T */
     68  8615  Andrew 
     69  8615  Andrew /*
     70  8615  Andrew  * These routines implement local file access. They are placed into a
     71  8615  Andrew  * vector of functions that are called by all I/O operations in fileset.c
     72  8615  Andrew  * and flowop_library.c. This represents the default file system plug-in,
     73  8615  Andrew  * and may be replaced by vectors for other file system plug-ins.
     74  8615  Andrew  */
     75  8615  Andrew 
     76  8615  Andrew static int fb_lfs_freemem(fb_fdesc_t *fd, off64_t size);
     77  8615  Andrew static int fb_lfs_open(fb_fdesc_t *, char *, int, int);
     78  8615  Andrew static int fb_lfs_pread(fb_fdesc_t *, caddr_t, fbint_t, off64_t);
     79  8615  Andrew static int fb_lfs_read(fb_fdesc_t *, caddr_t, fbint_t);
     80  8615  Andrew static int fb_lfs_pwrite(fb_fdesc_t *, caddr_t, fbint_t, off64_t);
     81  8615  Andrew static int fb_lfs_write(fb_fdesc_t *, caddr_t, fbint_t);
     82  8615  Andrew static int fb_lfs_lseek(fb_fdesc_t *, off64_t, int);
     83  8615  Andrew static int fb_lfs_truncate(fb_fdesc_t *, off64_t);
     84  8615  Andrew static int fb_lfs_rename(const char *, const char *);
     85  8615  Andrew static int fb_lfs_close(fb_fdesc_t *);
     86  8615  Andrew static int fb_lfs_link(const char *, const char *);
     87  8615  Andrew static int fb_lfs_symlink(const char *, const char *);
     88  8615  Andrew static int fb_lfs_unlink(char *);
     89  8615  Andrew static ssize_t fb_lfs_readlink(const char *, char *, size_t);
     90  8615  Andrew static int fb_lfs_mkdir(char *, int);
     91  8615  Andrew static int fb_lfs_rmdir(char *);
     92  8615  Andrew static DIR *fb_lfs_opendir(char *);
     93  8615  Andrew static struct dirent *fb_lfs_readdir(DIR *);
     94  8615  Andrew static int fb_lfs_closedir(DIR *);
     95  8615  Andrew static int fb_lfs_fsync(fb_fdesc_t *);
     96  8615  Andrew static int fb_lfs_stat(char *, struct stat64 *);
     97  8615  Andrew static int fb_lfs_fstat(fb_fdesc_t *, struct stat64 *);
     98  8615  Andrew static int fb_lfs_access(const char *, int);
     99  9356  Andrew static void fb_lfs_recur_rm(char *);
    100  8615  Andrew 
    101  8615  Andrew static fsplug_func_t fb_lfs_funcs =
    102  8615  Andrew {
    103  8615  Andrew 	"locfs",
    104  8615  Andrew 	fb_lfs_freemem,		/* flush page cache */
    105  8615  Andrew 	fb_lfs_open,		/* open */
    106  8615  Andrew 	fb_lfs_pread,		/* pread */
    107  8615  Andrew 	fb_lfs_read,		/* read */
    108  8615  Andrew 	fb_lfs_pwrite,		/* pwrite */
    109  8615  Andrew 	fb_lfs_write,		/* write */
    110  8615  Andrew 	fb_lfs_lseek,		/* lseek */
    111  8615  Andrew 	fb_lfs_truncate,	/* ftruncate */
    112  8615  Andrew 	fb_lfs_rename,		/* rename */
    113  8615  Andrew 	fb_lfs_close,		/* close */
    114  8615  Andrew 	fb_lfs_link,		/* link */
    115  8615  Andrew 	fb_lfs_symlink,		/* symlink */
    116  8615  Andrew 	fb_lfs_unlink,		/* unlink */
    117  8615  Andrew 	fb_lfs_readlink,	/* readlink */
    118  8615  Andrew 	fb_lfs_mkdir,		/* mkdir */
    119  8615  Andrew 	fb_lfs_rmdir,		/* rmdir */
    120  8615  Andrew 	fb_lfs_opendir,		/* opendir */
    121  8615  Andrew 	fb_lfs_readdir,		/* readdir */
    122  8615  Andrew 	fb_lfs_closedir,	/* closedir */
    123  8615  Andrew 	fb_lfs_fsync,		/* fsync */
    124  8615  Andrew 	fb_lfs_stat,		/* stat */
    125  8615  Andrew 	fb_lfs_fstat,		/* fstat */
    126  9356  Andrew 	fb_lfs_access,		/* access */
    127  9356  Andrew 	fb_lfs_recur_rm		/* recursive rm */
    128  8615  Andrew };
    129  8615  Andrew 
    130  8615  Andrew #ifdef HAVE_AIO
    131  8615  Andrew /*
    132  8615  Andrew  * Local file system asynchronous IO flowops are in this module, as
    133  8615  Andrew  * they have a number of local file system specific features.
    134  8615  Andrew  */
    135  8615  Andrew static int fb_lfsflow_aiowrite(threadflow_t *threadflow, flowop_t *flowop);
    136  8615  Andrew static int fb_lfsflow_aiowait(threadflow_t *threadflow, flowop_t *flowop);
    137  8615  Andrew 
    138  8615  Andrew static flowop_proto_t fb_lfsflow_funcs[] = {
    139  8615  Andrew 	FLOW_TYPE_AIO, FLOW_ATTR_WRITE, "aiowrite", flowop_init_generic,
    140  8615  Andrew 	fb_lfsflow_aiowrite, flowop_destruct_generic,
    141  8615  Andrew 	FLOW_TYPE_AIO, 0, "aiowait", flowop_init_generic,
    142  8615  Andrew 	fb_lfsflow_aiowait, flowop_destruct_generic
    143  8615  Andrew };
    144  8615  Andrew 
    145  8615  Andrew #endif /* HAVE_AIO */
    146  8615  Andrew 
    147  8615  Andrew /*
    148  8615  Andrew  * Initialize this processes I/O functions vector to point to
    149  8615  Andrew  * the vector of local file system I/O functions
    150  8615  Andrew  */
    151  8615  Andrew void
    152  8615  Andrew fb_lfs_funcvecinit(void)
    153  8615  Andrew {
    154  8615  Andrew 	fs_functions_vec = &fb_lfs_funcs;
    155  8615  Andrew }
    156  8615  Andrew 
    157  8615  Andrew /*
    158  8615  Andrew  * Initialize those flowops whose implementation is file system
    159  8615  Andrew  * specific.
    160  8615  Andrew  */
    161  8615  Andrew void
    162  8615  Andrew fb_lfs_flowinit(void)
    163  8615  Andrew {
    164  8615  Andrew 	int nops;
    165  8615  Andrew 
    166  8615  Andrew 	/*
    167  8615  Andrew 	 * re-initialize the I/O functions vector while we are at
    168  8615  Andrew 	 * it as it may have been redefined since the process was
    169  8615  Andrew 	 * created, at least if this is the master processes
    170  8615  Andrew 	 */
    171  8615  Andrew 	fb_lfs_funcvecinit();
    172  8615  Andrew 
    173  8615  Andrew #ifdef HAVE_AIO
    174  8615  Andrew 	nops = sizeof (fb_lfsflow_funcs) / sizeof (flowop_proto_t);
    175  8615  Andrew 	flowop_flow_init(fb_lfsflow_funcs, nops);
    176  8615  Andrew #endif /* HAVE_AIO */
    177  8615  Andrew }
    178  8615  Andrew 
    179  8615  Andrew /*
    180  8615  Andrew  * Frees up memory mapped file region of supplied size. The
    181  8615  Andrew  * file descriptor "fd" indicates which memory mapped file.
    182  8615  Andrew  * If successful, returns 0. Otherwise returns -1 if "size"
    183  8615  Andrew  * is zero, or -1 times the number of times msync() failed.
    184  8615  Andrew  */
    185  8615  Andrew static int
    186  8615  Andrew fb_lfs_freemem(fb_fdesc_t *fd, off64_t size)
    187  8615  Andrew {
    188  8615  Andrew 	off64_t left;
    189  8615  Andrew 	int ret = 0;
    190  8615  Andrew 
    191  8615  Andrew 	for (left = size; left > 0; left -= MMAP_SIZE) {
    192  8615  Andrew 		off64_t thismapsize;
    193  8615  Andrew 		caddr_t addr;
    194  8615  Andrew 
    195  8615  Andrew 		thismapsize = MIN(MMAP_SIZE, left);
    196  8615  Andrew 		addr = mmap64(0, thismapsize, PROT_READ|PROT_WRITE,
    197  8615  Andrew 		    MAP_SHARED, fd->fd_num, size - left);
    198  8615  Andrew 		ret += msync(addr, thismapsize, MS_INVALIDATE);
    199  8615  Andrew 		(void) munmap(addr, thismapsize);
    200  8615  Andrew 	}
    201  8615  Andrew 	return (ret);
    202  8615  Andrew }
    203  8615  Andrew 
    204  8615  Andrew /*
    205  8615  Andrew  * Does a posix pread. Returns what the pread() returns.
    206  8615  Andrew  */
    207  8615  Andrew static int
    208  8615  Andrew fb_lfs_pread(fb_fdesc_t *fd, caddr_t iobuf, fbint_t iosize, off64_t fileoffset)
    209  8615  Andrew {
    210  8615  Andrew 	return (pread64(fd->fd_num, iobuf, iosize, fileoffset));
    211  8615  Andrew }
    212  8615  Andrew 
    213  8615  Andrew /*
    214  8615  Andrew  * Does a posix read. Returns what the read() returns.
    215  8615  Andrew  */
    216  8615  Andrew static int
    217  8615  Andrew fb_lfs_read(fb_fdesc_t *fd, caddr_t iobuf, fbint_t iosize)
    218  8615  Andrew {
    219  8615  Andrew 	return (read(fd->fd_num, iobuf, iosize));
    220  8615  Andrew }
    221  8615  Andrew 
    222  8615  Andrew #ifdef HAVE_AIO
    223  8615  Andrew 
    224  8615  Andrew /*
    225  8615  Andrew  * Asynchronous write section. An Asynchronous IO element
    226  8615  Andrew  * (aiolist_t) is used to associate the asynchronous write request with
    227  8615  Andrew  * its subsequent completion. This element includes a aiocb64 struct
    228  8615  Andrew  * that is used by posix aio_xxx calls to track the asynchronous writes.
    229  8615  Andrew  * The flowops aiowrite and aiowait result in calls to these posix
    230  8615  Andrew  * aio_xxx system routines to do the actual asynchronous write IO
    231  8615  Andrew  * operations.
    232  8615  Andrew  */
    233  8615  Andrew 
    234  8615  Andrew 
    235  8615  Andrew /*
    236  8615  Andrew  * Allocates an asynchronous I/O list (aio, of type
    237  8615  Andrew  * aiolist_t) element. Adds it to the flowop thread's
    238  8615  Andrew  * threadflow aio list. Returns a pointer to the element.
    239  8615  Andrew  */
    240  8615  Andrew static aiolist_t *
    241  8615  Andrew aio_allocate(flowop_t *flowop)
    242  8615  Andrew {
    243  8615  Andrew 	aiolist_t *aiolist;
    244  8615  Andrew 
    245  8615  Andrew 	if ((aiolist = malloc(sizeof (aiolist_t))) == NULL) {
    246  8615  Andrew 		filebench_log(LOG_ERROR, "malloc aiolist failed");
    247  8615  Andrew 		filebench_shutdown(1);
    248  8615  Andrew 	}
    249  8615  Andrew 
    250  8615  Andrew 	/* Add to list */
    251  8615  Andrew 	if (flowop->fo_thread->tf_aiolist == NULL) {
    252  8615  Andrew 		flowop->fo_thread->tf_aiolist = aiolist;
    253  8615  Andrew 		aiolist->al_next = NULL;
    254  8615  Andrew 	} else {
    255  8615  Andrew 		aiolist->al_next = flowop->fo_thread->tf_aiolist;
    256  8615  Andrew 		flowop->fo_thread->tf_aiolist = aiolist;
    257  8615  Andrew 	}
    258  8615  Andrew 	return (aiolist);
    259  8615  Andrew }
    260  8615  Andrew 
    261  8615  Andrew /*
    262  8615  Andrew  * Searches for the aiolist element that has a matching
    263  8615  Andrew  * completion block, aiocb. If none found returns FILEBENCH_ERROR. If
    264  8615  Andrew  * found, removes the aiolist element from flowop thread's
    265  8615  Andrew  * list and returns FILEBENCH_OK.
    266  8615  Andrew  */
    267  8615  Andrew static int
    268  8615  Andrew aio_deallocate(flowop_t *flowop, struct aiocb64 *aiocb)
    269  8615  Andrew {
    270  8615  Andrew 	aiolist_t *aiolist = flowop->fo_thread->tf_aiolist;
    271  8615  Andrew 	aiolist_t *previous = NULL;
    272  8615  Andrew 	aiolist_t *match = NULL;
    273  8615  Andrew 
    274  8615  Andrew 	if (aiocb == NULL) {
    275  8615  Andrew 		filebench_log(LOG_ERROR, "null aiocb deallocate");
    276  8615  Andrew 		return (FILEBENCH_OK);
    277  8615  Andrew 	}
    278  8615  Andrew 
    279  8615  Andrew 	while (aiolist) {
    280  8615  Andrew 		if (aiocb == &(aiolist->al_aiocb)) {
    281  8615  Andrew 			match = aiolist;
    282  8615  Andrew 			break;
    283  8615  Andrew 		}
    284  8615  Andrew 		previous = aiolist;
    285  8615  Andrew 		aiolist = aiolist->al_next;
    286  8615  Andrew 	}
    287  8615  Andrew 
    288  8615  Andrew 	if (match == NULL)
    289  8615  Andrew 		return (FILEBENCH_ERROR);
    290  8615  Andrew 
    291  8615  Andrew 	/* Remove from the list */
    292  8615  Andrew 	if (previous)
    293  8615  Andrew 		previous->al_next = match->al_next;
    294  8615  Andrew 	else
    295  8615  Andrew 		flowop->fo_thread->tf_aiolist = match->al_next;
    296  8615  Andrew 
    297  8615  Andrew 	return (FILEBENCH_OK);
    298  8615  Andrew }
    299  8615  Andrew 
    300  8615  Andrew /*
    301  8615  Andrew  * Emulate posix aiowrite(). Determines which file to use,
    302  8615  Andrew  * either one file of a fileset, or the file associated
    303  8615  Andrew  * with a fileobj, allocates and fills an aiolist_t element
    304  8615  Andrew  * for the write, and issues the asynchronous write. This
    305  8615  Andrew  * operation is only valid for random IO, and returns an
    306  8615  Andrew  * error if the flowop is set for sequential IO. Returns
    307  8615  Andrew  * FILEBENCH_OK on success, FILEBENCH_NORSC if iosetup can't
    308  8615  Andrew  * obtain a file to open, and FILEBENCH_ERROR on any
    309  8615  Andrew  * encountered error.
    310  8615  Andrew  */
    311  8615  Andrew static int
    312  8615  Andrew fb_lfsflow_aiowrite(threadflow_t *threadflow, flowop_t *flowop)
    313  8615  Andrew {
    314  8615  Andrew 	caddr_t iobuf;
    315  8615  Andrew 	fbint_t wss;
    316  8615  Andrew 	fbint_t iosize;
    317  8615  Andrew 	fb_fdesc_t *fdesc;
    318  8615  Andrew 	int ret;
    319  8615  Andrew 
    320  8615  Andrew 	iosize = avd_get_int(flowop->fo_iosize);
    321  8615  Andrew 
    322  8615  Andrew 	if ((ret = flowoplib_iosetup(threadflow, flowop, &wss, &iobuf,
    323  8615  Andrew 	    &fdesc, iosize)) != FILEBENCH_OK)
    324  8615  Andrew 		return (ret);
    325  8615  Andrew 
    326  8615  Andrew 	if (avd_get_bool(flowop->fo_random)) {
    327  8615  Andrew 		uint64_t fileoffset;
    328  8615  Andrew 		struct aiocb64 *aiocb;
    329  8615  Andrew 		aiolist_t *aiolist;
    330  8615  Andrew 
    331  8615  Andrew 		if (filebench_randomno64(&fileoffset,
    332  8615  Andrew 		    wss, iosize, NULL) == -1) {
    333  8615  Andrew 			filebench_log(LOG_ERROR,
    334  8615  Andrew 			    "file size smaller than IO size for thread %s",
    335  8615  Andrew 			    flowop->fo_name);
    336  8615  Andrew 			return (FILEBENCH_ERROR);
    337  8615  Andrew 		}
    338  8615  Andrew 
    339  8615  Andrew 		aiolist = aio_allocate(flowop);
    340  8615  Andrew 		aiolist->al_type = AL_WRITE;
    341  8615  Andrew 		aiocb = &aiolist->al_aiocb;
    342  8615  Andrew 
    343  8615  Andrew 		aiocb->aio_fildes = fdesc->fd_num;
    344  8615  Andrew 		aiocb->aio_buf = iobuf;
    345  8615  Andrew 		aiocb->aio_nbytes = (size_t)iosize;
    346  8615  Andrew 		aiocb->aio_offset = (off64_t)fileoffset;
    347  8615  Andrew 		aiocb->aio_reqprio = 0;
    348  8615  Andrew 
    349  8615  Andrew 		filebench_log(LOG_DEBUG_IMPL,
    350  8615  Andrew 		    "aio fd=%d, bytes=%llu, offset=%llu",
    351  8615  Andrew 		    fdesc->fd_num, (u_longlong_t)iosize,
    352  8615  Andrew 		    (u_longlong_t)fileoffset);
    353  8615  Andrew 
    354  8615  Andrew 		flowop_beginop(threadflow, flowop);
    355  8615  Andrew 		if (aio_write64(aiocb) < 0) {
    356  8615  Andrew 			filebench_log(LOG_ERROR, "aiowrite failed: %s",
    357  8615  Andrew 			    strerror(errno));
    358  8615  Andrew 			filebench_shutdown(1);
    359  8615  Andrew 		}
    360  8615  Andrew 		flowop_endop(threadflow, flowop, iosize);
    361  8615  Andrew 	} else {
    362  8615  Andrew 		return (FILEBENCH_ERROR);
    363  8615  Andrew 	}
    364  8615  Andrew 
    365  8615  Andrew 	return (FILEBENCH_OK);
    366  8615  Andrew }
    367  8615  Andrew 
    368  8615  Andrew 
    369  8615  Andrew 
    370  8615  Andrew #define	MAXREAP 4096
    371  8615  Andrew 
    372  8615  Andrew /*
    373  8615  Andrew  * Emulate posix aiowait(). Waits for the completion of half the
    374  8615  Andrew  * outstanding asynchronous IOs, or a single IO, which ever is
    375  8615  Andrew  * larger. The routine will return after a sufficient number of
    376  8615  Andrew  * completed calls issued by any thread in the procflow have
    377  8615  Andrew  * completed, or a 1 second timout elapses. All completed
    378  8615  Andrew  * IO operations are deleted from the thread's aiolist.
    379  8615  Andrew  */
    380  8615  Andrew static int
    381  8615  Andrew fb_lfsflow_aiowait(threadflow_t *threadflow, flowop_t *flowop)
    382  8615  Andrew {
    383  8615  Andrew 	struct aiocb64 **worklist;
    384  8615  Andrew 	aiolist_t *aio = flowop->fo_thread->tf_aiolist;
    385  8615  Andrew 	int uncompleted = 0;
    386  8615  Andrew 
    387  8615  Andrew 	worklist = calloc(MAXREAP, sizeof (struct aiocb64 *));
    388  8615  Andrew 
    389  8615  Andrew 	/* Count the list of pending aios */
    390  8615  Andrew 	while (aio) {
    391  8615  Andrew 		uncompleted++;
    392  8615  Andrew 		aio = aio->al_next;
    393  8615  Andrew 	}
    394  8615  Andrew 
    395  8615  Andrew 	do {
    396  8615  Andrew 		uint_t ncompleted = 0;
    397  8615  Andrew 		uint_t todo;
    398  8615  Andrew 		struct timespec timeout;
    399  8615  Andrew 		int inprogress;
    400  8615  Andrew 		int i;
    401  8615  Andrew 
    402  8615  Andrew 		/* Wait for half of the outstanding requests */
    403  8615  Andrew 		timeout.tv_sec = 1;
    404  8615  Andrew 		timeout.tv_nsec = 0;
    405  8615  Andrew 
    406  8615  Andrew 		if (uncompleted > MAXREAP)
    407  8615  Andrew 			todo = MAXREAP;
    408  8615  Andrew 		else
    409  8615  Andrew 			todo = uncompleted / 2;
    410  8615  Andrew 
    411  8615  Andrew 		if (todo == 0)
    412  8615  Andrew 			todo = 1;
    413  8615  Andrew 
    414  8615  Andrew 		flowop_beginop(threadflow, flowop);
    415  8615  Andrew 
    416  8762  Andrew #if (defined(HAVE_AIOWAITN) && defined(USE_PROCESS_MODEL))
    417  8615  Andrew 		if (((aio_waitn64((struct aiocb64 **)worklist,
    418  8615  Andrew 		    MAXREAP, &todo, &timeout)) == -1) &&
    419  8615  Andrew 		    errno && (errno != ETIME)) {
    420  8615  Andrew 			filebench_log(LOG_ERROR,
    421  8615  Andrew 			    "aiowait failed: %s, outstanding = %d, "
    422  8615  Andrew 			    "ncompleted = %d ",
    423  8615  Andrew 			    strerror(errno), uncompleted, todo);
    424  8615  Andrew 		}
    425  8615  Andrew 
    426  8615  Andrew 		ncompleted = todo;
    427  8615  Andrew 		/* Take the  completed I/Os from the list */
    428  8615  Andrew 		inprogress = 0;
    429  8615  Andrew 		for (i = 0; i < ncompleted; i++) {
    430  8615  Andrew 			if ((aio_return64(worklist[i]) == -1) &&
    431  8615  Andrew 			    (errno == EINPROGRESS)) {
    432  8615  Andrew 				inprogress++;
    433  8615  Andrew 				continue;
    434  8615  Andrew 			}
    435  8615  Andrew 			if (aio_deallocate(flowop, worklist[i])
    436  8615  Andrew 			    == FILEBENCH_ERROR) {
    437  8615  Andrew 				filebench_log(LOG_ERROR, "Could not remove "
    438  8615  Andrew 				    "aio from list ");
    439  8615  Andrew 				flowop_endop(threadflow, flowop, 0);
    440  8615  Andrew 				return (FILEBENCH_ERROR);
    441  8615  Andrew 			}
    442  8615  Andrew 		}
    443  8615  Andrew 
    444  8615  Andrew 		uncompleted -= ncompleted;
    445  8615  Andrew 		uncompleted += inprogress;
    446  8615  Andrew 
    447  8615  Andrew #else
    448  8615  Andrew 
    449  8615  Andrew 		for (ncompleted = 0, inprogress = 0,
    450  8615  Andrew 		    aio = flowop->fo_thread->tf_aiolist;
    451  8615  Andrew 		    ncompleted < todo, aio != NULL; aio = aio->al_next) {
    452  8762  Andrew 			int result = aio_error64(&aio->al_aiocb);
    453  8615  Andrew 
    454  8615  Andrew 			if (result == EINPROGRESS) {
    455  8615  Andrew 				inprogress++;
    456  8615  Andrew 				continue;
    457  8615  Andrew 			}
    458  8615  Andrew 
    459  8762  Andrew 			if ((aio_return64(&aio->al_aiocb) == -1) || result) {
    460  8615  Andrew 				filebench_log(LOG_ERROR, "aio failed: %s",
    461  8615  Andrew 				    strerror(result));
    462  8615  Andrew 				continue;
    463  8615  Andrew 			}
    464  8615  Andrew 
    465  8615  Andrew 			ncompleted++;
    466  8615  Andrew 
    467  8615  Andrew 			if (aio_deallocate(flowop, &aio->al_aiocb) < 0) {
    468  8615  Andrew 				filebench_log(LOG_ERROR, "Could not remove "
    469  8762  Andrew 				    "aio from list ");
    470  8615  Andrew 				flowop_endop(threadflow, flowop, 0);
    471  8615  Andrew 				return (FILEBENCH_ERROR);
    472  8615  Andrew 			}
    473  8615  Andrew 		}
    474  8615  Andrew 
    475  8615  Andrew 		uncompleted -= ncompleted;
    476  8615  Andrew 
    477  8615  Andrew #endif
    478  8615  Andrew 		filebench_log(LOG_DEBUG_SCRIPT,
    479  8615  Andrew 		    "aio2 completed %d ios, uncompleted = %d, inprogress = %d",
    480  8615  Andrew 		    ncompleted, uncompleted, inprogress);
    481  8615  Andrew 
    482  8615  Andrew 	} while (uncompleted > MAXREAP);
    483  8615  Andrew 
    484  8615  Andrew 	flowop_endop(threadflow, flowop, 0);
    485  8615  Andrew 
    486  8615  Andrew 	free(worklist);
    487  8615  Andrew 
    488  8615  Andrew 	return (FILEBENCH_OK);
    489  8615  Andrew }
    490  8615  Andrew 
    491  8615  Andrew #endif /* HAVE_AIO */
    492  8615  Andrew 
    493  8615  Andrew /*
    494  8615  Andrew  * Does an open64 of a file. Inserts the file descriptor number returned
    495  8615  Andrew  * by open() into the supplied filebench fd. Returns FILEBENCH_OK on
    496  8615  Andrew  * successs, and FILEBENCH_ERROR on failure.
    497  8615  Andrew  */
    498  8615  Andrew 
    499  8615  Andrew static int
    500  8615  Andrew fb_lfs_open(fb_fdesc_t *fd, char *path, int flags, int perms)
    501  8615  Andrew {
    502  8615  Andrew 	if ((fd->fd_num = open64(path, flags, perms)) < 0)
    503  8615  Andrew 		return (FILEBENCH_ERROR);
    504  8615  Andrew 	else
    505  8615  Andrew 		return (FILEBENCH_OK);
    506  8615  Andrew }
    507  8615  Andrew 
    508  8615  Andrew /*
    509  8615  Andrew  * Does an unlink (delete) of a file.
    510  8615  Andrew  */
    511  8615  Andrew static int
    512  8615  Andrew fb_lfs_unlink(char *path)
    513  8615  Andrew {
    514  8615  Andrew 	return (unlink(path));
    515  8615  Andrew }
    516  8615  Andrew 
    517  8615  Andrew /*
    518  8615  Andrew  * Does a readlink of a symbolic link.
    519  8615  Andrew  */
    520  8615  Andrew static ssize_t
    521  8615  Andrew fb_lfs_readlink(const char *path, char *buf, size_t buf_size)
    522  8615  Andrew {
    523  8615  Andrew 	return (readlink(path, buf, buf_size));
    524  8615  Andrew }
    525  8615  Andrew 
    526  8615  Andrew /*
    527  8615  Andrew  * Does fsync of a file. Returns with fsync return info.
    528  8615  Andrew  */
    529  8615  Andrew static int
    530  8615  Andrew fb_lfs_fsync(fb_fdesc_t *fd)
    531  8615  Andrew {
    532  8615  Andrew 	return (fsync(fd->fd_num));
    533  8615  Andrew }
    534  8615  Andrew 
    535  8615  Andrew /*
    536  8615  Andrew  * Do a posix lseek of a file. Return what lseek() returns.
    537  8615  Andrew  */
    538  8615  Andrew static int
    539  8615  Andrew fb_lfs_lseek(fb_fdesc_t *fd, off64_t offset, int whence)
    540  8615  Andrew {
    541  8615  Andrew 	return (lseek64(fd->fd_num, offset, whence));
    542  8615  Andrew }
    543  8615  Andrew 
    544  8615  Andrew /*
    545  8615  Andrew  * Do a posix rename of a file. Return what rename() returns.
    546  8615  Andrew  */
    547  8615  Andrew static int
    548  8615  Andrew fb_lfs_rename(const char *old, const char *new)
    549  8615  Andrew {
    550  8615  Andrew 	return (rename(old, new));
    551  8615  Andrew }
    552  8615  Andrew 
    553  8615  Andrew 
    554  8615  Andrew /*
    555  8615  Andrew  * Do a posix close of a file. Return what close() returns.
    556  8615  Andrew  */
    557  8615  Andrew static int
    558  8615  Andrew fb_lfs_close(fb_fdesc_t *fd)
    559  8615  Andrew {
    560  8615  Andrew 	return (close(fd->fd_num));
    561  8615  Andrew }
    562  8615  Andrew 
    563  8615  Andrew /*
    564  8615  Andrew  * Use mkdir to create a directory.
    565  8615  Andrew  */
    566  8615  Andrew static int
    567  8615  Andrew fb_lfs_mkdir(char *path, int perm)
    568  8615  Andrew {
    569  8615  Andrew 	return (mkdir(path, perm));
    570  8615  Andrew }
    571  8615  Andrew 
    572  8615  Andrew /*
    573  8615  Andrew  * Use rmdir to delete a directory. Returns what rmdir() returns.
    574  8615  Andrew  */
    575  8615  Andrew static int
    576  8615  Andrew fb_lfs_rmdir(char *path)
    577  8615  Andrew {
    578  8615  Andrew 	return (rmdir(path));
    579  8615  Andrew }
    580  8615  Andrew 
    581  8615  Andrew /*
    582  9356  Andrew  * does a recursive rm to remove an entire directory tree (i.e. a fileset).
    583  9356  Andrew  * Supplied with the path to the root of the tree.
    584  9356  Andrew  */
    585  9356  Andrew static void
    586  9356  Andrew fb_lfs_recur_rm(char *path)
    587  9356  Andrew {
    588  9356  Andrew 	char cmd[MAXPATHLEN];
    589  9356  Andrew 
    590  9356  Andrew 	(void) snprintf(cmd, sizeof (cmd), "rm -rf %s", path);
    591  9356  Andrew 	(void) system(cmd);
    592  9356  Andrew }
    593  9356  Andrew 
    594  9356  Andrew /*
    595  8615  Andrew  * Does a posix opendir(), Returns a directory handle on success,
    596  8615  Andrew  * NULL on failure.
    597  8615  Andrew  */
    598  8615  Andrew static DIR *
    599  8615  Andrew fb_lfs_opendir(char *path)
    600  8615  Andrew {
    601  8615  Andrew 	return (opendir(path));
    602  8615  Andrew }
    603  8615  Andrew 
    604  8615  Andrew /*
    605  8615  Andrew  * Does a readdir() call. Returns a pointer to a table of directory
    606  8615  Andrew  * information on success, NULL on failure.
    607  8615  Andrew  */
    608  8615  Andrew static struct dirent *
    609  8615  Andrew fb_lfs_readdir(DIR *dirp)
    610  8615  Andrew {
    611  8615  Andrew 	return (readdir(dirp));
    612  8615  Andrew }
    613  8615  Andrew 
    614  8615  Andrew /*
    615  8615  Andrew  * Does a closedir() call.
    616  8615  Andrew  */
    617  8615  Andrew static int
    618  8615  Andrew fb_lfs_closedir(DIR *dirp)
    619  8615  Andrew {
    620  8615  Andrew 	return (closedir(dirp));
    621  8615  Andrew }
    622  8615  Andrew 
    623  8615  Andrew /*
    624  8615  Andrew  * Does an fstat of a file.
    625  8615  Andrew  */
    626  8615  Andrew static int
    627  8615  Andrew fb_lfs_fstat(fb_fdesc_t *fd, struct stat64 *statbufp)
    628  8615  Andrew {
    629  8615  Andrew 	return (fstat64(fd->fd_num, statbufp));
    630  8615  Andrew }
    631  8615  Andrew 
    632  8615  Andrew /*
    633  8615  Andrew  * Does a stat of a file.
    634  8615  Andrew  */
    635  8615  Andrew static int
    636  8615  Andrew fb_lfs_stat(char *path, struct stat64 *statbufp)
    637  8615  Andrew {
    638  8615  Andrew 	return (stat64(path, statbufp));
    639  8615  Andrew }
    640  8615  Andrew 
    641  8615  Andrew /*
    642  8615  Andrew  * Do a pwrite64 to a file.
    643  8615  Andrew  */
    644  8615  Andrew static int
    645  8615  Andrew fb_lfs_pwrite(fb_fdesc_t *fd, caddr_t iobuf, fbint_t iosize, off64_t offset)
    646  8615  Andrew {
    647  8615  Andrew 	return (pwrite64(fd->fd_num, iobuf, iosize, offset));
    648  8615  Andrew }
    649  8615  Andrew 
    650  8615  Andrew /*
    651  8615  Andrew  * Do a write to a file.
    652  8615  Andrew  */
    653  8615  Andrew static int
    654  8615  Andrew fb_lfs_write(fb_fdesc_t *fd, caddr_t iobuf, fbint_t iosize)
    655  8615  Andrew {
    656  8615  Andrew 	return (write(fd->fd_num, iobuf, iosize));
    657  8615  Andrew }
    658  8615  Andrew 
    659  8615  Andrew /*
    660  8615  Andrew  * Does a truncate operation and returns the result
    661  8615  Andrew  */
    662  8615  Andrew static int
    663  8615  Andrew fb_lfs_truncate(fb_fdesc_t *fd, off64_t fse_size)
    664  8615  Andrew {
    665  8615  Andrew #ifdef HAVE_FTRUNCATE64
    666  8615  Andrew 	return (ftruncate64(fd->fd_num, fse_size));
    667  8615  Andrew #else
    668  8615  Andrew 	return (ftruncate(fd->fd_num, (off_t)fse_size));
    669  8615  Andrew #endif
    670  8615  Andrew }
    671  8615  Andrew 
    672  8615  Andrew /*
    673  8615  Andrew  * Does a link operation and returns the result
    674  8615  Andrew  */
    675  8615  Andrew static int
    676  8615  Andrew fb_lfs_link(const char *existing, const char *new)
    677  8615  Andrew {
    678  8615  Andrew 	return (link(existing, new));
    679  8615  Andrew }
    680  8615  Andrew 
    681  8615  Andrew /*
    682  8615  Andrew  * Does a symlink operation and returns the result
    683  8615  Andrew  */
    684  8615  Andrew static int
    685  8615  Andrew fb_lfs_symlink(const char *existing, const char *new)
    686  8615  Andrew {
    687  8615  Andrew 	return (symlink(existing, new));
    688  8615  Andrew }
    689  8615  Andrew 
    690  8615  Andrew /*
    691  8615  Andrew  * Does an access() check on a file.
    692  8615  Andrew  */
    693  8615  Andrew static int
    694  8615  Andrew fb_lfs_access(const char *path, int amode)
    695  8615  Andrew {
    696  8615  Andrew 	return (access(path, amode));
    697  8615  Andrew }
    698