4 Copyright (C) 1999-2007 by Andrew Tridgell <tridge@samba.org>
5 Copyright (C) 2001 by Martin Pool <mbp@samba.org>
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, see <http://www.gnu.org/licenses/>.
31 static int find_handle(struct child_struct *child, int handle)
33 struct ftable *ftable = child->private;
35 for (i=0;i<MAX_FILES;i++) {
36 if (ftable[i].handle == handle) return i;
38 printf("(%d) ERROR: handle %d was not found\n",
44 /* Find the directory holding a file, and flush it to disk. We do
45 this in -S mode after a directory-modifying mode, to simulate the
46 way knfsd tries to flush directories. MKDIR and similar operations
47 are meant to be synchronous on NFSv2. */
48 static void sync_parent(struct child_struct *child, const char *fname)
54 if (strchr(fname, '/')) {
55 copy_name = strdup(fname);
56 slash = strrchr(copy_name, '/');
59 copy_name = strdup(".");
62 dir_fd = open(copy_name, O_RDONLY);
64 printf("[%d] open directory \"%s\" for sync failed: %s\n",
65 child->line, copy_name, strerror(errno));
67 #if defined(HAVE_FDATASYNC)
68 if (fdatasync(dir_fd) == -1) {
70 if (fsync(dir_fd) == -1) {
72 printf("[%d] datasync directory \"%s\" failed: %s\n",
73 child->line, copy_name,
76 if (close(dir_fd) == -1) {
77 printf("[%d] close directory failed: %s\n",
78 child->line, strerror(errno));
84 static void xattr_fd_read_hook(struct child_struct *child, int fd)
88 if (options.ea_enable) {
89 memset(buf, 0, sizeof(buf));
90 sys_fgetxattr(fd, "user.DosAttrib", buf, sizeof(buf));
98 static void xattr_fname_read_hook(struct child_struct *child, const char *fname)
101 if (options.ea_enable) {
103 sys_getxattr(fname, "user.DosAttrib", buf, sizeof(buf));
111 static void xattr_fd_write_hook(struct child_struct *child, int fd)
114 if (options.ea_enable) {
117 sys_fgetxattr(fd, "user.DosAttrib", buf, sizeof(buf));
118 memset(buf, 0, sizeof(buf));
119 /* give some probability of sharing */
120 if (random() % 10 < 2) {
121 *(time_t *)buf = time(NULL);
123 gettimeofday(&tv, NULL);
124 memcpy(buf, &tv, sizeof(tv));
126 if (sys_fsetxattr(fd, "user.DosAttrib", buf, sizeof(buf), 0) != 0) {
127 printf("[%d] fsetxattr failed - %s\n",
128 child->line, strerror(errno));
137 static int expected_status(const char *status)
139 if (strcmp(status, "NT_STATUS_OK") == 0) {
142 if (strncmp(status, "0x", 2) == 0 &&
143 strtoul(status, NULL, 16) == 0) {
150 simulate pvfs_resolve_name()
152 static void resolve_name(struct child_struct *child, const char *name)
160 if (name == NULL) return;
162 if (stat(name, &st) == 0) {
163 xattr_fname_read_hook(child, name);
167 if (options.no_resolve) {
171 dname = strdup(name);
172 p = strrchr(dname, '/');
177 dir = opendir(dname);
182 while ((d = readdir(dir))) {
183 if (strcasecmp(fname, d->d_name) == 0) break;
189 static void failed(struct child_struct *child)
192 printf("ERROR: child %d failed at line %d\n", child->id, child->line);
196 static void fio_setup(struct child_struct *child)
198 struct ftable *ftable;
199 ftable = calloc(MAX_FILES, sizeof(struct ftable));
200 child->private = ftable;
201 child->rate.last_time = timeval_current();
202 child->rate.last_bytes = 0;
205 static void fio_unlink(struct dbench_op *op)
207 resolve_name(op->child, op->fname);
209 if (unlink(op->fname) != expected_status(op->status)) {
210 printf("[%d] unlink %s failed (%s) - expected %s\n",
211 op->child->line, op->fname, strerror(errno), op->status);
214 if (options.sync_dirs) sync_parent(op->child, op->fname);
217 static void fio_mkdir(struct dbench_op *op)
220 resolve_name(op->child, op->fname);
221 if (options.stat_check && stat(op->fname, &st) == 0) {
224 mkdir(op->fname, 0777);
227 static void fio_rmdir(struct dbench_op *op)
230 resolve_name(op->child, op->fname);
232 if (options.stat_check &&
233 (stat(op->fname, &st) != 0 || !S_ISDIR(st.st_mode))) {
237 if (rmdir(op->fname) != expected_status(op->status)) {
238 printf("[%d] rmdir %s failed (%s) - expected %s\n",
239 op->child->line, op->fname, strerror(errno), op->status);
242 if (options.sync_dirs) sync_parent(op->child, op->fname);
245 static void fio_createx(struct dbench_op *op)
247 uint32_t create_options = op->params[0];
248 uint32_t create_disposition = op->params[1];
249 int fnum = op->params[2];
253 struct ftable *ftable = (struct ftable *)op->child->private;
255 resolve_name(op->child, op->fname);
257 if (options.sync_open) flags |= O_SYNC;
259 if (create_disposition == FILE_CREATE) {
260 if (options.stat_check && stat(op->fname, &st) == 0) {
261 create_disposition = FILE_OPEN;
267 if (create_disposition == FILE_OVERWRITE ||
268 create_disposition == FILE_OVERWRITE_IF) {
269 flags |= O_CREAT | O_TRUNC;
272 if (create_options & FILE_DIRECTORY_FILE) {
273 /* not strictly correct, but close enough */
274 if (!options.stat_check || stat(op->fname, &st) == -1) {
275 mkdir(op->fname, 0700);
279 if (create_options & FILE_DIRECTORY_FILE) flags = O_RDONLY|O_DIRECTORY;
281 fd = open(op->fname, flags, 0600);
282 if (fd == -1 && errno == EISDIR) {
283 flags = O_RDONLY|O_DIRECTORY;
284 fd = open(op->fname, flags, 0600);
287 if (expected_status(op->status) == 0) {
288 printf("[%d] open %s failed for handle %d (%s)\n",
289 op->child->line, op->fname, fnum, strerror(errno));
293 if (expected_status(op->status) != 0) {
294 printf("[%d] open %s succeeded for handle %d\n",
295 op->child->line, op->fname, fnum);
300 for (i=0;i<MAX_FILES;i++) {
301 if (ftable[i].handle == 0) break;
303 if (i == MAX_FILES) {
304 printf("file table full for %s\n", op->fname);
307 ftable[i].name = strdup(op->fname);
308 ftable[i].handle = fnum;
313 if (!S_ISDIR(st.st_mode)) {
314 xattr_fd_write_hook(op->child, fd);
318 static void fio_writex(struct dbench_op *op)
320 int handle = op->params[0];
321 int offset = op->params[1];
322 int size = op->params[2];
323 int ret_size = op->params[3];
324 int i = find_handle(op->child, handle);
327 struct ftable *ftable = (struct ftable *)op->child->private;
330 if (options.fake_io) {
331 op->child->bytes += ret_size;
332 op->child->bytes_since_fsync += ret_size;
336 buf = calloc(size, 1);
338 if (options.one_byte_write_fix &&
339 size == 1 && fstat(ftable[i].fd, &st) == 0) {
340 if (st.st_size > offset) {
342 pread(ftable[i].fd, &c, 1, offset);
343 if (c == ((unsigned char *)buf)[0]) {
345 op->child->bytes += size;
348 } else if (((unsigned char *)buf)[0] == 0) {
349 ftruncate(ftable[i].fd, offset+1);
351 op->child->bytes += size;
356 ret = pwrite(ftable[i].fd, buf, size, offset);
358 printf("[%d] write failed on handle %d (%s)\n",
359 op->child->line, handle, strerror(errno));
362 if (ret != ret_size) {
363 printf("[%d] wrote %d bytes, expected to write %d bytes on handle %d\n",
364 op->child->line, (int)ret, (int)ret_size, handle);
368 if (options.do_fsync) fsync(ftable[i].fd);
372 op->child->bytes += size;
373 op->child->bytes_since_fsync += size;
376 static void fio_readx(struct dbench_op *op)
378 int handle = op->params[0];
379 int offset = op->params[1];
380 int size = op->params[2];
381 int ret_size = op->params[3];
382 int i = find_handle(op->child, handle);
384 struct ftable *ftable = (struct ftable *)op->child->private;
386 if (options.fake_io) {
387 op->child->bytes += ret_size;
393 if (pread(ftable[i].fd, buf, size, offset) != ret_size) {
394 printf("[%d] read failed on handle %d (%s)\n",
395 op->child->line, handle, strerror(errno));
400 op->child->bytes += size;
403 static void fio_close(struct dbench_op *op)
405 int handle = op->params[0];
406 struct ftable *ftable = (struct ftable *)op->child->private;
407 int i = find_handle(op->child, handle);
409 ftable[i].handle = 0;
410 if (ftable[i].name) free(ftable[i].name);
411 ftable[i].name = NULL;
414 static void fio_rename(struct dbench_op *op)
416 const char *old = op->fname;
417 const char *new = op->fname2;
419 resolve_name(op->child, old);
420 resolve_name(op->child, new);
422 if (options.stat_check) {
424 if (stat(old, &st) != 0 && expected_status(op->status) == 0) {
425 printf("[%d] rename %s %s failed - file doesn't exist\n",
426 op->child->line, old, new);
432 if (rename(old, new) != expected_status(op->status)) {
433 printf("[%d] rename %s %s failed (%s) - expected %s\n",
434 op->child->line, old, new, strerror(errno), op->status);
437 if (options.sync_dirs) sync_parent(op->child, new);
440 static void fio_flush(struct dbench_op *op)
442 int handle = op->params[0];
443 struct ftable *ftable = (struct ftable *)op->child->private;
444 int i = find_handle(op->child, handle);
448 static void fio_qpathinfo(struct dbench_op *op)
450 resolve_name(op->child, op->fname);
453 static void fio_qfileinfo(struct dbench_op *op)
455 int handle = op->params[0];
456 int level = op->params[1];
457 struct ftable *ftable = (struct ftable *)op->child->private;
459 int i = find_handle(op->child, handle);
462 fstat(ftable[i].fd, &st);
463 xattr_fd_read_hook(op->child, ftable[i].fd);
466 static void fio_qfsinfo(struct dbench_op *op)
468 int level = op->params[0];
473 statvfs(op->child->directory, &st);
476 static void fio_findfirst(struct dbench_op *op)
478 int level = op->params[0];
479 int maxcnt = op->params[1];
480 int count = op->params[2];
489 resolve_name(op->child, op->fname);
491 if (strpbrk(op->fname, "<>*?\"") == NULL) {
495 p = strrchr(op->fname, '/');
498 dir = opendir(op->fname);
500 while (maxcnt && (d = readdir(dir))) maxcnt--;
504 static void fio_deltree(struct dbench_op *op)
509 d = opendir(op->fname);
510 if (d == NULL) return;
512 for (de=readdir(d);de;de=readdir(d)) {
515 if (strcmp(de->d_name, ".") == 0 ||
516 strcmp(de->d_name, "..") == 0) {
519 asprintf(&fname, "%s/%s", op->fname, de->d_name);
521 printf("Out of memory\n");
524 if (stat(fname, &st) != 0) {
527 if (S_ISDIR(st.st_mode)) {
528 struct dbench_op op2 = *op;
532 if (unlink(fname) != 0) {
533 printf("[%d] unlink '%s' failed - %s\n",
534 op->child->line, fname, strerror(errno));
542 static void fio_cleanup(struct child_struct *child)
549 asprintf(&dname, "%s/clients/client%d", child->directory, child->id);
555 asprintf(&dname, "%s%s", child->directory, "/clients");
561 static void fio_sfileinfo(struct dbench_op *op)
563 int handle = op->params[0];
564 int level = op->params[1];
565 struct ftable *ftable = (struct ftable *)op->child->private;
566 int i = find_handle(op->child, handle);
572 xattr_fd_read_hook(op->child, ftable[i].fd);
574 fstat(ftable[i].fd, &st);
576 tm.actime = st.st_atime - 10;
577 tm.modtime = st.st_mtime - 12;
579 utime(ftable[i].name, &tm);
581 if (!S_ISDIR(st.st_mode)) {
582 xattr_fd_write_hook(op->child, ftable[i].fd);
586 static void fio_lockx(struct dbench_op *op)
588 int handle = op->params[0];
589 uint32_t offset = op->params[1];
590 int size = op->params[2];
591 struct ftable *ftable = (struct ftable *)op->child->private;
592 int i = find_handle(op->child, handle);
597 lock.l_type = F_WRLCK;
598 lock.l_whence = SEEK_SET;
599 lock.l_start = offset;
603 fcntl(ftable[i].fd, F_SETLKW, &lock);
606 static void fio_unlockx(struct dbench_op *op)
608 int handle = op->params[0];
609 uint32_t offset = op->params[1];
610 int size = op->params[2];
611 struct ftable *ftable = (struct ftable *)op->child->private;
612 int i = find_handle(op->child, handle);
615 lock.l_type = F_UNLCK;
616 lock.l_whence = SEEK_SET;
617 lock.l_start = offset;
621 fcntl(ftable[i].fd, F_SETLKW, &lock);
624 static struct backend_op ops[] = {
625 { "Deltree", fio_deltree },
626 { "Flush", fio_flush },
627 { "Close", fio_close },
628 { "LockX", fio_lockx },
629 { "Rmdir", fio_rmdir },
630 { "Mkdir", fio_mkdir },
631 { "Rename", fio_rename },
632 { "ReadX", fio_readx },
633 { "WriteX", fio_writex },
634 { "Unlink", fio_unlink },
635 { "UnlockX", fio_unlockx },
636 { "FIND_FIRST", fio_findfirst },
637 { "SET_FILE_INFORMATION", fio_sfileinfo },
638 { "QUERY_FILE_INFORMATION", fio_qfileinfo },
639 { "QUERY_PATH_INFORMATION", fio_qpathinfo },
640 { "QUERY_FS_INFORMATION", fio_qfsinfo },
641 { "NTCreateX", fio_createx },
645 struct nb_operations fileio_ops = {
646 .backend_name = "dbench",
648 .cleanup = fio_cleanup,