1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2 * vim:expandtab:shiftwidth=8:tabstop=8:
4 * Copyright (C) 2002 Cluster File Systems, Inc.
5 * Author: Peter J. Braam <braam@clusterfs.com>
6 * Author: Phil Schwan <phil@clusterfs.com>
8 * This file is part of Lustre, http://www.lustre.org.
10 * Lustre is free software; you can redistribute it and/or
11 * modify it under the terms of version 2 of the GNU General Public
12 * License as published by the Free Software Foundation.
14 * Lustre is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with Lustre; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 #include <sys/ioctl.h>
28 #include <sys/socket.h>
29 #include <sys/types.h>
36 #include <linux/lustre_lib.h>
37 #include <linux/lustre_idl.h>
38 #include <linux/lustre_dlm.h>
44 #include <netinet/in.h>
49 #include <linux/list.h>
62 #define IOCINIT(data) \
64 memset(&data, 0, sizeof(data)); \
65 data.ioc_version = OBD_IOCTL_VERSION; \
66 data.ioc_conn1 = connid; \
67 data.ioc_len = sizeof(data); \
69 fprintf(stderr, "No device open, use device\n"); \
75 pack "LL LL LL LL LL LL LL L L L L L L L L L a60 a60 L L L",
94 0, 0, # struct list_head
100 char * obdo_print(struct obdo *obd)
104 sprintf(buf, "id: %Ld\ngrp: %Ld\natime: %Ld\nmtime: %Ld\nctime: %Ld\n"
105 "size: %Ld\nblocks: %Ld\nblksize: %d\nmode: %o\nuid: %d\n"
106 "gid: %d\nflags: %x\nobdflags: %x\nnlink: %d,\nvalid %x\n",
125 static char *cmdname(char *func)
127 static char buf[512];
130 sprintf(buf, "%s-%d", func, thread);
137 int getfd(char *func)
140 fd = open("/dev/obd", O_RDWR);
142 fprintf(stderr, "error: %s: opening /dev/obd: %s\n",
143 cmdname(func), strerror(errno));
150 #define difftime(a, b) \
151 ((double)(a)->tv_sec - (b)->tv_sec + \
152 ((double)((a)->tv_usec - (b)->tv_usec) / 1000000))
155 #define difftime(a, b) (((a)->tv_sec - (b)->tv_sec) + \
156 (((a)->tv_usec - (b)->tv_usec) / 1000000))
158 static int be_verbose(int verbose, struct timeval *next_time,
159 int num, int *next_num, int num_total)
166 if (next_time != NULL)
167 gettimeofday(&now, NULL);
169 /* A positive verbosity means to print every X iterations */
171 (next_num == NULL || num >= *next_num || num >= num_total)) {
172 *next_num += verbose;
174 next_time->tv_sec = now.tv_sec - verbose;
175 next_time->tv_usec = now.tv_usec;
180 /* A negative verbosity means to print at most each X seconds */
181 if (verbose < 0 && next_time != NULL && difftime(&now, next_time) >= 0){
182 next_time->tv_sec = now.tv_sec - verbose;
183 next_time->tv_usec = now.tv_usec;
192 static int get_verbose(const char *arg)
196 if (!arg || arg[0] == 'v')
198 else if (arg[0] == 's' || arg[0] == 'q')
201 verbose = (int) strtoul(arg, NULL, 0);
203 printf("Verbose = %d\n",verbose);
208 static int do_disconnect(char *func, int verbose)
210 struct obd_ioctl_data data;
218 rc = ioctl(fd, OBD_IOC_DISCONNECT , &data);
220 fprintf(stderr, "error: %s: %x %s\n", cmdname(func),
221 OBD_IOC_DISCONNECT, strerror(errno));
224 printf("%s: disconnected connid %d\n", cmdname(func),
232 extern command_t cmdlist[];
234 static int do_device(char *func, int dev)
236 struct obd_ioctl_data data;
238 memset(&data, 0, sizeof(data));
245 if (obd_ioctl_pack(&data, &buf, max)) {
246 fprintf(stderr, "error: %s: invalid ioctl\n", cmdname(func));
250 return ioctl(fd, OBD_IOC_DEVICE , buf);
253 static int jt_device(int argc, char **argv)
257 do_disconnect(argv[0], 1);
260 fprintf(stderr, "usage: %s devno\n", cmdname(argv[0]));
264 rc = do_device(argv[0], strtoul(argv[1], NULL, 0));
267 fprintf(stderr, "error: %s: %s\n", cmdname(argv[0]),
268 strerror(rc = errno));
273 static int jt_connect(int argc, char **argv)
275 struct obd_ioctl_data data;
280 do_disconnect(argv[0], 1);
283 fprintf(stderr, "usage: %s\n", cmdname(argv[0]));
287 rc = ioctl(fd, OBD_IOC_CONNECT , &data);
289 fprintf(stderr, "error: %s: %x %s\n", cmdname(argv[0]),
290 OBD_IOC_CONNECT, strerror(rc = errno));
292 connid = data.ioc_conn1;
297 static int jt_disconnect(int argc, char **argv)
300 fprintf(stderr, "usage: %s\n", cmdname(argv[0]));
304 return do_disconnect(argv[0], 0);
307 static int jt__device(int argc, char **argv)
313 fprintf(stderr, "usage: %s devno <command [args ...]>\n",
318 rc = do_device("device", strtoul(argv[1], NULL, 0));
323 rc = jt_connect(1, arg2);
327 rc = Parser_execarg(argc - 2, argv + 2, cmdlist);
329 ret = do_disconnect(argv[0], 0);
336 static int jt__threads(int argc, char **argv)
338 int threads, next_thread;
345 "usage: %s numthreads verbose devno <cmd [args ...]>\n",
350 threads = strtoul(argv[1], NULL, 0);
352 verbose = get_verbose(argv[2]);
354 printf("%s: starting %d threads on device %s running %s\n",
355 argv[0], threads, argv[3], argv[4]);
357 for (i = 1, next_thread = verbose; i <= threads; i++) {
360 fprintf(stderr, "error: %s: #%d - %s\n", argv[0], i,
361 strerror(rc = errno));
363 } else if (rc == 0) {
365 argv[2] = "--device";
366 return jt__device(argc - 2, argv + 2);
367 } else if (be_verbose(verbose, NULL, i, &next_thread, threads))
368 printf("%s: thread #%d (PID %d) started\n",
373 if (!thread) { /* parent process */
375 printf("%s: started %d threads\n\n", argv[0], i - 1);
379 for (j = 1; j < i; j++) {
381 int ret = wait(&status);
384 fprintf(stderr, "error: %s: wait - %s\n",
385 argv[0], strerror(errno));
390 * This is a hack. We _should_ be able to use
391 * WIFEXITED(status) to see if there was an
392 * error, but it appears to be broken and it
393 * always returns 1 (OK). See wait(2).
395 int err = WEXITSTATUS(status);
398 "%s: PID %d had rc=%d\n",
409 static int jt_detach(int argc, char **argv)
411 struct obd_ioctl_data data;
417 fprintf(stderr, "usage: %s\n", cmdname(argv[0]));
421 if (obd_ioctl_pack(&data, &buf, max)) {
422 fprintf(stderr, "error: %s: invalid ioctl\n", cmdname(argv[0]));
426 rc = ioctl(fd, OBD_IOC_DETACH , buf);
428 fprintf(stderr, "error: %s: %s\n", cmdname(argv[0]),
434 static int jt_cleanup(int argc, char **argv)
436 struct obd_ioctl_data data;
442 fprintf(stderr, "usage: %s\n", cmdname(argv[0]));
446 rc = ioctl(fd, OBD_IOC_CLEANUP , &data);
448 fprintf(stderr, "error: %s: %s\n", cmdname(argv[0]),
454 static int jt_newdev(int argc, char **argv)
456 struct obd_ioctl_data data;
465 fprintf(stderr, "usage: %s\n", cmdname(argv[0]));
469 rc = ioctl(fd, OBD_IOC_NEWDEV , &data);
471 fprintf(stderr, "error: %s: %s\n", cmdname(argv[0]),
474 printf("Current device set to %d\n", data.ioc_dev);
480 static int jt_attach(int argc, char **argv)
482 struct obd_ioctl_data data;
487 if (argc != 2 && argc != 3) {
488 fprintf(stderr, "usage: %s type [name [uuid]]\n",
493 data.ioc_inllen1 = strlen(argv[1]) + 1;
494 data.ioc_inlbuf1 = argv[1];
496 data.ioc_inllen2 = strlen(argv[2]) + 1;
497 data.ioc_inlbuf2 = argv[2];
500 if (obd_ioctl_pack(&data, &buf, max)) {
501 fprintf(stderr, "error: %s: invalid ioctl\n", cmdname(argv[0]));
505 rc = ioctl(fd, OBD_IOC_ATTACH , buf);
507 fprintf(stderr, "error: %s: %x %s\n", cmdname(argv[0]),
508 OBD_IOC_ATTACH, strerror(rc = errno));
509 else if (argc == 3) {
511 if (strlen(argv[2]) > 128) {
512 printf("Name too long to set environment\n");
515 snprintf(name, 512, "LUSTRE_DEV_%s", argv[2]);
516 rc = setenv(name, argv[1], 1);
518 printf("error setting env variable %s\n", name);
525 #define N2D_OFF 0x100 /* So we can tell between error codes and devices */
527 static int do_name2dev(char *func, char *name)
529 struct obd_ioctl_data data;
537 data.ioc_inllen1 = strlen(name) + 1;
538 data.ioc_inlbuf1 = name;
540 if (obd_ioctl_pack(&data, &buf, max)) {
541 fprintf(stderr, "error: %s: invalid ioctl\n", cmdname(func));
544 rc = ioctl(fd, OBD_IOC_NAME2DEV , buf);
546 fprintf(stderr, "error: %s: %s - %s\n", cmdname(func),
547 name, strerror(rc = errno));
551 memcpy((char *)(&data), buf, sizeof(data));
553 return data.ioc_dev + N2D_OFF;
556 static int jt_name2dev(int argc, char **argv)
561 fprintf(stderr, "usage: %s name\n", cmdname(argv[0]));
565 rc = do_name2dev(argv[0], argv[1]);
567 int dev = rc - N2D_OFF;
568 rc = do_device(argv[0], dev);
575 static int jt_setup(int argc, char **argv)
577 struct obd_ioctl_data data;
583 fprintf(stderr, "usage: %s [device] [fstype]\n",
590 if (argv[1][0] == '$') {
591 rc = do_name2dev(argv[0], argv[1] + 1);
593 printf("%s is device %d\n", argv[1],
595 data.ioc_dev = rc - N2D_OFF;
598 data.ioc_dev = strtoul(argv[1], NULL, 0);
599 data.ioc_inllen1 = strlen(argv[1]) + 1;
600 data.ioc_inlbuf1 = argv[1];
603 data.ioc_inllen2 = strlen(argv[2]) + 1;
604 data.ioc_inlbuf2 = argv[2];
607 if (obd_ioctl_pack(&data, &buf, max)) {
608 fprintf(stderr, "error: %s: invalid ioctl\n", cmdname(argv[0]));
611 rc = ioctl(fd, OBD_IOC_SETUP , buf);
613 fprintf(stderr, "error: %s: %s\n", cmdname(argv[0]),
614 strerror(rc = errno));
620 static int jt_create(int argc, char **argv)
622 struct obd_ioctl_data data;
623 struct timeval next_time;
624 int count = 1, next_count;
630 if (argc < 2 || argc > 4) {
631 fprintf(stderr, "usage: %s num [mode] [verbose]\n",
635 count = strtoul(argv[1], NULL, 0);
638 data.ioc_obdo1.o_mode = strtoul(argv[2], NULL, 0);
640 data.ioc_obdo1.o_mode = 0100644;
641 data.ioc_obdo1.o_valid = OBD_MD_FLMODE;
643 verbose = get_verbose(argv[3]);
645 printf("%s: %d obdos\n", cmdname(argv[0]), count);
646 gettimeofday(&next_time, NULL);
647 next_time.tv_sec -= verbose;
649 for (i = 1, next_count = verbose; i <= count ; i++) {
650 rc = ioctl(fd, OBD_IOC_CREATE , &data);
652 fprintf(stderr, "error: %s: #%d - %s\n",
653 cmdname(argv[0]), i, strerror(rc = errno));
656 if (be_verbose(verbose, &next_time, i, &next_count, count))
657 printf("%s: #%d is object id %Ld\n", cmdname(argv[0]),
658 i, data.ioc_obdo1.o_id);
663 static int jt_setattr(int argc, char **argv)
665 struct obd_ioctl_data data;
670 fprintf(stderr, "usage: %s id mode\n", cmdname(argv[0]));
674 data.ioc_obdo1.o_id = strtoul(argv[1], NULL, 0);
675 data.ioc_obdo1.o_mode = S_IFREG | strtoul(argv[2], NULL, 0);
676 data.ioc_obdo1.o_valid = OBD_MD_FLMODE;
678 rc = ioctl(fd, OBD_IOC_SETATTR , &data);
680 fprintf(stderr, "error: %s: %s\n", cmdname(argv[0]),
681 strerror(rc = errno));
686 static int jt_destroy(int argc, char **argv)
688 struct obd_ioctl_data data;
693 fprintf(stderr, "usage: %s id\n", cmdname(argv[0]));
697 data.ioc_obdo1.o_id = strtoul(argv[1], NULL, 0);
698 data.ioc_obdo1.o_mode = S_IFREG|0644;
700 rc = ioctl(fd, OBD_IOC_DESTROY , &data);
702 fprintf(stderr, "error: %s: %s\n", cmdname(argv[0]),
703 strerror(rc = errno));
708 static int jt_getattr(int argc, char **argv)
710 struct obd_ioctl_data data;
714 fprintf(stderr, "usage: %s id\n", cmdname(argv[0]));
719 data.ioc_obdo1.o_id = strtoul(argv[1], NULL, 0);
720 /* to help obd filter */
721 data.ioc_obdo1.o_mode = 0100644;
722 data.ioc_obdo1.o_valid = 0xffffffff;
723 printf("%s: object id %Ld\n", cmdname(argv[0]), data.ioc_obdo1.o_id);
725 rc = ioctl(fd, OBD_IOC_GETATTR , &data);
727 fprintf(stderr, "error: %s: %s\n", cmdname(argv[0]),
730 printf("%s: object id %Ld, mode %o\n", cmdname(argv[0]),
731 data.ioc_obdo1.o_id, data.ioc_obdo1.o_mode);
736 static int jt_test_getattr(int argc, char **argv)
738 struct obd_ioctl_data data;
739 struct timeval start, next_time;
740 int i, count, next_count;
744 if (argc != 2 && argc != 3) {
745 fprintf(stderr, "usage: %s count [verbose]\n",cmdname(argv[0]));
750 count = strtoul(argv[1], NULL, 0);
753 verbose = get_verbose(argv[2]);
757 data.ioc_obdo1.o_valid = 0xffffffff;
758 data.ioc_obdo1.o_id = 2;
759 gettimeofday(&start, NULL);
760 next_time.tv_sec = start.tv_sec - verbose;
761 next_time.tv_usec = start.tv_usec;
762 printf("%s: getting %d attrs (testing only): %s", cmdname(argv[0]),
763 count, ctime(&start.tv_sec));
765 for (i = 1, next_count = verbose; i <= count; i++) {
766 rc = ioctl(fd, OBD_IOC_GETATTR , &data);
768 fprintf(stderr, "error: %s: #%d - %s\n",
769 cmdname(argv[0]), i, strerror(rc = errno));
772 if (be_verbose(verbose, &next_time, i,&next_count,count))
773 printf("%s: got attr #%d\n", cmdname(argv[0]), i);
781 gettimeofday(&end, NULL);
783 diff = difftime(&end, &start);
786 printf("%s: %d attrs in %.4gs (%.4g attr/s): %s",
787 cmdname(argv[0]), i, diff, (double)i / diff,
793 static int jt_test_brw(int argc, char **argv)
795 struct obd_ioctl_data data;
796 struct timeval start, next_time;
798 int pages = 1, obdos = 1, count, next_count;
799 int verbose = 1, write = 0, rw;
804 if (argc < 2 || argc > 6) {
806 "usage: %s count [write [verbose [pages [obdos]]]]\n",
811 count = strtoul(argv[1], NULL, 0);
814 if (argv[2][0] == 'w' || argv[2][0] == '1')
816 else if (argv[2][0] == 'r' || argv[2][0] == '0')
819 verbose = get_verbose(argv[3]);
823 pages = strtoul(argv[4], NULL, 0);
825 obdos = strtoul(argv[5], NULL, 0);
827 if (obdos != 1 && obdos != 2) {
828 fprintf(stderr, "error: %s: only 1 or 2 obdos supported\n",
833 len = pages * PAGE_SIZE;
835 bulk = calloc(obdos, len);
837 fprintf(stderr, "error: %s: no memory allocating %dx%d pages\n",
838 cmdname(argv[0]), obdos, pages);
842 data.ioc_conn2 = connid;
843 data.ioc_obdo1.o_id = 2;
844 data.ioc_count = len;
846 data.ioc_plen1 = len;
847 data.ioc_pbuf1 = bulk;
849 data.ioc_obdo2.o_id = 2;
850 data.ioc_plen2 = len;
851 data.ioc_pbuf2 = bulk + len;
854 gettimeofday(&start, NULL);
855 next_time.tv_sec = start.tv_sec - verbose;
856 next_time.tv_usec = start.tv_usec;
858 printf("%s: %s %d (%dx%d pages) (testing only): %s",
859 cmdname(argv[0]), write ? "writing" : "reading",
860 count, obdos, pages, ctime(&start.tv_sec));
863 * We will put in the start time (and loop count inside the loop)
864 * at the beginning of each page so that we will be able to validate
865 * (at some later time) whether the data actually made it or not.
867 for (o = 0, b = bulk; o < obdos; o++)
868 for (p = 0; p < pages; p++, b += PAGE_SIZE)
869 memcpy(b, &start, sizeof(start));
871 rw = write ? OBD_IOC_BRW_WRITE : OBD_IOC_BRW_READ;
872 for (i = 1, next_count = verbose; i <= count; i++) {
874 b = bulk + sizeof(struct timeval);
875 for (o = 0; o < obdos; o++)
876 for (p = 0; p < pages; p++, b += PAGE_SIZE)
877 memcpy(b, &count, sizeof(count));
880 rc = ioctl(fd, rw, &data);
882 fprintf(stderr, "error: %s: #%d - %s on %s\n",
883 cmdname(argv[0]), i, strerror(rc = errno),
884 write ? "write" : "read");
886 } else if (be_verbose(verbose, &next_time, i,&next_count,count))
887 printf("%s: %s number %d\n", cmdname(argv[0]),
888 write ? "write" : "read", i);
897 gettimeofday(&end, NULL);
899 diff = difftime(&end, &start);
902 printf("%s: %s %dx%dx%d pages in %.4gs (%.4g pg/s): %s",
903 cmdname(argv[0]), write ? "wrote" : "read", obdos,
904 pages, i, diff, (double)obdos * i * pages / diff,
910 static int jt_test_ldlm(int argc, char **argv)
912 struct obd_ioctl_data data;
917 fprintf(stderr, "usage: %s\n", cmdname(argv[0]));
921 rc = ioctl(fd, IOC_LDLM_TEST, &data);
923 fprintf(stderr, "error: %s: test failed: %s\n",
924 cmdname(argv[0]), strerror(rc = errno));
928 static int jt_newconn(int argc, char **argv)
930 struct obd_ioctl_data data;
935 fprintf(stderr, "usage: %s\n", cmdname(argv[0]));
939 rc = ioctl(fd, OBD_RECOVD_NEWCONN , &data);
941 fprintf(stderr, "error: %s: %s\n", cmdname(argv[0]),
942 strerror(rc = errno));
947 command_t cmdlist[] = {
949 {"--device", jt__device, 0, "--device <devno> <command [args ...]>"},
950 {"--threads", jt__threads, 0,
951 "--threads <threads> <devno> <command [args ...]>"},
953 /* Device configuration commands */
954 {"newdev", jt_newdev, 0, "set device to a new unused obd (no args)"},
955 {"device", jt_device, 0, "set current device (args device_no name)"},
956 {"name2dev", jt_name2dev, 0, "set device by name (args name)"},
957 {"attach", jt_attach, 0, "name the type of device (args: type data"},
958 {"setup", jt_setup, 0, "setup device (args: <blkdev> [data]"},
959 {"detach", jt_detach, 0, "detach the current device (arg: )"},
960 {"cleanup", jt_cleanup, 0, "cleanup the current device (arg: )"},
962 /* Session commands */
963 {"connect", jt_connect, 0, "connect - get a connection to device"},
964 {"disconnect", jt_disconnect, 0,
965 "disconnect - break connection to device"},
967 /* Session operations */
968 {"create", jt_create, 0, "create [count [mode [verbose]]]"},
969 {"destroy", jt_destroy, 0, "destroy <id>"},
970 {"getattr", jt_getattr, 0, "getattr <id>"},
971 {"setattr", jt_setattr, 0, "setattr <id> <mode>"},
972 {"newconn", jt_newconn, 0, "newconn [newuuid]"},
973 {"test_getattr", jt_test_getattr, 0, "test_getattr <count> [verbose]"},
974 {"test_brw", jt_test_brw, 0, "test_brw <count> [write [verbose]]"},
975 {"test_ldlm", jt_test_ldlm, 0, "test lock manager (no args)"},
977 /* User interface commands */
978 {"help", Parser_help, 0, "help"},
979 {"exit", Parser_quit, 0, "quit"},
980 {"quit", Parser_quit, 0, "quit"},
985 static void signal_server(int sig)
988 do_disconnect("sigint", 1);
991 fprintf(stderr, "%s: got signal %d\n", cmdname("sigint"), sig);
995 int main(int argc, char **argv)
997 struct sigaction sigact;
1000 sigact.sa_handler = signal_server;
1001 sigfillset(&sigact.sa_mask);
1002 sigact.sa_flags = SA_RESTART;
1003 sigaction(SIGINT, &sigact, NULL);
1007 rc = Parser_execarg(argc - 1, argv + 1, cmdlist);
1009 Parser_init("obdctl > ", cmdlist);
1013 do_disconnect(argv[0], 1);