Whamcloud - gitweb
- Grammatical, LDLM updates to network.lyx
[fs/lustre-release.git] / lustre / utils / obdctl.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  *
8  *   This file is part of Lustre, http://www.lustre.org.
9  *
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.
13  *
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.
18  *
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.
22  *
23  */
24
25
26 #include <stdlib.h>
27 #include <sys/ioctl.h>
28 #include <fcntl.h>
29 #include <sys/socket.h>
30 #include <sys/types.h>
31 #include <sys/wait.h>
32 #include <sys/stat.h>
33 #include <stdio.h>
34 #include <stdarg.h>
35 #include <signal.h>
36 #define printk printf
37
38 #include <linux/lustre_lib.h>
39 #include <linux/lustre_idl.h>
40 #include <linux/lustre_dlm.h>
41
42 #include <libxml/xmlmemory.h>
43 #include <libxml/parser.h>
44
45 #include <unistd.h>
46 #include <sys/un.h>
47 #include <time.h>
48 #include <sys/time.h>
49 #include <netinet/in.h>
50 #include <errno.h>
51 #include <string.h>
52
53 #include <asm/page.h>           /* needed for PAGE_SIZE - rread */
54
55 #define __KERNEL__
56 #include <linux/list.h>
57 #undef __KERNEL__
58
59 #include "parser.h"
60 #include <stdio.h>
61
62 #define SHMEM_STATS 1
63 #if SHMEM_STATS
64 # include <sys/ipc.h>
65 # include <sys/shm.h>
66
67 # define MAX_SHMEM_COUNT 1024
68 static long long *shared_counters;
69 static long long counter_snapshot[2][MAX_SHMEM_COUNT];
70 struct timeval prev_time;
71 #endif
72
73 static int jt_newdev(int argc, char **argv);
74 static int jt_attach(int argc, char **argv);
75 static int jt_setup(int argc, char **argv);
76
77
78 int fd = -1;
79 uint64_t conn_addr = -1;
80 uint64_t conn_cookie;
81 char rawbuf[8192];
82 char *buf = rawbuf;
83 int max = 8192;
84 int thread;
85 int rc = 0;
86
87 #define IOCINIT(data)                                                   \
88 do {                                                                    \
89         memset(&data, 0, sizeof(data));                                 \
90         data.ioc_version = OBD_IOCTL_VERSION;                           \
91         data.ioc_addr = conn_addr;                                      \
92         data.ioc_cookie = conn_cookie;                                  \
93         data.ioc_len = sizeof(data);                                    \
94         if (fd < 0) {                                                   \
95                 fprintf(stderr, "No device open, use device\n");        \
96                 return 1;                                               \
97         }                                                               \
98 } while (0)
99
100 /*
101     pack "LL LL LL LL LL LL LL L L L L L L L L L a60 a60 L L L",
102     $obdo->{id}, 0,
103     $obdo->{gr}, 0,
104     $obdo->{atime}, 0,
105     $obdo->{mtime}, 0 ,
106     $obdo->{ctime}, 0,
107     $obdo->{size}, 0,
108     $obdo->{blocks}, 0,
109     $obdo->{blksize},
110     $obdo->{mode},
111     $obdo->{uid},
112     $obdo->{gid},
113     $obdo->{flags},
114     $obdo->{obdflags},
115     $obdo->{nlink},
116     $obdo->{generation},
117     $obdo->{valid},
118     $obdo->{inline},
119     $obdo->{obdmd},
120     0, 0, # struct list_head
121     0;  #  struct obd_ops
122 }
123
124 */
125
126 char *obdo_print(struct obdo *obd)
127 {
128         char buf[1024];
129
130         sprintf(buf, "id: %Ld\ngrp: %Ld\natime: %Ld\nmtime: %Ld\nctime: %Ld\n"
131                 "size: %Ld\nblocks: %Ld\nblksize: %d\nmode: %o\nuid: %d\n"
132                 "gid: %d\nflags: %x\nobdflags: %x\nnlink: %d,\nvalid %x\n",
133                 obd->o_id,
134                 obd->o_gr,
135                 obd->o_atime,
136                 obd->o_mtime,
137                 obd->o_ctime,
138                 obd->o_size,
139                 obd->o_blocks,
140                 obd->o_blksize,
141                 obd->o_mode,
142                 obd->o_uid,
143                 obd->o_gid,
144                 obd->o_flags, obd->o_obdflags, obd->o_nlink, obd->o_valid);
145         return strdup(buf);
146 }
147
148 static char *cmdname(char *func)
149 {
150         static char buf[512];
151
152         if (thread) {
153                 sprintf(buf, "%s-%d", func, thread);
154                 return buf;
155         }
156
157         return func;
158 }
159
160 int getfd(char *func)
161 {
162         if (fd == -1)
163                 fd = open("/dev/obd", O_RDWR);
164         if (fd == -1) {
165                 fprintf(stderr, "error: %s: opening /dev/obd: %s\n",
166                         cmdname(func), strerror(errno));
167                 return -1;
168         }
169         return 0;
170 }
171
172 #define difftime(a, b)                                          \
173         ((double)(a)->tv_sec - (b)->tv_sec +                    \
174          ((double)((a)->tv_usec - (b)->tv_usec) / 1000000))
175
176 static int be_verbose(int verbose, struct timeval *next_time,
177                       int num, int *next_num, int num_total)
178 {
179         struct timeval now;
180
181         if (!verbose)
182                 return 0;
183
184         if (next_time != NULL)
185                 gettimeofday(&now, NULL);
186
187         /* A positive verbosity means to print every X iterations */
188         if (verbose > 0 &&
189             (next_num == NULL || num >= *next_num || num >= num_total)) {
190                 *next_num += verbose;
191                 if (next_time) {
192                         next_time->tv_sec = now.tv_sec - verbose;
193                         next_time->tv_usec = now.tv_usec;
194                 }
195                 return 1;
196         }
197
198         /* A negative verbosity means to print at most each X seconds */
199         if (verbose < 0 && next_time != NULL && difftime(&now, next_time) >= 0) {
200                 next_time->tv_sec = now.tv_sec - verbose;
201                 next_time->tv_usec = now.tv_usec;
202                 if (next_num)
203                         *next_num = num;
204                 return 1;
205         }
206
207         return 0;
208 }
209
210 static int get_verbose(const char *arg)
211 {
212         int verbose;
213
214         if (!arg || arg[0] == 'v')
215                 verbose = 1;
216         else if (arg[0] == 's' || arg[0] == 'q')
217                 verbose = 0;
218         else
219                 verbose = (int)strtoul(arg, NULL, 0);
220
221         if (verbose < 0)
222                 printf("Print status every %d seconds\n", -verbose);
223         else if (verbose == 1)
224                 printf("Print status every operation\n");
225         else if (verbose > 1)
226                 printf("Print status every %d operations\n", verbose);
227
228         return verbose;
229 }
230
231 static int do_disconnect(char *func, int verbose)
232 {
233         struct obd_ioctl_data data;
234
235         if (conn_addr == -1)
236                 return 0;
237
238         IOCINIT(data);
239
240         rc = ioctl(fd, OBD_IOC_DISCONNECT, &data);
241         if (rc < 0) {
242                 fprintf(stderr, "error: %s: %x %s\n", cmdname(func),
243                         OBD_IOC_DISCONNECT, strerror(errno));
244         } else {
245                 if (verbose)
246                         printf("%s: disconnected conn %Lx\n", cmdname(func),
247                                conn_addr);
248                 conn_addr = -1;
249         }
250
251         return rc;
252 }
253
254 #if SHMEM_STATS
255 static void shmem_setup(void)
256 {
257         int shmid = shmget(IPC_PRIVATE, sizeof(counter_snapshot[0]), 0600);
258
259         if (shmid == -1) {
260                 fprintf(stderr, "Can't create shared memory counters: %s\n",
261                         strerror(errno));
262                 return;
263         }
264
265         shared_counters = (long long *)shmat(shmid, NULL, 0);
266
267         if (shared_counters == (long long *)(-1)) {
268                 fprintf(stderr, "Can't attach shared memory counters: %s\n",
269                         strerror(errno));
270                 shared_counters = NULL;
271                 return;
272         }
273 }
274
275 static inline void shmem_reset(void)
276 {
277         if (shared_counters == NULL)
278                 return;
279
280         memset(shared_counters, 0, sizeof(counter_snapshot[0]));
281         memset(counter_snapshot, 0, sizeof(counter_snapshot));
282         gettimeofday(&prev_time, NULL);
283 }
284
285 static inline void shmem_bump(void)
286 {
287         if (shared_counters == NULL || thread <= 0 || thread > MAX_SHMEM_COUNT)
288                 return;
289
290         shared_counters[thread - 1]++;
291 }
292
293 static void shmem_snap(int n)
294 {
295         struct timeval this_time;
296         int non_zero = 0;
297         long long total = 0;
298         double secs;
299         int i;
300
301         if (shared_counters == NULL || n > MAX_SHMEM_COUNT)
302                 return;
303
304         memcpy(counter_snapshot[1], counter_snapshot[0],
305                n * sizeof(counter_snapshot[0][0]));
306         memcpy(counter_snapshot[0], shared_counters,
307                n * sizeof(counter_snapshot[0][0]));
308         gettimeofday(&this_time, NULL);
309
310         for (i = 0; i < n; i++) {
311                 long long this_count =
312                         counter_snapshot[0][i] - counter_snapshot[1][i];
313
314                 if (this_count != 0) {
315                         non_zero++;
316                         total += this_count;
317                 }
318         }
319
320         secs = (this_time.tv_sec + this_time.tv_usec / 1000000.0) -
321                 (prev_time.tv_sec + prev_time.tv_usec / 1000000.0);
322
323         printf("%d/%d Total: %f/second\n", non_zero, n, total / secs);
324
325         prev_time = this_time;
326 }
327
328 #define SHMEM_SETUP()   shmem_setup()
329 #define SHMEM_RESET()   shmem_reset()
330 #define SHMEM_BUMP()    shmem_bump()
331 #define SHMEM_SNAP(n)   shmem_snap(n)
332 #else
333 #define SHMEM_SETUP()
334 #define SHMEM_RESET()
335 #define SHMEM_BUMP()
336 #define SHMEM_SNAP(n)
337 #endif
338
339 extern command_t cmdlist[];
340
341 static int xml_command(char *cmd, ...)
342 {
343         va_list args;
344         char *arg, *cmds[8];
345         int i = 1, j;
346
347         cmds[0] = cmd;
348         va_start(args, cmd);
349
350         while (((arg = va_arg(args, char *)) != NULL) && (i < 8)) {
351                 cmds[i] = arg;
352                 i++;
353         }
354
355         va_end(args);
356
357         printf("obdctl > ");
358         for (j = 0; j < i; j++)
359                 printf("%s ", cmds[j]);
360
361         printf("\n");
362
363         return Parser_execarg(i, cmds, cmdlist);
364 }
365
366 #if 0
367 static network_t *xml_network(xmlDocPtr doc, xmlNodePtr root)
368 {
369         xmlNodePtr cur = root->xmlChildrenNode;
370         network_t *net;
371
372         if ((net = (network_t *) calloc(1, sizeof(network_t))) == NULL) {
373                 printf("error: unable to malloc network_t\n");
374                 return NULL;
375         }
376
377         net->type = xmlGetProp(root, "type");
378         if (net->type == NULL) {
379                 printf("error: type attrib required (tcp, elan, myrinet)\n");
380                 free(net);
381                 return NULL;
382         }
383
384         while (cur != NULL) {
385                 if (!xmlStrcmp(cur->name, "server"))
386                         net->server = xmlNodeGetContent(cur);
387
388                 if (!xmlStrcmp(cur->name, "port"))
389                         net->port = atoi(xmlNodeGetContent(cur));
390
391                 cur = cur->next;
392         }
393
394         if (net->server == NULL) {
395                 printf("error: <server> tag required\n");
396                 free(net);
397                 return NULL;
398         }
399
400         return net;
401 }
402 #endif
403
404 static int xml_mds(xmlDocPtr doc, xmlNodePtr root,
405                    char *serv_name, char *serv_uuid)
406 {
407         xmlNodePtr cur = root->xmlChildrenNode;
408         char *fstype = NULL, *device = NULL;
409         int rc;
410
411         printf("--- Setting up MDS ---\n");
412         while (cur != NULL) {
413                 if (!xmlStrcmp(cur->name, "fstype"))
414                         fstype = xmlNodeGetContent(cur);
415
416                 if (!xmlStrcmp(cur->name, "device"))
417                         device = xmlNodeGetContent(cur);
418
419                 /* FIXME: Parse the network bits
420                  * if (!xmlStrcmp(cur->name, "network")) {
421                  *       net = xml_network(doc, cur);
422                  *       if (net == NULL)
423                  *               return -1;
424                  * }
425                  * free(net);
426                  */
427                 cur = cur->next;
428         }
429
430         if ((fstype == NULL) || (device == NULL)) {
431                 printf("error: <fstype> and <device> tags required\n");
432                 return -1;
433         }
434
435         if ((rc = xml_command("newdev", NULL)) != 0)
436                 return rc;
437
438         if ((rc =
439              xml_command("attach", "mds", serv_name, serv_uuid, NULL)) != 0)
440                 return rc;
441
442         if ((rc = xml_command("setup", device, fstype, NULL)) != 0)
443                 return rc;
444
445         return 0;
446 }
447
448 static int xml_obd(xmlDocPtr doc, xmlNodePtr root,
449                    char *serv_name, char *serv_uuid)
450 {
451         char *obdtype, *format = NULL, *fstype = NULL, *device = NULL;
452         xmlNodePtr cur = root->xmlChildrenNode;
453         int rc;
454
455         obdtype = xmlGetProp(root, "type");
456         printf("--- Setting up OBD ---\n");
457
458         while (cur != NULL) {
459                 if (!xmlStrcmp(cur->name, "fstype"))
460                         fstype = xmlNodeGetContent(cur);
461
462                 if (!xmlStrcmp(cur->name, "device"))
463                         device = xmlNodeGetContent(cur);
464
465                 if (!xmlStrcmp(cur->name, "autoformat"))
466                         format = xmlNodeGetContent(cur);
467
468                 cur = cur->next;
469         }
470
471         if ((obdtype == NULL) || (fstype == NULL) || (device == NULL)) {
472                 printf("error: 'type' attrib and <fstype> "
473                        "and <device> tags required\n");
474                 return -1;
475         }
476
477         /* FIXME: Building and configuring loopback devices should go here
478          * but is currently unsupported.  You'll have to use the scripts
479          * for now until support is added, or specify a real device.
480          */
481
482         if ((rc = xml_command("newdev", NULL)) != 0)
483                 return rc;
484
485         if ((rc = xml_command("attach", obdtype,
486                               serv_name, serv_uuid, NULL)) != 0)
487                 return rc;
488
489         if ((rc = xml_command("setup", device, fstype, NULL)) != 0)
490                 return rc;
491
492         return 0;
493 }
494
495 static int xml_ost(xmlDocPtr doc, xmlNodePtr root,
496                    char *serv_name, char *serv_uuid)
497 {
498         char *server_name = NULL, *server_uuid = NULL;
499         char *failover_name = NULL, *failover_uuid = NULL;
500         xmlNodePtr cur = root->xmlChildrenNode;
501         int server_num, failover_num, rc;
502
503         printf("--- Setting up OST ---\n");
504         while (cur != NULL) {
505                 if (!xmlStrcmp(cur->name, "server_id")) {
506                         server_num = atoi(xmlGetProp(cur, "num"));
507                         server_name = xmlGetProp(cur, "name");
508                         server_uuid = xmlGetProp(cur, "uuid");
509                 }
510
511                 /* FIXME: Properly handle multiple failover servers */
512                 if (!xmlStrcmp(cur->name, "failover_id")) {
513                         failover_num = atoi(xmlGetProp(cur, "num"));
514                         failover_name = xmlGetProp(cur, "name");
515                         failover_uuid = xmlGetProp(cur, "uuid");
516                 }
517
518                 cur = cur->next;
519         }
520
521         if ((server_name == NULL) || (server_uuid == NULL)) {
522                 printf("error: atleast the <server_id> tag is required\n");
523                 return -1;
524         }
525
526         if ((rc = xml_command("newdev", NULL)) != 0)
527                 return rc;
528
529         if ((rc =
530              xml_command("attach", "ost", serv_name, serv_uuid, NULL)) != 0)
531                 return rc;
532
533         if ((rc = xml_command("setup", server_name, NULL)) != 0)
534                 return rc;
535
536         return 0;
537 }
538
539 static int xml_osc(xmlDocPtr doc, xmlNodePtr root,
540                    char *serv_name, char *serv_uuid)
541 {
542         char *ost_name = NULL, *ost_uuid = NULL;
543         xmlNodePtr cur = root->xmlChildrenNode;
544         int ost_num, rc = 0;
545
546         printf("--- Setting up OSC ---\n");
547         while (cur != NULL) {
548                 if (!xmlStrcmp(cur->name, "service_id")) {
549                         ost_num = atoi(xmlGetProp(cur, "num"));
550                         ost_name = xmlGetProp(cur, "name");
551                         ost_uuid = xmlGetProp(cur, "uuid");
552                 }
553
554                 cur = cur->next;
555         }
556
557         if ((ost_name == NULL) || (ost_uuid == NULL)) {
558                 printf("error: atleast the <service_id> tag is required\n");
559                 return -1;
560         }
561
562         if ((rc = xml_command("newdev", NULL)) != 0)
563                 return rc;
564
565         if ((rc =
566              xml_command("attach", "osc", serv_name, serv_uuid, NULL)) != 0)
567                 return rc;
568
569         if ((rc = xml_command("setup", ost_uuid, "localhost", NULL)) != 0)
570                 return rc;
571
572         return 0;
573 }
574
575 static int xml_mdc(xmlDocPtr doc, xmlNodePtr root,
576                    char *serv_name, char *serv_uuid)
577 {
578         char *mds_name = NULL, *mds_uuid = NULL;
579         xmlNodePtr cur = root->xmlChildrenNode;
580         int mds_num, rc = 0;
581
582         printf("--- Setting up MDC ---\n");
583         while (cur != NULL) {
584                 if (!xmlStrcmp(cur->name, "service_id")) {
585                         mds_num = atoi(xmlGetProp(cur, "num"));
586                         mds_name = xmlGetProp(cur, "name");
587                         mds_uuid = xmlGetProp(cur, "uuid");
588                 }
589
590                 cur = cur->next;
591         }
592
593         if ((mds_name == NULL) || (mds_uuid == NULL)) {
594                 printf("error: atleast the <service_id> tag is required\n");
595                 return -1;
596         }
597
598         if ((rc = xml_command("newdev", NULL)) != 0)
599                 return rc;
600
601         if ((rc =
602              xml_command("attach", "mdc", serv_name, serv_uuid, NULL)) != 0)
603                 return rc;
604
605         if ((rc = xml_command("setup", mds_uuid, "localhost", NULL)) != 0)
606                 return rc;
607
608         return 0;
609 }
610
611 static int xml_lov(xmlDocPtr doc, xmlNodePtr root,
612                    char *serv_name, char *serv_uuid)
613 {
614         printf("--- Setting up LOV ---\n");
615         return 0;
616 }
617
618 static int xml_router(xmlDocPtr doc, xmlNodePtr root,
619                       char *serv_name, char *serv_uuid)
620 {
621         printf("--- Setting up ROUTER ---\n");
622         return 0;
623 }
624
625 static int xml_ldlm(xmlDocPtr doc, xmlNodePtr root,
626                     char *serv_name, char *serv_uuid)
627 {
628         int rc;
629
630         printf("--- Setting up LDLM ---\n");
631         if ((rc = xml_command("newdev", NULL)) != 0)
632                 return rc;
633
634         if ((rc =
635              xml_command("attach", "ldlm", serv_name, serv_uuid, NULL)) != 0)
636                 return rc;
637
638         if ((rc = xml_command("setup", NULL)) != 0)
639                 return rc;
640
641         return 0;
642 }
643
644 static int xml_service(xmlDocPtr doc, xmlNodePtr root,
645                        int serv_num, char *serv_name, char *serv_uuid)
646 {
647         xmlNodePtr cur = root;
648         char *name, *uuid;
649
650         while (cur != NULL) {
651                 name = xmlGetProp(cur, "name");
652                 uuid = xmlGetProp(cur, "uuid");
653
654                 if (xmlStrcmp(name, serv_name) || xmlStrcmp(uuid, serv_uuid)) {
655                         cur = cur->next;
656                         continue;
657                 }
658
659                 if (!xmlStrcmp(cur->name, "mds"))
660                         return xml_mds(doc, cur, name, uuid);
661                 else if (!xmlStrcmp(cur->name, "obd"))
662                         return xml_obd(doc, cur, name, uuid);
663                 else if (!xmlStrcmp(cur->name, "ost"))
664                         return xml_ost(doc, cur, name, uuid);
665                 else if (!xmlStrcmp(cur->name, "osc"))
666                         return xml_osc(doc, cur, name, uuid);
667                 else if (!xmlStrcmp(cur->name, "mdc"))
668                         return xml_mdc(doc, cur, name, uuid);
669                 else if (!xmlStrcmp(cur->name, "lov"))
670                         return xml_lov(doc, cur, name, uuid);
671                 else if (!xmlStrcmp(cur->name, "router"))
672                         return xml_router(doc, cur, name, uuid);
673                 else if (!xmlStrcmp(cur->name, "ldlm"))
674                         return xml_ldlm(doc, cur, name, uuid);
675                 else
676                         return -1;
677
678                 cur = cur->next;
679         }
680
681         printf("error: No XML config branch for name=%s uuid=%s\n",
682                serv_name, serv_uuid);
683         return -1;
684 }
685
686 static int xml_profile(xmlDocPtr doc, xmlNodePtr root,
687                        int prof_num, char *prof_name, char *prof_uuid)
688 {
689         xmlNodePtr parent, cur = root;
690         char *name, *uuid, *srv_name, *srv_uuid;
691         int rc = 0, num;
692
693         while (cur != NULL) {
694                 name = xmlGetProp(cur, "name");
695                 uuid = xmlGetProp(cur, "uuid");
696
697                 if (xmlStrcmp(cur->name, "profile") ||
698                     xmlStrcmp(name, prof_name) || xmlStrcmp(uuid, prof_uuid)) {
699                         cur = cur->next;
700                         continue;
701                 }
702
703                 /* FIXME: Doesn't understand mountpoints yet
704                  *        xml_mountpoint(doc, root, ...);
705                  */
706
707                 /* Setup each service in turn
708                  * FIXME: Should be sorted by "num" attr, we shouldn't
709                  *        assume they're in order in the XML document.
710                  */
711                 parent = cur;
712                 cur = cur->xmlChildrenNode;
713                 while (cur != NULL) {
714                         if (!xmlStrcmp(cur->name, "service_id")) {
715                                 num = atoi(xmlGetProp(cur, "num"));
716                                 rc = xml_service(doc, root, num,
717                                                  srv_name =
718                                                  xmlGetProp(cur, "name"),
719                                                  srv_uuid =
720                                                  xmlGetProp(cur, "uuid"));
721                                 if (rc != 0) {
722                                         printf("error: service config\n");
723                                         return rc;
724                                 }
725                         }
726
727                         cur = cur->next;
728                 }
729
730                 cur = parent->next;
731         }
732
733         return rc;
734 }
735
736 static int xml_node(xmlDocPtr doc, xmlNodePtr root)
737 {
738         xmlNodePtr parent, cur = root;
739         char *name, *uuid;
740         int rc = 0, num;
741
742         /* Walk the node tags looking for ours */
743         while (cur != NULL) {
744                 if (xmlStrcmp(cur->name, "node")) {
745                         cur = cur->next;
746                         continue;
747                 }
748
749                 name = xmlGetProp(cur, "name");
750                 if (name == NULL)
751                         return -1;
752
753                 uuid = xmlGetProp(cur, "uuid");
754                 if (uuid == NULL)
755                         return -1;
756
757                 /* FIXME: Verify our NAME and UUID against /etc/lustre/id
758                  *        so we're sure we are who we think we are.
759                  */
760
761                 /* Setup each profile in turn
762                  * FIXME: Should be sorted by "num" attr, we shouldn't
763                  *        assume they're in order in the XML document.
764                  */
765                 parent = cur;
766                 cur = cur->xmlChildrenNode;
767                 while (cur != NULL) {
768                         if (!xmlStrcmp(cur->name, "profile_id")) {
769                                 num = atoi(xmlGetProp(cur, "num"));
770                                 rc = xml_profile(doc, root, num,
771                                                  xmlGetProp(cur, "name"),
772                                                  xmlGetProp(cur, "uuid"));
773                                 if (rc != 0)
774                                         return rc;
775                         }
776
777                         cur = cur->next;
778                 }
779
780                 cur = parent->next;
781         }
782
783         return rc;
784 }
785
786 static int do_xml(char *func, char *file)
787 {
788         xmlDocPtr doc;
789         xmlNodePtr cur;
790         int rc;
791
792         doc = xmlParseFile(file);
793         if (doc == NULL) {
794                 fprintf(stderr, "error: Unable to parse XML\n");
795                 return -1;
796         }
797
798         cur = xmlDocGetRootElement(doc);
799         if (cur == NULL) {
800                 fprintf(stderr, "error: Empty XML\n");
801                 xmlFreeDoc(doc);
802                 return -1;
803         }
804
805         if (xmlStrcmp(cur->name, (const xmlChar *)"lustre")) {
806                 fprintf(stderr, "error: Root node != <lustre>\n");
807                 xmlFreeDoc(doc);
808                 return -1;
809         }
810
811         /* FIXME: Validate the XML against the DTD here */
812
813         /* FIXME: Merge all the text nodes under each branch and 
814          *        prune empty nodes.  Just to make the parsing more
815          *        tolerant, the exact location of nested tags isn't
816          *        critical for this.
817          */
818
819         rc = xml_node(doc, cur->xmlChildrenNode);
820         xmlFreeDoc(doc);
821
822         return rc;
823 }
824
825 static int do_device(char *func, int dev)
826 {
827         struct obd_ioctl_data data;
828
829         memset(&data, 0, sizeof(data));
830
831         data.ioc_dev = dev;
832
833         if (getfd(func))
834                 return -1;
835
836         if (obd_ioctl_pack(&data, &buf, max)) {
837                 fprintf(stderr, "error: %s: invalid ioctl\n", cmdname(func));
838                 return -2;
839         }
840
841         return ioctl(fd, OBD_IOC_DEVICE, buf);
842 }
843
844 static int jt_device(int argc, char **argv)
845 {
846         do_disconnect(argv[0], 1);
847
848         if (argc != 2) {
849                 fprintf(stderr, "usage: %s devno\n", cmdname(argv[0]));
850                 return -1;
851         }
852
853         rc = do_device(argv[0], strtoul(argv[1], NULL, 0));
854
855         if (rc < 0)
856                 fprintf(stderr, "error: %s: %s\n", cmdname(argv[0]),
857                         strerror(rc = errno));
858
859         return rc;
860 }
861
862 static int jt_connect(int argc, char **argv)
863 {
864         struct obd_ioctl_data data;
865
866         IOCINIT(data);
867
868         do_disconnect(argv[0], 1);
869
870         if (argc != 1) {
871                 fprintf(stderr, "usage: %s\n", cmdname(argv[0]));
872                 return -1;
873         }
874
875         rc = ioctl(fd, OBD_IOC_CONNECT, &data);
876         if (rc < 0)
877                 fprintf(stderr, "error: %s: %x %s\n", cmdname(argv[0]),
878                         OBD_IOC_CONNECT, strerror(rc = errno));
879         else
880                 conn_addr = data.ioc_addr;
881         conn_cookie = data.ioc_cookie;
882         return rc;
883 }
884
885 static int jt_disconnect(int argc, char **argv)
886 {
887         if (argc != 1) {
888                 fprintf(stderr, "usage: %s\n", cmdname(argv[0]));
889                 return -1;
890         }
891
892         if (conn_addr == -1)
893                 return 0;
894
895         return do_disconnect(argv[0], 0);
896 }
897
898 static int jt__xml(int argc, char **argv)
899 {
900         if (argc < 2) {
901                 fprintf(stderr, "usage: %s <xml file> <command [args ...]>\n",
902                         cmdname(argv[0]));
903                 return -1;
904         }
905
906         return do_xml("xml", argv[1]);
907 }
908
909 static int jt__device(int argc, char **argv)
910 {
911         char *arg2[3];
912         int ret;
913
914         if (argc < 3) {
915                 fprintf(stderr, "usage: %s devno <command [args ...]>\n",
916                         cmdname(argv[0]));
917                 return -1;
918         }
919
920         rc = do_device("device", strtoul(argv[1], NULL, 0));
921
922         if (!rc) {
923                 arg2[0] = "connect";
924                 arg2[1] = NULL;
925                 rc = jt_connect(1, arg2);
926         }
927
928         if (!rc)
929                 rc = Parser_execarg(argc - 2, argv + 2, cmdlist);
930
931         ret = do_disconnect(argv[0], 0);
932         if (!rc)
933                 rc = ret;
934
935         return rc;
936 }
937
938 static int jt__threads(int argc, char **argv)
939 {
940         int threads, next_thread;
941         int verbose;
942         int i;
943
944         if (argc < 5) {
945                 fprintf(stderr,
946                         "usage: %s numthreads verbose devno <cmd [args ...]>\n",
947                         argv[0]);
948                 return -1;
949         }
950
951         threads = strtoul(argv[1], NULL, 0);
952
953         verbose = get_verbose(argv[2]);
954
955         if (verbose != 0)
956                 printf("%s: starting %d threads on device %s running %s\n",
957                        argv[0], threads, argv[3], argv[4]);
958
959         SHMEM_RESET();
960
961         for (i = 1, next_thread = verbose; i <= threads; i++) {
962                 rc = fork();
963                 if (rc < 0) {
964                         fprintf(stderr, "error: %s: #%d - %s\n", argv[0], i,
965                                 strerror(rc = errno));
966                         break;
967                 } else if (rc == 0) {
968                         thread = i;
969                         argv[2] = "--device";
970                         return jt__device(argc - 2, argv + 2);
971                 } else if (be_verbose(verbose, NULL, i, &next_thread, threads))
972                         printf("%s: thread #%d (PID %d) started\n",
973                                argv[0], i, rc);
974                 rc = 0;
975         }
976
977         if (!thread) {          /* parent process */
978                 int live_threads = threads;
979
980                 while (live_threads > 0) {
981                         int status;
982                         pid_t ret;
983
984                         ret = waitpid(0, &status, verbose < 0 ? WNOHANG : 0);
985                         if (ret == 0) {
986                                 if (verbose >= 0)
987                                         abort();
988
989                                 sleep(-verbose);
990                                 SHMEM_SNAP(threads);
991                                 continue;
992                         }
993
994                         if (ret < 0) {
995                                 fprintf(stderr, "error: %s: wait - %s\n",
996                                         argv[0], strerror(errno));
997                                 if (!rc)
998                                         rc = errno;
999                         } else {
1000                                 /*
1001                                  * This is a hack.  We _should_ be able to use
1002                                  * WIFEXITED(status) to see if there was an
1003                                  * error, but it appears to be broken and it
1004                                  * always returns 1 (OK).  See wait(2).
1005                                  */
1006                                 int err = WEXITSTATUS(status);
1007                                 if (err)
1008                                         fprintf(stderr,
1009                                                 "%s: PID %d had rc=%d\n",
1010                                                 argv[0], ret, err);
1011                                 if (!rc)
1012                                         rc = err;
1013
1014                                 live_threads--;
1015                         }
1016                 }
1017         }
1018
1019         return rc;
1020 }
1021
1022 static int jt_detach(int argc, char **argv)
1023 {
1024         struct obd_ioctl_data data;
1025
1026         IOCINIT(data);
1027
1028         if (argc != 1) {
1029                 fprintf(stderr, "usage: %s\n", cmdname(argv[0]));
1030                 return -1;
1031         }
1032
1033         if (obd_ioctl_pack(&data, &buf, max)) {
1034                 fprintf(stderr, "error: %s: invalid ioctl\n", cmdname(argv[0]));
1035                 return -2;
1036         }
1037
1038         rc = ioctl(fd, OBD_IOC_DETACH, buf);
1039         if (rc < 0)
1040                 fprintf(stderr, "error: %s: %s\n", cmdname(argv[0]),
1041                         strerror(rc = errno));
1042
1043         return rc;
1044 }
1045
1046 static int jt_cleanup(int argc, char **argv)
1047 {
1048         struct obd_ioctl_data data;
1049
1050         IOCINIT(data);
1051
1052         if (argc != 1) {
1053                 fprintf(stderr, "usage: %s\n", cmdname(argv[0]));
1054                 return -1;
1055         }
1056
1057         rc = ioctl(fd, OBD_IOC_CLEANUP, &data);
1058         if (rc < 0)
1059                 fprintf(stderr, "error: %s: %s\n", cmdname(argv[0]),
1060                         strerror(rc = errno));
1061
1062         return rc;
1063 }
1064
1065 static int jt_newdev(int argc, char **argv)
1066 {
1067         struct obd_ioctl_data data;
1068
1069         if (getfd(argv[0]))
1070                 return -1;
1071
1072         IOCINIT(data);
1073
1074         if (argc != 1) {
1075                 fprintf(stderr, "usage: %s\n", cmdname(argv[0]));
1076                 return -1;
1077         }
1078
1079         rc = ioctl(fd, OBD_IOC_NEWDEV, &data);
1080         if (rc < 0)
1081                 fprintf(stderr, "error: %s: %s\n", cmdname(argv[0]),
1082                         strerror(rc = errno));
1083         else {
1084                 printf("Current device set to %d\n", data.ioc_dev);
1085         }
1086
1087         return rc;
1088 }
1089
1090 static int jt_list(int argc, char **argv)
1091 {
1092         char buf[1024];
1093         struct obd_ioctl_data *data = (struct obd_ioctl_data *)buf;
1094
1095         if (getfd(argv[0]))
1096                 return -1;
1097
1098         memset(buf, 0, sizeof(buf));
1099         data->ioc_version = OBD_IOCTL_VERSION;
1100         data->ioc_addr = conn_addr;
1101         data->ioc_cookie = conn_addr;
1102         data->ioc_len = sizeof(buf);
1103         data->ioc_inllen1 = sizeof(buf) - size_round(sizeof(*data));
1104
1105         if (argc != 1) {
1106                 fprintf(stderr, "usage: %s\n", cmdname(argv[0]));
1107                 return -1;
1108         }
1109
1110         rc = ioctl(fd, OBD_IOC_LIST, data);
1111         if (rc < 0)
1112                 fprintf(stderr, "error: %s: %s\n", cmdname(argv[0]),
1113                         strerror(rc = errno));
1114         else {
1115                 printf("%s", data->ioc_bulk);
1116         }
1117
1118         return rc;
1119 }
1120
1121 static int jt_attach(int argc, char **argv)
1122 {
1123         struct obd_ioctl_data data;
1124
1125         IOCINIT(data);
1126
1127         if (argc != 2 && argc != 3 && argc != 4) {
1128                 fprintf(stderr, "usage: %s type [name [uuid]]\n",
1129                         cmdname(argv[0]));
1130                 return -1;
1131         }
1132
1133         data.ioc_inllen1 = strlen(argv[1]) + 1;
1134         data.ioc_inlbuf1 = argv[1];
1135         if (argc >= 3) {
1136                 data.ioc_inllen2 = strlen(argv[2]) + 1;
1137                 data.ioc_inlbuf2 = argv[2];
1138         }
1139
1140         if (argc == 4) {
1141                 data.ioc_inllen3 = strlen(argv[3]) + 1;
1142                 data.ioc_inlbuf3 = argv[3];
1143         }
1144
1145         if (obd_ioctl_pack(&data, &buf, max)) {
1146                 fprintf(stderr, "error: %s: invalid ioctl\n", cmdname(argv[0]));
1147                 return -2;
1148         }
1149
1150         rc = ioctl(fd, OBD_IOC_ATTACH, buf);
1151         if (rc < 0)
1152                 fprintf(stderr, "error: %s: %x %s\n", cmdname(argv[0]),
1153                         OBD_IOC_ATTACH, strerror(rc = errno));
1154         else if (argc == 3) {
1155                 char name[1024];
1156                 if (strlen(argv[2]) > 128) {
1157                         printf("Name too long to set environment\n");
1158                         return -EINVAL;
1159                 }
1160                 snprintf(name, 512, "LUSTRE_DEV_%s", argv[2]);
1161                 rc = setenv(name, argv[1], 1);
1162                 if (rc) {
1163                         printf("error setting env variable %s\n", name);
1164                 }
1165         }
1166
1167         return rc;
1168 }
1169
1170 #define N2D_OFF 0x100      /* So we can tell between error codes and devices */
1171
1172 static int do_name2dev(char *func, char *name)
1173 {
1174         struct obd_ioctl_data data;
1175
1176         if (getfd(func))
1177                 return -1;
1178
1179         IOCINIT(data);
1180
1181         data.ioc_inllen1 = strlen(name) + 1;
1182         data.ioc_inlbuf1 = name;
1183
1184         if (obd_ioctl_pack(&data, &buf, max)) {
1185                 fprintf(stderr, "error: %s: invalid ioctl\n", cmdname(func));
1186                 return -2;
1187         }
1188         rc = ioctl(fd, OBD_IOC_NAME2DEV, buf);
1189         if (rc < 0) {
1190                 fprintf(stderr, "error: %s: %s - %s\n", cmdname(func),
1191                         name, strerror(rc = errno));
1192                 return rc;
1193         }
1194
1195         memcpy((char *)(&data), buf, sizeof(data));
1196
1197         return data.ioc_dev + N2D_OFF;
1198 }
1199
1200 static int jt_name2dev(int argc, char **argv)
1201 {
1202         if (argc != 2) {
1203                 Parser_printhelp("name2dev");
1204                 return -1;
1205         }
1206
1207         rc = do_name2dev(argv[0], argv[1]);
1208         if (rc >= N2D_OFF) {
1209                 int dev = rc - N2D_OFF;
1210                 rc = do_device(argv[0], dev);
1211                 if (rc == 0)
1212                         printf("%d\n", dev);
1213         }
1214         return rc;
1215 }
1216
1217 static int jt_setup(int argc, char **argv)
1218 {
1219         struct obd_ioctl_data data;
1220
1221         IOCINIT(data);
1222
1223         if (argc > 3) {
1224                 fprintf(stderr, "usage: %s [device] [fstype]\n",
1225                         cmdname(argv[0]));
1226                 return -1;
1227         }
1228
1229         data.ioc_dev = -1;
1230         if (argc > 1) {
1231                 if (argv[1][0] == '$') {
1232                         rc = do_name2dev(argv[0], argv[1] + 1);
1233                         if (rc >= N2D_OFF) {
1234                                 printf("%s is device %d\n", argv[1],
1235                                        rc - N2D_OFF);
1236                                 data.ioc_dev = rc - N2D_OFF;
1237                         }
1238                 } else
1239                         data.ioc_dev = strtoul(argv[1], NULL, 0);
1240                 data.ioc_inllen1 = strlen(argv[1]) + 1;
1241                 data.ioc_inlbuf1 = argv[1];
1242         }
1243         if (argc == 3) {
1244                 data.ioc_inllen2 = strlen(argv[2]) + 1;
1245                 data.ioc_inlbuf2 = argv[2];
1246         }
1247
1248         if (obd_ioctl_pack(&data, &buf, max)) {
1249                 fprintf(stderr, "error: %s: invalid ioctl\n", cmdname(argv[0]));
1250                 return -2;
1251         }
1252         rc = ioctl(fd, OBD_IOC_SETUP, buf);
1253         if (rc < 0)
1254                 fprintf(stderr, "error: %s: %s\n", cmdname(argv[0]),
1255                         strerror(rc = errno));
1256
1257         return rc;
1258 }
1259
1260
1261 static int jt_create(int argc, char **argv)
1262 {
1263         struct obd_ioctl_data data;
1264         struct timeval next_time;
1265         int count = 1, next_count;
1266         int verbose;
1267         int i;
1268
1269         IOCINIT(data);
1270         if (argc < 2 || argc > 4) {
1271                 fprintf(stderr, "usage: %s num [mode] [verbose]\n",
1272                         cmdname(argv[0]));
1273                 return -1;
1274         }
1275         count = strtoul(argv[1], NULL, 0);
1276
1277         if (argc > 2)
1278                 data.ioc_obdo1.o_mode = strtoul(argv[2], NULL, 0);
1279         else
1280                 data.ioc_obdo1.o_mode = 0100644;
1281         data.ioc_obdo1.o_valid = OBD_MD_FLMODE;
1282
1283         verbose = get_verbose(argv[3]);
1284
1285         printf("%s: %d obdos\n", cmdname(argv[0]), count);
1286         gettimeofday(&next_time, NULL);
1287         next_time.tv_sec -= verbose;
1288
1289         for (i = 1, next_count = verbose; i <= count; i++) {
1290                 rc = ioctl(fd, OBD_IOC_CREATE, &data);
1291                 SHMEM_BUMP();
1292                 if (rc < 0) {
1293                         fprintf(stderr, "error: %s: #%d - %s\n",
1294                                 cmdname(argv[0]), i, strerror(rc = errno));
1295                         break;
1296                 }
1297                 if (be_verbose(verbose, &next_time, i, &next_count, count))
1298                         printf("%s: #%d is object id %Ld\n", cmdname(argv[0]),
1299                                i, data.ioc_obdo1.o_id);
1300         }
1301         return rc;
1302 }
1303
1304 static int jt_setattr(int argc, char **argv)
1305 {
1306         struct obd_ioctl_data data;
1307
1308         IOCINIT(data);
1309         if (argc != 2) {
1310                 fprintf(stderr, "usage: %s id mode\n", cmdname(argv[0]));
1311                 return -1;
1312         }
1313
1314         data.ioc_obdo1.o_id = strtoul(argv[1], NULL, 0);
1315         data.ioc_obdo1.o_mode = S_IFREG | strtoul(argv[2], NULL, 0);
1316         data.ioc_obdo1.o_valid = OBD_MD_FLMODE;
1317
1318         rc = ioctl(fd, OBD_IOC_SETATTR, &data);
1319         if (rc < 0)
1320                 fprintf(stderr, "error: %s: %s\n", cmdname(argv[0]),
1321                         strerror(rc = errno));
1322
1323         return rc;
1324 }
1325
1326 static int jt_destroy(int argc, char **argv)
1327 {
1328         struct obd_ioctl_data data;
1329
1330         IOCINIT(data);
1331         if (argc != 2) {
1332                 fprintf(stderr, "usage: %s id\n", cmdname(argv[0]));
1333                 return -1;
1334         }
1335
1336         data.ioc_obdo1.o_id = strtoul(argv[1], NULL, 0);
1337         data.ioc_obdo1.o_mode = S_IFREG | 0644;
1338
1339         rc = ioctl(fd, OBD_IOC_DESTROY, &data);
1340         if (rc < 0)
1341                 fprintf(stderr, "error: %s: %s\n", cmdname(argv[0]),
1342                         strerror(rc = errno));
1343
1344         return rc;
1345 }
1346
1347 static int jt_getattr(int argc, char **argv)
1348 {
1349         struct obd_ioctl_data data;
1350
1351         if (argc != 2) {
1352                 fprintf(stderr, "usage: %s id\n", cmdname(argv[0]));
1353                 return -1;
1354         }
1355
1356         IOCINIT(data);
1357         data.ioc_obdo1.o_id = strtoul(argv[1], NULL, 0);
1358         /* to help obd filter */
1359         data.ioc_obdo1.o_mode = 0100644;
1360         data.ioc_obdo1.o_valid = 0xffffffff;
1361         printf("%s: object id %Ld\n", cmdname(argv[0]), data.ioc_obdo1.o_id);
1362
1363         rc = ioctl(fd, OBD_IOC_GETATTR, &data);
1364         if (rc) {
1365                 fprintf(stderr, "error: %s: %s\n", cmdname(argv[0]),
1366                         strerror(rc = errno));
1367         } else {
1368                 printf("%s: object id %Ld, mode %o\n", cmdname(argv[0]),
1369                        data.ioc_obdo1.o_id, data.ioc_obdo1.o_mode);
1370         }
1371         return rc;
1372 }
1373
1374 static int jt_test_getattr(int argc, char **argv)
1375 {
1376         struct obd_ioctl_data data;
1377         struct timeval start, next_time;
1378         int i, count, next_count;
1379         int verbose;
1380
1381         if (argc != 2 && argc != 3) {
1382                 fprintf(stderr, "usage: %s count [verbose]\n",
1383                         cmdname(argv[0]));
1384                 return -1;
1385         }
1386
1387         IOCINIT(data);
1388         count = strtoul(argv[1], NULL, 0);
1389
1390         if (argc == 3)
1391                 verbose = get_verbose(argv[2]);
1392         else
1393                 verbose = 1;
1394
1395         data.ioc_obdo1.o_valid = 0xffffffff;
1396         data.ioc_obdo1.o_id = 2;
1397         gettimeofday(&start, NULL);
1398         next_time.tv_sec = start.tv_sec - verbose;
1399         next_time.tv_usec = start.tv_usec;
1400         if (verbose != 0)
1401                 printf("%s: getting %d attrs (testing only): %s",
1402                        cmdname(argv[0]), count, ctime(&start.tv_sec));
1403
1404         for (i = 1, next_count = verbose; i <= count; i++) {
1405                 rc = ioctl(fd, OBD_IOC_GETATTR, &data);
1406                 SHMEM_BUMP();
1407                 if (rc < 0) {
1408                         fprintf(stderr, "error: %s: #%d - %s\n",
1409                                 cmdname(argv[0]), i, strerror(rc = errno));
1410                         break;
1411                 } else {
1412                         if (be_verbose
1413                             (verbose, &next_time, i, &next_count, count))
1414                                 printf("%s: got attr #%d\n", cmdname(argv[0]),
1415                                        i);
1416                 }
1417         }
1418
1419         if (!rc) {
1420                 struct timeval end;
1421                 double diff;
1422
1423                 gettimeofday(&end, NULL);
1424
1425                 diff = difftime(&end, &start);
1426
1427                 --i;
1428                 if (verbose != 0)
1429                         printf("%s: %d attrs in %.4gs (%.4g attr/s): %s",
1430                                cmdname(argv[0]), i, diff, (double)i / diff,
1431                                ctime(&end.tv_sec));
1432         }
1433         return rc;
1434 }
1435
1436 static int jt_test_brw(int argc, char **argv)
1437 {
1438         struct obd_ioctl_data data;
1439         struct timeval start, next_time;
1440         char *bulk, *b;
1441         int pages = 1, obdos = 1, count, next_count;
1442         int verbose = 1, write = 0, rw;
1443         int i, o, p;
1444         int len;
1445
1446         if (argc < 2 || argc > 6) {
1447                 fprintf(stderr,
1448                         "usage: %s count [write [verbose [pages [obdos]]]]\n",
1449                         cmdname(argv[0]));
1450                 return -1;
1451         }
1452
1453         count = strtoul(argv[1], NULL, 0);
1454
1455         if (argc >= 3) {
1456                 if (argv[2][0] == 'w' || argv[2][0] == '1')
1457                         write = 1;
1458                 else if (argv[2][0] == 'r' || argv[2][0] == '0')
1459                         write = 0;
1460
1461                 verbose = get_verbose(argv[3]);
1462         }
1463
1464         if (argc >= 5)
1465                 pages = strtoul(argv[4], NULL, 0);
1466         if (argc >= 6)
1467                 obdos = strtoul(argv[5], NULL, 0);
1468
1469         if (obdos != 1 && obdos != 2) {
1470                 fprintf(stderr, "error: %s: only 1 or 2 obdos supported\n",
1471                         cmdname(argv[0]));
1472                 return -2;
1473         }
1474
1475         len = pages * PAGE_SIZE;
1476
1477         bulk = calloc(obdos, len);
1478         if (!bulk) {
1479                 fprintf(stderr, "error: %s: no memory allocating %dx%d pages\n",
1480                         cmdname(argv[0]), obdos, pages);
1481                 return -2;
1482         }
1483         IOCINIT(data);
1484         data.ioc_obdo1.o_id = 2;
1485         data.ioc_count = len;
1486         data.ioc_offset = 0;
1487         data.ioc_plen1 = len;
1488         data.ioc_pbuf1 = bulk;
1489         if (obdos > 1) {
1490                 data.ioc_obdo2.o_id = 3;
1491                 data.ioc_plen2 = len;
1492                 data.ioc_pbuf2 = bulk + len;
1493         }
1494
1495         gettimeofday(&start, NULL);
1496         next_time.tv_sec = start.tv_sec - verbose;
1497         next_time.tv_usec = start.tv_usec;
1498
1499         if (verbose != 0)
1500                 printf("%s: %s %d (%dx%d pages) (testing only): %s",
1501                        cmdname(argv[0]), write ? "writing" : "reading",
1502                        count, obdos, pages, ctime(&start.tv_sec));
1503
1504         /*
1505          * We will put in the start time (and loop count inside the loop)
1506          * at the beginning of each page so that we will be able to validate
1507          * (at some later time) whether the data actually made it or not.
1508          *
1509          * XXX we do not currently use any of this memory in OBD_IOC_BRW_*
1510          *     just to avoid the overhead of the copy_{to,from}_user.  It
1511          *     can be fixed if we ever need to send real data around.
1512          */
1513         for (o = 0, b = bulk; o < obdos; o++)
1514                 for (p = 0; p < pages; p++, b += PAGE_SIZE)
1515                         memcpy(b, &start, sizeof(start));
1516
1517         rw = write ? OBD_IOC_BRW_WRITE : OBD_IOC_BRW_READ;
1518         for (i = 1, next_count = verbose; i <= count; i++) {
1519                 if (write) {
1520                         b = bulk + sizeof(struct timeval);
1521                         for (o = 0; o < obdos; o++)
1522                                 for (p = 0; p < pages; p++, b += PAGE_SIZE)
1523                                         memcpy(b, &count, sizeof(count));
1524                 }
1525
1526                 rc = ioctl(fd, rw, &data);
1527                 SHMEM_BUMP();
1528                 if (rc) {
1529                         fprintf(stderr, "error: %s: #%d - %s on %s\n",
1530                                 cmdname(argv[0]), i, strerror(rc = errno),
1531                                 write ? "write" : "read");
1532                         break;
1533                 } else if (be_verbose
1534                            (verbose, &next_time, i, &next_count, count))
1535                         printf("%s: %s number %d\n", cmdname(argv[0]),
1536                                write ? "write" : "read", i);
1537         }
1538
1539         free(bulk);
1540
1541         if (!rc) {
1542                 struct timeval end;
1543                 double diff;
1544
1545                 gettimeofday(&end, NULL);
1546
1547                 diff = difftime(&end, &start);
1548
1549                 --i;
1550                 if (verbose != 0)
1551                         printf("%s: %s %dx%dx%d pages in %.4gs (%.4g pg/s): %s",
1552                                cmdname(argv[0]), write ? "wrote" : "read",
1553                                obdos, pages, i, diff,
1554                                (double)obdos * i * pages / diff,
1555                                ctime(&end.tv_sec));
1556         }
1557         return rc;
1558 }
1559
1560 static int jt_lov_config(int argc, char **argv)
1561 {
1562         struct obd_ioctl_data data;
1563         struct lov_desc desc;
1564         uuid_t *uuidarray;
1565         int size, i;
1566         IOCINIT(data);
1567
1568         printf("WARNING: obdctl lovconfig NOT MAINTAINED\n");
1569         return -1;
1570
1571         if (argc <= 5) {
1572                 Parser_printhelp("lovconfig");
1573                 return -1;
1574         }
1575
1576         if (strlen(argv[1]) > sizeof(uuid_t) - 1) {
1577                 fprintf(stderr, "lov_config: no %dB memory for uuid's\n",
1578                         strlen(argv[1]));
1579                 return -ENOMEM;
1580         }
1581
1582         memset(&desc, 0, sizeof(desc));
1583         strcpy(desc.ld_uuid, argv[1]);
1584         desc.ld_default_stripe_count = strtoul(argv[2], NULL, 0);
1585         desc.ld_default_stripe_size = strtoul(argv[3], NULL, 0);
1586         desc.ld_pattern = strtoul(argv[4], NULL, 0);
1587         desc.ld_tgt_count = argc - 5;
1588
1589
1590         size = sizeof(uuid_t) * desc.ld_tgt_count;
1591         uuidarray = malloc(size);
1592         if (!uuidarray) {
1593                 fprintf(stderr, "lov_config: no %dB memory for uuid's\n", size);
1594                 return -ENOMEM;
1595         }
1596         memset(uuidarray, 0, size);
1597         for (i = 5; i < argc; i++) {
1598                 char *buf = (char *)(uuidarray + i - 5);
1599                 if (strlen(argv[i]) >= sizeof(uuid_t)) {
1600                         fprintf(stderr, "lov_config: arg %d (%s) too long\n",
1601                                 i, argv[i]);
1602                         free(uuidarray);
1603                         return -EINVAL;
1604                 }
1605                 strcpy(buf, argv[i]);
1606         }
1607
1608         data.ioc_inllen1 = sizeof(desc);
1609         data.ioc_inlbuf1 = (char *)&desc;
1610         data.ioc_inllen2 = size;
1611         data.ioc_inlbuf2 = (char *)uuidarray;
1612
1613         if (obd_ioctl_pack(&data, &buf, max)) {
1614                 fprintf(stderr, "error: %s: invalid ioctl\n", cmdname(argv[0]));
1615                 return -EINVAL;
1616         }
1617
1618         rc = ioctl(fd, OBD_IOC_LOV_CONFIG, buf);
1619         if (rc < 0)
1620                 fprintf(stderr, "lov_config: error: %s: %s\n",
1621                         cmdname(argv[0]), strerror(rc = errno));
1622         free(uuidarray);
1623         return rc;
1624 }
1625
1626 static int jt_test_ldlm(int argc, char **argv)
1627 {
1628         struct obd_ioctl_data data;
1629
1630         IOCINIT(data);
1631         if (argc != 1) {
1632                 fprintf(stderr, "usage: %s\n", cmdname(argv[0]));
1633                 return 1;
1634         }
1635
1636         rc = ioctl(fd, IOC_LDLM_TEST, &data);
1637         if (rc)
1638                 fprintf(stderr, "error: %s: test failed: %s\n",
1639                         cmdname(argv[0]), strerror(rc = errno));
1640         return rc;
1641 }
1642
1643 static int jt_dump_ldlm(int argc, char **argv)
1644 {
1645         struct obd_ioctl_data data;
1646
1647         IOCINIT(data);
1648         if (argc != 1) {
1649                 fprintf(stderr, "usage: %s\n", cmdname(argv[0]));
1650                 return 1;
1651         }
1652
1653         rc = ioctl(fd, IOC_LDLM_DUMP, &data);
1654         if (rc)
1655                 fprintf(stderr, "error: %s failed: %s\n",
1656                         cmdname(argv[0]), strerror(rc = errno));
1657         return rc;
1658 }
1659
1660 static int jt_newconn(int argc, char **argv)
1661 {
1662         struct obd_ioctl_data data;
1663
1664         IOCINIT(data);
1665         if (argc != 1) {
1666                 fprintf(stderr, "usage: %s\n", cmdname(argv[0]));
1667                 return -1;
1668         }
1669
1670         rc = ioctl(fd, OBD_IOC_RECOVD_NEWCONN, &data);
1671         if (rc < 0)
1672                 fprintf(stderr, "error: %s: %s\n", cmdname(argv[0]),
1673                         strerror(rc = errno));
1674
1675         return rc;
1676 }
1677
1678 static int jt_quit(int argc, char **argv)
1679 {
1680         Parser_quit(argc, argv);
1681
1682         return rc;
1683 }
1684
1685 command_t cmdlist[] = {
1686         /* Metacommands */
1687         {"--xml", jt__xml, 0, "--xml <xml file> <command [args ...]>"},
1688         {"--device", jt__device, 0, "--device <devno> <command [args ...]>"},
1689         {"--threads", jt__threads, 0,
1690          "--threads <threads> <devno> <command [args ...]>"},
1691
1692         /* Device configuration commands */
1693         {"lovconfig", jt_lov_config, 0, "configure lov data on MDS "
1694          "[usage: lovconfig lov-uuid stripecount, stripesize, pattern, UUID1, [UUID2, ...]"},
1695         {"list", jt_list, 0, "list the devices (no args)"},
1696         {"newdev", jt_newdev, 0, "set device to a new unused obd (no args)"},
1697         {"device", jt_device, 0, "set current device (args device_no name)"},
1698         {"name2dev", jt_name2dev, 0,
1699          "set device by name [usage: name2dev devname]"},
1700         {"attach", jt_attach, 0, "name the type of device (args: type data"},
1701         {"setup", jt_setup, 0, "setup device (args: <blkdev> [data]"},
1702         {"detach", jt_detach, 0, "detach the current device (arg: )"},
1703         {"cleanup", jt_cleanup, 0, "cleanup the current device (arg: )"},
1704
1705         /* Session commands */
1706         {"connect", jt_connect, 0, "connect - get a connection to device"},
1707         {"disconnect", jt_disconnect, 0,
1708          "disconnect - break connection to device"},
1709
1710         /* Session operations */
1711         {"create", jt_create, 0, "create [count [mode [verbose]]]"},
1712         {"destroy", jt_destroy, 0, "destroy <id>"},
1713         {"getattr", jt_getattr, 0, "getattr <id>"},
1714         {"setattr", jt_setattr, 0, "setattr <id> <mode>"},
1715         {"newconn", jt_newconn, 0, "newconn [newuuid]"},
1716         {"test_getattr", jt_test_getattr, 0, "test_getattr <count> [verbose]"},
1717         {"test_brw", jt_test_brw, 0, "test_brw <count> [write [verbose]]"},
1718         {"test_ldlm", jt_test_ldlm, 0, "test lock manager (no args)"},
1719         {"dump_ldlm", jt_dump_ldlm, 0, "dump all lock manager state (no args)"},
1720
1721         /* User interface commands */
1722         {"help", Parser_help, 0, "help"},
1723         {"exit", jt_quit, 0, "quit"},
1724         {"quit", jt_quit, 0, "quit"},
1725         {0, 0, 0, NULL}
1726 };
1727
1728
1729 static void signal_server(int sig)
1730 {
1731         if (sig == SIGINT) {
1732                 do_disconnect("sigint", 1);
1733                 exit(1);
1734         } else
1735                 fprintf(stderr, "%s: got signal %d\n", cmdname("sigint"), sig);
1736 }
1737
1738 int main(int argc, char **argv)
1739 {
1740         struct sigaction sigact;
1741
1742         sigact.sa_handler = signal_server;
1743         sigfillset(&sigact.sa_mask);
1744         sigact.sa_flags = SA_RESTART;
1745         sigaction(SIGINT, &sigact, NULL);
1746
1747         setlinebuf(stdout);
1748         SHMEM_SETUP();
1749
1750         if (argc > 1) {
1751                 rc = Parser_execarg(argc - 1, argv + 1, cmdlist);
1752         } else {
1753                 Parser_init("obdctl > ", cmdlist);
1754                 rc = Parser_commands();
1755         }
1756
1757         do_disconnect(argv[0], 1);
1758         return rc;
1759 }