[dbench @ cvs-1:tridge-20070624144947-nvb9q50s9ps3a3al]
[tridge/dbench.git] / fileio.c
1 /* 
2    dbench version 2
3    Copyright (C) 1999 by Andrew Tridgell <tridge@samba.org>
4    Copyright (C) 2001 by Martin Pool <mbp@samba.org>
5    
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include "dbench.h"
22
23 #define MAX_FILES 200
24
25 char *server = NULL;
26 extern int sync_open, sync_dirs, do_fsync;
27
28 static struct {
29         char *name;
30         int fd;
31         int handle;
32 } ftable[MAX_FILES];
33
34 static int find_handle(struct child_struct *child, int handle)
35 {
36         int i;
37         for (i=0;i<MAX_FILES;i++) {
38                 if (ftable[i].handle == handle) return i;
39         }
40         printf("(%d) ERROR: handle %d was not found\n", 
41                child->line, handle);
42         exit(1);
43 }
44
45
46 /* Find the directory holding a file, and flush it to disk.  We do
47    this in -S mode after a directory-modifying mode, to simulate the
48    way knfsd tries to flush directories.  MKDIR and similar operations
49    are meant to be synchronous on NFSv2. */
50 static void sync_parent(char *fname)
51 {
52         char *copy_name;
53         int dir_fd;
54         char *slash;
55
56         if (strchr(fname, '/')) {
57                 copy_name = strdup(fname);
58                 slash = strrchr(copy_name, '/');
59                 *slash = '\0';
60         } else {
61                 copy_name = strdup(".");
62         } 
63         
64         dir_fd = open(copy_name, O_RDONLY);
65         if (dir_fd == -1) {
66                 printf("open directory \"%s\" for sync failed: %s\n",
67                        copy_name,
68                        strerror(errno));
69         } else {
70 #if defined(HAVE_FDATASYNC)
71                 if (fdatasync(dir_fd) == -1) {
72 #else
73                 if (fsync(dir_fd) == -1) {
74 #endif
75                         printf("datasync directory \"%s\" failed: %s\n",
76                                copy_name,
77                                strerror(errno));
78                 }
79                 if (close(dir_fd) == -1) {
80                         printf("close directory failed: %s\n",
81                                strerror(errno));
82                 }
83         }
84         free(copy_name);
85 }
86
87 static void xattr_fd_read_hook(int fd)
88 {
89 #if HAVE_EA_SUPPORT
90         extern int ea_enable;
91         char buf[44];
92         if (ea_enable) {
93                 memset(buf, 0, sizeof(buf));
94                 sys_fgetxattr(fd, "user.DosAttrib", buf, sizeof(buf));
95         }
96 #else
97         (void)fd;
98 #endif
99 }
100
101 static void xattr_fname_read_hook(const char *fname)
102 {
103 #if HAVE_EA_SUPPORT
104         extern int ea_enable;
105         if (ea_enable) {
106                 char buf[44];
107                 sys_getxattr(fname, "user.DosAttrib", buf, sizeof(buf));
108         }
109 #else
110         (void)fname;
111 #endif
112 }
113
114 static void xattr_fd_write_hook(int fd)
115 {
116 #if HAVE_EA_SUPPORT
117         extern int ea_enable;
118         if (ea_enable) {
119                 struct timeval tv;
120                 char buf[44];
121                 sys_fgetxattr(fd, "user.DosAttrib", buf, sizeof(buf));
122                 memset(buf, 0, sizeof(buf));
123                 /* give some probability of sharing */
124                 if (random() % 10 < 2) {
125                         *(time_t *)buf = time(NULL);
126                 } else {
127                         gettimeofday(&tv, NULL);
128                         memcpy(buf, &tv, sizeof(tv));
129                 }
130                 if (sys_fsetxattr(fd, "user.DosAttrib", buf, sizeof(buf), 0) != 0) {
131                         printf("fsetxattr failed - %s\n", strerror(errno));
132                         exit(1);
133                 }
134         }
135 #else
136         (void)fd;
137 #endif
138 }
139
140 static int expected_status(const char *status)
141 {
142         if (strcmp(status, "NT_STATUS_OK") == 0) {
143                 return 0;
144         }
145         if (strncmp(status, "0x", 2) == 0 &&
146             strtoul(status, NULL, 16) == 0) {
147                 return 0;
148         }
149         return -1;
150 }
151
152 /*
153   simulate pvfs_resolve_name()
154 */
155 static void resolve_name(const char *name)
156 {
157         struct stat st;
158         char *dname, *fname;
159         DIR *dir;
160         char *p;
161         struct dirent *d;
162
163         if (name == NULL) return;
164
165         if (stat(name, &st) == 0) {
166                 xattr_fname_read_hook(name);
167                 return;
168         }
169
170         dname = strdup(name);
171         p = strrchr(dname, '/');
172         if (!p) return;
173         *p = 0;
174         fname = p+1;
175
176         dir = opendir(dname);
177         if (!dir) {
178                 free(dname);
179                 return;
180         }
181         while ((d = readdir(dir))) {
182                 if (strcasecmp(fname, d->d_name) == 0) break;
183         }
184         closedir(dir);
185         free(dname);
186 }
187
188 static void failed(struct child_struct *child)
189 {
190         child->failed = 1;
191         printf("ERROR: child %d failed\n", child->id);
192         exit(1);
193 }
194
195 void nb_setup(struct child_struct *child)
196 {
197         (void)child;
198 }
199
200 void nb_unlink(struct child_struct *child, char *fname, int attr, const char *status)
201 {
202         (void)attr;
203
204         resolve_name(fname);
205
206         if (unlink(fname) != expected_status(status)) {
207                 printf("(%d) unlink %s failed (%s) - expected %s\n", 
208                        child->line, fname, strerror(errno), status);
209                 failed(child);
210         }
211         if (sync_dirs) sync_parent(fname);
212 }
213
214 void nb_mkdir(struct child_struct *child, char *dname, const char *status)
215 {
216         (void)child;
217         (void)status;
218         resolve_name(dname);
219         mkdir(dname, 0777);
220 }
221
222 void nb_rmdir(struct child_struct *child, char *fname, const char *status)
223 {
224         resolve_name(fname);
225
226         if (rmdir(fname) != expected_status(status)) {
227                 printf("(%d) rmdir %s failed (%s) - expected %s\n", 
228                        child->line, fname, strerror(errno), status);
229                 failed(child);
230         }
231         if (sync_dirs) sync_parent(fname);
232 }
233
234 void nb_createx(struct child_struct *child, const char *fname, 
235                 uint32_t create_options, uint32_t create_disposition, int fnum,
236                 const char *status)
237 {
238         int fd, i;
239         int flags = O_RDWR;
240         struct stat st;
241
242         resolve_name(fname);
243
244         if (sync_open) flags |= O_SYNC;
245
246         if (create_disposition == FILE_CREATE) {
247                 flags |= O_CREAT;
248         }
249
250         if (create_disposition == FILE_OVERWRITE ||
251             create_disposition == FILE_OVERWRITE_IF) {
252                 flags |= O_CREAT | O_TRUNC;
253         }
254
255         if (create_options & FILE_DIRECTORY_FILE) {
256                 /* not strictly correct, but close enough */
257                 mkdir(fname, 0700);
258         }
259
260         if (create_options & FILE_DIRECTORY_FILE) flags = O_RDONLY|O_DIRECTORY;
261
262         fd = open(fname, flags, 0600);
263         if (fd == -1 && errno == EISDIR) {
264                 flags = O_RDONLY|O_DIRECTORY;
265                 fd = open(fname, flags, 0600);
266         }
267         if (fd == -1) {
268                 if (expected_status(status) == 0) {
269                         printf("(%d) open %s failed for handle %d (%s)\n", 
270                                child->line, fname, fnum, strerror(errno));
271                 }
272                 return;
273         }
274         if (expected_status(status) != 0) {
275                 printf("(%d) open %s succeeded for handle %d\n", 
276                        child->line, fname, fnum);
277                 close(fd);
278                 return;
279         }
280         
281         for (i=0;i<MAX_FILES;i++) {
282                 if (ftable[i].handle == 0) break;
283         }
284         if (i == MAX_FILES) {
285                 printf("file table full for %s\n", fname);
286                 exit(1);
287         }
288         ftable[i].name = strdup(fname);
289         ftable[i].handle = fnum;
290         ftable[i].fd = fd;
291
292         fstat(fd, &st);
293
294         if (!S_ISDIR(st.st_mode)) {
295                 xattr_fd_write_hook(fd);
296         }
297 }
298
299 void nb_writex(struct child_struct *child, int handle, int offset, 
300                int size, int ret_size, const char *status)
301 {
302         int i = find_handle(child, handle);
303         void *buf;
304         struct stat st;
305
306         (void)status;
307
308         buf = calloc(size, 1);
309
310         if (size == 1 && fstat(ftable[i].fd, &st) == 0) {
311                 if (st.st_size > offset) {
312                         unsigned char c;
313                         pread(ftable[i].fd, &c, 1, offset);
314                         if (c == ((unsigned char *)buf)[0]) {
315                                 free(buf);
316                                 child->bytes += size;
317                                 return;
318                         }
319                 } else if (((unsigned char *)buf)[0] == 0) {
320                         ftruncate(ftable[i].fd, offset+1);
321                         free(buf);
322                         child->bytes += size;
323                         return;
324                 } 
325         }
326
327         if (pwrite(ftable[i].fd, buf, size, offset) != ret_size) {
328                 printf("write failed on handle %d (%s)\n", handle, strerror(errno));
329                 exit(1);
330         }
331
332         if (do_fsync) fsync(ftable[i].fd);
333
334         free(buf);
335
336         child->bytes += size;
337 }
338
339 void nb_readx(struct child_struct *child, int handle, int offset, 
340               int size, int ret_size, const char *status)
341 {
342         int i = find_handle(child, handle);
343         void *buf;
344
345         (void)status;
346
347         buf = malloc(size);
348
349         if (pread(ftable[i].fd, buf, size, offset) != ret_size) {
350                 printf("read failed on handle %d (%s)\n", handle, strerror(errno));
351         }
352
353         free(buf);
354
355         child->bytes += size;
356 }
357
358 void nb_close(struct child_struct *child, int handle, const char *status)
359 {
360         int i = find_handle(child, handle);
361         (void)status;
362         close(ftable[i].fd);
363         ftable[i].handle = 0;
364         if (ftable[i].name) free(ftable[i].name);
365         ftable[i].name = NULL;
366 }
367
368 void nb_rename(struct child_struct *child, char *old, char *new, const char *status)
369 {
370         resolve_name(old);
371         resolve_name(new);
372
373         if (rename(old, new) != expected_status(status)) {
374                 printf("rename %s %s failed (%s) - expected %s\n", 
375                        old, new, strerror(errno), status);
376                 failed(child);
377         }
378         if (sync_dirs) sync_parent(new);
379 }
380
381 void nb_flush(struct child_struct *child, int handle, const char *status)
382 {
383         (void)status;
384         find_handle(child, handle);
385         /* noop */
386 }
387
388 void nb_qpathinfo(struct child_struct *child, const char *fname, int level, 
389                   const char *status)
390 {
391         (void)child;
392         (void)level;
393         (void)status;
394         resolve_name(fname);
395 }
396
397 void nb_qfileinfo(struct child_struct *child, int handle, int level, const char *status)
398 {
399         struct stat st;
400         int i = find_handle(child, handle);
401         (void)child;
402         (void)level;
403         (void)status;
404         fstat(ftable[i].fd, &st);
405         xattr_fd_read_hook(ftable[i].fd);
406 }
407
408 void nb_qfsinfo(struct child_struct *child, int level, const char *status)
409 {
410         struct statvfs st;
411
412         (void)level;
413         (void)status;
414
415         statvfs(child->directory, &st);
416 }
417
418 void nb_findfirst(struct child_struct *child, char *fname, int level, int maxcnt, 
419                   int count, const char *status)
420 {
421         DIR *dir;
422         struct dirent *d;
423         char *p;
424
425         (void)child;
426         (void)level;
427         (void)count;
428         (void)status;
429
430         resolve_name(fname);
431
432         if (strpbrk(fname, "<>*?\"") == NULL) {
433                 return;
434         }
435
436         p = strrchr(fname, '/');
437         if (!p) return;
438         *p = 0;
439         dir = opendir(fname);
440         if (!dir) return;
441         while (maxcnt && (d = readdir(dir))) maxcnt--;
442         closedir(dir);
443 }
444
445 void nb_cleanup(struct child_struct *child)
446 {
447         char *dname;
448
449         asprintf(&dname, "%s/clients/client%d", child->directory, child->id);
450         nb_deltree(child, dname);
451         free(dname);
452
453         asprintf(&dname, "%s%s", child->directory, "/clients");
454         rmdir(dname);
455         free(dname);
456 }
457
458 void nb_deltree(struct child_struct *child, char *dname)
459 {
460         char *path;
461         (void)child;
462         asprintf(&path, "/bin/rm -rf %s", dname);
463         system(path);
464         free(path);
465 }
466
467 void nb_sfileinfo(struct child_struct *child, int handle, int level, const char *status)
468 {
469         int i = find_handle(child, handle);
470         struct utimbuf tm;
471         struct stat st;
472         (void)child;
473         (void)handle;
474         (void)level;
475         (void)status;
476         xattr_fd_read_hook(ftable[i].fd);
477
478         fstat(ftable[i].fd, &st);
479
480         tm.actime = st.st_atime - 10;
481         tm.modtime = st.st_mtime - 12;
482
483         utime(ftable[i].name, &tm);
484
485         if (!S_ISDIR(st.st_mode)) {
486                 xattr_fd_write_hook(ftable[i].fd);
487         }
488 }
489
490 void nb_lockx(struct child_struct *child, int handle, uint32_t offset, int size, 
491               const char *status)
492 {
493         int i = find_handle(child, handle);
494         struct flock lock;
495
496         (void)child;
497         (void)status;
498
499         lock.l_type = F_WRLCK;
500         lock.l_whence = SEEK_SET;
501         lock.l_start = offset;
502         lock.l_len = size;
503         lock.l_pid = 0;
504
505         fcntl(ftable[i].fd, F_SETLKW, &lock);
506 }
507
508 void nb_unlockx(struct child_struct *child,
509                 int handle, uint32_t offset, int size, const char *status)
510 {
511         int i = find_handle(child, handle);
512         struct flock lock;
513
514         (void)child;
515         (void)status;
516
517         lock.l_type = F_UNLCK;
518         lock.l_whence = SEEK_SET;
519         lock.l_start = offset;
520         lock.l_len = size;
521         lock.l_pid = 0;
522
523         fcntl(ftable[i].fd, F_SETLKW, &lock);
524 }
525
526 void nb_sleep(struct child_struct *child, int usec, const char *status)
527 {
528         (void)child;
529         (void)usec;
530         (void)status;
531         usleep(usec);
532 }