Whamcloud - gitweb
20794fa51858ccab89745a8c2a04ce1bdac2d318
[fs/lustre-release.git] / lustre / utils / obd.c
1 /*
2  * GPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 only,
8  * as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License version 2 for more details (a copy is included
14  * in the LICENSE file that accompanied this code).
15  *
16  * You should have received a copy of the GNU General Public License
17  * version 2 along with this program; If not, see
18  * http://www.gnu.org/licenses/gpl-2.0.html
19  *
20  * GPL HEADER END
21  */
22 /*
23  * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
24  * Use is subject to license terms.
25  *
26  * Copyright (c) 2011, 2017, Intel Corporation.
27  */
28 /*
29  * This file is part of Lustre, http://www.lustre.org/
30  *
31  * lustre/utils/obd.c
32  *
33  * Author: Peter J. Braam <braam@clusterfs.com>
34  * Author: Phil Schwan <phil@clusterfs.com>
35  * Author: Andreas Dilger <adilger@clusterfs.com>
36  * Author: Robert Read <rread@clusterfs.com>
37  */
38
39 #include <sys/ioctl.h>
40 #include <sys/socket.h>
41 #include <sys/stat.h>
42 #include <sys/time.h>
43 #include <sys/types.h>
44 #include <sys/un.h>
45 #include <sys/wait.h>
46
47 #include <ctype.h>
48 #include <errno.h>
49 #include <fcntl.h>
50 #include <getopt.h>
51 #include <signal.h>
52 #include <stdarg.h>
53 #include <stdbool.h>
54 #include <stdio.h>
55 #include <stdlib.h>
56 #include <string.h>
57 #include <time.h>
58 #include <unistd.h>
59 #include <limits.h>
60 #include "obdctl.h"
61 #include "lustreapi_internal.h"
62 #include <libcfs/util/list.h>
63 #include <libcfs/util/ioctl.h>
64 #include <libcfs/util/param.h>
65 #include <libcfs/util/parser.h>
66 #include <libcfs/util/string.h>
67
68 #include <linux/lnet/nidstr.h>
69 #include <linux/lnet/lnetctl.h>
70 #ifdef HAVE_SERVER_SUPPPORT
71 #include <linux/lustre/lustre_barrier_user.h>
72 #include <linux/lustre/lustre_disk.h>
73 #endif
74 #include <linux/lustre/lustre_cfg.h>
75 #include <linux/lustre/lustre_ioctl.h>
76 #include <linux/lustre/lustre_ostid.h>
77 #include <linux/lustre/lustre_param.h>
78 #include <linux/lustre/lustre_ver.h>
79
80 #include <lustre/lustreapi.h>
81
82 #define MAX_STRING_SIZE 128
83
84 #if HAVE_LIBPTHREAD
85 #include <sys/ipc.h>
86 #include <sys/shm.h>
87 #include <pthread.h>
88
89 #define MAX_THREADS 4096
90 #define MAX_BASE_ID 0xffffffff
91 #define NIDSTRING_LENGTH 64
92 struct shared_data {
93         pthread_mutex_t mutex;
94         pthread_cond_t  cond;
95         int       stopping;
96         struct {
97                 __u64 counters[MAX_THREADS];
98                 __u64 offsets[MAX_THREADS];
99                 int   thr_running;
100                 int   start_barrier;
101                 int   stop_barrier;
102                 struct timeval start_time;
103                 struct timeval end_time;
104         } body;
105 };
106
107 static struct shared_data *shared_data;
108 static __u64 counter_snapshot[2][MAX_THREADS];
109 static int prev_valid;
110 static struct timeval prev_time;
111 static int thread;
112 static int nthreads;
113 #else
114 const int thread;
115 const int nthreads = 1;
116 #endif
117
118 static int cur_device = -1;
119
120 int lcfg_ioctl(char *func, int dev_id, struct lustre_cfg *lcfg)
121 {
122         struct obd_ioctl_data data;
123         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
124         int rc;
125
126         memset(&data, 0, sizeof(data));
127         data.ioc_dev = cur_device;
128         data.ioc_type = LUSTRE_CFG_TYPE;
129         data.ioc_plen1 = lustre_cfg_len(lcfg->lcfg_bufcount,
130                                         lcfg->lcfg_buflens);
131         data.ioc_pbuf1 = (void *)lcfg;
132         memset(buf, 0, sizeof(rawbuf));
133         rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
134         if (rc) {
135                 fprintf(stderr, "error: %s: invalid ioctl\n", jt_cmdname(func));
136                 return rc;
137         }
138
139         rc =  l_ioctl(dev_id, OBD_IOC_PROCESS_CFG, buf);
140
141         return rc;
142 }
143
144 static int do_device(char *func, char *devname);
145
146 static int get_mgs_device(void)
147 {
148         char mgs[] = "$MGS";
149         static int mgs_device = -1;
150
151         if (mgs_device == -1) {
152                 int rc;
153
154                 do_disconnect(NULL, 1);
155                 rc = do_device("mgsioc", mgs);
156                 if (rc) {
157                         fprintf(stderr,
158                                 "This command must be run on the MGS.\n");
159                         errno = ENODEV;
160                         return -1;
161                 }
162                 mgs_device = cur_device;
163         }
164         return mgs_device;
165 }
166
167 /* Returns -1 on error with errno set */
168 int lcfg_mgs_ioctl(char *func, int dev_id, struct lustre_cfg *lcfg)
169 {
170         struct obd_ioctl_data data;
171         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
172         int rc;
173
174         memset(&data, 0, sizeof(data));
175         rc = data.ioc_dev = get_mgs_device();
176         if (rc < 0)
177                 goto out;
178         data.ioc_type = LUSTRE_CFG_TYPE;
179         data.ioc_plen1 = lustre_cfg_len(lcfg->lcfg_bufcount,
180                                         lcfg->lcfg_buflens);
181         data.ioc_pbuf1 = (void *)lcfg;
182         memset(buf, 0, sizeof(rawbuf));
183         rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
184         if (rc) {
185                 fprintf(stderr, "error: %s: invalid ioctl\n", jt_cmdname(func));
186                 return rc;
187         }
188
189         rc = l_ioctl(dev_id, OBD_IOC_PARAM, buf);
190 out:
191         if (rc && errno == ENOSYS)
192                 fprintf(stderr, "Make sure cfg_device is set first.\n");
193
194         return rc;
195 }
196
197 char *obdo_print(struct obdo *obd)
198 {
199         char buf[1024];
200
201         snprintf(buf, sizeof(buf), "id: %#jx\ngrp: %#jx\natime: %ju\n"
202                  "mtime: %ju\nctime: %ju\nsize: %ju\nblocks: %ju"
203                  "\nblksize: %u\nmode: %o\nuid: %d\ngid: %d\nflags: %x\n"
204                  "misc: %x\nnlink: %d,\nvalid %#jx\n",
205                  (uintmax_t)ostid_id(&obd->o_oi),
206                  (uintmax_t)ostid_seq(&obd->o_oi),
207                  (uintmax_t)obd->o_atime, (uintmax_t)obd->o_mtime,
208                  (uintmax_t)obd->o_ctime, (uintmax_t)obd->o_size,
209                  (uintmax_t)obd->o_blocks, obd->o_blksize, obd->o_mode,
210                  obd->o_uid, obd->o_gid, obd->o_flags, obd->o_misc,
211                  obd->o_nlink, (uintmax_t)obd->o_valid);
212         return strdup(buf);
213 }
214
215 #define BAD_VERBOSE (-999999999)
216
217 char *jt_cmdname(char *func)
218 {
219         static char buf[512];
220
221         if (thread) {
222                 sprintf(buf, "%s-%d", func, thread);
223                 return buf;
224         }
225
226         return func;
227 }
228
229 #define difftime(a, b)                                  \
230         ((a)->tv_sec - (b)->tv_sec +                    \
231          ((a)->tv_usec - (b)->tv_usec) / 1000000.0)
232
233 static int be_verbose(int verbose, struct timeval *next_time,
234                       __u64 num, __u64 *next_num, int num_total)
235 {
236         struct timeval now;
237
238         if (!verbose)
239                 return 0;
240
241         if (next_time)
242                 gettimeofday(&now, NULL);
243
244         /* A positive verbosity means to print every X iterations */
245         if (verbose > 0 && (num >= *next_num || num >= num_total)) {
246                 *next_num += verbose;
247                 if (next_time) {
248                         next_time->tv_sec = now.tv_sec - verbose;
249                         next_time->tv_usec = now.tv_usec;
250                 }
251                 return 1;
252         }
253
254         /* A negative verbosity means to print at most each X seconds */
255         if (verbose < 0 && next_time && difftime(&now, next_time) >= 0.0) {
256                 next_time->tv_sec = now.tv_sec - verbose;
257                 next_time->tv_usec = now.tv_usec;
258                 *next_num = num;
259                 return 1;
260         }
261
262         return 0;
263 }
264
265 static int get_verbose(char *func, const char *arg)
266 {
267         int verbose;
268         char *end;
269
270         if (!arg || arg[0] == 'v') {
271                 verbose = 1;
272         } else if (arg[0] == 's' || arg[0] == 'q') {
273                 verbose = 0;
274         } else {
275                 verbose = (int)strtoul(arg, &end, 0);
276                 if (*end) {
277                         fprintf(stderr, "error: %s: bad verbose option '%s'\n",
278                                 jt_cmdname(func), arg);
279                         return BAD_VERBOSE;
280                 }
281         }
282
283         if (verbose < 0)
284                 printf("Print status every %d seconds\n", -verbose);
285         else if (verbose == 1)
286                 printf("Print status every operation\n");
287         else if (verbose > 1)
288                 printf("Print status every %d operations\n", verbose);
289
290         return verbose;
291 }
292
293 int do_disconnect(char *func, int verbose)
294 {
295         lcfg_set_devname(NULL);
296         cur_device = -1;
297         return 0;
298 }
299
300 #ifdef MAX_THREADS
301 static int shmem_setup(void)
302 {
303         pthread_mutexattr_t mattr;
304         pthread_condattr_t  cattr;
305         int rc;
306         int shmid;
307
308         /* Create new segment */
309         shmid = shmget(IPC_PRIVATE, sizeof(*shared_data), 0600);
310         if (shmid == -1) {
311                 fprintf(stderr, "Can't create shared data: %s\n",
312                         strerror(errno));
313                 return errno;
314         }
315
316         /* Attatch to new segment */
317         shared_data = (struct shared_data *)shmat(shmid, NULL, 0);
318
319         if (shared_data == (struct shared_data *)(-1)) {
320                 fprintf(stderr, "Can't attach shared data: %s\n",
321                         strerror(errno));
322                 shared_data = NULL;
323                 return errno;
324         }
325
326         /*
327          * Mark segment as destroyed, so it will disappear when we exit.
328          * Forks will inherit attached segments, so we should be OK.
329          */
330         if (shmctl(shmid, IPC_RMID, NULL) == -1) {
331                 fprintf(stderr, "Can't destroy shared data: %s\n",
332                         strerror(errno));
333                 return errno;
334         }
335
336         pthread_mutexattr_init(&mattr);
337         pthread_condattr_init(&cattr);
338
339         rc = pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_SHARED);
340         if (rc != 0) {
341                 fprintf(stderr, "Can't set shared mutex attr\n");
342                 goto out;
343         }
344
345         rc = pthread_condattr_setpshared(&cattr, PTHREAD_PROCESS_SHARED);
346         if (rc != 0) {
347                 fprintf(stderr, "Can't set shared cond attr\n");
348                 goto out;
349         }
350
351         pthread_mutex_init(&shared_data->mutex, &mattr);
352         pthread_cond_init(&shared_data->cond, &cattr);
353 out:
354         pthread_mutexattr_destroy(&mattr);
355         pthread_condattr_destroy(&cattr);
356
357         return rc;
358 }
359
360 static inline void shmem_lock(void)
361 {
362         pthread_mutex_lock(&shared_data->mutex);
363 }
364
365 static inline void shmem_unlock(void)
366 {
367         pthread_mutex_unlock(&shared_data->mutex);
368 }
369
370 static inline void shmem_wait(void)
371 {
372         pthread_cond_wait(&shared_data->cond, &shared_data->mutex);
373 }
374
375 static inline void shmem_wakeup_all(void)
376 {
377         pthread_cond_broadcast(&shared_data->cond);
378 }
379
380 static inline void shmem_reset(int total_threads)
381 {
382         if (!shared_data)
383                 return;
384
385         memset(&shared_data->body, 0, sizeof(shared_data->body));
386         memset(counter_snapshot, 0, sizeof(counter_snapshot));
387         prev_valid = 0;
388         shared_data->stopping = 0;
389         shared_data->body.start_barrier = total_threads;
390         shared_data->body.stop_barrier = total_threads;
391 }
392
393 static inline void shmem_bump(__u32 counter)
394 {
395         static bool running_not_bumped = true;
396
397         if (!shared_data || thread <= 0 || thread > MAX_THREADS)
398                 return;
399
400         shmem_lock();
401         shared_data->body.counters[thread - 1] += counter;
402         if (running_not_bumped) {
403                 shared_data->body.thr_running++;
404                 running_not_bumped = false;
405         }
406         shmem_unlock();
407 }
408
409 static void shmem_total(int total_threads)
410 {
411         __u64 total = 0;
412         double secs;
413         int i;
414
415         if (!shared_data || total_threads > MAX_THREADS)
416                 return;
417
418         shmem_lock();
419         for (i = 0; i < total_threads; i++)
420                 total += shared_data->body.counters[i];
421
422         secs = difftime(&shared_data->body.end_time,
423                         &shared_data->body.start_time);
424         shmem_unlock();
425
426         printf("Total: total %ju threads %d sec %f %f/second\n",
427                (uintmax_t)total, total_threads, secs, total / secs);
428 }
429
430 static void shmem_snap(int total_threads, int live_threads)
431 {
432         struct timeval this_time;
433         int non_zero = 0;
434         __u64 total = 0;
435         double secs;
436         int running;
437         int i;
438
439         if (!shared_data || total_threads > MAX_THREADS)
440                 return;
441
442         shmem_lock();
443         memcpy(counter_snapshot[0], shared_data->body.counters,
444                total_threads * sizeof(counter_snapshot[0][0]));
445         running = shared_data->body.thr_running;
446         shmem_unlock();
447
448         gettimeofday(&this_time, NULL);
449
450         for (i = 0; i < total_threads; i++) {
451                 long long this_count =
452                         counter_snapshot[0][i] - counter_snapshot[1][i];
453
454                 if (this_count != 0) {
455                         non_zero++;
456                         total += this_count;
457                 }
458         }
459
460         secs = difftime(&this_time, &prev_time);
461         if (prev_valid && secs > 1.0) {   /* someone screwed with the time? */
462                 printf("%d/%d Total: %f/second\n", non_zero, total_threads,
463                        total / secs);
464
465                 memcpy(counter_snapshot[1], counter_snapshot[0],
466                        total_threads * sizeof(counter_snapshot[0][0]));
467                 prev_time = this_time;
468         }
469         if (!prev_valid && running == total_threads) {
470                 prev_valid = 1;
471                 /* drop counters when all threads were started */
472                 memcpy(counter_snapshot[1], counter_snapshot[0],
473                        total_threads * sizeof(counter_snapshot[0][0]));
474                 prev_time = this_time;
475         }
476 }
477
478 static void shmem_stop(void)
479 {
480         if (!shared_data)
481                 return;
482
483         shared_data->stopping = 1;
484 }
485
486 static void shmem_cleanup(void)
487 {
488         if (!shared_data)
489                 return;
490
491         shmem_stop();
492
493         pthread_mutex_destroy(&shared_data->mutex);
494         pthread_cond_destroy(&shared_data->cond);
495 }
496
497 static int shmem_running(void)
498 {
499         return (!shared_data || !shared_data->stopping);
500 }
501
502 static void shmem_end_time_locked(void)
503 {
504         shared_data->body.stop_barrier--;
505         if (shared_data->body.stop_barrier == 0)
506                 gettimeofday(&shared_data->body.end_time, NULL);
507 }
508
509 static void shmem_start_time_locked(void)
510 {
511         shared_data->body.start_barrier--;
512         if (shared_data->body.start_barrier == 0) {
513                 shmem_wakeup_all();
514                 gettimeofday(&shared_data->body.start_time, NULL);
515         } else {
516                 shmem_wait();
517         }
518 }
519
520 #else
521 static int shmem_setup(void)
522 {
523         return 0;
524 }
525
526 static inline void shmem_reset(int total_threads)
527 {
528 }
529
530 static inline void shmem_bump(__u32 counters)
531 {
532 }
533
534 static void shmem_lock(void)
535 {
536 }
537
538 static void shmem_unlock(void)
539 {
540 }
541
542 static void shmem_cleanup(void)
543 {
544 }
545
546 static int shmem_running(void)
547 {
548         return 1;
549 }
550 #endif
551
552 extern command_t cmdlist[];
553
554 static int do_device(char *func, char *devname)
555 {
556         int dev;
557
558         dev = parse_devname(func, devname, cur_device);
559         if (dev < 0)
560                 return -1;
561
562         lcfg_set_devname(devname);
563         cur_device = dev;
564         return 0;
565 }
566
567 int jt_obd_get_device(void)
568 {
569         return cur_device;
570 }
571
572 int jt_obd_device(int argc, char **argv)
573 {
574         int rc;
575
576         if (argc > 2)
577                 return CMD_HELP;
578
579         if (argc == 1) {
580                 printf("current device is %d - %s\n",
581                        cur_device, lcfg_get_devname() ? : "not set");
582                 return 0;
583         }
584         rc = do_device("device", argv[1]);
585         return rc;
586 }
587
588 int jt_opt_device(int argc, char **argv)
589 {
590         int ret;
591         int rc;
592
593         if (argc < 3)
594                 return CMD_HELP;
595
596         rc = do_device("device", argv[1]);
597
598         if (!rc)
599                 rc = Parser_execarg(argc - 2, argv + 2, cmdlist);
600
601         ret = do_disconnect(argv[0], 0);
602         if (!rc)
603                 rc = ret;
604
605         return rc;
606 }
607
608 #ifdef MAX_THREADS
609 static void parent_sighandler(int sig)
610 {
611 }
612
613 int jt_opt_threads(int argc, char **argv)
614 {
615         static char      cmdstr[129];
616         sigset_t         saveset;
617         sigset_t         sigset;
618         struct sigaction sigact;
619         struct sigaction saveact1;
620         struct sigaction saveact2;
621         unsigned long    threads;
622         __u64            next_thread;
623         int verbose;
624         int rc = 0;
625         int report_count = -1;
626         char *end;
627         int i;
628
629         if (argc < 5)
630                 return CMD_HELP;
631
632         threads = strtoul(argv[1], &end, 0);
633
634         if (*end == '.')
635                 report_count = strtoul(end + 1, &end, 0);
636
637         if (*end || threads > MAX_THREADS) {
638                 fprintf(stderr, "error: %s: invalid thread count '%s'\n",
639                         jt_cmdname(argv[0]), argv[1]);
640                 return CMD_HELP;
641         }
642
643         verbose = get_verbose(argv[0], argv[2]);
644         if (verbose == BAD_VERBOSE)
645                 return CMD_HELP;
646
647         if (verbose != 0) {
648                 snprintf(cmdstr, sizeof(cmdstr), "%s", argv[4]);
649                 for (i = 5; i < argc; i++)
650                         snprintf(cmdstr + strlen(cmdstr),
651                                  sizeof(cmdstr) - strlen(cmdstr),
652                                  " %s", argv[i]);
653
654                 printf("%s: starting %ld threads on device %s running %s\n",
655                        argv[0], threads, argv[3], cmdstr);
656         }
657
658         shmem_reset(threads);
659
660         sigemptyset(&sigset);
661         sigaddset(&sigset, SIGALRM);
662         sigaddset(&sigset, SIGCHLD);
663         sigprocmask(SIG_BLOCK, &sigset, &saveset);
664
665         nthreads = threads;
666
667         for (i = 1, next_thread = verbose; i <= threads; i++) {
668                 rc = fork();
669                 if (rc < 0) {
670                         fprintf(stderr, "error: %s: #%d - %s\n", argv[0], i,
671                                 strerror(rc = errno));
672                         break;
673                 } else if (rc == 0) {
674                         sigprocmask(SIG_SETMASK, &saveset, NULL);
675
676                         thread = i;
677                         argv[2] = "--device";
678                         exit(jt_opt_device(argc - 2, argv + 2));
679                 } else if (be_verbose(verbose, NULL, i, &next_thread, threads))
680                         printf("%s: thread #%d (PID %d) started\n",
681                                argv[0], i, rc);
682                 rc = 0;
683         }
684
685         if (!thread) {          /* parent process */
686                 int live_threads = threads;
687
688                 sigemptyset(&sigset);
689                 sigemptyset(&sigact.sa_mask);
690                 sigact.sa_handler = parent_sighandler;
691                 sigact.sa_flags = 0;
692
693                 sigaction(SIGALRM, &sigact, &saveact1);
694                 sigaction(SIGCHLD, &sigact, &saveact2);
695
696                 while (live_threads > 0) {
697                         int status;
698                         pid_t ret;
699
700                         if (verbose < 0)        /* periodic stats */
701                                 alarm(-verbose);
702
703                         sigsuspend(&sigset);
704                         alarm(0);
705
706                         while (live_threads > 0) {
707                                 ret = waitpid(0, &status, WNOHANG);
708                                 if (ret == 0)
709                                         break;
710
711                                 if (ret < 0) {
712                                         fprintf(stderr,
713                                                 "error: %s: wait - %s\n",
714                                                 argv[0], strerror(errno));
715                                         if (!rc)
716                                                 rc = errno;
717                                         continue;
718                                 } else {
719                                         /*
720                                          * This is a hack.  We _should_ be able
721                                          * to use WIFEXITED(status) to see if
722                                          * there was an error, but it appears
723                                          * to be broken and it always returns 1
724                                          * (OK).  See wait(2).
725                                          */
726                                         int err = WEXITSTATUS(status);
727
728                                         if (err || WIFSIGNALED(status))
729                                                 fprintf(stderr,
730                                                         "%s: PID %d had rc=%d\n",
731                                                         argv[0], ret, err);
732                                         if (!rc)
733                                                 rc = err;
734
735                                         live_threads--;
736                                 }
737                         }
738
739                         /* Show stats while all threads running */
740                         if (verbose < 0) {
741                                 shmem_snap(threads, live_threads);
742                                 if (report_count > 0 && --report_count == 0)
743                                         shmem_stop();
744                         }
745                 }
746                 sigaction(SIGCHLD, &saveact2, NULL);
747                 sigaction(SIGALRM, &saveact1, NULL);
748         }
749
750         shmem_total(threads);
751         sigprocmask(SIG_SETMASK, &saveset, NULL);
752
753         return rc;
754 }
755 #else
756 int jt_opt_threads(int argc, char **argv)
757 {
758         fprintf(stderr, "%s not-supported in a single-threaded runtime\n",
759                 jt_cmdname(argv[0]));
760         return CMD_HELP;
761 }
762 #endif
763
764 int jt_opt_net(int argc, char **argv)
765 {
766         char *arg2[3];
767         int rc;
768
769         if (argc < 3)
770                 return CMD_HELP;
771
772         arg2[0] = argv[0];
773         arg2[1] = argv[1];
774         arg2[2] = NULL;
775         rc = jt_ptl_network(2, arg2);
776
777         if (!rc)
778                 rc = Parser_execarg(argc - 2, argv + 2, cmdlist);
779
780         return rc;
781 }
782
783 #ifdef HAVE_SERVER_SUPPORT
784 /*
785  * Place this here so we can build tools that work with
786  * older Lustre versions
787  */
788 #ifndef OBD_IOC_NO_TRANSNO
789 #define OBD_IOC_NO_TRANSNO      _IOW('f', 140, OBD_IOC_DATA_TYPE)
790 #endif
791
792 int jt_obd_no_transno(int argc, char **argv)
793 {
794         struct obd_ioctl_data data;
795         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
796         glob_t path;
797         int count;
798         int fd;
799         int rc;
800
801         if (argc != 1)
802                 return CMD_HELP;
803
804         memset(buf, 0, sizeof(rawbuf));
805
806         rc = cfs_get_param_paths(&path, "no_transno");
807         if (rc != 0)
808                 goto old_ioctl;
809
810         fd = open(path.gl_pathv[0], O_WRONLY);
811         if (fd < 0) {
812                 cfs_free_param_data(&path);
813                 goto old_ioctl;
814         }
815
816         snprintf(rawbuf, sizeof(rawbuf), "%d", cur_device);
817
818         count = write(fd, rawbuf, strlen(rawbuf));
819         if (count < 0)
820                 rc = errno;
821
822         cfs_free_param_data(&path);
823         close(fd);
824         if (rc)
825                 goto old_ioctl;
826
827         return 0;
828
829 old_ioctl:
830 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
831         memset(&data, 0, sizeof(data));
832         data.ioc_dev = cur_device;
833
834         rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
835         if (rc) {
836                 fprintf(stderr, "error: %s: invalid ioctl\n",
837                         jt_cmdname(argv[0]));
838                 return rc;
839         }
840         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_NO_TRANSNO, buf);
841         if (rc < 0)
842                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
843                         strerror(rc = errno));
844 #endif
845         return rc;
846 }
847
848 int jt_obd_set_readonly(int argc, char **argv)
849 {
850         struct obd_ioctl_data data;
851         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
852         int rc;
853
854         memset(&data, 0, sizeof(data));
855         data.ioc_dev = cur_device;
856
857         if (argc != 1)
858                 return CMD_HELP;
859
860         memset(buf, 0, sizeof(rawbuf));
861         rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
862         if (rc) {
863                 fprintf(stderr, "error: %s: invalid ioctl\n",
864                         jt_cmdname(argv[0]));
865                 return rc;
866         }
867         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_SET_READONLY, buf);
868         if (rc < 0)
869                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
870                         strerror(rc = errno));
871
872         return rc;
873 }
874
875 static int obd_abort_recovery(char *cmd, enum obd_abort_recovery_flags flags)
876 {
877         struct obd_ioctl_data data = {
878                 .ioc_dev = cur_device,
879                 .ioc_type = flags,
880         };
881         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
882         int rc;
883
884         memset(buf, 0, sizeof(rawbuf));
885         rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
886         if (rc) {
887                 fprintf(stderr, "error: %s: invalid ioctl\n",
888                         jt_cmdname(cmd));
889                 return rc;
890         }
891         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_ABORT_RECOVERY, buf);
892         if (rc < 0)
893                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(cmd),
894                         strerror(rc = errno));
895
896         return rc;
897 }
898
899 int jt_obd_abort_recovery(int argc, char **argv)
900 {
901         if (argc != 1)
902                 return CMD_HELP;
903
904         return obd_abort_recovery(argv[0], OBD_FLG_ABORT_RECOV_OST);
905 }
906
907 int jt_obd_abort_recovery_mdt(int argc, char **argv)
908 {
909         if (argc != 1)
910                 return CMD_HELP;
911
912         return obd_abort_recovery(argv[0], OBD_FLG_ABORT_RECOV_MDT);
913 }
914 #else /* ! HAVE_SERVER_SUPPROT */
915 int jt_obd_no_transno(int argc, char **argv)
916 {
917         if (argc != 1)
918                 return CMD_HELP;
919
920         fprintf(stderr, "error: %s: invalid ioctl\n",
921                 jt_cmdname(argv[0]));
922         return -EOPNOTSUPP;
923 }
924
925 int jt_obd_set_readonly(int argc, char **argv)
926 {
927         if (argc != 1)
928                 return CMD_HELP;
929
930         fprintf(stderr, "error: %s: invalid ioctl\n",
931                 jt_cmdname(argv[0]));
932         return -EOPNOTSUPP;
933 }
934
935 int jt_obd_abort_recovery(int argc, char **argv)
936 {
937         if (argc != 1)
938                 return CMD_HELP;
939
940         fprintf(stderr, "error: %s: invalid ioctl\n",
941                 jt_cmdname(argv[0]));
942         return -EOPNOTSUPP;
943 }
944
945 int jt_obd_abort_recovery_mdt(int argc, char **argv)
946 {
947         if (argc != 1)
948                 return CMD_HELP;
949
950         fprintf(stderr, "error: %s: invalid ioctl\n",
951                 jt_cmdname(argv[0]));
952         return -EOPNOTSUPP;
953 }
954 #endif /* HAVE_SERVER_SUPPORT */
955
956 int jt_get_version(int argc, char **argv)
957 {
958         char version[128];
959         int rc;
960
961         if (argc != 1)
962                 return CMD_HELP;
963
964         rc = llapi_get_version_string(version, sizeof(version));
965         if (rc)
966                 printf("Lustre version: %s\n", LUSTRE_VERSION_STRING);
967         else
968                 printf("Lustre version: %s\n", version);
969
970         return 0;
971 }
972
973 struct jt_fid_space {
974         __u64   jt_seq;
975         __u64   jt_id;
976         int     jt_width;
977 };
978
979 int jt_obd_alloc_fids(struct jt_fid_space *space, struct lu_fid *fid,
980                       __u64 *count)
981 {
982         int rc;
983
984         if (space->jt_seq == 0 || space->jt_id == space->jt_width) {
985                 struct obd_ioctl_data  data;
986                 char rawbuf[MAX_IOC_BUFLEN];
987                 char *buf = rawbuf;
988                 __u64 seqnr;
989                 int max_count;
990
991                 memset(&data, 0, sizeof(data));
992                 data.ioc_dev = cur_device;
993
994                 data.ioc_pbuf1 = (char *)&seqnr;
995                 data.ioc_plen1 = sizeof(seqnr);
996
997                 data.ioc_pbuf2 = (char *)&max_count;
998                 data.ioc_plen2 = sizeof(max_count);
999
1000                 memset(buf, 0, sizeof(rawbuf));
1001                 rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
1002                 if (rc) {
1003                         fprintf(stderr, "error: invalid ioctl rc = %d\n", rc);
1004                         return rc;
1005                 }
1006
1007                 rc = l_ioctl(OBD_DEV_ID, OBD_IOC_ECHO_ALLOC_SEQ, buf);
1008                 if (rc) {
1009                         fprintf(stderr, "ioctl error: rc = %d\n", rc);
1010                         return rc;
1011                 }
1012
1013                 space->jt_seq = *(__u64 *)data.ioc_pbuf1;
1014                 space->jt_width = *(int *)data.ioc_pbuf2;
1015                 space->jt_id = 1;
1016         }
1017         fid->f_seq = space->jt_seq;
1018         fid->f_oid = space->jt_id;
1019         fid->f_ver = 0;
1020
1021         space->jt_id = space->jt_id + *count;
1022         if (space->jt_id > space->jt_width)
1023                 space->jt_id = space->jt_width;
1024
1025         *count = space->jt_id - fid->f_oid;
1026         return 0;
1027 }
1028
1029 #define MD_STEP_COUNT 1000
1030 int jt_obd_md_common(int argc, char **argv, int cmd)
1031 {
1032         struct obd_ioctl_data  data;
1033         struct timeval         start;
1034         struct timeval         end_time;
1035         char rawbuf[MAX_IOC_BUFLEN];
1036         char *buf = rawbuf;
1037         int mode = 0000644;
1038         int create_mode;
1039         int rc = 0;
1040         char *parent_basedir = NULL;
1041         char dirname[4096];
1042         int parent_base_id = 0;
1043         int parent_count = 1;
1044         __u64 child_base_id = -1;
1045         int stripe_count = 0;
1046         int stripe_index = -1;
1047         int count = 0;
1048         char *end;
1049         __u64 seconds = 0;
1050         double diff;
1051         int c;
1052         __u64 total_count = 0;
1053         char *name = NULL;
1054         struct jt_fid_space fid_space = {0};
1055         int version = 0;
1056         struct option long_opts[] = {
1057         { .val = 'b',   .name = "child_base_id",
1058                                                 .has_arg = required_argument },
1059         { .val = 'c',   .name = "stripe_count",
1060                                                 .has_arg = required_argument },
1061         { .val = 'd',   .name = "parent_basedir",
1062                                                 .has_arg = required_argument },
1063         { .val = 'D',   .name = "parent_dircount",
1064                                                 .has_arg = required_argument },
1065         { .val = 'i',   .name = "stripe_index", .has_arg = required_argument },
1066         { .val = 'm',   .name = "mode",         .has_arg = required_argument },
1067         { .val = 'n',   .name = "count",        .has_arg = required_argument },
1068         { .val = 't',   .name = "time",         .has_arg = required_argument },
1069         { .val = 'v',   .name = "version",      .has_arg = no_argument },
1070         { .name = NULL } };
1071
1072         while ((c = getopt_long(argc, argv, "b:c:d:D:m:n:t:v",
1073                                 long_opts, NULL)) >= 0) {
1074                 switch (c) {
1075                 case 'b':
1076                         child_base_id = strtoull(optarg, &end, 0);
1077                         if (*end) {
1078                                 fprintf(stderr,
1079                                         "error: %s: bad child_base_id '%s'\n",
1080                                         jt_cmdname(argv[0]), optarg);
1081                                 return CMD_HELP;
1082                         }
1083                         break;
1084                 case 'c':
1085                         stripe_count = strtoul(optarg, &end, 0);
1086                         if (*end) {
1087                                 fprintf(stderr,
1088                                         "error: %s: bad stripe count '%s'\n",
1089                                         jt_cmdname(argv[0]), optarg);
1090                                 return CMD_HELP;
1091                         }
1092                         break;
1093                 case 'd':
1094                         parent_basedir = optarg;
1095                         break;
1096                 case 'D':
1097                         parent_count = strtoul(optarg, &end, 0);
1098                         if (*end) {
1099                                 fprintf(stderr,
1100                                         "error: %s: bad parent count '%s'\n",
1101                                         jt_cmdname(argv[0]), optarg);
1102                                 return CMD_HELP;
1103                         }
1104                         break;
1105                 case 'i':
1106                         stripe_index = strtoul(optarg, &end, 0);
1107                         if (*end) {
1108                                 fprintf(stderr,
1109                                         "error: %s: bad stripe index '%s'\n",
1110                                         jt_cmdname(argv[0]), optarg);
1111                                 return CMD_HELP;
1112                         }
1113                         break;
1114                 case 'm':
1115                         mode = strtoul(optarg, &end, 0);
1116                         if (*end) {
1117                                 fprintf(stderr, "error: %s: bad mode '%s'\n",
1118                                         jt_cmdname(argv[0]), optarg);
1119                                 return CMD_HELP;
1120                         }
1121                         break;
1122                 case 'n':
1123                         total_count = strtoul(optarg, &end, 0);
1124                         if (*end || total_count == 0) {
1125                                 fprintf(stderr, "%s: bad child count '%s'\n",
1126                                         jt_cmdname(argv[0]), optarg);
1127                                 return CMD_HELP;
1128                         }
1129                         break;
1130                 case 't':
1131                         seconds = strtoull(optarg, &end, 0);
1132                         if (*end) {
1133                                 fprintf(stderr, "error: %s: seconds '%s'\n",
1134                                         jt_cmdname(argv[0]), optarg);
1135                                 return CMD_HELP;
1136                         }
1137                         break;
1138                 case 'v':
1139                         version = 1;
1140                         break;
1141                 default:
1142                         fprintf(stderr,
1143                                 "error: %s: option '%s' unrecognized\n",
1144                                 argv[0], argv[optind - 1]);
1145                         return CMD_HELP;
1146                 }
1147         }
1148
1149         memset(&data, 0, sizeof(data));
1150         data.ioc_dev = cur_device;
1151         if (child_base_id == -1) {
1152                 if (optind >= argc)
1153                         return CMD_HELP;
1154                 name = argv[optind];
1155                 total_count = 1;
1156         } else {
1157                 if (optind < argc) {
1158                         fprintf(stderr,
1159                                 "child_base_id and name can not specified at the same time\n");
1160                         return CMD_HELP;
1161                 }
1162         }
1163
1164         if (stripe_count == 0 && stripe_index != -1) {
1165                 fprintf(stderr,
1166                         "If stripe_count is 0, stripe_index can not be specified\n");
1167                 return CMD_HELP;
1168         }
1169
1170         if (total_count == 0 && seconds == 0) {
1171                 fprintf(stderr, "count or seconds needs to be indicated\n");
1172                 return CMD_HELP;
1173         }
1174
1175         if (parent_count <= 0) {
1176                 fprintf(stderr, "parent count must < 0\n");
1177                 return CMD_HELP;
1178         }
1179
1180 #ifdef MAX_THREADS
1181         if (thread) {
1182                 shmem_lock();
1183                 /* threads interleave */
1184                 if (parent_base_id != -1)
1185                         parent_base_id += (thread - 1) % parent_count;
1186
1187                 if (child_base_id != -1)
1188                         child_base_id +=  (thread - 1) *
1189                                 (MAX_BASE_ID / nthreads);
1190
1191                 shmem_start_time_locked();
1192                 shmem_unlock();
1193         }
1194 #endif
1195         /*
1196          * If parent directory is not specified, try to get the directory
1197          * from name
1198          */
1199         if (!parent_basedir) {
1200                 char *last_lash;
1201
1202                 if (!name) {
1203                         fprintf(stderr,
1204                                 "parent_basedir or name must be indicated!\n");
1205                         return CMD_HELP;
1206                 }
1207                 /*Get directory and name from name*/
1208                 last_lash = strrchr(name, '/');
1209                 if (!last_lash || name[0] != '/') {
1210                         fprintf(stderr, "Can not locate %s\n", name);
1211                         return CMD_HELP;
1212                 }
1213
1214                 if (last_lash == name) {
1215                         sprintf(dirname, "%s", "/");
1216                         name++;
1217                 } else {
1218                         int namelen = (unsigned long)last_lash -
1219                                       (unsigned long)name + 1;
1220                         snprintf(dirname, namelen, "%s", name);
1221                         name = last_lash + 1;
1222                 }
1223
1224                 data.ioc_pbuf1 = dirname;
1225                 data.ioc_plen1 = strlen(dirname);
1226
1227                 data.ioc_pbuf2 = name;
1228                 data.ioc_plen2 = strlen(name);
1229         } else {
1230                 if (name) {
1231                         data.ioc_pbuf2 = name;
1232                         data.ioc_plen2 = strlen(name);
1233                 }
1234                 if (parent_base_id > 0)
1235                         sprintf(dirname, "%s%d", parent_basedir,
1236                                 parent_base_id);
1237                 else
1238                         sprintf(dirname, "%s", parent_basedir);
1239                 data.ioc_pbuf1 = dirname;
1240                 data.ioc_plen1 = strlen(dirname);
1241         }
1242
1243         if (cmd == ECHO_MD_MKDIR || cmd == ECHO_MD_RMDIR)
1244                 create_mode = S_IFDIR;
1245         else
1246                 create_mode = S_IFREG;
1247
1248         data.ioc_obdo1.o_mode = mode | S_IFDIR;
1249         data.ioc_obdo1.o_valid = OBD_MD_FLID | OBD_MD_FLTYPE | OBD_MD_FLMODE |
1250                                  OBD_MD_FLFLAGS | OBD_MD_FLGROUP;
1251         data.ioc_command = cmd;
1252
1253         gettimeofday(&start, NULL);
1254         while (shmem_running()) {
1255                 struct lu_fid fid = { 0 };
1256
1257                 if (child_base_id != -1)
1258                         data.ioc_obdo2.o_oi.oi.oi_id = child_base_id;
1259                 data.ioc_obdo2.o_mode = mode | create_mode;
1260                 data.ioc_obdo2.o_valid = OBD_MD_FLID | OBD_MD_FLTYPE |
1261                                          OBD_MD_FLMODE | OBD_MD_FLFLAGS |
1262                                          OBD_MD_FLGROUP;
1263                 data.ioc_obdo2.o_misc = stripe_count;
1264                 data.ioc_obdo2.o_stripe_idx = stripe_index;
1265
1266                 if (total_count > 0) {
1267                         if ((total_count - count) > MD_STEP_COUNT)
1268                                 data.ioc_count = MD_STEP_COUNT;
1269                         else
1270                                 data.ioc_count = total_count - count;
1271                 } else {
1272                         data.ioc_count = MD_STEP_COUNT;
1273                 }
1274
1275                 if (cmd == ECHO_MD_CREATE || cmd == ECHO_MD_MKDIR) {
1276                         /*Allocate fids for the create */
1277                         rc = jt_obd_alloc_fids(&fid_space, &fid,
1278                                                &data.ioc_count);
1279                         if (rc) {
1280                                 fprintf(stderr, "Allocate fids error %d.\n",
1281                                         rc);
1282                                 return rc;
1283                         }
1284                         data.ioc_obdo1.o_oi.oi_fid = fid;
1285                 }
1286
1287                 child_base_id += data.ioc_count;
1288                 count += data.ioc_count;
1289
1290                 memset(buf, 0, sizeof(rawbuf));
1291                 rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
1292                 if (rc) {
1293                         fprintf(stderr, "error: %s: invalid ioctl %d\n",
1294                                 jt_cmdname(argv[0]), rc);
1295                         return rc;
1296                 }
1297
1298                 rc = l_ioctl(OBD_DEV_ID, OBD_IOC_ECHO_MD, buf);
1299                 if (rc) {
1300                         fprintf(stderr, "error: %s: %s\n",
1301                                 jt_cmdname(argv[0]), strerror(rc = errno));
1302                         return rc;
1303                 }
1304                 shmem_bump(data.ioc_count);
1305
1306                 gettimeofday(&end_time, NULL);
1307                 diff = difftime(&end_time, &start);
1308                 if (seconds > 0 && (__u64)diff > seconds)
1309                         break;
1310
1311                 if (count >= total_count && total_count > 0)
1312                         break;
1313         }
1314
1315         if (count > 0 && version) {
1316                 gettimeofday(&end_time, NULL);
1317                 diff = difftime(&end_time, &start);
1318                 printf("%s: %d in %.3fs (%.3f /s): %s",
1319                        jt_cmdname(argv[0]), count, diff,
1320                        (double)count / diff, ctime(&end_time.tv_sec));
1321         }
1322
1323 #ifdef MAX_THREADS
1324         if (thread) {
1325                 shmem_lock();
1326                 shmem_end_time_locked();
1327                 shmem_unlock();
1328         }
1329 #endif
1330         return rc;
1331 }
1332
1333 int jt_obd_test_create(int argc, char **argv)
1334 {
1335         return jt_obd_md_common(argc, argv, ECHO_MD_CREATE);
1336 }
1337
1338 int jt_obd_test_mkdir(int argc, char **argv)
1339 {
1340         return jt_obd_md_common(argc, argv, ECHO_MD_MKDIR);
1341 }
1342
1343 int jt_obd_test_destroy(int argc, char **argv)
1344 {
1345         return jt_obd_md_common(argc, argv, ECHO_MD_DESTROY);
1346 }
1347
1348 int jt_obd_test_rmdir(int argc, char **argv)
1349 {
1350         return jt_obd_md_common(argc, argv, ECHO_MD_RMDIR);
1351 }
1352
1353 int jt_obd_test_lookup(int argc, char **argv)
1354 {
1355         return jt_obd_md_common(argc, argv, ECHO_MD_LOOKUP);
1356 }
1357
1358 int jt_obd_test_setxattr(int argc, char **argv)
1359 {
1360         return jt_obd_md_common(argc, argv, ECHO_MD_SETATTR);
1361 }
1362
1363 int jt_obd_test_md_getattr(int argc, char **argv)
1364 {
1365         return jt_obd_md_common(argc, argv, ECHO_MD_GETATTR);
1366 }
1367
1368 int jt_obd_create(int argc, char **argv)
1369 {
1370         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
1371         struct obd_ioctl_data data;
1372         struct timeval next_time;
1373         __u64 count = 1, next_count, base_id = 1;
1374         int verbose = 1, mode = 0100644, rc = 0, i;
1375         char *end;
1376
1377         memset(&data, 0, sizeof(data));
1378         data.ioc_dev = cur_device;
1379         if (argc < 2 || argc > 4)
1380                 return CMD_HELP;
1381
1382         count = strtoull(argv[1], &end, 0);
1383         if (*end) {
1384                 fprintf(stderr, "error: %s: invalid iteration count '%s'\n",
1385                         jt_cmdname(argv[0]), argv[1]);
1386                 return CMD_HELP;
1387         }
1388
1389         if (argc > 2) {
1390                 mode = strtoul(argv[2], &end, 0);
1391                 if (*end) {
1392                         fprintf(stderr, "error: %s: invalid mode '%s'\n",
1393                                 jt_cmdname(argv[0]), argv[2]);
1394                         return CMD_HELP;
1395                 }
1396                 if (!(mode & S_IFMT))
1397                         mode |= S_IFREG;
1398         }
1399
1400         if (argc > 3) {
1401                 verbose = get_verbose(argv[0], argv[3]);
1402                 if (verbose == BAD_VERBOSE)
1403                         return CMD_HELP;
1404         }
1405
1406         printf("%s: %jd objects\n", jt_cmdname(argv[0]), (uintmax_t)count);
1407         gettimeofday(&next_time, NULL);
1408         next_time.tv_sec -= verbose;
1409
1410         ostid_set_seq_echo(&data.ioc_obdo1.o_oi);
1411         for (i = 1, next_count = verbose; i <= count && shmem_running(); i++) {
1412                 /*
1413                  * base_id is 1 so we don't need to worry about it being
1414                  * greater than OBIF_MAX_OID
1415                  */
1416                 data.ioc_obdo1.o_oi.oi_fid.f_oid = base_id;
1417                 data.ioc_obdo1.o_mode = mode;
1418                 data.ioc_obdo1.o_uid = 0;
1419                 data.ioc_obdo1.o_gid = 0;
1420                 data.ioc_obdo1.o_projid = 0;
1421                 data.ioc_obdo1.o_valid = OBD_MD_FLTYPE | OBD_MD_FLMODE |
1422                                          OBD_MD_FLID | OBD_MD_FLUID |
1423                                          OBD_MD_FLGID | OBD_MD_FLGROUP |
1424                                          OBD_MD_FLPROJID;
1425
1426                 memset(buf, 0, sizeof(rawbuf));
1427                 rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
1428                 if (rc) {
1429                         fprintf(stderr, "error: %s: invalid ioctl\n",
1430                                 jt_cmdname(argv[0]));
1431                         return rc;
1432                 }
1433                 rc = l_ioctl(OBD_DEV_ID, OBD_IOC_CREATE, buf);
1434                 llapi_ioctl_unpack(&data, buf, sizeof(rawbuf));
1435                 shmem_bump(1);
1436                 if (rc < 0) {
1437                         fprintf(stderr, "error: %s: #%d - %s\n",
1438                                 jt_cmdname(argv[0]), i, strerror(rc = errno));
1439                         break;
1440                 }
1441                 if (!(data.ioc_obdo1.o_valid & OBD_MD_FLID)) {
1442                         fprintf(stderr, "error: %s: oid not valid #%d:%#jx\n",
1443                                 jt_cmdname(argv[0]), i,
1444                                 (uintmax_t)data.ioc_obdo1.o_valid);
1445                         rc = EINVAL;
1446                         break;
1447                 }
1448
1449                 if (be_verbose(verbose, &next_time, i, &next_count, count))
1450                         printf("%s: #%d is object id %#jx\n",
1451                                jt_cmdname(argv[0]), i,
1452                                (uintmax_t)ostid_id(&data.ioc_obdo1.o_oi));
1453         }
1454
1455         return rc;
1456 }
1457
1458 int jt_obd_setattr(int argc, char **argv)
1459 {
1460         struct obd_ioctl_data data;
1461         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
1462         __u64 objid;
1463         char *end;
1464         int mode;
1465         int rc;
1466
1467         memset(&data, 0, sizeof(data));
1468         data.ioc_dev = cur_device;
1469         if (argc != 2)
1470                 return CMD_HELP;
1471
1472         objid = strtoull(argv[1], &end, 0);
1473         if (*end) {
1474                 fprintf(stderr, "error: %s: objid '%s' is not a number\n",
1475                         jt_cmdname(argv[0]), argv[1]);
1476                 return CMD_HELP;
1477         }
1478
1479         if (objid > OBIF_MAX_OID) {
1480                 fprintf(stderr, "error: %s: invalid objid '%s'\n",
1481                         jt_cmdname(argv[0]), argv[1]);
1482                 return CMD_HELP;
1483         }
1484
1485         mode = strtoul(argv[2], &end, 0);
1486         if (*end) {
1487                 fprintf(stderr, "error: %s: invalid mode '%s'\n",
1488                         jt_cmdname(argv[0]), argv[2]);
1489                 return CMD_HELP;
1490         }
1491
1492         ostid_set_seq_echo(&data.ioc_obdo1.o_oi);
1493         data.ioc_obdo1.o_mode = S_IFREG | mode;
1494         data.ioc_obdo1.o_oi.oi_fid.f_oid = objid;
1495         data.ioc_obdo1.o_valid = OBD_MD_FLID | OBD_MD_FLTYPE | OBD_MD_FLMODE;
1496
1497         memset(buf, 0, sizeof(rawbuf));
1498         rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
1499         if (rc) {
1500                 fprintf(stderr, "error: %s: invalid ioctl\n",
1501                         jt_cmdname(argv[0]));
1502                 return rc;
1503         }
1504         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_SETATTR, buf);
1505         if (rc < 0)
1506                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
1507                         strerror(rc = errno));
1508
1509         return rc;
1510 }
1511
1512 int jt_obd_test_setattr(int argc, char **argv)
1513 {
1514         struct obd_ioctl_data data;
1515         struct timeval start, next_time;
1516         __u64 i, count, next_count;
1517         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
1518         int verbose = 1;
1519         __u64 objid = 3;
1520         char *end;
1521         int rc = 0;
1522
1523         if (argc < 2 || argc > 4)
1524                 return CMD_HELP;
1525
1526         memset(&data, 0, sizeof(data));
1527         data.ioc_dev = cur_device;
1528         count = strtoull(argv[1], &end, 0);
1529         if (*end) {
1530                 fprintf(stderr, "error: %s: invalid iteration count '%s'\n",
1531                         jt_cmdname(argv[0]), argv[1]);
1532                 return CMD_HELP;
1533         }
1534
1535         if (argc >= 3) {
1536                 verbose = get_verbose(argv[0], argv[2]);
1537                 if (verbose == BAD_VERBOSE)
1538                         return CMD_HELP;
1539         }
1540
1541         if (argc >= 4) {
1542                 if (argv[3][0] == 't') {
1543                         objid = strtoull(argv[3] + 1, &end, 0);
1544                         if (thread)
1545                                 objid += thread - 1;
1546                 } else {
1547                         objid = strtoull(argv[3], &end, 0);
1548                 }
1549                 if (*end) {
1550                         fprintf(stderr, "error: %s: invalid objid '%s'\n",
1551                                 jt_cmdname(argv[0]), argv[3]);
1552                         return CMD_HELP;
1553                 }
1554         }
1555
1556         gettimeofday(&start, NULL);
1557         next_time.tv_sec = start.tv_sec - verbose;
1558         next_time.tv_usec = start.tv_usec;
1559         if (verbose != 0)
1560                 printf("%s: setting %jd attrs (objid %#jx): %s",
1561                        jt_cmdname(argv[0]), (uintmax_t)count,
1562                        (uintmax_t)objid, ctime(&start.tv_sec));
1563
1564         ostid_set_seq_echo(&data.ioc_obdo1.o_oi);
1565         for (i = 1, next_count = verbose; i <= count && shmem_running(); i++) {
1566                 if (objid > OBIF_MAX_OID) {
1567                         fprintf(stderr, "errr: %s: invalid objid '%llu'\n",
1568                                 jt_cmdname(argv[0]), (unsigned long long)objid);
1569                         return -E2BIG;
1570                 }
1571
1572                 data.ioc_obdo1.o_oi.oi_fid.f_oid = objid;
1573                 data.ioc_obdo1.o_mode = S_IFREG;
1574                 data.ioc_obdo1.o_valid = OBD_MD_FLID | OBD_MD_FLTYPE |
1575                                          OBD_MD_FLMODE;
1576                 memset(buf, 0, sizeof(rawbuf));
1577                 rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
1578                 if (rc) {
1579                         fprintf(stderr, "error: %s: invalid ioctl\n",
1580                                 jt_cmdname(argv[0]));
1581                         return rc;
1582                 }
1583                 rc = l_ioctl(OBD_DEV_ID, OBD_IOC_SETATTR, &data);
1584                 shmem_bump(1);
1585                 if (rc < 0) {
1586                         fprintf(stderr, "error: %s: #%jd - %d:%s\n",
1587                                 jt_cmdname(argv[0]), (uintmax_t)i,
1588                                 errno, strerror(rc = errno));
1589                         break;
1590                 }
1591                 if (be_verbose(verbose, &next_time, i, &next_count, count))
1592                         printf("%s: set attr #%jd\n",
1593                                jt_cmdname(argv[0]), (uintmax_t)i);
1594         }
1595
1596         if (!rc) {
1597                 struct timeval end;
1598                 double diff;
1599
1600                 gettimeofday(&end, NULL);
1601
1602                 diff = difftime(&end, &start);
1603
1604                 --i;
1605                 if (verbose != 0)
1606                         printf("%s: %jd attrs in %.3fs (%.3f attr/s): %s",
1607                                jt_cmdname(argv[0]), (uintmax_t)i, diff,
1608                                i / diff, ctime(&end.tv_sec));
1609         }
1610         return rc;
1611 }
1612
1613 int jt_obd_destroy(int argc, char **argv)
1614 {
1615         struct obd_ioctl_data data;
1616         struct timeval next_time;
1617         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
1618         __u64 count = 1, next_count;
1619         int verbose = 1;
1620         __u64 id;
1621         char *end;
1622         int rc = 0, i;
1623
1624         memset(&data, 0, sizeof(data));
1625         data.ioc_dev = cur_device;
1626         if (argc < 2 || argc > 4)
1627                 return CMD_HELP;
1628
1629         errno = 0;
1630         id = strtoull(argv[1], &end, 0);
1631         if (*end || id == 0 || errno != 0) {
1632                 fprintf(stderr, "error: %s: invalid objid '%s'\n",
1633                         jt_cmdname(argv[0]), argv[1]);
1634                 return CMD_HELP;
1635         }
1636         if (argc > 2) {
1637                 count = strtoull(argv[2], &end, 0);
1638                 if (*end) {
1639                         fprintf(stderr,
1640                                 "error: %s: invalid iteration count '%s'\n",
1641                                 jt_cmdname(argv[0]), argv[2]);
1642                         return CMD_HELP;
1643                 }
1644         }
1645
1646         if (argc > 3) {
1647                 verbose = get_verbose(argv[0], argv[3]);
1648                 if (verbose == BAD_VERBOSE)
1649                         return CMD_HELP;
1650         }
1651
1652         printf("%s: %jd objects\n", jt_cmdname(argv[0]), (uintmax_t)count);
1653         gettimeofday(&next_time, NULL);
1654         next_time.tv_sec -= verbose;
1655
1656         ostid_set_seq_echo(&data.ioc_obdo1.o_oi);
1657         for (i = 1, next_count = verbose; i <= count && shmem_running();
1658              i++, id++) {
1659                 if (id > OBIF_MAX_OID) {
1660                         fprintf(stderr, "errr: %s: invalid objid '%llu'\n",
1661                                 jt_cmdname(argv[0]), (unsigned long long)id);
1662                         return -E2BIG;
1663                 }
1664
1665                 data.ioc_obdo1.o_oi.oi_fid.f_oid = id;
1666                 data.ioc_obdo1.o_mode = S_IFREG | 0644;
1667                 data.ioc_obdo1.o_valid = OBD_MD_FLID | OBD_MD_FLMODE;
1668
1669                 memset(buf, 0, sizeof(rawbuf));
1670                 rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
1671                 if (rc) {
1672                         fprintf(stderr, "error: %s: invalid ioctl\n",
1673                                 jt_cmdname(argv[0]));
1674                         return rc;
1675                 }
1676                 rc = l_ioctl(OBD_DEV_ID, OBD_IOC_DESTROY, buf);
1677                 llapi_ioctl_unpack(&data, buf, sizeof(rawbuf));
1678                 shmem_bump(1);
1679                 if (rc < 0) {
1680                         fprintf(stderr, "error: %s: objid %#jx: %s\n",
1681                                 jt_cmdname(argv[0]), (uintmax_t)id,
1682                                 strerror(rc = errno));
1683                         break;
1684                 }
1685
1686                 if (be_verbose(verbose, &next_time, i, &next_count, count))
1687                         printf("%s: #%d is object id %#jx\n",
1688                                jt_cmdname(argv[0]), i, (uintmax_t)id);
1689         }
1690
1691         return rc;
1692 }
1693
1694 static int jt_str_to_ost_id(const char *str, struct ost_id *oi)
1695 {
1696         __u64 oid;
1697         char *end;
1698
1699         oid = strtoull(str, &end, 0);
1700         if (*end == '\0') {
1701                 /* If str is a single number then assume old echo
1702                  * client usage. */
1703                 if (oid > OBIF_MAX_OID)
1704                         return -EINVAL;
1705
1706                 ostid_set_seq_echo(oi);
1707                 oi->oi_fid.f_oid = oid;
1708                 return 0;
1709         }
1710
1711         return llapi_fid_parse(str, &oi->oi_fid, NULL);
1712 }
1713
1714 int jt_obd_getattr(int argc, char **argv)
1715 {
1716         struct obd_ioctl_data data;
1717         struct obdo *oa;
1718         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
1719         int rc;
1720
1721         if (argc != 2)
1722                 return CMD_HELP;
1723
1724         memset(&data, 0, sizeof(data));
1725         data.ioc_dev = cur_device;
1726         oa = &data.ioc_obdo1;
1727
1728         rc = jt_str_to_ost_id(argv[1], &oa->o_oi);
1729         if (rc < 0) {
1730                 fprintf(stderr, "error: %s: invalid objid of FID '%s'\n",
1731                         jt_cmdname(argv[0]), argv[1]);
1732                 return CMD_HELP;
1733         }
1734
1735         oa->o_valid = OBD_MD_FLID | OBD_MD_FLGROUP;
1736
1737         memset(buf, 0, sizeof(rawbuf));
1738         rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
1739         if (rc) {
1740                 fprintf(stderr, "error: %s: invalid ioctl\n",
1741                         jt_cmdname(argv[0]));
1742                 return rc;
1743         }
1744         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_GETATTR, buf);
1745         llapi_ioctl_unpack(&data, buf, sizeof(rawbuf));
1746         if (rc) {
1747                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
1748                         strerror(rc = errno));
1749                 return rc;
1750         }
1751
1752 #define OP4(bits, name, format, value)                                  \
1753         do {                                                            \
1754                 if ((oa->o_valid & (bits)) == (bits))                   \
1755                         printf("%s: "format"\n", (name), value);        \
1756         } while (0)
1757
1758 #define OPM(bits, member, format)                                       \
1759         OP4(bits, #member, format, (uintmax_t)(oa->o_ ## member))
1760
1761 #define OPO(bits, member) OPM(bits, member, "%#jo")
1762 #define OPU(bits, member) OPM(bits, member, "%ju")
1763 #define OPX(bits, member) OPM(bits, member, "%#jx")
1764
1765         OPX(0, valid);
1766         OPX(OBD_MD_FLID | OBD_MD_FLGROUP, oi.oi.oi_id);
1767         OPX(OBD_MD_FLID | OBD_MD_FLGROUP, oi.oi.oi_seq);
1768         OP4(OBD_MD_FLID | OBD_MD_FLGROUP, "oi.oi_fid", DFID, PFID(&oa->o_oi.oi_fid));
1769         OPU(OBD_MD_FLATIME, atime);
1770         OPU(OBD_MD_FLMTIME, mtime);
1771         OPU(OBD_MD_FLCTIME, ctime);
1772         OPU(OBD_MD_FLSIZE, size);
1773         OPU(OBD_MD_FLBLOCKS, blocks);
1774         OPU(OBD_MD_FLBLKSZ, blksize);
1775         OPO(OBD_MD_FLMODE | OBD_MD_FLTYPE, mode);
1776         OPU(OBD_MD_FLUID, uid);
1777         OPU(OBD_MD_FLGID, gid);
1778         OPU(OBD_MD_FLFLAGS, flags);
1779         OPU(OBD_MD_FLNLINK, nlink);
1780         OPX(OBD_MD_FLPARENT | OBD_MD_FLFID, parent_seq);
1781         OPX(OBD_MD_FLPARENT | OBD_MD_FLFID, parent_oid);
1782         OPX(OBD_MD_FLPARENT | OBD_MD_FLFID, parent_ver);
1783         OPU(OBD_MD_LAYOUT_VERSION, layout_version);
1784         OPU(OBD_MD_FLGRANT, grant);
1785         OPU(OBD_MD_FLPROJID, projid);
1786         OPU(OBD_MD_FLDATAVERSION, data_version);
1787 #undef OP4
1788 #undef OPM
1789 #undef OPO
1790 #undef OPU
1791 #undef OPX
1792
1793         return 0;
1794 }
1795
1796 int jt_obd_test_getattr(int argc, char **argv)
1797 {
1798         struct obd_ioctl_data data;
1799         struct timeval start, next_time;
1800         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
1801         __u64 i, count, next_count;
1802         int verbose = 1;
1803         __u64 objid = 3;
1804         char *end;
1805         int rc = 0;
1806
1807         if (argc < 2 || argc > 4)
1808                 return CMD_HELP;
1809
1810         memset(&data, 0, sizeof(data));
1811         data.ioc_dev = cur_device;
1812         count = strtoull(argv[1], &end, 0);
1813         if (*end) {
1814                 fprintf(stderr, "error: %s: invalid iteration count '%s'\n",
1815                         jt_cmdname(argv[0]), argv[1]);
1816                 return CMD_HELP;
1817         }
1818
1819         if (argc >= 3) {
1820                 verbose = get_verbose(argv[0], argv[2]);
1821                 if (verbose == BAD_VERBOSE)
1822                         return CMD_HELP;
1823         }
1824
1825         if (argc >= 4) {
1826                 if (argv[3][0] == 't') {
1827                         objid = strtoull(argv[3] + 1, &end, 0);
1828                         if (thread)
1829                                 objid += thread - 1;
1830                 } else {
1831                         objid = strtoull(argv[3], &end, 0);
1832                 }
1833                 if (*end) {
1834                         fprintf(stderr, "error: %s: invalid objid '%s'\n",
1835                                 jt_cmdname(argv[0]), argv[3]);
1836                         return CMD_HELP;
1837                 }
1838         }
1839
1840         gettimeofday(&start, NULL);
1841         next_time.tv_sec = start.tv_sec - verbose;
1842         next_time.tv_usec = start.tv_usec;
1843         if (verbose != 0)
1844                 printf("%s: getting %jd attrs (objid %#jx): %s",
1845                        jt_cmdname(argv[0]), (uintmax_t)count,
1846                        (uintmax_t)objid, ctime(&start.tv_sec));
1847
1848         ostid_set_seq_echo(&data.ioc_obdo1.o_oi);
1849         for (i = 1, next_count = verbose; i <= count && shmem_running(); i++) {
1850                 if (objid > OBIF_MAX_OID) {
1851                         fprintf(stderr, "errr: %s: invalid objid '%llu'\n",
1852                                 jt_cmdname(argv[0]), (unsigned long long)objid);
1853                         return -E2BIG;
1854                 }
1855
1856                 data.ioc_obdo1.o_oi.oi_fid.f_oid = objid;
1857                 data.ioc_obdo1.o_mode = S_IFREG;
1858                 data.ioc_obdo1.o_valid = 0xffffffff;
1859                 memset(buf, 0, sizeof(rawbuf));
1860                 rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
1861                 if (rc) {
1862                         fprintf(stderr, "error: %s: invalid ioctl\n",
1863                                 jt_cmdname(argv[0]));
1864                         return rc;
1865                 }
1866                 rc = l_ioctl(OBD_DEV_ID, OBD_IOC_GETATTR, &data);
1867                 shmem_bump(1);
1868                 if (rc < 0) {
1869                         fprintf(stderr, "error: %s: #%jd - %d:%s\n",
1870                                 jt_cmdname(argv[0]), (uintmax_t)i,
1871                                 errno, strerror(rc = errno));
1872                         break;
1873                 }
1874                 if (be_verbose(verbose, &next_time, i, &next_count, count))
1875                         printf("%s: got attr #%jd\n",
1876                                jt_cmdname(argv[0]), (uintmax_t)i);
1877         }
1878
1879         if (!rc) {
1880                 struct timeval end;
1881                 double diff;
1882
1883                 gettimeofday(&end, NULL);
1884
1885                 diff = difftime(&end, &start);
1886
1887                 --i;
1888                 if (verbose != 0)
1889                         printf("%s: %jd attrs in %.3fs (%.3f attr/s): %s",
1890                                jt_cmdname(argv[0]), (uintmax_t)i, diff,
1891                                i / diff, ctime(&end.tv_sec));
1892         }
1893
1894         return rc;
1895 }
1896
1897 /*
1898  * test_brw <cnt>                                               count
1899  *      <r|w[r(repeat)x(noverify)]>                             mode
1900  *      <q|v|#(print interval)>                                 verbosity
1901  *      <npages[+offset]>                                       blocksize
1902  *      <[[<interleave_threads>]t(inc obj by thread#)]obj>      object
1903  *      [p|g<args>]                                             batch
1904  */
1905 int jt_obd_test_brw(int argc, char **argv)
1906 {
1907         struct obd_ioctl_data data;
1908         struct timeval start, next_time;
1909         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
1910         __u64 count, next_count, len, stride, thr_offset = 0, objid = 3;
1911         int write = 0, verbose = 1, cmd, i, rc = 0, pages = 1;
1912         int offset_pages = 0;
1913         long n;
1914         int repeat_offset = 0;
1915         unsigned long long ull;
1916         int  nthr_per_obj = 0;
1917         int  verify = 1;
1918         int  obj_idx = 0;
1919         char *end;
1920
1921         if (argc < 2 || argc > 7) {
1922                 fprintf(stderr, "error: %s: bad number of arguments: %d\n",
1923                         jt_cmdname(argv[0]), argc);
1924                 return CMD_HELP;
1925         }
1926
1927         count = strtoull(argv[1], &end, 0);
1928         if (*end) {
1929                 fprintf(stderr, "error: %s: bad iteration count '%s'\n",
1930                         jt_cmdname(argv[0]), argv[1]);
1931                 return CMD_HELP;
1932         }
1933
1934         if (argc >= 3) {
1935                 if (argv[2][0] == 'w' || argv[2][0] == '1')
1936                         write = 1;
1937                 /* else it's a read */
1938
1939                 if (argv[2][0] != 0)
1940                         for (i = 1; argv[2][i] != 0; i++)
1941                                 switch (argv[2][i]) {
1942                                 case 'r':
1943                                         repeat_offset = 1;
1944                                         break;
1945
1946                                 case 'x':
1947                                         verify = 0;
1948                                         break;
1949
1950                                 default:
1951                                         fprintf(stderr,
1952                                                 "Can't parse cmd '%s'\n",
1953                                                 argv[2]);
1954                                         return CMD_HELP;
1955                                 }
1956         }
1957
1958         if (argc >= 4) {
1959                 verbose = get_verbose(argv[0], argv[3]);
1960                 if (verbose == BAD_VERBOSE)
1961                         return CMD_HELP;
1962         }
1963
1964         if (argc >= 5) {
1965                 pages = strtoul(argv[4], &end, 0);
1966
1967                 if (*end == '+')
1968                         offset_pages = strtoul(end + 1, &end, 0);
1969
1970                 if (*end != 0 || offset_pages < 0 || offset_pages >= pages) {
1971                         fprintf(stderr, "error: %s: bad npages[+offset] parameter '%s'\n",
1972                                 jt_cmdname(argv[0]), argv[4]);
1973                         return CMD_HELP;
1974                 }
1975         }
1976
1977         if (argc >= 6) {
1978                 if (thread && (n = strtol(argv[5], &end, 0)) > 0 &&
1979                     *end == 't' && (ull = strtoull(end + 1, &end, 0)) > 0 &&
1980                     *end == 0) {
1981                         nthr_per_obj = n;
1982                         objid = ull;
1983                 } else if (thread && argv[5][0] == 't') {
1984                         nthr_per_obj = 1;
1985                         objid = strtoull(argv[5] + 1, &end, 0);
1986                 } else {
1987                         nthr_per_obj = 0;
1988                         objid = strtoull(argv[5], &end, 0);
1989                 }
1990                 if (*end) {
1991                         fprintf(stderr, "error: %s: bad objid '%s'\n",
1992                                 jt_cmdname(argv[0]), argv[5]);
1993                         return CMD_HELP;
1994                 }
1995         }
1996
1997         memset(&data, 0, sizeof(data));
1998         data.ioc_dev = cur_device;
1999
2000         /*
2001          * communicate the 'type' of brw test and batching to echo_client.
2002          * don't start.  we'd love to refactor this lctl->echo_client
2003          * interface
2004          */
2005         data.ioc_pbuf1 = (void *)1;
2006         data.ioc_plen1 = 1;
2007
2008         if (argc >= 7) {
2009                 switch (argv[6][0]) {
2010                 case 'g': /* plug and unplug */
2011                         data.ioc_pbuf1 = (void *)2;
2012                         data.ioc_plen1 = strtoull(argv[6] + 1, &end, 0);
2013                         break;
2014                 case 'p': /* prep and commit */
2015                         data.ioc_pbuf1 = (void *)3;
2016                         data.ioc_plen1 = strtoull(argv[6] + 1, &end, 0);
2017                         break;
2018                 default:
2019                         fprintf(stderr,
2020                                 "error: %s: batching '%s' needs to specify 'p' or 'g'\n",
2021                                 jt_cmdname(argv[0]), argv[6]);
2022                         return CMD_HELP;
2023                 }
2024
2025                 if (*end) {
2026                         fprintf(stderr, "error: %s: bad batching '%s'\n",
2027                                 jt_cmdname(argv[0]), argv[6]);
2028                         return CMD_HELP;
2029                 }
2030                 data.ioc_plen1 *= getpagesize();
2031         }
2032
2033         len = pages * getpagesize();
2034         thr_offset = offset_pages * getpagesize();
2035         stride = len;
2036
2037 #ifdef MAX_THREADS
2038         if (thread) {
2039                 shmem_lock();
2040                 if (nthr_per_obj != 0) {
2041                         /* threads interleave */
2042                         obj_idx = (thread - 1) / nthr_per_obj;
2043                         objid += obj_idx;
2044                         stride *= nthr_per_obj;
2045                         if ((thread - 1) % nthr_per_obj == 0) {
2046                                 shared_data->body.offsets[obj_idx] =
2047                                         stride + thr_offset;
2048                         }
2049                         thr_offset += ((thread - 1) % nthr_per_obj) * len;
2050                 } else {
2051                         /* threads disjoint */
2052                         thr_offset += (thread - 1) * len;
2053                 }
2054
2055                 shmem_start_time_locked();
2056                 shmem_unlock();
2057         }
2058 #endif
2059
2060         ostid_set_seq_echo(&data.ioc_obdo1.o_oi);
2061         if (objid > OBIF_MAX_OID) {
2062                 fprintf(stderr, "errr: %s: invalid objid '%llu'\n",
2063                         jt_cmdname(argv[0]), (unsigned long long)objid);
2064                 return -E2BIG;
2065         }
2066
2067         data.ioc_obdo1.o_oi.oi_fid.f_oid = objid;
2068         data.ioc_obdo1.o_mode = S_IFREG;
2069         data.ioc_obdo1.o_valid = OBD_MD_FLID | OBD_MD_FLTYPE | OBD_MD_FLMODE |
2070                                  OBD_MD_FLFLAGS | OBD_MD_FLGROUP;
2071         data.ioc_obdo1.o_flags = (verify ? OBD_FL_DEBUG_CHECK : 0);
2072         data.ioc_count = len;
2073         data.ioc_offset = (repeat_offset ? 0 : thr_offset);
2074
2075         gettimeofday(&start, NULL);
2076         next_time.tv_sec = start.tv_sec - verbose;
2077         next_time.tv_usec = start.tv_usec;
2078
2079         if (verbose != 0)
2080                 printf("%s: %s %jux%d pages (obj %#jx, off %ju): %s",
2081                        jt_cmdname(argv[0]), write ? "writing" : "reading",
2082                        (uintmax_t)count, pages, (uintmax_t)objid,
2083                        (uintmax_t)data.ioc_offset, ctime(&start.tv_sec));
2084
2085         cmd = write ? OBD_IOC_BRW_WRITE : OBD_IOC_BRW_READ;
2086         for (i = 1, next_count = verbose; i <= count && shmem_running(); i++) {
2087                 data.ioc_obdo1.o_valid &= ~(OBD_MD_FLBLOCKS | OBD_MD_FLGRANT);
2088                 memset(buf, 0, sizeof(rawbuf));
2089                 rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
2090                 if (rc) {
2091                         fprintf(stderr, "error: %s: invalid ioctl\n",
2092                                 jt_cmdname(argv[0]));
2093                         return rc;
2094                 }
2095                 rc = l_ioctl(OBD_DEV_ID, cmd, buf);
2096                 shmem_bump(1);
2097                 if (rc) {
2098                         fprintf(stderr, "error: %s: #%d - %s on %s\n",
2099                                 jt_cmdname(argv[0]), i, strerror(rc = errno),
2100                                 write ? "write" : "read");
2101                         break;
2102                 } else if (be_verbose(verbose, &next_time, i,
2103                                       &next_count, count)) {
2104                         shmem_lock();
2105                         printf("%s: %s number %d @ %jd:%ju for %d\n",
2106                                jt_cmdname(argv[0]), write ? "write" : "read", i,
2107                                (uintmax_t)ostid_id(&data.ioc_obdo1.o_oi),
2108                                (uintmax_t)data.ioc_offset,
2109                                (int)(pages * getpagesize()));
2110                         shmem_unlock();
2111                 }
2112
2113                 if (!repeat_offset) {
2114 #ifdef MAX_THREADS
2115                         if (stride == len) {
2116                                 data.ioc_offset += stride;
2117                         } else if (i < count) {
2118                                 shmem_lock();
2119                                 data.ioc_offset =
2120                                         shared_data->body.offsets[obj_idx];
2121                                 shared_data->body.offsets[obj_idx] += len;
2122                                 shmem_unlock();
2123                         }
2124 #else
2125                         data.ioc_offset += len;
2126                         obj_idx = 0; /* avoids an unused var warning */
2127 #endif
2128                 }
2129         }
2130
2131         if (!rc) {
2132                 struct timeval end;
2133                 double diff;
2134
2135                 gettimeofday(&end, NULL);
2136
2137                 diff = difftime(&end, &start);
2138
2139                 --i;
2140                 if (verbose != 0)
2141                         printf("%s: %s %dx%d pages in %.3fs (%.3f MB/s): %s",
2142                                jt_cmdname(argv[0]), write ? "wrote" : "read",
2143                                i, pages, diff,
2144                                ((double)i * pages * getpagesize()) /
2145                                (diff * 1048576.0), ctime(&end.tv_sec));
2146         }
2147
2148 #ifdef MAX_THREADS
2149         if (thread) {
2150                 shmem_lock();
2151                 shmem_end_time_locked();
2152                 shmem_unlock();
2153         }
2154 #endif
2155         return rc;
2156 }
2157
2158 static int do_activate(int argc, char **argv, int flag)
2159 {
2160         struct obd_ioctl_data data;
2161         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
2162         int rc;
2163
2164         memset(&data, 0, sizeof(data));
2165         data.ioc_dev = cur_device;
2166         if (argc != 1)
2167                 return CMD_HELP;
2168
2169         /* reuse offset for 'active' */
2170         data.ioc_offset = flag;
2171
2172         memset(buf, 0, sizeof(rawbuf));
2173         rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
2174         if (rc) {
2175                 fprintf(stderr, "error: %s: invalid ioctl\n",
2176                         jt_cmdname(argv[0]));
2177                 return rc;
2178         }
2179         rc = l_ioctl(OBD_DEV_ID, IOC_OSC_SET_ACTIVE, buf);
2180         if (rc)
2181                 fprintf(stderr, "error: %s: failed: %s\n",
2182                         jt_cmdname(argv[0]), strerror(rc = errno));
2183
2184         return rc;
2185 }
2186
2187 /**
2188  * Replace nids for given device.
2189  * lctl replace_nids <devicename> <nid1>[,nid2,nid3]
2190  * Command should be started on MGS server.
2191  * Only MGS server should be started (command execution
2192  * returns error in another cases). Command mount
2193  * -t lustre <MDT partition> -o nosvc <mount point>
2194  * can be used for that.
2195  *
2196  * llogs for MDTs and clients are processed. All
2197  * records copied as is except add_uuid and setup. This records
2198  * are skipped and recorded with new nids and uuid.
2199  *
2200  * \see mgs_replace_nids
2201  * \see mgs_replace_log
2202  * \see mgs_replace_nids_handler
2203  */
2204 int jt_replace_nids(int argc, char **argv)
2205 {
2206         int rc;
2207         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
2208         struct obd_ioctl_data data;
2209
2210         memset(&data, 0, sizeof(data));
2211         data.ioc_dev = get_mgs_device();
2212         if (argc != 3)
2213                 return CMD_HELP;
2214
2215         data.ioc_inllen1 = strlen(argv[1]) + 1;
2216         data.ioc_inlbuf1 = argv[1];
2217
2218         data.ioc_inllen2 = strlen(argv[2]) + 1;
2219         data.ioc_inlbuf2 = argv[2];
2220         memset(buf, 0, sizeof(rawbuf));
2221         rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
2222         if (rc) {
2223                 fprintf(stderr, "error: %s: invalid ioctl\n",
2224                         jt_cmdname(argv[0]));
2225                 return rc;
2226         }
2227
2228         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_REPLACE_NIDS, buf);
2229         if (rc < 0) {
2230                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
2231                         strerror(rc = errno));
2232         }
2233
2234         return rc;
2235 }
2236
2237 int jt_obd_deactivate(int argc, char **argv)
2238 {
2239         return do_activate(argc, argv, 0);
2240 }
2241
2242 int jt_obd_activate(int argc, char **argv)
2243 {
2244         return do_activate(argc, argv, 1);
2245 }
2246
2247 int jt_obd_recover(int argc, char **argv)
2248 {
2249         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
2250         struct obd_ioctl_data data;
2251         int rc;
2252
2253         memset(&data, 0, sizeof(data));
2254         data.ioc_dev = cur_device;
2255         if (argc > 2)
2256                 return CMD_HELP;
2257
2258         if (argc == 2) {
2259                 data.ioc_inllen1 = strlen(argv[1]) + 1;
2260                 data.ioc_inlbuf1 = argv[1];
2261         }
2262
2263         memset(buf, 0, sizeof(rawbuf));
2264         rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
2265         if (rc) {
2266                 fprintf(stderr, "error: %s: invalid ioctl\n",
2267                         jt_cmdname(argv[0]));
2268                 return rc;
2269         }
2270         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_CLIENT_RECOVER, buf);
2271         if (rc < 0) {
2272                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
2273                         strerror(rc = errno));
2274         }
2275
2276         return rc;
2277 }
2278
2279 int jt_obd_mdc_lookup(int argc, char **argv)
2280 {
2281         struct obd_ioctl_data data;
2282         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
2283         char *parent, *child;
2284         int rc, fd, verbose = 1;
2285
2286         if (argc < 3 || argc > 4)
2287                 return CMD_HELP;
2288
2289         parent = argv[1];
2290         child = argv[2];
2291         if (argc == 4)
2292                 verbose = get_verbose(argv[0], argv[3]);
2293
2294         memset(&data, 0, sizeof(data));
2295         data.ioc_dev = cur_device;
2296
2297         data.ioc_inllen1 = strlen(child) + 1;
2298         data.ioc_inlbuf1 = child;
2299
2300         memset(buf, 0, sizeof(rawbuf));
2301         rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
2302         if (rc) {
2303                 fprintf(stderr, "error: %s: invalid ioctl\n",
2304                         jt_cmdname(argv[0]));
2305                 return rc;
2306         }
2307
2308         fd = open(parent, O_RDONLY);
2309         if (fd < 0) {
2310                 fprintf(stderr, "open \"%s\" failed: %s\n", parent,
2311                         strerror(errno));
2312                 return -1;
2313         }
2314
2315         rc = ioctl(fd, IOC_MDC_LOOKUP, buf);
2316         if (rc < 0) {
2317                 fprintf(stderr, "error: %s: ioctl error: %s\n",
2318                         jt_cmdname(argv[0]), strerror(rc = errno));
2319         }
2320         close(fd);
2321
2322         if (verbose) {
2323                 rc = llapi_ioctl_unpack(&data, buf, sizeof(rawbuf));
2324                 if (rc) {
2325                         fprintf(stderr, "error: %s: invalid reply\n",
2326                                 jt_cmdname(argv[0]));
2327                         return rc;
2328                 }
2329                 printf("%s: mode %o uid %d gid %d\n",
2330                        child, data.ioc_obdo1.o_mode, data.ioc_obdo1.o_uid,
2331                        data.ioc_obdo1.o_gid);
2332         }
2333
2334         return rc;
2335 }
2336
2337 #ifdef HAVE_SERVER_SUPPORT
2338 /**
2339  * Clear config logs for given device or filesystem.
2340  * lctl clear_conf <devicename|fsname>
2341  * Command has to be run on MGS node having MGS device mounted with -o
2342  * nosvc.
2343  *
2344  * Configuration logs for filesystem or one particular log is
2345  * processed. New log is created, original log is read, its records
2346  * marked SKIP do not get copied to new log. Others are copied as-is.
2347  * Original file is renamed to log.${time}.bak.
2348  *
2349  * \see mgs_clear_configs
2350  * \see mgs_replace_log
2351  * \see mgs_clear_config_handler
2352  **/
2353 int jt_lcfg_clear(int argc, char **argv)
2354 {
2355         int rc;
2356         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
2357         struct obd_ioctl_data data;
2358
2359         memset(&data, 0, sizeof(data));
2360         data.ioc_dev = get_mgs_device();
2361         if (argc != 2)
2362                 return CMD_HELP;
2363
2364         data.ioc_inllen1 = strlen(argv[1]) + 1;
2365         data.ioc_inlbuf1 = argv[1];
2366
2367         memset(buf, 0, sizeof(rawbuf));
2368         rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
2369         if (rc) {
2370                 fprintf(stderr, "error: %s: invalid ioctl\n",
2371                         jt_cmdname(argv[0]));
2372                 return rc;
2373         }
2374
2375         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_CLEAR_CONFIGS, buf);
2376         if (rc < 0) {
2377                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
2378                         strerror(rc = errno));
2379         }
2380
2381         return rc;
2382 }
2383
2384 int jt_lcfg_fork(int argc, char **argv)
2385 {
2386         struct obd_ioctl_data data;
2387         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
2388         int rc;
2389
2390         if (argc != 3)
2391                 return CMD_HELP;
2392
2393         memset(&data, 0, sizeof(data));
2394         data.ioc_dev = get_mgs_device();
2395         data.ioc_inllen1 = strlen(argv[1]) + 1;
2396         data.ioc_inlbuf1 = argv[1];
2397         data.ioc_inllen2 = strlen(argv[2]) + 1;
2398         data.ioc_inlbuf2 = argv[2];
2399
2400         memset(buf, 0, sizeof(rawbuf));
2401         rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
2402         if (rc) {
2403                 fprintf(stderr, "error: %s: invalid ioctl\n",
2404                         jt_cmdname(argv[0]));
2405                 return rc;
2406         }
2407
2408         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_LCFG_FORK, buf);
2409         if (rc < 0)
2410                 fprintf(stderr, "error: %s: OBD_IOC_LCFG_FORK failed: %s\n",
2411                         jt_cmdname(argv[0]), strerror(errno));
2412
2413         return rc;
2414 }
2415
2416 int jt_lcfg_erase(int argc, char **argv)
2417 {
2418         struct obd_ioctl_data data;
2419         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
2420         int rc;
2421
2422         if (argc == 3) {
2423                 if (strncmp(argv[2], "-q", strlen("-q")) != 0 &&
2424                     strncmp(argv[2], "--quiet", strlen("--quiet")) != 0)
2425                         return CMD_HELP;
2426         } else if (argc != 2) {
2427                 return CMD_HELP;
2428         }
2429
2430         memset(&data, 0, sizeof(data));
2431         data.ioc_dev = get_mgs_device();
2432         data.ioc_inllen1 = strlen(argv[1]) + 1;
2433         data.ioc_inlbuf1 = argv[1];
2434
2435         memset(buf, 0, sizeof(rawbuf));
2436         rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
2437         if (rc) {
2438                 fprintf(stderr, "error: %s: invalid ioctl\n",
2439                         jt_cmdname(argv[0]));
2440                 return rc;
2441         }
2442
2443         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_LCFG_ERASE, buf);
2444         if (rc < 0)
2445                 fprintf(stderr, "error: %s: OBD_IOC_LCFG_ERASE failed: %s\n",
2446                         jt_cmdname(argv[0]), strerror(errno));
2447
2448         return rc;
2449 }
2450 #else /* !HAVE_SERVER_SUPPORT */
2451 int jt_lcfg_clear(int argc, char **argv)
2452 {
2453         if (argc != 2)
2454                 return CMD_HELP;
2455
2456         fprintf(stderr, "error: %s: invalid ioctl\n",
2457                 jt_cmdname(argv[0]));
2458         return -EOPNOTSUPP;
2459 }
2460
2461 int jt_lcfg_fork(int argc, char **argv)
2462 {
2463         if (argc != 3)
2464                 return CMD_HELP;
2465
2466         fprintf(stderr, "error: %s: invalid ioctl\n",
2467                 jt_cmdname(argv[0]));
2468         return -EOPNOTSUPP;
2469 }
2470
2471 int jt_lcfg_erase(int argc, char **argv)
2472 {
2473         if (argc != 3)
2474                 return CMD_HELP;
2475
2476         fprintf(stderr, "error: %s: invalid ioctl\n",
2477                 jt_cmdname(argv[0]));
2478         return -EOPNOTSUPP;
2479 }
2480 #endif /* HAVE_SERVER_SUPPORT */
2481
2482 enum llog_default_dev_op {
2483         LLOG_DFLT_MGS_SET = 0,
2484         LLOG_DFLT_DEV_RESET
2485 };
2486
2487 static int llog_default_device(enum llog_default_dev_op op)
2488 {
2489         int rc = 0;
2490         static int dflt_dev = -1;
2491
2492         if (op == LLOG_DFLT_MGS_SET && (cur_device == -1)) {
2493                 char mgs[] = "$MGS";
2494
2495                 rc = do_device("llog_default_device", mgs);
2496                 dflt_dev = cur_device;
2497
2498         } else if (op == LLOG_DFLT_DEV_RESET && (dflt_dev != -1)) {
2499                 do_disconnect(NULL, 1);
2500                 dflt_dev = -1;
2501         }
2502
2503         return rc;
2504 }
2505
2506 static int llog_catlist_next(int index, char *buf, size_t buflen)
2507 {
2508         struct obd_ioctl_data data;
2509         int rc;
2510
2511         memset(&data, 0, sizeof(data));
2512         data.ioc_dev = cur_device;
2513         data.ioc_inllen1 = buflen - __ALIGN_KERNEL(sizeof(data), 8);
2514         data.ioc_count = index;
2515         memset(buf, 0, buflen);
2516         rc = llapi_ioctl_pack(&data, &buf, buflen);
2517         if (rc < 0) {
2518                 fprintf(stderr, "error: invalid llapi_ioctl_pack: %s\n",
2519                         strerror(errno));
2520                 return rc;
2521         }
2522         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_CATLOGLIST, buf);
2523         if (rc < 0) {
2524                 fprintf(stderr, "OBD_IOC_CATLOGLIST failed: %s\n",
2525                         strerror(errno));
2526                 return rc;
2527         }
2528         return ((struct obd_ioctl_data *)buf)->ioc_count;
2529 }
2530
2531 int jt_llog_catlist(int argc, char **argv)
2532 {
2533         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
2534         char *tmp = NULL;
2535         int start = 0;
2536
2537         if (argc != 1)
2538                 return CMD_HELP;
2539
2540         if (llog_default_device(LLOG_DFLT_MGS_SET))
2541                 return CMD_INCOMPLETE;
2542
2543         do {
2544                 start = llog_catlist_next(start, rawbuf, sizeof(rawbuf));
2545                 if (start < 0)
2546                         break;
2547                 tmp = ((struct obd_ioctl_data *)buf)->ioc_bulk;
2548                 if (strlen(tmp) > 0)
2549                         fprintf(stdout, "%s", tmp);
2550                 else
2551                         break;
2552         } while (start);
2553
2554         llog_default_device(LLOG_DFLT_DEV_RESET);
2555
2556         return start;
2557 }
2558
2559 int jt_llog_info(int argc, char **argv)
2560 {
2561         const struct option long_opts[] = {
2562         /* Allow optional "--catalog" for compatibility with llog commands. */
2563         { .val = 'c',   .name = "catalog",      .has_arg = required_argument },
2564         { .val = 'h',   .name = "help",         .has_arg = no_argument },
2565         { .name = NULL } };
2566         struct obd_ioctl_data data = { 0 };
2567         char rawbuf[MAX_IOC_BUFLEN] = "", *buf = rawbuf;
2568         char *cmd = argv[0];
2569         char *catalog = NULL;
2570         int rc, c;
2571
2572         while ((c = getopt_long(argc, argv, "c:h", long_opts, NULL)) != -1) {
2573                 switch (c) {
2574                 case 'c':
2575                         catalog = optarg;
2576                         break;
2577                 case 'h':
2578                 default:
2579                         return CMD_HELP;
2580                 }
2581         }
2582         argc -= optind;
2583         argv += optind;
2584         /* support "logname" positional parameter */
2585         if (argc == 1) {
2586                 if (catalog) {
2587                         fprintf(stderr,
2588                                 "%s: catalog is set, unknown argument '%s'\n",
2589                                 cmd, optarg);
2590                         return CMD_HELP;
2591                 }
2592                 catalog = argv[0];
2593         } else if (!catalog || argc > 1) {
2594                 return CMD_HELP;
2595         }
2596
2597         /* Manage default device */
2598         if (llog_default_device(LLOG_DFLT_MGS_SET))
2599                 return CMD_INCOMPLETE;
2600
2601         data.ioc_dev = cur_device;
2602         data.ioc_inllen1 = strlen(catalog) + 1;
2603         data.ioc_inlbuf1 = catalog;
2604         data.ioc_inllen2 = sizeof(rawbuf) - __ALIGN_KERNEL(sizeof(data), 8) -
2605                            __ALIGN_KERNEL(data.ioc_inllen1, 8);
2606         rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
2607         if (rc) {
2608                 fprintf(stderr, "%s: ioctl_pack failed for catalog '%s': %s\n",
2609                         jt_cmdname(cmd), catalog, strerror(-rc));
2610                 goto err;
2611         }
2612
2613         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_LLOG_INFO, buf);
2614         if (rc == 0)
2615                 fprintf(stdout, "%s", ((struct obd_ioctl_data *)buf)->ioc_bulk);
2616         else
2617                 fprintf(stderr, "%s: OBD_IOC_LLOG_INFO failed: %s\n",
2618                         jt_cmdname(cmd), strerror(errno));
2619
2620 err:
2621         llog_default_device(LLOG_DFLT_DEV_RESET);
2622
2623         return rc;
2624 }
2625
2626 int jt_llog_print_cb(const char *record, void *private)
2627 {
2628         printf("%s\n", record);
2629
2630         return 0;
2631 }
2632
2633 static int
2634 llog_process_records(int (record_cb)(const char *record, void *private),
2635                      const char *record, void *private, bool reverse)
2636 {
2637         char *ptr = NULL;
2638         char *tmp = NULL;
2639         int rc = 0;
2640
2641         if (!reverse) {
2642                 do {
2643                         ptr = strchr(record, '\n');
2644                         if (ptr)
2645                                 *ptr = '\0';
2646                         rc = record_cb(record, private);
2647                         if (rc)
2648                                 goto out;
2649                         if (ptr)
2650                                 record = ptr + 1;
2651                 } while (ptr && *(ptr + 1));
2652         } else {
2653                 tmp = (char *)record;
2654
2655                 ptr = strrchr(record, '\n');
2656                 if (ptr)
2657                         *ptr = '\0';
2658                 else
2659                         goto out;
2660                 while ((ptr = strrchr(record, '\n'))) {
2661                         tmp = ptr + 1;
2662                         *ptr = '\0';
2663                         rc = record_cb(tmp, private);
2664                         if (rc)
2665                                 goto out;
2666                 };
2667                 rc = record_cb(record, private);
2668                 if (rc)
2669                         goto out;
2670         }
2671 out:
2672         return rc;
2673 }
2674
2675 /**
2676  * Iterate over llog records, typically YAML-formatted configuration logs
2677  *
2678  * \param logname[in]   name of llog file or FID
2679  * \param start[in]     first record to process
2680  * \param end[in]       last record to process (inclusive)
2681  * \param cb[in]        callback for records. Return -ve error, or +ve abort.
2682  * \param private[in,out] private data passed to the \a record_cb function
2683  * \param reverse[in]   print the llog records from the beginning or the end
2684  *
2685  * \retval              0 on success
2686  *                      others handled by the caller
2687  */
2688 int jt_llog_print_iter(char *logname, long start, long end,
2689                        int (record_cb)(const char *record, void *private),
2690                        void *private, bool reverse, bool raw)
2691 {
2692         struct obd_ioctl_data data = { 0 };
2693         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
2694         char startbuf[16], endbuf[16];
2695         static long inc = sizeof(rawbuf) / 128;
2696         long rec;
2697         int rc = 0;
2698
2699         /* default end of indexes is max indexes in a llog bitmap */
2700         if (end == -1)
2701                 end = LLOG_MIN_CHUNK_SIZE * 8 - 1;
2702
2703         data.ioc_dev = cur_device;
2704         data.ioc_inlbuf1 = logname;
2705         data.ioc_inllen1 = strlen(logname) + 1;
2706
2707         /*
2708          * Estimate about 128 characters per configuration record.  Not all
2709          * records will be printed in any case, so they should easily fit.  If
2710          * not, the kernel will return -EOVERFLOW and ask for fewer records.
2711          *
2712          * We don't want to request records from the kernel one-at-a-time, as
2713          * it restarts the config llog iteration from the beginning, so we
2714          * fetch multiple records from the kernel per call and split locally.
2715          */
2716         for (rec = start; rec < end; rec += inc) {
2717                 char *record = ((struct obd_ioctl_data *)buf)->ioc_bulk;
2718                 __u32 *is_llog_eof = &((struct obd_ioctl_data *)buf)->ioc_u32_2;
2719
2720 retry:
2721                 snprintf(startbuf, sizeof(startbuf), "%lu", rec);
2722                 snprintf(endbuf, sizeof(endbuf), "%lu",
2723                          end < rec + inc - 1 ? end : rec + inc - 1);
2724
2725                 data.ioc_u32_1 = raw ? 1 : 0;
2726                 /* start and end record numbers are passed as ASCII digits */
2727                 data.ioc_inlbuf2 = startbuf;
2728                 data.ioc_inllen2 = strlen(startbuf) + 1;
2729                 data.ioc_inlbuf3 = endbuf;
2730                 data.ioc_inllen3 = strlen(endbuf) + 1;
2731
2732                 data.ioc_inllen4 = sizeof(rawbuf) -
2733                         __ALIGN_KERNEL(sizeof(data), 8) -
2734                         __ALIGN_KERNEL(data.ioc_inllen1, 8) -
2735                         __ALIGN_KERNEL(data.ioc_inllen2, 8) -
2736                         __ALIGN_KERNEL(data.ioc_inllen3, 8);
2737                 memset(buf, 0, sizeof(rawbuf));
2738                 rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
2739                 if (rc) {
2740                         fprintf(stderr, "%s: invalid ioctl data\n", logname);
2741                         goto out;
2742                 }
2743
2744                 rc = l_ioctl(OBD_DEV_ID, OBD_IOC_LLOG_PRINT, buf);
2745                 if (rc == -EOVERFLOW && inc > 2) {
2746                         inc /= 2;
2747                         goto retry;
2748                 }
2749                 if (rc) {
2750                         fprintf(stderr, "%s: OBD_IOC_LLOG_PRINT failed: %s\n",
2751                                 logname, strerror(errno));
2752                         rc = -errno;
2753                         goto out;
2754                 }
2755
2756                 /* record was not modified -> all indexes are skipped */
2757                 if (strcmp(record, logname) != 0)
2758                         rc = llog_process_records(record_cb, record, private,
2759                                                   reverse);
2760                 if (rc)
2761                         goto out;
2762
2763                 /* end of llog file ? */
2764                 if (*is_llog_eof)
2765                         break;
2766         }
2767
2768 out:
2769         return rc;
2770 }
2771
2772 static int llog_parse_catalog_options(int *argc, char ***argv, char **catalog,
2773                                       long *start, long *end, int *raw)
2774 {
2775         const struct option long_opts[] = {
2776         /* the --catalog option is not required, just for consistency */
2777         { .val = 'c',   .name = "catalog",      .has_arg = required_argument },
2778         { .val = 'e',   .name = "end",          .has_arg = required_argument },
2779         { .val = 'h',   .name = "help",         .has_arg = no_argument },
2780         { .val = 'r',   .name = "raw",          .has_arg = no_argument },
2781         { .val = 's',   .name = "start",        .has_arg = required_argument },
2782         { .name = NULL } };
2783         char *cmd = (*argv)[0];
2784         char *endp;
2785         int c;
2786
2787         if (!catalog || !start || !end)
2788                 return -EINVAL;
2789
2790         /* now process command line arguments*/
2791         while ((c = getopt_long(*argc, *argv, "c:e:hrs:",
2792                                 long_opts, NULL)) != -1) {
2793                 switch (c) {
2794                 case 'c':
2795                         *catalog = optarg;
2796                         break;
2797                 case 'e':
2798                         *end = strtol(optarg, &endp, 0);
2799                         if (*endp != '\0') {
2800                                 fprintf(stderr, "%s: bad end value '%s'\n",
2801                                         cmd, optarg);
2802                                 return CMD_HELP;
2803                         }
2804                         break;
2805                 case 'r':
2806                         if (!raw)
2807                                 return CMD_HELP;
2808                         *raw = 1;
2809                         break;
2810                 case 's':
2811                         *start = strtol(optarg, &endp, 0);
2812                         if (*endp != '\0') {
2813                                 fprintf(stderr, "%s: bad start value '%s'\n",
2814                                         cmd, optarg);
2815                                 return CMD_HELP;
2816                         }
2817                         break;
2818                 case 'h':
2819                 default:
2820                         return CMD_HELP;
2821                 }
2822         }
2823         *argc -= optind;
2824         *argv += optind;
2825
2826         /*
2827          * support old optional positional parameters only if they were
2828          * not already specified with named arguments: logname [start [end]]
2829          */
2830         if (*argc >= 1) {
2831                 if (*catalog) {
2832                         fprintf(stderr,
2833                                 "%s: logname is set, unknown argument '%s'\n",
2834                                 cmd, (*argv)[0]);
2835                         return CMD_HELP;
2836                 }
2837                 *catalog = (*argv)[0];
2838                 (*argc)--;
2839                 (*argv)++;
2840         }
2841
2842         if (*catalog == NULL) {
2843                 fprintf(stderr, "%s: no logname specified\n", cmd);
2844                 return CMD_HELP;
2845         }
2846
2847         if (*argc >= 1) {
2848                 if (*start != 1) {
2849                         fprintf(stderr,
2850                                 "%s: --start is set, unknown argument '%s'\n",
2851                                 cmd, (*argv)[0]);
2852                         return CMD_HELP;
2853                 }
2854
2855                 *start = strtol((*argv)[0], &endp, 0);
2856                 if (*endp != '\0') {
2857                         fprintf(stderr, "%s: bad start value '%s'\n",
2858                                 cmd, (*argv)[0]);
2859                         return CMD_HELP;
2860                 }
2861                 (*argc)--;
2862                 (*argv)++;
2863         }
2864         if (*argc >= 1) {
2865                 if (*end != -1) {
2866                         fprintf(stderr,
2867                                 "%s: --end is set, unknown argument '%s'\n",
2868                                 cmd, (*argv)[0]);
2869                         return CMD_HELP;
2870                 }
2871
2872                 *end = strtol((*argv)[0], &endp, 0);
2873                 if (*endp != '\0') {
2874                         fprintf(stderr, "%s: bad end value '%s'\n",
2875                                 cmd, (*argv)[0]);
2876                         return CMD_HELP;
2877                 }
2878                 (*argc)--;
2879                 (*argv)++;
2880         }
2881         if (*argc > 1) {
2882                 fprintf(stderr, "%s: unknown argument '%s'\n", cmd, (*argv)[0]);
2883                 return CMD_HELP;
2884         }
2885
2886         if (*end != -1 && *end < *start) {
2887                 fprintf(stderr, "%s: end '%lu' less than than start '%lu'\n",
2888                         cmd, *end, *start);
2889                 return CMD_HELP;
2890         }
2891
2892         return 0;
2893 }
2894
2895 int jt_llog_print(int argc, char **argv)
2896 {
2897         char *catalog = NULL;
2898         long start = 1, end = -1;
2899         int raw = 0;
2900         int rc;
2901
2902         rc = llog_parse_catalog_options(&argc, &argv, &catalog, &start, &end,
2903                                         &raw);
2904         if (rc)
2905                 return rc;
2906
2907         if (llog_default_device(LLOG_DFLT_MGS_SET))
2908                 return CMD_INCOMPLETE;
2909
2910         rc = jt_llog_print_iter(catalog, start, end, jt_llog_print_cb,
2911                                 NULL, false, !!raw);
2912
2913         llog_default_device(LLOG_DFLT_DEV_RESET);
2914
2915         return rc;
2916 }
2917
2918 /*
2919  * Parse catalog, log ID, and optionally a log index with either optional
2920  * arguments or positional arguments.  Only the initial catalog argument
2921  * may be positional with other optional arguments.
2922  *
2923  * The positional arguments option should eventually be phased out.
2924  */
2925 static int llog_parse_catalog_log_idx(int *argc, char ***argv, const char *opts,
2926                                       struct obd_ioctl_data *data)
2927 {
2928         const struct option long_opts[] = {
2929         /* the --catalog option is not required, just for consistency */
2930         { .val = 'c',   .name = "catalog",      .has_arg = required_argument },
2931         { .val = 'h',   .name = "help",         .has_arg = no_argument },
2932         { .val = 'i',   .name = "log_idx",      .has_arg = required_argument },
2933         { .val = 'l',   .name = "log_id",       .has_arg = required_argument },
2934         { .name = NULL } };
2935         int c;
2936
2937         /* sanity check */
2938         if (!data || *argc <= 1)
2939                 return -1;
2940
2941         data->ioc_dev = cur_device;
2942
2943         /* now process command line arguments*/
2944         while ((c = getopt_long(*argc, *argv, opts, long_opts, NULL)) != -1) {
2945                 switch (c) {
2946                 case 'c':
2947                         data->ioc_inllen1 = strlen(optarg) + 1;
2948                         data->ioc_inlbuf1 = optarg;
2949                         break;
2950                 case 'i':
2951                         data->ioc_inllen3 = strlen(optarg) + 1;
2952                         data->ioc_inlbuf3 = optarg;
2953                         break;
2954                 case 'l': /* The log_id option isn't currently needed for
2955                            * cancel as mdt_iocontrol() handles IOC_LLOG_CANCEL,
2956                            * but we may as well keep it for now.
2957                            */
2958                         data->ioc_inllen2 = strlen(optarg) + 1;
2959                         data->ioc_inlbuf2 = optarg;
2960                         break;
2961                 case 'h':
2962                 default:
2963                         return CMD_HELP;
2964                 }
2965         }
2966
2967         *argc -= optind;
2968         *argv += optind;
2969
2970         /* Allow catalog to be specified as first option without --catalog */
2971         if (!data->ioc_inlbuf1 && *argc > 0) {
2972                 data->ioc_inlbuf1 = (*argv)[0];
2973                 data->ioc_inllen1 = strlen((*argv)[0]) + 1;
2974                 (*argc)--;
2975                 (*argv)++;
2976         }
2977
2978         return 0;
2979 }
2980
2981 int jt_llog_cancel(int argc, char **argv)
2982 {
2983         struct obd_ioctl_data data = { 0 };
2984         char rawbuf[MAX_IOC_BUFLEN] = "", *buf = rawbuf;
2985         char *cmd = argv[0];
2986         int rc;
2987
2988         /* Manage default device */
2989         if (llog_default_device(LLOG_DFLT_MGS_SET))
2990                 return CMD_INCOMPLETE;
2991
2992         /* Parse catalog file (in inlbuf1) and named parameters */
2993         rc = llog_parse_catalog_log_idx(&argc, &argv, "c:hi:l:", &data);
2994
2995         /*
2996          * Handle old positional parameters if not using named parameters,
2997          * either "<catalog> <log_idx>" or "<catalog> <log_id> <log_idx>".
2998          * It was "inlbuf3 = log_idx", and "inlbuf2 = log_id" (ignored by
2999          * config log cancel), and shows why I hate positional parameters.
3000          */
3001         if (argc == 1) {
3002                 data.ioc_inllen3 = strlen(argv[0]) + 1;
3003                 data.ioc_inlbuf3 = argv[0];
3004         } else if (argc == 2) {
3005                 data.ioc_inllen2 = strlen(argv[0]) + 1;
3006                 data.ioc_inlbuf2 = argv[0];
3007                 data.ioc_inllen3 = strlen(argv[1]) + 1;
3008                 data.ioc_inlbuf3 = argv[1];
3009         }
3010
3011         if (!data.ioc_inlbuf1 || !data.ioc_inlbuf3) {
3012                 /* missing mandatory parameters */
3013                 rc = CMD_HELP;
3014                 goto err;
3015         }
3016
3017         rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
3018         if (rc) {
3019                 fprintf(stderr, "%s: ioctl_pack for catalog '%s' failed: %s\n",
3020                         jt_cmdname(cmd), data.ioc_inlbuf1, strerror(-rc));
3021                 goto err;
3022         }
3023
3024         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_LLOG_CANCEL, buf);
3025         if (rc)
3026                 fprintf(stderr, "%s: cancel catalog '%s:%s' failed: %s\n",
3027                         jt_cmdname(cmd), data.ioc_inlbuf1, data.ioc_inlbuf3,
3028                         strerror(errno));
3029
3030 err:
3031         llog_default_device(LLOG_DFLT_DEV_RESET);
3032         return rc;
3033 }
3034
3035 int jt_llog_check(int argc, char **argv)
3036 {
3037         struct obd_ioctl_data data = { 0 };
3038         char rawbuf[MAX_IOC_BUFLEN] = "", *buf = rawbuf;
3039         char *catalog = NULL;
3040         char startbuf[16], endbuf[16];
3041         long start = 1, end = -1;
3042         char *cmd = argv[0];
3043         int rc;
3044
3045         rc = llog_parse_catalog_options(&argc, &argv, &catalog, &start,
3046                                         &end, NULL);
3047         if (rc)
3048                 return rc;
3049
3050         if (llog_default_device(LLOG_DFLT_MGS_SET))
3051                 return CMD_INCOMPLETE;
3052
3053         if (end == -1)
3054                 end = 0x7fffffff;
3055
3056         data.ioc_dev = cur_device;
3057         data.ioc_inllen1 = strlen(catalog) + 1;
3058         data.ioc_inlbuf1 = catalog;
3059
3060         snprintf(startbuf, sizeof(startbuf), "%lu", start);
3061         snprintf(endbuf, sizeof(endbuf), "%lu", end);
3062         /* start and end record numbers are passed as ASCII digits */
3063         data.ioc_inllen2 = strlen(startbuf) + 1;
3064         data.ioc_inlbuf2 = startbuf;
3065         data.ioc_inllen3 = strlen(endbuf) + 1;
3066         data.ioc_inlbuf3 = endbuf;
3067
3068         data.ioc_inllen4 = sizeof(rawbuf) - __ALIGN_KERNEL(sizeof(data), 8) -
3069                            __ALIGN_KERNEL(data.ioc_inllen1, 8) -
3070                            __ALIGN_KERNEL(data.ioc_inllen2, 8) -
3071                            __ALIGN_KERNEL(data.ioc_inllen3, 8);
3072         rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
3073         if (rc) {
3074                 fprintf(stderr, "%s: ioctl_pack failed for catalog '%s': %s\n",
3075                         jt_cmdname(cmd), data.ioc_inlbuf1, strerror(-rc));
3076                 goto err;
3077         }
3078
3079         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_LLOG_CHECK, buf);
3080         if (rc == 0)
3081                 fprintf(stdout, "%s", ((struct obd_ioctl_data *)buf)->ioc_bulk);
3082         else
3083                 fprintf(stderr, "%s: OBD_IOC_LLOG_CHECK failed: %s\n",
3084                         jt_cmdname(cmd), strerror(errno));
3085 err:
3086         llog_default_device(LLOG_DFLT_DEV_RESET);
3087         return rc;
3088 }
3089
3090 int jt_llog_remove(int argc, char **argv)
3091 {
3092         struct obd_ioctl_data data = { 0 };
3093         char rawbuf[MAX_IOC_BUFLEN] = "", *buf = rawbuf;
3094         char *cmd = argv[0];
3095         int rc;
3096
3097         if (llog_default_device(LLOG_DFLT_MGS_SET))
3098                 return CMD_INCOMPLETE;
3099
3100         rc = llog_parse_catalog_log_idx(&argc, &argv, "c:hl:", &data);
3101         if (rc)
3102                 goto err;
3103
3104         if (argc == 1) {
3105                 if (data.ioc_inlbuf2) {
3106                         fprintf(stderr,
3107                                 "%s: --log_id is set, unknown argument '%s'\n",
3108                                 jt_cmdname(cmd), argv[0]);
3109                         rc = CMD_HELP;
3110                         goto err;
3111                 }
3112
3113                 data.ioc_inllen2 = strlen(argv[0]) + 1;
3114                 data.ioc_inlbuf2 = argv[0];
3115         }
3116
3117         rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
3118         if (rc) {
3119                 fprintf(stderr, "%s: ioctl_pack for catalog '%s' failed: %s\n",
3120                         jt_cmdname(cmd), data.ioc_inlbuf1, strerror(-rc));
3121                 goto err;
3122         }
3123
3124         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_LLOG_REMOVE, buf);
3125         if (rc)
3126                 fprintf(stderr, "%s: cancel catalog '%s:%s' failed: %s\n",
3127                         jt_cmdname(cmd), data.ioc_inlbuf1, data.ioc_inlbuf2,
3128                         strerror(-rc));
3129
3130 err:
3131         llog_default_device(LLOG_DFLT_DEV_RESET);
3132         return rc;
3133 }
3134
3135 static void signal_server(int sig)
3136 {
3137         if (sig == SIGINT) {
3138                 do_disconnect("sigint", 1);
3139                 exit(1);
3140         } else {
3141                 fprintf(stderr, "%s: got signal %d\n", jt_cmdname("sigint"),
3142                         sig);
3143         }
3144 }
3145
3146 int obd_initialize(int argc, char **argv)
3147 {
3148         if (shmem_setup() != 0)
3149                 return -1;
3150
3151         register_ioc_dev(OBD_DEV_ID, OBD_DEV_PATH);
3152
3153         return 0;
3154 }
3155
3156 void obd_finalize(int argc, char **argv)
3157 {
3158         struct sigaction sigact;
3159
3160         /* sigact initialization */
3161         sigact.sa_handler = signal_server;
3162         sigfillset(&sigact.sa_mask);
3163         sigact.sa_flags = SA_RESTART;
3164         /* coverity[uninit_use_in_call] */
3165         sigaction(SIGINT, &sigact, NULL);
3166
3167         shmem_cleanup();
3168         do_disconnect(argv[0], 1);
3169 }
3170
3171 /**
3172  * Get the index of the last llog record
3173  *
3174  * logid:            [0x3:0xa:0x0]:0
3175  * flags:            4 (plain)
3176  * records_count:    57
3177  * last_index:       57
3178  *
3179  * \param logname[in]   pointer to config log name
3180  *
3181  * \retval              > 0 on success
3182  *                      <= 0 on error
3183  */
3184 static long llog_last_index(char *logname)
3185 {
3186         struct obd_ioctl_data data = { 0 };
3187         char rawbuf[MAX_IOC_BUFLEN] = "", *buf = rawbuf;
3188         char *last_index;
3189         long rc;
3190
3191         data.ioc_dev = cur_device;
3192         data.ioc_inllen1 = strlen(logname) + 1;
3193         data.ioc_inlbuf1 = logname;
3194         data.ioc_inllen2 = sizeof(rawbuf) - __ALIGN_KERNEL(sizeof(data), 8) -
3195                            __ALIGN_KERNEL(data.ioc_inllen1, 8);
3196         rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
3197         if (rc) {
3198                 fprintf(stderr, "%s: ioctl_pack failed for catalog '%s': %s\n",
3199                         __func__, logname, strerror(-rc));
3200                 return rc;
3201         }
3202
3203         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_LLOG_INFO, buf);
3204         if (rc == 0) {
3205                 last_index = strstr(((struct obd_ioctl_data *)buf)->ioc_bulk,
3206                                     "last_index:");
3207                 return strtol(last_index + 11, NULL, 10);
3208         }
3209
3210         rc = -errno;
3211
3212         return rc;
3213 }
3214
3215 static char *get_llog_event_name(__u32 cmd)
3216 {
3217 #ifdef HAVE_SERVER_SUPPORT
3218         struct lcfg_type_data *data;
3219
3220         data = lcfg_cmd2data(cmd);
3221         if (data)
3222                 return data->ltd_name;
3223 #endif
3224         return NULL;
3225 }
3226
3227 static char *get_event_filter(__u32 cmd)
3228 {
3229         char *event_name;
3230         char *filter = NULL;
3231         int len;
3232
3233         event_name = get_llog_event_name(cmd);
3234         if (event_name) {
3235                 /* 9 bytes for "event: , " */
3236                 len = 9 + strlen(event_name);
3237                 filter = malloc(len + 1);
3238                 if (!filter)
3239                         return NULL;
3240                 memset(filter, 0, len + 1);
3241                 snprintf(filter, len, "event: %s, ", event_name);
3242                 return filter;
3243         }
3244
3245         return NULL;
3246 }
3247
3248 /**
3249  * Callback to search ostname in llog
3250  * - { index: 23, event: attach, device: lustre-OST0000-osc, type: osc,
3251  *     UUID: lustre-clilov_UUID }
3252  * - { index: 24, event: setup, device: lustre-OST0000-osc,
3253  *     UUID: lustre-OST0000_UUID, node: 192.168.0.120@tcp }
3254  * - { index: 25, event: add_osc, device: lustre-clilov,
3255  *     ost: lustre-OST0000_UUID, index: 0, gen: 1 }
3256  *
3257  * \param record[in]    pointer to llog record
3258  * \param data[in]      pointer to ostname
3259  *
3260  * \retval              1 if ostname is found
3261  *                      0 if ostname is not found
3262  *                      -ENOENT if ostname is deleted
3263  */
3264 static int llog_search_ost_cb(const char *record, void *data)
3265 {
3266         char *ostname = data;
3267         char ost_filter[MAX_STRING_SIZE] = {'\0'};
3268         char *add_osc, *del_osc, *setup, *cleanup;
3269
3270         add_osc = get_event_filter(LCFG_LOV_ADD_OBD);
3271         del_osc = get_event_filter(LCFG_LOV_DEL_OBD);
3272         setup = get_event_filter(LCFG_SETUP);
3273         cleanup = get_event_filter(LCFG_CLEANUP);
3274         if (!add_osc || !del_osc || !setup || !cleanup)
3275                 return -ENOMEM;
3276
3277         if (ostname && ostname[0])
3278                 snprintf(ost_filter, sizeof(ost_filter), " %s,", ostname);
3279
3280         if (strstr(record, ost_filter)) {
3281                 if (strstr(record, add_osc) || strstr(record, setup))
3282                         return 1;
3283                 if (strstr(record, del_osc) || strstr(record, cleanup))
3284                         return -ENOENT;
3285         }
3286
3287         free(add_osc);
3288         free(del_osc);
3289         free(setup);
3290         free(cleanup);
3291
3292         return 0;
3293 }
3294
3295 /**
3296  * Search ost in llog
3297  *
3298  * \param logname[in]           pointer to config log name
3299  * \param last_index[in]        the index of the last llog record
3300  * \param ostname[in]           pointer to ost name
3301  *
3302  * \retval                      1 if ostname is found
3303  *                              0 if ostname is not found
3304  */
3305 static int llog_search_ost(char *logname, long last_index, char *ostname)
3306 {
3307         long start, end, inc = MAX_IOC_BUFLEN / 128;
3308         int rc = 0;
3309
3310         for (end = last_index; end > 1; end -= inc) {
3311                 start = end - inc > 0 ? end - inc : 1;
3312                 rc = jt_llog_print_iter(logname, start, end, llog_search_ost_cb,
3313                                         ostname, true, false);
3314                 if (rc)
3315                         break;
3316         }
3317
3318         return (rc == 1 ? 1 : 0);
3319 }
3320
3321 struct llog_del_ost_priv {
3322         char *logname;
3323         char *ostname;
3324         int found;
3325         int dryrun;
3326 };
3327
3328 /**
3329  * Callback to search and delete ostname in llog
3330  *
3331  * \param record[in]    pointer to llog record
3332  * \param data[in]      pointer to ostname
3333  *
3334  * \retval              1 if ostname is found and entry deleted
3335  *                      0 if ostname is not found
3336  *                      < 0 if error
3337  */
3338 static int llog_del_ost_cb(const char *record, void *data)
3339 {
3340         char ost_filter[MAX_STRING_SIZE] = {'\0'};
3341         char log_idxstr[MAX_STRING_SIZE] = {'\0'};
3342         long int log_idx = 0;
3343         struct llog_del_ost_priv *priv = data;
3344         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
3345         struct obd_ioctl_data ioc_data = { 0 };
3346         int rc = 0;
3347
3348         if (priv->ostname && priv->ostname[0])
3349                 snprintf(ost_filter, sizeof(ost_filter), " %s", priv->ostname);
3350
3351         if (!strstr(record, ost_filter))
3352                 return rc;
3353
3354         rc = sscanf(record, "- { index: %ld", &log_idx);
3355         if (rc < 0) {
3356                 fprintf(stderr, "error: record without index:\n%s\n",
3357                         record);
3358                 return 0;
3359         }
3360         snprintf(log_idxstr, sizeof(log_idxstr), "%ld", log_idx);
3361
3362         ioc_data.ioc_dev = cur_device;
3363         ioc_data.ioc_inllen1 = strlen(priv->logname) + 1;
3364         ioc_data.ioc_inlbuf1 = priv->logname;
3365         ioc_data.ioc_inllen3 = strlen(log_idxstr) + 1;
3366         ioc_data.ioc_inlbuf3 = log_idxstr;
3367
3368         rc = llapi_ioctl_pack(&ioc_data, &buf, sizeof(rawbuf));
3369         if (rc) {
3370                 fprintf(stderr, "ioctl_pack for catalog '%s' failed: %s\n",
3371                         ioc_data.ioc_inlbuf1, strerror(-rc));
3372                 return rc;
3373         }
3374
3375         if (priv->dryrun) {
3376                 fprintf(stdout, "[DRY RUN] cancel catalog '%s:%s':\"%s\"\n",
3377                         ioc_data.ioc_inlbuf1, ioc_data.ioc_inlbuf3, record);
3378         } else {
3379                 rc = l_ioctl(OBD_DEV_ID, OBD_IOC_LLOG_CANCEL, buf);
3380                 if (rc)
3381                         fprintf(stderr, "cancel catalog '%s:%s' failed: %s\n",
3382                                 ioc_data.ioc_inlbuf1, ioc_data.ioc_inlbuf3,
3383                                 strerror(errno));
3384                 else {
3385                         fprintf(stdout, "cancel catalog %s log_idx %ld: done\n",
3386                                 priv->logname, log_idx);
3387                         priv->found++;
3388                 }
3389         }
3390         return rc;
3391 }
3392
3393 /**
3394  * Search and delete ost in llog
3395  *
3396  * \param logname[in]           pointer to config log name
3397  * \param last_index[in]        the index of the last llog record
3398  * \param ostname[in]           pointer to ost name
3399  * \param dryrun[in]            dry run?
3400  *
3401  * \retval                      1 if ostname is found and deleted
3402  *                              0 if ostname is not found
3403  */
3404 static int llog_del_ost(char *logname, long last_index, char *ostname,
3405                         int dryrun)
3406 {
3407         long start, end, inc = MAX_IOC_BUFLEN / 128;
3408         int rc = 0;
3409         struct llog_del_ost_priv priv = { logname, ostname, false, dryrun };
3410
3411         for (end = last_index; end > 1; end -= inc) {
3412                 start = end - inc > 0 ? end - inc : 1;
3413                 rc = jt_llog_print_iter(logname, start, end, llog_del_ost_cb,
3414                                         &priv, true, false);
3415                 if (rc)
3416                         break;
3417         }
3418
3419         if (priv.found)
3420                 fprintf(stdout, "del_ost: cancelled %d catalog entries\n",
3421                         priv.found);
3422         else
3423                 fprintf(stdout, "del_ost: no catalog entry deleted\n");
3424
3425         return rc;
3426 }
3427
3428 struct llog_pool_data {
3429         char lpd_fsname[LUSTRE_MAXFSNAME + 1];
3430         char lpd_poolname[LOV_MAXPOOLNAME + 1];
3431         char lpd_ostname[MAX_OBD_NAME + 1];
3432         enum lcfg_command_type lpd_cmd_type;
3433         bool lpd_pool_exists;
3434         int lpd_ost_num;
3435 };
3436
3437 /**
3438  * Called for each formatted line in the config log (within range).
3439  *
3440  * - { index: 74, event: new_pool, device: tfs-clilov, fsname: tfs, pool: tmp }
3441  * - { index: 77, event: add_pool, device: tfs-clilov, fsname: tfs, pool: tmp,
3442  *     ost: tfs-OST0000_UUID }
3443  * - { index: 224, event: remove_pool, device: tfs-clilov, fsname: tfs,
3444  *     pool: tmp, ost: tfs-OST0003_UUID }
3445  * - { index: 227, event: del_pool, device: tfs-clilov, fsname: tfs, pool: tmp }
3446  *
3447  * \param record[in]    pointer to llog record
3448  * \param data[in]      pointer to llog_pool_data
3449  *
3450  * \retval              1 if pool or OST is found
3451  *                      0 if pool or OST is not found
3452  *                      -ENOENT if pool or OST is removed
3453  */
3454 static int llog_search_pool_cb(const char *record, void *data)
3455 {
3456         struct llog_pool_data *lpd = data;
3457         char pool_filter[MAX_STRING_SIZE] = "";
3458         char *new_pool, *del_pool, *add_pool, *rem_pool;
3459         char *found = NULL;
3460         int fs_pool_len = 0, rc = 0;
3461
3462         new_pool = get_event_filter(LCFG_POOL_NEW);
3463         del_pool = get_event_filter(LCFG_POOL_DEL);
3464         add_pool = get_event_filter(LCFG_POOL_ADD);
3465         rem_pool = get_event_filter(LCFG_POOL_REM);
3466         if (!new_pool || !del_pool || !add_pool || !rem_pool) {
3467                 rc = -ENOMEM;
3468                 goto out;
3469         }
3470
3471         fs_pool_len = 16 + strlen(lpd->lpd_fsname) + strlen(lpd->lpd_poolname);
3472         snprintf(pool_filter, fs_pool_len + 1, "fsname: %s, pool: %s",
3473                  lpd->lpd_fsname, lpd->lpd_poolname);
3474
3475         /* search poolname */
3476         found = strstr(record, pool_filter);
3477         if (found &&
3478             (found[fs_pool_len] == ' ' || found[fs_pool_len] == ',')) {
3479                 if (strstr(record, new_pool)) {
3480                         lpd->lpd_pool_exists = true;
3481                         rc = 1;
3482                         goto out;
3483                 }
3484                 if (strstr(record, del_pool)) {
3485                         lpd->lpd_pool_exists = false;
3486                         rc = -ENOENT;
3487                         goto out;
3488                 }
3489
3490                 if (lpd->lpd_cmd_type == LCFG_POOL_NEW ||
3491                     lpd->lpd_cmd_type == LCFG_POOL_DEL) {
3492                         /* In function mgs_pool_cmd(), a pool's pool_new/add
3493                          * record will be marked as "SKIP" if its pool_destroy/
3494                          * remove record is logged later. That means the "SKIP"
3495                          * record won't be printed here and thus lpd_ost_num
3496                          * doesn't need to be decreased as well.
3497                          */
3498                         if (strstr(record, add_pool))
3499                                 lpd->lpd_ost_num++;
3500                 } else if (lpd->lpd_ostname[0] != '\0') {
3501                         if (strstr(record, lpd->lpd_ostname)) {
3502                                 lpd->lpd_pool_exists = true;
3503                                 if (strstr(record, add_pool)) {
3504                                         lpd->lpd_ost_num = 1;
3505                                         rc = 1;
3506                                         goto out;
3507                                 }
3508                                 if (strstr(record, rem_pool)) {
3509                                         lpd->lpd_ost_num = 0;
3510                                         rc = -ENOENT;
3511                                         goto out;
3512                                 }
3513                         }
3514                 }
3515         }
3516 out:
3517         if (new_pool)
3518                 free(new_pool);
3519         if (del_pool)
3520                 free(del_pool);
3521         if (add_pool)
3522                 free(add_pool);
3523         if (rem_pool)
3524                 free(rem_pool);
3525
3526         return rc;
3527 }
3528
3529 /* Search pool and its ost in llog
3530  *
3531  * \param logname[in]           pointer to config log name
3532  * \param last_index[in]        the index of the last llog record
3533  * \param fsname[in]            pointer to filesystem name
3534  * \param poolname[in]          pointer pool name
3535  * \param ostname[in]           pointer to OST name(OSTnnnn-UUID)
3536  * \param cmd[in]               pool command type
3537  *
3538  * \retval                      < 0 on error
3539  *                              0 if pool is empty or OST is not found
3540  *                              1 if pool is not empty or OST is found
3541  */
3542 static int llog_search_pool(char *logname, long last_index, char *fsname,
3543                             char *poolname, char *ostname,
3544                             enum lcfg_command_type cmd)
3545 {
3546         struct llog_pool_data lpd;
3547         long start, end, inc = MAX_IOC_BUFLEN / 128;
3548         int rc = 0;
3549
3550         memset(&lpd, 0, sizeof(lpd));
3551         lpd.lpd_cmd_type = cmd;
3552         lpd.lpd_pool_exists = false;
3553         lpd.lpd_ost_num = 0;
3554         strncpy(lpd.lpd_fsname, fsname, sizeof(lpd.lpd_fsname) - 1);
3555         if (poolname && poolname[0])
3556                 strncpy(lpd.lpd_poolname, poolname,
3557                         sizeof(lpd.lpd_poolname) - 1);
3558         if (ostname && ostname[0])
3559                 strncpy(lpd.lpd_ostname, ostname, sizeof(lpd.lpd_ostname) - 1);
3560
3561         for (end = last_index; end > 1; end -= inc) {
3562                 start = end - inc > 0 ? end - inc : 1;
3563                 rc = jt_llog_print_iter(logname, start, end,
3564                                         llog_search_pool_cb, &lpd, true, false);
3565                 if (rc) {
3566                         if (rc == 1 && lpd.lpd_pool_exists)
3567                                 rc = lpd.lpd_ost_num ? 1 : 0;
3568                         else if (rc == -ENOENT && lpd.lpd_pool_exists &&
3569                                  !lpd.lpd_ost_num)
3570                                 rc = 0;
3571                         goto out;
3572                 }
3573         }
3574
3575         rc = -ENOENT;
3576 out:
3577         return rc;
3578 }
3579
3580 static bool combined_mgs_mds(char *fsname)
3581 {
3582         glob_t path;
3583         int rc;
3584
3585         rc = cfs_get_param_paths(&path, "mdt/%s-MDT0000", fsname);
3586         if (!rc)
3587                 cfs_free_param_data(&path);
3588
3589         if (get_mgs_device() > 0 && !rc)
3590                 return true;
3591
3592         return false;
3593 }
3594
3595 /*
3596  * if pool is NULL, search ostname in target_obd
3597  * if pool is not NULL:
3598  *  - if pool not found returns errno < 0
3599  *  - if ostname is NULL, returns 1 if pool is not empty and 0 if pool empty
3600  *  - if ostname is not NULL, returns 1 if OST is in pool and 0 if not
3601  */
3602 int lctl_search_ost(char *fsname, char *poolname, char *ostname,
3603                     enum lcfg_command_type cmd)
3604 {
3605         char logname[MAX_OBD_NAME] = {'\0'};
3606         long last_index;
3607
3608         if (fsname && fsname[0] == '\0')
3609                 fsname = NULL;
3610         if (!fsname)
3611                 return -EINVAL;
3612
3613         if (combined_mgs_mds(fsname))
3614                 return llapi_search_ost(fsname, poolname, ostname);
3615
3616         /* fetch the last_index of llog record */
3617         snprintf(logname, sizeof(logname), "%s-client", fsname);
3618         last_index = llog_last_index(logname);
3619         if (last_index < 0)
3620                 return last_index;
3621
3622         /* if pool is NULL, search ostname in target_obd */
3623         if (!poolname && ostname)
3624                 return llog_search_ost(logname, last_index, ostname);
3625
3626         return llog_search_pool(logname, last_index, fsname, poolname,
3627                                 ostname, cmd);
3628 }
3629
3630 static int check_pool_cmd(enum lcfg_command_type cmd, char *fsname,
3631                           char *poolname, char *ostname)
3632 {
3633         int rc;
3634
3635         rc = lctl_search_ost(fsname, poolname, ostname, cmd);
3636         if (rc < 0 && (cmd != LCFG_POOL_NEW)) {
3637                 fprintf(stderr, "Pool %s.%s not found\n",
3638                         fsname, poolname);
3639                 return rc;
3640         }
3641
3642         switch (cmd) {
3643         case LCFG_POOL_NEW: {
3644                 if (ostname)
3645                         return -EINVAL;
3646
3647                 if (rc >= 0) {
3648                         fprintf(stderr, "Pool %s.%s already exists\n",
3649                                 fsname, poolname);
3650                         return -EEXIST;
3651                 }
3652                 return 0;
3653         }
3654         case LCFG_POOL_DEL: {
3655                 if (ostname)
3656                         return -EINVAL;
3657
3658                 if (rc == 1) {
3659                         fprintf(stderr,
3660                                 "Pool %s.%s not empty, please remove all members\n",
3661                                 fsname, poolname);
3662                         return -ENOTEMPTY;
3663                 }
3664                 return 0;
3665         }
3666         case LCFG_POOL_ADD: {
3667                 if (rc == 1) {
3668                         fprintf(stderr, "OST %s is already in pool %s.%s\n",
3669                                 ostname, fsname, poolname);
3670                         return -EEXIST;
3671                 }
3672                 rc = lctl_search_ost(fsname, NULL, ostname, cmd);
3673                 if (rc == 0) {
3674                         fprintf(stderr, "OST %s is not part of the '%s' fs.\n",
3675                                 ostname, fsname);
3676                         return -ENOENT;
3677                 }
3678                 return 0;
3679         }
3680         case LCFG_POOL_REM: {
3681                 if (rc == 0) {
3682                         fprintf(stderr, "OST %s not found in pool %s.%s\n",
3683                                 ostname, fsname, poolname);
3684                         return -ENOENT;
3685                 }
3686                 return 0;
3687         }
3688         default:
3689                 break;
3690         } /* switch */
3691         return -EINVAL;
3692 }
3693
3694 /*
3695  * This check only verifies that the changes have been "pushed out" to
3696  * the client successfully.  This involves waiting for a config update,
3697  * and so may fail because of problems in that code or post-command
3698  * network loss. So reporting a warning is appropriate, but not a failure.
3699  */
3700 static int check_pool_cmd_result(enum lcfg_command_type cmd, char *fsname,
3701                                  char *poolname, char *ostname)
3702 {
3703         int cpt = 10;
3704         int rc = 0;
3705
3706         switch (cmd) {
3707         case LCFG_POOL_NEW: {
3708                 do {
3709                         rc = lctl_search_ost(fsname, poolname, NULL, cmd);
3710                         if (rc == -ENODEV)
3711                                 return rc;
3712                         if (rc < 0)
3713                                 sleep(1);
3714                         cpt--;
3715                 } while ((rc < 0) && (cpt > 0));
3716                 if (rc >= 0) {
3717                         fprintf(stderr, "Pool %s.%s created\n",
3718                                 fsname, poolname);
3719                         return 0;
3720                 }
3721
3722                 fprintf(stderr, "Warning, pool %s.%s not found\n", fsname,
3723                         poolname);
3724                 return -ENOENT;
3725         }
3726         case LCFG_POOL_DEL: {
3727                 do {
3728                         rc = lctl_search_ost(fsname, poolname, NULL, cmd);
3729                         if (rc == -ENODEV)
3730                                 return rc;
3731                         if (rc >= 0)
3732                                 sleep(1);
3733                         cpt--;
3734                 } while ((rc >= 0) && (cpt > 0));
3735                 if (rc < 0) {
3736                         fprintf(stderr, "Pool %s.%s destroyed\n",
3737                                 fsname, poolname);
3738                         return 0;
3739                 }
3740
3741                 fprintf(stderr, "Warning, pool %s.%s still found\n", fsname,
3742                         poolname);
3743                 return -EEXIST;
3744         }
3745         case LCFG_POOL_ADD: {
3746                 do {
3747                         rc = lctl_search_ost(fsname, poolname, ostname, cmd);
3748                         if (rc == -ENODEV)
3749                                 return rc;
3750                         if (rc != 1)
3751                                 sleep(1);
3752                         cpt--;
3753                 } while ((rc != 1) && (cpt > 0));
3754                 if (rc == 1) {
3755                         fprintf(stderr, "OST %s added to pool %s.%s\n",
3756                                 ostname, fsname, poolname);
3757                         return 0;
3758                 }
3759                 fprintf(stderr, "Warning, OST %s not found in pool %s.%s\n",
3760                         ostname, fsname, poolname);
3761                 return -ENOENT;
3762         }
3763         case LCFG_POOL_REM: {
3764                 do {
3765                         rc = lctl_search_ost(fsname, poolname, ostname, cmd);
3766                         if (rc == -ENODEV)
3767                                 return rc;
3768                         if (rc == 1)
3769                                 sleep(1);
3770                         cpt--;
3771                 } while ((rc == 1) && (cpt > 0));
3772                 if (rc != 1) {
3773                         fprintf(stderr, "OST %s removed from pool %s.%s\n",
3774                                 ostname, fsname, poolname);
3775                         return 0;
3776                 }
3777                 fprintf(stderr, "Warning, OST %s still found in pool %s.%s\n",
3778                         ostname, fsname, poolname);
3779                 return -EEXIST;
3780         }
3781         default:
3782                 break;
3783         }
3784         return -EINVAL;
3785 }
3786
3787 static int check_and_complete_ostname(char *fsname, char *ostname)
3788 {
3789         char *ptr;
3790         char real_ostname[MAX_OBD_NAME + 1];
3791         char i;
3792
3793         /* if OST name does not start with fsname, we add it */
3794         /* if not check if the fsname is the right one */
3795         ptr = strchr(ostname, '-');
3796         if (!ptr) {
3797                 sprintf(real_ostname, "%s-%s", fsname, ostname);
3798         } else if (strncmp(ostname, fsname, strlen(fsname)) != 0) {
3799                 fprintf(stderr, "%s does not start with fsname %s\n",
3800                         ostname, fsname);
3801                 return -EINVAL;
3802         } else {
3803                 if (strlen(ostname) > sizeof(real_ostname) - 1)
3804                         return -E2BIG;
3805
3806                 strncpy(real_ostname, ostname, sizeof(real_ostname));
3807         }
3808
3809         /* real_ostname is fsname-????? */
3810         ptr = real_ostname + strlen(fsname) + 1;
3811         if (strncmp(ptr, "OST", 3) != 0) {
3812                 fprintf(stderr, "%s does not start by %s-OST nor OST\n",
3813                         ostname, fsname);
3814                 return -EINVAL;
3815         }
3816         /* real_ostname is fsname-OST????? */
3817         ptr += 3;
3818         for (i = 0; i < 4; i++) {
3819                 if (!isxdigit(*ptr)) {
3820                         fprintf(stderr,
3821                                 "ost's index in %s is not an hexa number\n",
3822                                 ostname);
3823                         return -EINVAL;
3824                 }
3825                 ptr++;
3826         }
3827         /* real_ostname is fsname-OSTXXXX????? */
3828         /* if OST name does not end with _UUID, we add it */
3829         if (*ptr == '\0') {
3830                 strcat(real_ostname, "_UUID");
3831         } else if (strcmp(ptr, "_UUID") != 0) {
3832                 fprintf(stderr,
3833                         "ostname %s does not end with _UUID\n", ostname);
3834                 return -EINVAL;
3835         }
3836         /* real_ostname is fsname-OSTXXXX_UUID */
3837         strcpy(ostname, real_ostname);
3838         return 0;
3839 }
3840
3841 /* returns 0 or -errno */
3842 static int pool_cmd(enum lcfg_command_type cmd, char *cmdname,
3843                     char *fullpoolname, char *fsname, char *poolname,
3844                     char *ostname)
3845 {
3846         int rc = 0;
3847         struct obd_ioctl_data data;
3848         struct lustre_cfg_bufs bufs;
3849         struct lustre_cfg *lcfg;
3850         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
3851
3852         rc = check_pool_cmd(cmd, fsname, poolname, ostname);
3853         if (rc == -ENODEV)
3854                 fprintf(stderr,
3855                         "Can't verify pool command since there is no local MDT or client, proceeding anyhow...\n");
3856         else if (rc)
3857                 return rc;
3858
3859         lustre_cfg_bufs_reset(&bufs, NULL);
3860         lustre_cfg_bufs_set_string(&bufs, 0, cmdname);
3861         lustre_cfg_bufs_set_string(&bufs, 1, fullpoolname);
3862         if (ostname)
3863                 lustre_cfg_bufs_set_string(&bufs, 2, ostname);
3864
3865         lcfg = malloc(lustre_cfg_len(bufs.lcfg_bufcount, bufs.lcfg_buflen));
3866         if (!lcfg)
3867                 return -ENOMEM;
3868         lustre_cfg_init(lcfg, cmd, &bufs);
3869
3870         memset(&data, 0, sizeof(data));
3871         rc = data.ioc_dev = get_mgs_device();
3872         if (rc < 0)
3873                 goto out;
3874
3875         data.ioc_type = LUSTRE_CFG_TYPE;
3876         data.ioc_plen1 = lustre_cfg_len(lcfg->lcfg_bufcount,
3877                                         lcfg->lcfg_buflens);
3878         data.ioc_pbuf1 = (void *)lcfg;
3879
3880         memset(buf, 0, sizeof(rawbuf));
3881         rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
3882         if (rc) {
3883                 fprintf(stderr, "error: %s: invalid ioctl\n",
3884                         jt_cmdname(cmdname));
3885                 free(lcfg);
3886                 return rc;
3887         }
3888         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_POOL, buf);
3889 out:
3890         if (rc)
3891                 rc = -errno;
3892         switch (rc) {
3893         case -ENAMETOOLONG:
3894                 fprintf(stderr,
3895                         "error: %s: either the pool or file system name is too long (max pool name len is %d and file system name is %d)\n",
3896                         jt_cmdname(cmdname), LOV_MAXPOOLNAME, LUSTRE_MAXFSNAME);
3897                 break;
3898         case -EINVAL:
3899                 fprintf(stderr,
3900                         "error: %s can contain only alphanumeric characters, underscores, and dashes besides the required '.'\n",
3901                         jt_cmdname(cmdname));
3902         default:
3903                 break;
3904         }
3905         free(lcfg);
3906         return rc;
3907 }
3908
3909 int jt_del_ost(int argc, char **argv)
3910 {
3911         char *fsname = NULL, *ptr, *logname;
3912         char mdtpattern[16], clipattern[16];
3913         char ostname[MAX_OBD_NAME + 1];
3914         long last_index;
3915         __u32 index;
3916         int rc, start = 0, dryrun = 0;
3917         char c;
3918
3919         static struct option long_opts[] = {
3920         { .val = 'h',   .name = "help",         .has_arg = no_argument },
3921         { .val = 'n',   .name = "dryrun",       .has_arg = no_argument },
3922         { .val = 't',   .name = "target",       .has_arg = required_argument },
3923         { .name = NULL } };
3924
3925         while ((c = getopt_long(argc, argv, "hnt:", long_opts, NULL)) != -1) {
3926                 switch (c) {
3927                 case 't':
3928                         fsname = strdup(optarg);
3929                         break;
3930                 case 'n':
3931                         dryrun = 1;
3932                         break;
3933                 case 'h':
3934                 default:
3935                         free(fsname);
3936                         return CMD_HELP;
3937                 }
3938         }
3939
3940         if (fsname == NULL)
3941                 return CMD_HELP;
3942
3943         if (llog_default_device(LLOG_DFLT_MGS_SET)) {
3944                 rc = CMD_INCOMPLETE;
3945                 goto out;
3946         }
3947
3948         ptr = strstr(fsname, "-OST");
3949         if (!ptr) {
3950                 rc = CMD_HELP;
3951                 goto err;
3952         }
3953
3954         if (dryrun)
3955                 fprintf(stdout, "del_ost: dry run for target %s\n", fsname);
3956
3957         *ptr++ = '\0';
3958         rc = sscanf(ptr, "OST%04x", &index);
3959         if (rc != 1) {
3960                 rc = -EINVAL;
3961                 goto err;
3962         }
3963
3964         if (strlen(ptr) > sizeof(ostname) - 1) {
3965                 rc = -E2BIG;
3966                 goto err;
3967         }
3968
3969         snprintf(mdtpattern, sizeof(mdtpattern), "%s-MDT", fsname);
3970         snprintf(clipattern, sizeof(clipattern), "%s-client", fsname);
3971         snprintf(ostname, sizeof(ostname), "%s-%s", fsname, ptr);
3972
3973         do {
3974                 char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
3975                 char *begin, *end;
3976
3977                 start = llog_catlist_next(start, rawbuf, sizeof(rawbuf));
3978                 if (start < 0)
3979                         break;
3980                 begin = ((struct obd_ioctl_data *)buf)->ioc_bulk;
3981                 if (strlen(begin) == 0)
3982                         break;
3983
3984                 while ((end = strchr(begin, '\n'))) {
3985                         *end = '\0';
3986                         logname = strstr(begin, "config_log: ");
3987
3988                         if (logname && (strstr(logname, mdtpattern) ||
3989                                         strstr(logname, clipattern))) {
3990                                 logname += 12;
3991
3992                                 fprintf(stdout, "config_log: %s\n", logname);
3993
3994                                 last_index = llog_last_index(logname);
3995                                 if (last_index < 0) {
3996                                         fprintf(stderr,
3997                                                 "error with catalog %s: %s\n",
3998                                                 logname, strerror(-last_index));
3999                                         rc = -last_index;
4000                                         goto err;
4001                                 }
4002                                 rc = llog_del_ost(logname, last_index, ostname,
4003                                                   dryrun);
4004                                 if (rc < 0)
4005                                         goto err;
4006                         }
4007                         begin = end + 1;
4008                 }
4009         } while (start);
4010
4011 err:
4012         llog_default_device(LLOG_DFLT_DEV_RESET);
4013 out:
4014         free(fsname);
4015         return rc;
4016 }
4017
4018 #ifdef HAVE_SERVER_SUPPORT
4019 /**
4020  * Format and send the ioctl to the MGS.
4021  *
4022  * \param       cmd             IOCTL to send
4023  * \param       ret_data        void pointer to return anything from
4024  *                              ioctl
4025  * \param       num_args        number of arguments to pack into the
4026  *                              ioctl buffer
4027  * \param       argv[]          variable number of string arguments
4028  *
4029  * \retval                      0 on success
4030  */
4031 static int nodemap_cmd(enum lcfg_command_type cmd, void *ret_data,
4032                        unsigned int ret_size, ...)
4033 {
4034         va_list                 ap;
4035         char                    *arg;
4036         int                     i = 0;
4037         struct lustre_cfg_bufs  bufs;
4038         struct obd_ioctl_data   data;
4039         struct lustre_cfg       *lcfg;
4040         char                    rawbuf[MAX_IOC_BUFLEN];
4041         char                    *buf = rawbuf;
4042         int                     rc = 0;
4043
4044         lustre_cfg_bufs_reset(&bufs, NULL);
4045
4046         va_start(ap, ret_size);
4047         arg = va_arg(ap, char *);
4048         while (arg) {
4049                 lustre_cfg_bufs_set_string(&bufs, i, arg);
4050                 i++;
4051                 arg = va_arg(ap, char *);
4052         }
4053         va_end(ap);
4054
4055         lcfg = malloc(lustre_cfg_len(bufs.lcfg_bufcount, bufs.lcfg_buflen));
4056         if (!lcfg)
4057                 return -ENOMEM;
4058         lustre_cfg_init(lcfg, cmd, &bufs);
4059
4060         memset(&data, 0, sizeof(data));
4061         rc = data.ioc_dev = get_mgs_device();
4062         if (rc < 0)
4063                 goto out;
4064
4065         data.ioc_type = LUSTRE_CFG_TYPE;
4066         data.ioc_plen1 = lustre_cfg_len(lcfg->lcfg_bufcount,
4067                                         lcfg->lcfg_buflens);
4068         data.ioc_pbuf1 = (void *)lcfg;
4069
4070         memset(buf, 0, sizeof(rawbuf));
4071         rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
4072         if (rc) {
4073                 fprintf(stderr,
4074                         "error: invalid ioctl request: %08x errno: %d: %s\n",
4075                         cmd, errno, strerror(-rc));
4076                 goto out;
4077         }
4078
4079         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_NODEMAP, buf);
4080         if (rc) {
4081                 fprintf(stderr,
4082                         "error: invalid ioctl: %08x errno: %d: %s\n",
4083                         cmd, errno, strerror(errno));
4084                 goto out;
4085         }
4086
4087         if (ret_data) {
4088                 rc = llapi_ioctl_unpack(&data, buf, sizeof(rawbuf));
4089                 if (rc)
4090                         goto out;
4091
4092                 if (ret_size > data.ioc_plen1)
4093                         ret_size = data.ioc_plen1;
4094
4095                 memcpy(ret_data, data.ioc_pbuf1, ret_size);
4096         }
4097 out:
4098         free(lcfg);
4099
4100         return rc;
4101 }
4102
4103 /**
4104  * activate nodemap functions
4105  *
4106  * \param       argc            number of args
4107  * \param       argv[]          variable string arguments
4108  *
4109  * argv[0]                      1 for activate or 0 for deactivate
4110  *
4111  * \retval                      0 on success
4112  */
4113 int jt_nodemap_activate(int argc, char **argv)
4114 {
4115         int rc;
4116
4117         rc = nodemap_cmd(LCFG_NODEMAP_ACTIVATE, NULL, 0, argv[0], argv[1],
4118                          NULL);
4119
4120         if (rc != 0) {
4121                 errno = -rc;
4122                 perror(argv[0]);
4123         }
4124
4125         return rc;
4126 }
4127
4128 /**
4129  * add a nodemap
4130  *
4131  * \param       argc            number of args
4132  * \param       argv[]          variable string arguments
4133  *
4134  * argv[0]                      nodemap name
4135  *
4136  * \retval                      0 on success
4137  */
4138 int jt_nodemap_add(int argc, char **argv)
4139 {
4140         int rc;
4141
4142         rc = llapi_nodemap_exists(argv[1]);
4143         if (rc == 0) {
4144                 fprintf(stderr, "error: %s existing nodemap name\n", argv[1]);
4145                 return 1;
4146         }
4147
4148         rc = nodemap_cmd(LCFG_NODEMAP_ADD, NULL, 0, argv[0], argv[1], NULL);
4149
4150         if (rc != 0) {
4151                 errno = -rc;
4152                 perror(argv[0]);
4153         }
4154
4155         return rc;
4156 }
4157
4158 /**
4159  * delete a nodemap
4160  *
4161  * \param       argc            number of args
4162  * \param       argv[]          variable string arguments
4163  *
4164  * argv[0]                      nodemap name
4165  *
4166  * \retval                      0 on success
4167  */
4168 int jt_nodemap_del(int argc, char **argv)
4169 {
4170         int rc;
4171
4172         rc = llapi_nodemap_exists(argv[1]);
4173         if (rc != 0) {
4174                 fprintf(stderr, "error: %s not existing nodemap name\n",
4175                         argv[1]);
4176                 return rc;
4177         }
4178         rc = nodemap_cmd(LCFG_NODEMAP_DEL, NULL, 0, argv[0], argv[1], NULL);
4179
4180         if (rc != 0) {
4181                 errno = -rc;
4182                 perror(argv[0]);
4183         }
4184
4185         return rc;
4186 }
4187
4188 /**
4189  * test a nid for nodemap membership
4190  *
4191  * \param       argc            number of args
4192  * \param       argv[]          variable string arguments
4193  *
4194  * argv[0]                      properly formatted nid
4195  *
4196  * \retval                      0 on success
4197  */
4198 int jt_nodemap_test_nid(int argc, char **argv)
4199 {
4200         char    rawbuf[MAX_IOC_BUFLEN];
4201         int     rc;
4202
4203         rc = nodemap_cmd(LCFG_NODEMAP_TEST_NID, &rawbuf, sizeof(rawbuf),
4204                          argv[0], argv[1], NULL);
4205         if (rc == 0)
4206                 printf("%s\n", (char *)rawbuf);
4207
4208         return rc;
4209 }
4210
4211 /**
4212  * test a nodemap id pair for mapping
4213  *
4214  * \param       argc            number of args
4215  * \param       argv[[]         variable string arguments
4216  *
4217  * \retval                      0 on success
4218  *
4219  * The argv array should contain the nodemap name, the id
4220  * to checking the mapping on, and the id type (UID or GID)
4221  *
4222  */
4223 int jt_nodemap_test_id(int argc, char **argv)
4224 {
4225         char    rawbuf[MAX_IOC_BUFLEN];
4226         char    *nidstr = NULL;
4227         char    *idstr = NULL;
4228         char    *typestr = NULL;
4229         int     rc = 0;
4230         int     c;
4231
4232         static struct option long_opts[] = {
4233                 { .val = 'i',   .name = "id",   .has_arg = required_argument },
4234                 { .val = 'n',   .name = "nid",  .has_arg = required_argument },
4235                 { .val = 't',   .name = "idtype",
4236                                                 .has_arg = required_argument },
4237                 { .name = NULL } };
4238
4239         while ((c = getopt_long(argc, argv, "n:t:i:",
4240                                 long_opts, NULL)) != -1) {
4241                 switch (c) {
4242                 case 'n':
4243                         nidstr = optarg;
4244                         break;
4245                 case 't':
4246                         typestr = optarg;
4247                         break;
4248                 case 'i':
4249                         idstr = optarg;
4250                         break;
4251                 }
4252         }
4253
4254         if (!nidstr || !typestr || !idstr) {
4255                 fprintf(stderr,
4256                         "usage: nodemap_test_id --nid <nid> --idtype [uid|gid] --id <id>\n");
4257                 return -1;
4258         }
4259
4260         rc = nodemap_cmd(LCFG_NODEMAP_TEST_ID, &rawbuf, sizeof(rawbuf),
4261                          argv[0], nidstr, typestr, idstr, NULL);
4262         if (rc == 0)
4263                 printf("%s\n", (char *)rawbuf);
4264
4265         return rc;
4266 }
4267
4268 /**
4269  * parse nid range
4270  *
4271  * \param       nodemap_range   --range string
4272  * \param       nid_range       nid range string, min_nid:max_nid
4273  *
4274  * \retval                      0 on success
4275  */
4276 static int parse_nid_range(char *nodemap_range, char *nid_range, int range_len)
4277 {
4278         char                    min_nid[LNET_NIDSTR_SIZE + 1];
4279         char                    max_nid[LNET_NIDSTR_SIZE + 1];
4280         struct list_head        nidlist;
4281         int                     rc = 0;
4282
4283         INIT_LIST_HEAD(&nidlist);
4284
4285         if (cfs_parse_nidlist(nodemap_range, strlen(nodemap_range),
4286                               &nidlist) <= 0) {
4287                 fprintf(stderr,
4288                         "error: nodemap_xxx_range: can't parse nid range: %s\n",
4289                         nodemap_range);
4290                 return -EINVAL;
4291         }
4292
4293         rc = cfs_nidrange_find_min_max(&nidlist, &min_nid[0], &max_nid[0],
4294                                        LNET_NIDSTR_SIZE);
4295         if (rc < 0) {
4296                 if (rc == -EINVAL)
4297                         fprintf(stderr,
4298                                 "error: nodemap_xxx_range: nid range uses currently unsupported features\n");
4299                 else if (rc == -ERANGE)
4300                         fprintf(stderr,
4301                                 "error: nodemap_xxx_range: nodemap ranges must be contiguous\n");
4302
4303                 return rc;
4304         }
4305
4306         snprintf(nid_range, range_len, "%s:%s", min_nid, max_nid);
4307
4308         return rc;
4309 }
4310
4311 /**
4312  * add an nid range to a nodemap
4313  *
4314  * \param       argc            number of args
4315  * \param       argv[]          variable string arguments
4316  *
4317  * --name                       nodemap name
4318  * --range                      properly formatted nid range
4319  *
4320  * \retval                      0 on success, -errno on error
4321  */
4322 int jt_nodemap_add_range(int argc, char **argv)
4323 {
4324         char                    *nodemap_name = NULL;
4325         char                    *nodemap_range = NULL;
4326         char                    nid_range[2 * LNET_NIDSTR_SIZE + 2];
4327         int                     rc = 0;
4328         int                     c;
4329
4330         static struct option long_opts[] = {
4331         { .val = 'n',   .name = "name",         .has_arg = required_argument },
4332         { .val = 'r',   .name = "range",        .has_arg = required_argument },
4333         { .name = NULL } };
4334
4335         while ((c = getopt_long(argc, argv, "n:r:",
4336                                 long_opts, NULL)) != -1) {
4337                 switch (c) {
4338                 case 'n':
4339                         nodemap_name = optarg;
4340                         break;
4341                 case 'r':
4342                         nodemap_range = optarg;
4343                         break;
4344                 }
4345         }
4346
4347         if (!nodemap_name || !nodemap_range) {
4348                 fprintf(stderr,
4349                         "usage: nodemap_add_range --name <name> --range <range>\n");
4350                 return -EINVAL;
4351         }
4352
4353         rc = parse_nid_range(nodemap_range, nid_range, sizeof(nid_range));
4354         if (rc) {
4355                 return rc;
4356         }
4357         rc = nodemap_cmd(LCFG_NODEMAP_ADD_RANGE, NULL, 0, argv[0],
4358                          nodemap_name, nid_range, NULL);
4359         if (rc) {
4360                 fprintf(stderr,
4361                         "error: %s: cannot add range '%s' to nodemap '%s': %s\n",
4362                         jt_cmdname(argv[0]), nodemap_range, nodemap_name,
4363                         strerror(-rc));
4364         }
4365
4366         return rc;
4367 }
4368
4369 /**
4370  * delete an nid range to a nodemap
4371  *
4372  * \param       argc            number of args
4373  * \param       argv[]          variable string arguments
4374  *
4375  * --name                       nodemap name
4376  * --range                      properly formatted nid range
4377  *
4378  * \retval                      0 on success
4379  */
4380 int jt_nodemap_del_range(int argc, char **argv)
4381 {
4382         char                    *nodemap_name = NULL;
4383         char                    *nodemap_range = NULL;
4384         char                    nid_range[2 * LNET_NIDSTR_SIZE + 2];
4385         int                     rc = 0;
4386         int                     c;
4387
4388         static struct option long_opts[] = {
4389         { .val = 'n',   .name = "name",         .has_arg = required_argument },
4390         { .val = 'r',   .name = "range",        .has_arg = required_argument },
4391         { .name = NULL } };
4392
4393         while ((c = getopt_long(argc, argv, "n:r:",
4394                                 long_opts, NULL)) != -1) {
4395                 switch (c) {
4396                 case 'n':
4397                         nodemap_name = optarg;
4398                         break;
4399                 case 'r':
4400                         nodemap_range = optarg;
4401                         break;
4402                 }
4403         }
4404
4405         if (!nodemap_name || !nodemap_range) {
4406                 fprintf(stderr,
4407                         "usage: nodemap_del_range --name <name> --range <range>\n");
4408                 return -1;
4409         }
4410
4411         rc = parse_nid_range(nodemap_range, nid_range, sizeof(nid_range));
4412         if (rc) {
4413                 errno = -rc;
4414                 return rc;
4415         }
4416         rc = nodemap_cmd(LCFG_NODEMAP_DEL_RANGE, NULL, 0, argv[0],
4417                          nodemap_name, nid_range, NULL);
4418         if (rc != 0) {
4419                 errno = -rc;
4420                 fprintf(stderr,
4421                         "error: %s: cannot delete range '%s' to nodemap '%s': rc = %d\n",
4422                         jt_cmdname(argv[0]), nodemap_range, nodemap_name, rc);
4423         }
4424
4425         return rc;
4426 }
4427
4428 /**
4429  * set a fileset on a nodemap
4430  *
4431  * \param       argc            number of args
4432  * \param       argv[]          variable string arguments
4433  *
4434  * --name                       nodemap name
4435  * --fileset                    fileset name
4436  *
4437  * \retval                      0 on success
4438  */
4439 int jt_nodemap_set_fileset(int argc, char **argv)
4440 {
4441         char *nodemap_name = NULL;
4442         char *fileset_name = NULL;
4443         int   rc = 0;
4444         int   c;
4445
4446         static struct option long_opts[] = {
4447         { .val = 'f',   .name = "fileset",      .has_arg = required_argument },
4448         { .val = 'n',   .name = "name",         .has_arg = required_argument },
4449         { .name = NULL } };
4450
4451         while ((c = getopt_long(argc, argv, "n:f:",
4452                                 long_opts, NULL)) != -1) {
4453                 switch (c) {
4454                 case 'n':
4455                         nodemap_name = optarg;
4456                         break;
4457                 case 'f':
4458                         fileset_name = optarg;
4459                         break;
4460                 }
4461         }
4462
4463         if (!nodemap_name || !fileset_name) {
4464                 fprintf(stderr,
4465                         "usage: nodemap_set_fileset --name <name> --fileset <fileset>\n");
4466                 return -1;
4467         }
4468
4469         rc = nodemap_cmd(LCFG_NODEMAP_SET_FILESET, NULL, 0, argv[0],
4470                          nodemap_name, fileset_name, NULL);
4471         if (rc != 0) {
4472                 errno = -rc;
4473                 fprintf(stderr,
4474                         "error: %s: cannot set fileset '%s' on nodemap '%s': rc = %d\n",
4475                         jt_cmdname(argv[0]), fileset_name, nodemap_name, rc);
4476         }
4477
4478         return rc;
4479 }
4480
4481 /**
4482  * set SELinux policy info on a nodemap
4483  *
4484  * \param       argc            number of args
4485  * \param       argv[]          variable string arguments
4486  *
4487  * --name                       nodemap name
4488  * --sepol                      SELinux policy info
4489  *
4490  * \retval                      0 on success
4491  */
4492 int jt_nodemap_set_sepol(int argc, char **argv)
4493 {
4494         char *nodemap_name = NULL;
4495         char *sepol = NULL;
4496         int   rc = 0;
4497         int   c;
4498
4499         static struct option long_options[] = {
4500                 {
4501                         .name           = "name",
4502                         .has_arg        = required_argument,
4503                         .val            = 'n',
4504                 },
4505                 {
4506                         .name           = "sepol",
4507                         .has_arg        = required_argument,
4508                         .val            = 's',
4509                 },
4510                 {
4511                         .name = NULL,
4512                 }
4513         };
4514
4515         while ((c = getopt_long(argc, argv, "n:s:",
4516                                 long_options, NULL)) != -1) {
4517                 switch (c) {
4518                 case 'n':
4519                         nodemap_name = optarg;
4520                         break;
4521                 case 's':
4522                         sepol = optarg;
4523                         break;
4524                 }
4525         }
4526
4527         if (!nodemap_name || !sepol) {
4528                 fprintf(stderr,
4529                         "usage: nodemap_set_sepol --name <name> --sepol <sepol>\n");
4530                 return -1;
4531         }
4532
4533         rc = nodemap_cmd(LCFG_NODEMAP_SET_SEPOL, NULL, 0, argv[0],
4534                          nodemap_name, sepol, NULL);
4535         if (rc != 0) {
4536                 errno = -rc;
4537                 fprintf(stderr,
4538                         "error: %s: cannot set sepol '%s' on nodemap '%s': rc = %d\n",
4539                         jt_cmdname(argv[0]), sepol, nodemap_name, rc);
4540         }
4541
4542         return rc;
4543 }
4544
4545 /**
4546  * modify a nodemap's behavior
4547  *
4548  * \param       argc            number of args
4549  * \param       argv[]          variable string arguments
4550  *
4551  * --name                       nodemap name
4552  * --property                   nodemap property to change
4553  *                              admin, trusted, squash_uid, squash_gid)
4554  * --value                      value to set property
4555  *
4556  * \retval                      0 on success
4557  */
4558 int jt_nodemap_modify(int argc, char **argv)
4559 {
4560         int                     c;
4561         int                     rc = 0;
4562         enum lcfg_command_type  cmd = 0;
4563         char                    *nodemap_name = NULL;
4564         char                    *param = NULL;
4565         char                    *value = NULL;
4566
4567         static struct option long_opts[] = {
4568         { .val = 'n',   .name = "name",         .has_arg = required_argument },
4569         { .val = 'p',   .name = "property",     .has_arg = required_argument },
4570         { .val = 'v',   .name = "value",        .has_arg = required_argument },
4571         { .name = NULL } };
4572
4573         while ((c = getopt_long(argc, argv, "n:p:v:",
4574                                 long_opts, NULL)) != -1) {
4575                 switch (c) {
4576                 case 'n':
4577                         nodemap_name = optarg;
4578                         break;
4579                 case 'p':
4580                         param = optarg;
4581                         break;
4582                 case 'v':
4583                         value = optarg;
4584                         break;
4585                 }
4586         }
4587
4588         if (!nodemap_name || !param || !value) {
4589                 fprintf(stderr,
4590                         "usage: nodemap_modify --name <nodemap_name> --property <property_name> --value <value>\n");
4591                 fprintf(stderr,
4592                         "valid properties: admin trusted map_mode squash_uid squash_gid squash_projid deny_unknown audit_mode forbid_encryption readonly_mount rbac\n");
4593                 return -1;
4594         }
4595
4596         if (strcmp("admin", param) == 0) {
4597                 cmd = LCFG_NODEMAP_ADMIN;
4598         } else if (strcmp("trusted", param) == 0) {
4599                 cmd = LCFG_NODEMAP_TRUSTED;
4600         } else if (strcmp("deny_unknown", param) == 0) {
4601                 cmd = LCFG_NODEMAP_DENY_UNKNOWN;
4602         } else if (strcmp("squash_uid", param) == 0) {
4603                 cmd = LCFG_NODEMAP_SQUASH_UID;
4604         } else if (strcmp("squash_gid", param) == 0) {
4605                 cmd = LCFG_NODEMAP_SQUASH_GID;
4606         } else if (strcmp("squash_projid", param) == 0) {
4607                 cmd = LCFG_NODEMAP_SQUASH_PROJID;
4608         } else if (strcmp("map_mode", param) == 0) {
4609                 cmd = LCFG_NODEMAP_MAP_MODE;
4610         } else if (strcmp("audit_mode", param) == 0) {
4611                 cmd = LCFG_NODEMAP_AUDIT_MODE;
4612         } else if (strcmp("forbid_encryption", param) == 0) {
4613                 cmd = LCFG_NODEMAP_FORBID_ENCRYPT;
4614         } else if (strcmp("readonly_mount", param) == 0) {
4615                 cmd = LCFG_NODEMAP_READONLY_MOUNT;
4616         } else if (strcmp("rbac", param) == 0) {
4617                 cmd = LCFG_NODEMAP_RBAC;
4618         } else {
4619                 fprintf(stderr,
4620                         "error: %s: nodemap_modify invalid subcommand: %s\n",
4621                         jt_cmdname(argv[0]), param);
4622                 return -1;
4623         }
4624
4625         rc = nodemap_cmd(cmd, NULL, 0, argv[0], nodemap_name, param,
4626                          value, NULL);
4627         if (rc != 0) {
4628                 errno = -rc;
4629                 fprintf(stderr,
4630                         "error: %s: cannot modify nodemap '%s' to param '%s': value '%s': rc = %d\n",
4631                         jt_cmdname(argv[0]), nodemap_name, param, value, rc);
4632         }
4633
4634         return rc;
4635 }
4636
4637 int jt_nodemap_add_idmap(int argc, char **argv)
4638 {
4639         int                     c;
4640         enum                    lcfg_command_type cmd = 0;
4641         char                    *nodemap_name = NULL;
4642         char                    *idmap = NULL;
4643         char                    *idtype = NULL;
4644         int                     rc = 0;
4645
4646         static struct option long_opts[] = {
4647         { .val = 'i',   .name = "idtype",       .has_arg = required_argument },
4648         { .val = 'm',   .name = "idmap",        .has_arg = required_argument },
4649         { .val = 'n',   .name = "name",         .has_arg = required_argument },
4650         { .name = NULL } };
4651
4652         while ((c = getopt_long(argc, argv, "n:m:i:",
4653                                 long_opts, NULL)) != -1) {
4654                 switch (c) {
4655                 case 'n':
4656                         nodemap_name = optarg;
4657                         break;
4658                 case 'm':
4659                         idmap = optarg;
4660                         break;
4661                 case 'i':
4662                         idtype = optarg;
4663                         break;
4664                 }
4665         }
4666
4667         if (!nodemap_name || !idmap || !idtype) {
4668                 fprintf(stderr,
4669                         "usage: %s --name <name> --idtype [uid | gid | projid] --idmap <client id>:<filesystem id>\n",
4670                         argv[0]);
4671                 return -1;
4672         }
4673
4674         if (strcmp("uid", idtype) == 0) {
4675                 cmd = LCFG_NODEMAP_ADD_UIDMAP;
4676         } else if (strcmp("gid", idtype) == 0) {
4677                 cmd = LCFG_NODEMAP_ADD_GIDMAP;
4678         } else if (strcmp("projid", idtype) == 0) {
4679                 cmd = LCFG_NODEMAP_ADD_PROJIDMAP;
4680         } else {
4681                 fprintf(stderr,
4682                         "usage: %s --name <name> --idtype [uid | gid | projid] --idmap <client id>:<filesystem id>\n",
4683                         argv[0]);
4684                 return -1;
4685         }
4686
4687         rc = nodemap_cmd(cmd, NULL, 0, argv[0], nodemap_name, idmap, NULL);
4688         if (rc != 0) {
4689                 errno = -rc;
4690                 fprintf(stderr,
4691                         "cannot add %smap '%s' to nodemap '%s': rc = %d\n",
4692                         idtype, idmap, nodemap_name, rc);
4693         }
4694
4695         return rc;
4696 }
4697
4698 int jt_nodemap_del_idmap(int argc, char **argv)
4699 {
4700         int                     c;
4701         enum                    lcfg_command_type cmd = 0;
4702         char                    *nodemap_name = NULL;
4703         char                    *idmap = NULL;
4704         char                    *idtype = NULL;
4705         int                     rc = 0;
4706
4707         static struct option long_opts[] = {
4708         { .val = 'i',   .name = "idtype",       .has_arg = required_argument },
4709         { .val = 'm',   .name = "idmap",        .has_arg = required_argument },
4710         { .val = 'n',   .name = "name",         .has_arg = required_argument },
4711         { .name = NULL } };
4712
4713         while ((c = getopt_long(argc, argv, "n:m:i:",
4714                                 long_opts, NULL)) != -1) {
4715                 switch (c) {
4716                 case 'n':
4717                         nodemap_name = optarg;
4718                         break;
4719                 case 'm':
4720                         idmap = optarg;
4721                         break;
4722                 case 'i':
4723                         idtype = optarg;
4724                         break;
4725                 }
4726         }
4727
4728         if (!nodemap_name || !idmap || !idtype) {
4729                 fprintf(stderr,
4730                         "usage: %s --name <name> --idtype [uid | gid | projid] --idmap <client id>:<filesystem id>\n",
4731                         argv[0]);
4732                 return -1;
4733         }
4734
4735         if (strcmp("uid", idtype) == 0) {
4736                 cmd = LCFG_NODEMAP_DEL_UIDMAP;
4737         } else if (strcmp("gid", idtype) == 0) {
4738                 cmd = LCFG_NODEMAP_DEL_GIDMAP;
4739         } else if (strcmp("projid", idtype) == 0) {
4740                 cmd = LCFG_NODEMAP_DEL_PROJIDMAP;
4741         } else {
4742                 fprintf(stderr,
4743                         "usage: %s --name <name> --idtype [uid | gid | projid] --idmap <client id>:<filesystem id>\n",
4744                         argv[0]);
4745                 return -1;
4746         }
4747
4748         rc = nodemap_cmd(cmd, NULL, 0, argv[0], nodemap_name, idmap, NULL);
4749         if (rc != 0) {
4750                 errno = -rc;
4751                 fprintf(stderr,
4752                         "cannot delete %smap '%s' from nodemap '%s': rc = %d\n",
4753                         idtype, idmap, nodemap_name, rc);
4754         }
4755
4756         return rc;
4757 }
4758 #else /* !HAVE_SERVER_SUPPORT */
4759 int jt_nodemap_activate(int argc, char **argv)
4760 {
4761         fprintf(stderr, "error: %s: invalid ioctl\n",
4762                 jt_cmdname(argv[0]));
4763         return -EOPNOTSUPP;
4764 }
4765
4766 int jt_nodemap_add(int argc, char **argv)
4767 {
4768         fprintf(stderr, "error: %s: invalid ioctl\n",
4769                 jt_cmdname(argv[0]));
4770         return -EOPNOTSUPP;
4771 }
4772
4773 int jt_nodemap_del(int argc, char **argv)
4774 {
4775         fprintf(stderr, "error: %s: invalid ioctl\n",
4776                 jt_cmdname(argv[0]));
4777         return -EOPNOTSUPP;
4778 }
4779
4780 int jt_nodemap_modify(int argc, char **argv)
4781 {
4782         fprintf(stderr, "error: %s: invalid ioctl\n",
4783                 jt_cmdname(argv[0]));
4784         return -EOPNOTSUPP;
4785 }
4786
4787 int jt_nodemap_add_range(int argc, char **argv)
4788 {
4789         fprintf(stderr, "error: %s: invalid ioctl\n",
4790                 jt_cmdname(argv[0]));
4791         return -EOPNOTSUPP;
4792 }
4793
4794 int jt_nodemap_test_nid(int argc, char **argv)
4795 {
4796         fprintf(stderr, "error: %s: invalid ioctl\n",
4797                 jt_cmdname(argv[0]));
4798         return -EOPNOTSUPP;
4799 }
4800
4801 int jt_nodemap_del_range(int argc, char **argv)
4802 {
4803         fprintf(stderr, "error: %s: invalid ioctl\n",
4804                 jt_cmdname(argv[0]));
4805         return -EOPNOTSUPP;
4806 }
4807
4808 int jt_nodemap_add_idmap(int argc, char **argv)
4809 {
4810         fprintf(stderr, "error: %s: invalid ioctl\n",
4811                 jt_cmdname(argv[0]));
4812         return -EOPNOTSUPP;
4813 }
4814
4815 int jt_nodemap_del_idmap(int argc, char **argv)
4816 {
4817         fprintf(stderr, "error: %s: invalid ioctl\n",
4818                 jt_cmdname(argv[0]));
4819         return -EOPNOTSUPP;
4820 }
4821
4822 int jt_nodemap_test_id(int argc, char **argv)
4823 {
4824         fprintf(stderr, "error: %s: invalid ioctl\n",
4825                 jt_cmdname(argv[0]));
4826         return -EOPNOTSUPP;
4827 }
4828
4829 int jt_nodemap_set_fileset(int argc, char **argv)
4830 {
4831         fprintf(stderr, "error: %s: invalid ioctl\n",
4832                 jt_cmdname(argv[0]));
4833         return -EOPNOTSUPP;
4834 }
4835
4836 int jt_nodemap_set_sepol(int argc, char **argv)
4837 {
4838         fprintf(stderr, "error: %s: invalid ioctl\n",
4839                 jt_cmdname(argv[0]));
4840         return -EOPNOTSUPP;
4841 }
4842
4843 int jt_nodemap_info(int argc, char **argv)
4844 {
4845         fprintf(stderr, "error: %s: invalid ioctl\n",
4846                 jt_cmdname(argv[0]));
4847         return -EOPNOTSUPP;
4848 }
4849 #endif /* HAVE_SERVER_SUPPORT */
4850
4851 /*
4852  * this function tranforms a rule [start-end/step] into an array
4853  * of matching numbers
4854  * supported forms are:
4855  * [start]                : just this number
4856  * [start-end]            : all numbers from start to end
4857  * [start-end/step]       : numbers from start to end with increment of step
4858  * on return, format contains a printf format string which can be used
4859  * to generate all the strings
4860  */
4861 static int get_array_idx(char *rule, char *format, int **array)
4862 {
4863         char *start, *end, *ptr;
4864         unsigned int lo, hi, step;
4865         int array_sz = 0;
4866         int i, array_idx;
4867         int rc;
4868
4869         start = strchr(rule, '[');
4870         end = strchr(rule, ']');
4871         if ((!start) || (!end)) {
4872                 *array = malloc(sizeof(int));
4873                 if (!*array)
4874                         return 0;
4875                 strcpy(format, rule);
4876                 array_sz = 1;
4877                 return array_sz;
4878         }
4879         *start = '\0';
4880         *end = '\0';
4881         end++;
4882         start++;
4883         /* put in format the printf format (the rule without the range) */
4884         sprintf(format, "%s%%.4x%s", rule, end);
4885
4886         array_idx = 0;
4887         array_sz = 0;
4888         *array = NULL;
4889         /* loop on , separator */
4890         do {
4891                 /* extract the 3 fields */
4892                 rc = sscanf(start, "%x-%x/%u", &lo, &hi, &step);
4893                 switch (rc) {
4894                 case 0:
4895                         goto err;
4896                 case 1: {
4897                         void *tmp;
4898
4899                         array_sz++;
4900                         tmp = realloc(*array, array_sz * sizeof(int));
4901                         if (!tmp)
4902                                 goto err;
4903                         *array = tmp;
4904                         (*array)[array_idx] = lo;
4905                         array_idx++;
4906                         break;
4907                 }
4908                 case 2: {
4909                         step = 1;
4910                         /* do not break to share code with case 3: */
4911                 }
4912                 case 3: {
4913                         void *tmp;
4914
4915                         if ((hi < lo) || (step == 0))
4916                                 goto err;
4917                         array_sz += (hi - lo) / step + 1;
4918                         tmp = realloc(*array, array_sz * sizeof(int));
4919                         if (!tmp)
4920                                 goto err;
4921                         *array = tmp;
4922                         for (i = lo; i <= hi; i += step, array_idx++)
4923                                 (*array)[array_idx] = i;
4924                         break;
4925                 }
4926                 }
4927                 ptr = strchr(start, ',');
4928                 if (ptr)
4929                         start = ptr + 1;
4930
4931         } while (ptr);
4932         return array_sz;
4933 err:
4934         if (*array) {
4935                 free(*array);
4936                 *array = NULL;
4937         }
4938         return 0;
4939 }
4940
4941 struct llog_pool_name {
4942         char lpn_name[UUID_MAX];
4943         struct list_head lpn_list;
4944 };
4945
4946 struct llog_pool_list_data {
4947         char lpld_fsname[LUSTRE_MAXFSNAME + 1];
4948         char lpld_poolname[LOV_MAXPOOLNAME + 1];
4949         bool lpld_exists;
4950         struct list_head lpld_list_head;
4951 };
4952
4953 /**
4954  * Callback to list pool information in llog
4955  * - { index: 74, event: new_pool, device: tfs-clilov, fsname: tfs, pool: tmp }
4956  * - { index: 77, event: add_pool, device: tfs-clilov, fsname: tfs, pool: tmp,
4957  *     ost: tfs-OST0000_UUID }
4958  * - { index: 224, event: remove_pool, device: tfs-clilov, fsname: tfs,
4959  *     pool: tmp, ost: tfs-OST0003_UUID }
4960  * - { index: 227, event: del_pool, device: tfs-clilov, fsname: tfs, pool: tmp }
4961  *
4962  * \param record[in]    pointer to llog record
4963  * \param data[in]      pointer to struct llog_pool_list_data
4964  *
4965  * \retval              0 on success
4966  *                      <0 on error
4967  */
4968 static int llog_poollist_cb(const char *record, void *data)
4969 {
4970         struct llog_pool_list_data *lpld = data;
4971         char pool_filter[MAX_STRING_SIZE] = "";
4972         char *new_record, *del_record, *del_pool, *found;
4973         char type[10] = "";
4974         int filter_len, rc = 0;
4975
4976         filter_len = snprintf(pool_filter, sizeof(pool_filter), " fsname: %s,",
4977                               lpld->lpld_fsname);
4978         if (lpld->lpld_poolname[0] == '\0') {
4979                 new_record = get_event_filter(LCFG_POOL_NEW);
4980                 del_record = get_event_filter(LCFG_POOL_DEL);
4981                 strncpy(type, " pool: ", sizeof(type));
4982         } else {
4983                 filter_len += snprintf(pool_filter + filter_len,
4984                                        sizeof(pool_filter) - filter_len,
4985                                        " pool: %s", lpld->lpld_poolname);
4986                 new_record = get_event_filter(LCFG_POOL_ADD);
4987                 del_record = get_event_filter(LCFG_POOL_REM);
4988                 strncpy(type, " ost: ", sizeof(type));
4989         }
4990         del_pool = get_event_filter(LCFG_POOL_DEL);
4991
4992         if (!new_record || !del_record || !del_pool) {
4993                 rc = -ENOMEM;
4994                 goto out;
4995         }
4996
4997         found = strstr(record, pool_filter);
4998         if (found &&
4999             (found[filter_len] == ' ' || found[filter_len] == ',')) {
5000                 struct llog_pool_name *tmp = NULL;
5001                 struct list_head *head = &lpld->lpld_list_head;
5002                 char *name;
5003                 int name_len, type_len = strlen(type);
5004
5005                 lpld->lpld_exists = true;
5006                 if (strstr(record, new_record)) {
5007                         name = strstr(record, type);
5008                         /* 2 bytes for " }" */
5009                         name_len = strlen(name) - type_len - 2;
5010                         if (name_len <= 0 || name_len > sizeof(tmp->lpn_name))
5011                                 return -EINVAL;
5012                         tmp = malloc(sizeof(struct llog_pool_name));
5013                         if (!tmp) {
5014                                 rc = -ENOMEM;
5015                                 goto out;
5016                         }
5017                         memset(tmp, 0, sizeof(struct llog_pool_name));
5018                         strncpy(tmp->lpn_name, name + type_len, name_len);
5019                         list_add_tail(&tmp->lpn_list, &lpld->lpld_list_head);
5020                 } else if (strstr(record, del_record)) {
5021                         name = strstr(record, type);
5022                         name_len = strlen(name) - type_len - 2;
5023                         list_for_each_entry(tmp, head, lpn_list) {
5024                                 if (strncmp(tmp->lpn_name, name + type_len,
5025                                             name_len) == 0 &&
5026                                             tmp->lpn_name[name_len] == '\0') {
5027                                         list_del(&tmp->lpn_list);
5028                                         free(tmp);
5029                                         break;
5030                                 }
5031                         }
5032                 }
5033                 /* verify if the specified pool still exists */
5034                 if (lpld->lpld_poolname[0] && strstr(record, del_pool))
5035                         lpld->lpld_exists = false;
5036         }
5037 out:
5038         if (new_record)
5039                 free(new_record);
5040         if (del_record)
5041                 free(del_record);
5042         if (del_pool)
5043                 free(del_pool);
5044
5045         return rc;
5046 }
5047
5048 /**
5049  * List pool information by config log
5050  *
5051  * \param fsname[in]    pointer to filesystem name
5052  * \param poolname[in]  pointer to pool name
5053  *
5054  * \retval              0 on success
5055  *                      < 0 on error
5056  */
5057 int llog_poollist(char *fsname, char *poolname)
5058 {
5059         char logname[MAX_OBD_NAME] = {'\0'};
5060         struct llog_pool_list_data lpld;
5061         struct llog_pool_name *tmp;
5062         struct list_head *head;
5063         int rc = 0;
5064
5065         if (fsname && fsname[0] == '\0')
5066                 fsname = NULL;
5067         if (!fsname)
5068                 return -EINVAL;
5069
5070         memset(&lpld, 0, sizeof(lpld));
5071         INIT_LIST_HEAD(&lpld.lpld_list_head);
5072         lpld.lpld_exists = false;
5073         strncpy(lpld.lpld_fsname, fsname, sizeof(lpld.lpld_fsname) - 1);
5074         if (poolname && poolname[0])
5075                 strncpy(lpld.lpld_poolname, poolname,
5076                         sizeof(lpld.lpld_poolname) - 1);
5077         snprintf(logname, sizeof(logname), "%s-client", fsname);
5078         rc = jt_llog_print_iter(logname, 0, -1, llog_poollist_cb, &lpld, false,
5079                                 false);
5080
5081         if (poolname && poolname[0])
5082                 printf("Pool: %s.%s\n", fsname, poolname);
5083         else
5084                 printf("Pools from %s:\n", fsname);
5085
5086         head = &lpld.lpld_list_head;
5087         if (poolname && poolname[0] && !lpld.lpld_exists && list_empty(head))
5088                 return -ENOENT;
5089
5090         list_for_each_entry(tmp, head, lpn_list) {
5091                 if (poolname && poolname[0])
5092                         printf("%s\n", tmp->lpn_name);
5093                 else
5094                         printf("%s.%s\n", fsname, tmp->lpn_name);
5095                 list_del(&tmp->lpn_list);
5096                 free(tmp);
5097         }
5098
5099         return rc;
5100 }
5101
5102 static bool get_pools_path(char *fsname)
5103 {
5104         glob_t path;
5105         int rc;
5106
5107         rc = cfs_get_param_paths(&path, "lov/%s-*/pools", fsname);
5108         if (!rc)
5109                 cfs_free_param_data(&path);
5110
5111         return (rc == 0);
5112 }
5113
5114 static int extract_fsname_poolname(char **argv, char *fsname,
5115                                    char *poolname)
5116 {
5117         char *cmd = argv[0], *param = argv[1];
5118         char *ptr;
5119         int rc;
5120
5121         snprintf(fsname, PATH_MAX + 1, "%s", param);
5122         ptr = strchr(fsname, '.');
5123         if (!ptr) {
5124                 if (strcmp(cmd, "pool_list") == 0) {
5125                         poolname = NULL;
5126                         goto out;
5127                 }
5128                 fprintf(stderr, ". is missing in %s\n", fsname);
5129                 rc = -EINVAL;
5130                 goto err;
5131         }
5132
5133         if ((ptr - fsname) == 0) {
5134                 fprintf(stderr, "fsname is empty\n");
5135                 rc = -EINVAL;
5136                 goto err;
5137         }
5138
5139         *ptr = '\0';
5140         ++ptr;
5141
5142         if (ptr[0] == '\0') {
5143                 fprintf(stderr, "poolname is empty\n");
5144                 rc = -EINVAL;
5145                 goto err;
5146         }
5147
5148         strncpy(poolname, ptr, LOV_MAXPOOLNAME);
5149         poolname[LOV_MAXPOOLNAME] = '\0';
5150
5151         if (lov_pool_is_reserved(poolname)) {
5152                 fprintf(stderr, "poolname cannot be '%s'\n", poolname);
5153                 return -EINVAL;
5154         }
5155 out:
5156         return 0;
5157
5158 err:
5159         fprintf(stderr, "argument %s must be <fsname>.<poolname>\n", param);
5160         return rc;
5161 }
5162
5163 int jt_pool_cmd(int argc, char **argv)
5164 {
5165         enum lcfg_command_type cmd;
5166         char fsname[PATH_MAX + 1];
5167         char poolname[LOV_MAXPOOLNAME + 1];
5168         char *ostnames_buf = NULL;
5169         int i, rc;
5170         int *array = NULL, array_sz;
5171         struct {
5172                 int     rc;
5173                 char   *ostname;
5174         } *cmds = NULL;
5175
5176         switch (argc) {
5177         case 0:
5178         case 1: return CMD_HELP;
5179         case 2: {
5180                 rc = extract_fsname_poolname(argv, fsname, poolname);
5181                 if (rc)
5182                         break;
5183
5184                 if (strcmp("pool_new", argv[0]) == 0) {
5185                         cmd = LCFG_POOL_NEW;
5186                 } else if (strcmp("pool_destroy", argv[0]) == 0) {
5187                         cmd = LCFG_POOL_DEL;
5188                 } else if (strcmp("pool_list", argv[0]) == 0) {
5189                         if (get_pools_path(fsname))
5190                                 return llapi_poollist(argv[1]);
5191                         if (get_mgs_device() > 0)
5192                                 return llog_poollist(fsname, poolname);
5193                         fprintf(stderr,
5194                                 "Cannot run pool_list command since there is no local MGS/MDT or client\n");
5195                         return CMD_HELP;
5196                 } else {
5197                         return CMD_HELP;
5198                 }
5199
5200                 rc = pool_cmd(cmd, argv[0], argv[1], fsname, poolname, NULL);
5201                 if (rc)
5202                         break;
5203
5204                 check_pool_cmd_result(cmd, fsname, poolname, NULL);
5205                 break;
5206         }
5207         default: {
5208                 char format[2 * MAX_OBD_NAME];
5209
5210                 if (strcmp("pool_remove", argv[0]) == 0)
5211                         cmd = LCFG_POOL_REM;
5212                 else if (strcmp("pool_add", argv[0]) == 0)
5213                         cmd = LCFG_POOL_ADD;
5214                 else
5215                         return CMD_HELP;
5216
5217                 rc = extract_fsname_poolname(argv, fsname, poolname);
5218                 if (rc)
5219                         break;
5220
5221                 for (i = 2; i < argc; i++) {
5222                         int j;
5223
5224                         array_sz = get_array_idx(argv[i], format, &array);
5225                         if (array_sz == 0)
5226                                 return CMD_HELP;
5227
5228                         cmds = malloc(array_sz * sizeof(cmds[0]));
5229                         if (cmds) {
5230                                 ostnames_buf = malloc(array_sz *
5231                                                       (MAX_OBD_NAME + 1));
5232                         } else {
5233                                 free(array);
5234                                 rc = -ENOMEM;
5235                                 goto out;
5236                         }
5237
5238                         for (j = 0; j < array_sz; j++) {
5239                                 char ostname[MAX_OBD_NAME + 1];
5240                                 int rc2;
5241
5242                                 snprintf(ostname, MAX_OBD_NAME, format,
5243                                          array[j]);
5244                                 ostname[MAX_OBD_NAME] = '\0';
5245
5246                                 rc2 = check_and_complete_ostname(fsname,
5247                                                                 ostname);
5248                                 if (rc2) {
5249                                         free(array);
5250                                         free(cmds);
5251                                         if (ostnames_buf)
5252                                                 free(ostnames_buf);
5253                                         rc = rc ? rc : rc2;
5254                                         goto out;
5255                                 }
5256                                 if (ostnames_buf) {
5257                                         cmds[j].ostname =
5258                                         &ostnames_buf[(MAX_OBD_NAME + 1) * j];
5259                                         strcpy(cmds[j].ostname, ostname);
5260                                 } else {
5261                                         cmds[j].ostname = NULL;
5262                                 }
5263                                 cmds[j].rc = pool_cmd(cmd, argv[0], argv[1],
5264                                                       fsname, poolname,
5265                                                       ostname);
5266                                 /* Return an err if any of the add/dels fail */
5267                                 if (!rc)
5268                                         rc = cmds[j].rc;
5269                         }
5270                         for (j = 0; j < array_sz; j++) {
5271                                 if (!cmds[j].rc) {
5272                                         char ostname[MAX_OBD_NAME + 1];
5273
5274                                         if (!cmds[j].ostname) {
5275                                                 snprintf(ostname, MAX_OBD_NAME,
5276                                                          format, array[j]);
5277                                                 ostname[MAX_OBD_NAME] = '\0';
5278                                                 check_and_complete_ostname(
5279                                                         fsname, ostname);
5280                                         } else {
5281                                                 strcpy(ostname,
5282                                                        cmds[j].ostname);
5283                                         }
5284                                         check_pool_cmd_result(cmd, fsname,
5285                                                               poolname,
5286                                                               ostname);
5287                                 }
5288                         }
5289                         if (array_sz > 0)
5290                                 free(array);
5291                         if (cmds)
5292                                 free(cmds);
5293                         if (ostnames_buf)
5294                                 free(ostnames_buf);
5295                 }
5296                 fallthrough;
5297         }
5298         } /* switch */
5299
5300 out:
5301         if (rc != 0) {
5302                 errno = -rc;
5303                 perror(argv[0]);
5304         }
5305
5306         return rc;
5307 }
5308
5309 #ifdef HAVE_SERVER_SUPPORT
5310 static const char *barrier_status2name(enum barrier_status status)
5311 {
5312         switch (status) {
5313         case BS_INIT:
5314                 return "init";
5315         case BS_FREEZING_P1:
5316                 return "freezing_p1";
5317         case BS_FREEZING_P2:
5318                 return "freezing_p2";
5319         case BS_FROZEN:
5320                 return "frozen";
5321         case BS_THAWING:
5322                 return "thawing";
5323         case BS_THAWED:
5324                 return "thawed";
5325         case BS_FAILED:
5326                 return "failed";
5327         case BS_EXPIRED:
5328                 return "expired";
5329         case BS_RESCAN:
5330                 return "rescan";
5331         default:
5332                 return "unknown";
5333         }
5334 }
5335
5336 int jt_barrier_freeze(int argc, char **argv)
5337 {
5338         struct obd_ioctl_data data;
5339         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
5340         struct barrier_ctl bc;
5341         int rc;
5342
5343         if (argc < 2 || argc > 3)
5344                 return CMD_HELP;
5345
5346         memset(&data, 0, sizeof(data));
5347         rc = data.ioc_dev = get_mgs_device();
5348         if (rc < 0)
5349                 return rc;
5350
5351         memset(&bc, 0, sizeof(bc));
5352         bc.bc_version = BARRIER_VERSION_V1;
5353         bc.bc_cmd = BC_FREEZE;
5354         if (argc == 3)
5355                 bc.bc_timeout = atoi(argv[2]);
5356         if (bc.bc_timeout == 0)
5357                 bc.bc_timeout = BARRIER_TIMEOUT_DEFAULT;
5358
5359         if (strlen(argv[1]) > 8) {
5360                 fprintf(stderr,
5361                         "%s: fsname name %s is too long. It should not exceed 8.\n",
5362                         argv[0], argv[1]);
5363                 return -EINVAL;
5364         }
5365
5366         strncpy(bc.bc_name, argv[1], sizeof(bc.bc_name));
5367         data.ioc_inlbuf1 = (char *)&bc;
5368         data.ioc_inllen1 = sizeof(bc);
5369         memset(buf, 0, sizeof(rawbuf));
5370         rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
5371         if (rc) {
5372                 fprintf(stderr, "Fail to pack ioctl data: rc = %d.\n", rc);
5373                 return rc;
5374         }
5375
5376         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_BARRIER, buf);
5377         if (rc < 0)
5378                 fprintf(stderr, "Fail to freeze barrier for %s: %s\n",
5379                         argv[1], strerror(errno));
5380
5381         return rc;
5382 }
5383
5384 int jt_barrier_thaw(int argc, char **argv)
5385 {
5386         struct obd_ioctl_data data;
5387         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
5388         struct barrier_ctl bc;
5389         int rc;
5390
5391         if (argc != 2)
5392                 return CMD_HELP;
5393
5394         memset(&data, 0, sizeof(data));
5395         rc = data.ioc_dev = get_mgs_device();
5396         if (rc < 0)
5397                 return rc;
5398
5399         memset(&bc, 0, sizeof(bc));
5400         bc.bc_version = BARRIER_VERSION_V1;
5401         bc.bc_cmd = BC_THAW;
5402
5403         if (strlen(argv[1]) > 8) {
5404                 fprintf(stderr,
5405                         "fsname name %s is too long. It should not exceed 8.\n",
5406                         argv[1]);
5407                 return -EINVAL;
5408         }
5409
5410         strncpy(bc.bc_name, argv[1], sizeof(bc.bc_name));
5411         data.ioc_inlbuf1 = (char *)&bc;
5412         data.ioc_inllen1 = sizeof(bc);
5413         memset(buf, 0, sizeof(rawbuf));
5414         rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
5415         if (rc) {
5416                 fprintf(stderr, "Fail to pack ioctl data: rc = %d.\n", rc);
5417                 return rc;
5418         }
5419
5420         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_BARRIER, buf);
5421         if (rc < 0)
5422                 fprintf(stderr, "Fail to thaw barrier for %s: %s\n",
5423                         argv[1], strerror(errno));
5424
5425         return rc;
5426 }
5427
5428 int __jt_barrier_stat(const char *fsname, struct barrier_ctl *bc)
5429 {
5430         struct obd_ioctl_data data;
5431         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
5432         int rc;
5433
5434         memset(&data, 0, sizeof(data));
5435         rc = data.ioc_dev = get_mgs_device();
5436         if (rc < 0)
5437                 return rc;
5438
5439         memset(bc, 0, sizeof(*bc));
5440         bc->bc_version = BARRIER_VERSION_V1;
5441         bc->bc_cmd = BC_STAT;
5442         strncpy(bc->bc_name, fsname, sizeof(bc->bc_name) - 1);
5443         data.ioc_inlbuf1 = (char *)bc;
5444         data.ioc_inllen1 = sizeof(*bc);
5445         memset(buf, 0, sizeof(rawbuf));
5446         rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
5447         if (rc) {
5448                 fprintf(stderr, "Fail to pack ioctl data: rc = %d.\n", rc);
5449                 return rc;
5450         }
5451
5452         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_BARRIER, buf);
5453         if (rc < 0)
5454                 fprintf(stderr, "Fail to query barrier for %s: %s\n",
5455                         fsname, strerror(errno));
5456         else
5457                 llapi_ioctl_unpack(&data, buf, sizeof(rawbuf));
5458
5459         return rc;
5460 }
5461
5462 int jt_barrier_stat(int argc, char **argv)
5463 {
5464         struct barrier_ctl bc;
5465         static struct option long_opt_barrier_stat[] = {
5466                 {
5467                         .val            = 's',
5468                         .name           = "state",
5469                         .has_arg        = no_argument,
5470                 },
5471                 {       .val            = 't',
5472                         .name           = "timeout",
5473                         .has_arg        = no_argument,
5474                 },
5475                 {
5476                         NULL
5477                 }
5478         };
5479         const char *name;
5480         int index;
5481         int opt;
5482         int rc;
5483         bool state = false;
5484         bool timeout = false;
5485
5486         while ((opt = getopt_long(argc, argv, "st", long_opt_barrier_stat,
5487                                   &index)) != EOF) {
5488                 switch (opt) {
5489                 case 's':
5490                         state = true;
5491                         break;
5492                 case 't':
5493                         timeout = true;
5494                         break;
5495                 default:
5496                         return CMD_HELP;
5497                 }
5498         }
5499
5500         if (optind >= argc)
5501                 return CMD_HELP;
5502
5503         name = argv[optind];
5504         if (strlen(name) > 8) {
5505                 fprintf(stderr,
5506                         "fsname name %s is too long. It should not exceed 8.\n",
5507                         name);
5508                 return -EINVAL;
5509         }
5510
5511         rc = __jt_barrier_stat(name, &bc);
5512         if (!rc) {
5513                 if (state && !timeout)
5514                         printf("%s\n", barrier_status2name(bc.bc_status));
5515                 else if (timeout && !state)
5516                         printf("%d\n",
5517                                (bc.bc_status == BS_FREEZING_P1 ||
5518                                 bc.bc_status == BS_FREEZING_P2 ||
5519                                 bc.bc_status == BS_FROZEN) ?
5520                                bc.bc_timeout : 0);
5521                 else
5522                         printf("state: %s\ntimeout: %d seconds\n",
5523                                barrier_status2name(bc.bc_status),
5524                                (bc.bc_status == BS_FREEZING_P1 ||
5525                                 bc.bc_status == BS_FREEZING_P2 ||
5526                                 bc.bc_status == BS_FROZEN) ?
5527                                bc.bc_timeout : 0);
5528         }
5529
5530         return rc;
5531 }
5532
5533 int jt_barrier_rescan(int argc, char **argv)
5534 {
5535         struct obd_ioctl_data data;
5536         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
5537         struct barrier_ctl bc;
5538         int rc;
5539
5540         if (argc < 2 || argc > 3)
5541                 return CMD_HELP;
5542
5543         memset(&data, 0, sizeof(data));
5544         rc = data.ioc_dev = get_mgs_device();
5545         if (rc < 0)
5546                 return rc;
5547
5548         memset(&bc, 0, sizeof(bc));
5549         bc.bc_version = BARRIER_VERSION_V1;
5550         bc.bc_cmd = BC_RESCAN;
5551         if (argc == 3)
5552                 bc.bc_timeout = atoi(argv[2]);
5553         if (bc.bc_timeout == 0)
5554                 bc.bc_timeout = BARRIER_TIMEOUT_DEFAULT;
5555
5556         if (strlen(argv[1]) > 8) {
5557                 fprintf(stderr,
5558                         "fsname name %s is too long. It should not exceed 8.\n",
5559                         argv[1]);
5560                 return -EINVAL;
5561         }
5562
5563         strncpy(bc.bc_name, argv[1], sizeof(bc.bc_name));
5564         data.ioc_inlbuf1 = (char *)&bc;
5565         data.ioc_inllen1 = sizeof(bc);
5566         memset(buf, 0, sizeof(rawbuf));
5567         rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
5568         if (rc) {
5569                 fprintf(stderr, "Fail to pack ioctl data: rc = %d.\n", rc);
5570                 return rc;
5571         }
5572
5573         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_BARRIER, buf);
5574         if (rc < 0) {
5575                 fprintf(stderr, "Fail to rescan barrier bitmap for %s: %s\n",
5576                         argv[1], strerror(errno));
5577         } else {
5578                 llapi_ioctl_unpack(&data, buf, sizeof(rawbuf));
5579                 printf("%u of %u MDT(s) in the filesystem %s are inactive\n",
5580                        bc.bc_absence, bc.bc_total, argv[1]);
5581         }
5582
5583         return rc;
5584 }
5585 #endif /* HAVE_SERVER_SUPPORT */
5586
5587 int jt_get_obj_version(int argc, char **argv)
5588 {
5589         struct lu_fid fid;
5590         struct obd_ioctl_data data;
5591         __u64 version, id = ULLONG_MAX, group = ULLONG_MAX;
5592         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf, *fidstr;
5593         int rc, c;
5594
5595         while ((c = getopt(argc, argv, "i:g:")) != -1) {
5596                 switch (c) {
5597                 case 'i':
5598                         id = strtoull(optarg, NULL, 0);
5599                         break;
5600                 case 'g':
5601                         group = strtoull(optarg, NULL, 0);
5602                         break;
5603                 default:
5604                         return CMD_HELP;
5605                 }
5606         }
5607
5608         argc -= optind;
5609         fidstr = *(argv + optind);
5610
5611         if (!(id != ULLONG_MAX && group != ULLONG_MAX && argc == 0) &&
5612             !(id == ULLONG_MAX && group == ULLONG_MAX && argc == 1))
5613                 return CMD_HELP;
5614
5615         memset(&data, 0, sizeof(data));
5616         data.ioc_dev = cur_device;
5617         if (argc == 1) {
5618                 rc = llapi_fid_parse(fidstr, &fid, NULL);
5619                 if (rc) {
5620                         fprintf(stderr, "%s: error parsing FID '%s': %s\n",
5621                                 jt_cmdname(argv[0]), fidstr, strerror(-rc));
5622                         return rc;
5623                 }
5624
5625                 data.ioc_inlbuf1 = (char *)&fid;
5626                 data.ioc_inllen1 = sizeof(fid);
5627         } else {
5628                 data.ioc_inlbuf3 = (char *)&id;
5629                 data.ioc_inllen3 = sizeof(id);
5630                 data.ioc_inlbuf4 = (char *)&group;
5631                 data.ioc_inllen4 = sizeof(group);
5632         }
5633         data.ioc_inlbuf2 = (char *)&version;
5634         data.ioc_inllen2 = sizeof(version);
5635
5636         memset(buf, 0, sizeof(*buf));
5637         rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
5638         if (rc) {
5639                 fprintf(stderr, "error: %s: packing ioctl arguments: %s\n",
5640                         jt_cmdname(argv[0]), strerror(-rc));
5641                 return rc;
5642         }
5643
5644         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_GET_OBJ_VERSION, buf);
5645         if (rc) {
5646                 fprintf(stderr, "error: %s: ioctl: %s\n",
5647                         jt_cmdname(argv[0]), strerror(errno));
5648                 return -errno;
5649         }
5650
5651         llapi_ioctl_unpack(&data, buf, sizeof(rawbuf));
5652         printf("%#jx\n", (uintmax_t)version);
5653
5654         return 0;
5655 }
5656
5657 #ifdef HAVE_SERVER_SUPPORT
5658 int jt_changelog_register(int argc, char **argv)
5659 {
5660         struct option long_opts[] = {
5661         { .val = 'h', .name = "help", .has_arg = no_argument },
5662         { .val = 'm', .name = "mask", .has_arg = required_argument },
5663         { .val = 'n', .name = "nameonly", .has_arg = no_argument },
5664         { .val = 'u', .name = "user", .has_arg = required_argument },
5665         { .name = NULL } };
5666         struct obd_ioctl_data data = { 0 };
5667         char rawbuf[MAX_IOC_BUFLEN] = "";
5668         char *buf = rawbuf;
5669         char *device = lcfg_get_devname();
5670         char *username = NULL, *usermask = NULL;
5671         bool print_name_only = false;
5672         int c;
5673         int rc;
5674
5675         if (cur_device < 0 || !device)
5676                 return CMD_HELP;
5677
5678         while ((c = getopt_long(argc, argv, "hm:nu:", long_opts, NULL)) != -1) {
5679                 switch (c) {
5680                 case 'm':
5681                         usermask = strdup(optarg);
5682                         if (!usermask) {
5683                                 fprintf(stderr,
5684                                         "error: %s: %s: cannot copy '%s'\n",
5685                                         jt_cmdname(argv[0]), strerror(errno),
5686                                         optarg);
5687                                 return -errno;
5688                         }
5689                         break;
5690                 case 'n':
5691                         print_name_only = true;
5692                         break;
5693                 case 'u':
5694                         username = strdup(optarg);
5695                         if (!username) {
5696                                 fprintf(stderr,
5697                                         "error: %s: %s: cannot copy '%s'\n",
5698                                         jt_cmdname(argv[0]), strerror(errno),
5699                                         optarg);
5700                                 return -errno;
5701                         }
5702                         break;
5703                 case 'h':
5704                 default:
5705                         free(username);
5706                         free(usermask);
5707                         return CMD_HELP;
5708                 }
5709         }
5710
5711         data.ioc_dev = cur_device;
5712         if (username) {
5713                 data.ioc_inlbuf1 = username;
5714                 data.ioc_inllen1 = strlen(username) + 1;
5715         }
5716
5717         if (usermask) {
5718                 data.ioc_inlbuf2 = usermask;
5719                 data.ioc_inllen2 = strlen(usermask) + 1;
5720         }
5721
5722         rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
5723         if (rc < 0) {
5724                 fprintf(stderr, "error: %s: cannot pack ioctl: %s\n",
5725                         jt_cmdname(argv[0]), strerror(-rc));
5726                 goto out;
5727         }
5728         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_CHANGELOG_REG, buf);
5729         if (rc < 0) {
5730                 rc = -errno;
5731                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
5732                         rc == -EEXIST ? "User exists" : strerror(-rc));
5733                 goto out;
5734         }
5735
5736         llapi_ioctl_unpack(&data, buf, sizeof(rawbuf));
5737
5738         if (data.ioc_u32_1 == 0) {
5739                 fprintf(stderr, "received invalid userid!\n");
5740                 rc = -EPROTO;
5741                 goto out;
5742         }
5743
5744         if (print_name_only)
5745                 printf("%s%u%s%s\n", CHANGELOG_USER_PREFIX, data.ioc_u32_1,
5746                        username ? "-" : "", username ? : "");
5747         else
5748                 printf("%s: Registered changelog userid '%s%u%s%s'\n",
5749                        device, CHANGELOG_USER_PREFIX, data.ioc_u32_1,
5750                        username ? "-" : "", username ? : "");
5751 out:
5752         free(usermask);
5753         free(username);
5754         return rc;
5755 }
5756
5757 int jt_changelog_deregister(int argc, char **argv)
5758 {
5759         struct option long_opts[] = {
5760         { .val = 'h', .name = "help", .has_arg = no_argument },
5761         { .val = 'u', .name = "user", .has_arg = required_argument },
5762         { .name = NULL } };
5763         struct obd_ioctl_data data = { 0 };
5764         char rawbuf[MAX_IOC_BUFLEN] = "";
5765         char *buf = rawbuf;
5766         char *device = lcfg_get_devname();
5767         char *username = NULL;
5768         int id = 0;
5769         int c, rc;
5770
5771         if (cur_device < 0 || !device)
5772                 return CMD_HELP;
5773
5774         while ((c = getopt_long(argc, argv, "hu:", long_opts, NULL)) != -1) {
5775                 switch (c) {
5776                 case 'u':
5777                         username = strdup(optarg);
5778                         if (!username) {
5779                                 fprintf(stderr,
5780                                         "error: %s: %s: cannot copy '%s'\n",
5781                                         jt_cmdname(argv[0]), strerror(errno),
5782                                         optarg);
5783                                 return -errno;
5784                         }
5785                         break;
5786                 case 'h':
5787                 default:
5788                         free(username);
5789                         return CMD_HELP;
5790                 }
5791         }
5792
5793         if (1 == optind && argc > 1) {
5794                 /* first check if pure ID was passed */
5795                 id = atoi(argv[optind]);
5796                 /* nameless cl<ID> format or cl<ID>-... format, only ID matters */
5797                 if (id == 0)
5798                         sscanf(argv[optind], CHANGELOG_USER_PREFIX"%d", &id);
5799
5800                 /* no valid ID was parsed */
5801                 if (id <= 0) {
5802                         rc = -EINVAL;
5803                         fprintf(stderr,
5804                                 "error: %s: expect <ID> or cl<ID>[-name] got '%s'\n",
5805                                 strerror(-rc), argv[optind]);
5806                         return CMD_HELP;
5807                 }
5808                 optind++;
5809         }
5810
5811         if (optind < argc || argc == 1)
5812                 return CMD_HELP;
5813
5814         data.ioc_dev = cur_device;
5815         data.ioc_u32_1 = id;
5816         if (username) {
5817                 data.ioc_inlbuf1 = username;
5818                 data.ioc_inllen1 = strlen(username) + 1;
5819         }
5820
5821         rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
5822         if (rc < 0) {
5823                 fprintf(stderr, "error: %s: invalid ioctl\n",
5824                         jt_cmdname(argv[0]));
5825                 return rc;
5826         }
5827
5828         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_CHANGELOG_DEREG, buf);
5829         if (rc < 0) {
5830                 rc = -errno;
5831                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
5832                         rc == -ENOENT ? "User not found" : strerror(-rc));
5833                 return rc;
5834         }
5835
5836         llapi_ioctl_unpack(&data, buf, sizeof(rawbuf));
5837         printf("%s: Deregistered changelog user #%u\n", device, data.ioc_u32_1);
5838
5839         return 0;
5840 }
5841 #else /* !HAVE_SERVER_SUPPORT */
5842 int jt_changelog_register(int argc, char **argv)
5843 {
5844         fprintf(stderr, "error: %s: invalid ioctl\n",
5845                 jt_cmdname(argv[0]));
5846         return -EOPNOTSUPP;
5847 }
5848
5849 int jt_changelog_deregister(int argc, char **argv)
5850 {
5851         fprintf(stderr, "error: %s: invalid ioctl\n",
5852                 jt_cmdname(argv[0]));
5853         return -EOPNOTSUPP;
5854 }
5855 #endif /* HAVE_SERVER_SUPPORT */
5856
5857 int jt_pcc_add(int argc, char **argv)
5858 {
5859         struct option long_opts[] = {
5860                 { .val = 'p', .name = "param", .has_arg = required_argument },
5861                 { .name = NULL } };
5862         const char *mntpath;
5863         const char *pccpath;
5864         char *param = NULL;
5865         char cmd[PATH_MAX];
5866         int rc;
5867
5868         optind = 1;
5869         while ((rc = getopt_long(argc, argv, "p:", long_opts, NULL)) != -1) {
5870                 switch (rc) {
5871                 case 'p':
5872                         param = optarg;
5873                         break;
5874                 default:
5875                         return CMD_HELP;
5876                 }
5877         }
5878
5879         if (!param) {
5880                 fprintf(stderr, "%s: must specify the config param for PCC\n",
5881                         jt_cmdname(argv[0]));
5882                 return CMD_HELP;
5883         }
5884
5885         if (optind + 2 != argc) {
5886                 fprintf(stderr,
5887                         "%s: must specify mount path and PCC path %d:%d\n",
5888                         jt_cmdname(argv[0]), optind, argc);
5889                 return CMD_HELP;
5890         }
5891
5892         mntpath = argv[optind++];
5893         pccpath = argv[optind];
5894
5895         snprintf(cmd, PATH_MAX, "add %s %s", pccpath, param);
5896         rc = llapi_pccdev_set(mntpath, cmd);
5897         if (rc < 0)
5898                 fprintf(stderr, "%s: failed to run '%s' on %s\n",
5899                         jt_cmdname(argv[0]), cmd, mntpath);
5900
5901         return rc;
5902 }
5903
5904 int jt_pcc_del(int argc, char **argv)
5905 {
5906         const char *mntpath;
5907         const char *pccpath;
5908         char cmd[PATH_MAX];
5909         int rc;
5910
5911         optind = 1;
5912         if (argc != 3) {
5913                 fprintf(stderr, "%s: require 3 arguments\n",
5914                         jt_cmdname(argv[0]));
5915                 return CMD_HELP;
5916         }
5917
5918         mntpath = argv[optind++];
5919         pccpath = argv[optind++];
5920
5921         snprintf(cmd, PATH_MAX, "del %s", pccpath);
5922         rc = llapi_pccdev_set(mntpath, cmd);
5923         if (rc < 0)
5924                 fprintf(stderr, "%s: failed to run '%s' on %s\n",
5925                         jt_cmdname(argv[0]), cmd, mntpath);
5926
5927         return rc;
5928 }
5929
5930 int jt_pcc_clear(int argc, char **argv)
5931 {
5932         const char *mntpath;
5933         int rc;
5934
5935         optind = 1;
5936         if (argc != 2) {
5937                 fprintf(stderr, "%s: require 2 arguments\n",
5938                         jt_cmdname(argv[0]));
5939                 return CMD_HELP;
5940         }
5941
5942         mntpath = argv[optind];
5943         rc = llapi_pccdev_set(mntpath, "clear");
5944         if (rc < 0)
5945                 fprintf(stderr, "%s: failed to run 'clear' on %s\n",
5946                         jt_cmdname(argv[0]), mntpath);
5947
5948         return rc;
5949 }
5950
5951 int jt_pcc_list(int argc, char **argv)
5952 {
5953         const char *mntpath;
5954         int rc;
5955
5956         optind = 1;
5957         if (argc != 2) {
5958                 fprintf(stderr, "%s: require 2 arguments\n",
5959                         jt_cmdname(argv[0]));
5960                 return CMD_HELP;
5961         }
5962
5963         mntpath = argv[optind];
5964         rc = llapi_pccdev_get(mntpath);
5965         if (rc < 0)
5966                 fprintf(stderr, "%s: failed to run 'pcc list' on %s\n",
5967                         jt_cmdname(argv[0]), mntpath);
5968
5969         return rc;
5970 }