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