fix a debug statement to print also the directory name (and not
[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", cbd->dirname);
157                 free(cbd);
158                 exit(10);
159         }
160         free(cbd);
161 }
162
163 static int check_status(int status, const char *expected)
164 {
165         if (strcmp(expected, "*") == 0){
166                 return 1;
167         }
168         if (strncmp(expected, "0x", 2) == 0) {
169                 return status == strtol(expected, NULL, 16);
170         }
171         return 0;
172 }
173
174 static void failed(struct child_struct *child)
175 {
176         child->failed = 1;
177         printf("ERROR: child %d failed at line %d\n", child->id, child->line);
178         exit(1);
179 }
180
181 static void nfs3_getattr(struct dbench_op *op)
182 {
183         nfsstat3 res;
184
185         res = nfsio_getattr(op->child->private, op->fname, NULL);
186         if (!check_status(res, op->status)) {
187                 printf("[%d] GETATTR \"%s\" failed (%x) - expected %s\n", 
188                        op->child->line, op->fname, res, op->status);
189                 failed(op->child);
190         }
191 }
192
193
194 static void nfs3_lookup(struct dbench_op *op)
195 {
196         nfsstat3 res;
197
198         res = nfsio_lookup(op->child->private, op->fname, NULL);
199         if (!check_status(res, op->status)) {
200                 printf("[%d] LOOKUP \"%s\" failed (%x) - expected %s\n", 
201                        op->child->line, op->fname, res, op->status);
202                 failed(op->child);
203         }
204 }
205
206 static void nfs3_create(struct dbench_op *op)
207 {
208         nfsstat3 res;
209
210         res = nfsio_create(op->child->private, op->fname);
211         if (!check_status(res, op->status)) {
212                 printf("[%d] CREATE \"%s\" failed (%x) - expected %s\n", 
213                        op->child->line, op->fname, res, op->status);
214                 failed(op->child);
215         }
216 }
217
218 static void nfs3_write(struct dbench_op *op)
219 {
220         int offset = op->params[0];
221         int len = op->params[1];
222         int stable = op->params[2];
223         nfsstat3 res;
224
225         if ((options.trunc_io > 0) && (len > options.trunc_io)) {
226                 len = options.trunc_io;
227         }
228
229         res = nfsio_write(op->child->private, op->fname, rw_buf, offset, len, stable);
230         if (!check_status(res, op->status)) {
231                 printf("[%d] WRITE \"%s\" failed (%x) - expected %s\n", 
232                        op->child->line, op->fname,
233                        res, op->status);
234                 failed(op->child);
235         }
236         op->child->bytes += len;
237 }
238
239 static void nfs3_commit(struct dbench_op *op)
240 {
241         nfsstat3 res;
242
243         res = nfsio_commit(op->child->private, op->fname);
244         if (!check_status(res, op->status)) {
245                 printf("[%d] COMMIT \"%s\" failed (%x) - expected %s\n", 
246                        op->child->line, op->fname, res, op->status);
247                 failed(op->child);
248         }
249 }
250
251
252 static void nfs3_read(struct dbench_op *op)
253 {
254         int offset = op->params[0];
255         int len = op->params[1];
256         nfsstat3 res = 0;
257
258         if ((options.trunc_io > 0) && (len > options.trunc_io)) {
259                 len = options.trunc_io;
260         }
261
262         res = nfsio_read(op->child->private, op->fname, NULL, offset, len, NULL, NULL);
263         if (!check_status(res, op->status)) {
264                 printf("[%d] READ \"%s\" failed (%x) - expected %s\n", 
265                        op->child->line, op->fname,
266                        res, op->status);
267                 failed(op->child);
268         }
269         op->child->bytes += len;
270 }
271
272 static void nfs3_access(struct dbench_op *op)
273 {
274         nfsstat3 res;
275
276         res = nfsio_access(op->child->private, op->fname, 0, NULL);
277         if (!check_status(res, op->status)) {
278                 printf("[%d] ACCESS \"%s\" failed (%x) - expected %s\n", 
279                        op->child->line, op->fname, res, op->status);
280                 failed(op->child);
281         }
282 }
283
284 static void nfs3_mkdir(struct dbench_op *op)
285 {
286         nfsstat3 res;
287
288         res = nfsio_mkdir(op->child->private, op->fname);
289         if (!check_status(res, op->status)) {
290                 printf("[%d] MKDIR \"%s\" failed (%x) - expected %s\n", 
291                        op->child->line, op->fname, res, op->status);
292                 failed(op->child);
293         }
294 }
295
296 static void nfs3_rmdir(struct dbench_op *op)
297 {
298         nfsstat3 res;
299
300         res = nfsio_rmdir(op->child->private, op->fname);
301         if (!check_status(res, op->status)) {
302                 printf("[%d] RMDIR \"%s\" failed (%x) - expected %s\n", 
303                        op->child->line, op->fname, res, op->status);
304                 failed(op->child);
305         }
306 }
307
308 static void nfs3_fsstat(struct dbench_op *op)
309 {
310         nfsstat3 res;
311
312         res = nfsio_fsstat(op->child->private);
313         if (!check_status(res, op->status)) {
314                 printf("[%d] FSSTAT failed (%x) - expected %s\n", 
315                        op->child->line, res, op->status);
316                 failed(op->child);
317         }
318 }
319
320 static void nfs3_fsinfo(struct dbench_op *op)
321 {
322         nfsstat3 res;
323
324         res = nfsio_fsinfo(op->child->private);
325         if (!check_status(res, op->status)) {
326                 printf("[%d] FSINFO failed (%x) - expected %s\n", 
327                        op->child->line, res, op->status);
328                 failed(op->child);
329         }
330 }
331
332 static void nfs3_symlink(struct dbench_op *op)
333 {
334         nfsstat3 res;
335
336         res = nfsio_symlink(op->child->private, op->fname, op->fname2);
337         if (!check_status(res, op->status)) {
338                 printf("[%d] SYMLINK \"%s\"->\"%s\" failed (%x) - expected %s\n", 
339                        op->child->line, op->fname, op->fname2,
340                        res, op->status);
341                 failed(op->child);
342         }
343 }
344
345 static void nfs3_remove(struct dbench_op *op)
346 {
347         nfsstat3 res;
348
349         res = nfsio_remove(op->child->private, op->fname);
350         if (!check_status(res, op->status)) {
351                 printf("[%d] REMOVE \"%s\" failed (%x) - expected %s\n", 
352                        op->child->line, op->fname, res, op->status);
353                 failed(op->child);
354         }
355 }
356
357 static void nfs3_readdirplus(struct dbench_op *op)
358 {
359         nfsstat3 res;
360
361         res = nfsio_readdirplus(op->child->private, op->fname, NULL, NULL);
362         if (!check_status(res, op->status)) {
363                 printf("[%d] READDIRPLUS \"%s\" failed (%x) - expected %s\n", 
364                        op->child->line, op->fname, res, op->status);
365                 failed(op->child);
366         }
367 }
368
369 static void nfs3_link(struct dbench_op *op)
370 {
371         nfsstat3 res;
372
373         res = nfsio_link(op->child->private, op->fname, op->fname2);
374         if (!check_status(res, op->status)) {
375                 printf("[%d] LINK \"%s\"->\"%s\" failed (%x) - expected %s\n", 
376                        op->child->line, op->fname, op->fname2,
377                        res, op->status);
378                 failed(op->child);
379         }
380 }
381
382 static void nfs3_rename(struct dbench_op *op)
383 {
384         nfsstat3 res;
385
386         res = nfsio_rename(op->child->private, op->fname, op->fname2);
387         if (!check_status(res, op->status)) {
388                 printf("[%d] RENAME \"%s\"->\"%s\" failed (%x) - expected %s\n", 
389                        op->child->line, op->fname, op->fname2,
390                        res, op->status);
391                 failed(op->child);
392         }
393 }
394
395 static struct backend_op ops[] = {
396         { "Deltree",  nfs3_deltree },
397         { "GETATTR3", nfs3_getattr },
398         { "LOOKUP3",  nfs3_lookup },
399         { "CREATE3",  nfs3_create },
400         { "WRITE3",   nfs3_write },
401         { "COMMIT3",  nfs3_commit },
402         { "READ3",    nfs3_read },
403         { "ACCESS3",  nfs3_access },
404         { "MKDIR3",   nfs3_mkdir },
405         { "RMDIR3",   nfs3_rmdir },
406         { "FSSTAT3",  nfs3_fsstat },
407         { "FSINFO3",  nfs3_fsinfo },
408         { "SYMLINK3", nfs3_symlink },
409         { "REMOVE3",  nfs3_remove },
410         { "READDIRPLUS3", nfs3_readdirplus },
411         { "RENAME3",  nfs3_rename },
412         { "LINK3",    nfs3_link },
413         { NULL, NULL}
414 };
415
416 struct nb_operations nfs_ops = {
417         .backend_name = "nfsbench",
418         .setup        = nfs3_setup,
419         .cleanup      = nfs3_cleanup,
420         .ops          = ops
421 };