Whamcloud - gitweb
LU-16138 kernel: preserve RHEL8.x server kABI for block integrity
[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         if (end == -1)
2700                 end = 0x7fffffff;
2701
2702         data.ioc_dev = cur_device;
2703         data.ioc_inlbuf1 = logname;
2704         data.ioc_inllen1 = strlen(logname) + 1;
2705
2706         /*
2707          * Estimate about 128 characters per configuration record.  Not all
2708          * records will be printed in any case, so they should easily fit.  If
2709          * not, the kernel will return -EOVERFLOW and ask for fewer records.
2710          *
2711          * We don't want to request records from the kernel one-at-a-time, as
2712          * it restarts the config llog iteration from the beginning, so we
2713          * fetch multiple records from the kernel per call and split locally.
2714          */
2715         for (rec = start; rec < end; rec += inc) {
2716                 char *record = ((struct obd_ioctl_data *)buf)->ioc_bulk;
2717
2718 retry:
2719                 snprintf(startbuf, sizeof(startbuf), "%lu", rec);
2720                 snprintf(endbuf, sizeof(endbuf), "%lu",
2721                          end < rec + inc - 1 ? end : rec + inc - 1);
2722
2723                 data.ioc_u32_1 = raw ? 1 : 0;
2724                 /* start and end record numbers are passed as ASCII digits */
2725                 data.ioc_inlbuf2 = startbuf;
2726                 data.ioc_inllen2 = strlen(startbuf) + 1;
2727                 data.ioc_inlbuf3 = endbuf;
2728                 data.ioc_inllen3 = strlen(endbuf) + 1;
2729
2730                 data.ioc_inllen4 = sizeof(rawbuf) -
2731                         __ALIGN_KERNEL(sizeof(data), 8) -
2732                         __ALIGN_KERNEL(data.ioc_inllen1, 8) -
2733                         __ALIGN_KERNEL(data.ioc_inllen2, 8) -
2734                         __ALIGN_KERNEL(data.ioc_inllen3, 8);
2735                 memset(buf, 0, sizeof(rawbuf));
2736                 rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
2737                 if (rc) {
2738                         fprintf(stderr, "%s: invalid ioctl data\n", logname);
2739                         goto out;
2740                 }
2741
2742                 rc = l_ioctl(OBD_DEV_ID, OBD_IOC_LLOG_PRINT, buf);
2743                 if (rc == -EOVERFLOW && inc > 2) {
2744                         inc /= 2;
2745                         goto retry;
2746                 }
2747                 if (rc) {
2748                         fprintf(stderr, "%s: OBD_IOC_LLOG_PRINT failed: %s\n",
2749                                 logname, strerror(errno));
2750                         rc = -errno;
2751                         goto out;
2752                 }
2753
2754                 /* There is no "end of list" marker, record was not modified */
2755                 if (strcmp(record, logname) == 0)
2756                         break;
2757
2758                 rc = llog_process_records(record_cb, record, private, reverse);
2759                 if (rc)
2760                         goto out;
2761         }
2762
2763 out:
2764         return rc;
2765 }
2766
2767 static int llog_parse_catalog_options(int *argc, char ***argv, char **catalog,
2768                                       long *start, long *end, int *raw)
2769 {
2770         const struct option long_opts[] = {
2771         /* the --catalog option is not required, just for consistency */
2772         { .val = 'c',   .name = "catalog",      .has_arg = required_argument },
2773         { .val = 'e',   .name = "end",          .has_arg = required_argument },
2774         { .val = 'h',   .name = "help",         .has_arg = no_argument },
2775         { .val = 'r',   .name = "raw",          .has_arg = no_argument },
2776         { .val = 's',   .name = "start",        .has_arg = required_argument },
2777         { .name = NULL } };
2778         char *cmd = (*argv)[0];
2779         char *endp;
2780         int c;
2781
2782         if (!catalog || !start || !end)
2783                 return -EINVAL;
2784
2785         /* now process command line arguments*/
2786         while ((c = getopt_long(*argc, *argv, "c:e:hrs:",
2787                                 long_opts, NULL)) != -1) {
2788                 switch (c) {
2789                 case 'c':
2790                         *catalog = optarg;
2791                         break;
2792                 case 'e':
2793                         *end = strtol(optarg, &endp, 0);
2794                         if (*endp != '\0') {
2795                                 fprintf(stderr, "%s: bad end value '%s'\n",
2796                                         cmd, optarg);
2797                                 return CMD_HELP;
2798                         }
2799                         break;
2800                 case 'r':
2801                         if (!raw)
2802                                 return CMD_HELP;
2803                         *raw = 1;
2804                         break;
2805                 case 's':
2806                         *start = strtol(optarg, &endp, 0);
2807                         if (*endp != '\0') {
2808                                 fprintf(stderr, "%s: bad start value '%s'\n",
2809                                         cmd, optarg);
2810                                 return CMD_HELP;
2811                         }
2812                         break;
2813                 case 'h':
2814                 default:
2815                         return CMD_HELP;
2816                 }
2817         }
2818         *argc -= optind;
2819         *argv += optind;
2820
2821         /*
2822          * support old optional positional parameters only if they were
2823          * not already specified with named arguments: logname [start [end]]
2824          */
2825         if (*argc >= 1) {
2826                 if (*catalog) {
2827                         fprintf(stderr,
2828                                 "%s: logname is set, unknown argument '%s'\n",
2829                                 cmd, (*argv)[0]);
2830                         return CMD_HELP;
2831                 }
2832                 *catalog = (*argv)[0];
2833                 (*argc)--;
2834                 (*argv)++;
2835         }
2836
2837         if (*catalog == NULL) {
2838                 fprintf(stderr, "%s: no logname specified\n", cmd);
2839                 return CMD_HELP;
2840         }
2841
2842         if (*argc >= 1) {
2843                 if (*start != 1) {
2844                         fprintf(stderr,
2845                                 "%s: --start is set, unknown argument '%s'\n",
2846                                 cmd, (*argv)[0]);
2847                         return CMD_HELP;
2848                 }
2849
2850                 *start = strtol((*argv)[0], &endp, 0);
2851                 if (*endp != '\0') {
2852                         fprintf(stderr, "%s: bad start value '%s'\n",
2853                                 cmd, (*argv)[0]);
2854                         return CMD_HELP;
2855                 }
2856                 (*argc)--;
2857                 (*argv)++;
2858         }
2859         if (*argc >= 1) {
2860                 if (*end != -1) {
2861                         fprintf(stderr,
2862                                 "%s: --end is set, unknown argument '%s'\n",
2863                                 cmd, (*argv)[0]);
2864                         return CMD_HELP;
2865                 }
2866
2867                 *end = strtol((*argv)[0], &endp, 0);
2868                 if (*endp != '\0') {
2869                         fprintf(stderr, "%s: bad end value '%s'\n",
2870                                 cmd, (*argv)[0]);
2871                         return CMD_HELP;
2872                 }
2873                 (*argc)--;
2874                 (*argv)++;
2875         }
2876         if (*argc > 1) {
2877                 fprintf(stderr, "%s: unknown argument '%s'\n", cmd, (*argv)[0]);
2878                 return CMD_HELP;
2879         }
2880
2881         if (*end != -1 && *end < *start) {
2882                 fprintf(stderr, "%s: end '%lu' less than than start '%lu'\n",
2883                         cmd, *end, *start);
2884                 return CMD_HELP;
2885         }
2886
2887         return 0;
2888 }
2889
2890 int jt_llog_print(int argc, char **argv)
2891 {
2892         char *catalog = NULL;
2893         long start = 1, end = -1;
2894         int raw = 0;
2895         int rc;
2896
2897         rc = llog_parse_catalog_options(&argc, &argv, &catalog, &start, &end,
2898                                         &raw);
2899         if (rc)
2900                 return rc;
2901
2902         if (llog_default_device(LLOG_DFLT_MGS_SET))
2903                 return CMD_INCOMPLETE;
2904
2905         rc = jt_llog_print_iter(catalog, start, end, jt_llog_print_cb,
2906                                 NULL, false, !!raw);
2907
2908         llog_default_device(LLOG_DFLT_DEV_RESET);
2909
2910         return rc;
2911 }
2912
2913 /*
2914  * Parse catalog, log ID, and optionally a log index with either optional
2915  * arguments or positional arguments.  Only the initial catalog argument
2916  * may be positional with other optional arguments.
2917  *
2918  * The positional arguments option should eventually be phased out.
2919  */
2920 static int llog_parse_catalog_log_idx(int *argc, char ***argv, const char *opts,
2921                                       struct obd_ioctl_data *data)
2922 {
2923         const struct option long_opts[] = {
2924         /* the --catalog option is not required, just for consistency */
2925         { .val = 'c',   .name = "catalog",      .has_arg = required_argument },
2926         { .val = 'h',   .name = "help",         .has_arg = no_argument },
2927         { .val = 'i',   .name = "log_idx",      .has_arg = required_argument },
2928         { .val = 'l',   .name = "log_id",       .has_arg = required_argument },
2929         { .name = NULL } };
2930         int c;
2931
2932         /* sanity check */
2933         if (!data || *argc <= 1)
2934                 return -1;
2935
2936         data->ioc_dev = cur_device;
2937
2938         /* now process command line arguments*/
2939         while ((c = getopt_long(*argc, *argv, opts, long_opts, NULL)) != -1) {
2940                 switch (c) {
2941                 case 'c':
2942                         data->ioc_inllen1 = strlen(optarg) + 1;
2943                         data->ioc_inlbuf1 = optarg;
2944                         break;
2945                 case 'i':
2946                         data->ioc_inllen3 = strlen(optarg) + 1;
2947                         data->ioc_inlbuf3 = optarg;
2948                         break;
2949                 case 'l': /* The log_id option isn't currently needed for
2950                            * cancel as mdt_iocontrol() handles IOC_LLOG_CANCEL,
2951                            * but we may as well keep it for now.
2952                            */
2953                         data->ioc_inllen2 = strlen(optarg) + 1;
2954                         data->ioc_inlbuf2 = optarg;
2955                         break;
2956                 case 'h':
2957                 default:
2958                         return CMD_HELP;
2959                 }
2960         }
2961
2962         *argc -= optind;
2963         *argv += optind;
2964
2965         /* Allow catalog to be specified as first option without --catalog */
2966         if (!data->ioc_inlbuf1 && *argc > 0) {
2967                 data->ioc_inlbuf1 = (*argv)[0];
2968                 data->ioc_inllen1 = strlen((*argv)[0]) + 1;
2969                 (*argc)--;
2970                 (*argv)++;
2971         }
2972
2973         return 0;
2974 }
2975
2976 int jt_llog_cancel(int argc, char **argv)
2977 {
2978         struct obd_ioctl_data data = { 0 };
2979         char rawbuf[MAX_IOC_BUFLEN] = "", *buf = rawbuf;
2980         char *cmd = argv[0];
2981         int rc;
2982
2983         /* Manage default device */
2984         if (llog_default_device(LLOG_DFLT_MGS_SET))
2985                 return CMD_INCOMPLETE;
2986
2987         /* Parse catalog file (in inlbuf1) and named parameters */
2988         rc = llog_parse_catalog_log_idx(&argc, &argv, "c:hi:l:", &data);
2989
2990         /*
2991          * Handle old positional parameters if not using named parameters,
2992          * either "<catalog> <log_idx>" or "<catalog> <log_id> <log_idx>".
2993          * It was "inlbuf3 = log_idx", and "inlbuf2 = log_id" (ignored by
2994          * config log cancel), and shows why I hate positional parameters.
2995          */
2996         if (argc == 1) {
2997                 data.ioc_inllen3 = strlen(argv[0]) + 1;
2998                 data.ioc_inlbuf3 = argv[0];
2999         } else if (argc == 2) {
3000                 data.ioc_inllen2 = strlen(argv[0]) + 1;
3001                 data.ioc_inlbuf2 = argv[0];
3002                 data.ioc_inllen3 = strlen(argv[1]) + 1;
3003                 data.ioc_inlbuf3 = argv[1];
3004         }
3005
3006         if (!data.ioc_inlbuf1 || !data.ioc_inlbuf3) {
3007                 /* missing mandatory parameters */
3008                 rc = CMD_HELP;
3009                 goto err;
3010         }
3011
3012         rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
3013         if (rc) {
3014                 fprintf(stderr, "%s: ioctl_pack for catalog '%s' failed: %s\n",
3015                         jt_cmdname(cmd), data.ioc_inlbuf1, strerror(-rc));
3016                 goto err;
3017         }
3018
3019         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_LLOG_CANCEL, buf);
3020         if (rc)
3021                 fprintf(stderr, "%s: cancel catalog '%s:%s' failed: %s\n",
3022                         jt_cmdname(cmd), data.ioc_inlbuf1, data.ioc_inlbuf3,
3023                         strerror(errno));
3024
3025 err:
3026         llog_default_device(LLOG_DFLT_DEV_RESET);
3027         return rc;
3028 }
3029
3030 int jt_llog_check(int argc, char **argv)
3031 {
3032         struct obd_ioctl_data data = { 0 };
3033         char rawbuf[MAX_IOC_BUFLEN] = "", *buf = rawbuf;
3034         char *catalog = NULL;
3035         char startbuf[16], endbuf[16];
3036         long start = 1, end = -1;
3037         char *cmd = argv[0];
3038         int rc;
3039
3040         rc = llog_parse_catalog_options(&argc, &argv, &catalog, &start,
3041                                         &end, NULL);
3042         if (rc)
3043                 return rc;
3044
3045         if (llog_default_device(LLOG_DFLT_MGS_SET))
3046                 return CMD_INCOMPLETE;
3047
3048         if (end == -1)
3049                 end = 0x7fffffff;
3050
3051         data.ioc_dev = cur_device;
3052         data.ioc_inllen1 = strlen(catalog) + 1;
3053         data.ioc_inlbuf1 = catalog;
3054
3055         snprintf(startbuf, sizeof(startbuf), "%lu", start);
3056         snprintf(endbuf, sizeof(endbuf), "%lu", end);
3057         /* start and end record numbers are passed as ASCII digits */
3058         data.ioc_inllen2 = strlen(startbuf) + 1;
3059         data.ioc_inlbuf2 = startbuf;
3060         data.ioc_inllen3 = strlen(endbuf) + 1;
3061         data.ioc_inlbuf3 = endbuf;
3062
3063         data.ioc_inllen4 = sizeof(rawbuf) - __ALIGN_KERNEL(sizeof(data), 8) -
3064                            __ALIGN_KERNEL(data.ioc_inllen1, 8) -
3065                            __ALIGN_KERNEL(data.ioc_inllen2, 8) -
3066                            __ALIGN_KERNEL(data.ioc_inllen3, 8);
3067         rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
3068         if (rc) {
3069                 fprintf(stderr, "%s: ioctl_pack failed for catalog '%s': %s\n",
3070                         jt_cmdname(cmd), data.ioc_inlbuf1, strerror(-rc));
3071                 goto err;
3072         }
3073
3074         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_LLOG_CHECK, buf);
3075         if (rc == 0)
3076                 fprintf(stdout, "%s", ((struct obd_ioctl_data *)buf)->ioc_bulk);
3077         else
3078                 fprintf(stderr, "%s: OBD_IOC_LLOG_CHECK failed: %s\n",
3079                         jt_cmdname(cmd), strerror(errno));
3080 err:
3081         llog_default_device(LLOG_DFLT_DEV_RESET);
3082         return rc;
3083 }
3084
3085 int jt_llog_remove(int argc, char **argv)
3086 {
3087         struct obd_ioctl_data data = { 0 };
3088         char rawbuf[MAX_IOC_BUFLEN] = "", *buf = rawbuf;
3089         char *cmd = argv[0];
3090         int rc;
3091
3092         if (llog_default_device(LLOG_DFLT_MGS_SET))
3093                 return CMD_INCOMPLETE;
3094
3095         rc = llog_parse_catalog_log_idx(&argc, &argv, "c:hl:", &data);
3096         if (rc)
3097                 goto err;
3098
3099         if (argc == 1) {
3100                 if (data.ioc_inlbuf2) {
3101                         fprintf(stderr,
3102                                 "%s: --log_id is set, unknown argument '%s'\n",
3103                                 jt_cmdname(cmd), argv[0]);
3104                         rc = CMD_HELP;
3105                         goto err;
3106                 }
3107
3108                 data.ioc_inllen2 = strlen(argv[0]) + 1;
3109                 data.ioc_inlbuf2 = argv[0];
3110         }
3111
3112         rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
3113         if (rc) {
3114                 fprintf(stderr, "%s: ioctl_pack for catalog '%s' failed: %s\n",
3115                         jt_cmdname(cmd), data.ioc_inlbuf1, strerror(-rc));
3116                 goto err;
3117         }
3118
3119         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_LLOG_REMOVE, buf);
3120         if (rc)
3121                 fprintf(stderr, "%s: cancel catalog '%s:%s' failed: %s\n",
3122                         jt_cmdname(cmd), data.ioc_inlbuf1, data.ioc_inlbuf2,
3123                         strerror(-rc));
3124
3125 err:
3126         llog_default_device(LLOG_DFLT_DEV_RESET);
3127         return rc;
3128 }
3129
3130 static void signal_server(int sig)
3131 {
3132         if (sig == SIGINT) {
3133                 do_disconnect("sigint", 1);
3134                 exit(1);
3135         } else {
3136                 fprintf(stderr, "%s: got signal %d\n", jt_cmdname("sigint"),
3137                         sig);
3138         }
3139 }
3140
3141 int obd_initialize(int argc, char **argv)
3142 {
3143         if (shmem_setup() != 0)
3144                 return -1;
3145
3146         register_ioc_dev(OBD_DEV_ID, OBD_DEV_PATH);
3147
3148         return 0;
3149 }
3150
3151 void obd_finalize(int argc, char **argv)
3152 {
3153         struct sigaction sigact;
3154
3155         /* sigact initialization */
3156         sigact.sa_handler = signal_server;
3157         sigfillset(&sigact.sa_mask);
3158         sigact.sa_flags = SA_RESTART;
3159         /* coverity[uninit_use_in_call] */
3160         sigaction(SIGINT, &sigact, NULL);
3161
3162         shmem_cleanup();
3163         do_disconnect(argv[0], 1);
3164 }
3165
3166 /**
3167  * Get the index of the last llog record
3168  *
3169  * logid:            [0x3:0xa:0x0]:0
3170  * flags:            4 (plain)
3171  * records_count:    57
3172  * last_index:       57
3173  *
3174  * \param logname[in]   pointer to config log name
3175  *
3176  * \retval              > 0 on success
3177  *                      <= 0 on error
3178  */
3179 static long llog_last_index(char *logname)
3180 {
3181         struct obd_ioctl_data data = { 0 };
3182         char rawbuf[MAX_IOC_BUFLEN] = "", *buf = rawbuf;
3183         char *last_index;
3184         long rc;
3185
3186         data.ioc_dev = cur_device;
3187         data.ioc_inllen1 = strlen(logname) + 1;
3188         data.ioc_inlbuf1 = logname;
3189         data.ioc_inllen2 = sizeof(rawbuf) - __ALIGN_KERNEL(sizeof(data), 8) -
3190                            __ALIGN_KERNEL(data.ioc_inllen1, 8);
3191         rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
3192         if (rc) {
3193                 fprintf(stderr, "%s: ioctl_pack failed for catalog '%s': %s\n",
3194                         __func__, logname, strerror(-rc));
3195                 return rc;
3196         }
3197
3198         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_LLOG_INFO, buf);
3199         if (rc == 0) {
3200                 last_index = strstr(((struct obd_ioctl_data *)buf)->ioc_bulk,
3201                                     "last_index:");
3202                 return strtol(last_index + 11, NULL, 10);
3203         }
3204
3205         rc = -errno;
3206
3207         return rc;
3208 }
3209
3210 static char *get_llog_event_name(__u32 cmd)
3211 {
3212 #ifdef HAVE_SERVER_SUPPORT
3213         struct lcfg_type_data *data;
3214
3215         data = lcfg_cmd2data(cmd);
3216         if (data)
3217                 return data->ltd_name;
3218 #endif
3219         return NULL;
3220 }
3221
3222 static char *get_event_filter(__u32 cmd)
3223 {
3224         char *event_name;
3225         char *filter = NULL;
3226         int len;
3227
3228         event_name = get_llog_event_name(cmd);
3229         if (event_name) {
3230                 /* 9 bytes for "event: , " */
3231                 len = 9 + strlen(event_name);
3232                 filter = malloc(len + 1);
3233                 if (!filter)
3234                         return NULL;
3235                 memset(filter, 0, len + 1);
3236                 snprintf(filter, len, "event: %s, ", event_name);
3237                 return filter;
3238         }
3239
3240         return NULL;
3241 }
3242
3243 /**
3244  * Callback to search ostname in llog
3245  * - { index: 23, event: attach, device: lustre-OST0000-osc, type: osc,
3246  *     UUID: lustre-clilov_UUID }
3247  * - { index: 24, event: setup, device: lustre-OST0000-osc,
3248  *     UUID: lustre-OST0000_UUID, node: 192.168.0.120@tcp }
3249  * - { index: 25, event: add_osc, device: lustre-clilov,
3250  *     ost: lustre-OST0000_UUID, index: 0, gen: 1 }
3251  *
3252  * \param record[in]    pointer to llog record
3253  * \param data[in]      pointer to ostname
3254  *
3255  * \retval              1 if ostname is found
3256  *                      0 if ostname is not found
3257  *                      -ENOENT if ostname is deleted
3258  */
3259 static int llog_search_ost_cb(const char *record, void *data)
3260 {
3261         char *ostname = data;
3262         char ost_filter[MAX_STRING_SIZE] = {'\0'};
3263         char *add_osc, *del_osc, *setup, *cleanup;
3264
3265         add_osc = get_event_filter(LCFG_LOV_ADD_OBD);
3266         del_osc = get_event_filter(LCFG_LOV_DEL_OBD);
3267         setup = get_event_filter(LCFG_SETUP);
3268         cleanup = get_event_filter(LCFG_CLEANUP);
3269         if (!add_osc || !del_osc || !setup || !cleanup)
3270                 return -ENOMEM;
3271
3272         if (ostname && ostname[0])
3273                 snprintf(ost_filter, sizeof(ost_filter), " %s,", ostname);
3274
3275         if (strstr(record, ost_filter)) {
3276                 if (strstr(record, add_osc) || strstr(record, setup))
3277                         return 1;
3278                 if (strstr(record, del_osc) || strstr(record, cleanup))
3279                         return -ENOENT;
3280         }
3281
3282         free(add_osc);
3283         free(del_osc);
3284         free(setup);
3285         free(cleanup);
3286
3287         return 0;
3288 }
3289
3290 /**
3291  * Search ost in llog
3292  *
3293  * \param logname[in]           pointer to config log name
3294  * \param last_index[in]        the index of the last llog record
3295  * \param ostname[in]           pointer to ost name
3296  *
3297  * \retval                      1 if ostname is found
3298  *                              0 if ostname is not found
3299  */
3300 static int llog_search_ost(char *logname, long last_index, char *ostname)
3301 {
3302         long start, end, inc = MAX_IOC_BUFLEN / 128;
3303         int rc = 0;
3304
3305         for (end = last_index; end > 1; end -= inc) {
3306                 start = end - inc > 0 ? end - inc : 1;
3307                 rc = jt_llog_print_iter(logname, start, end, llog_search_ost_cb,
3308                                         ostname, true, false);
3309                 if (rc)
3310                         break;
3311         }
3312
3313         return (rc == 1 ? 1 : 0);
3314 }
3315
3316 struct llog_del_ost_priv {
3317         char *logname;
3318         char *ostname;
3319         int found;
3320         int dryrun;
3321 };
3322
3323 /**
3324  * Callback to search and delete ostname in llog
3325  *
3326  * \param record[in]    pointer to llog record
3327  * \param data[in]      pointer to ostname
3328  *
3329  * \retval              1 if ostname is found and entry deleted
3330  *                      0 if ostname is not found
3331  *                      < 0 if error
3332  */
3333 static int llog_del_ost_cb(const char *record, void *data)
3334 {
3335         char ost_filter[MAX_STRING_SIZE] = {'\0'};
3336         char log_idxstr[MAX_STRING_SIZE] = {'\0'};
3337         long int log_idx = 0;
3338         struct llog_del_ost_priv *priv = data;
3339         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
3340         struct obd_ioctl_data ioc_data = { 0 };
3341         int rc = 0;
3342
3343         if (priv->ostname && priv->ostname[0])
3344                 snprintf(ost_filter, sizeof(ost_filter), " %s", priv->ostname);
3345
3346         if (!strstr(record, ost_filter))
3347                 return rc;
3348
3349         rc = sscanf(record, "- { index: %ld", &log_idx);
3350         if (rc < 0) {
3351                 fprintf(stderr, "error: record without index:\n%s\n",
3352                         record);
3353                 return 0;
3354         }
3355         snprintf(log_idxstr, sizeof(log_idxstr), "%ld", log_idx);
3356
3357         ioc_data.ioc_dev = cur_device;
3358         ioc_data.ioc_inllen1 = strlen(priv->logname) + 1;
3359         ioc_data.ioc_inlbuf1 = priv->logname;
3360         ioc_data.ioc_inllen3 = strlen(log_idxstr) + 1;
3361         ioc_data.ioc_inlbuf3 = log_idxstr;
3362
3363         rc = llapi_ioctl_pack(&ioc_data, &buf, sizeof(rawbuf));
3364         if (rc) {
3365                 fprintf(stderr, "ioctl_pack for catalog '%s' failed: %s\n",
3366                         ioc_data.ioc_inlbuf1, strerror(-rc));
3367                 return rc;
3368         }
3369
3370         if (priv->dryrun) {
3371                 fprintf(stdout, "[DRY RUN] cancel catalog '%s:%s':\"%s\"\n",
3372                         ioc_data.ioc_inlbuf1, ioc_data.ioc_inlbuf3, record);
3373         } else {
3374                 rc = l_ioctl(OBD_DEV_ID, OBD_IOC_LLOG_CANCEL, buf);
3375                 if (rc)
3376                         fprintf(stderr, "cancel catalog '%s:%s' failed: %s\n",
3377                                 ioc_data.ioc_inlbuf1, ioc_data.ioc_inlbuf3,
3378                                 strerror(errno));
3379                 else {
3380                         fprintf(stdout, "cancel catalog %s log_idx %ld: done\n",
3381                                 priv->logname, log_idx);
3382                         priv->found++;
3383                 }
3384         }
3385         return rc;
3386 }
3387
3388 /**
3389  * Search and delete ost in llog
3390  *
3391  * \param logname[in]           pointer to config log name
3392  * \param last_index[in]        the index of the last llog record
3393  * \param ostname[in]           pointer to ost name
3394  * \param dryrun[in]            dry run?
3395  *
3396  * \retval                      1 if ostname is found and deleted
3397  *                              0 if ostname is not found
3398  */
3399 static int llog_del_ost(char *logname, long last_index, char *ostname,
3400                         int dryrun)
3401 {
3402         long start, end, inc = MAX_IOC_BUFLEN / 128;
3403         int rc = 0;
3404         struct llog_del_ost_priv priv = { logname, ostname, false, dryrun };
3405
3406         for (end = last_index; end > 1; end -= inc) {
3407                 start = end - inc > 0 ? end - inc : 1;
3408                 rc = jt_llog_print_iter(logname, start, end, llog_del_ost_cb,
3409                                         &priv, true, false);
3410                 if (rc)
3411                         break;
3412         }
3413
3414         if (priv.found)
3415                 fprintf(stdout, "del_ost: cancelled %d catalog entries\n",
3416                         priv.found);
3417         else
3418                 fprintf(stdout, "del_ost: no catalog entry deleted\n");
3419
3420         return rc;
3421 }
3422
3423 struct llog_pool_data {
3424         char lpd_fsname[LUSTRE_MAXFSNAME + 1];
3425         char lpd_poolname[LOV_MAXPOOLNAME + 1];
3426         char lpd_ostname[MAX_OBD_NAME + 1];
3427         enum lcfg_command_type lpd_cmd_type;
3428         bool lpd_pool_exists;
3429         int lpd_ost_num;
3430 };
3431
3432 /**
3433  * Called for each formatted line in the config log (within range).
3434  *
3435  * - { index: 74, event: new_pool, device: tfs-clilov, fsname: tfs, pool: tmp }
3436  * - { index: 77, event: add_pool, device: tfs-clilov, fsname: tfs, pool: tmp,
3437  *     ost: tfs-OST0000_UUID }
3438  * - { index: 224, event: remove_pool, device: tfs-clilov, fsname: tfs,
3439  *     pool: tmp, ost: tfs-OST0003_UUID }
3440  * - { index: 227, event: del_pool, device: tfs-clilov, fsname: tfs, pool: tmp }
3441  *
3442  * \param record[in]    pointer to llog record
3443  * \param data[in]      pointer to llog_pool_data
3444  *
3445  * \retval              1 if pool or OST is found
3446  *                      0 if pool or OST is not found
3447  *                      -ENOENT if pool or OST is removed
3448  */
3449 static int llog_search_pool_cb(const char *record, void *data)
3450 {
3451         struct llog_pool_data *lpd = data;
3452         char pool_filter[MAX_STRING_SIZE] = "";
3453         char *new_pool, *del_pool, *add_pool, *rem_pool;
3454         char *found = NULL;
3455         int fs_pool_len = 0, rc = 0;
3456
3457         new_pool = get_event_filter(LCFG_POOL_NEW);
3458         del_pool = get_event_filter(LCFG_POOL_DEL);
3459         add_pool = get_event_filter(LCFG_POOL_ADD);
3460         rem_pool = get_event_filter(LCFG_POOL_REM);
3461         if (!new_pool || !del_pool || !add_pool || !rem_pool) {
3462                 rc = -ENOMEM;
3463                 goto out;
3464         }
3465
3466         fs_pool_len = 16 + strlen(lpd->lpd_fsname) + strlen(lpd->lpd_poolname);
3467         snprintf(pool_filter, fs_pool_len + 1, "fsname: %s, pool: %s",
3468                  lpd->lpd_fsname, lpd->lpd_poolname);
3469
3470         /* search poolname */
3471         found = strstr(record, pool_filter);
3472         if (found &&
3473             (found[fs_pool_len] == ' ' || found[fs_pool_len] == ',')) {
3474                 if (strstr(record, new_pool)) {
3475                         lpd->lpd_pool_exists = true;
3476                         rc = 1;
3477                         goto out;
3478                 }
3479                 if (strstr(record, del_pool)) {
3480                         lpd->lpd_pool_exists = false;
3481                         rc = -ENOENT;
3482                         goto out;
3483                 }
3484
3485                 if (lpd->lpd_cmd_type == LCFG_POOL_NEW ||
3486                     lpd->lpd_cmd_type == LCFG_POOL_DEL) {
3487                         /* In function mgs_pool_cmd(), a pool's pool_new/add
3488                          * record will be marked as "SKIP" if its pool_destroy/
3489                          * remove record is logged later. That means the "SKIP"
3490                          * record won't be printed here and thus lpd_ost_num
3491                          * doesn't need to be decreased as well.
3492                          */
3493                         if (strstr(record, add_pool))
3494                                 lpd->lpd_ost_num++;
3495                 } else if (lpd->lpd_ostname && lpd->lpd_ostname[0]) {
3496                         if (strstr(record, lpd->lpd_ostname)) {
3497                                 lpd->lpd_pool_exists = true;
3498                                 if (strstr(record, add_pool)) {
3499                                         lpd->lpd_ost_num = 1;
3500                                         rc = 1;
3501                                         goto out;
3502                                 }
3503                                 if (strstr(record, rem_pool)) {
3504                                         lpd->lpd_ost_num = 0;
3505                                         rc = -ENOENT;
3506                                         goto out;
3507                                 }
3508                         }
3509                 }
3510         }
3511 out:
3512         if (new_pool)
3513                 free(new_pool);
3514         if (del_pool)
3515                 free(del_pool);
3516         if (add_pool)
3517                 free(add_pool);
3518         if (rem_pool)
3519                 free(rem_pool);
3520
3521         return rc;
3522 }
3523
3524 /* Search pool and its ost in llog
3525  *
3526  * \param logname[in]           pointer to config log name
3527  * \param last_index[in]        the index of the last llog record
3528  * \param fsname[in]            pointer to filesystem name
3529  * \param poolname[in]          pointer pool name
3530  * \param ostname[in]           pointer to OST name(OSTnnnn-UUID)
3531  * \param cmd[in]               pool command type
3532  *
3533  * \retval                      < 0 on error
3534  *                              0 if pool is empty or OST is not found
3535  *                              1 if pool is not empty or OST is found
3536  */
3537 static int llog_search_pool(char *logname, long last_index, char *fsname,
3538                             char *poolname, char *ostname,
3539                             enum lcfg_command_type cmd)
3540 {
3541         struct llog_pool_data lpd;
3542         long start, end, inc = MAX_IOC_BUFLEN / 128;
3543         int rc = 0;
3544
3545         memset(&lpd, 0, sizeof(lpd));
3546         lpd.lpd_cmd_type = cmd;
3547         lpd.lpd_pool_exists = false;
3548         lpd.lpd_ost_num = 0;
3549         strncpy(lpd.lpd_fsname, fsname, sizeof(lpd.lpd_fsname) - 1);
3550         if (poolname && poolname[0])
3551                 strncpy(lpd.lpd_poolname, poolname,
3552                         sizeof(lpd.lpd_poolname) - 1);
3553         if (ostname && ostname[0])
3554                 strncpy(lpd.lpd_ostname, ostname, sizeof(lpd.lpd_ostname) - 1);
3555
3556         for (end = last_index; end > 1; end -= inc) {
3557                 start = end - inc > 0 ? end - inc : 1;
3558                 rc = jt_llog_print_iter(logname, start, end,
3559                                         llog_search_pool_cb, &lpd, true, false);
3560                 if (rc) {
3561                         if (rc == 1 && lpd.lpd_pool_exists)
3562                                 rc = lpd.lpd_ost_num ? 1 : 0;
3563                         else if (rc == -ENOENT && lpd.lpd_pool_exists &&
3564                                  !lpd.lpd_ost_num)
3565                                 rc = 0;
3566                         goto out;
3567                 }
3568         }
3569
3570         rc = -ENOENT;
3571 out:
3572         return rc;
3573 }
3574
3575 static bool combined_mgs_mds(char *fsname)
3576 {
3577         glob_t path;
3578         int rc;
3579
3580         rc = cfs_get_param_paths(&path, "mdt/%s-MDT0000", fsname);
3581         if (!rc)
3582                 cfs_free_param_data(&path);
3583
3584         if (get_mgs_device() > 0 && !rc)
3585                 return true;
3586
3587         return false;
3588 }
3589
3590 /*
3591  * if pool is NULL, search ostname in target_obd
3592  * if pool is not NULL:
3593  *  - if pool not found returns errno < 0
3594  *  - if ostname is NULL, returns 1 if pool is not empty and 0 if pool empty
3595  *  - if ostname is not NULL, returns 1 if OST is in pool and 0 if not
3596  */
3597 int lctl_search_ost(char *fsname, char *poolname, char *ostname,
3598                     enum lcfg_command_type cmd)
3599 {
3600         char logname[MAX_OBD_NAME] = {'\0'};
3601         long last_index;
3602
3603         if (fsname && fsname[0] == '\0')
3604                 fsname = NULL;
3605         if (!fsname)
3606                 return -EINVAL;
3607
3608         if (combined_mgs_mds(fsname))
3609                 return llapi_search_ost(fsname, poolname, ostname);
3610
3611         /* fetch the last_index of llog record */
3612         snprintf(logname, sizeof(logname), "%s-client", fsname);
3613         last_index = llog_last_index(logname);
3614         if (last_index < 0)
3615                 return last_index;
3616
3617         /* if pool is NULL, search ostname in target_obd */
3618         if (!poolname && ostname)
3619                 return llog_search_ost(logname, last_index, ostname);
3620
3621         return llog_search_pool(logname, last_index, fsname, poolname,
3622                                 ostname, cmd);
3623 }
3624
3625 static int check_pool_cmd(enum lcfg_command_type cmd, char *fsname,
3626                           char *poolname, char *ostname)
3627 {
3628         int rc;
3629
3630         rc = lctl_search_ost(fsname, poolname, ostname, cmd);
3631         if (rc < 0 && (cmd != LCFG_POOL_NEW)) {
3632                 fprintf(stderr, "Pool %s.%s not found\n",
3633                         fsname, poolname);
3634                 return rc;
3635         }
3636
3637         switch (cmd) {
3638         case LCFG_POOL_NEW: {
3639                 if (ostname)
3640                         return -EINVAL;
3641
3642                 if (rc >= 0) {
3643                         fprintf(stderr, "Pool %s.%s already exists\n",
3644                                 fsname, poolname);
3645                         return -EEXIST;
3646                 }
3647                 return 0;
3648         }
3649         case LCFG_POOL_DEL: {
3650                 if (ostname)
3651                         return -EINVAL;
3652
3653                 if (rc == 1) {
3654                         fprintf(stderr,
3655                                 "Pool %s.%s not empty, please remove all members\n",
3656                                 fsname, poolname);
3657                         return -ENOTEMPTY;
3658                 }
3659                 return 0;
3660         }
3661         case LCFG_POOL_ADD: {
3662                 if (rc == 1) {
3663                         fprintf(stderr, "OST %s is already in pool %s.%s\n",
3664                                 ostname, fsname, poolname);
3665                         return -EEXIST;
3666                 }
3667                 rc = lctl_search_ost(fsname, NULL, ostname, cmd);
3668                 if (rc == 0) {
3669                         fprintf(stderr, "OST %s is not part of the '%s' fs.\n",
3670                                 ostname, fsname);
3671                         return -ENOENT;
3672                 }
3673                 return 0;
3674         }
3675         case LCFG_POOL_REM: {
3676                 if (rc == 0) {
3677                         fprintf(stderr, "OST %s not found in pool %s.%s\n",
3678                                 ostname, fsname, poolname);
3679                         return -ENOENT;
3680                 }
3681                 return 0;
3682         }
3683         default:
3684                 break;
3685         } /* switch */
3686         return -EINVAL;
3687 }
3688
3689 /*
3690  * This check only verifies that the changes have been "pushed out" to
3691  * the client successfully.  This involves waiting for a config update,
3692  * and so may fail because of problems in that code or post-command
3693  * network loss. So reporting a warning is appropriate, but not a failure.
3694  */
3695 static int check_pool_cmd_result(enum lcfg_command_type cmd, char *fsname,
3696                                  char *poolname, char *ostname)
3697 {
3698         int cpt = 10;
3699         int rc = 0;
3700
3701         switch (cmd) {
3702         case LCFG_POOL_NEW: {
3703                 do {
3704                         rc = lctl_search_ost(fsname, poolname, NULL, cmd);
3705                         if (rc == -ENODEV)
3706                                 return rc;
3707                         if (rc < 0)
3708                                 sleep(1);
3709                         cpt--;
3710                 } while ((rc < 0) && (cpt > 0));
3711                 if (rc >= 0) {
3712                         fprintf(stderr, "Pool %s.%s created\n",
3713                                 fsname, poolname);
3714                         return 0;
3715                 }
3716
3717                 fprintf(stderr, "Warning, pool %s.%s not found\n", fsname,
3718                         poolname);
3719                 return -ENOENT;
3720         }
3721         case LCFG_POOL_DEL: {
3722                 do {
3723                         rc = lctl_search_ost(fsname, poolname, NULL, cmd);
3724                         if (rc == -ENODEV)
3725                                 return rc;
3726                         if (rc >= 0)
3727                                 sleep(1);
3728                         cpt--;
3729                 } while ((rc >= 0) && (cpt > 0));
3730                 if (rc < 0) {
3731                         fprintf(stderr, "Pool %s.%s destroyed\n",
3732                                 fsname, poolname);
3733                         return 0;
3734                 }
3735
3736                 fprintf(stderr, "Warning, pool %s.%s still found\n", fsname,
3737                         poolname);
3738                 return -EEXIST;
3739         }
3740         case LCFG_POOL_ADD: {
3741                 do {
3742                         rc = lctl_search_ost(fsname, poolname, ostname, cmd);
3743                         if (rc == -ENODEV)
3744                                 return rc;
3745                         if (rc != 1)
3746                                 sleep(1);
3747                         cpt--;
3748                 } while ((rc != 1) && (cpt > 0));
3749                 if (rc == 1) {
3750                         fprintf(stderr, "OST %s added to pool %s.%s\n",
3751                                 ostname, fsname, poolname);
3752                         return 0;
3753                 }
3754                 fprintf(stderr, "Warning, OST %s not found in pool %s.%s\n",
3755                         ostname, fsname, poolname);
3756                 return -ENOENT;
3757         }
3758         case LCFG_POOL_REM: {
3759                 do {
3760                         rc = lctl_search_ost(fsname, poolname, ostname, cmd);
3761                         if (rc == -ENODEV)
3762                                 return rc;
3763                         if (rc == 1)
3764                                 sleep(1);
3765                         cpt--;
3766                 } while ((rc == 1) && (cpt > 0));
3767                 if (rc != 1) {
3768                         fprintf(stderr, "OST %s removed from pool %s.%s\n",
3769                                 ostname, fsname, poolname);
3770                         return 0;
3771                 }
3772                 fprintf(stderr, "Warning, OST %s still found in pool %s.%s\n",
3773                         ostname, fsname, poolname);
3774                 return -EEXIST;
3775         }
3776         default:
3777                 break;
3778         }
3779         return -EINVAL;
3780 }
3781
3782 static int check_and_complete_ostname(char *fsname, char *ostname)
3783 {
3784         char *ptr;
3785         char real_ostname[MAX_OBD_NAME + 1];
3786         char i;
3787
3788         /* if OST name does not start with fsname, we add it */
3789         /* if not check if the fsname is the right one */
3790         ptr = strchr(ostname, '-');
3791         if (!ptr) {
3792                 sprintf(real_ostname, "%s-%s", fsname, ostname);
3793         } else if (strncmp(ostname, fsname, strlen(fsname)) != 0) {
3794                 fprintf(stderr, "%s does not start with fsname %s\n",
3795                         ostname, fsname);
3796                 return -EINVAL;
3797         } else {
3798                 if (strlen(ostname) > sizeof(real_ostname) - 1)
3799                         return -E2BIG;
3800
3801                 strncpy(real_ostname, ostname, sizeof(real_ostname));
3802         }
3803
3804         /* real_ostname is fsname-????? */
3805         ptr = real_ostname + strlen(fsname) + 1;
3806         if (strncmp(ptr, "OST", 3) != 0) {
3807                 fprintf(stderr, "%s does not start by %s-OST nor OST\n",
3808                         ostname, fsname);
3809                 return -EINVAL;
3810         }
3811         /* real_ostname is fsname-OST????? */
3812         ptr += 3;
3813         for (i = 0; i < 4; i++) {
3814                 if (!isxdigit(*ptr)) {
3815                         fprintf(stderr,
3816                                 "ost's index in %s is not an hexa number\n",
3817                                 ostname);
3818                         return -EINVAL;
3819                 }
3820                 ptr++;
3821         }
3822         /* real_ostname is fsname-OSTXXXX????? */
3823         /* if OST name does not end with _UUID, we add it */
3824         if (*ptr == '\0') {
3825                 strcat(real_ostname, "_UUID");
3826         } else if (strcmp(ptr, "_UUID") != 0) {
3827                 fprintf(stderr,
3828                         "ostname %s does not end with _UUID\n", ostname);
3829                 return -EINVAL;
3830         }
3831         /* real_ostname is fsname-OSTXXXX_UUID */
3832         strcpy(ostname, real_ostname);
3833         return 0;
3834 }
3835
3836 /* returns 0 or -errno */
3837 static int pool_cmd(enum lcfg_command_type cmd, char *cmdname,
3838                     char *fullpoolname, char *fsname, char *poolname,
3839                     char *ostname)
3840 {
3841         int rc = 0;
3842         struct obd_ioctl_data data;
3843         struct lustre_cfg_bufs bufs;
3844         struct lustre_cfg *lcfg;
3845         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
3846
3847         rc = check_pool_cmd(cmd, fsname, poolname, ostname);
3848         if (rc == -ENODEV)
3849                 fprintf(stderr,
3850                         "Can't verify pool command since there is no local MDT or client, proceeding anyhow...\n");
3851         else if (rc)
3852                 return rc;
3853
3854         lustre_cfg_bufs_reset(&bufs, NULL);
3855         lustre_cfg_bufs_set_string(&bufs, 0, cmdname);
3856         lustre_cfg_bufs_set_string(&bufs, 1, fullpoolname);
3857         if (ostname)
3858                 lustre_cfg_bufs_set_string(&bufs, 2, ostname);
3859
3860         lcfg = malloc(lustre_cfg_len(bufs.lcfg_bufcount, bufs.lcfg_buflen));
3861         if (!lcfg)
3862                 return -ENOMEM;
3863         lustre_cfg_init(lcfg, cmd, &bufs);
3864
3865         memset(&data, 0, sizeof(data));
3866         rc = data.ioc_dev = get_mgs_device();
3867         if (rc < 0)
3868                 goto out;
3869
3870         data.ioc_type = LUSTRE_CFG_TYPE;
3871         data.ioc_plen1 = lustre_cfg_len(lcfg->lcfg_bufcount,
3872                                         lcfg->lcfg_buflens);
3873         data.ioc_pbuf1 = (void *)lcfg;
3874
3875         memset(buf, 0, sizeof(rawbuf));
3876         rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
3877         if (rc) {
3878                 fprintf(stderr, "error: %s: invalid ioctl\n",
3879                         jt_cmdname(cmdname));
3880                 free(lcfg);
3881                 return rc;
3882         }
3883         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_POOL, buf);
3884 out:
3885         if (rc)
3886                 rc = -errno;
3887         switch (rc) {
3888         case -ENAMETOOLONG:
3889                 fprintf(stderr,
3890                         "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",
3891                         jt_cmdname(cmdname), LOV_MAXPOOLNAME, LUSTRE_MAXFSNAME);
3892                 break;
3893         case -EINVAL:
3894                 fprintf(stderr,
3895                         "error: %s can contain only alphanumeric characters, underscores, and dashes besides the required '.'\n",
3896                         jt_cmdname(cmdname));
3897         default:
3898                 break;
3899         }
3900         free(lcfg);
3901         return rc;
3902 }
3903
3904 int jt_del_ost(int argc, char **argv)
3905 {
3906         char *fsname = NULL, *ptr, *logname;
3907         char mdtpattern[16], clipattern[16];
3908         char ostname[MAX_OBD_NAME + 1];
3909         long last_index;
3910         __u32 index;
3911         int rc, start = 0, dryrun = 0;
3912         char c;
3913
3914         static struct option long_opts[] = {
3915         { .val = 'h',   .name = "help",         .has_arg = no_argument },
3916         { .val = 'n',   .name = "dryrun",       .has_arg = no_argument },
3917         { .val = 't',   .name = "target",       .has_arg = required_argument },
3918         { .name = NULL } };
3919
3920         while ((c = getopt_long(argc, argv, "hnt:", long_opts, NULL)) != -1) {
3921                 switch (c) {
3922                 case 't':
3923                         fsname = strdup(optarg);
3924                         break;
3925                 case 'n':
3926                         dryrun = 1;
3927                         break;
3928                 case 'h':
3929                 default:
3930                         free(fsname);
3931                         return CMD_HELP;
3932                 }
3933         }
3934
3935         if (fsname == NULL)
3936                 return CMD_HELP;
3937
3938         if (llog_default_device(LLOG_DFLT_MGS_SET)) {
3939                 rc = CMD_INCOMPLETE;
3940                 goto out;
3941         }
3942
3943         ptr = strstr(fsname, "-OST");
3944         if (!ptr) {
3945                 rc = CMD_HELP;
3946                 goto err;
3947         }
3948
3949         if (dryrun)
3950                 fprintf(stdout, "del_ost: dry run for target %s\n", fsname);
3951
3952         *ptr++ = '\0';
3953         rc = sscanf(ptr, "OST%04x", &index);
3954         if (rc != 1) {
3955                 rc = -EINVAL;
3956                 goto err;
3957         }
3958
3959         if (strlen(ptr) > sizeof(ostname) - 1) {
3960                 rc = -E2BIG;
3961                 goto err;
3962         }
3963
3964         snprintf(mdtpattern, sizeof(mdtpattern), "%s-MDT", fsname);
3965         snprintf(clipattern, sizeof(clipattern), "%s-client", fsname);
3966         snprintf(ostname, sizeof(ostname), "%s-%s", fsname, ptr);
3967
3968         do {
3969                 char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
3970                 char *begin, *end;
3971
3972                 start = llog_catlist_next(start, rawbuf, sizeof(rawbuf));
3973                 if (start < 0)
3974                         break;
3975                 begin = ((struct obd_ioctl_data *)buf)->ioc_bulk;
3976                 if (strlen(begin) == 0)
3977                         break;
3978
3979                 while ((end = strchr(begin, '\n'))) {
3980                         *end = '\0';
3981                         logname = strstr(begin, "config_log: ");
3982
3983                         if (logname && (strstr(logname, mdtpattern) ||
3984                                         strstr(logname, clipattern))) {
3985                                 logname += 12;
3986
3987                                 fprintf(stdout, "config_log: %s\n", logname);
3988
3989                                 last_index = llog_last_index(logname);
3990                                 if (last_index < 0) {
3991                                         fprintf(stderr,
3992                                                 "error with catalog %s: %s\n",
3993                                                 logname, strerror(-last_index));
3994                                         rc = -last_index;
3995                                         goto err;
3996                                 }
3997                                 rc = llog_del_ost(logname, last_index, ostname,
3998                                                   dryrun);
3999                                 if (rc < 0)
4000                                         goto err;
4001                         }
4002                         begin = end + 1;
4003                 }
4004         } while (start);
4005
4006 err:
4007         llog_default_device(LLOG_DFLT_DEV_RESET);
4008 out:
4009         free(fsname);
4010         return rc;
4011 }
4012
4013 #ifdef HAVE_SERVER_SUPPORT
4014 /**
4015  * Format and send the ioctl to the MGS.
4016  *
4017  * \param       cmd             IOCTL to send
4018  * \param       ret_data        void pointer to return anything from
4019  *                              ioctl
4020  * \param       num_args        number of arguments to pack into the
4021  *                              ioctl buffer
4022  * \param       argv[]          variable number of string arguments
4023  *
4024  * \retval                      0 on success
4025  */
4026 static int nodemap_cmd(enum lcfg_command_type cmd, void *ret_data,
4027                        unsigned int ret_size, ...)
4028 {
4029         va_list                 ap;
4030         char                    *arg;
4031         int                     i = 0;
4032         struct lustre_cfg_bufs  bufs;
4033         struct obd_ioctl_data   data;
4034         struct lustre_cfg       *lcfg;
4035         char                    rawbuf[MAX_IOC_BUFLEN];
4036         char                    *buf = rawbuf;
4037         int                     rc = 0;
4038
4039         lustre_cfg_bufs_reset(&bufs, NULL);
4040
4041         va_start(ap, ret_size);
4042         arg = va_arg(ap, char *);
4043         while (arg) {
4044                 lustre_cfg_bufs_set_string(&bufs, i, arg);
4045                 i++;
4046                 arg = va_arg(ap, char *);
4047         }
4048         va_end(ap);
4049
4050         lcfg = malloc(lustre_cfg_len(bufs.lcfg_bufcount, bufs.lcfg_buflen));
4051         if (!lcfg)
4052                 return -ENOMEM;
4053         lustre_cfg_init(lcfg, cmd, &bufs);
4054
4055         memset(&data, 0, sizeof(data));
4056         rc = data.ioc_dev = get_mgs_device();
4057         if (rc < 0)
4058                 goto out;
4059
4060         data.ioc_type = LUSTRE_CFG_TYPE;
4061         data.ioc_plen1 = lustre_cfg_len(lcfg->lcfg_bufcount,
4062                                         lcfg->lcfg_buflens);
4063         data.ioc_pbuf1 = (void *)lcfg;
4064
4065         memset(buf, 0, sizeof(rawbuf));
4066         rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
4067         if (rc) {
4068                 fprintf(stderr,
4069                         "error: invalid ioctl request: %08x errno: %d: %s\n",
4070                         cmd, errno, strerror(-rc));
4071                 goto out;
4072         }
4073
4074         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_NODEMAP, buf);
4075         if (rc) {
4076                 fprintf(stderr,
4077                         "error: invalid ioctl: %08x errno: %d: %s\n",
4078                         cmd, errno, strerror(errno));
4079                 goto out;
4080         }
4081
4082         if (ret_data) {
4083                 rc = llapi_ioctl_unpack(&data, buf, sizeof(rawbuf));
4084                 if (rc)
4085                         goto out;
4086
4087                 if (ret_size > data.ioc_plen1)
4088                         ret_size = data.ioc_plen1;
4089
4090                 memcpy(ret_data, data.ioc_pbuf1, ret_size);
4091         }
4092 out:
4093         free(lcfg);
4094
4095         return rc;
4096 }
4097
4098 /**
4099  * activate nodemap functions
4100  *
4101  * \param       argc            number of args
4102  * \param       argv[]          variable string arguments
4103  *
4104  * argv[0]                      1 for activate or 0 for deactivate
4105  *
4106  * \retval                      0 on success
4107  */
4108 int jt_nodemap_activate(int argc, char **argv)
4109 {
4110         int rc;
4111
4112         rc = nodemap_cmd(LCFG_NODEMAP_ACTIVATE, NULL, 0, argv[0], argv[1],
4113                          NULL);
4114
4115         if (rc != 0) {
4116                 errno = -rc;
4117                 perror(argv[0]);
4118         }
4119
4120         return rc;
4121 }
4122
4123 /**
4124  * add a nodemap
4125  *
4126  * \param       argc            number of args
4127  * \param       argv[]          variable string arguments
4128  *
4129  * argv[0]                      nodemap name
4130  *
4131  * \retval                      0 on success
4132  */
4133 int jt_nodemap_add(int argc, char **argv)
4134 {
4135         int rc;
4136
4137         rc = llapi_nodemap_exists(argv[1]);
4138         if (rc == 0) {
4139                 fprintf(stderr, "error: %s existing nodemap name\n", argv[1]);
4140                 return 1;
4141         }
4142
4143         rc = nodemap_cmd(LCFG_NODEMAP_ADD, NULL, 0, argv[0], argv[1], NULL);
4144
4145         if (rc != 0) {
4146                 errno = -rc;
4147                 perror(argv[0]);
4148         }
4149
4150         return rc;
4151 }
4152
4153 /**
4154  * delete a nodemap
4155  *
4156  * \param       argc            number of args
4157  * \param       argv[]          variable string arguments
4158  *
4159  * argv[0]                      nodemap name
4160  *
4161  * \retval                      0 on success
4162  */
4163 int jt_nodemap_del(int argc, char **argv)
4164 {
4165         int rc;
4166
4167         rc = llapi_nodemap_exists(argv[1]);
4168         if (rc != 0) {
4169                 fprintf(stderr, "error: %s not existing nodemap name\n",
4170                         argv[1]);
4171                 return rc;
4172         }
4173         rc = nodemap_cmd(LCFG_NODEMAP_DEL, NULL, 0, argv[0], argv[1], NULL);
4174
4175         if (rc != 0) {
4176                 errno = -rc;
4177                 perror(argv[0]);
4178         }
4179
4180         return rc;
4181 }
4182
4183 /**
4184  * test a nid for nodemap membership
4185  *
4186  * \param       argc            number of args
4187  * \param       argv[]          variable string arguments
4188  *
4189  * argv[0]                      properly formatted nid
4190  *
4191  * \retval                      0 on success
4192  */
4193 int jt_nodemap_test_nid(int argc, char **argv)
4194 {
4195         char    rawbuf[MAX_IOC_BUFLEN];
4196         int     rc;
4197
4198         rc = nodemap_cmd(LCFG_NODEMAP_TEST_NID, &rawbuf, sizeof(rawbuf),
4199                          argv[0], argv[1], NULL);
4200         if (rc == 0)
4201                 printf("%s\n", (char *)rawbuf);
4202
4203         return rc;
4204 }
4205
4206 /**
4207  * test a nodemap id pair for mapping
4208  *
4209  * \param       argc            number of args
4210  * \param       argv[[]         variable string arguments
4211  *
4212  * \retval                      0 on success
4213  *
4214  * The argv array should contain the nodemap name, the id
4215  * to checking the mapping on, and the id type (UID or GID)
4216  *
4217  */
4218 int jt_nodemap_test_id(int argc, char **argv)
4219 {
4220         char    rawbuf[MAX_IOC_BUFLEN];
4221         char    *nidstr = NULL;
4222         char    *idstr = NULL;
4223         char    *typestr = NULL;
4224         int     rc = 0;
4225         int     c;
4226
4227         static struct option long_opts[] = {
4228                 { .val = 'i',   .name = "id",   .has_arg = required_argument },
4229                 { .val = 'n',   .name = "nid",  .has_arg = required_argument },
4230                 { .val = 't',   .name = "idtype",
4231                                                 .has_arg = required_argument },
4232                 { .name = NULL } };
4233
4234         while ((c = getopt_long(argc, argv, "n:t:i:",
4235                                 long_opts, NULL)) != -1) {
4236                 switch (c) {
4237                 case 'n':
4238                         nidstr = optarg;
4239                         break;
4240                 case 't':
4241                         typestr = optarg;
4242                         break;
4243                 case 'i':
4244                         idstr = optarg;
4245                         break;
4246                 }
4247         }
4248
4249         if (!nidstr || !typestr || !idstr) {
4250                 fprintf(stderr,
4251                         "usage: nodemap_test_id --nid <nid> --idtype [uid|gid] --id <id>\n");
4252                 return -1;
4253         }
4254
4255         rc = nodemap_cmd(LCFG_NODEMAP_TEST_ID, &rawbuf, sizeof(rawbuf),
4256                          argv[0], nidstr, typestr, idstr, NULL);
4257         if (rc == 0)
4258                 printf("%s\n", (char *)rawbuf);
4259
4260         return rc;
4261 }
4262
4263 /**
4264  * parse nid range
4265  *
4266  * \param       nodemap_range   --range string
4267  * \param       nid_range       nid range string, min_nid:max_nid
4268  *
4269  * \retval                      0 on success
4270  */
4271 static int parse_nid_range(char *nodemap_range, char *nid_range, int range_len)
4272 {
4273         char                    min_nid[LNET_NIDSTR_SIZE + 1];
4274         char                    max_nid[LNET_NIDSTR_SIZE + 1];
4275         struct list_head        nidlist;
4276         int                     rc = 0;
4277
4278         INIT_LIST_HEAD(&nidlist);
4279
4280         if (cfs_parse_nidlist(nodemap_range, strlen(nodemap_range),
4281                               &nidlist) <= 0) {
4282                 fprintf(stderr,
4283                         "error: nodemap_xxx_range: can't parse nid range: %s\n",
4284                         nodemap_range);
4285                 return -EINVAL;
4286         }
4287
4288         rc = cfs_nidrange_find_min_max(&nidlist, &min_nid[0], &max_nid[0],
4289                                        LNET_NIDSTR_SIZE);
4290         if (rc < 0) {
4291                 if (rc == -EINVAL)
4292                         fprintf(stderr,
4293                                 "error: nodemap_xxx_range: nid range uses currently unsupported features\n");
4294                 else if (rc == -ERANGE)
4295                         fprintf(stderr,
4296                                 "error: nodemap_xxx_range: nodemap ranges must be contiguous\n");
4297
4298                 return rc;
4299         }
4300
4301         snprintf(nid_range, range_len, "%s:%s", min_nid, max_nid);
4302
4303         return rc;
4304 }
4305
4306 /**
4307  * add an nid range to a nodemap
4308  *
4309  * \param       argc            number of args
4310  * \param       argv[]          variable string arguments
4311  *
4312  * --name                       nodemap name
4313  * --range                      properly formatted nid range
4314  *
4315  * \retval                      0 on success, -errno on error
4316  */
4317 int jt_nodemap_add_range(int argc, char **argv)
4318 {
4319         char                    *nodemap_name = NULL;
4320         char                    *nodemap_range = NULL;
4321         char                    nid_range[2 * LNET_NIDSTR_SIZE + 2];
4322         int                     rc = 0;
4323         int                     c;
4324
4325         static struct option long_opts[] = {
4326         { .val = 'n',   .name = "name",         .has_arg = required_argument },
4327         { .val = 'r',   .name = "range",        .has_arg = required_argument },
4328         { .name = NULL } };
4329
4330         while ((c = getopt_long(argc, argv, "n:r:",
4331                                 long_opts, NULL)) != -1) {
4332                 switch (c) {
4333                 case 'n':
4334                         nodemap_name = optarg;
4335                         break;
4336                 case 'r':
4337                         nodemap_range = optarg;
4338                         break;
4339                 }
4340         }
4341
4342         if (!nodemap_name || !nodemap_range) {
4343                 fprintf(stderr,
4344                         "usage: nodemap_add_range --name <name> --range <range>\n");
4345                 return -EINVAL;
4346         }
4347
4348         rc = parse_nid_range(nodemap_range, nid_range, sizeof(nid_range));
4349         if (rc) {
4350                 return rc;
4351         }
4352         rc = nodemap_cmd(LCFG_NODEMAP_ADD_RANGE, NULL, 0, argv[0],
4353                          nodemap_name, nid_range, NULL);
4354         if (rc) {
4355                 fprintf(stderr,
4356                         "error: %s: cannot add range '%s' to nodemap '%s': %s\n",
4357                         jt_cmdname(argv[0]), nodemap_range, nodemap_name,
4358                         strerror(-rc));
4359         }
4360
4361         return rc;
4362 }
4363
4364 /**
4365  * delete an nid range to a nodemap
4366  *
4367  * \param       argc            number of args
4368  * \param       argv[]          variable string arguments
4369  *
4370  * --name                       nodemap name
4371  * --range                      properly formatted nid range
4372  *
4373  * \retval                      0 on success
4374  */
4375 int jt_nodemap_del_range(int argc, char **argv)
4376 {
4377         char                    *nodemap_name = NULL;
4378         char                    *nodemap_range = NULL;
4379         char                    nid_range[2 * LNET_NIDSTR_SIZE + 2];
4380         int                     rc = 0;
4381         int                     c;
4382
4383         static struct option long_opts[] = {
4384         { .val = 'n',   .name = "name",         .has_arg = required_argument },
4385         { .val = 'r',   .name = "range",        .has_arg = required_argument },
4386         { .name = NULL } };
4387
4388         while ((c = getopt_long(argc, argv, "n:r:",
4389                                 long_opts, NULL)) != -1) {
4390                 switch (c) {
4391                 case 'n':
4392                         nodemap_name = optarg;
4393                         break;
4394                 case 'r':
4395                         nodemap_range = optarg;
4396                         break;
4397                 }
4398         }
4399
4400         if (!nodemap_name || !nodemap_range) {
4401                 fprintf(stderr,
4402                         "usage: nodemap_del_range --name <name> --range <range>\n");
4403                 return -1;
4404         }
4405
4406         rc = parse_nid_range(nodemap_range, nid_range, sizeof(nid_range));
4407         if (rc) {
4408                 errno = -rc;
4409                 return rc;
4410         }
4411         rc = nodemap_cmd(LCFG_NODEMAP_DEL_RANGE, NULL, 0, argv[0],
4412                          nodemap_name, nid_range, NULL);
4413         if (rc != 0) {
4414                 errno = -rc;
4415                 fprintf(stderr,
4416                         "error: %s: cannot delete range '%s' to nodemap '%s': rc = %d\n",
4417                         jt_cmdname(argv[0]), nodemap_range, nodemap_name, rc);
4418         }
4419
4420         return rc;
4421 }
4422
4423 /**
4424  * set a fileset on a nodemap
4425  *
4426  * \param       argc            number of args
4427  * \param       argv[]          variable string arguments
4428  *
4429  * --name                       nodemap name
4430  * --fileset                    fileset name
4431  *
4432  * \retval                      0 on success
4433  */
4434 int jt_nodemap_set_fileset(int argc, char **argv)
4435 {
4436         char *nodemap_name = NULL;
4437         char *fileset_name = NULL;
4438         int   rc = 0;
4439         int   c;
4440
4441         static struct option long_opts[] = {
4442         { .val = 'f',   .name = "fileset",      .has_arg = required_argument },
4443         { .val = 'n',   .name = "name",         .has_arg = required_argument },
4444         { .name = NULL } };
4445
4446         while ((c = getopt_long(argc, argv, "n:f:",
4447                                 long_opts, NULL)) != -1) {
4448                 switch (c) {
4449                 case 'n':
4450                         nodemap_name = optarg;
4451                         break;
4452                 case 'f':
4453                         fileset_name = optarg;
4454                         break;
4455                 }
4456         }
4457
4458         if (!nodemap_name || !fileset_name) {
4459                 fprintf(stderr,
4460                         "usage: nodemap_set_fileset --name <name> --fileset <fileset>\n");
4461                 return -1;
4462         }
4463
4464         rc = nodemap_cmd(LCFG_NODEMAP_SET_FILESET, NULL, 0, argv[0],
4465                          nodemap_name, fileset_name, NULL);
4466         if (rc != 0) {
4467                 errno = -rc;
4468                 fprintf(stderr,
4469                         "error: %s: cannot set fileset '%s' on nodemap '%s': rc = %d\n",
4470                         jt_cmdname(argv[0]), fileset_name, nodemap_name, rc);
4471         }
4472
4473         return rc;
4474 }
4475
4476 /**
4477  * set SELinux policy info on a nodemap
4478  *
4479  * \param       argc            number of args
4480  * \param       argv[]          variable string arguments
4481  *
4482  * --name                       nodemap name
4483  * --sepol                      SELinux policy info
4484  *
4485  * \retval                      0 on success
4486  */
4487 int jt_nodemap_set_sepol(int argc, char **argv)
4488 {
4489         char *nodemap_name = NULL;
4490         char *sepol = NULL;
4491         int   rc = 0;
4492         int   c;
4493
4494         static struct option long_options[] = {
4495                 {
4496                         .name           = "name",
4497                         .has_arg        = required_argument,
4498                         .val            = 'n',
4499                 },
4500                 {
4501                         .name           = "sepol",
4502                         .has_arg        = required_argument,
4503                         .val            = 's',
4504                 },
4505                 {
4506                         .name = NULL,
4507                 }
4508         };
4509
4510         while ((c = getopt_long(argc, argv, "n:s:",
4511                                 long_options, NULL)) != -1) {
4512                 switch (c) {
4513                 case 'n':
4514                         nodemap_name = optarg;
4515                         break;
4516                 case 's':
4517                         sepol = optarg;
4518                         break;
4519                 }
4520         }
4521
4522         if (!nodemap_name || !sepol) {
4523                 fprintf(stderr,
4524                         "usage: nodemap_set_sepol --name <name> --sepol <sepol>\n");
4525                 return -1;
4526         }
4527
4528         rc = nodemap_cmd(LCFG_NODEMAP_SET_SEPOL, NULL, 0, argv[0],
4529                          nodemap_name, sepol, NULL);
4530         if (rc != 0) {
4531                 errno = -rc;
4532                 fprintf(stderr,
4533                         "error: %s: cannot set sepol '%s' on nodemap '%s': rc = %d\n",
4534                         jt_cmdname(argv[0]), sepol, nodemap_name, rc);
4535         }
4536
4537         return rc;
4538 }
4539
4540 /**
4541  * modify a nodemap's behavior
4542  *
4543  * \param       argc            number of args
4544  * \param       argv[]          variable string arguments
4545  *
4546  * --name                       nodemap name
4547  * --property                   nodemap property to change
4548  *                              admin, trusted, squash_uid, squash_gid)
4549  * --value                      value to set property
4550  *
4551  * \retval                      0 on success
4552  */
4553 int jt_nodemap_modify(int argc, char **argv)
4554 {
4555         int                     c;
4556         int                     rc = 0;
4557         enum lcfg_command_type  cmd = 0;
4558         char                    *nodemap_name = NULL;
4559         char                    *param = NULL;
4560         char                    *value = NULL;
4561
4562         static struct option long_opts[] = {
4563         { .val = 'n',   .name = "name",         .has_arg = required_argument },
4564         { .val = 'p',   .name = "property",     .has_arg = required_argument },
4565         { .val = 'v',   .name = "value",        .has_arg = required_argument },
4566         { .name = NULL } };
4567
4568         while ((c = getopt_long(argc, argv, "n:p:v:",
4569                                 long_opts, NULL)) != -1) {
4570                 switch (c) {
4571                 case 'n':
4572                         nodemap_name = optarg;
4573                         break;
4574                 case 'p':
4575                         param = optarg;
4576                         break;
4577                 case 'v':
4578                         value = optarg;
4579                         break;
4580                 }
4581         }
4582
4583         if (!nodemap_name || !param || !value) {
4584                 fprintf(stderr,
4585                         "usage: nodemap_modify --name <nodemap_name> --property <property_name> --value <value>\n");
4586                 fprintf(stderr,
4587                         "valid properties: admin trusted map_mode squash_uid squash_gid squash_projid deny_unknown audit_mode forbid_encryption readonly_mount\n");
4588                 return -1;
4589         }
4590
4591         if (strcmp("admin", param) == 0) {
4592                 cmd = LCFG_NODEMAP_ADMIN;
4593         } else if (strcmp("trusted", param) == 0) {
4594                 cmd = LCFG_NODEMAP_TRUSTED;
4595         } else if (strcmp("deny_unknown", param) == 0) {
4596                 cmd = LCFG_NODEMAP_DENY_UNKNOWN;
4597         } else if (strcmp("squash_uid", param) == 0) {
4598                 cmd = LCFG_NODEMAP_SQUASH_UID;
4599         } else if (strcmp("squash_gid", param) == 0) {
4600                 cmd = LCFG_NODEMAP_SQUASH_GID;
4601         } else if (strcmp("squash_projid", param) == 0) {
4602                 cmd = LCFG_NODEMAP_SQUASH_PROJID;
4603         } else if (strcmp("map_mode", param) == 0) {
4604                 cmd = LCFG_NODEMAP_MAP_MODE;
4605         } else if (strcmp("audit_mode", param) == 0) {
4606                 cmd = LCFG_NODEMAP_AUDIT_MODE;
4607         } else if (strcmp("forbid_encryption", param) == 0) {
4608                 cmd = LCFG_NODEMAP_FORBID_ENCRYPT;
4609         } else if (strcmp("readonly_mount", param) == 0) {
4610                 cmd = LCFG_NODEMAP_READONLY_MOUNT;
4611         } else {
4612                 fprintf(stderr,
4613                         "error: %s: nodemap_modify invalid subcommand: %s\n",
4614                         jt_cmdname(argv[0]), param);
4615                 return -1;
4616         }
4617
4618         rc = nodemap_cmd(cmd, NULL, 0, argv[0], nodemap_name, param,
4619                          value, NULL);
4620         if (rc != 0) {
4621                 errno = -rc;
4622                 fprintf(stderr,
4623                         "error: %s: cannot modify nodemap '%s' to param '%s': value '%s': rc = %d\n",
4624                         jt_cmdname(argv[0]), nodemap_name, param, value, rc);
4625         }
4626
4627         return rc;
4628 }
4629
4630 int jt_nodemap_add_idmap(int argc, char **argv)
4631 {
4632         int                     c;
4633         enum                    lcfg_command_type cmd = 0;
4634         char                    *nodemap_name = NULL;
4635         char                    *idmap = NULL;
4636         char                    *idtype = NULL;
4637         int                     rc = 0;
4638
4639         static struct option long_opts[] = {
4640         { .val = 'i',   .name = "idtype",       .has_arg = required_argument },
4641         { .val = 'm',   .name = "idmap",        .has_arg = required_argument },
4642         { .val = 'n',   .name = "name",         .has_arg = required_argument },
4643         { .name = NULL } };
4644
4645         while ((c = getopt_long(argc, argv, "n:m:i:",
4646                                 long_opts, NULL)) != -1) {
4647                 switch (c) {
4648                 case 'n':
4649                         nodemap_name = optarg;
4650                         break;
4651                 case 'm':
4652                         idmap = optarg;
4653                         break;
4654                 case 'i':
4655                         idtype = optarg;
4656                         break;
4657                 }
4658         }
4659
4660         if (!nodemap_name || !idmap || !idtype) {
4661                 fprintf(stderr,
4662                         "usage: %s --name <name> --idtype [uid | gid | projid] --idmap <client id>:<filesystem id>\n",
4663                         argv[0]);
4664                 return -1;
4665         }
4666
4667         if (strcmp("uid", idtype) == 0) {
4668                 cmd = LCFG_NODEMAP_ADD_UIDMAP;
4669         } else if (strcmp("gid", idtype) == 0) {
4670                 cmd = LCFG_NODEMAP_ADD_GIDMAP;
4671         } else if (strcmp("projid", idtype) == 0) {
4672                 cmd = LCFG_NODEMAP_ADD_PROJIDMAP;
4673         } else {
4674                 fprintf(stderr,
4675                         "usage: %s --name <name> --idtype [uid | gid | projid] --idmap <client id>:<filesystem id>\n",
4676                         argv[0]);
4677                 return -1;
4678         }
4679
4680         rc = nodemap_cmd(cmd, NULL, 0, argv[0], nodemap_name, idmap, NULL);
4681         if (rc != 0) {
4682                 errno = -rc;
4683                 fprintf(stderr,
4684                         "cannot add %smap '%s' to nodemap '%s': rc = %d\n",
4685                         idtype, idmap, nodemap_name, rc);
4686         }
4687
4688         return rc;
4689 }
4690
4691 int jt_nodemap_del_idmap(int argc, char **argv)
4692 {
4693         int                     c;
4694         enum                    lcfg_command_type cmd = 0;
4695         char                    *nodemap_name = NULL;
4696         char                    *idmap = NULL;
4697         char                    *idtype = NULL;
4698         int                     rc = 0;
4699
4700         static struct option long_opts[] = {
4701         { .val = 'i',   .name = "idtype",       .has_arg = required_argument },
4702         { .val = 'm',   .name = "idmap",        .has_arg = required_argument },
4703         { .val = 'n',   .name = "name",         .has_arg = required_argument },
4704         { .name = NULL } };
4705
4706         while ((c = getopt_long(argc, argv, "n:m:i:",
4707                                 long_opts, NULL)) != -1) {
4708                 switch (c) {
4709                 case 'n':
4710                         nodemap_name = optarg;
4711                         break;
4712                 case 'm':
4713                         idmap = optarg;
4714                         break;
4715                 case 'i':
4716                         idtype = optarg;
4717                         break;
4718                 }
4719         }
4720
4721         if (!nodemap_name || !idmap || !idtype) {
4722                 fprintf(stderr,
4723                         "usage: %s --name <name> --idtype [uid | gid | projid] --idmap <client id>:<filesystem id>\n",
4724                         argv[0]);
4725                 return -1;
4726         }
4727
4728         if (strcmp("uid", idtype) == 0) {
4729                 cmd = LCFG_NODEMAP_DEL_UIDMAP;
4730         } else if (strcmp("gid", idtype) == 0) {
4731                 cmd = LCFG_NODEMAP_DEL_GIDMAP;
4732         } else if (strcmp("projid", idtype) == 0) {
4733                 cmd = LCFG_NODEMAP_DEL_PROJIDMAP;
4734         } else {
4735                 fprintf(stderr,
4736                         "usage: %s --name <name> --idtype [uid | gid | projid] --idmap <client id>:<filesystem id>\n",
4737                         argv[0]);
4738                 return -1;
4739         }
4740
4741         rc = nodemap_cmd(cmd, NULL, 0, argv[0], nodemap_name, idmap, NULL);
4742         if (rc != 0) {
4743                 errno = -rc;
4744                 fprintf(stderr,
4745                         "cannot delete %smap '%s' from nodemap '%s': rc = %d\n",
4746                         idtype, idmap, nodemap_name, rc);
4747         }
4748
4749         return rc;
4750 }
4751 #else /* !HAVE_SERVER_SUPPORT */
4752 int jt_nodemap_activate(int argc, char **argv)
4753 {
4754         fprintf(stderr, "error: %s: invalid ioctl\n",
4755                 jt_cmdname(argv[0]));
4756         return -EOPNOTSUPP;
4757 }
4758
4759 int jt_nodemap_add(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_del(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_modify(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_add_range(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_test_nid(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_del_range(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_add_idmap(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_del_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_test_id(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_set_fileset(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_sepol(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_info(int argc, char **argv)
4837 {
4838         fprintf(stderr, "error: %s: invalid ioctl\n",
4839                 jt_cmdname(argv[0]));
4840         return -EOPNOTSUPP;
4841 }
4842 #endif /* HAVE_SERVER_SUPPORT */
4843
4844 /*
4845  * this function tranforms a rule [start-end/step] into an array
4846  * of matching numbers
4847  * supported forms are:
4848  * [start]                : just this number
4849  * [start-end]            : all numbers from start to end
4850  * [start-end/step]       : numbers from start to end with increment of step
4851  * on return, format contains a printf format string which can be used
4852  * to generate all the strings
4853  */
4854 static int get_array_idx(char *rule, char *format, int **array)
4855 {
4856         char *start, *end, *ptr;
4857         unsigned int lo, hi, step;
4858         int array_sz = 0;
4859         int i, array_idx;
4860         int rc;
4861
4862         start = strchr(rule, '[');
4863         end = strchr(rule, ']');
4864         if ((!start) || (!end)) {
4865                 *array = malloc(sizeof(int));
4866                 if (!*array)
4867                         return 0;
4868                 strcpy(format, rule);
4869                 array_sz = 1;
4870                 return array_sz;
4871         }
4872         *start = '\0';
4873         *end = '\0';
4874         end++;
4875         start++;
4876         /* put in format the printf format (the rule without the range) */
4877         sprintf(format, "%s%%.4x%s", rule, end);
4878
4879         array_idx = 0;
4880         array_sz = 0;
4881         *array = NULL;
4882         /* loop on , separator */
4883         do {
4884                 /* extract the 3 fields */
4885                 rc = sscanf(start, "%x-%x/%u", &lo, &hi, &step);
4886                 switch (rc) {
4887                 case 0:
4888                         goto err;
4889                 case 1: {
4890                         void *tmp;
4891
4892                         array_sz++;
4893                         tmp = realloc(*array, array_sz * sizeof(int));
4894                         if (!tmp)
4895                                 goto err;
4896                         *array = tmp;
4897                         (*array)[array_idx] = lo;
4898                         array_idx++;
4899                         break;
4900                 }
4901                 case 2: {
4902                         step = 1;
4903                         /* do not break to share code with case 3: */
4904                 }
4905                 case 3: {
4906                         void *tmp;
4907
4908                         if ((hi < lo) || (step == 0))
4909                                 goto err;
4910                         array_sz += (hi - lo) / step + 1;
4911                         tmp = realloc(*array, array_sz * sizeof(int));
4912                         if (!tmp)
4913                                 goto err;
4914                         *array = tmp;
4915                         for (i = lo; i <= hi; i += step, array_idx++)
4916                                 (*array)[array_idx] = i;
4917                         break;
4918                 }
4919                 }
4920                 ptr = strchr(start, ',');
4921                 if (ptr)
4922                         start = ptr + 1;
4923
4924         } while (ptr);
4925         return array_sz;
4926 err:
4927         if (*array) {
4928                 free(*array);
4929                 *array = NULL;
4930         }
4931         return 0;
4932 }
4933
4934 struct llog_pool_name {
4935         char lpn_name[UUID_MAX];
4936         struct list_head lpn_list;
4937 };
4938
4939 struct llog_pool_list_data {
4940         char lpld_fsname[LUSTRE_MAXFSNAME + 1];
4941         char lpld_poolname[LOV_MAXPOOLNAME + 1];
4942         bool lpld_exists;
4943         struct list_head lpld_list_head;
4944 };
4945
4946 /**
4947  * Callback to list pool information in llog
4948  * - { index: 74, event: new_pool, device: tfs-clilov, fsname: tfs, pool: tmp }
4949  * - { index: 77, event: add_pool, device: tfs-clilov, fsname: tfs, pool: tmp,
4950  *     ost: tfs-OST0000_UUID }
4951  * - { index: 224, event: remove_pool, device: tfs-clilov, fsname: tfs,
4952  *     pool: tmp, ost: tfs-OST0003_UUID }
4953  * - { index: 227, event: del_pool, device: tfs-clilov, fsname: tfs, pool: tmp }
4954  *
4955  * \param record[in]    pointer to llog record
4956  * \param data[in]      pointer to struct llog_pool_list_data
4957  *
4958  * \retval              0 on success
4959  *                      <0 on error
4960  */
4961 static int llog_poollist_cb(const char *record, void *data)
4962 {
4963         struct llog_pool_list_data *lpld = data;
4964         char pool_filter[MAX_STRING_SIZE] = "";
4965         char *new_record, *del_record, *del_pool, *found;
4966         char type[10] = "";
4967         int filter_len, rc = 0;
4968
4969         filter_len = snprintf(pool_filter, sizeof(pool_filter), " fsname: %s,",
4970                               lpld->lpld_fsname);
4971         if (lpld->lpld_poolname[0] == '\0') {
4972                 new_record = get_event_filter(LCFG_POOL_NEW);
4973                 del_record = get_event_filter(LCFG_POOL_DEL);
4974                 strncpy(type, " pool: ", sizeof(type));
4975         } else {
4976                 filter_len += snprintf(pool_filter + filter_len,
4977                                        sizeof(pool_filter) - filter_len,
4978                                        " pool: %s", lpld->lpld_poolname);
4979                 new_record = get_event_filter(LCFG_POOL_ADD);
4980                 del_record = get_event_filter(LCFG_POOL_REM);
4981                 strncpy(type, " ost: ", sizeof(type));
4982         }
4983         del_pool = get_event_filter(LCFG_POOL_DEL);
4984
4985         if (!new_record || !del_record || !del_pool) {
4986                 rc = -ENOMEM;
4987                 goto out;
4988         }
4989
4990         found = strstr(record, pool_filter);
4991         if (found &&
4992             (found[filter_len] == ' ' || found[filter_len] == ',')) {
4993                 struct llog_pool_name *tmp = NULL;
4994                 struct list_head *head = &lpld->lpld_list_head;
4995                 char *name;
4996                 int name_len, type_len = strlen(type);
4997
4998                 lpld->lpld_exists = true;
4999                 if (strstr(record, new_record)) {
5000                         name = strstr(record, type);
5001                         /* 2 bytes for " }" */
5002                         name_len = strlen(name) - type_len - 2;
5003                         if (name_len <= 0 || name_len > sizeof(tmp->lpn_name))
5004                                 return -EINVAL;
5005                         tmp = malloc(sizeof(struct llog_pool_name));
5006                         if (!tmp) {
5007                                 rc = -ENOMEM;
5008                                 goto out;
5009                         }
5010                         memset(tmp, 0, sizeof(struct llog_pool_name));
5011                         strncpy(tmp->lpn_name, name + type_len, name_len);
5012                         list_add_tail(&tmp->lpn_list, &lpld->lpld_list_head);
5013                 } else if (strstr(record, del_record)) {
5014                         name = strstr(record, type);
5015                         name_len = strlen(name) - type_len - 2;
5016                         list_for_each_entry(tmp, head, lpn_list) {
5017                                 if (strncmp(tmp->lpn_name, name + type_len,
5018                                             name_len) == 0 &&
5019                                             tmp->lpn_name[name_len] == '\0') {
5020                                         list_del(&tmp->lpn_list);
5021                                         free(tmp);
5022                                         break;
5023                                 }
5024                         }
5025                 }
5026                 /* verify if the specified pool still exists */
5027                 if (lpld->lpld_poolname[0] && strstr(record, del_pool))
5028                         lpld->lpld_exists = false;
5029         }
5030 out:
5031         if (new_record)
5032                 free(new_record);
5033         if (del_record)
5034                 free(del_record);
5035         if (del_pool)
5036                 free(del_pool);
5037
5038         return rc;
5039 }
5040
5041 /**
5042  * List pool information by config log
5043  *
5044  * \param fsname[in]    pointer to filesystem name
5045  * \param poolname[in]  pointer to pool name
5046  *
5047  * \retval              0 on success
5048  *                      < 0 on error
5049  */
5050 int llog_poollist(char *fsname, char *poolname)
5051 {
5052         char logname[MAX_OBD_NAME] = {'\0'};
5053         struct llog_pool_list_data lpld;
5054         struct llog_pool_name *tmp;
5055         struct list_head *head;
5056         int rc = 0;
5057
5058         if (fsname && fsname[0] == '\0')
5059                 fsname = NULL;
5060         if (!fsname)
5061                 return -EINVAL;
5062
5063         memset(&lpld, 0, sizeof(lpld));
5064         INIT_LIST_HEAD(&lpld.lpld_list_head);
5065         lpld.lpld_exists = false;
5066         strncpy(lpld.lpld_fsname, fsname, sizeof(lpld.lpld_fsname) - 1);
5067         if (poolname && poolname[0])
5068                 strncpy(lpld.lpld_poolname, poolname,
5069                         sizeof(lpld.lpld_poolname) - 1);
5070         snprintf(logname, sizeof(logname), "%s-client", fsname);
5071         rc = jt_llog_print_iter(logname, 0, -1, llog_poollist_cb, &lpld, false,
5072                                 false);
5073
5074         if (poolname && poolname[0])
5075                 printf("Pool: %s.%s\n", fsname, poolname);
5076         else
5077                 printf("Pools from %s:\n", fsname);
5078
5079         head = &lpld.lpld_list_head;
5080         if (poolname && poolname[0] && !lpld.lpld_exists && list_empty(head))
5081                 return -ENOENT;
5082
5083         list_for_each_entry(tmp, head, lpn_list) {
5084                 if (poolname && poolname[0])
5085                         printf("%s\n", tmp->lpn_name);
5086                 else
5087                         printf("%s.%s\n", fsname, tmp->lpn_name);
5088                 list_del(&tmp->lpn_list);
5089                 free(tmp);
5090         }
5091
5092         return rc;
5093 }
5094
5095 static bool get_pools_path(char *fsname)
5096 {
5097         glob_t path;
5098         int rc;
5099
5100         rc = cfs_get_param_paths(&path, "lov/%s-*/pools", fsname);
5101         if (!rc)
5102                 cfs_free_param_data(&path);
5103
5104         return (rc == 0);
5105 }
5106
5107 static int extract_fsname_poolname(char **argv, char *fsname,
5108                                    char *poolname)
5109 {
5110         char *cmd = argv[0], *param = argv[1];
5111         char *ptr;
5112         int rc;
5113
5114         snprintf(fsname, PATH_MAX + 1, "%s", param);
5115         ptr = strchr(fsname, '.');
5116         if (!ptr) {
5117                 if (strcmp(cmd, "pool_list") == 0) {
5118                         poolname = NULL;
5119                         goto out;
5120                 }
5121                 fprintf(stderr, ". is missing in %s\n", fsname);
5122                 rc = -EINVAL;
5123                 goto err;
5124         }
5125
5126         if ((ptr - fsname) == 0) {
5127                 fprintf(stderr, "fsname is empty\n");
5128                 rc = -EINVAL;
5129                 goto err;
5130         }
5131
5132         *ptr = '\0';
5133         ++ptr;
5134
5135         if (strlen(ptr) == 0) {
5136                 fprintf(stderr, "poolname is empty\n");
5137                 rc = -EINVAL;
5138                 goto err;
5139         }
5140
5141         strncpy(poolname, ptr, LOV_MAXPOOLNAME);
5142         poolname[LOV_MAXPOOLNAME] = '\0';
5143
5144         if (strncmp(poolname, "none", LOV_MAXPOOLNAME) == 0) {
5145                 fprintf(stderr, "poolname cannot be 'none'\n");
5146                 return -EINVAL;
5147         }
5148 out:
5149         return 0;
5150
5151 err:
5152         fprintf(stderr, "argument %s must be <fsname>.<poolname>\n", param);
5153         return rc;
5154 }
5155
5156 int jt_pool_cmd(int argc, char **argv)
5157 {
5158         enum lcfg_command_type cmd;
5159         char fsname[PATH_MAX + 1];
5160         char poolname[LOV_MAXPOOLNAME + 1];
5161         char *ostnames_buf = NULL;
5162         int i, rc;
5163         int *array = NULL, array_sz;
5164         struct {
5165                 int     rc;
5166                 char   *ostname;
5167         } *cmds = NULL;
5168
5169         switch (argc) {
5170         case 0:
5171         case 1: return CMD_HELP;
5172         case 2: {
5173                 rc = extract_fsname_poolname(argv, fsname, poolname);
5174                 if (rc)
5175                         break;
5176
5177                 if (strcmp("pool_new", argv[0]) == 0) {
5178                         cmd = LCFG_POOL_NEW;
5179                 } else if (strcmp("pool_destroy", argv[0]) == 0) {
5180                         cmd = LCFG_POOL_DEL;
5181                 } else if (strcmp("pool_list", argv[0]) == 0) {
5182                         if (get_pools_path(fsname))
5183                                 return llapi_poollist(argv[1]);
5184                         if (get_mgs_device() > 0)
5185                                 return llog_poollist(fsname, poolname);
5186                         fprintf(stderr,
5187                                 "Cannot run pool_list command since there is no local MGS/MDT or client\n");
5188                         return CMD_HELP;
5189                 } else {
5190                         return CMD_HELP;
5191                 }
5192
5193                 rc = pool_cmd(cmd, argv[0], argv[1], fsname, poolname, NULL);
5194                 if (rc)
5195                         break;
5196
5197                 check_pool_cmd_result(cmd, fsname, poolname, NULL);
5198                 break;
5199         }
5200         default: {
5201                 char format[2 * MAX_OBD_NAME];
5202
5203                 if (strcmp("pool_remove", argv[0]) == 0)
5204                         cmd = LCFG_POOL_REM;
5205                 else if (strcmp("pool_add", argv[0]) == 0)
5206                         cmd = LCFG_POOL_ADD;
5207                 else
5208                         return CMD_HELP;
5209
5210                 rc = extract_fsname_poolname(argv, fsname, poolname);
5211                 if (rc)
5212                         break;
5213
5214                 for (i = 2; i < argc; i++) {
5215                         int j;
5216
5217                         array_sz = get_array_idx(argv[i], format, &array);
5218                         if (array_sz == 0)
5219                                 return CMD_HELP;
5220
5221                         cmds = malloc(array_sz * sizeof(cmds[0]));
5222                         if (cmds) {
5223                                 ostnames_buf = malloc(array_sz *
5224                                                       (MAX_OBD_NAME + 1));
5225                         } else {
5226                                 free(array);
5227                                 rc = -ENOMEM;
5228                                 goto out;
5229                         }
5230
5231                         for (j = 0; j < array_sz; j++) {
5232                                 char ostname[MAX_OBD_NAME + 1];
5233                                 int rc2;
5234
5235                                 snprintf(ostname, MAX_OBD_NAME, format,
5236                                          array[j]);
5237                                 ostname[MAX_OBD_NAME] = '\0';
5238
5239                                 rc2 = check_and_complete_ostname(fsname,
5240                                                                 ostname);
5241                                 if (rc2) {
5242                                         free(array);
5243                                         free(cmds);
5244                                         if (ostnames_buf)
5245                                                 free(ostnames_buf);
5246                                         rc = rc ? rc : rc2;
5247                                         goto out;
5248                                 }
5249                                 if (ostnames_buf) {
5250                                         cmds[j].ostname =
5251                                         &ostnames_buf[(MAX_OBD_NAME + 1) * j];
5252                                         strcpy(cmds[j].ostname, ostname);
5253                                 } else {
5254                                         cmds[j].ostname = NULL;
5255                                 }
5256                                 cmds[j].rc = pool_cmd(cmd, argv[0], argv[1],
5257                                                       fsname, poolname,
5258                                                       ostname);
5259                                 /* Return an err if any of the add/dels fail */
5260                                 if (!rc)
5261                                         rc = cmds[j].rc;
5262                         }
5263                         for (j = 0; j < array_sz; j++) {
5264                                 if (!cmds[j].rc) {
5265                                         char ostname[MAX_OBD_NAME + 1];
5266
5267                                         if (!cmds[j].ostname) {
5268                                                 snprintf(ostname, MAX_OBD_NAME,
5269                                                          format, array[j]);
5270                                                 ostname[MAX_OBD_NAME] = '\0';
5271                                                 check_and_complete_ostname(
5272                                                         fsname, ostname);
5273                                         } else {
5274                                                 strcpy(ostname,
5275                                                        cmds[j].ostname);
5276                                         }
5277                                         check_pool_cmd_result(cmd, fsname,
5278                                                               poolname,
5279                                                               ostname);
5280                                 }
5281                         }
5282                         if (array_sz > 0)
5283                                 free(array);
5284                         if (cmds)
5285                                 free(cmds);
5286                         if (ostnames_buf)
5287                                 free(ostnames_buf);
5288                 }
5289                 fallthrough;
5290         }
5291         } /* switch */
5292
5293 out:
5294         if (rc != 0) {
5295                 errno = -rc;
5296                 perror(argv[0]);
5297         }
5298
5299         return rc;
5300 }
5301
5302 #ifdef HAVE_SERVER_SUPPORT
5303 static const char *barrier_status2name(enum barrier_status status)
5304 {
5305         switch (status) {
5306         case BS_INIT:
5307                 return "init";
5308         case BS_FREEZING_P1:
5309                 return "freezing_p1";
5310         case BS_FREEZING_P2:
5311                 return "freezing_p2";
5312         case BS_FROZEN:
5313                 return "frozen";
5314         case BS_THAWING:
5315                 return "thawing";
5316         case BS_THAWED:
5317                 return "thawed";
5318         case BS_FAILED:
5319                 return "failed";
5320         case BS_EXPIRED:
5321                 return "expired";
5322         case BS_RESCAN:
5323                 return "rescan";
5324         default:
5325                 return "unknown";
5326         }
5327 }
5328
5329 int jt_barrier_freeze(int argc, char **argv)
5330 {
5331         struct obd_ioctl_data data;
5332         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
5333         struct barrier_ctl bc;
5334         int rc;
5335
5336         if (argc < 2 || argc > 3)
5337                 return CMD_HELP;
5338
5339         memset(&data, 0, sizeof(data));
5340         rc = data.ioc_dev = get_mgs_device();
5341         if (rc < 0)
5342                 return rc;
5343
5344         memset(&bc, 0, sizeof(bc));
5345         bc.bc_version = BARRIER_VERSION_V1;
5346         bc.bc_cmd = BC_FREEZE;
5347         if (argc == 3)
5348                 bc.bc_timeout = atoi(argv[2]);
5349         if (bc.bc_timeout == 0)
5350                 bc.bc_timeout = BARRIER_TIMEOUT_DEFAULT;
5351
5352         if (strlen(argv[1]) > 8) {
5353                 fprintf(stderr,
5354                         "%s: fsname name %s is too long. It should not exceed 8.\n",
5355                         argv[0], argv[1]);
5356                 return -EINVAL;
5357         }
5358
5359         strncpy(bc.bc_name, argv[1], sizeof(bc.bc_name));
5360         data.ioc_inlbuf1 = (char *)&bc;
5361         data.ioc_inllen1 = sizeof(bc);
5362         memset(buf, 0, sizeof(rawbuf));
5363         rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
5364         if (rc) {
5365                 fprintf(stderr, "Fail to pack ioctl data: rc = %d.\n", rc);
5366                 return rc;
5367         }
5368
5369         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_BARRIER, buf);
5370         if (rc < 0)
5371                 fprintf(stderr, "Fail to freeze barrier for %s: %s\n",
5372                         argv[1], strerror(errno));
5373
5374         return rc;
5375 }
5376
5377 int jt_barrier_thaw(int argc, char **argv)
5378 {
5379         struct obd_ioctl_data data;
5380         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
5381         struct barrier_ctl bc;
5382         int rc;
5383
5384         if (argc != 2)
5385                 return CMD_HELP;
5386
5387         memset(&data, 0, sizeof(data));
5388         rc = data.ioc_dev = get_mgs_device();
5389         if (rc < 0)
5390                 return rc;
5391
5392         memset(&bc, 0, sizeof(bc));
5393         bc.bc_version = BARRIER_VERSION_V1;
5394         bc.bc_cmd = BC_THAW;
5395
5396         if (strlen(argv[1]) > 8) {
5397                 fprintf(stderr,
5398                         "fsname name %s is too long. It should not exceed 8.\n",
5399                         argv[1]);
5400                 return -EINVAL;
5401         }
5402
5403         strncpy(bc.bc_name, argv[1], sizeof(bc.bc_name));
5404         data.ioc_inlbuf1 = (char *)&bc;
5405         data.ioc_inllen1 = sizeof(bc);
5406         memset(buf, 0, sizeof(rawbuf));
5407         rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
5408         if (rc) {
5409                 fprintf(stderr, "Fail to pack ioctl data: rc = %d.\n", rc);
5410                 return rc;
5411         }
5412
5413         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_BARRIER, buf);
5414         if (rc < 0)
5415                 fprintf(stderr, "Fail to thaw barrier for %s: %s\n",
5416                         argv[1], strerror(errno));
5417
5418         return rc;
5419 }
5420
5421 int __jt_barrier_stat(const char *fsname, struct barrier_ctl *bc)
5422 {
5423         struct obd_ioctl_data data;
5424         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
5425         int rc;
5426
5427         memset(&data, 0, sizeof(data));
5428         rc = data.ioc_dev = get_mgs_device();
5429         if (rc < 0)
5430                 return rc;
5431
5432         memset(bc, 0, sizeof(*bc));
5433         bc->bc_version = BARRIER_VERSION_V1;
5434         bc->bc_cmd = BC_STAT;
5435         strncpy(bc->bc_name, fsname, sizeof(bc->bc_name) - 1);
5436         data.ioc_inlbuf1 = (char *)bc;
5437         data.ioc_inllen1 = sizeof(*bc);
5438         memset(buf, 0, sizeof(rawbuf));
5439         rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
5440         if (rc) {
5441                 fprintf(stderr, "Fail to pack ioctl data: rc = %d.\n", rc);
5442                 return rc;
5443         }
5444
5445         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_BARRIER, buf);
5446         if (rc < 0)
5447                 fprintf(stderr, "Fail to query barrier for %s: %s\n",
5448                         fsname, strerror(errno));
5449         else
5450                 llapi_ioctl_unpack(&data, buf, sizeof(rawbuf));
5451
5452         return rc;
5453 }
5454
5455 int jt_barrier_stat(int argc, char **argv)
5456 {
5457         struct barrier_ctl bc;
5458         static struct option long_opt_barrier_stat[] = {
5459                 {
5460                         .val            = 's',
5461                         .name           = "state",
5462                         .has_arg        = no_argument,
5463                 },
5464                 {       .val            = 't',
5465                         .name           = "timeout",
5466                         .has_arg        = no_argument,
5467                 },
5468                 {
5469                         NULL
5470                 }
5471         };
5472         const char *name;
5473         int index;
5474         int opt;
5475         int rc;
5476         bool state = false;
5477         bool timeout = false;
5478
5479         while ((opt = getopt_long(argc, argv, "st", long_opt_barrier_stat,
5480                                   &index)) != EOF) {
5481                 switch (opt) {
5482                 case 's':
5483                         state = true;
5484                         break;
5485                 case 't':
5486                         timeout = true;
5487                         break;
5488                 default:
5489                         return CMD_HELP;
5490                 }
5491         }
5492
5493         if (optind >= argc)
5494                 return CMD_HELP;
5495
5496         name = argv[optind];
5497         if (strlen(name) > 8) {
5498                 fprintf(stderr,
5499                         "fsname name %s is too long. It should not exceed 8.\n",
5500                         name);
5501                 return -EINVAL;
5502         }
5503
5504         rc = __jt_barrier_stat(name, &bc);
5505         if (!rc) {
5506                 if (state && !timeout)
5507                         printf("%s\n", barrier_status2name(bc.bc_status));
5508                 else if (timeout && !state)
5509                         printf("%d\n",
5510                                (bc.bc_status == BS_FREEZING_P1 ||
5511                                 bc.bc_status == BS_FREEZING_P2 ||
5512                                 bc.bc_status == BS_FROZEN) ?
5513                                bc.bc_timeout : 0);
5514                 else
5515                         printf("state: %s\ntimeout: %d seconds\n",
5516                                barrier_status2name(bc.bc_status),
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         }
5522
5523         return rc;
5524 }
5525
5526 int jt_barrier_rescan(int argc, char **argv)
5527 {
5528         struct obd_ioctl_data data;
5529         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
5530         struct barrier_ctl bc;
5531         int rc;
5532
5533         if (argc < 2 || argc > 3)
5534                 return CMD_HELP;
5535
5536         memset(&data, 0, sizeof(data));
5537         rc = data.ioc_dev = get_mgs_device();
5538         if (rc < 0)
5539                 return rc;
5540
5541         memset(&bc, 0, sizeof(bc));
5542         bc.bc_version = BARRIER_VERSION_V1;
5543         bc.bc_cmd = BC_RESCAN;
5544         if (argc == 3)
5545                 bc.bc_timeout = atoi(argv[2]);
5546         if (bc.bc_timeout == 0)
5547                 bc.bc_timeout = BARRIER_TIMEOUT_DEFAULT;
5548
5549         if (strlen(argv[1]) > 8) {
5550                 fprintf(stderr,
5551                         "fsname name %s is too long. It should not exceed 8.\n",
5552                         argv[1]);
5553                 return -EINVAL;
5554         }
5555
5556         strncpy(bc.bc_name, argv[1], sizeof(bc.bc_name));
5557         data.ioc_inlbuf1 = (char *)&bc;
5558         data.ioc_inllen1 = sizeof(bc);
5559         memset(buf, 0, sizeof(rawbuf));
5560         rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
5561         if (rc) {
5562                 fprintf(stderr, "Fail to pack ioctl data: rc = %d.\n", rc);
5563                 return rc;
5564         }
5565
5566         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_BARRIER, buf);
5567         if (rc < 0) {
5568                 fprintf(stderr, "Fail to rescan barrier bitmap for %s: %s\n",
5569                         argv[1], strerror(errno));
5570         } else {
5571                 llapi_ioctl_unpack(&data, buf, sizeof(rawbuf));
5572                 printf("%u of %u MDT(s) in the filesystem %s are inactive\n",
5573                        bc.bc_absence, bc.bc_total, argv[1]);
5574         }
5575
5576         return rc;
5577 }
5578 #endif /* HAVE_SERVER_SUPPORT */
5579
5580 int jt_get_obj_version(int argc, char **argv)
5581 {
5582         struct lu_fid fid;
5583         struct obd_ioctl_data data;
5584         __u64 version, id = ULLONG_MAX, group = ULLONG_MAX;
5585         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf, *fidstr;
5586         int rc, c;
5587
5588         while ((c = getopt(argc, argv, "i:g:")) != -1) {
5589                 switch (c) {
5590                 case 'i':
5591                         id = strtoull(optarg, NULL, 0);
5592                         break;
5593                 case 'g':
5594                         group = strtoull(optarg, NULL, 0);
5595                         break;
5596                 default:
5597                         return CMD_HELP;
5598                 }
5599         }
5600
5601         argc -= optind;
5602         fidstr = *(argv + optind);
5603
5604         if (!(id != ULLONG_MAX && group != ULLONG_MAX && argc == 0) &&
5605             !(id == ULLONG_MAX && group == ULLONG_MAX && argc == 1))
5606                 return CMD_HELP;
5607
5608         memset(&data, 0, sizeof(data));
5609         data.ioc_dev = cur_device;
5610         if (argc == 1) {
5611                 rc = llapi_fid_parse(fidstr, &fid, NULL);
5612                 if (rc) {
5613                         fprintf(stderr, "%s: error parsing FID '%s': %s\n",
5614                                 jt_cmdname(argv[0]), fidstr, strerror(-rc));
5615                         return rc;
5616                 }
5617
5618                 data.ioc_inlbuf1 = (char *)&fid;
5619                 data.ioc_inllen1 = sizeof(fid);
5620         } else {
5621                 data.ioc_inlbuf3 = (char *)&id;
5622                 data.ioc_inllen3 = sizeof(id);
5623                 data.ioc_inlbuf4 = (char *)&group;
5624                 data.ioc_inllen4 = sizeof(group);
5625         }
5626         data.ioc_inlbuf2 = (char *)&version;
5627         data.ioc_inllen2 = sizeof(version);
5628
5629         memset(buf, 0, sizeof(*buf));
5630         rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
5631         if (rc) {
5632                 fprintf(stderr, "error: %s: packing ioctl arguments: %s\n",
5633                         jt_cmdname(argv[0]), strerror(-rc));
5634                 return rc;
5635         }
5636
5637         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_GET_OBJ_VERSION, buf);
5638         if (rc) {
5639                 fprintf(stderr, "error: %s: ioctl: %s\n",
5640                         jt_cmdname(argv[0]), strerror(errno));
5641                 return -errno;
5642         }
5643
5644         llapi_ioctl_unpack(&data, buf, sizeof(rawbuf));
5645         printf("%#jx\n", (uintmax_t)version);
5646
5647         return 0;
5648 }
5649
5650 #ifdef HAVE_SERVER_SUPPORT
5651 int jt_changelog_register(int argc, char **argv)
5652 {
5653         struct option long_opts[] = {
5654         { .val = 'h', .name = "help", .has_arg = no_argument },
5655         { .val = 'm', .name = "mask", .has_arg = required_argument },
5656         { .val = 'n', .name = "nameonly", .has_arg = no_argument },
5657         { .val = 'u', .name = "user", .has_arg = required_argument },
5658         { .name = NULL } };
5659         struct obd_ioctl_data data = { 0 };
5660         char rawbuf[MAX_IOC_BUFLEN] = "";
5661         char *buf = rawbuf;
5662         char *device = lcfg_get_devname();
5663         char *username = NULL, *usermask = NULL;
5664         bool print_name_only = false;
5665         int c;
5666         int rc;
5667
5668         if (cur_device < 0 || !device)
5669                 return CMD_HELP;
5670
5671         while ((c = getopt_long(argc, argv, "hm:nu:", long_opts, NULL)) != -1) {
5672                 switch (c) {
5673                 case 'm':
5674                         usermask = strdup(optarg);
5675                         if (!usermask) {
5676                                 fprintf(stderr,
5677                                         "error: %s: %s: cannot copy '%s'\n",
5678                                         jt_cmdname(argv[0]), strerror(errno),
5679                                         optarg);
5680                                 return -errno;
5681                         }
5682                         break;
5683                 case 'n':
5684                         print_name_only = true;
5685                         break;
5686                 case 'u':
5687                         username = strdup(optarg);
5688                         if (!username) {
5689                                 fprintf(stderr,
5690                                         "error: %s: %s: cannot copy '%s'\n",
5691                                         jt_cmdname(argv[0]), strerror(errno),
5692                                         optarg);
5693                                 return -errno;
5694                         }
5695                         break;
5696                 case 'h':
5697                 default:
5698                         free(username);
5699                         free(usermask);
5700                         return CMD_HELP;
5701                 }
5702         }
5703
5704         data.ioc_dev = cur_device;
5705         if (username) {
5706                 data.ioc_inlbuf1 = username;
5707                 data.ioc_inllen1 = strlen(username) + 1;
5708         }
5709
5710         if (usermask) {
5711                 data.ioc_inlbuf2 = usermask;
5712                 data.ioc_inllen2 = strlen(usermask) + 1;
5713         }
5714
5715         rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
5716         if (rc < 0) {
5717                 fprintf(stderr, "error: %s: cannot pack ioctl: %s\n",
5718                         jt_cmdname(argv[0]), strerror(-rc));
5719                 goto out;
5720         }
5721         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_CHANGELOG_REG, buf);
5722         if (rc < 0) {
5723                 rc = -errno;
5724                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
5725                         rc == -EEXIST ? "User exists" : strerror(-rc));
5726                 goto out;
5727         }
5728
5729         llapi_ioctl_unpack(&data, buf, sizeof(rawbuf));
5730
5731         if (data.ioc_u32_1 == 0) {
5732                 fprintf(stderr, "received invalid userid!\n");
5733                 rc = -EPROTO;
5734                 goto out;
5735         }
5736
5737         if (print_name_only)
5738                 printf("%s%u%s%s\n", CHANGELOG_USER_PREFIX, data.ioc_u32_1,
5739                        username ? "-" : "", username ? : "");
5740         else
5741                 printf("%s: Registered changelog userid '%s%u%s%s'\n",
5742                        device, CHANGELOG_USER_PREFIX, data.ioc_u32_1,
5743                        username ? "-" : "", username ? : "");
5744 out:
5745         free(usermask);
5746         free(username);
5747         return rc;
5748 }
5749
5750 int jt_changelog_deregister(int argc, char **argv)
5751 {
5752         struct option long_opts[] = {
5753         { .val = 'h', .name = "help", .has_arg = no_argument },
5754         { .val = 'u', .name = "user", .has_arg = required_argument },
5755         { .name = NULL } };
5756         struct obd_ioctl_data data = { 0 };
5757         char rawbuf[MAX_IOC_BUFLEN] = "";
5758         char *buf = rawbuf;
5759         char *device = lcfg_get_devname();
5760         char *username = NULL;
5761         int id = 0;
5762         int c, rc;
5763
5764         if (cur_device < 0 || !device)
5765                 return CMD_HELP;
5766
5767         while ((c = getopt_long(argc, argv, "hu:", long_opts, NULL)) != -1) {
5768                 switch (c) {
5769                 case 'u':
5770                         username = strdup(optarg);
5771                         if (!username) {
5772                                 fprintf(stderr,
5773                                         "error: %s: %s: cannot copy '%s'\n",
5774                                         jt_cmdname(argv[0]), strerror(errno),
5775                                         optarg);
5776                                 return -errno;
5777                         }
5778                         break;
5779                 case 'h':
5780                 default:
5781                         free(username);
5782                         return CMD_HELP;
5783                 }
5784         }
5785
5786         if (1 == optind && argc > 1) {
5787                 /* first check if pure ID was passed */
5788                 id = atoi(argv[optind]);
5789                 /* nameless cl<ID> format or cl<ID>-... format, only ID matters */
5790                 if (id == 0)
5791                         sscanf(argv[optind], CHANGELOG_USER_PREFIX"%d", &id);
5792
5793                 /* no valid ID was parsed */
5794                 if (id <= 0) {
5795                         rc = -EINVAL;
5796                         fprintf(stderr,
5797                                 "error: %s: expect <ID> or cl<ID>[-name] got '%s'\n",
5798                                 strerror(-rc), argv[optind]);
5799                         return CMD_HELP;
5800                 }
5801                 optind++;
5802         }
5803
5804         if (optind < argc || argc == 1)
5805                 return CMD_HELP;
5806
5807         data.ioc_dev = cur_device;
5808         data.ioc_u32_1 = id;
5809         if (username) {
5810                 data.ioc_inlbuf1 = username;
5811                 data.ioc_inllen1 = strlen(username) + 1;
5812         }
5813
5814         rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
5815         if (rc < 0) {
5816                 fprintf(stderr, "error: %s: invalid ioctl\n",
5817                         jt_cmdname(argv[0]));
5818                 return rc;
5819         }
5820
5821         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_CHANGELOG_DEREG, buf);
5822         if (rc < 0) {
5823                 rc = -errno;
5824                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
5825                         rc == -ENOENT ? "User not found" : strerror(-rc));
5826                 return rc;
5827         }
5828
5829         llapi_ioctl_unpack(&data, buf, sizeof(rawbuf));
5830         printf("%s: Deregistered changelog user #%u\n", device, data.ioc_u32_1);
5831
5832         return 0;
5833 }
5834 #else /* !HAVE_SERVER_SUPPORT */
5835 int jt_changelog_register(int argc, char **argv)
5836 {
5837         fprintf(stderr, "error: %s: invalid ioctl\n",
5838                 jt_cmdname(argv[0]));
5839         return -EOPNOTSUPP;
5840 }
5841
5842 int jt_changelog_deregister(int argc, char **argv)
5843 {
5844         fprintf(stderr, "error: %s: invalid ioctl\n",
5845                 jt_cmdname(argv[0]));
5846         return -EOPNOTSUPP;
5847 }
5848 #endif /* HAVE_SERVER_SUPPORT */
5849
5850 int jt_pcc_add(int argc, char **argv)
5851 {
5852         struct option long_opts[] = {
5853                 { .val = 'p', .name = "param", .has_arg = required_argument },
5854                 { .name = NULL } };
5855         const char *mntpath;
5856         const char *pccpath;
5857         char *param = NULL;
5858         char cmd[PATH_MAX];
5859         int rc;
5860
5861         optind = 1;
5862         while ((rc = getopt_long(argc, argv, "p:", long_opts, NULL)) != -1) {
5863                 switch (rc) {
5864                 case 'p':
5865                         param = optarg;
5866                         break;
5867                 default:
5868                         return CMD_HELP;
5869                 }
5870         }
5871
5872         if (!param) {
5873                 fprintf(stderr, "%s: must specify the config param for PCC\n",
5874                         jt_cmdname(argv[0]));
5875                 return CMD_HELP;
5876         }
5877
5878         if (optind + 2 != argc) {
5879                 fprintf(stderr,
5880                         "%s: must specify mount path and PCC path %d:%d\n",
5881                         jt_cmdname(argv[0]), optind, argc);
5882                 return CMD_HELP;
5883         }
5884
5885         mntpath = argv[optind++];
5886         pccpath = argv[optind];
5887
5888         snprintf(cmd, PATH_MAX, "add %s %s", pccpath, param);
5889         rc = llapi_pccdev_set(mntpath, cmd);
5890         if (rc < 0)
5891                 fprintf(stderr, "%s: failed to run '%s' on %s\n",
5892                         jt_cmdname(argv[0]), cmd, mntpath);
5893
5894         return rc;
5895 }
5896
5897 int jt_pcc_del(int argc, char **argv)
5898 {
5899         const char *mntpath;
5900         const char *pccpath;
5901         char cmd[PATH_MAX];
5902         int rc;
5903
5904         optind = 1;
5905         if (argc != 3) {
5906                 fprintf(stderr, "%s: require 3 arguments\n",
5907                         jt_cmdname(argv[0]));
5908                 return CMD_HELP;
5909         }
5910
5911         mntpath = argv[optind++];
5912         pccpath = argv[optind++];
5913
5914         snprintf(cmd, PATH_MAX, "del %s", pccpath);
5915         rc = llapi_pccdev_set(mntpath, cmd);
5916         if (rc < 0)
5917                 fprintf(stderr, "%s: failed to run '%s' on %s\n",
5918                         jt_cmdname(argv[0]), cmd, mntpath);
5919
5920         return rc;
5921 }
5922
5923 int jt_pcc_clear(int argc, char **argv)
5924 {
5925         const char *mntpath;
5926         int rc;
5927
5928         optind = 1;
5929         if (argc != 2) {
5930                 fprintf(stderr, "%s: require 2 arguments\n",
5931                         jt_cmdname(argv[0]));
5932                 return CMD_HELP;
5933         }
5934
5935         mntpath = argv[optind];
5936         rc = llapi_pccdev_set(mntpath, "clear");
5937         if (rc < 0)
5938                 fprintf(stderr, "%s: failed to run 'clear' on %s\n",
5939                         jt_cmdname(argv[0]), mntpath);
5940
5941         return rc;
5942 }
5943
5944 int jt_pcc_list(int argc, char **argv)
5945 {
5946         const char *mntpath;
5947         int rc;
5948
5949         optind = 1;
5950         if (argc != 2) {
5951                 fprintf(stderr, "%s: require 2 arguments\n",
5952                         jt_cmdname(argv[0]));
5953                 return CMD_HELP;
5954         }
5955
5956         mntpath = argv[optind];
5957         rc = llapi_pccdev_get(mntpath);
5958         if (rc < 0)
5959                 fprintf(stderr, "%s: failed to run 'pcc list' on %s\n",
5960                         jt_cmdname(argv[0]), mntpath);
5961
5962         return rc;
5963 }