Grrrrr different distributions ship different libsmbclient with different APIs
[sahlberg/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 _FILE_OFFSET_BITS 64
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 struct cb_data {
37         struct nfsio *nfsio;
38         char *dirname;
39 };
40
41 static void nfs3_deltree(struct dbench_op *op);
42
43 static void nfs3_cleanup(struct child_struct *child)
44 {
45         char *dname;
46         struct dbench_op op;
47         ZERO_STRUCT(op);
48
49         asprintf(&dname, "/clients/client%d", child->id);
50         op.fname = dname;
51         op.child = child;
52         nfs3_deltree(&op);
53         free(dname);
54 }
55
56 static void nfs3_setup(struct child_struct *child)
57 {
58         const char *status = "0x00000000";
59         nfsstat3 res;
60
61         child->rate.last_time = timeval_current();
62         child->rate.last_bytes = 0;
63
64
65         srandom(getpid() ^ time(NULL));
66         child->private = nfsio_connect(options.server, options.export, options.protocol);
67
68         if (child->private == NULL) {
69                 child->failed = 1;
70                 printf("nfsio_connect() failed\n");
71                 exit(10);
72         }
73
74         /* create '/clients' */
75         res = nfsio_lookup(child->private, "/clients", NULL);
76         if (res == NFS3ERR_NOENT) {
77                 res = nfsio_mkdir(child->private, "/clients");
78                 if( (res != NFS3_OK) &&
79                     (res != NFS3ERR_EXIST) ) {
80                         printf("Failed to create '/clients' directory. res:%u\n", res);
81                         exit(10);
82                 }
83         }
84 }
85
86
87 static void dirent_cb(struct entryplus3 *e, void *private_data)
88 {
89         struct cb_data *cbd = private_data;
90         nfsstat3 res;
91         char *objname;
92
93         if (!strcmp(cbd->dirname,".")) {
94                 return;
95         }
96         if (!strcmp(cbd->dirname,"..")) {
97                 return;
98         }
99
100         asprintf(&objname, "%s/%s", cbd->dirname, e->name);
101         if (objname == NULL) {
102                 printf("Failed to talloc ne object name in dirent_cb\n");
103                 exit(10);
104         }
105
106         if (e->name_attributes.post_op_attr_u.attributes.type == NF3DIR) {
107                 struct cb_data *new_cbd = malloc(sizeof(struct cb_data));
108
109                 new_cbd->nfsio = cbd->nfsio;
110                 new_cbd->dirname = strdup(objname);
111
112                 nfsio_readdirplus(cbd->nfsio, objname, dirent_cb, new_cbd);
113                 
114                 res = nfsio_rmdir(cbd->nfsio, objname);
115                 if (res != NFS3_OK) {
116                         printf("Failed to remove object : \"%s\"  %s (%d)\n", objname, nfs_error(res), res);
117                         free(objname);
118                         free(new_cbd->dirname);
119                         free(new_cbd);
120                         exit(10);
121                 }
122
123
124                 free(objname);
125                 free(new_cbd->dirname);
126                 free(new_cbd);
127                 return;
128         }
129
130         res = nfsio_remove(cbd->nfsio, objname);
131         if (res != NFS3_OK) {
132                 printf("Failed to remove object : \"%s\" %s %d\n", objname, nfs_error(res), res);
133                 free(objname);
134                 exit(10);
135         }
136
137         free(objname);
138 }
139
140 static void nfs3_deltree(struct dbench_op *op)
141 {
142         struct cb_data *cbd;
143         nfsstat3 res;
144         
145         cbd = malloc(sizeof(struct cb_data));
146
147         cbd->nfsio = op->child->private;
148         cbd->dirname = discard_const(op->fname);
149
150         res = nfsio_lookup(cbd->nfsio, cbd->dirname, NULL);
151         if (res != NFS3ERR_NOENT) {
152                 nfsio_readdirplus(cbd->nfsio, cbd->dirname, dirent_cb, cbd);
153                 nfsio_rmdir(cbd->nfsio, cbd->dirname);
154         }
155
156         res = nfsio_lookup(cbd->nfsio, cbd->dirname, NULL);
157         if (res != NFS3ERR_NOENT) {
158                 printf("Directory \"%s\" not empty. Aborting\n", cbd->dirname);
159                 free(cbd);
160                 exit(10);
161         }
162         free(cbd);
163 }
164
165 static int check_status(int status, const char *expected)
166 {
167         if (strcmp(expected, "*") == 0){
168                 return 1;
169         }
170         if (strncmp(expected, "0x", 2) == 0) {
171                 return status == strtol(expected, NULL, 16);
172         }
173         return 0;
174 }
175
176 static void failed(struct child_struct *child)
177 {
178         child->failed = 1;
179         printf("ERROR: child %d failed at line %d\n", child->id, child->line);
180         exit(1);
181 }
182
183 static void nfs3_getattr(struct dbench_op *op)
184 {
185         nfsstat3 res;
186
187         res = nfsio_getattr(op->child->private, op->fname, NULL);
188         if (!check_status(res, op->status)) {
189                 printf("[%d] GETATTR \"%s\" failed (%x) - expected %s\n", 
190                        op->child->line, op->fname, res, op->status);
191                 failed(op->child);
192         }
193 }
194
195
196 static void nfs3_lookup(struct dbench_op *op)
197 {
198         nfsstat3 res;
199
200         res = nfsio_lookup(op->child->private, op->fname, NULL);
201         if (!check_status(res, op->status)) {
202                 printf("[%d] LOOKUP \"%s\" failed (%x) - expected %s\n", 
203                        op->child->line, op->fname, res, op->status);
204                 failed(op->child);
205         }
206 }
207
208 static void nfs3_create(struct dbench_op *op)
209 {
210         nfsstat3 res;
211
212         res = nfsio_create(op->child->private, op->fname);
213         if (!check_status(res, op->status)) {
214                 printf("[%d] CREATE \"%s\" failed (%x) - expected %s\n", 
215                        op->child->line, op->fname, res, op->status);
216                 failed(op->child);
217         }
218 }
219
220 static void nfs3_write(struct dbench_op *op)
221 {
222         off_t offset = op->params[0];
223         int len = op->params[1];
224         int stable = op->params[2];
225         nfsstat3 res;
226
227         if ((options.trunc_io > 0) && (len > options.trunc_io)) {
228                 len = options.trunc_io;
229         }
230
231         res = nfsio_write(op->child->private, op->fname, rw_buf, offset, len, stable);
232         if (!check_status(res, op->status)) {
233                 printf("[%d] WRITE \"%s\" failed (%x) - expected %s\n", 
234                        op->child->line, op->fname,
235                        res, op->status);
236                 failed(op->child);
237         }
238         op->child->bytes += len;
239 }
240
241 static void nfs3_commit(struct dbench_op *op)
242 {
243         nfsstat3 res;
244
245         res = nfsio_commit(op->child->private, op->fname);
246         if (!check_status(res, op->status)) {
247                 printf("[%d] COMMIT \"%s\" failed (%x) - expected %s\n", 
248                        op->child->line, op->fname, res, op->status);
249                 failed(op->child);
250         }
251 }
252
253
254 static void nfs3_read(struct dbench_op *op)
255 {
256         off_t offset = op->params[0];
257         int len = op->params[1];
258         nfsstat3 res = 0;
259
260         if ((options.trunc_io > 0) && (len > options.trunc_io)) {
261                 len = options.trunc_io;
262         }
263
264         res = nfsio_read(op->child->private, op->fname, NULL, offset, len, NULL, NULL);
265         if (!check_status(res, op->status)) {
266                 printf("[%d] READ \"%s\" failed (%x) - expected %s\n", 
267                        op->child->line, op->fname,
268                        res, op->status);
269                 failed(op->child);
270         }
271         op->child->bytes += len;
272 }
273
274 static void nfs3_access(struct dbench_op *op)
275 {
276         nfsstat3 res;
277
278         res = nfsio_access(op->child->private, op->fname, 0, NULL);
279         if (!check_status(res, op->status)) {
280                 printf("[%d] ACCESS \"%s\" failed (%x) - expected %s\n", 
281                        op->child->line, op->fname, res, op->status);
282                 failed(op->child);
283         }
284 }
285
286 static void nfs3_mkdir(struct dbench_op *op)
287 {
288         nfsstat3 res;
289
290         res = nfsio_mkdir(op->child->private, op->fname);
291         if (!check_status(res, op->status)) {
292                 printf("[%d] MKDIR \"%s\" failed (%x) - expected %s\n", 
293                        op->child->line, op->fname, res, op->status);
294                 failed(op->child);
295         }
296 }
297
298 static void nfs3_rmdir(struct dbench_op *op)
299 {
300         nfsstat3 res;
301
302         res = nfsio_rmdir(op->child->private, op->fname);
303         if (!check_status(res, op->status)) {
304                 printf("[%d] RMDIR \"%s\" failed (%x) - expected %s\n", 
305                        op->child->line, op->fname, res, op->status);
306                 failed(op->child);
307         }
308 }
309
310 static void nfs3_fsstat(struct dbench_op *op)
311 {
312         nfsstat3 res;
313
314         res = nfsio_fsstat(op->child->private);
315         if (!check_status(res, op->status)) {
316                 printf("[%d] FSSTAT failed (%x) - expected %s\n", 
317                        op->child->line, res, op->status);
318                 failed(op->child);
319         }
320 }
321
322 static void nfs3_fsinfo(struct dbench_op *op)
323 {
324         nfsstat3 res;
325
326         res = nfsio_fsinfo(op->child->private);
327         if (!check_status(res, op->status)) {
328                 printf("[%d] FSINFO failed (%x) - expected %s\n", 
329                        op->child->line, res, op->status);
330                 failed(op->child);
331         }
332 }
333
334 static void nfs3_symlink(struct dbench_op *op)
335 {
336         nfsstat3 res;
337
338         res = nfsio_symlink(op->child->private, op->fname, op->fname2);
339         if (!check_status(res, op->status)) {
340                 printf("[%d] SYMLINK \"%s\"->\"%s\" failed (%x) - expected %s\n", 
341                        op->child->line, op->fname, op->fname2,
342                        res, op->status);
343                 failed(op->child);
344         }
345 }
346
347 static void nfs3_remove(struct dbench_op *op)
348 {
349         nfsstat3 res;
350
351         res = nfsio_remove(op->child->private, op->fname);
352         if (!check_status(res, op->status)) {
353                 printf("[%d] REMOVE \"%s\" failed (%x) - expected %s\n", 
354                        op->child->line, op->fname, res, op->status);
355                 failed(op->child);
356         }
357 }
358
359 static void nfs3_readdirplus(struct dbench_op *op)
360 {
361         nfsstat3 res;
362
363         res = nfsio_readdirplus(op->child->private, op->fname, NULL, NULL);
364         if (!check_status(res, op->status)) {
365                 printf("[%d] READDIRPLUS \"%s\" failed (%x) - expected %s\n", 
366                        op->child->line, op->fname, res, op->status);
367                 failed(op->child);
368         }
369 }
370
371 static void nfs3_link(struct dbench_op *op)
372 {
373         nfsstat3 res;
374
375         res = nfsio_link(op->child->private, op->fname, op->fname2);
376         if (!check_status(res, op->status)) {
377                 printf("[%d] LINK \"%s\"->\"%s\" failed (%x) - expected %s\n", 
378                        op->child->line, op->fname, op->fname2,
379                        res, op->status);
380                 failed(op->child);
381         }
382 }
383
384 static void nfs3_rename(struct dbench_op *op)
385 {
386         nfsstat3 res;
387
388         res = nfsio_rename(op->child->private, op->fname, op->fname2);
389         if (!check_status(res, op->status)) {
390                 printf("[%d] RENAME \"%s\"->\"%s\" failed (%x) - expected %s\n", 
391                        op->child->line, op->fname, op->fname2,
392                        res, op->status);
393                 failed(op->child);
394         }
395 }
396
397 static int nfs3_init(void)
398 {
399         void *handle;
400
401         handle = nfsio_connect(options.server, options.export, options.protocol);
402         if (handle == NULL) {
403                 printf("Failed to connect to NFS server\n");
404                 return 1;
405         }
406
407         nfsio_disconnect(handle);
408         return 0;
409 }
410
411 static struct backend_op ops[] = {
412         { "Deltree",  nfs3_deltree },
413         { "GETATTR3", nfs3_getattr },
414         { "LOOKUP3",  nfs3_lookup },
415         { "CREATE3",  nfs3_create },
416         { "WRITE3",   nfs3_write },
417         { "COMMIT3",  nfs3_commit },
418         { "READ3",    nfs3_read },
419         { "ACCESS3",  nfs3_access },
420         { "MKDIR3",   nfs3_mkdir },
421         { "RMDIR3",   nfs3_rmdir },
422         { "FSSTAT3",  nfs3_fsstat },
423         { "FSINFO3",  nfs3_fsinfo },
424         { "SYMLINK3", nfs3_symlink },
425         { "REMOVE3",  nfs3_remove },
426         { "READDIRPLUS3", nfs3_readdirplus },
427         { "RENAME3",  nfs3_rename },
428         { "LINK3",    nfs3_link },
429         { NULL, NULL}
430 };
431
432 struct nb_operations nfs_ops = {
433         .backend_name = "nfsbench",
434         .init         = nfs3_init,
435         .setup        = nfs3_setup,
436         .cleanup      = nfs3_cleanup,
437         .ops          = ops
438 };