9d28a086ad8510e544d6e15cae1bd4491e8b22c2
[tridge/dbench.git] / nfsio.c
1 /* 
2    nfs backend for dbench
3
4    Copyright (C) 2008 by Ronnie Sahlberg (ronniesahlberg@gmail.com)
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 3 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, see <http://www.gnu.org/licenses/>.
18 */
19
20 #define _GNU_SOURCE
21 #include <stdio.h>
22 #undef _GNU_SOURCE
23
24 #include "mount.h"
25 #include "nfs.h"
26 #include "libnfs.h"
27 #include "dbench.h"
28
29 #define discard_const(ptr) ((void *)((intptr_t)(ptr)))
30
31 #define MAX_FILES 200
32
33 static char rw_buf[65536];
34
35
36 void nb_sleep(struct child_struct *child, int usec, const char *status)
37 {
38         (void)child;
39         (void)usec;
40         (void)status;
41         usleep(usec);
42 }
43
44 struct cb_data {
45         struct nfsio *nfsio;
46         char *dirname;
47 };
48
49 static void dirent_cb(struct entryplus3 *e, void *private_data)
50 {
51         struct cb_data *cbd = private_data;
52         nfsstat3 res;
53         char *objname;
54
55         if (!strcmp(cbd->dirname,".")) {
56                 return;
57         }
58         if (!strcmp(cbd->dirname,"..")) {
59                 return;
60         }
61
62         asprintf(&objname, "%s/%s", cbd->dirname, e->name);
63         if (objname == NULL) {
64                 printf("Failed to talloc ne object name in dirent_cb\n");
65                 exit(10);
66         }
67
68         if (e->name_attributes.post_op_attr_u.attributes.type == NF3DIR) {
69                 struct cb_data *new_cbd = malloc(sizeof(struct cb_data));
70
71                 new_cbd->nfsio = cbd->nfsio;
72                 new_cbd->dirname = strdup(objname);
73
74                 nfsio_readdirplus(cbd->nfsio, objname, dirent_cb, new_cbd);
75                 
76                 res = nfsio_rmdir(cbd->nfsio, objname);
77                 if (res != NFS3_OK) {
78                         printf("Failed to remove object : \"%s\"  %s (%d)\n", objname, nfs_error(res), res);
79                         free(objname);
80                         free(new_cbd->dirname);
81                         free(new_cbd);
82                         exit(10);
83                 }
84
85
86                 free(objname);
87                 free(new_cbd->dirname);
88                 free(new_cbd);
89                 return;
90         }
91
92         res = nfsio_remove(cbd->nfsio, objname);
93         if (res != NFS3_OK) {
94                 printf("Failed to remove object : \"%s\" %s %d\n", objname, nfs_error(res), res);
95                 free(objname);
96                 exit(10);
97         }
98
99         free(objname);
100 }
101
102 static void nfs3_deltree(struct child_struct *child, const char *dname)
103 {
104         struct cb_data *cbd;
105         nfsstat3 res;
106         
107         cbd = malloc(sizeof(struct cb_data));
108
109         cbd->nfsio = child->private;
110         cbd->dirname = discard_const(dname);
111
112         res = nfsio_lookup(cbd->nfsio, cbd->dirname, NULL);
113         if (res != NFS3ERR_NOENT) {
114                 nfsio_readdirplus(cbd->nfsio, cbd->dirname, dirent_cb, cbd);
115                 nfsio_rmdir(cbd->nfsio, cbd->dirname);
116         }
117
118         res = nfsio_lookup(cbd->nfsio, cbd->dirname, NULL);
119         if (res != NFS3ERR_NOENT) {
120                 printf("Directory \"%s\" not empty. Aborting\n");
121                 free(cbd);
122                 exit(10);
123         }
124         free(cbd);
125 }
126
127 static int expected_status(const char *status)
128 {
129         if (strncmp(status, "0x", 2) == 0) {
130                 return strtol(status, NULL, 16);
131         }
132 }
133
134 static void failed(struct child_struct *child)
135 {
136         child->failed = 1;
137         printf("ERROR: child %d failed at line %d\n", child->id, child->line);
138         exit(1);
139 }
140
141 static void nfs3_getattr(struct child_struct *child, const char *fname, const char *status)
142 {
143         nfsstat3 res;
144
145         res = nfsio_getattr(child->private, fname, NULL);
146         if (res != expected_status(status)) {
147                 printf("[%d] GETATTR \"%s\" failed (%x) - expected %x\n", 
148                        child->line, fname, res, expected_status(status));
149                 failed(child);
150         }
151 }
152
153
154 static void nfs3_lookup(struct child_struct *child, const char *fname, const char *status)
155 {
156         nfsstat3 res;
157
158         res = nfsio_lookup(child->private, fname, NULL);
159         if (res != expected_status(status)) {
160                 printf("[%d] LOOKUP \"%s\" failed (%x) - expected %x\n", 
161                        child->line, fname, res, expected_status(status));
162                 failed(child);
163         }
164 }
165
166 static void nfs3_create(struct child_struct *child, const char *fname, const char *status)
167 {
168         nfsstat3 res;
169
170         res = nfsio_create(child->private, fname);
171         if (res != expected_status(status)) {
172                 printf("[%d] CREATE \"%s\" failed (%x) - expected %x\n", 
173                        child->line, fname, res, expected_status(status));
174                 failed(child);
175         }
176 }
177
178 static void nfs3_write(struct child_struct *child, const char *fname, int offset, int len, int stable, const char *status)
179 {
180         nfsstat3 res;
181
182         res = nfsio_write(child->private, fname, rw_buf, offset, len, stable);
183         if (res != expected_status(status)) {
184                 printf("[%d] WRITE \"%s\" failed (%x) - expected %x\n", 
185                        child->line, fname,
186                        res, expected_status(status));
187                 failed(child);
188         }
189         child->bytes += len;
190 }
191
192 static void nfs3_commit(struct child_struct *child, const char *fname, const char *status)
193 {
194         nfsstat3 res;
195
196         res = nfsio_commit(child->private, fname);
197         if (res != expected_status(status)) {
198                 printf("[%d] COMMIT \"%s\" failed (%x) - expected %x\n", 
199                        child->line, fname, res, expected_status(status));
200                 failed(child);
201         }
202 }
203
204
205 static void nfs3_read(struct child_struct *child, const char *fname, int offset, int len, const char *status)
206 {
207         nfsstat3 res = 0;
208
209         res = nfsio_read(child->private, fname, rw_buf, offset, len, NULL, NULL);
210         if (res != expected_status(status)) {
211                 printf("[%d] READ \"%s\" failed (%x) - expected %x\n", 
212                        child->line, fname,
213                        res, expected_status(status));
214                 failed(child);
215         }
216         child->bytes += len;
217 }
218
219 static void nfs3_access(struct child_struct *child, const char *fname, int desired, int granted, const char *status)
220 {
221         nfsstat3 res;
222
223         res = nfsio_access(child->private, fname, 0, NULL);
224         if (res != expected_status(status)) {
225                 printf("[%d] ACCESS \"%s\" failed (%x) - expected %x\n", 
226                        child->line, fname, res, expected_status(status));
227                 failed(child);
228         }
229 }
230
231 static void nfs3_mkdir(struct child_struct *child, const char *fname, const char *status)
232 {
233         nfsstat3 res;
234
235         res = nfsio_mkdir(child->private, fname);
236         if (res != expected_status(status)) {
237                 printf("[%d] MKDIR \"%s\" failed (%x) - expected %x\n", 
238                        child->line, fname, res, expected_status(status));
239                 failed(child);
240         }
241 }
242
243 static void nfs3_rmdir(struct child_struct *child, const char *fname, const char *status)
244 {
245         nfsstat3 res;
246
247         res = nfsio_rmdir(child->private, fname);
248         if (res != expected_status(status)) {
249                 printf("[%d] RMDIR \"%s\" failed (%x) - expected %x\n", 
250                        child->line, fname, res, expected_status(status));
251                 failed(child);
252         }
253 }
254
255 static void nfs3_fsstat(struct child_struct *child, const char *status)
256 {
257         nfsstat3 res;
258
259         res = nfsio_fsstat(child->private);
260         if (res != expected_status(status)) {
261                 printf("[%d] FSSTAT failed (%x) - expected %x\n", 
262                        child->line, res, expected_status(status));
263                 failed(child);
264         }
265 }
266
267 static void nfs3_fsinfo(struct child_struct *child, const char *status)
268 {
269         nfsstat3 res;
270
271         res = nfsio_fsinfo(child->private);
272         if (res != expected_status(status)) {
273                 printf("[%d] FSINFO failed (%x) - expected %x\n", 
274                        child->line, res, expected_status(status));
275                 failed(child);
276         }
277 }
278
279 static void nfs3_cleanup(struct child_struct *child)
280 {
281         char *dname;
282
283         asprintf(&dname, "/clients/client%d", child->id);
284         nfs3_deltree(child, dname);
285         free(dname);
286 }
287
288 static void nfs3_setup(struct child_struct *child)
289 {
290         const char *status = "0x00000000";
291
292         child->rate.last_time = timeval_current();
293         child->rate.last_bytes = 0;
294
295
296         srandom(getpid() ^ time(NULL));
297         child->private = nfsio_connect(options.server, options.export, options.protocol);
298
299         if (child->private == NULL) {
300                 child->failed = 1;
301                 printf("nfsio_connect() failed\n");
302                 exit(10);
303         }
304
305 }
306
307 static void nfs3_symlink(struct child_struct *child, const char *fname, const char *fname2, const char *status)
308 {
309         nfsstat3 res;
310
311         res = nfsio_symlink(child->private, fname, fname2);
312         if (res != expected_status(status)) {
313                 printf("[%d] SYMLINK \"%s\"->\"%s\" failed (%x) - expected %x\n", 
314                        child->line, fname, fname2,
315                        res, expected_status(status));
316                 failed(child);
317         }
318 }
319
320 static void nfs3_remove(struct child_struct *child, const char *fname, const char *status)
321 {
322         nfsstat3 res;
323
324         res = nfsio_remove(child->private, fname);
325         if (res != expected_status(status)) {
326                 printf("[%d] REMOVE \"%s\" failed (%x) - expected %x\n", 
327                        child->line, fname, res, expected_status(status));
328                 failed(child);
329         }
330 }
331
332 static void nfs3_readdirplus(struct child_struct *child, const char *fname, const char *status)
333 {
334         nfsstat3 res;
335
336         res = nfsio_readdirplus(child->private, fname, NULL, NULL);
337         if (res != expected_status(status)) {
338                 printf("[%d] READDIRPLUS \"%s\" failed (%x) - expected %x\n", 
339                        child->line, fname, res, expected_status(status));
340                 failed(child);
341         }
342 }
343
344 static void nfs3_link(struct child_struct *child, const char *fname, const char *fname2, const char *status)
345 {
346         nfsstat3 res;
347
348         res = nfsio_link(child->private, fname, fname2);
349         if (res != expected_status(status)) {
350                 printf("[%d] LINK \"%s\"->\"%s\" failed (%x) - expected %x\n", 
351                        child->line, fname, fname2,
352                        res, expected_status(status));
353                 failed(child);
354         }
355 }
356
357 static void nfs3_rename(struct child_struct *child, const char *fname, const char *fname2, const char *status)
358 {
359         nfsstat3 res;
360
361         res = nfsio_rename(child->private, fname, fname2);
362         if (res != expected_status(status)) {
363                 printf("[%d] RENAME \"%s\"->\"%s\" failed (%x) - expected %x\n", 
364                        child->line, fname, fname2,
365                        res, expected_status(status));
366                 failed(child);
367         }
368 }
369
370 struct nb_operations nb_ops = {
371         .setup          = nfs3_setup,
372         .deltree        = nfs3_deltree,
373         .cleanup        = nfs3_cleanup,
374
375         .getattr3       = nfs3_getattr,
376         .lookup3        = nfs3_lookup,
377         .create3        = nfs3_create,
378         .write3         = nfs3_write,
379         .commit3        = nfs3_commit,
380         .read3          = nfs3_read,
381         .access3        = nfs3_access,
382         .mkdir3         = nfs3_mkdir,
383         .rmdir3         = nfs3_rmdir,
384         .fsstat3        = nfs3_fsstat,
385         .fsinfo3        = nfs3_fsinfo,
386         .symlink3       = nfs3_symlink,
387         .remove3        = nfs3_remove,
388         .readdirplus3   = nfs3_readdirplus,
389         .rename3        = nfs3_rename,
390         .link3          = nfs3_link,
391 };