1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #include "nfsgen.h"
28
29 int64_t io_buff_size = 32 * 1024; /* default to 32KB */
30 int64_t io_buff_num = 1024;
31 int64_t io_hold_num = -1; /* default to no wait */
32 int64_t io_init_offset = 0;
33 int64_t io_loop_count = 1;
34 int64_t lock_init_offset = 0;
35 int64_t lock_range = 0;
36 int64_t maxTruncSize = 0;
37 short lock_type;
38 int is_read = 0;
39 int is_write = 0;
40 int is_lock = 0;
41 int is_blockinglock = 0;
42 int is_unlock = 0;
43 int is_closefile = 0;
44 int is_truncate = 0;
45 int is_returndel = 0;
46 int open_flag = O_RDONLY;
47 int signaled = 0;
48 mode_t open_mode = 0664;
49 unsigned int write_seed = 777;
50 unsigned int read_seed = 777;
51 unsigned int sleep_sec = 0;
52 char *file_name = NULL;
53
54 void
55 fileOperatorDump()
56 {
57 dprint("io_buff_size: %lld\n", io_buff_size);
58 dprint("io_buff_num: %lld\n", io_buff_num);
59 dprint("io_hold_num: %lld\n", io_hold_num);
60 dprint("io_init_offset: %lld\n", io_init_offset);
61 dprint("io_loop_count: %lld\n", io_loop_count);
62 dprint("lock_init_offset: %lld\n", lock_init_offset);
63 dprint("lock_range: %lld\n", lock_range);
64 dprint("lock_type: %d\n", lock_type);
65 dprint("is_read: %d\n", is_read);
66 dprint("is_write: %d\n", is_write);
67 dprint("is_lock: %d\n", is_lock);
68 dprint("is_unlock: %d\n", is_unlock);
69 dprint("is_closefile: %d\n", is_closefile);
70 dprint("is_truncate: %d\n", is_truncate);
71 dprint("maxTruncSize: %lld\n", maxTruncSize);
72 dprint("open_flag: %d\n", open_flag);
73 dprint("open_mode: %d\n", open_mode);
74 dprint("write_seed: %d\n", write_seed);
75 dprint("read_seed: %d\n", read_seed);
76 dprint("sleep_sec: %d\n", sleep_sec);
77 dprint("debug: %d\n", debug);
78 dprint("showerror: %d\n", showerror);
79 dprint("file_name: %s\n", file_name);
80 dprint("-----------------------------------------\n\n");
81 }
82
83
84 /*
85 * signal(SIGUSR1) handler
86 */
87 void
88 handler(int signo)
89 {
90 dprint("got signal #%d\n", signo);
91 signaled = 1;
92 }
93
94 /*
95 * fill the buffer with random data
96 * arguments:
97 * $1 : buffer used to contain data
98 * $2 : buffer size
99 * $3 : seed used to generate random data
100 */
101 void
102 genBuffer(unsigned char *buff, int64_t size, unsigned int *write_seed)
103 {
104 int64_t index = 0;
105 for (index = 0; index < size; index ++) {
106 buff[index] = (unsigned char)(rand_r(write_seed) % 256);
107 }
108 }
109
110
111 /*
112 * check data in buffer is correct or not
113 * arguments:
114 * $1 : data buffer
115 * $2 : buffer size
116 * return value:
117 * On sucess, return 0
118 * On error, return 1
119 */
120 int
121 checkBuffer(unsigned char *buff, int64_t buff_size)
122 {
123 int index = 0;
124 int ret = 0;
125 unsigned char tmp;
126
127 dprint("Started to check buffer data ... \n");
128 for (index = 0; index < buff_size; index++) {
129 tmp = (unsigned char) (rand_r(&read_seed) % 256);
130 if (buff[index] != tmp) {
131 eprint("check buff failed at %d, expect: %c, \
132 real: %c \n", index, buff[index], tmp);
133 ret = 1;
134 break;
135 }
136 }
137
138 return (ret);
139 }
140
141 /*
142 * lock or unlock file with exclusive lock
143 * arguments:
144 * $1 : file descriptor
145 * $2 : indicates lock or unlock
146 * return value:
147 * On sucess, return 0
148 * On error, return 1
149 */
150 int
151 lockUnlockFile(int fd, int is_lock, short l_type, off64_t l_start, \
152 off64_t l_len)
153 {
154 int ret = 0;
155 struct flock lock_stat;
156
157 lock_stat.l_whence = SEEK_SET;
158 lock_stat.l_start = l_start;
159 lock_stat.l_len = l_len;
160
161 if (is_lock == 1) {
162 dprint("Started to lock file ...\n");
163 lock_stat.l_type = l_type;
164 if (fcntl(fd, (is_blockinglock == 1) ? F_SETLKW : F_SETLK, \
165 &lock_stat) < 0) {
166 eprint("failed to set lock(unavailable) on file: \
167 %s, %s\n", file_name, strerror(errno));
168 ret = 1;
169 } else {
170 print("got %s lock; sleeping...\n", \
171 (is_write == 1) ? "exclusive" : "shared");
172
173 sleep(sleep_sec);
174 }
175 } else {
176 dprint("Started to unlock file ...\n");
177 lock_stat.l_type = F_UNLCK;
178 if (fcntl(fd, F_SETLKW, &lock_stat) < 0) {
179 eprint("failed to unlock file, %s, \
180 %s\n", file_name, strerror(errno));
181 ret = 1;
182 }
183 }
184
185 return (ret);
186 }
187
188
189 /*
190 * file operator main function to handle file IO
191 */
192 int
193 mainFunc()
194 {
195 int ret = 0;
196 int fd = 0;
197 int i = 0;
198 unsigned char *buff = NULL;
199 int64_t gotBytes = 0;
200 off64_t truncOffset = 0;
201
202 dprint("Started mainFunc() ...\n");
203
204 /* register signal handler */
205 signal(SIGUSR1, handler);
206
207 /* open file */
208 if ((fd = open(file_name, open_flag, open_mode)) < 0) {
209 eprint("failed to open file: %s, %s\n", file_name, \
210 strerror(errno));
211 ret = 1;
212 return (ret);
213 }
214
215 /* lock file */
216 if (is_lock == 1) {
217 if ((ret = lockUnlockFile(fd, 1, lock_type, lock_init_offset, \
218 lock_range)) < 0) {
219 eprint("failed to lock file: %s, %s\n", file_name, \
220 strerror(errno));
221 ret = 1;
222 close(fd);
223 return (ret);
224 }
225 }
226
227 /* generate data buffer */
228 if ((buff = (unsigned char *)malloc(io_buff_size)) == NULL) {
229 eprint("failed to mallock %d size memory buff, %s\n", \
230 io_buff_size, strerror(errno));
231 close(fd);
232 ret = 1;
233 return (ret);
234 }
235
236 while (io_loop_count > 0) {
237 if (is_truncate == 1) {
238 io_init_offset = (off64_t)rand_r(&write_seed) \
239 % maxTruncSize;
240 }
241
242 /* lseek to init offset */
243 if (lseek64(fd, io_init_offset, SEEK_SET) != io_init_offset) {
244 eprint("failed to lseek to :%d\n", io_init_offset);
245 ret = 1;
246 break;
247 }
248
249 /* file IO untill the waitnumber */
250 dprint("Started to IO file till io_hold_num ...\n");
251 for (i = 0; i < io_hold_num; i++) {
252 if (is_write == 1) {
253 genBuffer(buff, io_buff_size, &write_seed);
254 if (nfsgenWrite(fd, buff, io_buff_size) != \
255 io_buff_size) {
256 eprint("failed to write data:%d, %s\n",\
257 errno, strerror(errno));
258 ret = 1;
259 break;
260 } else {
261 /*
262 * read back for check
263 * if is_trucate set
264 */
265 if (is_truncate == 1) {
266 if (lseek64(fd, \
267 io_init_offset, \
268 SEEK_SET) != \
269 io_init_offset) {
270 eprint("failed to \
271 lseek to :%d\n", \
272 io_init_offset);
273 ret = 1;
274 break;
275 }
276 if ((gotBytes = nfsgenRead(fd, \
277 buff, io_buff_size)) != \
278 io_buff_size) {
279 eprint("failed to read \
280 data, exp: %d, \
281 real: %d \n", \
282 gotBytes, \
283 io_buff_size);
284 ret = 1;
285 break;
286 }
287 if (checkBuffer(buff, \
288 io_buff_size) \
289 != 0) {
290 ret = 1;
291 break;
292 }
293 }
294 }
295 } else {
296 if ((gotBytes = nfsgenRead(fd, buff, \
297 io_buff_size)) != io_buff_size) {
298 eprint("failed to read data, exp: %d, \
299 real: %d \n", gotBytes, \
300 io_buff_size);
301 ret = 1;
302 break;
303 }
304 }
305 }
306
307 if (ret != 0) {
308 break;
309 }
310
311 /* okay, truncate file */
312 if (is_truncate == 1) {
313 dprint("Started to truncate file ...\n");
314 if (ftruncate64(fd, (off64_t)rand_r(&write_seed) % \
315 maxTruncSize < 0)) {
316 eprint("failed to truncate file to a random \
317 size, %s", strerror(errno));
318 ret = 1;
319 break;
320 }
321 }
322
323 /* okay, I'm here, signal outside, I'm ready */
324 if (io_hold_num >= 0) {
325 print("I am ready, I_am_ready\n");
326 }
327
328 /* go to sleep, wait instruction from user */
329 if (io_hold_num >= 0) {
330 dprint("Started to wait the user signal comes from \
331 outsider ...\n");
332 while (signaled == 0) {
333 yield();
334 }
335 }
336
337 if (signaled == 1) {
338 /* read back data for check */
339 print("signalled, read back data for check\n");
340 if (lseek(fd, io_init_offset, SEEK_SET) != \
341 io_init_offset) {
342 eprint("failed to lseek to :%d\n", \
343 io_init_offset);
344 ret = 1;
345 break;
346 }
347
348 /* read data */
349 for (i = 0; i < io_hold_num; i++) {
350 if ((gotBytes = nfsgenRead(fd, buff, \
351 io_buff_size)) != io_buff_size) {
352 eprint("failed to read data, \
353 exp: %d, real: %d \n", \
354 gotBytes, io_buff_size);
355 ret = 1;
356 break;
357 } else {
358 if ((ret = checkBuffer(buff, \
359 io_buff_size)) != 0) {
360 ret = 1;
361 break;
362 }
363 }
364 } /* end of for */
365 if (ret != 0) {
366 break;
367 }
368 }
369
370 /* continue IO untill the waitnumber */
371 dprint("Started to finish the remaining IO ...\n");
372 for (; i < io_buff_num; i++) {
373 if (is_write == 1) {
374 genBuffer(buff, io_buff_size, &write_seed);
375 if (nfsgenWrite(fd, buff, io_buff_size) \
376 != io_buff_size) {
377 eprint("failed to write data: \
378 %d, %s\n", errno, \
379 strerror(errno));
380 ret = 1;
381 break;
382 }
383 } else {
384 if ((gotBytes = nfsgenRead(fd, buff, \
385 io_buff_size)) != io_buff_size) {
386 eprint("failed to read data, expect \
387 %d, real got %d \n", \
388 gotBytes, io_buff_size);
389 ret = 1;
390 break;
391 }
392 }
393 } /* end of for */
394
395 if (ret != 0) {
396 break;
397 }
398
399 io_loop_count --;
400 } /* end of while */
401
402 /* unlock file */
403 if ((ret == 0) && (is_unlock == 1)) {
404 if ((ret = lockUnlockFile(fd, 0, lock_type, lock_init_offset, \
405 lock_range)) < 0) {
406 eprint("failed to lock file: %s, %s\n", file_name, \
407 strerror(errno));
408 ret = 1;
409 }
410 }
411
412 /* return delegation type */
413 if ((ret == 0) && (is_returndel == 1)) {
414 i = get_deleg(fd, file_name);
415 print("return_delegation_type=%d\n", i);
416 }
417
418 /* close file */
419 if (is_closefile == 1) {
420 if (close(fd) < 0) {
421 eprint("failed to close file: %s, %s\n", file_name, \
422 strerror(errno));
423 ret = errno;
424 }
425 }
426
427 /* free data buff */
428 free(buff);
429
430
431 return (ret);
432 }
433
434
435 void
436 usage(char *cmd)
437 {
438 printf("%s [options] filename\n", cmd);
439 printf("options:\n");
440 printf("\t -o open_flag specify file open flag \n");
441 printf("\t 0: O_RDONLY \n");
442 printf("\t 1: O_WRONLY|O_CREAT \n");
443 printf("\t 2: O_WRONLY|O_APPEND \n");
444 printf("\t 3: O_WRONLY|O_TRUNC \n");
445 printf("\t 4: O_RDWR|O_CREAT \n");
446 printf("\t 5: O_RDWR|O_APPEND \n");
447 printf("\t 6: O_RDWR|O_TRUNC \n");
448 printf("\t -m open_mode specify file open mode, \n");
449 printf("\t default to 0664 \n");
450 printf("\t -L lock_type is_blocking offset range \n");
451 printf("\t lock_type to 0 is read-lock, \n");
452 printf("\t 1 is write-lock \n");
453 printf("\t -B buff_size buff_number hold_number \n");
454 printf("\t specify buffer size, buffer number \n");
455 printf("\t and where IO should be held and wait \n");
456 printf("\t signal comes from outside user \n");
457 printf("\t -e seed specify seed to generate \n");
458 printf("\t random data \n");
459 printf("\t -s sleep_seconds specify sleep seconds \n");
460 printf("\t -i offset specify IO initial offset \n");
461 printf("\t -l count specify loop count \n");
462 printf("\t -t maxTruncSize specify max random truancate size in \n");
463 printf("\t each loop iteration, but user cannot \n");
464 printf("\t specify -t along with hold_number >= 0 \n");
465 printf("\t in -B option \n");
466 printf("\t -R read data from file \n");
467 printf("\t -W write data into file \n");
468 printf("\t -c close file at end \n");
469 printf("\t -d return delegation type as return code \n");
470 printf("\t at end \n");
471 printf("\t -u unlock file at end \n");
472 printf("\t -D trun on debug infomation \n");
473 printf("\t -h show this help information \n");
474 }
475
476 char
477 *removePrefixBlank(char *src)
478 {
479 char *ret = src;
480 while (*ret == ' ') {
481 ret ++; }
482
483 return (ret);
484 }
485
486 int
487 main(int argc, char *argv[])
488 {
489 int c = 0;
490 int ret = 0;
491 int tmp = 0;
492 char *poptarg = NULL;
493 char *envBuff = NULL;
494
495 if (argc < 2) {
496 usage(argv[0]);
497 return (1);
498 }
499 while ((c = getopt(argc, argv, "o:m:L:B:e:s:i:l:t:RWcduDh")) != -1) {
500 switch (c) {
501 case 'o':
502 tmp = strtol(optarg, NULL, 0);
503 switch (tmp) {
504 case 0:
505 open_flag = O_RDONLY;
506 break;
507 case 1:
508 open_flag = O_WRONLY|O_CREAT;
509 break;
510 case 2:
511 open_flag = \
512 O_WRONLY|O_APPEND|O_CREAT;
513 break;
514 case 3:
515 open_flag = \
516 O_WRONLY|O_TRUNC|O_CREAT;
517 break;
518 case 4:
519 open_flag = \
520 O_RDWR|O_CREAT|O_CREAT;
521 break;
522 case 5:
523 open_flag = \
524 O_RDWR|O_APPEND|O_CREAT;
525 break;
526 case 6:
527 open_flag = \
528 O_RDWR|O_TRUNC|O_CREAT;
529 break;
530 case 7:
531 open_flag = O_WRONLY;
532 break;
533 default:
534 print("Invalid open flag \
535 parameter\n");
536 usage(argv[0]);
537 return (1);
538 }
539 break;
540 case 'm':
541 open_mode = (mode_t)strtol(optarg, NULL, 0);
542 break;
543 case 'L':
544 is_lock = 1;
545 poptarg = (char *)optarg;
546 tmp = strtol(optarg, NULL, 0);
547 poptarg = \
548 strstr(removePrefixBlank(poptarg), " ");
549 is_blockinglock = strtol(poptarg, NULL, 0);
550 poptarg = \
551 strstr(removePrefixBlank(poptarg), " ");
552 lock_init_offset = \
553 (off64_t)strtol(poptarg, NULL, 0);
554 poptarg = \
555 strstr(removePrefixBlank(poptarg), " ");
556 lock_range = (off64_t)strtol(poptarg, NULL, 0);
557 switch (tmp) {
558 case 0:
559 lock_type = F_RDLCK;
560 break;
561 case 1:
562 lock_type = F_WRLCK;
563 break;
564 default:
565 print("Invalid lock \
566 parameter\n");
567 usage(argv[0]);
568 return (1);
569 }
570 break;
571 case 'B':
572 poptarg = (char *)optarg;
573 io_buff_size = \
574 (int64_t)strtol(poptarg, NULL, 0);
575 poptarg = \
576 strstr(removePrefixBlank(poptarg), " ");
577 io_buff_num = (int64_t)strtol(poptarg, NULL, 0);
578 poptarg = \
579 strstr(removePrefixBlank(poptarg), " ");
580 io_hold_num = (int64_t)strtol(poptarg, NULL, 0);
581 break;
582 case 'e':
583 write_seed = (unsigned int)strtol(optarg, \
584 NULL, 0);
585 read_seed = write_seed;
586 break;
587 case 's':
588 sleep_sec = (unsigned int)strtol(optarg, \
589 NULL, 0);
590 break;
591 case 'i':
592 io_init_offset = (int64_t)strtol(optarg, \
593 NULL, 0);
594 break;
595 case 'l':
596 io_loop_count = (int64_t)strtol(optarg, \
597 NULL, 0);
598 break;
599 case 't':
600 is_truncate = 1;
601 maxTruncSize = (int64_t)strtol(optarg, NULL, 0);
602 break;
603 case 'R':
604 is_read = 1;
605 break;
606 case 'W':
607 is_write = 1;
608 break;
609 case 'c':
610 is_closefile = 1;
611 break;
612 case 'd':
613 is_returndel = 1;
614 break;
615 case 'u':
616 is_unlock = 1;
617 break;
618 case 'D':
619 debug = 1;
620 break;
621 case 'h':
622 usage(argv[0]);
623 break;
624 default:
625 usage(argv[0]);
626 return (1);
627 }
628 }
629
630 /* get filename */
631 file_name = argv[optind];
632 if (file_name == NULL) {
633 print("no file_name specified\n");
634 usage(argv[0]);
635 return (1);
636 }
637
638 /* check for read and write */
639 if (((is_read == 1) && (is_write == 1)) || \
640 ((is_read == 0) && (is_write == 0))) {
641 print("User need to speicfy at least one of -R and -W option, \
642 -R and -W are exclusive options\n");
643 usage(argv[0]);
644 return (1);
645 }
646
647 /* check -t and hold_number in -B option */
648 if ((is_truncate == 1) && (io_hold_num >= 0)) {
649 print("Limitation: user cannot specify -t and hold_num \
650 large than -1 at the same time \n");
651 usage(argv[0]);
652 return (1);
653 }
654
655 /* check FILE_OPERATOR_DEBUG in case of user didn't specify -D option */
656 if (debug == 0) {
657 if ((envBuff = getenv("FILE_OPERATOR_DEBUG")) != NULL) {
658 if (strcasecmp(envBuff, "ON") == 0) {
659 debug = 1;
660 }
661 }
662 }
663
664 /*
665 * file_operator default to print out error info unless user
666 * specified env SHOWERROR=OFF
667 */
668 showerror = 1;
669 if ((envBuff = getenv("SHOWERROR")) != NULL) {
670 if (strcasecmp(envBuff, "OFF") == 0) {
671 showerror = 0;
672 }
673 }
674
675
676 fileOperatorDump();
677
678 /* okay, go to the mainFunc */
679 if ((ret = mainFunc()) == 0) {
680 print("completed successfully!\n");
681 }
682
683 return (ret);
684 }