shared one binary for all backends
[tridge/dbench.git] / nfsio.c
1 /* 
2    Copyright (C) by Ronnie Sahlberg <sahlberg@samba.org> 2008
3    
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 3 of the License, or
7    (at your option) any later version.
8    
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13    
14    You should have received a copy of the GNU General Public License
15    along with this program; if not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #define _GNU_SOURCE
19 #include <stdio.h>
20 #undef _GNU_SOURCE
21
22 #include "mount.h"
23 #include "nfs.h"
24 #include "libnfs.h"
25 #include "dbench.h"
26
27 #define discard_const(ptr) ((void *)((intptr_t)(ptr)))
28
29 #define MAX_FILES 200
30
31 static char rw_buf[65536];
32
33
34 struct cb_data {
35         struct nfsio *nfsio;
36         char *dirname;
37 };
38
39 static void nfs3_deltree(struct dbench_op *op);
40
41 static void nfs3_cleanup(struct child_struct *child)
42 {
43         char *dname;
44         struct dbench_op op;
45         ZERO_STRUCT(op);
46
47         asprintf(&dname, "/clients/client%d", child->id);
48         op.fname = dname;
49         op.child = child;
50         nfs3_deltree(&op);
51         free(dname);
52 }
53
54 static void nfs3_setup(struct child_struct *child)
55 {
56         const char *status = "0x00000000";
57         nfsstat3 res;
58
59         child->rate.last_time = timeval_current();
60         child->rate.last_bytes = 0;
61
62
63         srandom(getpid() ^ time(NULL));
64         child->private = nfsio_connect(options.server, options.export, options.protocol);
65
66         if (child->private == NULL) {
67                 child->failed = 1;
68                 printf("nfsio_connect() failed\n");
69                 exit(10);
70         }
71
72         /* create '/clients' */
73         res = nfsio_lookup(child->private, "/clients", NULL);
74         if (res == NFS3ERR_NOENT) {
75                 res = nfsio_mkdir(child->private, "/clients");
76                 if( (res != NFS3_OK) &&
77                     (res != NFS3ERR_EXIST) ) {
78                         printf("Failed to create '/clients' directory. res:%u\n", res);
79                         exit(10);
80                 }
81         }
82 }
83
84
85 static void dirent_cb(struct entryplus3 *e, void *private_data)
86 {
87         struct cb_data *cbd = private_data;
88         nfsstat3 res;
89         char *objname;
90
91         if (!strcmp(cbd->dirname,".")) {
92                 return;
93         }
94         if (!strcmp(cbd->dirname,"..")) {
95                 return;
96         }
97
98         asprintf(&objname, "%s/%s", cbd->dirname, e->name);
99         if (objname == NULL) {
100                 printf("Failed to talloc ne object name in dirent_cb\n");
101                 exit(10);
102         }
103
104         if (e->name_attributes.post_op_attr_u.attributes.type == NF3DIR) {
105                 struct cb_data *new_cbd = malloc(sizeof(struct cb_data));
106
107                 new_cbd->nfsio = cbd->nfsio;
108                 new_cbd->dirname = strdup(objname);
109
110                 nfsio_readdirplus(cbd->nfsio, objname, dirent_cb, new_cbd);
111                 
112                 res = nfsio_rmdir(cbd->nfsio, objname);
113                 if (res != NFS3_OK) {
114                         printf("Failed to remove object : \"%s\"  %s (%d)\n", objname, nfs_error(res), res);
115                         free(objname);
116                         free(new_cbd->dirname);
117                         free(new_cbd);
118                         exit(10);
119                 }
120
121
122                 free(objname);
123                 free(new_cbd->dirname);
124                 free(new_cbd);
125                 return;
126         }
127
128         res = nfsio_remove(cbd->nfsio, objname);
129         if (res != NFS3_OK) {
130                 printf("Failed to remove object : \"%s\" %s %d\n", objname, nfs_error(res), res);
131                 free(objname);
132                 exit(10);
133         }
134
135         free(objname);
136 }
137
138 static void nfs3_deltree(struct dbench_op *op)
139 {
140         struct cb_data *cbd;
141         nfsstat3 res;
142         
143         cbd = malloc(sizeof(struct cb_data));
144
145         cbd->nfsio = op->child->private;
146         cbd->dirname = discard_const(op->fname);
147
148         res = nfsio_lookup(cbd->nfsio, cbd->dirname, NULL);
149         if (res != NFS3ERR_NOENT) {
150                 nfsio_readdirplus(cbd->nfsio, cbd->dirname, dirent_cb, cbd);
151                 nfsio_rmdir(cbd->nfsio, cbd->dirname);
152         }
153
154         res = nfsio_lookup(cbd->nfsio, cbd->dirname, NULL);
155         if (res != NFS3ERR_NOENT) {
156                 printf("Directory \"%s\" not empty. Aborting\n");
157                 free(cbd);
158                 exit(10);
159         }
160         free(cbd);
161 }
162
163 static int expected_status(const char *status)
164 {
165         if (strncmp(status, "0x", 2) == 0) {
166                 return strtol(status, NULL, 16);
167         }
168 }
169
170 static void failed(struct child_struct *child)
171 {
172         child->failed = 1;
173         printf("ERROR: child %d failed at line %d\n", child->id, child->line);
174         exit(1);
175 }
176
177 static void nfs3_getattr(struct dbench_op *op)
178 {
179         nfsstat3 res;
180
181         res = nfsio_getattr(op->child->private, op->fname, NULL);
182         if (res != expected_status(op->status)) {
183                 printf("[%d] GETATTR \"%s\" failed (%x) - expected %x\n", 
184                        op->child->line, op->fname, res, expected_status(op->status));
185                 failed(op->child);
186         }
187 }
188
189
190 static void nfs3_lookup(struct dbench_op *op)
191 {
192         nfsstat3 res;
193
194         res = nfsio_lookup(op->child->private, op->fname, NULL);
195         if (res != expected_status(op->status)) {
196                 printf("[%d] LOOKUP \"%s\" failed (%x) - expected %x\n", 
197                        op->child->line, op->fname, res, expected_status(op->status));
198                 failed(op->child);
199         }
200 }
201
202 static void nfs3_create(struct dbench_op *op)
203 {
204         nfsstat3 res;
205
206         res = nfsio_create(op->child->private, op->fname);
207         if (res != expected_status(op->status)) {
208                 printf("[%d] CREATE \"%s\" failed (%x) - expected %x\n", 
209                        op->child->line, op->fname, res, expected_status(op->status));
210                 failed(op->child);
211         }
212 }
213
214 static void nfs3_write(struct dbench_op *op)
215 {
216         int offset = op->params[0];
217         int len = op->params[1];
218         int stable = op->params[2];
219         nfsstat3 res;
220
221         res = nfsio_write(op->child->private, op->fname, rw_buf, offset, len, stable);
222         if (res != expected_status(op->status)) {
223                 printf("[%d] WRITE \"%s\" failed (%x) - expected %x\n", 
224                        op->child->line, op->fname,
225                        res, expected_status(op->status));
226                 failed(op->child);
227         }
228         op->child->bytes += len;
229 }
230
231 static void nfs3_commit(struct dbench_op *op)
232 {
233         nfsstat3 res;
234
235         res = nfsio_commit(op->child->private, op->fname);
236         if (res != expected_status(op->status)) {
237                 printf("[%d] COMMIT \"%s\" failed (%x) - expected %x\n", 
238                        op->child->line, op->fname, res, expected_status(op->status));
239                 failed(op->child);
240         }
241 }
242
243
244 static void nfs3_read(struct dbench_op *op)
245 {
246         int offset = op->params[0];
247         int len = op->params[1];
248         nfsstat3 res = 0;
249
250         res = nfsio_read(op->child->private, op->fname, rw_buf, offset, len, NULL, NULL);
251         if (res != expected_status(op->status)) {
252                 printf("[%d] READ \"%s\" failed (%x) - expected %x\n", 
253                        op->child->line, op->fname,
254                        res, expected_status(op->status));
255                 failed(op->child);
256         }
257         op->child->bytes += len;
258 }
259
260 static void nfs3_access(struct dbench_op *op)
261 {
262         nfsstat3 res;
263
264         res = nfsio_access(op->child->private, op->fname, 0, NULL);
265         if (res != expected_status(op->status)) {
266                 printf("[%d] ACCESS \"%s\" failed (%x) - expected %x\n", 
267                        op->child->line, op->fname, res, expected_status(op->status));
268                 failed(op->child);
269         }
270 }
271
272 static void nfs3_mkdir(struct dbench_op *op)
273 {
274         nfsstat3 res;
275
276         res = nfsio_mkdir(op->child->private, op->fname);
277         if (res != expected_status(op->status)) {
278                 printf("[%d] MKDIR \"%s\" failed (%x) - expected %x\n", 
279                        op->child->line, op->fname, res, expected_status(op->status));
280                 failed(op->child);
281         }
282 }
283
284 static void nfs3_rmdir(struct dbench_op *op)
285 {
286         nfsstat3 res;
287
288         res = nfsio_rmdir(op->child->private, op->fname);
289         if (res != expected_status(op->status)) {
290                 printf("[%d] RMDIR \"%s\" failed (%x) - expected %x\n", 
291                        op->child->line, op->fname, res, expected_status(op->status));
292                 failed(op->child);
293         }
294 }
295
296 static void nfs3_fsstat(struct dbench_op *op)
297 {
298         nfsstat3 res;
299
300         res = nfsio_fsstat(op->child->private);
301         if (res != expected_status(op->status)) {
302                 printf("[%d] FSSTAT failed (%x) - expected %x\n", 
303                        op->child->line, res, expected_status(op->status));
304                 failed(op->child);
305         }
306 }
307
308 static void nfs3_fsinfo(struct dbench_op *op)
309 {
310         nfsstat3 res;
311
312         res = nfsio_fsinfo(op->child->private);
313         if (res != expected_status(op->status)) {
314                 printf("[%d] FSINFO failed (%x) - expected %x\n", 
315                        op->child->line, res, expected_status(op->status));
316                 failed(op->child);
317         }
318 }
319
320 static void nfs3_symlink(struct dbench_op *op)
321 {
322         nfsstat3 res;
323
324         res = nfsio_symlink(op->child->private, op->fname, op->fname2);
325         if (res != expected_status(op->status)) {
326                 printf("[%d] SYMLINK \"%s\"->\"%s\" failed (%x) - expected %x\n", 
327                        op->child->line, op->fname, op->fname2,
328                        res, expected_status(op->status));
329                 failed(op->child);
330         }
331 }
332
333 static void nfs3_remove(struct dbench_op *op)
334 {
335         nfsstat3 res;
336
337         res = nfsio_remove(op->child->private, op->fname);
338         if (res != expected_status(op->status)) {
339                 printf("[%d] REMOVE \"%s\" failed (%x) - expected %x\n", 
340                        op->child->line, op->fname, res, expected_status(op->status));
341                 failed(op->child);
342         }
343 }
344
345 static void nfs3_readdirplus(struct dbench_op *op)
346 {
347         nfsstat3 res;
348
349         res = nfsio_readdirplus(op->child->private, op->fname, NULL, NULL);
350         if (res != expected_status(op->status)) {
351                 printf("[%d] READDIRPLUS \"%s\" failed (%x) - expected %x\n", 
352                        op->child->line, op->fname, res, expected_status(op->status));
353                 failed(op->child);
354         }
355 }
356
357 static void nfs3_link(struct dbench_op *op)
358 {
359         nfsstat3 res;
360
361         res = nfsio_link(op->child->private, op->fname, op->fname2);
362         if (res != expected_status(op->status)) {
363                 printf("[%d] LINK \"%s\"->\"%s\" failed (%x) - expected %x\n", 
364                        op->child->line, op->fname, op->fname2,
365                        res, expected_status(op->status));
366                 failed(op->child);
367         }
368 }
369
370 static void nfs3_rename(struct dbench_op *op)
371 {
372         nfsstat3 res;
373
374         res = nfsio_rename(op->child->private, op->fname, op->fname2);
375         if (res != expected_status(op->status)) {
376                 printf("[%d] RENAME \"%s\"->\"%s\" failed (%x) - expected %x\n", 
377                        op->child->line, op->fname, op->fname2,
378                        res, expected_status(op->status));
379                 failed(op->child);
380         }
381 }
382
383 static struct backend_op ops[] = {
384         { "Deltree",  nfs3_deltree },
385         { "GETATTR3", nfs3_getattr },
386         { "LOOKUP3",  nfs3_lookup },
387         { "CREATE3",  nfs3_create },
388         { "WRITE3",   nfs3_write },
389         { "COMMIT3",  nfs3_commit },
390         { "READ3",    nfs3_read },
391         { "ACCESS3",  nfs3_access },
392         { "MKDIR3",   nfs3_mkdir },
393         { "RMDIR3",   nfs3_rmdir },
394         { "FSSTAT3",  nfs3_fsstat },
395         { "FSINFO3",  nfs3_fsinfo },
396         { "SYMLINK3", nfs3_symlink },
397         { "REMOVE3",  nfs3_remove },
398         { "READDIRPLUS3", nfs3_readdirplus },
399         { "RENAME3",  nfs3_rename },
400         { "LINK3",    nfs3_link },
401         { NULL, NULL}
402 };
403
404 struct nb_operations nfs_ops = {
405         .backend_name = "nfsbench",
406         .setup        = nfs3_setup,
407         .cleanup      = nfs3_cleanup,
408         .ops          = ops
409 };