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));
149 #define difftime(a, b) \
150 ((double)(a)->tv_sec - (b)->tv_sec + \
151 ((double)((a)->tv_usec - (b)->tv_usec) / 1000000))
153 static int be_verbose(int verbose, struct timeval *next_time,
154 int num, int *next_num, int num_total)
161 if (next_time != NULL)
162 gettimeofday(&now, NULL);
164 /* A positive verbosity means to print every X iterations */
166 (next_num == NULL || num >= *next_num || num >= num_total)) {
167 *next_num += verbose;
169 next_time->tv_sec = now.tv_sec - verbose;
170 next_time->tv_usec = now.tv_usec;
175 /* A negative verbosity means to print at most each X seconds */
176 if (verbose < 0 && next_time != NULL && difftime(&now, next_time) >= 0){
177 next_time->tv_sec = now.tv_sec - verbose;
178 next_time->tv_usec = now.tv_usec;
187 static int get_verbose(const char *arg)
191 if (!arg || arg[0] == 'v')
193 else if (arg[0] == 's' || arg[0] == 'q')
196 verbose = strtoul(arg, NULL, 0);
201 static int do_disconnect(char *func, int verbose)
203 struct obd_ioctl_data data;
211 rc = ioctl(fd, OBD_IOC_DISCONNECT , &data);
213 fprintf(stderr, "error: %s: %x %s\n", cmdname(func),
214 OBD_IOC_DISCONNECT, strerror(errno));
217 printf("%s: disconnected connid %d\n", cmdname(func),
225 extern command_t cmdlist[];
227 static int do_device(char *func, int dev)
229 struct obd_ioctl_data data;
231 memset(&data, 0, sizeof(data));
238 if (obd_ioctl_pack(&data, &buf, max)) {
239 fprintf(stderr, "error: %s: invalid ioctl\n", cmdname(func));
243 return ioctl(fd, OBD_IOC_DEVICE , buf);
246 static int jt_device(int argc, char **argv)
250 do_disconnect(argv[0], 1);
253 fprintf(stderr, "usage: %s devno\n", cmdname(argv[0]));
257 rc = do_device(argv[0], strtoul(argv[1], NULL, 0));
260 fprintf(stderr, "error: %s: %s\n", cmdname(argv[0]),
261 strerror(rc = errno));
266 static int jt_connect(int argc, char **argv)
268 struct obd_ioctl_data data;
273 do_disconnect(argv[0], 1);
276 fprintf(stderr, "usage: %s\n", cmdname(argv[0]));
280 rc = ioctl(fd, OBD_IOC_CONNECT , &data);
282 fprintf(stderr, "error: %s: %x %s\n", cmdname(argv[0]),
283 OBD_IOC_CONNECT, strerror(rc = errno));
285 connid = data.ioc_conn1;
290 static int jt_disconnect(int argc, char **argv)
293 fprintf(stderr, "usage: %s\n", cmdname(argv[0]));
297 return do_disconnect(argv[0], 0);
300 static int jt__device(int argc, char **argv)
306 fprintf(stderr, "usage: %s devno <command [args ...]>\n",
311 rc = do_device("device", strtoul(argv[1], NULL, 0));
316 rc = jt_connect(1, arg2);
320 rc = Parser_execarg(argc - 2, argv + 2, cmdlist);
322 ret = do_disconnect(argv[0], 0);
329 static int jt__threads(int argc, char **argv)
331 int threads, next_thread;
338 "usage: %s numthreads verbose devno <cmd [args ...]>\n",
343 threads = strtoul(argv[1], NULL, 0);
345 verbose = get_verbose(argv[2]);
347 printf("%s: starting %d threads on device %s running %s\n",
348 argv[0], threads, argv[3], argv[4]);
350 for (i = 1, next_thread = verbose; i <= threads; i++) {
353 fprintf(stderr, "error: %s: #%d - %s\n", argv[0], i,
354 strerror(rc = errno));
356 } else if (rc == 0) {
358 argv[2] = "--device";
359 return jt__device(argc - 2, argv + 2);
360 } else if (be_verbose(verbose, NULL, i, &next_thread, threads))
361 printf("%s: thread #%d (PID %d) started\n",
366 if (!thread) { /* parent process */
368 printf("%s: started %d threads\n\n", argv[0], i - 1);
372 for (j = 1; j < i; j++) {
374 int ret = wait(&status);
377 fprintf(stderr, "error: %s: wait - %s\n",
378 argv[0], strerror(errno));
383 * This is a hack. We _should_ be able to use
384 * WIFEXITED(status) to see if there was an
385 * error, but it appears to be broken and it
386 * always returns 1 (OK). See wait(2).
388 int err = WEXITSTATUS(status);
391 "%s: PID %d had rc=%d\n",
402 static int jt_detach(int argc, char **argv)
404 struct obd_ioctl_data data;
410 fprintf(stderr, "usage: %s\n", cmdname(argv[0]));
414 if (obd_ioctl_pack(&data, &buf, max)) {
415 fprintf(stderr, "error: %s: invalid ioctl\n", cmdname(argv[0]));
419 rc = ioctl(fd, OBD_IOC_DETACH , buf);
421 fprintf(stderr, "error: %s: %s\n", cmdname(argv[0]),
427 static int jt_cleanup(int argc, char **argv)
429 struct obd_ioctl_data data;
435 fprintf(stderr, "usage: %s\n", cmdname(argv[0]));
439 rc = ioctl(fd, OBD_IOC_CLEANUP , &data);
441 fprintf(stderr, "error: %s: %s\n", cmdname(argv[0]),
447 static int jt_newdev(int argc, char **argv)
449 struct obd_ioctl_data data;
458 fprintf(stderr, "usage: %s\n", cmdname(argv[0]));
462 rc = ioctl(fd, OBD_IOC_NEWDEV , &data);
464 fprintf(stderr, "error: %s: %s\n", cmdname(argv[0]),
467 printf("Current device set to %d\n", data.ioc_dev);
473 static int jt_attach(int argc, char **argv)
475 struct obd_ioctl_data data;
480 if (argc != 2 && argc != 3) {
481 fprintf(stderr, "usage: %s type [name [uuid]]\n",
486 data.ioc_inllen1 = strlen(argv[1]) + 1;
487 data.ioc_inlbuf1 = argv[1];
489 data.ioc_inllen2 = strlen(argv[2]) + 1;
490 data.ioc_inlbuf2 = argv[2];
493 if (obd_ioctl_pack(&data, &buf, max)) {
494 fprintf(stderr, "error: %s: invalid ioctl\n", cmdname(argv[0]));
498 rc = ioctl(fd, OBD_IOC_ATTACH , buf);
500 fprintf(stderr, "error: %s: %x %s\n", cmdname(argv[0]),
501 OBD_IOC_ATTACH, strerror(rc = errno));
502 else if (argc == 3) {
504 if (strlen(argv[2]) > 128) {
505 printf("Name too long to set environment\n");
508 snprintf(name, 512, "LUSTRE_DEV_%s", argv[2]);
509 rc = setenv(name, argv[1], 1);
511 printf("error setting env variable %s\n", name);
518 #define N2D_OFF 0x100 /* So we can tell between error codes and devices */
520 static int do_name2dev(char *func, char *name)
522 struct obd_ioctl_data data;
530 data.ioc_inllen1 = strlen(name) + 1;
531 data.ioc_inlbuf1 = name;
533 if (obd_ioctl_pack(&data, &buf, max)) {
534 fprintf(stderr, "error: %s: invalid ioctl\n", cmdname(func));
537 rc = ioctl(fd, OBD_IOC_NAME2DEV , buf);
539 fprintf(stderr, "error: %s: %s - %s\n", cmdname(func),
540 name, strerror(rc = errno));
544 memcpy((char *)(&data), buf, sizeof(data));
546 return data.ioc_dev + N2D_OFF;
549 static int jt_name2dev(int argc, char **argv)
554 fprintf(stderr, "usage: %s name\n", cmdname(argv[0]));
558 rc = do_name2dev(argv[0], argv[1]);
560 int dev = rc - N2D_OFF;
561 rc = do_device(argv[0], dev);
568 static int jt_setup(int argc, char **argv)
570 struct obd_ioctl_data data;
576 fprintf(stderr, "usage: %s [device] [fstype]\n",
583 if (argv[1][0] == '$') {
584 rc = do_name2dev(argv[0], argv[1] + 1);
586 printf("%s is device %d\n", argv[1],
588 data.ioc_dev = rc - N2D_OFF;
591 data.ioc_dev = strtoul(argv[1], NULL, 0);
592 data.ioc_inllen1 = strlen(argv[1]) + 1;
593 data.ioc_inlbuf1 = argv[1];
596 data.ioc_inllen2 = strlen(argv[2]) + 1;
597 data.ioc_inlbuf2 = argv[2];
600 if (obd_ioctl_pack(&data, &buf, max)) {
601 fprintf(stderr, "error: %s: invalid ioctl\n", cmdname(argv[0]));
604 rc = ioctl(fd, OBD_IOC_SETUP , buf);
606 fprintf(stderr, "error: %s: %s\n", cmdname(argv[0]),
607 strerror(rc = errno));
613 static int jt_create(int argc, char **argv)
615 struct obd_ioctl_data data;
616 struct timeval next_time;
617 int count = 1, next_count;
623 if (argc < 2 || argc > 4) {
624 fprintf(stderr, "usage: %s num [mode] [verbose]\n",
628 count = strtoul(argv[1], NULL, 0);
631 data.ioc_obdo1.o_mode = strtoul(argv[2], NULL, 0);
633 data.ioc_obdo1.o_mode = 0100644;
634 data.ioc_obdo1.o_valid = OBD_MD_FLMODE;
636 verbose = get_verbose(argv[3]);
638 printf("%s: %d obdos\n", cmdname(argv[0]), count);
639 gettimeofday(&next_time, NULL);
640 next_time.tv_sec -= verbose;
642 for (i = 1, next_count = verbose; i <= count ; i++) {
643 rc = ioctl(fd, OBD_IOC_CREATE , &data);
645 fprintf(stderr, "error: %s: #%d - %s\n",
646 cmdname(argv[0]), i, strerror(rc = errno));
649 if (be_verbose(verbose, &next_time, i, &next_count, count))
650 printf("%s: #%d is object id %Ld\n", cmdname(argv[0]),
651 i, data.ioc_obdo1.o_id);
656 static int jt_setattr(int argc, char **argv)
658 struct obd_ioctl_data data;
663 fprintf(stderr, "usage: %s id mode\n", cmdname(argv[0]));
667 data.ioc_obdo1.o_id = strtoul(argv[1], NULL, 0);
668 data.ioc_obdo1.o_mode = S_IFREG | strtoul(argv[2], NULL, 0);
669 data.ioc_obdo1.o_valid = OBD_MD_FLMODE;
671 rc = ioctl(fd, OBD_IOC_SETATTR , &data);
673 fprintf(stderr, "error: %s: %s\n", cmdname(argv[0]),
674 strerror(rc = errno));
679 static int jt_destroy(int argc, char **argv)
681 struct obd_ioctl_data data;
686 fprintf(stderr, "usage: %s id\n", cmdname(argv[0]));
690 data.ioc_obdo1.o_id = strtoul(argv[1], NULL, 0);
691 data.ioc_obdo1.o_mode = S_IFREG|0644;
693 rc = ioctl(fd, OBD_IOC_DESTROY , &data);
695 fprintf(stderr, "error: %s: %s\n", cmdname(argv[0]),
696 strerror(rc = errno));
701 static int jt_getattr(int argc, char **argv)
703 struct obd_ioctl_data data;
707 fprintf(stderr, "usage: %s id\n", cmdname(argv[0]));
712 data.ioc_obdo1.o_id = strtoul(argv[1], NULL, 0);
713 /* to help obd filter */
714 data.ioc_obdo1.o_mode = 0100644;
715 data.ioc_obdo1.o_valid = 0xffffffff;
716 printf("%s: object id %Ld\n", cmdname(argv[0]), data.ioc_obdo1.o_id);
718 rc = ioctl(fd, OBD_IOC_GETATTR , &data);
720 fprintf(stderr, "error: %s: %s\n", cmdname(argv[0]),
723 printf("%s: object id %Ld, mode %o\n", cmdname(argv[0]),
724 data.ioc_obdo1.o_id, data.ioc_obdo1.o_mode);
729 static int jt_test_getattr(int argc, char **argv)
731 struct obd_ioctl_data data;
732 struct timeval start, next_time;
733 int i, count, next_count;
737 if (argc != 2 && argc != 3) {
738 fprintf(stderr, "usage: %s count [verbose]\n",cmdname(argv[0]));
743 count = strtoul(argv[1], NULL, 0);
745 verbose = get_verbose(argv[2]);
747 data.ioc_obdo1.o_valid = 0xffffffff;
748 data.ioc_obdo1.o_id = 2;
749 gettimeofday(&start, NULL);
750 next_time.tv_sec = start.tv_sec - verbose;
751 next_time.tv_usec = start.tv_usec;
752 printf("%s: getting %d attrs (testing only): %s", cmdname(argv[0]),
753 count, ctime(&start.tv_sec));
755 for (i = 1, next_count = verbose; i <= count; i++) {
756 rc = ioctl(fd, OBD_IOC_GETATTR , &data);
758 fprintf(stderr, "error: %s: #%d - %s\n",
759 cmdname(argv[0]), i, strerror(rc = errno));
761 } else if (be_verbose(verbose, &next_time, i,&next_count,count))
762 printf("%s: got attr #%d\n", cmdname(argv[0]), i);
769 gettimeofday(&end, NULL);
771 diff = difftime(&end, &start);
774 printf("%s: %d attrs in %.4gs (%.4g attr/s): %s",
775 cmdname(argv[0]), i, diff, (double)i / diff,
781 static int jt_test_brw(int argc, char **argv)
783 struct obd_ioctl_data data;
784 struct timeval start, next_time;
786 int pages = 1, obdos = 1, count, next_count;
787 int verbose = 1, write = 0, rw;
792 if (argc < 2 || argc > 6) {
794 "usage: %s count [write [verbose [pages [obdos]]]]\n",
799 count = strtoul(argv[1], NULL, 0);
802 if (argv[2][0] == 'w' || argv[2][0] == '1')
804 else if (argv[2][0] == 'r' || argv[2][0] == '0')
807 verbose = get_verbose(argv[3]);
811 pages = strtoul(argv[4], NULL, 0);
813 obdos = strtoul(argv[5], NULL, 0);
815 if (obdos != 1 && obdos != 2) {
816 fprintf(stderr, "error: %s: only 1 or 2 obdos supported\n",
821 len = pages * PAGE_SIZE;
823 bulk = calloc(obdos, len);
825 fprintf(stderr, "error: %s: no memory allocating %dx%d pages\n",
826 cmdname(argv[0]), obdos, pages);
830 data.ioc_conn2 = connid;
831 data.ioc_obdo1.o_id = 2;
832 data.ioc_count = len;
834 data.ioc_plen1 = len;
835 data.ioc_pbuf1 = bulk;
837 data.ioc_obdo2.o_id = 2;
838 data.ioc_plen2 = len;
839 data.ioc_pbuf2 = bulk + len;
842 gettimeofday(&start, NULL);
843 next_time.tv_sec = start.tv_sec - verbose;
844 next_time.tv_usec = start.tv_usec;
846 printf("%s: %s %d (%dx%d pages) (testing only): %s",
847 cmdname(argv[0]), write ? "writing" : "reading",
848 count, obdos, pages, ctime(&start.tv_sec));
851 * We will put in the start time (and loop count inside the loop)
852 * at the beginning of each page so that we will be able to validate
853 * (at some later time) whether the data actually made it or not.
855 for (o = 0, b = bulk; o < obdos; o++)
856 for (p = 0; p < pages; p++, b += PAGE_SIZE)
857 memcpy(b, &start, sizeof(start));
859 rw = write ? OBD_IOC_BRW_WRITE : OBD_IOC_BRW_READ;
860 for (i = 1, next_count = verbose; i <= count; i++) {
862 b = bulk + sizeof(struct timeval);
863 for (o = 0; o < obdos; o++)
864 for (p = 0; p < pages; p++, b += PAGE_SIZE)
865 memcpy(b, &count, sizeof(count));
868 rc = ioctl(fd, rw, &data);
870 fprintf(stderr, "error: %s: #%d - %s on %s\n",
871 cmdname(argv[0]), i, strerror(rc = errno),
872 write ? "write" : "read");
874 } else if (be_verbose(verbose, &next_time, i,&next_count,count))
875 printf("%s: %s number %d\n", cmdname(argv[0]),
876 write ? "write" : "read", i);
885 gettimeofday(&end, NULL);
887 diff = difftime(&end, &start);
890 printf("%s: %s %dx%dx%d pages in %.4gs (%.4g pg/s): %s",
891 cmdname(argv[0]), write ? "wrote" : "read", obdos,
892 pages, i, diff, (double)obdos * i * pages / diff,
898 static int jt_test_ldlm(int argc, char **argv)
900 struct obd_ioctl_data data;
905 fprintf(stderr, "usage: %s\n", cmdname(argv[0]));
909 rc = ioctl(fd, IOC_LDLM_TEST, &data);
911 fprintf(stderr, "error: %s: test failed: %s\n",
912 cmdname(argv[0]), strerror(rc = errno));
916 static int jt_newconn(int argc, char **argv)
918 struct obd_ioctl_data data;
923 fprintf(stderr, "usage: %s\n", cmdname(argv[0]));
927 rc = ioctl(fd, OBD_RECOVD_NEWCONN , &data);
929 fprintf(stderr, "error: %s: %s\n", cmdname(argv[0]),
930 strerror(rc = errno));
935 command_t cmdlist[] = {
937 {"--device", jt__device, 0, "--device <devno> <command [args ...]>"},
938 {"--threads", jt__threads, 0,
939 "--threads <threads> <devno> <command [args ...]>"},
941 /* Device configuration commands */
942 {"newdev", jt_newdev, 0, "set device to a new unused obd (no args)"},
943 {"device", jt_device, 0, "set current device (args device_no name)"},
944 {"name2dev", jt_name2dev, 0, "set device by name (args name)"},
945 {"attach", jt_attach, 0, "name the type of device (args: type data"},
946 {"setup", jt_setup, 0, "setup device (args: <blkdev> [data]"},
947 {"detach", jt_detach, 0, "detach the current device (arg: )"},
948 {"cleanup", jt_cleanup, 0, "cleanup the current device (arg: )"},
950 /* Session commands */
951 {"connect", jt_connect, 0, "connect - get a connection to device"},
952 {"disconnect", jt_disconnect, 0,
953 "disconnect - break connection to device"},
955 /* Session operations */
956 {"create", jt_create, 0, "create [count [mode [verbose]]]"},
957 {"destroy", jt_destroy, 0, "destroy <id>"},
958 {"getattr", jt_getattr, 0, "getattr <id>"},
959 {"setattr", jt_setattr, 0, "setattr <id> <mode>"},
960 {"newconn", jt_newconn, 0, "newconn [newuuid]"},
961 {"test_getattr", jt_test_getattr, 0, "test_getattr <count> [verbose]"},
962 {"test_brw", jt_test_brw, 0, "test_brw <count> [write [verbose]]"},
963 {"test_ldlm", jt_test_ldlm, 0, "test lock manager (no args)"},
965 /* User interface commands */
966 {"help", Parser_help, 0, "help"},
967 {"exit", Parser_quit, 0, "quit"},
968 {"quit", Parser_quit, 0, "quit"},
973 static void signal_server(int sig)
976 do_disconnect("sigint", 1);
979 fprintf(stderr, "%s: got signal %d\n", cmdname("sigint"), sig);
983 int main(int argc, char **argv)
985 struct sigaction sigact;
988 sigact.sa_handler = signal_server;
989 sigfillset(&sigact.sa_mask);
990 sigact.sa_flags = SA_RESTART;
991 sigaction(SIGINT, &sigact, NULL);
995 rc = Parser_execarg(argc - 1, argv + 1, cmdlist);
997 Parser_init("obdctl > ", cmdlist);
1001 do_disconnect(argv[0], 1);