989ce471c38fc586b2f63daf41c5347e2afa8934
[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;
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) return 0;
143         return -1;
144 }
145
146 /*
147   simulate pvfs_resolve_name()
148 */
149 static void resolve_name(const char *name)
150 {
151         struct stat st;
152         char *dname, *fname;
153         DIR *dir;
154         char *p;
155         struct dirent *d;
156
157         if (stat(name, &st) == 0) {
158                 xattr_fname_read_hook(name);
159                 return;
160         }
161
162         dname = strdup(name);
163         p = strrchr(dname, '/');
164         if (!p) return;
165         *p = 0;
166         fname = p+1;
167
168         dir = opendir(dname);
169         if (!dir) {
170                 free(dname);
171                 return;
172         }
173         while ((d = readdir(dir))) {
174                 if (strcasecmp(fname, d->d_name) == 0) break;
175         }
176         closedir(dir);
177         free(dname);
178 }
179
180 static void failed(struct child_struct *child)
181 {
182         child->failed = 1;
183         printf("ERROR: child %d failed\n", child->id);
184         exit(1);
185 }
186
187 void nb_setup(struct child_struct *child)
188 {
189         (void)child;
190 }
191
192 void nb_unlink(struct child_struct *child, char *fname, int attr, const char *status)
193 {
194         (void)attr;
195
196         resolve_name(fname);
197
198         if (unlink(fname) != expected_status(status)) {
199                 printf("(%d) unlink %s failed (%s) - expected %s\n", 
200                        child->line, fname, strerror(errno), status);
201                 failed(child);
202         }
203         if (sync_dirs) sync_parent(fname);
204 }
205
206 void nb_mkdir(struct child_struct *child, char *dname, const char *status)
207 {
208         (void)child;
209         (void)status;
210         resolve_name(dname);
211         mkdir(dname, 0777);
212 }
213
214 void nb_rmdir(struct child_struct *child, char *fname, const char *status)
215 {
216         resolve_name(fname);
217
218         if (rmdir(fname) != expected_status(status)) {
219                 printf("(%d) rmdir %s failed (%s) - expected %s\n", 
220                        child->line, fname, strerror(errno), status);
221                 failed(child);
222         }
223         if (sync_dirs) sync_parent(fname);
224 }
225
226 void nb_createx(struct child_struct *child, const char *fname, 
227                 uint32_t create_options, uint32_t create_disposition, int fnum,
228                 const char *status)
229 {
230         int fd, i;
231         int flags = O_RDWR;
232         struct stat st;
233
234         resolve_name(fname);
235
236         if (sync_open) flags |= O_SYNC;
237
238         if (create_disposition == FILE_CREATE) {
239                 flags |= O_CREAT;
240         }
241
242         if (create_disposition == FILE_OVERWRITE ||
243             create_disposition == FILE_OVERWRITE_IF) {
244                 flags |= O_CREAT | O_TRUNC;
245         }
246
247         if (create_options & FILE_DIRECTORY_FILE) {
248                 /* not strictly correct, but close enough */
249                 mkdir(fname, 0700);
250         }
251
252         if (create_options & FILE_DIRECTORY_FILE) flags = O_RDONLY|O_DIRECTORY;
253
254         fd = open(fname, flags, 0600);
255         if (fd == -1) {
256                 if (strcmp(status, "NT_STATUS_OK") == 0) {
257                         printf("(%d) open %s failed for handle %d (%s)\n", 
258                                child->line, fname, fnum, strerror(errno));
259                 }
260                 return;
261         }
262         if (strcmp(status, "NT_STATUS_OK") != 0) {
263                 printf("(%d) open %s succeeded for handle %d\n", 
264                        child->line, fname, fnum);
265                 close(fd);
266                 return;
267         }
268         
269         for (i=0;i<MAX_FILES;i++) {
270                 if (ftable[i].handle == 0) break;
271         }
272         if (i == MAX_FILES) {
273                 printf("file table full for %s\n", fname);
274                 exit(1);
275         }
276         ftable[i].name = strdup(fname);
277         ftable[i].handle = fnum;
278         ftable[i].fd = fd;
279
280         fstat(fd, &st);
281
282         if (!S_ISDIR(st.st_mode)) {
283                 xattr_fd_write_hook(fd);
284         }
285 }
286
287 void nb_writex(struct child_struct *child, int handle, int offset, 
288                int size, int ret_size, const char *status)
289 {
290         int i = find_handle(child, handle);
291         void *buf;
292
293         (void)status;
294
295         buf = calloc(size, 1);
296
297         if (pwrite(ftable[i].fd, buf, size, offset) != ret_size) {
298                 printf("write failed on handle %d (%s)\n", handle, strerror(errno));
299                 exit(1);
300         }
301
302         free(buf);
303
304         child->bytes += size;
305 }
306
307 void nb_readx(struct child_struct *child, int handle, int offset, 
308               int size, int ret_size, const char *status)
309 {
310         int i = find_handle(child, handle);
311         void *buf;
312
313         (void)status;
314
315         buf = malloc(size);
316
317         if (pread(ftable[i].fd, buf, size, offset) != ret_size) {
318                 printf("read failed on handle %d (%s)\n", handle, strerror(errno));
319         }
320
321         free(buf);
322
323         child->bytes += size;
324 }
325
326 void nb_close(struct child_struct *child, int handle, const char *status)
327 {
328         int i = find_handle(child, handle);
329         (void)status;
330         close(ftable[i].fd);
331         ftable[i].handle = 0;
332         if (ftable[i].name) free(ftable[i].name);
333         ftable[i].name = NULL;
334 }
335
336 void nb_rename(struct child_struct *child, char *old, char *new, const char *status)
337 {
338         resolve_name(old);
339         resolve_name(new);
340
341         if (rename(old, new) != expected_status(status)) {
342                 printf("rename %s %s failed (%s) - expected %s\n", 
343                        old, new, strerror(errno), status);
344                 failed(child);
345         }
346         if (sync_dirs) sync_parent(new);
347 }
348
349 void nb_flush(struct child_struct *child, int handle, const char *status)
350 {
351         (void)status;
352         find_handle(child, handle);
353         /* noop */
354 }
355
356 void nb_qpathinfo(struct child_struct *child, const char *fname, int level, 
357                   const char *status)
358 {
359         (void)child;
360         (void)level;
361         (void)status;
362         resolve_name(fname);
363 }
364
365 void nb_qfileinfo(struct child_struct *child, int handle, int level, const char *status)
366 {
367         struct stat st;
368         int i = find_handle(child, handle);
369         (void)child;
370         (void)level;
371         (void)status;
372         fstat(ftable[i].fd, &st);
373         xattr_fd_read_hook(ftable[i].fd);
374 }
375
376 void nb_qfsinfo(struct child_struct *child, int level, const char *status)
377 {
378         struct statvfs st;
379
380         (void)level;
381         (void)status;
382
383         statvfs(child->directory, &st);
384 }
385
386 void nb_findfirst(struct child_struct *child, char *fname, int level, int maxcnt, 
387                   int count, const char *status)
388 {
389         DIR *dir;
390         struct dirent *d;
391         char *p;
392
393         (void)child;
394         (void)level;
395         (void)count;
396         (void)status;
397
398         resolve_name(fname);
399
400         if (strpbrk(fname, "<>*?\"") == NULL) {
401                 return;
402         }
403
404         p = strrchr(fname, '/');
405         if (!p) return;
406         *p = 0;
407         dir = opendir(fname);
408         if (!dir) return;
409         while (maxcnt && (d = readdir(dir))) maxcnt--;
410         closedir(dir);
411 }
412
413 void nb_cleanup(struct child_struct *child)
414 {
415         char *dname;
416
417         asprintf(&dname, "%s/clients/client%d", child->directory, child->id);
418         nb_deltree(child, dname);
419         free(dname);
420
421         asprintf(&dname, "%s%s", child->directory, "/clients");
422         rmdir(dname);
423         free(dname);
424 }
425
426 void nb_deltree(struct child_struct *child, char *dname)
427 {
428         char *path;
429         (void)child;
430         asprintf(&path, "/bin/rm -rf %s", dname);
431         system(path);
432         free(path);
433 }
434
435 void nb_sfileinfo(struct child_struct *child, int handle, int level, const char *status)
436 {
437         int i = find_handle(child, handle);
438         struct utimbuf tm;
439         struct stat st;
440         (void)child;
441         (void)handle;
442         (void)level;
443         (void)status;
444         xattr_fd_read_hook(ftable[i].fd);
445
446         fstat(ftable[i].fd, &st);
447
448         tm.actime = st.st_atime - 10;
449         tm.modtime = st.st_mtime - 12;
450
451         utime(ftable[i].name, &tm);
452
453         if (!S_ISDIR(st.st_mode)) {
454                 xattr_fd_write_hook(ftable[i].fd);
455         }
456 }
457
458 void nb_lockx(struct child_struct *child, int handle, uint32_t offset, int size, 
459               const char *status)
460 {
461         int i = find_handle(child, handle);
462         struct flock lock;
463
464         (void)child;
465         (void)status;
466
467         lock.l_type = F_WRLCK;
468         lock.l_whence = SEEK_SET;
469         lock.l_start = offset;
470         lock.l_len = size;
471         lock.l_pid = 0;
472
473         fcntl(ftable[i].fd, F_SETLKW, &lock);
474 }
475
476 void nb_unlockx(struct child_struct *child,
477                 int handle, uint32_t offset, int size, const char *status)
478 {
479         int i = find_handle(child, handle);
480         struct flock lock;
481
482         (void)child;
483         (void)status;
484
485         lock.l_type = F_UNLCK;
486         lock.l_whence = SEEK_SET;
487         lock.l_start = offset;
488         lock.l_len = size;
489         lock.l_pid = 0;
490
491         fcntl(ftable[i].fd, F_SETLKW, &lock);
492 }
493
494 void nb_sleep(struct child_struct *child, int usec, const char *status)
495 {
496         (void)child;
497         (void)usec;
498         (void)status;
499         usleep(usec);
500 }