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