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