Whamcloud - gitweb
- reorganize so same functions are used by both obdctl and lctl
[fs/lustre-release.git] / lustre / utils / obd.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  *  Copyright (C) 2002 Cluster File Systems, Inc.
5  *   Author: Peter J. Braam <braam@clusterfs.com>
6  *   Author: Phil Schwan <phil@clusterfs.com>
7  *   Author: Robert Read <rread@clusterfs.com> 
8  *
9  *   This file is part of Lustre, http://www.lustre.org.
10  *
11  *   Lustre is free software; you can redistribute it and/or
12  *   modify it under the terms of version 2 of the GNU General Public
13  *   License as published by the Free Software Foundation.
14  *
15  *   Lustre is distributed in the hope that it will be useful,
16  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
17  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  *   GNU General Public License for more details.
19  *
20  *   You should have received a copy of the GNU General Public License
21  *   along with Lustre; if not, write to the Free Software
22  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23  *
24  */
25
26
27 #include <stdlib.h>
28 #include <sys/ioctl.h>
29 #include <fcntl.h>
30 #include <sys/socket.h>
31 #include <sys/types.h>
32 #include <sys/wait.h>
33 #include <sys/stat.h>
34 #include <stdio.h>
35 #include <stdarg.h>
36 #include <signal.h>
37 #define printk printf
38
39 #include <linux/lustre_lib.h>
40 #include <linux/lustre_idl.h>
41 #include <linux/lustre_dlm.h>
42
43 #include <unistd.h>
44 #include <sys/un.h>
45 #include <time.h>
46 #include <sys/time.h>
47 #include <netinet/in.h>
48 #include <errno.h>
49 #include <string.h>
50
51 #include <asm/page.h>           /* needed for PAGE_SIZE - rread */
52
53 #define __KERNEL__
54 #include <linux/list.h>
55 #undef __KERNEL__
56
57 #include "obdctl.h"
58 #include "parser.h"
59 #include <stdio.h>
60
61 #define SHMEM_STATS 1
62 #if SHMEM_STATS
63 # include <sys/ipc.h>
64 # include <sys/shm.h>
65
66 # define MAX_SHMEM_COUNT 1024
67 static long long *shared_counters;
68 static long long counter_snapshot[2][MAX_SHMEM_COUNT];
69 struct timeval prev_time;
70 #endif
71
72 int fd = -1;
73 uint64_t conn_addr = -1;
74 uint64_t conn_cookie;
75 char rawbuf[8192];
76 char *buf = rawbuf;
77 int max = 8192;
78
79 static int thread;
80
81 static int getfd(char *func);
82 static char *cmdname(char *func);
83
84 #define IOCINIT(data)                                                   \
85 do {                                                                    \
86         memset(&data, 0, sizeof(data));                                 \
87         data.ioc_version = OBD_IOCTL_VERSION;                           \
88         data.ioc_addr = conn_addr;                                      \
89         data.ioc_cookie = conn_cookie;                                  \
90         data.ioc_len = sizeof(data);                                    \
91         if (fd < 0) {                                                   \
92                 fprintf(stderr, "No device open, use device\n");        \
93                 return 1;                                               \
94         }                                                               \
95 } while (0)
96
97 /*
98     pack "LL LL LL LL LL LL LL L L L L L L L L L a60 a60 L L L",
99     $obdo->{id}, 0,
100     $obdo->{gr}, 0,
101     $obdo->{atime}, 0,
102     $obdo->{mtime}, 0 ,
103     $obdo->{ctime}, 0,
104     $obdo->{size}, 0,
105     $obdo->{blocks}, 0,
106     $obdo->{blksize},
107     $obdo->{mode},
108     $obdo->{uid},
109     $obdo->{gid},
110     $obdo->{flags},
111     $obdo->{obdflags},
112     $obdo->{nlink},
113     $obdo->{generation},
114     $obdo->{valid},
115     $obdo->{inline},
116     $obdo->{obdmd},
117     0, 0, # struct list_head
118     0;  #  struct obd_ops
119 }
120
121 */
122
123 char *obdo_print(struct obdo *obd)
124 {
125         char buf[1024];
126
127         sprintf(buf, "id: %Ld\ngrp: %Ld\natime: %Ld\nmtime: %Ld\nctime: %Ld\n"
128                 "size: %Ld\nblocks: %Ld\nblksize: %d\nmode: %o\nuid: %d\n"
129                 "gid: %d\nflags: %x\nobdflags: %x\nnlink: %d,\nvalid %x\n",
130                 obd->o_id,
131                 obd->o_gr,
132                 obd->o_atime,
133                 obd->o_mtime,
134                 obd->o_ctime,
135                 obd->o_size,
136                 obd->o_blocks,
137                 obd->o_blksize,
138                 obd->o_mode,
139                 obd->o_uid,
140                 obd->o_gid,
141                 obd->o_flags, obd->o_obdflags, obd->o_nlink, obd->o_valid);
142         return strdup(buf);
143 }
144
145
146
147 #define N2D_OFF 0x100      /* So we can tell between error codes and devices */
148
149 static int do_name2dev(char *func, char *name)
150 {
151         struct obd_ioctl_data data;
152         int rc;
153
154         if (getfd(func))
155                 return -1;
156
157         IOCINIT(data);
158
159         data.ioc_inllen1 = strlen(name) + 1;
160         data.ioc_inlbuf1 = name;
161
162         if (obd_ioctl_pack(&data, &buf, max)) {
163                 fprintf(stderr, "error: %s: invalid ioctl\n", cmdname(func));
164                 return -2;
165         }
166         rc = ioctl(fd, OBD_IOC_NAME2DEV, buf);
167         if (rc < 0) {
168                 fprintf(stderr, "error: %s: %s - %s\n", cmdname(func),
169                         name, strerror(rc = errno));
170                 return rc;
171         }
172
173         memcpy((char *)(&data), buf, sizeof(data));
174
175         return data.ioc_dev + N2D_OFF;
176 }
177
178 /* 
179  * resolve a device name to a device number.
180  * supports a number or name.  
181  * FIXME: support UUID 
182  */
183 static int parse_devname(char * func, char *name) 
184 {
185         int rc;
186         int ret = -1;
187
188         if (!name) 
189                 return ret;
190         if (name[0] == '$') {
191                 rc = do_name2dev(func, name + 1);
192                 if (rc >= N2D_OFF) {
193                         ret = rc - N2D_OFF;
194                         printf("%s is device %d\n", name,
195                                ret);
196                 } else {
197                         fprintf(stderr, "error: %s: %s: %s\n", cmdname(func),
198                                 name, "device not found");
199                 }
200                         
201         } else
202                 ret = strtoul(name, NULL, 0);
203         return ret;
204 }
205
206 static char *cmdname(char *func)
207 {
208         static char buf[512];
209
210         if (thread) {
211                 sprintf(buf, "%s-%d", func, thread);
212                 return buf;
213         }
214
215         return func;
216 }
217
218 static int getfd(char *func)
219 {
220         if (fd == -1)
221                 fd = open("/dev/obd", O_RDWR);
222         if (fd == -1) {
223                 fprintf(stderr, "error: %s: opening /dev/obd: %s\n"
224                         "hint: lustre kernel modules may not be loaded.\n",
225                         cmdname(func), strerror(errno));
226                 return -1;
227         }
228         return 0;
229 }
230
231 #define difftime(a, b)                                          \
232         ((double)(a)->tv_sec - (b)->tv_sec +                    \
233          ((double)((a)->tv_usec - (b)->tv_usec) / 1000000))
234
235 static int be_verbose(int verbose, struct timeval *next_time,
236                       int num, int *next_num, int num_total)
237 {
238         struct timeval now;
239
240         if (!verbose)
241                 return 0;
242
243         if (next_time != NULL)
244                 gettimeofday(&now, NULL);
245
246         /* A positive verbosity means to print every X iterations */
247         if (verbose > 0 &&
248             (next_num == NULL || num >= *next_num || num >= num_total)) {
249                 *next_num += verbose;
250                 if (next_time) {
251                         next_time->tv_sec = now.tv_sec - verbose;
252                         next_time->tv_usec = now.tv_usec;
253                 }
254                 return 1;
255         }
256
257         /* A negative verbosity means to print at most each X seconds */
258         if (verbose < 0 && next_time != NULL && difftime(&now, next_time) >= 0) {
259                 next_time->tv_sec = now.tv_sec - verbose;
260                 next_time->tv_usec = now.tv_usec;
261                 if (next_num)
262                         *next_num = num;
263                 return 1;
264         }
265
266         return 0;
267 }
268
269 static int get_verbose(const char *arg)
270 {
271         int verbose;
272
273         if (!arg || arg[0] == 'v')
274                 verbose = 1;
275         else if (arg[0] == 's' || arg[0] == 'q')
276                 verbose = 0;
277         else
278                 verbose = (int)strtoul(arg, NULL, 0);
279
280         if (verbose < 0)
281                 printf("Print status every %d seconds\n", -verbose);
282         else if (verbose == 1)
283                 printf("Print status every operation\n");
284         else if (verbose > 1)
285                 printf("Print status every %d operations\n", verbose);
286
287         return verbose;
288 }
289
290 int do_disconnect(char *func, int verbose)
291 {
292         int rc;
293         struct obd_ioctl_data data;
294
295         if (conn_addr == -1)
296                 return 0;
297
298         IOCINIT(data);
299
300         rc = ioctl(fd, OBD_IOC_DISCONNECT, &data);
301         if (rc < 0) {
302                 fprintf(stderr, "error: %s: %x %s\n", cmdname(func),
303                         OBD_IOC_DISCONNECT, strerror(errno));
304         } else {
305                 if (verbose)
306                         printf("%s: disconnected conn %Lx\n", cmdname(func),
307                                conn_addr);
308                 conn_addr = -1;
309         }
310
311         return rc;
312 }
313
314 #if SHMEM_STATS
315 static void shmem_setup(void)
316 {
317         int shmid = shmget(IPC_PRIVATE, sizeof(counter_snapshot[0]), 0600);
318
319         if (shmid == -1) {
320                 fprintf(stderr, "Can't create shared memory counters: %s\n",
321                         strerror(errno));
322                 return;
323         }
324
325         shared_counters = (long long *)shmat(shmid, NULL, 0);
326
327         if (shared_counters == (long long *)(-1)) {
328                 fprintf(stderr, "Can't attach shared memory counters: %s\n",
329                         strerror(errno));
330                 shared_counters = NULL;
331                 return;
332         }
333 }
334
335 static inline void shmem_reset(void)
336 {
337         if (shared_counters == NULL)
338                 return;
339
340         memset(shared_counters, 0, sizeof(counter_snapshot[0]));
341         memset(counter_snapshot, 0, sizeof(counter_snapshot));
342         gettimeofday(&prev_time, NULL);
343 }
344
345 static inline void shmem_bump(void)
346 {
347         if (shared_counters == NULL || thread <= 0 || thread > MAX_SHMEM_COUNT)
348                 return;
349
350         shared_counters[thread - 1]++;
351 }
352
353 static void shmem_snap(int n)
354 {
355         struct timeval this_time;
356         int non_zero = 0;
357         long long total = 0;
358         double secs;
359         int i;
360
361         if (shared_counters == NULL || n > MAX_SHMEM_COUNT)
362                 return;
363
364         memcpy(counter_snapshot[1], counter_snapshot[0],
365                n * sizeof(counter_snapshot[0][0]));
366         memcpy(counter_snapshot[0], shared_counters,
367                n * sizeof(counter_snapshot[0][0]));
368         gettimeofday(&this_time, NULL);
369
370         for (i = 0; i < n; i++) {
371                 long long this_count =
372                         counter_snapshot[0][i] - counter_snapshot[1][i];
373
374                 if (this_count != 0) {
375                         non_zero++;
376                         total += this_count;
377                 }
378         }
379
380         secs = (this_time.tv_sec + this_time.tv_usec / 1000000.0) -
381                 (prev_time.tv_sec + prev_time.tv_usec / 1000000.0);
382
383         printf("%d/%d Total: %f/second\n", non_zero, n, total / secs);
384
385         prev_time = this_time;
386 }
387
388 #define SHMEM_SETUP()   shmem_setup()
389 #define SHMEM_RESET()   shmem_reset()
390 #define SHMEM_BUMP()    shmem_bump()
391 #define SHMEM_SNAP(n)   shmem_snap(n)
392 #else
393 #define SHMEM_SETUP()
394 #define SHMEM_RESET()
395 #define SHMEM_BUMP()
396 #define SHMEM_SNAP(n)
397 #endif
398
399 extern command_t cmdlist[];
400
401 static int do_device(char *func, int dev)
402 {
403         struct obd_ioctl_data data;
404
405         memset(&data, 0, sizeof(data));
406
407         data.ioc_dev = dev;
408
409         if (getfd(func))
410                 return -1;
411
412         if (obd_ioctl_pack(&data, &buf, max)) {
413                 fprintf(stderr, "error: %s: invalid ioctl\n", cmdname(func));
414                 return -2;
415         }
416
417         return ioctl(fd, OBD_IOC_DEVICE, buf);
418 }
419
420 int jt_obd_device(int argc, char **argv)
421 {
422         int rc, dev;
423         do_disconnect(argv[0], 1);
424
425         if (argc != 2) 
426                 return CMD_HELP;
427
428         dev = parse_devname(argv[0], argv[1]);
429         if (dev < 0) {
430                 return -1; 
431         }
432
433         rc = do_device(argv[0], dev);
434         if (rc < 0)
435                 fprintf(stderr, "error: %s: %s\n", cmdname(argv[0]),
436                         strerror(rc = errno));
437
438         return rc;
439 }
440
441 int jt_obd_connect(int argc, char **argv)
442 {
443         struct obd_ioctl_data data;
444         int rc;
445
446         IOCINIT(data);
447
448         do_disconnect(argv[0], 1);
449
450         if (argc != 1)
451                 return CMD_HELP;
452
453         rc = ioctl(fd, OBD_IOC_CONNECT, &data);
454         if (rc < 0)
455                 fprintf(stderr, "error: %s: %x %s\n", cmdname(argv[0]),
456                         OBD_IOC_CONNECT, strerror(rc = errno));
457         else {
458                 conn_addr = data.ioc_addr;
459                 conn_cookie = data.ioc_cookie;
460         }
461         return rc;
462 }
463
464 int jt_obd_disconnect(int argc, char **argv)
465 {
466         if (argc != 1)
467                 return CMD_HELP;
468
469         if (conn_addr == -1)
470                 return 0;
471
472         return do_disconnect(argv[0], 0);
473 }
474
475 int jt_opt_device(int argc, char **argv)
476 {
477         char *arg2[3];
478         int ret;
479         int rc;
480
481         if (argc < 3) {
482                 fprintf(stderr, "usage: %s devno <command [args ...]>\n",
483                         cmdname(argv[0]));
484                 return -1;
485         }
486
487         rc = do_device("device", parse_devname(argv[0], argv[1]));
488
489         if (!rc) {
490                 arg2[0] = "connect";
491                 arg2[1] = NULL;
492                 rc = jt_obd_connect(1, arg2);
493         }
494
495         if (!rc)
496                 rc = Parser_execarg(argc - 2, argv + 2, cmdlist);
497
498         ret = do_disconnect(argv[0], 0);
499         if (!rc)
500                 rc = ret;
501
502         return rc;
503 }
504
505 int jt_opt_threads(int argc, char **argv)
506 {
507         int threads, next_thread;
508         int verbose;
509         int rc = 0;
510         int i;
511
512         if (argc < 5) {
513                 fprintf(stderr,
514                         "usage: %s numthreads verbose devno <cmd [args ...]>\n",
515                         argv[0]);
516                 return -1;
517         }
518
519         threads = strtoul(argv[1], NULL, 0);
520
521         verbose = get_verbose(argv[2]);
522
523         if (verbose != 0)
524                 printf("%s: starting %d threads on device %s running %s\n",
525                        argv[0], threads, argv[3], argv[4]);
526
527         SHMEM_RESET();
528
529         for (i = 1, next_thread = verbose; i <= threads; i++) {
530                 rc = fork();
531                 if (rc < 0) {
532                         fprintf(stderr, "error: %s: #%d - %s\n", argv[0], i,
533                                 strerror(rc = errno));
534                         break;
535                 } else if (rc == 0) {
536                         thread = i;
537                         argv[2] = "--device";
538                         return jt_opt_device(argc - 2, argv + 2);
539                 } else if (be_verbose(verbose, NULL, i, &next_thread, threads))
540                         printf("%s: thread #%d (PID %d) started\n",
541                                argv[0], i, rc);
542                 rc = 0;
543         }
544
545         if (!thread) {          /* parent process */
546                 int live_threads = threads;
547
548                 while (live_threads > 0) {
549                         int status;
550                         pid_t ret;
551
552                         ret = waitpid(0, &status, verbose < 0 ? WNOHANG : 0);
553                         if (ret == 0) {
554                                 if (verbose >= 0)
555                                         abort();
556
557                                 sleep(-verbose);
558                                 SHMEM_SNAP(threads);
559                                 continue;
560                         }
561
562                         if (ret < 0) {
563                                 fprintf(stderr, "error: %s: wait - %s\n",
564                                         argv[0], strerror(errno));
565                                 if (!rc)
566                                         rc = errno;
567                         } else {
568                                 /*
569                                  * This is a hack.  We _should_ be able to use
570                                  * WIFEXITED(status) to see if there was an
571                                  * error, but it appears to be broken and it
572                                  * always returns 1 (OK).  See wait(2).
573                                  */
574                                 int err = WEXITSTATUS(status);
575                                 if (err)
576                                         fprintf(stderr,
577                                                 "%s: PID %d had rc=%d\n",
578                                                 argv[0], ret, err);
579                                 if (!rc)
580                                         rc = err;
581
582                                 live_threads--;
583                         }
584                 }
585         }
586
587         return rc;
588 }
589
590 int jt_obd_detach(int argc, char **argv)
591 {
592         struct obd_ioctl_data data;
593         int rc;
594
595         IOCINIT(data);
596
597         if (argc != 1) 
598                 return CMD_HELP;
599
600         if (obd_ioctl_pack(&data, &buf, max)) {
601                 fprintf(stderr, "error: %s: invalid ioctl\n", cmdname(argv[0]));
602                 return -2;
603         }
604
605         rc = ioctl(fd, OBD_IOC_DETACH, buf);
606         if (rc < 0)
607                 fprintf(stderr, "error: %s: %s\n", cmdname(argv[0]),
608                         strerror(rc = errno));
609
610         return rc;
611 }
612
613 int jt_obd_cleanup(int argc, char **argv)
614 {
615         struct obd_ioctl_data data;
616         int rc;
617
618         IOCINIT(data);
619
620         if (argc != 1) 
621                 return CMD_HELP;
622
623         rc = ioctl(fd, OBD_IOC_CLEANUP, &data);
624         if (rc < 0)
625                 fprintf(stderr, "error: %s: %s\n", cmdname(argv[0]),
626                         strerror(rc = errno));
627
628         return rc;
629 }
630
631 int jt_obd_newdev(int argc, char **argv)
632 {
633         int rc;
634         struct obd_ioctl_data data;
635
636         if (getfd(argv[0]))
637                 return -1;
638
639         IOCINIT(data);
640
641         if (argc != 1) 
642                 return CMD_HELP;
643
644         rc = ioctl(fd, OBD_IOC_NEWDEV, &data);
645         if (rc < 0)
646                 fprintf(stderr, "error: %s: %s\n", cmdname(argv[0]),
647                         strerror(rc = errno));
648         else {
649                 printf("Current device set to %d\n", data.ioc_dev);
650         }
651
652         return rc;
653 }
654
655 int jt_obd_list(int argc, char **argv)
656 {
657         int rc;
658         char buf[1024];
659         struct obd_ioctl_data *data = (struct obd_ioctl_data *)buf;
660
661         if (getfd(argv[0]))
662                 return -1;
663
664         memset(buf, 0, sizeof(buf));
665         data->ioc_version = OBD_IOCTL_VERSION;
666         data->ioc_addr = conn_addr;
667         data->ioc_cookie = conn_addr;
668         data->ioc_len = sizeof(buf);
669         data->ioc_inllen1 = sizeof(buf) - size_round(sizeof(*data));
670
671         if (argc != 1) 
672                 return CMD_HELP;
673
674         rc = ioctl(fd, OBD_IOC_LIST, data);
675         if (rc < 0)
676                 fprintf(stderr, "error: %s: %s\n", cmdname(argv[0]),
677                         strerror(rc = errno));
678         else {
679                 printf("%s", data->ioc_bulk);
680         }
681
682         return rc;
683 }
684
685 int jt_obd_attach(int argc, char **argv)
686 {
687         struct obd_ioctl_data data;
688         int rc;
689
690         IOCINIT(data);
691
692         if (argc != 2 && argc != 3 && argc != 4) 
693                 return CMD_HELP;
694
695         data.ioc_inllen1 = strlen(argv[1]) + 1;
696         data.ioc_inlbuf1 = argv[1];
697         if (argc >= 3) {
698                 data.ioc_inllen2 = strlen(argv[2]) + 1;
699                 data.ioc_inlbuf2 = argv[2];
700         }
701
702         if (argc == 4) {
703                 data.ioc_inllen3 = strlen(argv[3]) + 1;
704                 data.ioc_inlbuf3 = argv[3];
705         }
706
707         if (obd_ioctl_pack(&data, &buf, max)) {
708                 fprintf(stderr, "error: %s: invalid ioctl\n", cmdname(argv[0]));
709                 return -2;
710         }
711
712         rc = ioctl(fd, OBD_IOC_ATTACH, buf);
713         if (rc < 0)
714                 fprintf(stderr, "error: %s: %x %s\n", cmdname(argv[0]),
715                         OBD_IOC_ATTACH, strerror(rc = errno));
716         else if (argc == 3) {
717                 char name[1024];
718                 if (strlen(argv[2]) > 128) {
719                         printf("Name too long to set environment\n");
720                         return -EINVAL;
721                 }
722                 snprintf(name, 512, "LUSTRE_DEV_%s", argv[2]);
723                 rc = setenv(name, argv[1], 1);
724                 if (rc) {
725                         printf("error setting env variable %s\n", name);
726                 }
727         }
728
729         return rc;
730 }
731
732 int jt_obd_name2dev(int argc, char **argv)
733 {
734         int rc;
735         if (argc != 2) 
736                 return CMD_HELP;
737
738         rc = do_name2dev(argv[0], argv[1]);
739         if (rc >= N2D_OFF) {
740                 int dev = rc - N2D_OFF;
741                 rc = do_device(argv[0], dev);
742                 if (rc == 0)
743                         printf("%d\n", dev);
744         }
745         return rc;
746 }
747
748 int jt_obd_setup(int argc, char **argv)
749 {
750         struct obd_ioctl_data data;
751         int rc;
752
753         IOCINIT(data);
754
755         if (argc > 3) 
756                 return CMD_HELP;
757
758         data.ioc_dev = -1;
759         if (argc > 1) {
760                 data.ioc_dev = parse_devname(argv[0], argv[1]);
761                 if (data.ioc_dev < 0)
762                         return -1;
763                 data.ioc_inllen1 = strlen(argv[1]) + 1;
764                 data.ioc_inlbuf1 = argv[1];
765         }
766         if (argc == 3) {
767                 data.ioc_inllen2 = strlen(argv[2]) + 1;
768                 data.ioc_inlbuf2 = argv[2];
769         }
770
771         if (obd_ioctl_pack(&data, &buf, max)) {
772                 fprintf(stderr, "error: %s: invalid ioctl\n", cmdname(argv[0]));
773                 return -2;
774         }
775         rc = ioctl(fd, OBD_IOC_SETUP, buf);
776         if (rc < 0)
777                 fprintf(stderr, "error: %s: %s\n", cmdname(argv[0]),
778                         strerror(rc = errno));
779
780         return rc;
781 }
782
783
784 int jt_obd_create(int argc, char **argv)
785 {
786         struct obd_ioctl_data data;
787         struct timeval next_time;
788         int count = 1, next_count;
789         int verbose;
790         int rc = 0, i;
791
792         IOCINIT(data);
793         if (argc < 2 || argc > 4) {
794                 fprintf(stderr, "usage: %s num [mode] [verbose]\n",
795                         cmdname(argv[0]));
796                 return -1;
797         }
798         count = strtoul(argv[1], NULL, 0);
799
800         if (argc > 2)
801                 data.ioc_obdo1.o_mode = strtoul(argv[2], NULL, 0);
802         else
803                 data.ioc_obdo1.o_mode = 0100644;
804         data.ioc_obdo1.o_valid = OBD_MD_FLMODE;
805
806         verbose = get_verbose(argv[3]);
807
808         printf("%s: %d obdos\n", cmdname(argv[0]), count);
809         gettimeofday(&next_time, NULL);
810         next_time.tv_sec -= verbose;
811
812         for (i = 1, next_count = verbose; i <= count; i++) {
813                 rc = ioctl(fd, OBD_IOC_CREATE, &data);
814                 SHMEM_BUMP();
815                 if (rc < 0) {
816                         fprintf(stderr, "error: %s: #%d - %s\n",
817                                 cmdname(argv[0]), i, strerror(rc = errno));
818                         break;
819                 }
820                 if (be_verbose(verbose, &next_time, i, &next_count, count))
821                         printf("%s: #%d is object id %Ld\n", cmdname(argv[0]),
822                                i, data.ioc_obdo1.o_id);
823         }
824         return rc;
825 }
826
827 int jt_obd_setattr(int argc, char **argv)
828 {
829         struct obd_ioctl_data data;
830         int rc;
831
832         IOCINIT(data);
833         if (argc != 2)
834                 return CMD_HELP;
835
836         data.ioc_obdo1.o_id = strtoul(argv[1], NULL, 0);
837         data.ioc_obdo1.o_mode = S_IFREG | strtoul(argv[2], NULL, 0);
838         data.ioc_obdo1.o_valid = OBD_MD_FLMODE;
839
840         rc = ioctl(fd, OBD_IOC_SETATTR, &data);
841         if (rc < 0)
842                 fprintf(stderr, "error: %s: %s\n", cmdname(argv[0]),
843                         strerror(rc = errno));
844
845         return rc;
846 }
847
848 int jt_obd_destroy(int argc, char **argv)
849 {
850         struct obd_ioctl_data data;
851         int rc;
852
853         IOCINIT(data);
854         if (argc != 2) {
855                 fprintf(stderr, "usage: %s id\n", cmdname(argv[0]));
856                 return -1;
857         }
858
859         data.ioc_obdo1.o_id = strtoul(argv[1], NULL, 0);
860         data.ioc_obdo1.o_mode = S_IFREG | 0644;
861
862         rc = ioctl(fd, OBD_IOC_DESTROY, &data);
863         if (rc < 0)
864                 fprintf(stderr, "error: %s: %s\n", cmdname(argv[0]),
865                         strerror(rc = errno));
866
867         return rc;
868 }
869
870 int jt_obd_getattr(int argc, char **argv)
871 {
872         struct obd_ioctl_data data;
873         int rc;
874
875         if (argc != 2) 
876                 return CMD_HELP;
877
878         IOCINIT(data);
879         data.ioc_obdo1.o_id = strtoul(argv[1], NULL, 0);
880         /* to help obd filter */
881         data.ioc_obdo1.o_mode = 0100644;
882         data.ioc_obdo1.o_valid = 0xffffffff;
883         printf("%s: object id %Ld\n", cmdname(argv[0]), data.ioc_obdo1.o_id);
884
885         rc = ioctl(fd, OBD_IOC_GETATTR, &data);
886         if (rc) {
887                 fprintf(stderr, "error: %s: %s\n", cmdname(argv[0]),
888                         strerror(rc = errno));
889         } else {
890                 printf("%s: object id %Ld, mode %o\n", cmdname(argv[0]),
891                        data.ioc_obdo1.o_id, data.ioc_obdo1.o_mode);
892         }
893         return rc;
894 }
895
896 int jt_obd_test_getattr(int argc, char **argv)
897 {
898         struct obd_ioctl_data data;
899         struct timeval start, next_time;
900         int i, count, next_count;
901         int verbose;
902         int rc = 0;
903
904         if (argc != 2 && argc != 3)
905                 return CMD_HELP;
906
907         IOCINIT(data);
908         count = strtoul(argv[1], NULL, 0);
909
910         if (argc == 3)
911                 verbose = get_verbose(argv[2]);
912         else
913                 verbose = 1;
914
915         data.ioc_obdo1.o_valid = 0xffffffff;
916         data.ioc_obdo1.o_id = 2;
917         gettimeofday(&start, NULL);
918         next_time.tv_sec = start.tv_sec - verbose;
919         next_time.tv_usec = start.tv_usec;
920         if (verbose != 0)
921                 printf("%s: getting %d attrs (testing only): %s",
922                        cmdname(argv[0]), count, ctime(&start.tv_sec));
923
924         for (i = 1, next_count = verbose; i <= count; i++) {
925                 rc = ioctl(fd, OBD_IOC_GETATTR, &data);
926                 SHMEM_BUMP();
927                 if (rc < 0) {
928                         fprintf(stderr, "error: %s: #%d - %s\n",
929                                 cmdname(argv[0]), i, strerror(rc = errno));
930                         break;
931                 } else {
932                         if (be_verbose
933                             (verbose, &next_time, i, &next_count, count))
934                                 printf("%s: got attr #%d\n", cmdname(argv[0]),
935                                        i);
936                 }
937         }
938
939         if (!rc) {
940                 struct timeval end;
941                 double diff;
942
943                 gettimeofday(&end, NULL);
944
945                 diff = difftime(&end, &start);
946
947                 --i;
948                 if (verbose != 0)
949                         printf("%s: %d attrs in %.4gs (%.4g attr/s): %s",
950                                cmdname(argv[0]), i, diff, (double)i / diff,
951                                ctime(&end.tv_sec));
952         }
953         return rc;
954 }
955
956 int jt_obd_test_brw(int argc, char **argv)
957 {
958         struct obd_ioctl_data data;
959         struct timeval start, next_time;
960         char *bulk, *b;
961         int pages = 1, obdos = 1, count, next_count;
962         int verbose = 1, write = 0, rw;
963         int i, o, p;
964         int len;
965         int rc = 0;
966
967         if (argc < 2 || argc > 6) 
968                 return CMD_HELP;
969
970         count = strtoul(argv[1], NULL, 0);
971
972         if (argc >= 3) {
973                 if (argv[2][0] == 'w' || argv[2][0] == '1')
974                         write = 1;
975                 else if (argv[2][0] == 'r' || argv[2][0] == '0')
976                         write = 0;
977
978                 verbose = get_verbose(argv[3]);
979         }
980
981         if (argc >= 5)
982                 pages = strtoul(argv[4], NULL, 0);
983         if (argc >= 6)
984                 obdos = strtoul(argv[5], NULL, 0);
985
986         if (obdos != 1 && obdos != 2) {
987                 fprintf(stderr, "error: %s: only 1 or 2 obdos supported\n",
988                         cmdname(argv[0]));
989                 return -2;
990         }
991
992         len = pages * PAGE_SIZE;
993
994         bulk = calloc(obdos, len);
995         if (!bulk) {
996                 fprintf(stderr, "error: %s: no memory allocating %dx%d pages\n",
997                         cmdname(argv[0]), obdos, pages);
998                 return -2;
999         }
1000         IOCINIT(data);
1001         data.ioc_obdo1.o_id = 2;
1002         data.ioc_count = len;
1003         data.ioc_offset = 0;
1004         data.ioc_plen1 = len;
1005         data.ioc_pbuf1 = bulk;
1006         if (obdos > 1) {
1007                 data.ioc_obdo2.o_id = 3;
1008                 data.ioc_plen2 = len;
1009                 data.ioc_pbuf2 = bulk + len;
1010         }
1011
1012         gettimeofday(&start, NULL);
1013         next_time.tv_sec = start.tv_sec - verbose;
1014         next_time.tv_usec = start.tv_usec;
1015
1016         if (verbose != 0)
1017                 printf("%s: %s %d (%dx%d pages) (testing only): %s",
1018                        cmdname(argv[0]), write ? "writing" : "reading",
1019                        count, obdos, pages, ctime(&start.tv_sec));
1020
1021         /*
1022          * We will put in the start time (and loop count inside the loop)
1023          * at the beginning of each page so that we will be able to validate
1024          * (at some later time) whether the data actually made it or not.
1025          *
1026          * XXX we do not currently use any of this memory in OBD_IOC_BRW_*
1027          *     just to avoid the overhead of the copy_{to,from}_user.  It
1028          *     can be fixed if we ever need to send real data around.
1029          */
1030         for (o = 0, b = bulk; o < obdos; o++)
1031                 for (p = 0; p < pages; p++, b += PAGE_SIZE)
1032                         memcpy(b, &start, sizeof(start));
1033
1034         rw = write ? OBD_IOC_BRW_WRITE : OBD_IOC_BRW_READ;
1035         for (i = 1, next_count = verbose; i <= count; i++) {
1036                 if (write) {
1037                         b = bulk + sizeof(struct timeval);
1038                         for (o = 0; o < obdos; o++)
1039                                 for (p = 0; p < pages; p++, b += PAGE_SIZE)
1040                                         memcpy(b, &count, sizeof(count));
1041                 }
1042
1043                 rc = ioctl(fd, rw, &data);
1044                 SHMEM_BUMP();
1045                 if (rc) {
1046                         fprintf(stderr, "error: %s: #%d - %s on %s\n",
1047                                 cmdname(argv[0]), i, strerror(rc = errno),
1048                                 write ? "write" : "read");
1049                         break;
1050                 } else if (be_verbose
1051                            (verbose, &next_time, i, &next_count, count))
1052                         printf("%s: %s number %d\n", cmdname(argv[0]),
1053                                write ? "write" : "read", i);
1054         }
1055
1056         free(bulk);
1057
1058         if (!rc) {
1059                 struct timeval end;
1060                 double diff;
1061
1062                 gettimeofday(&end, NULL);
1063
1064                 diff = difftime(&end, &start);
1065
1066                 --i;
1067                 if (verbose != 0)
1068                         printf("%s: %s %dx%dx%d pages in %.4gs (%.4g pg/s): %s",
1069                                cmdname(argv[0]), write ? "wrote" : "read",
1070                                obdos, pages, i, diff,
1071                                (double)obdos * i * pages / diff,
1072                                ctime(&end.tv_sec));
1073         }
1074         return rc;
1075 }
1076
1077 int jt_obd_lov_config(int argc, char **argv)
1078 {
1079         struct obd_ioctl_data data;
1080         struct lov_desc desc;
1081         uuid_t *uuidarray;
1082         int rc, size, i;
1083         IOCINIT(data);
1084
1085         printf("WARNING: obdctl lovconfig NOT MAINTAINED\n");
1086         return -1;
1087
1088         if (argc <= 6)
1089                 return CMD_HELP;
1090
1091         if (strlen(argv[1]) > sizeof(uuid_t) - 1) {
1092                 fprintf(stderr, "lov_config: no %dB memory for uuid's\n",
1093                         strlen(argv[1]));
1094                 return -ENOMEM;
1095         }
1096
1097         memset(&desc, 0, sizeof(desc));
1098         strcpy(desc.ld_uuid, argv[1]);
1099         desc.ld_default_stripe_count = strtoul(argv[2], NULL, 0);
1100         desc.ld_default_stripe_size = strtoul(argv[3], NULL, 0);
1101         desc.ld_default_stripe_offset = (__u64) strtoul(argv[4], NULL, 0); 
1102         desc.ld_pattern = strtoul(argv[5], NULL, 0);
1103         desc.ld_tgt_count = argc - 6;
1104
1105
1106         size = sizeof(uuid_t) * desc.ld_tgt_count;
1107         uuidarray = malloc(size);
1108         if (!uuidarray) {
1109                 fprintf(stderr, "lov_config: no %dB memory for uuid's\n", size);
1110                 return -ENOMEM;
1111         }
1112         memset(uuidarray, 0, size);
1113         for (i = 6; i < argc; i++) {
1114                 char *buf = (char *)(uuidarray + i - 6);
1115                 if (strlen(argv[i]) >= sizeof(uuid_t)) {
1116                         fprintf(stderr, "lov_config: arg %d (%s) too long\n",
1117                                 i, argv[i]);
1118                         free(uuidarray);
1119                         return -EINVAL;
1120                 }
1121                 strcpy(buf, argv[i]);
1122         }
1123
1124         data.ioc_inllen1 = sizeof(desc);
1125         data.ioc_inlbuf1 = (char *)&desc;
1126         data.ioc_inllen2 = size;
1127         data.ioc_inlbuf2 = (char *)uuidarray;
1128
1129         if (obd_ioctl_pack(&data, &buf, max)) {
1130                 fprintf(stderr, "error: %s: invalid ioctl\n", cmdname(argv[0]));
1131                 return -EINVAL;
1132         }
1133
1134         rc = ioctl(fd, OBD_IOC_LOV_CONFIG, buf);
1135         if (rc < 0)
1136                 fprintf(stderr, "lov_config: error: %s: %s\n",
1137                         cmdname(argv[0]), strerror(rc = errno));
1138         free(uuidarray);
1139         return rc;
1140 }
1141
1142 int jt_obd_test_ldlm(int argc, char **argv)
1143 {
1144         struct obd_ioctl_data data;
1145         int rc;
1146
1147         IOCINIT(data);
1148         if (argc != 1) 
1149                 return CMD_HELP;
1150
1151         rc = ioctl(fd, IOC_LDLM_TEST, &data);
1152         if (rc)
1153                 fprintf(stderr, "error: %s: test failed: %s\n",
1154                         cmdname(argv[0]), strerror(rc = errno));
1155         return rc;
1156 }
1157
1158 int jt_obd_dump_ldlm(int argc, char **argv)
1159 {
1160         struct obd_ioctl_data data;
1161         int rc;
1162
1163         IOCINIT(data);
1164         if (argc != 1) {
1165                 fprintf(stderr, "usage: %s\n", cmdname(argv[0]));
1166                 return 1;
1167         }
1168
1169         rc = ioctl(fd, IOC_LDLM_DUMP, &data);
1170         if (rc)
1171                 fprintf(stderr, "error: %s failed: %s\n",
1172                         cmdname(argv[0]), strerror(rc = errno));
1173         return rc;
1174 }
1175
1176 int jt_obd_newconn(int argc, char **argv)
1177 {
1178         int rc;
1179         struct obd_ioctl_data data;
1180
1181         IOCINIT(data);
1182         if (argc != 1) 
1183                 return CMD_HELP;
1184
1185         rc = ioctl(fd, OBD_IOC_RECOVD_NEWCONN, &data);
1186         if (rc < 0)
1187                 fprintf(stderr, "error: %s: %s\n", cmdname(argv[0]),
1188                         strerror(rc = errno));
1189
1190         return rc;
1191 }
1192
1193 static void signal_server(int sig)
1194 {
1195         if (sig == SIGINT) {
1196                 do_disconnect("sigint", 1);
1197                 exit(1);
1198         } else
1199                 fprintf(stderr, "%s: got signal %d\n", cmdname("sigint"), sig);
1200 }
1201
1202 int obd_initialize(int argc, char **argv) 
1203 {
1204         SHMEM_SETUP();
1205         return 0;
1206 }
1207
1208
1209 void obd_cleanup(int argc, char **argv) 
1210 {
1211         struct sigaction sigact;
1212
1213         sigact.sa_handler = signal_server;
1214         sigfillset(&sigact.sa_mask);
1215         sigact.sa_flags = SA_RESTART;
1216         sigaction(SIGINT, &sigact, NULL);
1217
1218         do_disconnect(argv[0], 1);
1219 }