/* * mlock_shim() * if mlock2 is available, randonly exerise this * or mlock. If not available, just fallback to * mlock. Also, pick random mlock2 flags */ static int mlock_shim(const void *addr, size_t len) { static bool use_mlock2 = true; if (use_mlock2) { uint32_t rnd = mwc32() >> 5; /* Randomly use mlock2 or mlock */ if (rnd & 1) { const int flags = (rnd & 2) ? 0 : MLOCK_ONFAULT; int ret; ret = sys_mlock2(addr, len, flags); if (!ret) return 0; if (errno != ENOSYS) return ret; /* mlock2 not supported... */ use_mlock2 = false; } } /* Just do mlock */ return mlock(addr, len); }
/* * stress_sendfile * stress reading of a temp file and writing to /dev/null via sendfile */ int stress_sendfile( uint64_t *const counter, const uint32_t instance, const uint64_t max_ops, const char *name) { char filename[PATH_MAX]; int fdin, fdout, ret = EXIT_SUCCESS; size_t sz; const pid_t pid = getpid(); if (!set_sendfile_size) { if (opt_flags & OPT_FLAGS_MAXIMIZE) opt_sendfile_size = MAX_SENDFILE_SIZE; if (opt_flags & OPT_FLAGS_MINIMIZE) opt_sendfile_size = MIN_SENDFILE_SIZE; } sz = (size_t)opt_sendfile_size; if (stress_temp_dir_mk(name, pid, instance) < 0) return EXIT_FAILURE; (void)umask(0077); (void)stress_temp_filename(filename, sizeof(filename), name, pid, instance, mwc32()); if ((fdin = open(filename, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR)) < 0) { pr_fail_err(name, "open"); ret = EXIT_FAILURE; goto dir_out; } (void)posix_fallocate(fdin, (off_t)0, (off_t)sz); if ((fdout = open("/dev/null", O_WRONLY)) < 0) { pr_fail_err(name, "open"); ret = EXIT_FAILURE; goto close_in; } do { off_t offset = 0; if (sendfile(fdout, fdin, &offset, sz) < 0) { pr_fail_err(name, "sendfile"); ret = EXIT_FAILURE; goto close_out; } (*counter)++; } while (opt_do_run && (!max_ops || *counter < max_ops)); close_out: (void)close(fdout); close_in: (void)close(fdin); (void)unlink(filename); dir_out: (void)stress_temp_dir_rm(name, pid, instance); return ret; }
/* * madvise_random() * apply random madvise setting to a memory region */ int madvise_random(void *addr, const size_t length) { #if !defined(__gnu_hurd__) if (opt_flags & OPT_FLAGS_MMAP_MADVISE) { int i = (mwc32() >> 7) % SIZEOF_ARRAY(madvise_options); return madvise(addr, length, madvise_options[i]); }
/* * stress_lsearch() * stress lsearch */ static int stress_lsearch(const args_t *args) { int32_t *data, *root; size_t i, max; uint64_t lsearch_size = DEFAULT_LSEARCH_SIZE; if (!get_setting("lsearch-size", &lsearch_size)) { if (g_opt_flags & OPT_FLAGS_MAXIMIZE) lsearch_size = MAX_LSEARCH_SIZE; if (g_opt_flags & OPT_FLAGS_MINIMIZE) lsearch_size = MIN_LSEARCH_SIZE; } max = (size_t)lsearch_size; if ((data = calloc(max, sizeof(*data))) == NULL) { pr_fail_dbg("malloc"); return EXIT_NO_RESOURCE; } if ((root = calloc(max, sizeof(*data))) == NULL) { free(data); pr_fail_dbg("malloc"); return EXIT_NO_RESOURCE; } do { size_t n = 0; /* Step #1, populate with data */ for (i = 0; g_keep_stressing_flag && i < max; i++) { void *ptr; data[i] = ((mwc32() & 0xfff) << 20) ^ i; ptr = lsearch(&data[i], root, &n, sizeof(*data), cmp); (void)ptr; } /* Step #2, find */ for (i = 0; g_keep_stressing_flag && i < n; i++) { int32_t *result; result = lfind(&data[i], root, &n, sizeof(*data), cmp); if (g_opt_flags & OPT_FLAGS_VERIFY) { if (result == NULL) pr_fail("%s: element %zu could not be found\n", args->name, i); else if (*result != data[i]) pr_fail("%s: element %zu found %" PRIu32 ", expecting %" PRIu32 "\n", args->name, i, *result, data[i]); } } inc_counter(args); } while (keep_stressing()); free(root); free(data); return EXIT_SUCCESS; }
static void HOT OPTIMIZE3 stress_memthrash_lock(const args_t *args, size_t mem_size) { uint32_t i; (void)args; for (i = 0; !thread_terminate && (i < 64); i++) { size_t offset = mwc32() % mem_size; volatile uint8_t *ptr = mem + offset; MEM_LOCK(ptr); } }
static void HOT OPTIMIZE3 stress_memthrash_mfence(const args_t *args, size_t mem_size) { uint32_t i; const uint32_t max = mwc16(); (void)args; for (i = 0; !thread_terminate && (i < max); i++) { size_t offset = mwc32() % mem_size; volatile uint8_t *ptr = mem + offset; *ptr = i & 0xff; mfence(); } }
/* * stress_filename_generate_random() * generate a filename of length sz_max with * random selection from possible char set */ void stress_filename_generate_random( char *filename, const size_t sz_max, const size_t chars_allowed) { size_t i; for (i = 0; i < sz_max; i++) { const int j = mwc32() % chars_allowed; filename[i] = allowed[j]; } if (*filename == '.') *filename = '_'; filename[i] = '\0'; }
/* * mwc_reseed() * dirty mwc reseed */ void mwc_reseed(void) { struct timeval tv; int i, n; __mwc.z = 0; if (gettimeofday(&tv, NULL) == 0) __mwc.z = (uint64_t)tv.tv_sec ^ (uint64_t)tv.tv_usec; __mwc.z += ~((unsigned char *)&__mwc.z - (unsigned char *)&tv); __mwc.w = (uint64_t)getpid() ^ (uint64_t)getppid()<<12; n = (int)__mwc.z % 1733; for (i = 0; i < n; i++) (void)mwc32(); }
static void HOT OPTIMIZE3 stress_memthrash_flush(const args_t *args, size_t mem_size) { uint32_t i; const uint32_t max = mwc16(); (void)args; for (i = 0; !thread_terminate && (i < max); i++) { size_t offset = mwc32() % mem_size; uint8_t *const ptr = mem + offset; volatile uint8_t *const vptr = ptr; *vptr = i & 0xff; clflush(ptr); } }
static inline HOT OPTIMIZE3 void stress_memthrash_random_chunk(const size_t chunk_size, size_t mem_size) { uint32_t i; const uint32_t max = mwc16(); size_t chunks = mem_size / chunk_size; if (chunks < 1) chunks = 1; for (i = 0; !thread_terminate && (i < max); i++) { const size_t chunk = mwc32() % chunks; const size_t offset = chunk * chunk_size; #if defined(__GNUC__) (void)__builtin_memset((void *)mem + offset, mwc8(), chunk_size); #else (void)memset((void *)mem + offset, mwc8(), chunk_size); #endif } }
static void HOT OPTIMIZE3 stress_memthrash_spinwrite(const args_t *args, size_t mem_size) { uint32_t i; const size_t offset = mwc32() % mem_size; volatile uint32_t *ptr = (uint32_t *)(mem + offset); (void)args; for (i = 0; !thread_terminate && (i < 65536); i++) { *ptr = i; *ptr = i; *ptr = i; *ptr = i; *ptr = i; *ptr = i; *ptr = i; *ptr = i; } }
/* * stress_lockbus() * stress memory with lock and increment */ int stress_lockbus( uint64_t *const counter, const uint32_t instance, const uint64_t max_ops, const char *name) { uint8_t *buffer; int flags = MAP_ANONYMOUS | MAP_SHARED; (void)instance; #if defined(MAP_POPULATE) flags |= MAP_POPULATE; #endif buffer = mmap(NULL, BUFFER_SIZE, PROT_READ | PROT_WRITE, flags, -1, 0); if (buffer == MAP_FAILED) { int rc = exit_status(errno); pr_err(stderr, "%s: mmap failed\n", name); return rc; } do { uint8_t *ptr = buffer + (mwc32() % (BUFFER_SIZE - CHUNK_SIZE)); const uint8_t inc = 1; LOCK_AND_INCx8(ptr, inc); LOCK_AND_INCx8(ptr, inc); LOCK_AND_INCx8(ptr, inc); LOCK_AND_INCx8(ptr, inc); LOCK_AND_INCx8(ptr, inc); LOCK_AND_INCx8(ptr, inc); LOCK_AND_INCx8(ptr, inc); LOCK_AND_INCx8(ptr, inc); (*counter)++; } while (opt_do_run && (!max_ops || *counter < max_ops)); (void)munmap(buffer, BUFFER_SIZE); return EXIT_SUCCESS; }
/* * stress on sched_affinity() * stress system by changing CPU affinity periodically */ int stress_affinity( uint64_t *const counter, const uint32_t instance, const uint64_t max_ops, const char *name) { unsigned long int cpu = 0; const unsigned long int cpus = (unsigned long int)stress_get_processors_configured(); cpu_set_t mask; (void)instance; (void)name; do { cpu = (opt_flags & OPT_FLAGS_AFFINITY_RAND) ? (mwc32() >> 4) : cpu + 1; cpu %= cpus; CPU_ZERO(&mask); CPU_SET(cpu, &mask); if (sched_setaffinity(0, sizeof(mask), &mask) < 0) { pr_fail(stderr, "%s: failed to move to CPU %lu\n", name, cpu); #if defined(_POSIX_PRIORITY_SCHEDULING) sched_yield(); #endif } else { /* Now get and check */ CPU_ZERO(&mask); CPU_SET(cpu, &mask); sched_getaffinity(0, sizeof(mask), &mask); if ((opt_flags & OPT_FLAGS_VERIFY) && (!CPU_ISSET(cpu, &mask))) pr_fail(stderr, "%s: failed to move to CPU %lu\n", name, cpu); } (*counter)++; } while (opt_do_run && (!max_ops || *counter < max_ops)); return EXIT_SUCCESS; }
/* * stress_timer_set() * set timer, ensure it is never zero */ void stress_timer_set(struct itimerspec *timer) { double rate; if (opt_flags & OPT_FLAGS_TIMER_RAND) { /* Mix in some random variation */ double r = ((double)(mwc32() % 10000) - 5000.0) / 40000.0; rate = rate_ns + (rate_ns * r); } else { rate = rate_ns; } timer->it_value.tv_sec = (long long int)rate / 1000000000; timer->it_value.tv_nsec = (long long int)rate % 1000000000; if (timer->it_interval.tv_sec == 0 && timer->it_interval.tv_nsec < 1) timer->it_interval.tv_nsec = 1; timer->it_interval.tv_sec = timer->it_value.tv_sec; timer->it_interval.tv_nsec = timer->it_value.tv_nsec; }
/* * handle_page_fault() * handle a write page fault caused by child */ static inline int handle_page_fault( const args_t *args, const int fd, uint8_t *addr, void *zero_page, uint8_t *data_start, uint8_t *data_end, const size_t page_size) { if ((addr < data_start) || (addr >= data_end)) { pr_fail_err("userfaultfd page fault address out of range"); return -1; } if (mwc32() & 1) { struct uffdio_copy copy; copy.copy = 0; copy.mode = 0; copy.dst = (unsigned long)addr; copy.src = (unsigned long)zero_page; copy.len = page_size; if (ioctl(fd, UFFDIO_COPY, ©) < 0) { pr_fail_err("userfaultfd page fault copy ioctl failed"); return -1; } } else { struct uffdio_zeropage zeropage; zeropage.range.start = (unsigned long)addr; zeropage.range.len = page_size; zeropage.mode = 0; if (ioctl(fd, UFFDIO_ZEROPAGE, &zeropage) < 0) { pr_fail_err("userfaultfd page fault zeropage ioctl failed"); return -1; } } return 0; }
/* * stress_sys_read() * read a proc file */ static inline void stress_sys_read(const char *name, const char *path) { int fd; ssize_t i = 0; char buffer[SYS_BUF_SZ]; if ((fd = open(path, O_RDONLY | O_NONBLOCK)) < 0) return; /* * Multiple randomly sized reads */ while (i < (4096 * SYS_BUF_SZ)) { ssize_t ret, sz = 1 + (mwc32() % sizeof(buffer)); redo: if (!opt_do_run) break; ret = read(fd, buffer, sz); if (ret < 0) { if ((errno == EAGAIN) || (errno == EINTR)) goto redo; break; } if (ret < sz) break; i += sz; } (void)close(fd); /* file should be R_OK if we've just opened it */ if ((access(path, R_OK) < 0) && (opt_flags & OPT_FLAGS_VERIFY)) { pr_fail(stderr, "%s: R_OK access failed on %s which " "could be opened, errno=%d (%s)\n", name, path, errno, strerror(errno)); } }
/* * stress_timer_set() * set timer, ensure it is never zero */ static void stress_timer_set(struct itimerspec *timer) { double rate; bool timer_rand = false; (void)get_setting("timer-rand", &timer_rand); if (timer_rand) { /* Mix in some random variation */ double r = ((double)(mwc32() % 10000) - 5000.0) / 40000.0; rate = rate_ns + (rate_ns * r); } else { rate = rate_ns; } timer->it_value.tv_sec = (time_t)rate / 1000000000; timer->it_value.tv_nsec = (suseconds_t)rate % 1000000000; if (timer->it_value.tv_sec == 0 && timer->it_value.tv_nsec < 1) timer->it_value.tv_nsec = 1; timer->it_interval.tv_sec = timer->it_value.tv_sec; timer->it_interval.tv_nsec = timer->it_value.tv_nsec; }
/* * stress_msync() * stress msync */ int stress_msync( uint64_t *const counter, const uint32_t instance, const uint64_t max_ops, const char *name) { uint8_t *buf = NULL; const size_t page_size = stress_get_pagesize(); const size_t min_size = 2 * page_size; size_t sz = min_size; ssize_t ret, rc = EXIT_SUCCESS; const pid_t pid = getpid(); int fd = -1; char filename[PATH_MAX]; ret = sigsetjmp(jmp_env, 1); if (ret) { pr_fail_err(name, "sigsetjmp"); return EXIT_FAILURE; } if (stress_sighandler(name, SIGBUS, stress_sigbus_handler, NULL) < 0) return EXIT_FAILURE; if (!set_msync_bytes) { if (opt_flags & OPT_FLAGS_MAXIMIZE) opt_msync_bytes = MAX_MSYNC_BYTES; if (opt_flags & OPT_FLAGS_MINIMIZE) opt_msync_bytes = MIN_MSYNC_BYTES; } sz = opt_msync_bytes & ~(page_size - 1); if (sz < min_size) sz = min_size; /* Make sure this is killable by OOM killer */ set_oom_adjustment(name, true); rc = stress_temp_dir_mk(name, pid, instance); if (rc < 0) return exit_status(-rc); (void)stress_temp_filename(filename, sizeof(filename), name, pid, instance, mwc32()); (void)umask(0077); if ((fd = open(filename, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR)) < 0) { rc = exit_status(errno); pr_fail_err(name, "open"); (void)unlink(filename); (void)stress_temp_dir_rm(name, pid, instance); return rc; } (void)unlink(filename); if (ftruncate(fd, sz) < 0) { pr_err(stderr, "%s: ftruncate failed, errno=%d (%s)\n", name, errno, strerror(errno)); (void)close(fd); (void)stress_temp_dir_rm(name, pid, instance); return EXIT_FAILURE; } buf = (uint8_t *)mmap(NULL, sz, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (buf == MAP_FAILED) { pr_err(stderr, "%s: failed to mmap memory, errno=%d (%s)\n", name, errno, strerror(errno)); rc = EXIT_NO_RESOURCE; goto err; } do { off_t offset; uint8_t val, data[page_size]; ret = sigsetjmp(jmp_env, 1); if (ret) { /* Try again */ continue; } /* * Change data in memory, msync to disk */ offset = (mwc64() % (sz - page_size)) & ~(page_size - 1); val = mwc8(); memset(buf + offset, val, page_size); ret = msync(buf + offset, page_size, MS_SYNC); if (ret < 0) { pr_fail(stderr, "%s: msync MS_SYNC on " "offset %jd failed, errno=%d (%s)", name, (intmax_t)offset, errno, strerror(errno)); goto do_invalidate; } ret = lseek(fd, offset, SEEK_SET); if (ret == (off_t)-1) { pr_err(stderr, "%s: cannot seet to offset %jd, " "errno=%d (%s)\n", name, (intmax_t)offset, errno, strerror(errno)); rc = EXIT_NO_RESOURCE; break; } ret = read(fd, data, sizeof(data)); if (ret < (ssize_t)sizeof(data)) { pr_fail(stderr, "%s: read failed, errno=%d (%s)\n", name, errno, strerror(errno)); goto do_invalidate; } if (stress_page_check(data, val, sizeof(data)) < 0) { pr_fail(stderr, "%s: msync'd data in file different " "to data in memory\n", name); } do_invalidate: /* * Now change data on disc, msync invalidate */ offset = (mwc64() % (sz - page_size)) & ~(page_size - 1); val = mwc8(); memset(buf + offset, val, page_size); ret = lseek(fd, offset, SEEK_SET); if (ret == (off_t)-1) { pr_err(stderr, "%s: cannot seet to offset %jd, errno=%d (%s)\n", name, (intmax_t)offset, errno, strerror(errno)); rc = EXIT_NO_RESOURCE; break; } ret = read(fd, data, sizeof(data)); if (ret < (ssize_t)sizeof(data)) { pr_fail(stderr, "%s: read failed, errno=%d (%s)\n", name, errno, strerror(errno)); goto do_next; } ret = msync(buf + offset, page_size, MS_INVALIDATE); if (ret < 0) { pr_fail(stderr, "%s: msync MS_INVALIDATE on " "offset %jd failed, errno=%d (%s)", name, (intmax_t)offset, errno, strerror(errno)); goto do_next; } if (stress_page_check(buf + offset, val, sizeof(data)) < 0) { pr_fail(stderr, "%s: msync'd data in memory " "different to data in file\n", name); } do_next: (*counter)++; } while (opt_do_run && (!max_ops || *counter < max_ops)); (void)munmap((void *)buf, sz); err: (void)close(fd); (void)stress_temp_dir_rm(name, pid, instance); if (sigbus_count) pr_inf(stdout, "%s: caught %" PRIu64 " SIGBUS signals\n", name, sigbus_count); return rc; }
/* * stress_copy_file * stress reading chunks of file using copy_file_range() */ int stress_copy_file( uint64_t *const counter, const uint32_t instance, const uint64_t max_ops, const char *name) { int fd_in, fd_out, rc = EXIT_FAILURE; char filename[PATH_MAX], tmp[PATH_MAX]; pid_t pid = getpid(); if (!set_copy_file_bytes) { if (opt_flags & OPT_FLAGS_MAXIMIZE) opt_copy_file_bytes = MAX_HDD_BYTES; if (opt_flags & OPT_FLAGS_MINIMIZE) opt_copy_file_bytes = MIN_HDD_BYTES; } if (opt_copy_file_bytes < DEFAULT_COPY_FILE_SIZE) opt_copy_file_bytes = DEFAULT_COPY_FILE_SIZE * 2; if (stress_temp_dir_mk(name, pid, instance) < 0) goto tidy_dir; (void)stress_temp_filename(filename, sizeof(filename), name, pid, instance, mwc32()); snprintf(tmp, sizeof(tmp), "%s-orig", filename); if ((fd_in = open(tmp, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR)) < 0) { rc = exit_status(errno); pr_fail_err(name, "open"); goto tidy_dir; } (void)unlink(tmp); if (ftruncate(fd_in, opt_copy_file_bytes) < 0) { rc = exit_status(errno); pr_fail_err(name, "ftruncate"); goto tidy_in; } if (fsync(fd_in) < 0) { pr_fail_err(name, "fsync"); goto tidy_in; } snprintf(tmp, sizeof(tmp), "%s-copy", filename); if ((fd_out = open(tmp, O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR)) < 0) { rc = exit_status(errno); pr_fail_err(name, "open"); goto tidy_in; } (void)unlink(tmp); do { ssize_t ret; loff_t off_in, off_out; off_in = mwc64() % (opt_copy_file_bytes - DEFAULT_COPY_FILE_SIZE); off_out = mwc64() % (opt_copy_file_bytes - DEFAULT_COPY_FILE_SIZE); ret = sys_copy_file_range(fd_in, &off_in, fd_out, &off_out, DEFAULT_COPY_FILE_SIZE, 0); if (ret < 0) { if ((errno == EAGAIN) || (errno == EINTR)) continue; pr_fail_err(name, "copy_file_range"); goto tidy_out; } (void)fsync(fd_out); (*counter)++; } while (opt_do_run && (!max_ops || *counter < max_ops)); rc = EXIT_SUCCESS; tidy_out: (void)close(fd_out); tidy_in: (void)close(fd_in); tidy_dir: (void)stress_temp_dir_rm(name, pid, instance); return rc; }
/* * stress_remap * stress page remapping */ static int stress_remap(const args_t *args) { mapdata_t *data; const size_t page_size = args->page_size; const size_t data_size = N_PAGES * page_size; const size_t stride = page_size / sizeof(*data); size_t i; data = mmap(NULL, data_size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); if (data == MAP_FAILED) { pr_err("%s: mmap failed: errno=%d (%s)\n", args->name, errno, strerror(errno)); return EXIT_NO_RESOURCE; } for (i = 0; i < N_PAGES; i++) data[i * stride] = i; do { size_t order[N_PAGES]; /* Reverse pages */ for (i = 0; i < N_PAGES; i++) order[i] = N_PAGES - 1 - i; if (remap_order(args, stride, data, order, page_size) < 0) break; check_order(args, stride, data, order, "reverse"); /* random order pages */ for (i = 0; i < N_PAGES; i++) order[i] = i; for (i = 0; i < N_PAGES; i++) { size_t tmp, j = mwc32() % N_PAGES; tmp = order[i]; order[i] = order[j]; order[j] = tmp; } if (remap_order(args, stride, data, order, page_size) < 0) break; check_order(args, stride, data, order, "random"); /* all mapped to 1 page */ for (i = 0; i < N_PAGES; i++) order[i] = 0; if (remap_order(args, stride, data, order, page_size) < 0) break; check_order(args, stride, data, order, "all-to-1"); /* reorder pages back again */ for (i = 0; i < N_PAGES; i++) order[i] = i; if (remap_order(args, stride, data, order, page_size) < 0) break; check_order(args, stride, data, order, "forward"); inc_counter(args); } while (keep_stressing()); (void)munmap(data, data_size); return EXIT_SUCCESS; }
/* * stress_fiemap * stress fiemap IOCTL */ int stress_fiemap( uint64_t *const counter, const uint32_t instance, const uint64_t max_ops, const char *name) { pid_t pids[MAX_FIEMAP_PROCS], mypid; int ret, fd, rc = EXIT_FAILURE, status; char filename[PATH_MAX]; size_t i; const size_t counters_sz = sizeof(uint64_t) * MAX_FIEMAP_PROCS; uint64_t *counters; uint64_t ops_per_proc = max_ops / MAX_FIEMAP_PROCS; uint64_t ops_remaining = max_ops % MAX_FIEMAP_PROCS; if (!set_fiemap_size) { if (opt_flags & OPT_FLAGS_MAXIMIZE) opt_fiemap_size = MAX_SEEK_SIZE; if (opt_flags & OPT_FLAGS_MINIMIZE) opt_fiemap_size = MIN_SEEK_SIZE; } /* We need some share memory for counter accounting */ counters = mmap(NULL, counters_sz, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); if (counters == MAP_FAILED) { pr_err(stderr, "%s: mmap failed: errno=%d (%s)\n", name, errno, strerror(errno)); return EXIT_NO_RESOURCE; } memset(counters, 0, counters_sz); mypid = getpid(); ret = stress_temp_dir_mk(name, mypid, instance); if (ret < 0) { rc = exit_status(-ret); goto clean; } (void)stress_temp_filename(filename, sizeof(filename), name, mypid, instance, mwc32()); (void)umask(0077); if ((fd = open(filename, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR)) < 0) { rc = exit_status(errno); pr_fail_err(name, "open"); goto clean; } (void)unlink(filename); for (i = 0; i < MAX_FIEMAP_PROCS; i++) { uint64_t ops = ops_per_proc + ((i == 0) ? ops_remaining : 0); pids[i] = stress_fiemap_spawn(name, fd, &counters[i], ops); if (pids[i] < 0) goto fail; } rc = stress_fiemap_writer(name, fd, counters, max_ops); /* And reap stressors */ for (i = 0; i < MAX_FIEMAP_PROCS; i++) { (void)kill(pids[i], SIGKILL); (void)waitpid(pids[i], &status, 0); (*counter) += counters[i]; } fail: (void)close(fd); clean: (void)munmap(counters, counters_sz); (void)stress_temp_dir_rm(name, mypid, instance); return rc; }
/* * stress_access * stress access family of system calls */ static int stress_access(const args_t *args) { int fd = -1, ret, rc = EXIT_FAILURE; char filename[PATH_MAX]; const mode_t all_mask = 0700; size_t i; const bool is_root = (geteuid() == 0); ret = stress_temp_dir_mk_args(args); if (ret < 0) return exit_status(-ret); (void)stress_temp_filename_args(args, filename, sizeof(filename), mwc32()); (void)umask(0700); if ((fd = creat(filename, S_IRUSR | S_IWUSR)) < 0) { rc = exit_status(errno); pr_fail_err("creat"); goto tidy; } do { for (i = 0; i < SIZEOF_ARRAY(modes); i++) { ret = fchmod(fd, modes[i].chmod_mode); if (CHMOD_ERR(ret)) { pr_err("%s: fchmod %3.3o failed: %d (%s)\n", args->name, (unsigned int)modes[i].chmod_mode, errno, strerror(errno)); goto tidy; } ret = access(filename, modes[i].access_mode); if (ret < 0) { pr_fail("%s: access %3.3o on chmod mode %3.3o failed: %d (%s)\n", args->name, modes[i].access_mode, (unsigned int)modes[i].chmod_mode, errno, strerror(errno)); } #if defined(HAVE_FACCESSAT) ret = faccessat(AT_FDCWD, filename, modes[i].access_mode, 0); if (ret < 0) { pr_fail("%s: faccessat %3.3o on chmod mode %3.3o failed: %d (%s)\n", args->name, modes[i].access_mode, (unsigned int)modes[i].chmod_mode, errno, strerror(errno)); } #endif if (modes[i].access_mode != 0) { const mode_t chmod_mode = modes[i].chmod_mode ^ all_mask; const bool s_ixusr = chmod_mode & S_IXUSR; const bool dont_ignore = !(is_root && s_ixusr); ret = fchmod(fd, chmod_mode); if (CHMOD_ERR(ret)) { pr_err("%s: fchmod %3.3o failed: %d (%s)\n", args->name, (unsigned int)chmod_mode, errno, strerror(errno)); goto tidy; } ret = access(filename, modes[i].access_mode); if ((ret == 0) && dont_ignore) { pr_fail("%s: access %3.3o on chmod mode %3.3o was ok (not expected): %d (%s)\n", args->name, modes[i].access_mode, (unsigned int)chmod_mode, errno, strerror(errno)); } #if defined(HAVE_FACCESSAT) ret = faccessat(AT_FDCWD, filename, modes[i].access_mode, AT_SYMLINK_NOFOLLOW); if ((ret == 0) && dont_ignore) { pr_fail("%s: faccessat %3.3o on chmod mode %3.3o was ok (not expected): %d (%s)\n", args->name, modes[i].access_mode, (unsigned int)chmod_mode, errno, strerror(errno)); } #endif } } inc_counter(args); } while (keep_stressing()); rc = EXIT_SUCCESS; tidy: if (fd >= 0) { (void)fchmod(fd, 0666); (void)close(fd); } (void)unlink(filename); (void)stress_temp_dir_rm_args(args); return rc; }
/* * stress_filename() * stress filename sizes etc */ int stress_filename ( uint64_t *const counter, const uint32_t instance, const uint64_t max_ops, const char *name) { const pid_t pid = getpid(); int rc = EXIT_FAILURE; size_t sz_left, sz_max; char dirname[PATH_MAX]; char filename[PATH_MAX]; char *ptr; struct statvfs buf; size_t i, chars_allowed = 0, sz; stress_temp_dir(dirname, sizeof(dirname), name, pid, instance); if (mkdir(dirname, S_IRWXU) < 0) { if (errno != EEXIST) { pr_fail_err(name, "mkdir"); return EXIT_FAILURE; } } if (statvfs(dirname, &buf) < 0) { pr_fail_err(name, "statvfs"); goto tidy_dir; } if (instance == 0) pr_dbg(stderr, "%s: maximum file size: %lu bytes\n", name, (long unsigned) buf.f_namemax); strncpy(filename, dirname, sizeof(filename) - 1); ptr = filename + strlen(dirname); *(ptr++) = '/'; *(ptr) = '\0'; sz_left = sizeof(filename) - (ptr - filename); sz_max = (size_t)buf.f_namemax; if (sz_left >= PATH_MAX) { pr_fail(stderr, "%s: max file name larger than PATH_MAX\n", name); goto tidy_dir; } switch (filename_opt) { case STRESS_FILENAME_POSIX: strcpy(allowed, posix_allowed); chars_allowed = strlen(allowed); break; case STRESS_FILENAME_EXT: stress_filename_ext(&chars_allowed); break; case STRESS_FILENAME_PROBE: default: stress_filename_probe(name, filename, ptr, &chars_allowed); break; } if (instance == 0) pr_dbg(stdout, "%s: filesystem allows %zu unique characters in a filename\n", name, chars_allowed); if (chars_allowed == 0) { pr_fail(stderr, "%s: cannot determine allowed characters in a filename\n", name); goto tidy_dir; } i = 0; sz = 1; do { char ch = allowed[i]; size_t rnd_sz = 1 + (mwc32() % sz_max); i++; if (i >= chars_allowed) i = 0; /* Should succeed */ stress_filename_generate(ptr, 1, ch); stress_filename_test(name, filename, 1, true); stress_filename_generate_random(ptr, 1, chars_allowed); stress_filename_test(name, filename, 1, true); /* Should succeed */ stress_filename_generate(ptr, sz_max, ch); stress_filename_test(name, filename, sz_max, true); stress_filename_generate_random(ptr, sz_max, chars_allowed); stress_filename_test(name, filename, sz_max, true); /* Should succeed */ stress_filename_generate(ptr, sz_max - 1, ch); stress_filename_test(name, filename, sz_max - 1, true); stress_filename_generate_random(ptr, sz_max - 1, chars_allowed); stress_filename_test(name, filename, sz_max - 1, true); /* Should fail */ stress_filename_generate(ptr, sz_max + 1, ch); stress_filename_test(name, filename, sz_max + 1, false); stress_filename_generate_random(ptr, sz_max + 1, chars_allowed); stress_filename_test(name, filename, sz_max + 1, false); /* Should succeed */ stress_filename_generate(ptr, sz, ch); stress_filename_test(name, filename, sz, true); stress_filename_generate_random(ptr, sz, chars_allowed); stress_filename_test(name, filename, sz, true); /* Should succeed */ stress_filename_generate(ptr, rnd_sz, ch); stress_filename_test(name, filename, rnd_sz, true); stress_filename_generate_random(ptr, rnd_sz, chars_allowed); stress_filename_test(name, filename, rnd_sz, true); sz++; if (sz > sz_max) sz = 1; } while (opt_do_run && (!max_ops || *counter < max_ops)); rc = EXIT_SUCCESS; tidy_dir: (void)rmdir(dirname); return rc; }
/* * stress_sync_file * stress the sync_file_range system call */ static int stress_sync_file(const args_t *args) { int fd, ret; off_t sync_file_bytes = DEFAULT_SYNC_FILE_BYTES; char filename[PATH_MAX]; if (!get_setting("sync_file-bytes", &sync_file_bytes)) { if (g_opt_flags & OPT_FLAGS_MAXIMIZE) sync_file_bytes = MAX_SYNC_FILE_BYTES; if (g_opt_flags & OPT_FLAGS_MINIMIZE) sync_file_bytes = MIN_SYNC_FILE_BYTES; } sync_file_bytes /= args->num_instances; if (sync_file_bytes < (off_t)MIN_SYNC_FILE_BYTES) sync_file_bytes = (off_t)MIN_SYNC_FILE_BYTES; ret = stress_temp_dir_mk_args(args); if (ret < 0) return exit_status(-ret); (void)stress_temp_filename_args(args, filename, sizeof(filename), mwc32()); if ((fd = open(filename, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR)) < 0) { ret = exit_status(errno); pr_fail_err("open"); (void)stress_temp_dir_rm_args(args); return ret; } (void)unlink(filename); do { shim_off64_t i, offset; const size_t mode_index = mwc32() % SIZEOF_ARRAY(sync_modes); const int mode = sync_modes[mode_index]; if (stress_sync_allocate(args, fd, sync_file_bytes) < 0) break; for (offset = 0; g_keep_stressing_flag && (offset < (shim_off64_t)sync_file_bytes); ) { shim_off64_t sz = (mwc32() & 0x1fc00) + KB; ret = shim_sync_file_range(fd, offset, sz, mode); if (ret < 0) { if (errno == ENOSYS) { pr_inf("%s: skipping stressor, sync_file_range is not implemented\n", args->name); goto err; } pr_fail_err("sync_file_range (forward)"); break; } offset += sz; } if (!g_keep_stressing_flag) break; if (stress_sync_allocate(args, fd, sync_file_bytes) < 0) break; for (offset = 0; g_keep_stressing_flag && (offset < (shim_off64_t)sync_file_bytes); ) { shim_off64_t sz = (mwc32() & 0x1fc00) + KB; ret = shim_sync_file_range(fd, sync_file_bytes - offset, sz, mode); if (ret < 0) { if (errno == ENOSYS) { pr_inf("%s: skipping stressor, sync_file_range is not implemented\n", args->name); goto err; } pr_fail_err("sync_file_range (reverse)"); break; } offset += sz; } if (!g_keep_stressing_flag) break; if (stress_sync_allocate(args, fd, sync_file_bytes) < 0) break; for (i = 0; i < g_keep_stressing_flag && ((shim_off64_t)(sync_file_bytes / (128 * KB))); i++) { offset = (mwc64() % sync_file_bytes) & ~((128 * KB) - 1); ret = shim_sync_file_range(fd, offset, 128 * KB, mode); if (ret < 0) { if (errno == ENOSYS) { pr_inf("%s: skipping stressor, sync_file_range is not implemented\n", args->name); goto err; } pr_fail_err("sync_file_range (random)"); break; } } inc_counter(args); } while (keep_stressing()); err: (void)close(fd); (void)stress_temp_dir_rm_args(args); return EXIT_SUCCESS; }
/* * stress_loop() * stress loopback device */ static int stress_loop(const args_t *args) { int ret, backing_fd, rc = EXIT_FAILURE; char backing_file[PATH_MAX]; size_t backing_size = 2 * MB; ret = stress_temp_dir_mk_args(args); if (ret < 0) return exit_status(-ret); (void)stress_temp_filename_args(args, backing_file, sizeof(backing_file), mwc32()); if ((backing_fd = open(backing_file, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR)) < 0) { pr_fail_err("open"); goto tidy; } if (ftruncate(backing_fd, backing_size) < 0) { pr_fail_err("ftruncate"); (void)close(backing_fd); goto tidy; } (void)unlink(backing_file); do { int ctrl_dev, loop_dev; int i; long dev_num; char dev_name[PATH_MAX]; struct loop_info info; /* * Open loop control device */ ctrl_dev = open("/dev/loop-control", O_RDWR); if (ctrl_dev < 0) { pr_fail("%s: cannot open /dev/loop-control: %d (%s)\n", args->name, errno, strerror(errno)); break; } /* * Attempt to get a free loop device */ dev_num = ioctl(ctrl_dev, LOOP_CTL_GET_FREE); if (dev_num < 0) goto next; /* * Open new loop device */ (void)snprintf(dev_name, sizeof(dev_name), "/dev/loop%ld", dev_num); loop_dev = open(dev_name, O_RDWR); if (loop_dev < 0) goto destroy_loop; /* * Associate loop device with backing storage */ ret = ioctl(loop_dev, LOOP_SET_FD, backing_fd); if (ret < 0) goto close_loop; #if defined(LOOP_GET_STATUS) /* * Fetch loop device status information */ ret = ioctl(loop_dev, LOOP_GET_STATUS, &info); if (ret < 0) goto clr_loop; /* * Try to set some flags */ info.lo_flags |= (LO_FLAGS_AUTOCLEAR | LO_FLAGS_READ_ONLY); #if defined(LOOP_SET_STATUS) ret = ioctl(loop_dev, LOOP_SET_STATUS, &info); (void)ret; #endif #endif #if defined(LOOP_SET_CAPACITY) /* * Resize command (even though we have not changed size) */ ret = ftruncate(backing_fd, backing_size * 2); (void)ret; ret = ioctl(loop_dev, LOOP_SET_CAPACITY); (void)ret; #endif #if defined(LOOP_GET_STATUS) clr_loop: #endif /* * Disassociate backing store from loop device */ for (i = 0; i < 1000; i++) { ret = ioctl(loop_dev, LOOP_CLR_FD, backing_fd); if (ret < 0) { if (errno == EBUSY) { (void)shim_usleep(10); } else { pr_fail("%s: failed to disassociate %s from backing store, " "errno=%d (%s)\n", args->name, dev_name, errno, strerror(errno)); goto close_loop; } } else { break; } } close_loop: (void)close(loop_dev); /* * Remove the loop device, may need several retries * if we get EBUSY */ destroy_loop: for (i = 0; i < 1000; i++) { ret = ioctl(ctrl_dev, LOOP_CTL_REMOVE, dev_num); if ((ret < 0) && (errno == EBUSY)) { (void)shim_usleep(10); } else { break; } } next: (void)close(ctrl_dev); #if defined(LOOP_SET_CAPACITY) ret = ftruncate(backing_fd, backing_size); (void)ret; #endif inc_counter(args); } while (keep_stressing()); rc = EXIT_SUCCESS; (void)close(backing_fd); tidy: (void)stress_temp_dir_rm_args(args); return rc; }
/* * stress_mergesort() * stress mergesort */ static int stress_mergesort(const args_t *args) { uint64_t mergesort_size = DEFAULT_MERGESORT_SIZE; int32_t *data, *ptr; size_t n, i; struct sigaction old_action; int ret; if (!get_setting("mergesort-size", &mergesort_size)) { if (g_opt_flags & OPT_FLAGS_MAXIMIZE) mergesort_size = MAX_MERGESORT_SIZE; if (g_opt_flags & OPT_FLAGS_MINIMIZE) mergesort_size = MIN_MERGESORT_SIZE; } n = (size_t)mergesort_size; if ((data = calloc(n, sizeof(*data))) == NULL) { pr_fail_dbg("malloc"); return EXIT_NO_RESOURCE; } if (stress_sighandler(args->name, SIGALRM, stress_mergesort_handler, &old_action) < 0) { free(data); return EXIT_FAILURE; } ret = sigsetjmp(jmp_env, 1); if (ret) { /* * We return here if SIGALRM jmp'd back */ (void)stress_sigrestore(args->name, SIGALRM, &old_action); goto tidy; } /* This is expensive, do it once */ for (ptr = data, i = 0; i < n; i++) *ptr++ = mwc32(); do { /* Sort "random" data */ if (mergesort(data, n, sizeof(*data), stress_mergesort_cmp_1) < 0) { pr_fail("%s: mergesort of random data failed: %d (%s)\n", args->name, errno, strerror(errno)); } else { if (g_opt_flags & OPT_FLAGS_VERIFY) { for (ptr = data, i = 0; i < n - 1; i++, ptr++) { if (*ptr > *(ptr+1)) { pr_fail("%s: sort error " "detected, incorrect ordering " "found\n", args->name); break; } } } } if (!g_keep_stressing_flag) break; /* Reverse sort */ if (mergesort(data, n, sizeof(*data), stress_mergesort_cmp_2) < 0) { pr_fail("%s: reversed mergesort of random data failed: %d (%s)\n", args->name, errno, strerror(errno)); } else { if (g_opt_flags & OPT_FLAGS_VERIFY) { for (ptr = data, i = 0; i < n - 1; i++, ptr++) { if (*ptr < *(ptr+1)) { pr_fail("%s: reverse sort " "error detected, incorrect " "ordering found\n", args->name); break; } } } } if (!g_keep_stressing_flag) break; /* And re-order by random compare to remix the data */ if (mergesort(data, n, sizeof(*data), stress_mergesort_cmp_3) < 0) { pr_fail("%s: mergesort failed: %d (%s)\n", args->name, errno, strerror(errno)); } /* Reverse sort this again */ if (mergesort(data, n, sizeof(*data), stress_mergesort_cmp_2) < 0) { pr_fail("%s: reversed mergesort of random data failed: %d (%s)\n", args->name, errno, strerror(errno)); } if (g_opt_flags & OPT_FLAGS_VERIFY) { for (ptr = data, i = 0; i < n - 1; i++, ptr++) { if (*ptr < *(ptr+1)) { pr_fail("%s: reverse sort " "error detected, incorrect " "ordering found\n", args->name); break; } } } if (!g_keep_stressing_flag) break; inc_counter(args); } while (keep_stressing()); do_jmp = false; (void)stress_sigrestore(args->name, SIGALRM, &old_action); tidy: free(data); return EXIT_SUCCESS; }
/* * stress_fault() * stress min and max page faulting */ static int stress_fault(const args_t *args) { #if !defined(__HAIKU__) struct rusage usage; #endif char filename[PATH_MAX]; int ret; NOCLOBBER int i; ret = stress_temp_dir_mk_args(args); if (ret < 0) return exit_status(-ret); (void)stress_temp_filename_args(args, filename, sizeof(filename), mwc32()); i = 0; if (stress_sighandler(args->name, SIGSEGV, stress_segvhandler, NULL) < 0) return EXIT_FAILURE; if (stress_sighandler(args->name, SIGBUS, stress_segvhandler, NULL) < 0) return EXIT_FAILURE; do { char *ptr; int fd; ret = sigsetjmp(jmp_env, 1); if (ret) { do_jmp = false; pr_err("%s: unexpected segmentation fault\n", args->name); break; } fd = open(filename, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); if (fd < 0) { if ((errno == ENOSPC) || (errno == ENOMEM)) continue; /* Try again */ pr_fail_err("open"); break; } #if defined(HAVE_POSIX_FALLOCATE) if (posix_fallocate(fd, 0, 1) < 0) { if (errno == ENOSPC) { (void)close(fd); continue; /* Try again */ } (void)close(fd); pr_fail_err("posix_fallocate"); break; } #else { char buffer[1]; redo: if (g_keep_stressing_flag && (write(fd, buffer, sizeof(buffer)) < 0)) { if ((errno == EAGAIN) || (errno == EINTR)) goto redo; if (errno == ENOSPC) { (void)close(fd); continue; } (void)close(fd); pr_fail_err("write"); break; } } #endif ret = sigsetjmp(jmp_env, 1); if (ret) { if (!keep_stressing()) do_jmp = false; if (fd != -1) (void)close(fd); goto next; } /* * Removing file here causes major fault when we touch * ptr later */ if (i & 1) (void)unlink(filename); ptr = mmap(NULL, 1, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); (void)close(fd); fd = -1; (void)fd; if (ptr == MAP_FAILED) { if ((errno == EAGAIN) || (errno == ENOMEM) || (errno == ENFILE)) goto next; pr_err("%s: mmap failed: errno=%d (%s)\n", args->name, errno, strerror(errno)); break; } *ptr = 0; /* Cause the page fault */ if (munmap(ptr, 1) < 0) { pr_err("%s: munmap failed: errno=%d (%s)\n", args->name, errno, strerror(errno)); break; } next: /* Remove file on-non major fault case */ if (!(i & 1)) (void)unlink(filename); i++; inc_counter(args); } while (keep_stressing()); /* Clean up, most times this is redundant */ (void)unlink(filename); (void)stress_temp_dir_rm_args(args); #if !defined(__HAIKU__) if (!getrusage(RUSAGE_SELF, &usage)) { pr_dbg("%s: page faults: minor: %lu, major: %lu\n", args->name, usage.ru_minflt, usage.ru_majflt); } #endif return EXIT_SUCCESS; }
/* * stress_fallocate * stress I/O via fallocate and ftruncate */ static int stress_fallocate(const args_t *args) { int fd, ret; char filename[PATH_MAX]; uint64_t ftrunc_errs = 0; off_t fallocate_bytes = DEFAULT_FALLOCATE_BYTES; if (!get_setting("fallocate-bytes", &fallocate_bytes)) { if (g_opt_flags & OPT_FLAGS_MAXIMIZE) fallocate_bytes = MAX_FALLOCATE_BYTES; if (g_opt_flags & OPT_FLAGS_MINIMIZE) fallocate_bytes = MIN_FALLOCATE_BYTES; } fallocate_bytes /= args->num_instances; if (fallocate_bytes < (off_t)MIN_FALLOCATE_BYTES) fallocate_bytes = (off_t)MIN_FALLOCATE_BYTES; ret = stress_temp_dir_mk_args(args); if (ret < 0) return exit_status(-ret); (void)stress_temp_filename_args(args, filename, sizeof(filename), mwc32()); if ((fd = open(filename, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR)) < 0) { ret = exit_status(errno); pr_fail_err("open"); (void)stress_temp_dir_rm_args(args); return ret; } (void)unlink(filename); do { #if defined(HAVE_POSIX_FALLOCATE) ret = posix_fallocate(fd, (off_t)0, fallocate_bytes); #else ret = shim_fallocate(fd, 0, (off_t)0, fallocate_bytes); #endif if (!g_keep_stressing_flag) break; (void)shim_fsync(fd); if ((ret == 0) && (g_opt_flags & OPT_FLAGS_VERIFY)) { struct stat buf; if (fstat(fd, &buf) < 0) pr_fail("%s: fstat on file failed", args->name); else if (buf.st_size != fallocate_bytes) pr_fail("%s: file size %jd does not " "match size the expected file " "size of %jd\n", args->name, (intmax_t)buf.st_size, (intmax_t)fallocate_bytes); } if (ftruncate(fd, 0) < 0) ftrunc_errs++; if (!g_keep_stressing_flag) break; (void)shim_fsync(fd); if (g_opt_flags & OPT_FLAGS_VERIFY) { struct stat buf; if (fstat(fd, &buf) < 0) pr_fail("%s: fstat on file failed", args->name); else if (buf.st_size != (off_t)0) pr_fail("%s: file size %jd does not " "match size the expected file size " "of 0\n", args->name, (intmax_t)buf.st_size); } if (ftruncate(fd, fallocate_bytes) < 0) ftrunc_errs++; (void)shim_fsync(fd); if (ftruncate(fd, 0) < 0) ftrunc_errs++; (void)shim_fsync(fd); if (SIZEOF_ARRAY(modes) > 1) { /* * non-portable Linux fallocate() */ int i; (void)shim_fallocate(fd, 0, (off_t)0, fallocate_bytes); if (!g_keep_stressing_flag) break; (void)shim_fsync(fd); for (i = 0; i < 64; i++) { off_t offset = (mwc64() % fallocate_bytes) & ~0xfff; int j = (mwc32() >> 8) % SIZEOF_ARRAY(modes); (void)shim_fallocate(fd, modes[j], offset, 64 * KB); if (!g_keep_stressing_flag) break; (void)shim_fsync(fd); } if (ftruncate(fd, 0) < 0) ftrunc_errs++; (void)shim_fsync(fd); } inc_counter(args); } while (keep_stressing());
/* * stress_file_ioctl * stress file ioctls */ static int stress_file_ioctl(const args_t *args) { char filename[PATH_MAX]; int ret, fd; #if defined(FICLONE) || defined(FICLONERANGE) int dfd; #endif const off_t file_sz = 8192; uint32_t rnd = mwc32(); ret = stress_temp_dir_mk_args(args); if (ret < 0) return exit_status(-ret); (void)stress_temp_filename_args(args, filename, sizeof(filename), rnd); fd = open(filename, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); if (fd < 0) { pr_err("%s: cannot create %s\n", args->name, filename); return exit_status(errno); } (void)unlink(filename); #if defined(FICLONE) || defined(FICLONERANGE) (void)stress_temp_filename_args(args, filename, sizeof(filename), rnd + 1); dfd = open(filename, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); if (dfd < 0) { (void)close(fd); pr_err("%s: cannot create %s\n", args->name, filename); return exit_status(errno); } (void)unlink(filename); #endif (void)shim_fallocate(fd, 0, 0, file_sz); #if defined(FICLONE) || defined(FICLONERANGE) (void)shim_fallocate(dfd, 0, 0, file_sz); #endif (void)shim_fsync(fd); do { int exercised = 0; #if defined(FIOCLEX) { ret = ioctl(fd, FIOCLEX); (void)ret; exercised++; } #endif #if defined(FIONCLEX) { ret = ioctl(fd, FIONCLEX); (void)ret; exercised++; } #endif #if defined(FIONBIO) { int opt; opt = 1; ret = ioctl(fd, FIONBIO, &opt); #if defined(O_NONBLOCK) check_flag(args, "FIONBIO", fd, O_NONBLOCK, ret, true); #else (void)ret; #endif opt = 0; ret = ioctl(fd, FIONBIO, &opt); #if defined(O_NONBLOCK) check_flag(args, "FIONBIO", fd, O_NONBLOCK, ret, false); #else (void)ret; #endif exercised++; } #endif #if defined(FIOASYNC) { int opt; opt = 1; ret = ioctl(fd, FIOASYNC, &opt); #if defined(O_ASYNC) check_flag(args, "FIONASYNC", fd, O_ASYNC, ret, true); #else (void)ret; #endif opt = 0; ret = ioctl(fd, FIOASYNC, &opt); #if defined(O_ASYNC) check_flag(args, "FIONASYNC", fd, O_ASYNC, ret, false); #else (void)ret; #endif exercised++; } #endif #if defined(FIOQSIZE) { shim_loff_t sz; struct stat buf; ret = fstat(fd, &buf); if (ret == 0) { ret = ioctl(fd, FIOQSIZE, &sz); if ((ret == 0) && (file_sz != buf.st_size)) pr_fail("%s: ioctl FIOQSIZE failed, size " "%jd (filesize) vs %jd (reported)\n", args->name, (intmax_t)file_sz, (intmax_t)sz); } exercised++; } #endif /* Disable this at the moment, it is fragile */ #if 0 #if defined(FIFREEZE) && defined(FITHAW) { ret = ioctl(fd, FIFREEZE); (void)ret; ret = ioctl(fd, FITHAW); (void)ret; exercised++; } #endif #endif #if defined(FIGETBSZ) { int isz; ret = ioctl(fd, FIGETBSZ, &isz); if ((ret == 0) && (isz < 1)) pr_fail("%s: ioctl FIGETBSZ returned unusual " "block size %d\n", args->name, isz); exercised++; } #endif #if defined(FICLONE) { ret = ioctl(dfd, FICLONE, fd); (void)ret; exercised++; } #endif #if defined(FICLONERANGE) { struct file_clone_range fcr; (void)memset(&fcr, 0, sizeof(fcr)); fcr.src_fd = fd; fcr.src_offset = 0; fcr.src_length = file_sz; fcr.dest_offset = 0; ret = ioctl(dfd, FICLONERANGE, &fcr); (void)ret; exercised++; } #endif #if defined(FIDEDUPERANGE) { const size_t sz = sizeof(struct file_dedupe_range) + sizeof(struct file_dedupe_range_info); char buf[sz] ALIGNED(64); struct file_dedupe_range *d = (struct file_dedupe_range *)buf; d->src_offset = 0; d->src_length = file_sz; d->dest_count = 1; d->reserved1 = 0; d->reserved2 = 0; d->info[0].dest_fd = dfd; d->info[0].dest_offset = 0; /* Zero the return values */ d->info[0].bytes_deduped = 0; d->info[0].status = 0; d->info[0].reserved = 0; ret = ioctl(fd, FIDEDUPERANGE, d); (void)ret; exercised++; } #endif #if defined(FIONREAD) { int isz = 0; ret = ioctl(fd, FIONREAD, &isz); (void)ret; exercised++; } #endif #if defined(FIONWRITE) { int isz = 0; ret = ioctl(fd, FIONWRITE, &isz); (void)ret; exercised++; } #endif #if defined(FS_IOC_RESVSP) { unsigned long isz = file_sz * 2; ret = ioctl(fd, FS_IOC_RESVP, &isz); (void)ret; exercised++; } #endif #if defined(FS_IOC_RESVSP64) { unsigned long isz = file_sz * 2; ret = ioctl(fd, FS_IOC_RESVP64, &isz); (void)ret; exercised++; } #endif #if defined(FIBMAP) { int block = 0; ret = ioctl(fd, FIBMAP, &block); (void)ret; exercised++; } #endif if (!exercised) { pr_inf("%s: no available file ioctls to exercise\n", args->name); ret = EXIT_NOT_IMPLEMENTED; goto tidy; } inc_counter(args); } while (keep_stressing()); ret = EXIT_SUCCESS; tidy: #if defined(FICLONE) || defined(FICLONERANGE) (void)close(dfd); #endif (void)close(fd); (void)stress_temp_dir_rm_args(args); return ret; }
/* * stress_aio * stress asynchronous I/O */ int stress_aio( uint64_t *const counter, const uint32_t instance, const uint64_t max_ops, const char *name) { int fd, rc = EXIT_FAILURE; io_req_t *io_reqs; struct sigaction sa; int i; uint64_t total = 0; char filename[PATH_MAX]; const pid_t pid = getpid(); if ((io_reqs = calloc((size_t)opt_aio_requests, sizeof(io_req_t))) == NULL) { pr_err(stderr, "%s: cannot allocate io request structures\n", name); return EXIT_FAILURE; } if (stress_temp_dir_mk(name, pid, instance) < 0) { free(io_reqs); return EXIT_FAILURE; } (void)stress_temp_filename(filename, sizeof(filename), name, pid, instance, mwc32()); (void)umask(0077); if ((fd = open(filename, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR)) < 0) { pr_failed_err(name, "open"); goto finish; } (void)unlink(filename); sigemptyset(&sa.sa_mask); sa.sa_flags = SA_RESTART | SA_SIGINFO; sa.sa_sigaction = aio_signal_handler; if (sigaction(SIGUSR1, &sa, NULL) < 0) { pr_failed_err(name, "sigaction"); } /* Kick off requests */ for (i = 0; i < opt_aio_requests; i++) { aio_fill_buffer(i, io_reqs[i].buffer, BUFFER_SZ); if (issue_aio_request(name, fd, (off_t)i * BUFFER_SZ, &io_reqs[i], i, aio_write) < 0) goto cancel; } do { usleep(250000); /* wait until a signal occurs */ for (i = 0; opt_do_run && (i < opt_aio_requests); i++) { if (io_reqs[i].status != EINPROGRESS) continue; io_reqs[i].status = aio_error(&io_reqs[i].aiocb); switch (io_reqs[i].status) { case ECANCELED: case 0: /* Succeeded or cancelled, so redo another */ (*counter)++; if (issue_aio_request(name, fd, (off_t)i * BUFFER_SZ, &io_reqs[i], i, (mwc32() & 0x8) ? aio_read : aio_write) < 0) goto cancel; break; case EINPROGRESS: break; default: /* Something went wrong */ pr_failed_errno(name, "aio_error", io_reqs[i].status); goto cancel; } } } while (opt_do_run && (!max_ops || *counter < max_ops)); rc = EXIT_SUCCESS; cancel: for (i = 0; i < opt_aio_requests; i++) { aio_issue_cancel(name, &io_reqs[i]); total += io_reqs[i].count; } (void)close(fd); finish: pr_dbg(stderr, "%s: total of %" PRIu64 " async I/O signals caught (instance %d)\n", name, total, instance); (void)stress_temp_dir_rm(name, pid, instance); free(io_reqs); return rc; }