Whamcloud - gitweb
LU-8616 dne: allow mkdir with specific MDTs
[fs/lustre-release.git] / lustre / utils / liblustreapi.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) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
24  * Use is subject to license terms.
25  *
26  * Copyright (c) 2011, 2016, Intel Corporation.
27  */
28 /*
29  * This file is part of Lustre, http://www.lustre.org/
30  * Lustre is a trademark of Sun Microsystems, Inc.
31  *
32  * lustre/utils/liblustreapi.c
33  *
34  * Author: Peter J. Braam <braam@clusterfs.com>
35  * Author: Phil Schwan <phil@clusterfs.com>
36  * Author: Robert Read <rread@clusterfs.com>
37  */
38
39 /* for O_DIRECTORY */
40 #ifndef _GNU_SOURCE
41 #define _GNU_SOURCE
42 #endif
43
44 #include <ctype.h>
45 #include <mntent.h>
46 #include <stdlib.h>
47 #include <stdio.h>
48 #include <string.h>
49 #include <stddef.h>
50 #include <sys/ioctl.h>
51 #include <unistd.h>
52 #include <fcntl.h>
53 #include <errno.h>
54 #include <dirent.h>
55 #include <stdarg.h>
56 #include <sys/stat.h>
57 #include <sys/statfs.h>
58 #include <sys/syscall.h>
59 #include <sys/time.h>
60 #include <sys/types.h>
61 #include <sys/xattr.h>
62 #include <time.h>
63 #include <fnmatch.h>
64 #include <libgen.h> /* for dirname() */
65 #ifdef HAVE_LINUX_UNISTD_H
66 #include <linux/unistd.h>
67 #else
68 #include <unistd.h>
69 #endif
70 #include <poll.h>
71
72 #include <libcfs/util/ioctl.h>
73 #include <libcfs/util/param.h>
74 #include <libcfs/util/string.h>
75 #include <linux/lnet/lnetctl.h>
76 #include <lustre/lustreapi.h>
77 #include <linux/lustre/lustre_ostid.h>
78 #include <linux/lustre/lustre_ioctl.h>
79 #include "lustreapi_internal.h"
80
81 static int llapi_msg_level = LLAPI_MSG_MAX;
82
83 char *mdt_hash_name[] = { "none",
84                           LMV_HASH_NAME_ALL_CHARS,
85                           LMV_HASH_NAME_FNV_1A_64 };
86
87 void llapi_msg_set_level(int level)
88 {
89         /* ensure level is in the good range */
90         if (level < LLAPI_MSG_OFF)
91                 llapi_msg_level = LLAPI_MSG_OFF;
92         else if (level > LLAPI_MSG_MAX)
93                 llapi_msg_level = LLAPI_MSG_MAX;
94         else
95                 llapi_msg_level = level;
96 }
97
98 int llapi_msg_get_level(void)
99 {
100         return llapi_msg_level;
101 }
102
103 static void error_callback_default(enum llapi_message_level level, int err,
104                                    const char *fmt, va_list ap)
105 {
106         vfprintf(stderr, fmt, ap);
107         if (level & LLAPI_MSG_NO_ERRNO)
108                 fprintf(stderr, "\n");
109         else
110                 fprintf(stderr, ": %s (%d)\n", strerror(err), err);
111 }
112
113 static void info_callback_default(enum llapi_message_level level, int err,
114                                   const char *fmt, va_list ap)
115 {
116         vfprintf(stdout, fmt, ap);
117 }
118
119 static llapi_log_callback_t llapi_error_callback = error_callback_default;
120 static llapi_log_callback_t llapi_info_callback = info_callback_default;
121
122
123 /* llapi_error will preserve errno */
124 void llapi_error(enum llapi_message_level level, int err, const char *fmt, ...)
125 {
126         va_list  args;
127         int      tmp_errno = errno;
128
129         if ((level & LLAPI_MSG_MASK) > llapi_msg_level)
130                 return;
131
132         va_start(args, fmt);
133         llapi_error_callback(level, abs(err), fmt, args);
134         va_end(args);
135         errno = tmp_errno;
136 }
137
138 /* llapi_printf will preserve errno */
139 void llapi_printf(enum llapi_message_level level, const char *fmt, ...)
140 {
141         va_list  args;
142         int      tmp_errno = errno;
143
144         if ((level & LLAPI_MSG_MASK) > llapi_msg_level)
145                 return;
146
147         va_start(args, fmt);
148         llapi_info_callback(level, 0, fmt, args);
149         va_end(args);
150         errno = tmp_errno;
151 }
152
153 /**
154  * Set a custom error logging function. Passing in NULL will reset the logging
155  * callback to its default value.
156  *
157  * This function returns the value of the old callback.
158  */
159 llapi_log_callback_t llapi_error_callback_set(llapi_log_callback_t cb)
160 {
161         llapi_log_callback_t    old = llapi_error_callback;
162
163         if (cb != NULL)
164                 llapi_error_callback = cb;
165         else
166                 llapi_error_callback = error_callback_default;
167
168         return old;
169 }
170
171 /**
172  * Set a custom info logging function. Passing in NULL will reset the logging
173  * callback to its default value.
174  *
175  * This function returns the value of the old callback.
176  */
177 llapi_log_callback_t llapi_info_callback_set(llapi_log_callback_t cb)
178 {
179         llapi_log_callback_t    old = llapi_info_callback;
180
181         if (cb != NULL)
182                 llapi_info_callback = cb;
183         else
184                 llapi_info_callback = info_callback_default;
185
186         return old;
187 }
188
189 /**
190  * size_units is to be initialized (or zeroed) by caller.
191  */
192 int llapi_parse_size(const char *optarg, unsigned long long *size,
193                      unsigned long long *size_units, int bytes_spec)
194 {
195         char *end;
196         char *argbuf = (char *)optarg;
197         unsigned long long frac = 0, frac_d = 1;
198
199         if (strncmp(optarg, "-", 1) == 0)
200                 return -1;
201
202         if (*size_units == 0)
203                 *size_units = 1;
204
205         *size = strtoull(argbuf, &end, 0);
206         if (end != NULL && *end == '.') {
207                 int i;
208
209                 argbuf = end + 1;
210                 frac = strtoull(argbuf, &end, 10);
211                 /* count decimal places */
212                 for (i = 0; i < (end - argbuf); i++)
213                         frac_d *= 10;
214         }
215
216         if (*end != '\0') {
217                 if ((*end == 'b') && *(end + 1) == '\0' &&
218                     (*size & (~0ULL << (64 - 9))) == 0 &&
219                     !bytes_spec) {
220                         *size_units = 1 << 9;
221                 } else if ((*end == 'b') &&
222                            *(end + 1) == '\0' &&
223                            bytes_spec) {
224                         *size_units = 1;
225                 } else if ((*end == 'k' || *end == 'K') &&
226                            *(end + 1) == '\0' &&
227                            (*size & (~0ULL << (64 - 10))) == 0) {
228                         *size_units = 1 << 10;
229                 } else if ((*end == 'm' || *end == 'M') &&
230                            *(end + 1) == '\0' &&
231                            (*size & (~0ULL << (64 - 20))) == 0) {
232                         *size_units = 1 << 20;
233                 } else if ((*end == 'g' || *end == 'G') &&
234                            *(end + 1) == '\0' &&
235                            (*size & (~0ULL << (64 - 30))) == 0) {
236                         *size_units = 1 << 30;
237                 } else if ((*end == 't' || *end == 'T') &&
238                            *(end + 1) == '\0' &&
239                            (*size & (~0ULL << (64 - 40))) == 0) {
240                         *size_units = 1ULL << 40;
241                 } else if ((*end == 'p' || *end == 'P') &&
242                            *(end + 1) == '\0' &&
243                            (*size & (~0ULL << (64 - 50))) == 0) {
244                         *size_units = 1ULL << 50;
245                 } else if ((*end == 'e' || *end == 'E') &&
246                            *(end + 1) == '\0' &&
247                            (*size & (~0ULL << (64 - 60))) == 0) {
248                         *size_units = 1ULL << 60;
249                 } else {
250                         return -1;
251                 }
252         }
253         *size = *size * *size_units + frac * *size_units / frac_d;
254
255         return 0;
256 }
257
258 int obd_ioctl_pack(struct obd_ioctl_data *data, char **pbuf, int max_len)
259 {
260         struct obd_ioctl_data *overlay;
261         char *ptr;
262
263         data->ioc_len = obd_ioctl_packlen(data);
264         data->ioc_version = OBD_IOCTL_VERSION;
265
266         if (*pbuf != NULL && data->ioc_len > max_len) {
267                 fprintf(stderr, "pbuf = %p, ioc_len = %u, max_len = %d\n",
268                         *pbuf, data->ioc_len, max_len);
269                 return -EINVAL;
270         }
271
272         if (*pbuf == NULL)
273                 *pbuf = malloc(data->ioc_len);
274
275         if (*pbuf == NULL)
276                 return -ENOMEM;
277
278         overlay = (struct obd_ioctl_data *)*pbuf;
279         memcpy(*pbuf, data, sizeof(*data));
280
281         ptr = overlay->ioc_bulk;
282         if (data->ioc_inlbuf1) {
283                 memcpy(ptr, data->ioc_inlbuf1, data->ioc_inllen1);
284                 ptr += cfs_size_round(data->ioc_inllen1);
285         }
286
287         if (data->ioc_inlbuf2) {
288                 memcpy(ptr, data->ioc_inlbuf2, data->ioc_inllen2);
289                 ptr += cfs_size_round(data->ioc_inllen2);
290         }
291
292         if (data->ioc_inlbuf3) {
293                 memcpy(ptr, data->ioc_inlbuf3, data->ioc_inllen3);
294                 ptr += cfs_size_round(data->ioc_inllen3);
295         }
296
297         if (data->ioc_inlbuf4) {
298                 memcpy(ptr, data->ioc_inlbuf4, data->ioc_inllen4);
299                 ptr += cfs_size_round(data->ioc_inllen4);
300         }
301
302         return 0;
303 }
304
305 int obd_ioctl_unpack(struct obd_ioctl_data *data, char *pbuf, int max_len)
306 {
307         struct obd_ioctl_data *overlay;
308         char *ptr;
309
310         if (pbuf == NULL)
311                 return 1;
312
313         overlay = (struct obd_ioctl_data *)pbuf;
314
315         /* Preserve the caller's buffer pointers */
316         overlay->ioc_inlbuf1 = data->ioc_inlbuf1;
317         overlay->ioc_inlbuf2 = data->ioc_inlbuf2;
318         overlay->ioc_inlbuf3 = data->ioc_inlbuf3;
319         overlay->ioc_inlbuf4 = data->ioc_inlbuf4;
320
321         memcpy(data, pbuf, sizeof(*data));
322
323         ptr = overlay->ioc_bulk;
324         if (data->ioc_inlbuf1) {
325                 memcpy(data->ioc_inlbuf1, ptr, data->ioc_inllen1);
326                 ptr += cfs_size_round(data->ioc_inllen1);
327         }
328
329         if (data->ioc_inlbuf2) {
330                 memcpy(data->ioc_inlbuf2, ptr, data->ioc_inllen2);
331                 ptr += cfs_size_round(data->ioc_inllen2);
332         }
333
334         if (data->ioc_inlbuf3) {
335                 memcpy(data->ioc_inlbuf3, ptr, data->ioc_inllen3);
336                 ptr += cfs_size_round(data->ioc_inllen3);
337         }
338
339         if (data->ioc_inlbuf4) {
340                 memcpy(data->ioc_inlbuf4, ptr, data->ioc_inllen4);
341                 ptr += cfs_size_round(data->ioc_inllen4);
342         }
343
344         return 0;
345 }
346
347 /* XXX: llapi_xxx() functions return negative values upon failure */
348
349 int llapi_stripe_limit_check(unsigned long long stripe_size, int stripe_offset,
350                                 int stripe_count, int stripe_pattern)
351 {
352         int page_size, rc;
353
354         /* 64 KB is the largest common page size I'm aware of (on ia64), but
355          * check the local page size just in case. */
356         page_size = LOV_MIN_STRIPE_SIZE;
357         if (getpagesize() > page_size) {
358                 page_size = getpagesize();
359                 llapi_err_noerrno(LLAPI_MSG_WARN,
360                                 "warning: your page size (%u) is "
361                                 "larger than expected (%u)", page_size,
362                                 LOV_MIN_STRIPE_SIZE);
363         }
364         if (!llapi_stripe_size_is_aligned(stripe_size)) {
365                 rc = -EINVAL;
366                 llapi_error(LLAPI_MSG_ERROR, rc, "error: bad stripe_size %llu, "
367                                 "must be an even multiple of %d bytes",
368                                 stripe_size, page_size);
369                 return rc;
370         }
371         if (!llapi_stripe_index_is_valid(stripe_offset)) {
372                 rc = -EINVAL;
373                 llapi_error(LLAPI_MSG_ERROR, rc, "error: bad stripe offset %d",
374                                 stripe_offset);
375                 return rc;
376         }
377         if (!llapi_stripe_count_is_valid(stripe_count)) {
378                 rc = -EINVAL;
379                 llapi_error(LLAPI_MSG_ERROR, rc, "error: bad stripe count %d",
380                                 stripe_count);
381                 return rc;
382         }
383         if (llapi_stripe_size_is_too_big(stripe_size)) {
384                 rc = -EINVAL;
385                 llapi_error(LLAPI_MSG_ERROR, rc,
386                                 "warning: stripe size 4G or larger "
387                                 "is not currently supported and would wrap");
388                 return rc;
389         }
390         return 0;
391 }
392
393 int llapi_dir_stripe_limit_check(int stripe_offset, int stripe_count,
394                                  int hash_type)
395 {
396         int rc;
397
398         if (!llapi_dir_stripe_index_is_valid(stripe_offset)) {
399                 rc = -EINVAL;
400                 llapi_error(LLAPI_MSG_ERROR, rc, "error: bad stripe offset %d",
401                                 stripe_offset);
402                 return rc;
403         }
404         if (!llapi_dir_stripe_count_is_valid(stripe_count)) {
405                 rc = -EINVAL;
406                 llapi_error(LLAPI_MSG_ERROR, rc, "error: bad stripe count %d",
407                                 stripe_count);
408                 return rc;
409         }
410
411         if (!llapi_dir_hash_type_is_valid(hash_type)) {
412                 rc = -EINVAL;
413                 llapi_error(LLAPI_MSG_ERROR, rc, "error: bad hash type %d",
414                                 hash_type);
415                 return rc;
416         }
417         return 0;
418 }
419
420 /*
421  * Trim a trailing newline from a string, if it exists.
422  */
423 int llapi_chomp_string(char *buf)
424 {
425         if (!buf || !*buf)
426                 return 0;
427
428         while (buf[1])
429                 buf++;
430
431         if (*buf != '\n')
432                 return 0;
433
434         *buf = '\0';
435         return '\n';
436 }
437
438 /*
439  * Wrapper to grab parameter settings for lov.*-clilov-*.* values
440  */
441 static int get_param_lov(const char *path, const char *param,
442                          char *buf, size_t buf_size)
443 {
444         struct obd_uuid uuid;
445         int rc;
446
447         rc = llapi_file_get_lov_uuid(path, &uuid);
448         if (rc != 0)
449                 return rc;
450
451         return get_lustre_param_value("lov", uuid.uuid, FILTER_BY_EXACT, param,
452                                       buf, buf_size);
453 }
454
455 /*
456  * Wrapper to grab parameter settings for lmv.*-clilov-*.* values
457  */
458 static int get_param_lmv(const char *path, const char *param,
459                          char *buf, size_t buf_size)
460 {
461         struct obd_uuid uuid;
462         int rc;
463
464         rc = llapi_file_get_lmv_uuid(path, &uuid);
465         if (rc != 0)
466                 return rc;
467
468         return get_lustre_param_value("lmv", uuid.uuid, FILTER_BY_EXACT, param,
469                                buf, buf_size);
470 }
471
472 static int get_mds_md_size(const char *path)
473 {
474         char buf[PATH_MAX], inst[PATH_MAX];
475         int md_size = lov_user_md_size(LOV_MAX_STRIPE_COUNT, LOV_USER_MAGIC_V3);
476         int rc;
477
478         rc = llapi_getname(path, inst, sizeof(inst));
479         if (rc != 0)
480                 return md_size;
481
482         /* Get the max ea size from llite parameters. */
483         rc = get_lustre_param_value("llite", inst, FILTER_BY_EXACT,
484                                     "max_easize", buf, sizeof(buf));
485         if (rc != 0)
486                 return md_size;
487
488         rc = atoi(buf);
489
490         return rc > 0 ? rc : md_size;
491 }
492
493 int llapi_get_agent_uuid(char *path, char *buf, size_t bufsize)
494 {
495         return get_param_lmv(path, "uuid", buf, bufsize);
496 }
497
498 /*
499  * if pool is NULL, search tgtname in target_obd
500  * if pool is not NULL:
501  *  if pool not found returns errno < 0
502  *  if tgtname is NULL, returns 1 if pool is not empty and 0 if pool empty
503  *  if tgtname is not NULL, returns 1 if OST is in pool and 0 if not
504  */
505 int llapi_search_tgt(char *fsname, char *poolname, char *tgtname, bool is_mdt)
506 {
507         char buffer[PATH_MAX];
508         size_t len = 0;
509         glob_t param;
510         FILE *fd;
511         int rc;
512
513         /* You need one or the other */
514         if (poolname == NULL && fsname == NULL)
515                 return -EINVAL;
516
517         if (tgtname != NULL)
518                 len = strlen(tgtname);
519
520         if (poolname == NULL && len == 0)
521                 return -EINVAL;
522
523         /* Search by poolname and fsname if is not NULL */
524         if (poolname != NULL) {
525                 rc = poolpath(&param, fsname, NULL);
526                 if (rc == 0) {
527                         snprintf(buffer, sizeof(buffer), "%s/%s",
528                                  param.gl_pathv[0], poolname);
529                 }
530         } else if (fsname != NULL) {
531                 rc = get_lustre_param_path(is_mdt ? "lmv" : "lov", fsname,
532                                            FILTER_BY_FS_NAME,
533                                            "target_obd", &param);
534                 if (rc == 0) {
535                         strncpy(buffer, param.gl_pathv[0],
536                                 sizeof(buffer));
537                 }
538         } else {
539                 return -EINVAL;
540         }
541         cfs_free_param_data(&param);
542         if (rc)
543                 return rc;
544
545         fd = fopen(buffer, "r");
546         if (fd == NULL)
547                 return -errno;
548
549         while (fgets(buffer, sizeof(buffer), fd) != NULL) {
550                 if (poolname == NULL) {
551                         char *ptr;
552                         /* Search for an tgtname in the list of targets
553                          * Line format is IDX: fsname-OST/MDTxxxx_UUID STATUS */
554                         ptr = strchr(buffer, ' ');
555                         if ((ptr != NULL) &&
556                             (strncmp(ptr + 1, tgtname, len) == 0)) {
557                                 fclose(fd);
558                                 return 1;
559                         }
560                 } else {
561                         /* Search for an tgtname in a pool,
562                          * (or an existing non-empty pool if no tgtname) */
563                         if ((tgtname == NULL) ||
564                             (strncmp(buffer, tgtname, len) == 0)) {
565                                 fclose(fd);
566                                 return 1;
567                         }
568                 }
569         }
570         fclose(fd);
571         return 0;
572 }
573
574 int llapi_search_ost(char *fsname, char *poolname, char *ostname)
575 {
576         return llapi_search_tgt(fsname, poolname, ostname, false);
577 }
578
579 /**
580  * Open a Lustre file.
581  *
582  * \param name     the name of the file to be opened
583  * \param flags    access mode, see flags in open(2)
584  * \param mode     permission of the file if it is created, see mode in open(2)
585  * \param param    stripe pattern of the newly created file
586  *
587  * \retval         file descriptor of opened file
588  * \retval         negative errno on failure
589  */
590 int llapi_file_open_param(const char *name, int flags, mode_t mode,
591                           const struct llapi_stripe_param *param)
592 {
593         char fsname[MAX_OBD_NAME + 1] = { 0 };
594         char *pool_name = param->lsp_pool;
595         struct lov_user_md *lum = NULL;
596         size_t lum_size = sizeof(*lum);
597         int fd, rc;
598
599         /* Make sure we are on a Lustre file system */
600         rc = llapi_search_fsname(name, fsname);
601         if (rc) {
602                 llapi_error(LLAPI_MSG_ERROR, rc,
603                             "'%s' is not on a Lustre filesystem",
604                             name);
605                 return rc;
606         }
607
608         /* Check if the stripe pattern is sane. */
609         rc = llapi_stripe_limit_check(param->lsp_stripe_size,
610                                       param->lsp_stripe_offset,
611                                       param->lsp_stripe_count,
612                                       param->lsp_stripe_pattern);
613         if (rc != 0)
614                 return rc;
615
616         /* Make sure we have a good pool */
617         if (pool_name != NULL) {
618                 /* in case user gives the full pool name <fsname>.<poolname>,
619                  * strip the fsname */
620                 char *ptr = strchr(pool_name, '.');
621                 if (ptr != NULL) {
622                         *ptr = '\0';
623                         if (strcmp(pool_name, fsname) != 0) {
624                                 *ptr = '.';
625                                 llapi_err_noerrno(LLAPI_MSG_ERROR,
626                                         "Pool '%s' is not on filesystem '%s'",
627                                         pool_name, fsname);
628                                 return -EINVAL;
629                         }
630                         pool_name = ptr + 1;
631                 }
632
633                 /* Make sure the pool exists and is non-empty */
634                 rc = llapi_search_ost(fsname, pool_name, NULL);
635                 if (rc < 1) {
636                         char *err = rc == 0 ? "has no OSTs" : "does not exist";
637
638                         llapi_err_noerrno(LLAPI_MSG_ERROR, "pool '%s.%s' %s",
639                                           fsname, pool_name, err);
640                         return -EINVAL;
641                 }
642
643                 lum_size = sizeof(struct lov_user_md_v3);
644         }
645
646         /* sanity check of target list */
647         if (param->lsp_is_specific) {
648                 char ostname[MAX_OBD_NAME + 1];
649                 bool found = false;
650                 int i;
651
652                 for (i = 0; i < param->lsp_stripe_count; i++) {
653                         snprintf(ostname, sizeof(ostname), "%s-OST%04x_UUID",
654                                  fsname, param->lsp_osts[i]);
655                         rc = llapi_search_ost(fsname, pool_name, ostname);
656                         if (rc <= 0) {
657                                 if (rc == 0)
658                                         rc = -ENODEV;
659
660                                 llapi_error(LLAPI_MSG_ERROR, rc,
661                                             "%s: cannot find OST %s in %s",
662                                             __func__, ostname,
663                                             pool_name != NULL ?
664                                             "pool" : "system");
665                                 return rc;
666                         }
667
668                         /* Make sure stripe offset is in OST list. */
669                         if (param->lsp_osts[i] == param->lsp_stripe_offset)
670                                 found = true;
671                 }
672                 if (!found) {
673                         llapi_error(LLAPI_MSG_ERROR, -EINVAL,
674                                     "%s: stripe offset '%d' is not in the "
675                                     "target list",
676                                     __func__, param->lsp_stripe_offset);
677                         return -EINVAL;
678                 }
679
680                 lum_size = lov_user_md_size(param->lsp_stripe_count,
681                                             LOV_USER_MAGIC_SPECIFIC);
682         }
683
684         lum = calloc(1, lum_size);
685         if (lum == NULL)
686                 return -ENOMEM;
687
688 retry_open:
689         fd = open(name, flags | O_LOV_DELAY_CREATE, mode);
690         if (fd < 0) {
691                 if (errno == EISDIR && !(flags & O_DIRECTORY)) {
692                         flags = O_DIRECTORY | O_RDONLY;
693                         goto retry_open;
694                 }
695         }
696
697         if (fd < 0) {
698                 rc = -errno;
699                 llapi_error(LLAPI_MSG_ERROR, rc, "unable to open '%s'", name);
700                 free(lum);
701                 return rc;
702         }
703
704         /*  Initialize IOCTL striping pattern structure */
705         lum->lmm_magic = LOV_USER_MAGIC_V1;
706         lum->lmm_pattern = param->lsp_stripe_pattern;
707         lum->lmm_stripe_size = param->lsp_stripe_size;
708         lum->lmm_stripe_count = param->lsp_stripe_count;
709         lum->lmm_stripe_offset = param->lsp_stripe_offset;
710         if (pool_name != NULL) {
711                 struct lov_user_md_v3 *lumv3 = (void *)lum;
712
713                 lumv3->lmm_magic = LOV_USER_MAGIC_V3;
714                 strncpy(lumv3->lmm_pool_name, pool_name, LOV_MAXPOOLNAME);
715         }
716         if (param->lsp_is_specific) {
717                 struct lov_user_md_v3 *lumv3 = (void *)lum;
718                 int i;
719
720                 lumv3->lmm_magic = LOV_USER_MAGIC_SPECIFIC;
721                 if (pool_name == NULL) {
722                         /* LOV_USER_MAGIC_SPECIFIC uses v3 format plus specified
723                          * OST list, therefore if pool is not specified we have
724                          * to pack a null pool name for placeholder. */
725                         memset(lumv3->lmm_pool_name, 0, LOV_MAXPOOLNAME);
726                 }
727
728                 for (i = 0; i < param->lsp_stripe_count; i++)
729                         lumv3->lmm_objects[i].l_ost_idx = param->lsp_osts[i];
730         }
731
732         if (ioctl(fd, LL_IOC_LOV_SETSTRIPE, lum) != 0) {
733                 char *errmsg = "stripe already set";
734
735                 rc = -errno;
736                 if (errno != EEXIST && errno != EALREADY)
737                         errmsg = strerror(errno);
738
739                 llapi_err_noerrno(LLAPI_MSG_ERROR,
740                                   "error on ioctl %#jx for '%s' (%d): %s",
741                                   (uintmax_t)LL_IOC_LOV_SETSTRIPE, name, fd,
742                                   errmsg);
743
744                 close(fd);
745                 fd = rc;
746         }
747
748         free(lum);
749
750         return fd;
751 }
752
753 int llapi_file_open_pool(const char *name, int flags, int mode,
754                          unsigned long long stripe_size, int stripe_offset,
755                          int stripe_count, int stripe_pattern, char *pool_name)
756 {
757         const struct llapi_stripe_param param = {
758                 .lsp_stripe_size = stripe_size,
759                 .lsp_stripe_count = stripe_count,
760                 .lsp_stripe_pattern = stripe_pattern,
761                 .lsp_stripe_offset = stripe_offset,
762                 .lsp_pool = pool_name
763         };
764         return llapi_file_open_param(name, flags, mode, &param);
765 }
766
767 int llapi_file_open(const char *name, int flags, int mode,
768                     unsigned long long stripe_size, int stripe_offset,
769                     int stripe_count, int stripe_pattern)
770 {
771         return llapi_file_open_pool(name, flags, mode, stripe_size,
772                                     stripe_offset, stripe_count,
773                                     stripe_pattern, NULL);
774 }
775
776 int llapi_file_create(const char *name, unsigned long long stripe_size,
777                       int stripe_offset, int stripe_count, int stripe_pattern)
778 {
779         int fd;
780
781         fd = llapi_file_open_pool(name, O_CREAT | O_WRONLY, 0644, stripe_size,
782                                   stripe_offset, stripe_count, stripe_pattern,
783                                   NULL);
784         if (fd < 0)
785                 return fd;
786
787         close(fd);
788         return 0;
789 }
790
791 int llapi_file_create_pool(const char *name, unsigned long long stripe_size,
792                            int stripe_offset, int stripe_count,
793                            int stripe_pattern, char *pool_name)
794 {
795         int fd;
796
797         fd = llapi_file_open_pool(name, O_CREAT | O_WRONLY, 0644, stripe_size,
798                                   stripe_offset, stripe_count, stripe_pattern,
799                                   pool_name);
800         if (fd < 0)
801                 return fd;
802
803         close(fd);
804         return 0;
805 }
806
807 static int verify_dir_param(const char *name,
808                             const struct llapi_stripe_param *param)
809 {
810         char fsname[MAX_OBD_NAME + 1] = { 0 };
811         char *pool_name = param->lsp_pool;
812         int rc;
813
814         /* Make sure we are on a Lustre file system */
815         rc = llapi_search_fsname(name, fsname);
816         if (rc) {
817                 llapi_error(LLAPI_MSG_ERROR, rc,
818                             "'%s' is not on a Lustre filesystem",
819                             name);
820                 return rc;
821         }
822
823         /* Check if the stripe pattern is sane. */
824         rc = llapi_dir_stripe_limit_check(param->lsp_stripe_offset,
825                                           param->lsp_stripe_count,
826                                           param->lsp_stripe_pattern);
827         if (rc != 0)
828                 return rc;
829
830         /* Make sure we have a good pool */
831         if (pool_name != NULL) {
832                 /* in case user gives the full pool name <fsname>.<poolname>,
833                  * strip the fsname */
834                 char *ptr = strchr(pool_name, '.');
835
836                 if (ptr != NULL) {
837                         *ptr = '\0';
838                         if (strcmp(pool_name, fsname) != 0) {
839                                 *ptr = '.';
840                                 llapi_err_noerrno(LLAPI_MSG_ERROR,
841                                         "Pool '%s' is not on filesystem '%s'",
842                                         pool_name, fsname);
843                                 return -EINVAL;
844                         }
845                         pool_name = ptr + 1;
846                 }
847
848                 /* Make sure the pool exists and is non-empty */
849                 rc = llapi_search_tgt(fsname, pool_name, NULL, true);
850                 if (rc < 1) {
851                         char *err = rc == 0 ? "has no OSTs" : "does not exist";
852
853                         llapi_err_noerrno(LLAPI_MSG_ERROR, "pool '%s.%s' %s",
854                                           fsname, pool_name, err);
855                         return -EINVAL;
856                 }
857         }
858
859         /* sanity check of target list */
860         if (param->lsp_is_specific) {
861                 char mdtname[MAX_OBD_NAME + 1];
862                 bool found = false;
863                 int i;
864
865                 for (i = 0; i < param->lsp_stripe_count; i++) {
866                         snprintf(mdtname, sizeof(mdtname), "%s-MDT%04x_UUID",
867                                  fsname, param->lsp_tgts[i]);
868                         rc = llapi_search_tgt(fsname, pool_name, mdtname, true);
869                         if (rc <= 0) {
870                                 if (rc == 0)
871                                         rc = -ENODEV;
872
873                                 llapi_error(LLAPI_MSG_ERROR, rc,
874                                             "%s: cannot find MDT %s in %s",
875                                             __func__, mdtname,
876                                             pool_name != NULL ?
877                                             "pool" : "system");
878                                 return rc;
879                         }
880
881                         /* Make sure stripe offset is in MDT list. */
882                         if (param->lsp_tgts[i] == param->lsp_stripe_offset)
883                                 found = true;
884                 }
885                 if (!found) {
886                         llapi_error(LLAPI_MSG_ERROR, -EINVAL,
887                                     "%s: stripe offset '%d' is not in the "
888                                     "target list",
889                                     __func__, param->lsp_stripe_offset);
890                         return -EINVAL;
891                 }
892         }
893
894         return 0;
895 }
896
897 static inline void param2lmu(struct lmv_user_md *lmu,
898                              const struct llapi_stripe_param *param)
899 {
900         lmu->lum_magic = param->lsp_is_specific ? LMV_USER_MAGIC_SPECIFIC :
901                                                   LMV_USER_MAGIC;
902         lmu->lum_stripe_count = param->lsp_stripe_count;
903         lmu->lum_stripe_offset = param->lsp_stripe_offset;
904         lmu->lum_hash_type = param->lsp_stripe_pattern;
905         if (param->lsp_pool != NULL)
906                 strncpy(lmu->lum_pool_name, param->lsp_pool, LOV_MAXPOOLNAME);
907         if (param->lsp_is_specific) {
908                 int i;
909
910                 for (i = 0; i < param->lsp_stripe_count; i++)
911                         lmu->lum_objects[i].lum_mds = param->lsp_tgts[i];
912         }
913 }
914
915 int llapi_dir_set_default_lmv(const char *name,
916                               const struct llapi_stripe_param *param)
917 {
918         struct lmv_user_md lmu = { 0 };
919         int fd;
920         int rc = 0;
921
922         rc = verify_dir_param(name, param);
923         if (rc)
924                 return rc;
925
926         /* TODO: default lmv doesn't support specific targets yet */
927         if (param->lsp_is_specific)
928                 return -EINVAL;
929
930         param2lmu(&lmu, param);
931
932         fd = open(name, O_DIRECTORY | O_RDONLY);
933         if (fd < 0) {
934                 rc = -errno;
935                 llapi_error(LLAPI_MSG_ERROR, rc, "unable to open '%s'", name);
936                 return rc;
937         }
938
939         rc = ioctl(fd, LL_IOC_LMV_SET_DEFAULT_STRIPE, &lmu);
940         if (rc < 0) {
941                 char *errmsg = "stripe already set";
942                 rc = -errno;
943                 if (errno != EEXIST && errno != EALREADY)
944                         errmsg = strerror(errno);
945
946                 llapi_err_noerrno(LLAPI_MSG_ERROR,
947                                   "error on LL_IOC_LMV_SETSTRIPE '%s' (%d): %s",
948                                   name, fd, errmsg);
949         }
950         close(fd);
951         return rc;
952 }
953
954 int llapi_dir_set_default_lmv_stripe(const char *name, int stripe_offset,
955                                      int stripe_count, int stripe_pattern,
956                                      const char *pool_name)
957 {
958         const struct llapi_stripe_param param = {
959                 .lsp_stripe_count = stripe_count,
960                 .lsp_stripe_offset = stripe_offset,
961                 .lsp_stripe_pattern = stripe_pattern,
962                 .lsp_pool = (char *)pool_name
963         };
964
965         return llapi_dir_set_default_lmv(name, &param);
966 }
967
968 /**
969  * Create a Lustre directory.
970  *
971  * \param name     the name of the directory to be created
972  * \param mode     permission of the file if it is created, see mode in open(2)
973  * \param param    stripe pattern of the newly created directory
974  *
975  * \retval         0 on success
976  * \retval         negative errno on failure
977  */
978 int llapi_dir_create_param(const char *name, mode_t mode,
979                            const struct llapi_stripe_param *param)
980 {
981         struct lmv_user_md *lmu = NULL;
982         size_t lmu_size = sizeof(*lmu);
983         struct obd_ioctl_data data = { 0 };
984         char rawbuf[8192];
985         char *buf = rawbuf;
986         char *dirpath = NULL;
987         char *namepath = NULL;
988         char *dir;
989         char *filename;
990         int fd, rc;
991
992         rc = verify_dir_param(name, param);
993         if (rc)
994                 return rc;
995
996         if (param->lsp_is_specific)
997                 lmu_size = lmv_user_md_size(param->lsp_stripe_count,
998                                             LMV_USER_MAGIC_SPECIFIC);
999
1000         lmu = calloc(1, lmu_size);
1001         if (lmu == NULL)
1002                 return -ENOMEM;
1003
1004         dirpath = strdup(name);
1005         if (!dirpath) {
1006                 free(lmu);
1007                 return -ENOMEM;
1008         }
1009
1010         namepath = strdup(name);
1011         if (!namepath) {
1012                 free(namepath);
1013                 free(lmu);
1014                 return -ENOMEM;
1015         }
1016
1017         param2lmu(lmu, param);
1018
1019         filename = basename(namepath);
1020         dir = dirname(dirpath);
1021
1022         data.ioc_inlbuf1 = (char *)filename;
1023         data.ioc_inllen1 = strlen(filename) + 1;
1024         data.ioc_inlbuf2 = (char *)lmu;
1025         data.ioc_inllen2 = lmu_size;
1026         data.ioc_type = mode;
1027         rc = obd_ioctl_pack(&data, &buf, sizeof(rawbuf));
1028         if (rc) {
1029                 llapi_error(LLAPI_MSG_ERROR, rc,
1030                             "error: LL_IOC_LMV_SETSTRIPE pack failed '%s'.",
1031                             name);
1032                 goto out;
1033         }
1034
1035         fd = open(dir, O_DIRECTORY | O_RDONLY);
1036         if (fd < 0) {
1037                 rc = -errno;
1038                 llapi_error(LLAPI_MSG_ERROR, rc, "unable to open '%s'", name);
1039                 goto out;
1040         }
1041
1042         if (ioctl(fd, LL_IOC_LMV_SETSTRIPE, buf)) {
1043                 char *errmsg = "stripe already set";
1044                 rc = -errno;
1045                 if (errno != EEXIST && errno != EALREADY)
1046                         errmsg = strerror(errno);
1047
1048                 llapi_err_noerrno(LLAPI_MSG_ERROR,
1049                                   "error on LL_IOC_LMV_SETSTRIPE '%s' (%d): %s",
1050                                   name, fd, errmsg);
1051         }
1052         close(fd);
1053 out:
1054         free(namepath);
1055         free(dirpath);
1056         free(lmu);
1057         return rc;
1058 }
1059
1060
1061 int llapi_dir_create_pool(const char *name, int mode, int stripe_offset,
1062                           int stripe_count, int stripe_pattern,
1063                           const char *pool_name)
1064 {
1065         const struct llapi_stripe_param param = {
1066                 .lsp_stripe_count = stripe_count,
1067                 .lsp_stripe_offset = stripe_offset,
1068                 .lsp_stripe_pattern = stripe_pattern,
1069                 .lsp_pool = (char *)pool_name
1070         };
1071
1072         return llapi_dir_create_param(name, mode, &param);
1073 }
1074
1075 int llapi_direntry_remove(char *dname)
1076 {
1077         char *dirpath = NULL;
1078         char *namepath = NULL;
1079         char *dir;
1080         char *filename;
1081         int fd = -1;
1082         int rc = 0;
1083
1084         dirpath = strdup(dname);
1085         namepath = strdup(dname);
1086         if (!dirpath || !namepath)
1087                 return -ENOMEM;
1088
1089         filename = basename(namepath);
1090
1091         dir = dirname(dirpath);
1092
1093         fd = open(dir, O_DIRECTORY | O_RDONLY);
1094         if (fd < 0) {
1095                 rc = -errno;
1096                 llapi_error(LLAPI_MSG_ERROR, rc, "unable to open '%s'",
1097                             filename);
1098                 goto out;
1099         }
1100
1101         if (ioctl(fd, LL_IOC_REMOVE_ENTRY, filename)) {
1102                 char *errmsg = strerror(errno);
1103                 llapi_err_noerrno(LLAPI_MSG_ERROR,
1104                                   "error on ioctl %#jx for '%s' (%d): %s",
1105                                   (uintmax_t)LL_IOC_LMV_SETSTRIPE, filename,
1106                                   fd, errmsg);
1107         }
1108 out:
1109         free(dirpath);
1110         free(namepath);
1111         if (fd != -1)
1112                 close(fd);
1113         return rc;
1114 }
1115
1116 /*
1117  * Find the fsname, the full path, and/or an open fd.
1118  * Either the fsname or path must not be NULL
1119  */
1120 int get_root_path(int want, char *fsname, int *outfd, char *path, int index)
1121 {
1122         struct mntent mnt;
1123         char buf[PATH_MAX], mntdir[PATH_MAX];
1124         char *ptr, *ptr_end;
1125         FILE *fp;
1126         int idx = 0, len = 0, mntlen, fd;
1127         int rc = -ENODEV;
1128
1129         /* get the mount point */
1130         fp = setmntent(PROC_MOUNTS, "r");
1131         if (fp == NULL) {
1132                 rc = -EIO;
1133                 llapi_error(LLAPI_MSG_ERROR, rc,
1134                             "setmntent(%s) failed", PROC_MOUNTS);
1135                 return rc;
1136         }
1137         while (1) {
1138                 if (getmntent_r(fp, &mnt, buf, sizeof(buf)) == NULL)
1139                         break;
1140
1141                 if (!llapi_is_lustre_mnt(&mnt))
1142                         continue;
1143
1144                 if ((want & WANT_INDEX) && (idx++ != index))
1145                         continue;
1146
1147                 mntlen = strlen(mnt.mnt_dir);
1148                 ptr = strchr(mnt.mnt_fsname, '/');
1149                 while (ptr && *ptr == '/')
1150                         ptr++;
1151                 /* thanks to the call to llapi_is_lustre_mnt() above,
1152                  * we are sure that mnt.mnt_fsname contains ":/",
1153                  * so ptr should never be NULL */
1154                 if (ptr == NULL)
1155                         continue;
1156                 ptr_end = ptr;
1157                 while (*ptr_end != '/' && *ptr_end != '\0')
1158                         ptr_end++;
1159
1160                 /* Check the fsname for a match, if given */
1161                 if (!(want & WANT_FSNAME) && fsname != NULL &&
1162                     (strlen(fsname) > 0) &&
1163                     (strncmp(ptr, fsname, ptr_end - ptr) != 0))
1164                         continue;
1165
1166                 /* If the path isn't set return the first one we find */
1167                 if (path == NULL || strlen(path) == 0) {
1168                         strncpy(mntdir, mnt.mnt_dir, strlen(mnt.mnt_dir));
1169                         mntdir[strlen(mnt.mnt_dir)] = '\0';
1170                         if ((want & WANT_FSNAME) && fsname != NULL) {
1171                                 strncpy(fsname, ptr, ptr_end - ptr);
1172                                 fsname[ptr_end - ptr] = '\0';
1173                         }
1174                         rc = 0;
1175                         break;
1176                 /* Otherwise find the longest matching path */
1177                 } else if ((strlen(path) >= mntlen) && (mntlen >= len) &&
1178                            (strncmp(mnt.mnt_dir, path, mntlen) == 0)) {
1179                         strncpy(mntdir, mnt.mnt_dir, strlen(mnt.mnt_dir));
1180                         mntdir[strlen(mnt.mnt_dir)] = '\0';
1181                         len = mntlen;
1182                         if ((want & WANT_FSNAME) && fsname != NULL) {
1183                                 strncpy(fsname, ptr, ptr_end - ptr);
1184                                 fsname[ptr_end - ptr] = '\0';
1185                         }
1186                         rc = 0;
1187                 }
1188         }
1189         endmntent(fp);
1190
1191         /* Found it */
1192         if (rc == 0) {
1193                 if ((want & WANT_PATH) && path != NULL) {
1194                         strncpy(path, mntdir, strlen(mntdir));
1195                         path[strlen(mntdir)] = '\0';
1196                 }
1197                 if (want & WANT_FD) {
1198                         fd = open(mntdir, O_RDONLY | O_DIRECTORY | O_NONBLOCK);
1199                         if (fd < 0) {
1200                                 rc = -errno;
1201                                 llapi_error(LLAPI_MSG_ERROR, rc,
1202                                             "error opening '%s'", mntdir);
1203
1204                         } else {
1205                                 *outfd = fd;
1206                         }
1207                 }
1208         } else if (want & WANT_ERROR)
1209                 llapi_err_noerrno(LLAPI_MSG_ERROR,
1210                                   "can't find fs root for '%s': %d",
1211                                   (want & WANT_PATH) ? fsname : path, rc);
1212         return rc;
1213 }
1214
1215 /*
1216  * search lustre mounts
1217  *
1218  * Calling this function will return to the user the mount point, mntdir, and
1219  * the file system name, fsname, if the user passed a buffer to this routine.
1220  *
1221  * The user inputs are pathname and index. If the pathname is supplied then
1222  * the value of the index will be ignored. The pathname will return data if
1223  * the pathname is located on a lustre mount. Index is used to pick which
1224  * mount point you want in the case of multiple mounted lustre file systems.
1225  * See function lfs_osts in lfs.c for an example of the index use.
1226  */
1227 int llapi_search_mounts(const char *pathname, int index, char *mntdir,
1228                         char *fsname)
1229 {
1230         int want = WANT_PATH, idx = -1;
1231
1232         if (!pathname || pathname[0] == '\0') {
1233                 want |= WANT_INDEX;
1234                 idx = index;
1235         } else
1236                 strcpy(mntdir, pathname);
1237
1238         if (fsname)
1239                 want |= WANT_FSNAME;
1240         return get_root_path(want, fsname, NULL, mntdir, idx);
1241 }
1242
1243 /* Given a path, find the corresponding Lustre fsname */
1244 int llapi_search_fsname(const char *pathname, char *fsname)
1245 {
1246         char *path;
1247         int rc;
1248
1249         path = realpath(pathname, NULL);
1250         if (path == NULL) {
1251                 char buf[PATH_MAX], *ptr;
1252
1253                 buf[0] = '\0';
1254                 if (pathname[0] != '/') {
1255                         /* Need an absolute path, but realpath() only works for
1256                          * pathnames that actually exist.  We go through the
1257                          * extra hurdle of dirname(getcwd() + pathname) in
1258                          * case the relative pathname contains ".." in it. */
1259                         if (getcwd(buf, sizeof(buf) - 2) == NULL)
1260                                 return -errno;
1261                         rc = strlcat(buf, "/", sizeof(buf));
1262                         if (rc >= sizeof(buf))
1263                                 return -E2BIG;
1264                 }
1265                 rc = strlcat(buf, pathname, sizeof(buf));
1266                 if (rc >= sizeof(buf))
1267                         return -E2BIG;
1268                 path = realpath(buf, NULL);
1269                 if (path == NULL) {
1270                         ptr = strrchr(buf, '/');
1271                         if (ptr == NULL)
1272                                 return -ENOENT;
1273                         *ptr = '\0';
1274                         path = realpath(buf, NULL);
1275                         if (path == NULL) {
1276                                 rc = -errno;
1277                                 llapi_error(LLAPI_MSG_ERROR, rc,
1278                                             "pathname '%s' cannot expand",
1279                                             pathname);
1280                                 return rc;
1281                         }
1282                 }
1283         }
1284         rc = get_root_path(WANT_FSNAME | WANT_ERROR, fsname, NULL, path, -1);
1285         free(path);
1286         return rc;
1287 }
1288
1289 int llapi_search_rootpath(char *pathname, const char *fsname)
1290 {
1291         return get_root_path(WANT_PATH, (char *)fsname, NULL, pathname, -1);
1292 }
1293
1294 int llapi_getname(const char *path, char *buf, size_t size)
1295 {
1296         struct obd_uuid uuid_buf;
1297         char *uuid = uuid_buf.uuid;
1298         int rc, nr;
1299
1300         memset(&uuid_buf, 0, sizeof(uuid_buf));
1301         rc = llapi_file_get_lov_uuid(path, &uuid_buf);
1302         if (rc)
1303                 return rc;
1304
1305         /* We want to turn lustre-clilov-ffff88002738bc00 into
1306          * lustre-ffff88002738bc00. */
1307
1308         nr = snprintf(buf, size, "%.*s-%s",
1309                       (int) (strlen(uuid) - 24), uuid,
1310                       uuid + strlen(uuid) - 16);
1311
1312         if (nr >= size)
1313                 rc = -ENAMETOOLONG;
1314
1315         return rc;
1316 }
1317
1318 /**
1319  * Get the list of pool members.
1320  * \param poolname    string of format \<fsname\>.\<poolname\>
1321  * \param members     caller-allocated array of char*
1322  * \param list_size   size of the members array
1323  * \param buffer      caller-allocated buffer for storing OST names
1324  * \param buffer_size size of the buffer
1325  *
1326  * \return number of members retrieved for this pool
1327  * \retval -error failure
1328  */
1329 int llapi_get_poolmembers(const char *poolname, char **members,
1330                           int list_size, char *buffer, int buffer_size)
1331 {
1332         char fsname[PATH_MAX];
1333         char *pool, *tmp;
1334         glob_t pathname;
1335         char buf[PATH_MAX];
1336         FILE *fd;
1337         int rc = 0;
1338         int nb_entries = 0;
1339         int used = 0;
1340
1341         /* name is FSNAME.POOLNAME */
1342         if (strlen(poolname) >= sizeof(fsname))
1343                 return -EOVERFLOW;
1344         strlcpy(fsname, poolname, sizeof(fsname));
1345         pool = strchr(fsname, '.');
1346         if (pool == NULL)
1347                 return -EINVAL;
1348
1349         *pool = '\0';
1350         pool++;
1351
1352         rc = poolpath(&pathname, fsname, NULL);
1353         if (rc != 0) {
1354                 llapi_error(LLAPI_MSG_ERROR, rc,
1355                             "Lustre filesystem '%s' not found",
1356                             fsname);
1357                 return rc;
1358         }
1359
1360         llapi_printf(LLAPI_MSG_NORMAL, "Pool: %s.%s\n", fsname, pool);
1361         rc = snprintf(buf, sizeof(buf), "%s/%s", pathname.gl_pathv[0], pool);
1362         cfs_free_param_data(&pathname);
1363         if (rc >= sizeof(buf))
1364                 return -EOVERFLOW;
1365         fd = fopen(buf, "r");
1366         if (fd == NULL) {
1367                 rc = -errno;
1368                 llapi_error(LLAPI_MSG_ERROR, rc, "cannot open %s", buf);
1369                 return rc;
1370         }
1371
1372         rc = 0;
1373         while (fgets(buf, sizeof(buf), fd) != NULL) {
1374                 if (nb_entries >= list_size) {
1375                         rc = -EOVERFLOW;
1376                         break;
1377                 }
1378                 buf[sizeof(buf) - 1] = '\0';
1379                 /* remove '\n' */
1380                 tmp = strchr(buf, '\n');
1381                 if (tmp != NULL)
1382                         *tmp='\0';
1383                 if (used + strlen(buf) + 1 > buffer_size) {
1384                         rc = -EOVERFLOW;
1385                         break;
1386                 }
1387
1388                 strcpy(buffer + used, buf);
1389                 members[nb_entries] = buffer + used;
1390                 used += strlen(buf) + 1;
1391                 nb_entries++;
1392                 rc = nb_entries;
1393         }
1394
1395         fclose(fd);
1396         return rc;
1397 }
1398
1399 /**
1400  * Get the list of pools in a filesystem.
1401  * \param name        filesystem name or path
1402  * \param poollist    caller-allocated array of char*
1403  * \param list_size   size of the poollist array
1404  * \param buffer      caller-allocated buffer for storing pool names
1405  * \param buffer_size size of the buffer
1406  *
1407  * \return number of pools retrieved for this filesystem
1408  * \retval -error failure
1409  */
1410 int llapi_get_poollist(const char *name, char **poollist, int list_size,
1411                        char *buffer, int buffer_size)
1412 {
1413         char rname[PATH_MAX];
1414         glob_t pathname;
1415         char *fsname;
1416         char *ptr;
1417         DIR *dir;
1418         struct dirent *pool;
1419         int rc = 0;
1420         unsigned int nb_entries = 0;
1421         unsigned int used = 0;
1422         unsigned int i;
1423
1424         /* initialize output array */
1425         for (i = 0; i < list_size; i++)
1426                 poollist[i] = NULL;
1427
1428         /* is name a pathname ? */
1429         ptr = strchr(name, '/');
1430         if (ptr != NULL) {
1431                 /* only absolute pathname is supported */
1432                 if (*name != '/')
1433                         return -EINVAL;
1434
1435                 if (!realpath(name, rname)) {
1436                         rc = -errno;
1437                         llapi_error(LLAPI_MSG_ERROR, rc, "invalid path '%s'",
1438                                     name);
1439                         return rc;
1440                 }
1441
1442                 fsname = strdup(rname);
1443                 if (!fsname)
1444                         return -ENOMEM;
1445
1446                 rc = poolpath(&pathname, NULL, rname);
1447         } else {
1448                 /* name is FSNAME */
1449                 fsname = strdup(name);
1450                 if (!fsname)
1451                         return -ENOMEM;
1452                 rc = poolpath(&pathname, fsname, NULL);
1453         }
1454         if (rc != 0) {
1455                 llapi_error(LLAPI_MSG_ERROR, rc,
1456                             "Lustre filesystem '%s' not found", name);
1457                 goto free_path;
1458         }
1459
1460         llapi_printf(LLAPI_MSG_NORMAL, "Pools from %s:\n", fsname);
1461         dir = opendir(pathname.gl_pathv[0]);
1462         if (dir == NULL) {
1463                 rc = -errno;
1464                 llapi_error(LLAPI_MSG_ERROR, rc,
1465                             "Could not open pool list for '%s'",
1466                             name);
1467                 goto free_path;
1468         }
1469
1470         do {
1471                 errno = 0;
1472                 pool = readdir(dir);
1473                 if (pool == NULL) {
1474                         rc = -errno;
1475                         goto free_dir;
1476                 }
1477
1478                 /* ignore . and .. */
1479                 if (!strcmp(pool->d_name, ".") || !strcmp(pool->d_name, ".."))
1480                         continue;
1481
1482                 /* check output bounds */
1483                 if (nb_entries >= list_size) {
1484                         rc = -EOVERFLOW;
1485                         goto free_dir;
1486                 }
1487
1488                 /* +2 for '.' and final '\0' */
1489                 if (used + strlen(pool->d_name) + strlen(fsname) + 2
1490                     > buffer_size) {
1491                         rc = -EOVERFLOW;
1492                         goto free_dir;
1493                 }
1494
1495                 sprintf(buffer + used, "%s.%s", fsname, pool->d_name);
1496                 poollist[nb_entries] = buffer + used;
1497                 used += strlen(pool->d_name) + strlen(fsname) + 2;
1498                 nb_entries++;
1499         } while (1);
1500
1501 free_dir:
1502         if (rc)
1503                 llapi_error(LLAPI_MSG_ERROR, rc,
1504                             "Error reading pool list for '%s'", name);
1505         closedir(dir);
1506 free_path:
1507         cfs_free_param_data(&pathname);
1508         if (fsname)
1509                 free(fsname);
1510         return rc != 0 ? rc : nb_entries;
1511 }
1512
1513 /* wrapper for lfs.c and obd.c */
1514 int llapi_poollist(const char *name)
1515 {
1516         /* list of pool names (assume that pool count is smaller
1517            than OST count) */
1518         char **list, *buffer = NULL, *fsname = (char *)name;
1519         char *poolname = NULL, *tmp = NULL, data[16];
1520         enum param_filter type = FILTER_BY_PATH;
1521         int obdcount, bufsize, rc, nb, i;
1522
1523         if (name == NULL)
1524                 return -EINVAL;
1525
1526         if (name[0] != '/') {
1527                 fsname = strdup(name);
1528                 if (fsname == NULL)
1529                         return -ENOMEM;
1530
1531                 poolname = strchr(fsname, '.');
1532                 if (poolname)
1533                         *poolname = '\0';
1534                 type = FILTER_BY_FS_NAME;
1535         }
1536
1537         rc = get_lustre_param_value("lov", fsname, type, "numobd",
1538                                     data, sizeof(data));
1539         if (rc < 0)
1540                 goto err;
1541         obdcount = atoi(data);
1542
1543         /* Allocate space for each fsname-OST0000_UUID, 1 per OST,
1544          * and also an array to store the pointers for all that
1545          * allocated space. */
1546 retry_get_pools:
1547         bufsize = sizeof(struct obd_uuid) * obdcount;
1548         buffer = realloc(tmp, bufsize + sizeof(*list) * obdcount);
1549         if (buffer == NULL) {
1550                 rc = -ENOMEM;
1551                 goto err;
1552         }
1553         list = (char **) (buffer + bufsize);
1554
1555         if (!poolname) {
1556                 /* name is a path or fsname */
1557                 nb = llapi_get_poollist(name, list, obdcount,
1558                                         buffer, bufsize);
1559         } else {
1560                 /* name is a pool name (<fsname>.<poolname>) */
1561                 nb = llapi_get_poolmembers(name, list, obdcount,
1562                                            buffer, bufsize);
1563         }
1564
1565         if (nb == -EOVERFLOW) {
1566                 obdcount *= 2;
1567                 tmp = buffer;
1568                 goto retry_get_pools;
1569         }
1570
1571         for (i = 0; i < nb; i++)
1572                 llapi_printf(LLAPI_MSG_NORMAL, "%s\n", list[i]);
1573         rc = (nb < 0 ? nb : 0);
1574 err:
1575         if (buffer)
1576                 free(buffer);
1577         if (fsname != NULL && type == FILTER_BY_FS_NAME)
1578                 free(fsname);
1579         return rc;
1580 }
1581
1582 typedef int (semantic_func_t)(char *path, DIR *parent, DIR **d,
1583                               void *data, struct dirent64 *de);
1584
1585 #define OBD_NOT_FOUND           (-1)
1586
1587 static int common_param_init(struct find_param *param, char *path)
1588 {
1589         int lum_size = get_mds_md_size(path);
1590
1591         if (lum_size < PATH_MAX + 1)
1592                 lum_size = PATH_MAX + 1;
1593
1594         param->fp_lum_size = lum_size;
1595         param->fp_lmd = calloc(1, sizeof(lstat_t) + param->fp_lum_size);
1596         if (param->fp_lmd == NULL) {
1597                 llapi_error(LLAPI_MSG_ERROR, -ENOMEM,
1598                             "error: allocation of %zu bytes for ioctl",
1599                             sizeof(lstat_t) + param->fp_lum_size);
1600                 return -ENOMEM;
1601         }
1602
1603         param->fp_lmv_stripe_count = 256;
1604         param->fp_lmv_md = calloc(1,
1605                                   lmv_user_md_size(param->fp_lmv_stripe_count,
1606                                                    LMV_MAGIC_V1));
1607         if (param->fp_lmv_md == NULL) {
1608                 llapi_error(LLAPI_MSG_ERROR, -ENOMEM,
1609                             "error: allocation of %d bytes for ioctl",
1610                             lmv_user_md_size(param->fp_lmv_stripe_count,
1611                                              LMV_MAGIC_V1));
1612                 return -ENOMEM;
1613         }
1614
1615         param->fp_got_uuids = 0;
1616         param->fp_obd_indexes = NULL;
1617         param->fp_obd_index = OBD_NOT_FOUND;
1618         if (!param->fp_migrate)
1619                 param->fp_mdt_index = OBD_NOT_FOUND;
1620         return 0;
1621 }
1622
1623 static void find_param_fini(struct find_param *param)
1624 {
1625         if (param->fp_obd_indexes)
1626                 free(param->fp_obd_indexes);
1627
1628         if (param->fp_lmd)
1629                 free(param->fp_lmd);
1630
1631         if (param->fp_lmv_md)
1632                 free(param->fp_lmv_md);
1633 }
1634
1635 static int cb_common_fini(char *path, DIR *parent, DIR **dirp, void *data,
1636                           struct dirent64 *de)
1637 {
1638         struct find_param *param = data;
1639         param->fp_depth--;
1640
1641         return 0;
1642 }
1643
1644 /* set errno upon failure */
1645 static DIR *opendir_parent(const char *path)
1646 {
1647         char *path_copy;
1648         char *parent_path;
1649         DIR *parent;
1650
1651         path_copy = strdup(path);
1652         if (path_copy == NULL)
1653                 return NULL;
1654
1655         parent_path = dirname(path_copy);
1656         parent = opendir(parent_path);
1657         free(path_copy);
1658
1659         return parent;
1660 }
1661
1662 static int cb_get_dirstripe(char *path, DIR *d, struct find_param *param)
1663 {
1664         int ret;
1665
1666 again:
1667         param->fp_lmv_md->lum_stripe_count = param->fp_lmv_stripe_count;
1668         if (param->fp_get_default_lmv)
1669                 param->fp_lmv_md->lum_magic = LMV_USER_MAGIC;
1670         else
1671                 param->fp_lmv_md->lum_magic = LMV_MAGIC_V1;
1672
1673         ret = ioctl(dirfd(d), LL_IOC_LMV_GETSTRIPE, param->fp_lmv_md);
1674         if (errno == E2BIG && ret != 0) {
1675                 int stripe_count;
1676                 int lmv_size;
1677
1678                 stripe_count = (__u32)param->fp_lmv_md->lum_stripe_count;
1679                 if (stripe_count <= param->fp_lmv_stripe_count)
1680                         return ret;
1681
1682                 free(param->fp_lmv_md);
1683                 param->fp_lmv_stripe_count = stripe_count;
1684                 lmv_size = lmv_user_md_size(stripe_count, LMV_MAGIC_V1);
1685                 param->fp_lmv_md = malloc(lmv_size);
1686                 if (param->fp_lmv_md == NULL) {
1687                         llapi_error(LLAPI_MSG_ERROR, -ENOMEM,
1688                                     "error: allocation of %d bytes for ioctl",
1689                                     lmv_user_md_size(param->fp_lmv_stripe_count,
1690                                                      LMV_MAGIC_V1));
1691                         return -ENOMEM;
1692                 }
1693                 goto again;
1694         }
1695         return ret;
1696 }
1697
1698 static int get_lmd_info(char *path, DIR *parent, DIR *dir,
1699                  struct lov_user_mds_data *lmd, int lumlen)
1700 {
1701         lstat_t *st = &lmd->lmd_st;
1702         int ret = 0;
1703
1704         if (parent == NULL && dir == NULL)
1705                 return -EINVAL;
1706
1707         if (dir) {
1708                 ret = ioctl(dirfd(dir), LL_IOC_MDC_GETINFO, (void *)lmd);
1709         } else if (parent) {
1710                 char *fname = strrchr(path, '/');
1711
1712                 /* To avoid opening, locking, and closing each file on the
1713                  * client if that is not needed. The GETFILEINFO ioctl can
1714                  * be done on the patent dir with a single open for all
1715                  * files in that directory, and it also doesn't pollute the
1716                  * client dcache with millions of dentries when traversing
1717                  * a large filesystem.  */
1718                 fname = (fname == NULL ? path : fname + 1);
1719                 /* retrieve needed file info */
1720                 strlcpy((char *)lmd, fname, lumlen);
1721                 ret = ioctl(dirfd(parent), IOC_MDC_GETFILEINFO, (void *)lmd);
1722         }
1723
1724         if (ret) {
1725                 if (errno == ENOTTY) {
1726                         /* ioctl is not supported, it is not a lustre fs.
1727                          * Do the regular lstat(2) instead. */
1728                         ret = lstat_f(path, st);
1729                         if (ret) {
1730                                 ret = -errno;
1731                                 llapi_error(LLAPI_MSG_ERROR, ret,
1732                                             "error: %s: lstat failed for %s",
1733                                             __func__, path);
1734                         }
1735                 } else if (errno == ENOENT) {
1736                         ret = -errno;
1737                         llapi_error(LLAPI_MSG_WARN, ret,
1738                                     "warning: %s: %s does not exist",
1739                                     __func__, path);
1740                 } else if (errno != EISDIR) {
1741                         ret = -errno;
1742                         llapi_error(LLAPI_MSG_ERROR, ret,
1743                                     "%s ioctl failed for %s.",
1744                                     dir ? "LL_IOC_MDC_GETINFO" :
1745                                     "IOC_MDC_GETFILEINFO", path);
1746                 } else {
1747                         ret = -errno;
1748                         llapi_error(LLAPI_MSG_ERROR, ret,
1749                                  "error: %s: IOC_MDC_GETFILEINFO failed for %s",
1750                                    __func__, path);
1751                 }
1752         }
1753         return ret;
1754 }
1755
1756 static int llapi_semantic_traverse(char *path, int size, DIR *parent,
1757                                    semantic_func_t sem_init,
1758                                    semantic_func_t sem_fini, void *data,
1759                                    struct dirent64 *de)
1760 {
1761         struct find_param *param = (struct find_param *)data;
1762         struct dirent64 *dent;
1763         int len, ret;
1764         DIR *d, *p = NULL;
1765
1766         ret = 0;
1767         len = strlen(path);
1768
1769         d = opendir(path);
1770         if (!d && errno != ENOTDIR) {
1771                 ret = -errno;
1772                 llapi_error(LLAPI_MSG_ERROR, ret, "%s: Failed to open '%s'",
1773                             __func__, path);
1774                 return ret;
1775         } else if (!d && !parent) {
1776                 /* ENOTDIR. Open the parent dir. */
1777                 p = opendir_parent(path);
1778                 if (!p) {
1779                         ret = -errno;
1780                         goto out;
1781                 }
1782         }
1783
1784         if (sem_init && (ret = sem_init(path, parent ?: p, &d, data, de)))
1785                 goto err;
1786
1787         if (d == NULL)
1788                 goto out;
1789
1790         while ((dent = readdir64(d)) != NULL) {
1791                 int rc;
1792
1793                 if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1794                         continue;
1795
1796                 /* Don't traverse .lustre directory */
1797                 if (!(strcmp(dent->d_name, dot_lustre_name)))
1798                         continue;
1799
1800                 path[len] = 0;
1801                 if ((len + dent->d_reclen + 2) > size) {
1802                         llapi_err_noerrno(LLAPI_MSG_ERROR,
1803                                           "error: %s: string buffer is too small",
1804                                           __func__);
1805                         break;
1806                 }
1807                 strcat(path, "/");
1808                 strcat(path, dent->d_name);
1809
1810                 if (dent->d_type == DT_UNKNOWN) {
1811                         lstat_t *st = &param->fp_lmd->lmd_st;
1812
1813                         rc = get_lmd_info(path, d, NULL, param->fp_lmd,
1814                                            param->fp_lum_size);
1815                         if (rc == 0)
1816                                 dent->d_type = IFTODT(st->st_mode);
1817                         else if (ret == 0)
1818                                 ret = rc;
1819
1820                         if (rc == -ENOENT)
1821                                 continue;
1822                 }
1823                 switch (dent->d_type) {
1824                 case DT_UNKNOWN:
1825                         llapi_err_noerrno(LLAPI_MSG_ERROR,
1826                                           "error: %s: '%s' is UNKNOWN type %d",
1827                                           __func__, dent->d_name, dent->d_type);
1828                         break;
1829                 case DT_DIR:
1830                         rc = llapi_semantic_traverse(path, size, d, sem_init,
1831                                                       sem_fini, data, dent);
1832                         if (rc != 0 && ret == 0)
1833                                 ret = rc;
1834                         break;
1835                 default:
1836                         rc = 0;
1837                         if (sem_init) {
1838                                 rc = sem_init(path, d, NULL, data, dent);
1839                                 if (rc < 0 && ret == 0)
1840                                         ret = rc;
1841                         }
1842                         if (sem_fini && rc == 0)
1843                                 sem_fini(path, d, NULL, data, dent);
1844                 }
1845         }
1846
1847 out:
1848         path[len] = 0;
1849
1850         if (sem_fini)
1851                 sem_fini(path, parent, &d, data, de);
1852 err:
1853         if (d)
1854                 closedir(d);
1855         if (p)
1856                 closedir(p);
1857         return ret;
1858 }
1859
1860 static int param_callback(char *path, semantic_func_t sem_init,
1861                           semantic_func_t sem_fini, struct find_param *param)
1862 {
1863         int ret, len = strlen(path);
1864         char *buf;
1865
1866         if (len > PATH_MAX) {
1867                 ret = -EINVAL;
1868                 llapi_error(LLAPI_MSG_ERROR, ret,
1869                             "Path name '%s' is too long", path);
1870                 return ret;
1871         }
1872
1873         buf = (char *)malloc(PATH_MAX + 1);
1874         if (!buf)
1875                 return -ENOMEM;
1876
1877         strlcpy(buf, path, PATH_MAX + 1);
1878         ret = common_param_init(param, buf);
1879         if (ret)
1880                 goto out;
1881
1882         param->fp_depth = 0;
1883
1884         ret = llapi_semantic_traverse(buf, PATH_MAX + 1, NULL, sem_init,
1885                                       sem_fini, param, NULL);
1886 out:
1887         find_param_fini(param);
1888         free(buf);
1889         return ret < 0 ? ret : 0;
1890 }
1891
1892 int llapi_file_fget_lov_uuid(int fd, struct obd_uuid *lov_name)
1893 {
1894         int rc = ioctl(fd, OBD_IOC_GETNAME, lov_name);
1895         if (rc) {
1896                 rc = -errno;
1897                 llapi_error(LLAPI_MSG_ERROR, rc, "error: can't get lov name.");
1898         }
1899         return rc;
1900 }
1901
1902 int llapi_file_fget_lmv_uuid(int fd, struct obd_uuid *lov_name)
1903 {
1904         int rc = ioctl(fd, OBD_IOC_GETMDNAME, lov_name);
1905         if (rc) {
1906                 rc = -errno;
1907                 llapi_error(LLAPI_MSG_ERROR, rc, "error: can't get lmv name.");
1908         }
1909         return rc;
1910 }
1911
1912 int llapi_file_get_lov_uuid(const char *path, struct obd_uuid *lov_uuid)
1913 {
1914         int fd, rc;
1915
1916         fd = open(path, O_RDONLY | O_NONBLOCK);
1917         if (fd < 0) {
1918                 rc = -errno;
1919                 llapi_error(LLAPI_MSG_ERROR, rc, "error opening %s", path);
1920                 return rc;
1921         }
1922
1923         rc = llapi_file_fget_lov_uuid(fd, lov_uuid);
1924
1925         close(fd);
1926         return rc;
1927 }
1928
1929 int llapi_file_get_lmv_uuid(const char *path, struct obd_uuid *lov_uuid)
1930 {
1931         int fd, rc;
1932
1933         fd = open(path, O_RDONLY | O_NONBLOCK);
1934         if (fd < 0) {
1935                 rc = -errno;
1936                 llapi_error(LLAPI_MSG_ERROR, rc, "error opening %s", path);
1937                 return rc;
1938         }
1939
1940         rc = llapi_file_fget_lmv_uuid(fd, lov_uuid);
1941
1942         close(fd);
1943         return rc;
1944 }
1945
1946 enum tgt_type {
1947         LOV_TYPE = 1,
1948         LMV_TYPE
1949 };
1950
1951 /*
1952  * If uuidp is NULL, return the number of available obd uuids.
1953  * If uuidp is non-NULL, then it will return the uuids of the obds. If
1954  * there are more OSTs than allocated to uuidp, then an error is returned with
1955  * the ost_count set to number of available obd uuids.
1956  */
1957 static int llapi_get_target_uuids(int fd, struct obd_uuid *uuidp,
1958                                   int *ost_count, enum tgt_type type)
1959 {
1960         char buf[PATH_MAX], format[32];
1961         int rc = 0, index = 0;
1962         struct obd_uuid name;
1963         glob_t param;
1964         FILE *fp;
1965
1966         /* Get the lov name */
1967         if (type == LOV_TYPE)
1968                 rc = llapi_file_fget_lov_uuid(fd, &name);
1969         else
1970                 rc = llapi_file_fget_lmv_uuid(fd, &name);
1971         if (rc != 0)
1972                 return rc;
1973
1974         /* Now get the ost uuids */
1975         rc = get_lustre_param_path(type == LOV_TYPE ? "lov" : "lmv", name.uuid,
1976                                    FILTER_BY_EXACT, "target_obd", &param);
1977         if (rc != 0)
1978                 return -ENOENT;
1979
1980         fp = fopen(param.gl_pathv[0], "r");
1981         if (fp == NULL) {
1982                 rc = -errno;
1983                 llapi_error(LLAPI_MSG_ERROR, rc, "error: opening '%s'",
1984                             param.gl_pathv[0]);
1985                 goto free_param;
1986         }
1987
1988         snprintf(format, sizeof(format),
1989                  "%%d: %%%zus", sizeof(uuidp[0].uuid) - 1);
1990         while (fgets(buf, sizeof(buf), fp) != NULL) {
1991                 if (uuidp && (index < *ost_count)) {
1992                         if (sscanf(buf, format, &index, uuidp[index].uuid) < 2)
1993                                 break;
1994                 }
1995                 index++;
1996         }
1997
1998         fclose(fp);
1999
2000         if (uuidp && (index > *ost_count))
2001                 rc = -EOVERFLOW;
2002
2003         *ost_count = index;
2004 free_param:
2005         cfs_free_param_data(&param);
2006         return rc;
2007 }
2008
2009 int llapi_lov_get_uuids(int fd, struct obd_uuid *uuidp, int *ost_count)
2010 {
2011         return llapi_get_target_uuids(fd, uuidp, ost_count, LOV_TYPE);
2012 }
2013
2014 int llapi_get_obd_count(char *mnt, int *count, int is_mdt)
2015 {
2016         int root;
2017         int rc;
2018
2019         root = open(mnt, O_RDONLY | O_DIRECTORY);
2020         if (root < 0) {
2021                 rc = -errno;
2022                 llapi_error(LLAPI_MSG_ERROR, rc, "open %s failed", mnt);
2023                 return rc;
2024         }
2025
2026         *count = is_mdt;
2027         rc = ioctl(root, LL_IOC_GETOBDCOUNT, count);
2028         if (rc < 0)
2029                 rc = -errno;
2030
2031         close(root);
2032         return rc;
2033 }
2034
2035 /* Check if user specified value matches a real uuid.  Ignore _UUID,
2036  * -osc-4ba41334, other trailing gunk in comparison.
2037  * @param real_uuid ends in "_UUID"
2038  * @param search_uuid may or may not end in "_UUID"
2039  */
2040 int llapi_uuid_match(char *real_uuid, char *search_uuid)
2041 {
2042         int cmplen = strlen(real_uuid);
2043         int searchlen = strlen(search_uuid);
2044
2045         if (cmplen > 5 && strcmp(real_uuid + cmplen - 5, "_UUID") == 0)
2046                 cmplen -= 5;
2047         if (searchlen > 5 && strcmp(search_uuid + searchlen - 5, "_UUID") == 0)
2048                 searchlen -= 5;
2049
2050         /* The UUIDs may legitimately be different lengths, if
2051          * the system was upgraded from an older version. */
2052         if (cmplen != searchlen)
2053                 return 0;
2054
2055         return (strncmp(search_uuid, real_uuid, cmplen) == 0);
2056 }
2057
2058 /* Here, param->fp_obd_uuid points to a single obduuid, the index of which is
2059  * returned in param->fp_obd_index */
2060 static int setup_obd_uuid(int fd, char *dname, struct find_param *param)
2061 {
2062         struct obd_uuid obd_uuid;
2063         char buf[PATH_MAX];
2064         glob_t param_data;
2065         char format[32];
2066         int rc = 0;
2067         FILE *fp;
2068
2069         if (param->fp_got_uuids)
2070                 return rc;
2071
2072         /* Get the lov/lmv name */
2073         if (param->fp_get_lmv)
2074                 rc = llapi_file_fget_lmv_uuid(fd, &obd_uuid);
2075         else
2076                 rc = llapi_file_fget_lov_uuid(fd, &obd_uuid);
2077         if (rc) {
2078                 if (rc != -ENOTTY) {
2079                         llapi_error(LLAPI_MSG_ERROR, rc,
2080                                     "error: can't get %s name: %s",
2081                                     param->fp_get_lmv ? "lmv" : "lov",
2082                                     dname);
2083                 } else {
2084                         rc = 0;
2085                 }
2086                 return rc;
2087         }
2088
2089         param->fp_got_uuids = 1;
2090
2091         /* Now get the ost uuids */
2092         rc = get_lustre_param_path(param->fp_get_lmv ? "lmv" : "lov",
2093                                    obd_uuid.uuid, FILTER_BY_EXACT,
2094                                    "target_obd", &param_data);
2095         if (rc != 0)
2096                 return -ENOENT;
2097
2098         fp = fopen(param_data.gl_pathv[0], "r");
2099         if (fp == NULL) {
2100                 rc = -errno;
2101                 llapi_error(LLAPI_MSG_ERROR, rc, "error: opening '%s'",
2102                             param_data.gl_pathv[0]);
2103                 goto free_param;
2104         }
2105
2106         if (!param->fp_obd_uuid && !param->fp_quiet && !param->fp_obds_printed)
2107                 llapi_printf(LLAPI_MSG_NORMAL, "%s:\n",
2108                              param->fp_get_lmv ? "MDTS" : "OBDS");
2109
2110         snprintf(format, sizeof(format),
2111                  "%%d: %%%zus", sizeof(obd_uuid.uuid) - 1);
2112         while (fgets(buf, sizeof(buf), fp) != NULL) {
2113                 int index;
2114
2115                 if (sscanf(buf, format, &index, obd_uuid.uuid) < 2)
2116                         break;
2117
2118                 if (param->fp_obd_uuid) {
2119                         if (llapi_uuid_match(obd_uuid.uuid,
2120                                              param->fp_obd_uuid->uuid)) {
2121                                 param->fp_obd_index = index;
2122                                 break;
2123                         }
2124                 } else if (!param->fp_quiet && !param->fp_obds_printed) {
2125                         /* Print everything */
2126                         llapi_printf(LLAPI_MSG_NORMAL, "%s", buf);
2127                 }
2128         }
2129         param->fp_obds_printed = 1;
2130
2131         fclose(fp);
2132
2133         if (param->fp_obd_uuid && (param->fp_obd_index == OBD_NOT_FOUND)) {
2134                 llapi_err_noerrno(LLAPI_MSG_ERROR,
2135                                   "error: %s: unknown obduuid: %s",
2136                                   __func__, param->fp_obd_uuid->uuid);
2137                 rc = -EINVAL;
2138         }
2139 free_param:
2140         cfs_free_param_data(&param_data);
2141         return rc;
2142 }
2143
2144 /* In this case, param->fp_obd_uuid will be an array of obduuids and
2145  * obd index for all these obduuids will be returned in
2146  * param->fp_obd_indexes */
2147 static int setup_indexes(DIR *dir, char *path, struct obd_uuid *obduuids,
2148                          int num_obds, int **obdindexes, int *obdindex,
2149                          enum tgt_type type)
2150 {
2151         int ret, obdcount, obd_valid = 0, obdnum;
2152         long i;
2153         struct obd_uuid *uuids = NULL;
2154         char buf[16];
2155         int *indexes;
2156
2157         if (type == LOV_TYPE)
2158                 ret = get_param_lov(path, "numobd", buf, sizeof(buf));
2159         else
2160                 ret = get_param_lmv(path, "numobd", buf, sizeof(buf));
2161         if (ret != 0)
2162                 return ret;
2163
2164         obdcount = atoi(buf);
2165         uuids = malloc(obdcount * sizeof(struct obd_uuid));
2166         if (uuids == NULL)
2167                 return -ENOMEM;
2168
2169 retry_get_uuids:
2170         ret = llapi_get_target_uuids(dirfd(dir), uuids, &obdcount, type);
2171         if (ret) {
2172                 if (ret == -EOVERFLOW) {
2173                         struct obd_uuid *uuids_temp;
2174
2175                         uuids_temp = realloc(uuids, obdcount *
2176                                              sizeof(struct obd_uuid));
2177                         if (uuids_temp != NULL) {
2178                                 uuids = uuids_temp;
2179                                 goto retry_get_uuids;
2180                         }
2181                         ret = -ENOMEM;
2182                 }
2183
2184                 llapi_error(LLAPI_MSG_ERROR, ret, "get ost uuid failed");
2185                 goto out_free;
2186         }
2187
2188         indexes = malloc(num_obds * sizeof(*obdindex));
2189         if (indexes == NULL) {
2190                 ret = -ENOMEM;
2191                 goto out_free;
2192         }
2193
2194         for (obdnum = 0; obdnum < num_obds; obdnum++) {
2195                 char *end = NULL;
2196
2197                 /* The user may have specified a simple index */
2198                 i = strtol(obduuids[obdnum].uuid, &end, 0);
2199                 if (end && *end == '\0' && i < obdcount) {
2200                         indexes[obdnum] = i;
2201                         obd_valid++;
2202                 } else {
2203                         for (i = 0; i < obdcount; i++) {
2204                                 if (llapi_uuid_match(uuids[i].uuid,
2205                                                      obduuids[obdnum].uuid)) {
2206                                         indexes[obdnum] = i;
2207                                         obd_valid++;
2208                                         break;
2209                                 }
2210                         }
2211                 }
2212                 if (i >= obdcount) {
2213                         indexes[obdnum] = OBD_NOT_FOUND;
2214                         llapi_err_noerrno(LLAPI_MSG_ERROR,
2215                                           "error: %s: unknown obduuid: %s",
2216                                           __func__, obduuids[obdnum].uuid);
2217                         ret = -EINVAL;
2218                 }
2219         }
2220
2221         if (obd_valid == 0)
2222                 *obdindex = OBD_NOT_FOUND;
2223         else
2224                 *obdindex = obd_valid;
2225
2226         *obdindexes = indexes;
2227 out_free:
2228         if (uuids)
2229                 free(uuids);
2230
2231         return ret;
2232 }
2233
2234 static int setup_target_indexes(DIR *dir, char *path, struct find_param *param)
2235 {
2236         int ret = 0;
2237
2238         if (param->fp_mdt_uuid) {
2239                 ret = setup_indexes(dir, path, param->fp_mdt_uuid,
2240                                     param->fp_num_mdts,
2241                                     &param->fp_mdt_indexes,
2242                                     &param->fp_mdt_index, LMV_TYPE);
2243                 if (ret)
2244                         return ret;
2245         }
2246
2247         if (param->fp_obd_uuid) {
2248                 ret = setup_indexes(dir, path, param->fp_obd_uuid,
2249                                     param->fp_num_obds,
2250                                     &param->fp_obd_indexes,
2251                                     &param->fp_obd_index, LOV_TYPE);
2252                 if (ret)
2253                         return ret;
2254         }
2255
2256         param->fp_got_uuids = 1;
2257
2258         return ret;
2259 }
2260
2261 int llapi_ostlist(char *path, struct find_param *param)
2262 {
2263         int fd;
2264         int ret;
2265
2266         fd = open(path, O_RDONLY | O_DIRECTORY);
2267         if (fd < 0)
2268                 return -errno;
2269
2270         ret = setup_obd_uuid(fd, path, param);
2271         close(fd);
2272
2273         return ret;
2274 }
2275
2276 /*
2277  * Tries to determine the default stripe attributes for a given filesystem. The
2278  * filesystem to check should be specified by fsname, or will be determined
2279  * using pathname.
2280  */
2281 static int sattr_get_defaults(const char *const fsname,
2282                               unsigned int *scount,
2283                               unsigned int *ssize,
2284                               unsigned int *soffset)
2285 {
2286         char val[PATH_MAX];
2287         int rc;
2288
2289         if (scount) {
2290                 rc = get_lustre_param_value("lov", fsname, FILTER_BY_FS_NAME,
2291                                             "stripecount", val, sizeof(val));
2292                 if (rc != 0)
2293                         return rc;
2294                 *scount = atoi(val);
2295         }
2296
2297         if (ssize) {
2298                 rc = get_lustre_param_value("lov", fsname, FILTER_BY_FS_NAME,
2299                                             "stripesize", val, sizeof(val));
2300                 if (rc != 0)
2301                         return rc;
2302                 *ssize = atoi(val);
2303         }
2304
2305         if (soffset) {
2306                 rc = get_lustre_param_value("lov", fsname, FILTER_BY_FS_NAME,
2307                                             "stripeoffset", val, sizeof(val));
2308                 if (rc != 0)
2309                         return rc;
2310                 *soffset = atoi(val);
2311         }
2312
2313         return 0;
2314 }
2315
2316 /*
2317  * Tries to gather the default stripe attributes for a given filesystem. If
2318  * the attributes can be determined, they are cached for easy retreival the
2319  * next time they are needed. Only a single filesystem's attributes are
2320  * cached at a time.
2321  */
2322 int sattr_cache_get_defaults(const char *const fsname,
2323                              const char *const pathname, unsigned int *scount,
2324                              unsigned int *ssize, unsigned int *soffset)
2325 {
2326         static struct {
2327                 char fsname[PATH_MAX + 1];
2328                 unsigned int stripecount;
2329                 unsigned int stripesize;
2330                 unsigned int stripeoffset;
2331         } cache = {
2332                 .fsname = {'\0'}
2333         };
2334
2335         int rc;
2336         char fsname_buf[PATH_MAX + 1];
2337         unsigned int tmp[3];
2338
2339         if (fsname == NULL) {
2340                 rc = llapi_search_fsname(pathname, fsname_buf);
2341                 if (rc)
2342                         return rc;
2343         } else {
2344                 strlcpy(fsname_buf, fsname, sizeof(fsname_buf));
2345         }
2346
2347         if (strncmp(fsname_buf, cache.fsname, sizeof(fsname_buf) - 1) != 0) {
2348                 /*
2349                  * Ensure all 3 sattrs (count, size, and offset) are
2350                  * successfully retrieved and stored in tmp before writing to
2351                  * cache.
2352                  */
2353                 rc = sattr_get_defaults(fsname_buf, &tmp[0], &tmp[1], &tmp[2]);
2354                 if (rc != 0)
2355                         return rc;
2356
2357                 cache.stripecount = tmp[0];
2358                 cache.stripesize = tmp[1];
2359                 cache.stripeoffset = tmp[2];
2360                 strlcpy(cache.fsname, fsname_buf, sizeof(cache.fsname));
2361         }
2362
2363         if (scount)
2364                 *scount = cache.stripecount;
2365         if (ssize)
2366                 *ssize = cache.stripesize;
2367         if (soffset)
2368                 *soffset = cache.stripeoffset;
2369
2370         return 0;
2371 }
2372
2373 static char *layout2name(__u32 layout_pattern)
2374 {
2375         if (layout_pattern == LOV_PATTERN_MDT)
2376                 return "mdt";
2377         else if (layout_pattern == LOV_PATTERN_RAID0)
2378                 return "raid0";
2379         else if (layout_pattern == (LOV_PATTERN_RAID0 | LOV_PATTERN_F_RELEASED))
2380                 return "released";
2381         else
2382                 return "unknown";
2383 }
2384
2385 enum lov_dump_flags {
2386         LDF_IS_DIR      = 0x0001,
2387         LDF_IS_RAW      = 0x0002,
2388         LDF_INDENT      = 0x0004,
2389         LDF_SKIP_OBJS   = 0x0008,
2390         LDF_YAML        = 0x0010,
2391 };
2392
2393 static void lov_dump_user_lmm_header(struct lov_user_md *lum, char *path,
2394                                      struct lov_user_ost_data_v1 *objects,
2395                                      int verbose, int depth, char *pool_name,
2396                                      enum lov_dump_flags flags)
2397 {
2398         bool is_dir = flags & LDF_IS_DIR;
2399         bool is_raw = flags & LDF_IS_RAW;
2400         bool indent = flags & LDF_INDENT;
2401         bool yaml = flags & LDF_YAML;
2402         bool skip_objs = flags & LDF_SKIP_OBJS;
2403         char *prefix = is_dir ? "" : "lmm_";
2404         char *separator = "";
2405         char *space = indent ? "      " : "";
2406         int rc;
2407
2408         if (is_dir && lmm_oi_seq(&lum->lmm_oi) == FID_SEQ_LOV_DEFAULT) {
2409                 lmm_oi_set_seq(&lum->lmm_oi, 0);
2410                 if (!indent && (verbose & VERBOSE_DETAIL))
2411                         llapi_printf(LLAPI_MSG_NORMAL, "%s(Default) ", space);
2412         }
2413
2414         if (!yaml && !indent && depth && path &&
2415             ((verbose != VERBOSE_OBJID) || !is_dir))
2416                 llapi_printf(LLAPI_MSG_NORMAL, "%s\n", path);
2417
2418         if ((verbose & VERBOSE_DETAIL) && !is_dir) {
2419                 llapi_printf(LLAPI_MSG_NORMAL, "%s%smagic:         0x%08X\n",
2420                              space, prefix, lum->lmm_magic);
2421                 llapi_printf(LLAPI_MSG_NORMAL, "%s%sseq:           %#jx\n",
2422                              space, prefix,
2423                              (uintmax_t)lmm_oi_seq(&lum->lmm_oi));
2424                 llapi_printf(LLAPI_MSG_NORMAL, "%s%sobject_id:     %#jx\n",
2425                              space, prefix,
2426                              (uintmax_t)lmm_oi_id(&lum->lmm_oi));
2427         }
2428         if ((verbose & (VERBOSE_DETAIL | VERBOSE_DFID)) && !is_dir) {
2429                 __u64 seq;
2430                 __u32 oid;
2431                 __u32 ver;
2432
2433                 if (verbose & ~VERBOSE_DFID)
2434                         llapi_printf(LLAPI_MSG_NORMAL, "%slmm_fid:           ",
2435                                      space);
2436                 /* This needs a bit of hand-holding since old 1.x lmm_oi
2437                  * have { oi.oi_id = mds_inum, oi.oi_seq = 0 } and 2.x lmm_oi
2438                  * have { oi.oi_id = mds_oid, oi.oi_seq = mds_seq } instead of
2439                  * a real FID.  Ideally the 2.x code would have stored this
2440                  * like a FID with { oi_id = mds_seq, oi_seq = mds_oid } so the
2441                  * ostid union lu_fid { f_seq = mds_seq, f_oid = mds_oid }
2442                  * worked properly (especially since IGIF FIDs use mds_inum as
2443                  * the FID SEQ), but unfortunately that didn't happen.
2444                  *
2445                  * Print it to look like an IGIF FID, even though the fields
2446                  * are reversed on disk, so that it makes sense to userspace.
2447                  *
2448                  * Don't use ostid_id() and ostid_seq(), since they assume the
2449                  * oi_fid fields are in the right order.  This is why there are
2450                  * separate lmm_oi_seq() and lmm_oi_id() routines for this.
2451                  *
2452                  * For newer layout types hopefully this will be a real FID. */
2453                 seq = lmm_oi_seq(&lum->lmm_oi) == 0 ?
2454                         lmm_oi_id(&lum->lmm_oi) : lmm_oi_seq(&lum->lmm_oi);
2455                 oid = lmm_oi_seq(&lum->lmm_oi) == 0 ?
2456                         0 : (__u32)lmm_oi_id(&lum->lmm_oi);
2457                 ver = (__u32)(lmm_oi_id(&lum->lmm_oi) >> 32);
2458                 if (yaml)
2459                         llapi_printf(LLAPI_MSG_NORMAL, DFID_NOBRACE"\n",
2460                                      seq, oid, ver);
2461                 else
2462                         llapi_printf(LLAPI_MSG_NORMAL, DFID"\n",
2463                                      seq, oid, ver);
2464         }
2465
2466         if (verbose & VERBOSE_COUNT) {
2467                 if (verbose & ~VERBOSE_COUNT)
2468                         llapi_printf(LLAPI_MSG_NORMAL, "%s%sstripe_count:  ",
2469                                      space, prefix);
2470                 if (is_dir) {
2471                         if (!is_raw && lum->lmm_stripe_count == 0 &&
2472                             lov_pattern(lum->lmm_pattern) != LOV_PATTERN_MDT) {
2473                                 unsigned int scount;
2474                                 rc = sattr_cache_get_defaults(NULL, path,
2475                                                               &scount, NULL,
2476                                                               NULL);
2477                                 if (rc == 0)
2478                                         llapi_printf(LLAPI_MSG_NORMAL, "%d",
2479                                                      scount);
2480                                 else
2481                                         llapi_error(LLAPI_MSG_ERROR, rc,
2482                                                     "Cannot determine default"
2483                                                     " stripe count.");
2484                         } else {
2485                                 llapi_printf(LLAPI_MSG_NORMAL, "%d",
2486                                              lum->lmm_stripe_count ==
2487                                              (typeof(lum->lmm_stripe_count))(-1)
2488                                              ? -1 : lum->lmm_stripe_count);
2489                         }
2490                 } else {
2491                         llapi_printf(LLAPI_MSG_NORMAL, "%hd",
2492                                      (__s16)lum->lmm_stripe_count);
2493                 }
2494                 if (!yaml && is_dir)
2495                         separator = " ";
2496                 else
2497                         separator = "\n";
2498         }
2499
2500         if (verbose & VERBOSE_SIZE) {
2501                 llapi_printf(LLAPI_MSG_NORMAL, "%s", separator);
2502                 if (verbose & ~VERBOSE_SIZE)
2503                         llapi_printf(LLAPI_MSG_NORMAL, "%s%sstripe_size:   ",
2504                                      space, prefix);
2505                 if (is_dir && !is_raw && lum->lmm_stripe_size == 0) {
2506                         unsigned int ssize;
2507                         rc = sattr_cache_get_defaults(NULL, path, NULL, &ssize,
2508                                                       NULL);
2509                         if (rc == 0)
2510                                 llapi_printf(LLAPI_MSG_NORMAL, "%u", ssize);
2511                         else
2512                                 llapi_error(LLAPI_MSG_ERROR, rc,
2513                                             "Cannot determine default"
2514                                             " stripe size.");
2515                 } else {
2516                         llapi_printf(LLAPI_MSG_NORMAL, "%u",
2517                                      lum->lmm_stripe_size);
2518                 }
2519                 if (!yaml && is_dir)
2520                         separator = " ";
2521                 else
2522                         separator = "\n";
2523         }
2524
2525         if ((verbose & VERBOSE_LAYOUT)) {
2526                 llapi_printf(LLAPI_MSG_NORMAL, "%s", separator);
2527                 if (verbose & ~VERBOSE_LAYOUT)
2528                         llapi_printf(LLAPI_MSG_NORMAL, "%s%spattern:       ",
2529                                      space, prefix);
2530                 if (lov_pattern_supported(lum->lmm_pattern))
2531                         llapi_printf(LLAPI_MSG_NORMAL, "%s",
2532                                      layout2name(lum->lmm_pattern));
2533                 else
2534                         llapi_printf(LLAPI_MSG_NORMAL, "%.x", lum->lmm_pattern);
2535                 separator = is_dir ? " " : "\n";
2536         }
2537
2538         if ((verbose & VERBOSE_GENERATION) && !is_dir) {
2539                 llapi_printf(LLAPI_MSG_NORMAL, "%s", separator);
2540                 if (verbose & ~VERBOSE_GENERATION)
2541                         llapi_printf(LLAPI_MSG_NORMAL, "%s%slayout_gen:    ",
2542                                      space, prefix);
2543                 llapi_printf(LLAPI_MSG_NORMAL, "%u",
2544                              (int)lum->lmm_layout_gen);
2545                 separator = "\n";
2546         }
2547
2548         if (verbose & VERBOSE_OFFSET) {
2549                 llapi_printf(LLAPI_MSG_NORMAL, "%s", separator);
2550                 if (verbose & ~VERBOSE_OFFSET)
2551                         llapi_printf(LLAPI_MSG_NORMAL, "%s%sstripe_offset: ",
2552                                      space, prefix);
2553                 if (is_dir || skip_objs)
2554                         llapi_printf(LLAPI_MSG_NORMAL, "%d",
2555                                      lum->lmm_stripe_offset ==
2556                                      (typeof(lum->lmm_stripe_offset))(-1) ? -1 :
2557                                      lum->lmm_stripe_offset);
2558                 else
2559                         llapi_printf(LLAPI_MSG_NORMAL, "%u",
2560                                      objects[0].l_ost_idx);
2561                 if (!yaml && is_dir)
2562                         separator = " ";
2563                 else
2564                         separator = "\n";
2565         }
2566
2567         if ((verbose & VERBOSE_POOL) && pool_name && (pool_name[0] != '\0')) {
2568                 llapi_printf(LLAPI_MSG_NORMAL, "%s", separator);
2569                 if (verbose & ~VERBOSE_POOL)
2570                         llapi_printf(LLAPI_MSG_NORMAL, "%s%spool:          ",
2571                                      space, prefix);
2572                 llapi_printf(LLAPI_MSG_NORMAL, "%s", pool_name);
2573                 if (!yaml && is_dir)
2574                         separator = " ";
2575                 else
2576                         separator = "\n";
2577         }
2578
2579         if (strlen(separator) != 0)
2580                 llapi_printf(LLAPI_MSG_NORMAL, "\n");
2581 }
2582
2583 void lov_dump_user_lmm_v1v3(struct lov_user_md *lum, char *pool_name,
2584                             struct lov_user_ost_data_v1 *objects,
2585                             char *path, int obdindex, int depth,
2586                             int header, enum lov_dump_flags flags)
2587 {
2588         bool is_dir = flags & LDF_IS_DIR;
2589         bool indent = flags & LDF_INDENT;
2590         bool skip_objs = flags & LDF_SKIP_OBJS;
2591         bool yaml = flags & LDF_YAML;
2592         int i, obdstripe = (obdindex != OBD_NOT_FOUND) ? 0 : 1;
2593
2594         if (!obdstripe) {
2595                 for (i = 0; !is_dir && i < lum->lmm_stripe_count; i++) {
2596                         if (obdindex == objects[i].l_ost_idx) {
2597                                 obdstripe = 1;
2598                                 break;
2599                         }
2600                 }
2601         }
2602
2603         if (obdstripe == 0)
2604                 return;
2605
2606         lov_dump_user_lmm_header(lum, path, objects, header, depth, pool_name,
2607                                  flags);
2608
2609         if (!is_dir && !skip_objs && (header & VERBOSE_OBJID) &&
2610             !(lum->lmm_pattern & LOV_PATTERN_F_RELEASED)) {
2611                 char *space = "      - ";
2612
2613                 if (indent)
2614                         llapi_printf(LLAPI_MSG_NORMAL,
2615                                      "%6slmm_objects:\n", " ");
2616                 else if (yaml)
2617                         llapi_printf(LLAPI_MSG_NORMAL, "lmm_objects:\n");
2618                 else
2619                         llapi_printf(LLAPI_MSG_NORMAL,
2620                                 "\tobdidx\t\t objid\t\t objid\t\t group\n");
2621
2622                 for (i = 0; i < lum->lmm_stripe_count; i++) {
2623                         int idx = objects[i].l_ost_idx;
2624                         long long oid = ostid_id(&objects[i].l_ost_oi);
2625                         long long gr = ostid_seq(&objects[i].l_ost_oi);
2626
2627                         if (obdindex != OBD_NOT_FOUND && obdindex != idx)
2628                                 continue;
2629
2630                         if (yaml) {
2631                                 struct lu_fid fid = { 0 };
2632
2633                                 ostid_to_fid(&fid, &objects[i].l_ost_oi, idx);
2634                                 llapi_printf(LLAPI_MSG_NORMAL,
2635                                     "%sl_ost_idx: %d\n", space, idx);
2636                                 llapi_printf(LLAPI_MSG_NORMAL,
2637                                     "%8sl_fid:     "DFID_NOBRACE"\n",
2638                                     " ", PFID(&fid));
2639                         } else if (indent) {
2640                                 struct lu_fid fid = { 0 };
2641
2642                                 ostid_to_fid(&fid, &objects[i].l_ost_oi, idx);
2643                                 llapi_printf(LLAPI_MSG_NORMAL,
2644                                     "%s%d: { l_ost_idx: %d, l_fid: "DFID" }\n",
2645                                     space, i, idx, PFID(&fid));
2646                         } else {
2647                                 char fmt[48];
2648                                 sprintf(fmt, "%s%s%s\n",
2649                                         "\t%6u\t%14llu\t%#13llx\t",
2650                                         (fid_seq_is_rsvd(gr) ||
2651                                          fid_seq_is_mdt0(gr)) ?
2652                                          "%14llu" : "%#14llx", "%s");
2653                                 llapi_printf(LLAPI_MSG_NORMAL, fmt, idx, oid,
2654                                              oid, gr,
2655                                              obdindex == idx ? " *" : "");
2656                         }
2657                 }
2658         }
2659         llapi_printf(LLAPI_MSG_NORMAL, "\n");
2660 }
2661
2662 void lmv_dump_user_lmm(struct lmv_user_md *lum, char *pool_name,
2663                        char *path, int obdindex, int depth, int verbose,
2664                        enum lov_dump_flags flags)
2665 {
2666         struct lmv_user_mds_data *objects = lum->lum_objects;
2667         char *prefix = lum->lum_magic == LMV_USER_MAGIC ? "(Default)" : "";
2668         int i, obdstripe = 0;
2669         char *separator = "";
2670         bool yaml = flags & LDF_YAML;
2671
2672         if (obdindex != OBD_NOT_FOUND) {
2673                 if (lum->lum_stripe_count == 0) {
2674                         if (obdindex == lum->lum_stripe_offset)
2675                                 obdstripe = 1;
2676                 } else {
2677                         for (i = 0; i < lum->lum_stripe_count; i++) {
2678                                 if (obdindex == objects[i].lum_mds) {
2679                                         llapi_printf(LLAPI_MSG_NORMAL,
2680                                                      "%s%s\n", prefix,
2681                                                      path);
2682                                         obdstripe = 1;
2683                                         break;
2684                                 }
2685                         }
2686                 }
2687         } else {
2688                 obdstripe = 1;
2689         }
2690
2691         if (!obdstripe)
2692                 return;
2693
2694         /* show all information default */
2695         if (!verbose) {
2696                 if (lum->lum_magic == LMV_USER_MAGIC)
2697                         verbose = VERBOSE_POOL | VERBOSE_COUNT |
2698                                   VERBOSE_OFFSET | VERBOSE_HASH_TYPE;
2699                 else
2700                         verbose = VERBOSE_OBJID;
2701         }
2702
2703         if (depth && path && ((verbose != VERBOSE_OBJID)))
2704                 llapi_printf(LLAPI_MSG_NORMAL, "%s%s\n", prefix, path);
2705
2706         if (verbose & VERBOSE_COUNT) {
2707                 llapi_printf(LLAPI_MSG_NORMAL, "%s", separator);
2708                 if (verbose & ~VERBOSE_COUNT)
2709                         llapi_printf(LLAPI_MSG_NORMAL, "lmv_stripe_count: ");
2710                 llapi_printf(LLAPI_MSG_NORMAL, "%u",
2711                              (int)lum->lum_stripe_count);
2712                 if ((verbose & VERBOSE_OFFSET) && !yaml)
2713                         separator = " ";
2714                 else
2715                         separator = "\n";
2716         }
2717
2718         if (verbose & VERBOSE_OFFSET) {
2719                 llapi_printf(LLAPI_MSG_NORMAL, "%s", separator);
2720                 if (verbose & ~VERBOSE_OFFSET)
2721                         llapi_printf(LLAPI_MSG_NORMAL, "lmv_stripe_offset: ");
2722                 llapi_printf(LLAPI_MSG_NORMAL, "%d",
2723                              (int)lum->lum_stripe_offset);
2724                 if (verbose & VERBOSE_HASH_TYPE && !yaml)
2725                         separator = " ";
2726                 else
2727                         separator = "\n";
2728         }
2729
2730         if (verbose & VERBOSE_HASH_TYPE) {
2731                 unsigned int type = lum->lum_hash_type;
2732
2733                 llapi_printf(LLAPI_MSG_NORMAL, "%s", separator);
2734                 if (verbose & ~VERBOSE_HASH_TYPE)
2735                         llapi_printf(LLAPI_MSG_NORMAL, "lmv_hash_type: ");
2736                 if (type < LMV_HASH_TYPE_MAX)
2737                         llapi_printf(LLAPI_MSG_NORMAL, "%s",
2738                                      mdt_hash_name[type]);
2739                 else
2740                         llapi_printf(LLAPI_MSG_NORMAL, "%d",
2741                                      (int)type);
2742                 separator = "\n";
2743         }
2744
2745         if (verbose & VERBOSE_OBJID && lum->lum_magic != LMV_USER_MAGIC) {
2746                 llapi_printf(LLAPI_MSG_NORMAL, "%s", separator);
2747                 if (obdstripe == 1 && lum->lum_stripe_count > 0)
2748                         llapi_printf(LLAPI_MSG_NORMAL,
2749                                      "mdtidx\t\t FID[seq:oid:ver]\n");
2750                 for (i = 0; i < lum->lum_stripe_count; i++) {
2751                         int idx = objects[i].lum_mds;
2752                         struct lu_fid *fid = &objects[i].lum_fid;
2753                         if ((obdindex == OBD_NOT_FOUND) || (obdindex == idx))
2754                                 llapi_printf(LLAPI_MSG_NORMAL,
2755                                              "%6u\t\t "DFID"\t\t%s\n",
2756                                             idx, PFID(fid),
2757                                             obdindex == idx ? " *" : "");
2758                 }
2759
2760         }
2761
2762         if ((verbose & VERBOSE_POOL) && pool_name != NULL &&
2763              pool_name[0] != '\0') {
2764                 llapi_printf(LLAPI_MSG_NORMAL, "%s", separator);
2765                 if (verbose & ~VERBOSE_POOL)
2766                         llapi_printf(LLAPI_MSG_NORMAL, "%slmv_pool:           ",
2767                                      prefix);
2768                 llapi_printf(LLAPI_MSG_NORMAL, "%s%c ", pool_name, ' ');
2769                 separator = "\n";
2770         }
2771
2772         if (!(verbose & VERBOSE_OBJID) || lum->lum_magic == LMV_USER_MAGIC)
2773                 llapi_printf(LLAPI_MSG_NORMAL, "\n");
2774 }
2775
2776 static void lov_dump_comp_v1_header(struct find_param *param, char *path,
2777                                     enum lov_dump_flags flags)
2778 {
2779         struct lov_comp_md_v1 *comp_v1 = (void *)&param->fp_lmd->lmd_lmm;
2780         int depth = param->fp_max_depth;
2781         int verbose = param->fp_verbose;
2782         bool yaml = flags & LDF_YAML;
2783
2784         if (depth && path && ((verbose != VERBOSE_OBJID) ||
2785                               !(flags & LDF_IS_DIR)) && !yaml)
2786                 llapi_printf(LLAPI_MSG_NORMAL, "%s\n", path);
2787
2788         if (verbose & VERBOSE_DETAIL) {
2789                 llapi_printf(LLAPI_MSG_NORMAL, "composite_header:\n");
2790                 llapi_printf(LLAPI_MSG_NORMAL, "%2slcm_magic:         0x%08X\n",
2791                              " ", comp_v1->lcm_magic);
2792                 llapi_printf(LLAPI_MSG_NORMAL, "%2slcm_size:          %u\n",
2793                              " ", comp_v1->lcm_size);
2794                 if (flags & LDF_IS_DIR)
2795                         llapi_printf(LLAPI_MSG_NORMAL,
2796                                      "%2slcm_flags:         %s\n", " ",
2797                                      comp_v1->lcm_mirror_count > 0 ?
2798                                                         "mirrored" : "");
2799                 else
2800                         llapi_printf(LLAPI_MSG_NORMAL,
2801                                      "%2slcm_flags:         %s\n",
2802                                      " ", lcm_flags_string(comp_v1->lcm_flags));
2803         }
2804
2805         if (verbose & VERBOSE_GENERATION) {
2806                 if (verbose & ~VERBOSE_GENERATION)
2807                         llapi_printf(LLAPI_MSG_NORMAL, "%2slcm_layout_gen:    ",
2808                                      " ");
2809                 llapi_printf(LLAPI_MSG_NORMAL, "%u\n", comp_v1->lcm_layout_gen);
2810         }
2811
2812         if (verbose & VERBOSE_MIRROR_COUNT) {
2813                 if (verbose & ~VERBOSE_MIRROR_COUNT)
2814                         llapi_printf(LLAPI_MSG_NORMAL, "%2slcm_mirror_count:  ",
2815                                      " ");
2816                 llapi_printf(LLAPI_MSG_NORMAL, "%u\n",
2817                              comp_v1->lcm_magic == LOV_USER_MAGIC_COMP_V1 ?
2818                              comp_v1->lcm_mirror_count + 1 : 1);
2819         }
2820
2821         if (verbose & VERBOSE_COMP_COUNT) {
2822                 if (verbose & ~VERBOSE_COMP_COUNT)
2823                         llapi_printf(LLAPI_MSG_NORMAL, "%2slcm_entry_count:   ",
2824                                      " ");
2825                 llapi_printf(LLAPI_MSG_NORMAL, "%u\n",
2826                              comp_v1->lcm_magic == LOV_USER_MAGIC_COMP_V1 ?
2827                              comp_v1->lcm_entry_count : 0);
2828         }
2829
2830         if (verbose & VERBOSE_DETAIL && !yaml)
2831                 llapi_printf(LLAPI_MSG_NORMAL, "components:\n");
2832 }
2833
2834 static void lcme_flags2str(__u32 comp_flags)
2835 {
2836         bool found = false;
2837         int i = 0;
2838
2839         if (!comp_flags) {
2840                 llapi_printf(LLAPI_MSG_NORMAL, "0");
2841                 return;
2842         }
2843         for (i = 0; i < ARRAY_SIZE(comp_flags_table); i++) {
2844                 if (comp_flags & comp_flags_table[i].cfn_flag) {
2845                         if (found)
2846                                 llapi_printf(LLAPI_MSG_NORMAL, ",");
2847                         llapi_printf(LLAPI_MSG_NORMAL, "%s",
2848                                      comp_flags_table[i].cfn_name);
2849                         comp_flags &= ~comp_flags_table[i].cfn_flag;
2850                         found = true;
2851                 }
2852         }
2853         if (comp_flags) {
2854                 if (found)
2855                         llapi_printf(LLAPI_MSG_NORMAL, ",");
2856                 llapi_printf(LLAPI_MSG_NORMAL, "%#x", comp_flags);
2857         }
2858 }
2859
2860 static void lov_dump_comp_v1_entry(struct find_param *param,
2861                                    enum lov_dump_flags flags, int index)
2862 {
2863         struct lov_comp_md_v1 *comp_v1 = (void *)&param->fp_lmd->lmd_lmm;
2864         struct lov_comp_md_entry_v1 *entry;
2865         char *separator = "";
2866         int verbose = param->fp_verbose;
2867         bool yaml = flags & LDF_YAML;
2868
2869         entry = &comp_v1->lcm_entries[index];
2870
2871         if (yaml)
2872                 llapi_printf(LLAPI_MSG_NORMAL, "%2scomponent%d:\n", " ", index);
2873
2874         if (verbose & VERBOSE_COMP_ID) {
2875                 if (verbose & VERBOSE_DETAIL && !yaml)
2876                         llapi_printf(LLAPI_MSG_NORMAL,
2877                                      "%slcme_id:             ", "  - ");
2878                 else if (verbose & ~VERBOSE_COMP_ID)
2879                         llapi_printf(LLAPI_MSG_NORMAL,
2880                                      "%4slcme_id:             ", " ");
2881                 if (entry->lcme_id != LCME_ID_INVAL)
2882                         llapi_printf(LLAPI_MSG_NORMAL, "%u", entry->lcme_id);
2883                 else
2884                         llapi_printf(LLAPI_MSG_NORMAL, "N/A");
2885                 separator = "\n";
2886         }
2887
2888         if (verbose & VERBOSE_COMP_FLAGS) {
2889                 llapi_printf(LLAPI_MSG_NORMAL, "%s", separator);
2890                 if (verbose & ~VERBOSE_COMP_FLAGS)
2891                         llapi_printf(LLAPI_MSG_NORMAL,
2892                                      "%4slcme_flags:          ", " ");
2893                 lcme_flags2str(entry->lcme_flags);
2894                 separator = "\n";
2895         }
2896
2897         if (verbose & VERBOSE_COMP_START) {
2898                 llapi_printf(LLAPI_MSG_NORMAL, "%s", separator);
2899                 if (verbose & ~VERBOSE_COMP_START)
2900                         llapi_printf(LLAPI_MSG_NORMAL,
2901                                      "%4slcme_extent.e_start: ", " ");
2902                 llapi_printf(LLAPI_MSG_NORMAL, "%llu",
2903                              entry->lcme_extent.e_start);
2904                 separator = "\n";
2905         }
2906
2907         if (verbose & VERBOSE_COMP_END) {
2908                 llapi_printf(LLAPI_MSG_NORMAL, "%s", separator);
2909                 if (verbose & ~VERBOSE_COMP_END)
2910                         llapi_printf(LLAPI_MSG_NORMAL,
2911                                      "%4slcme_extent.e_end:   ", " ");
2912                 if (entry->lcme_extent.e_end == LUSTRE_EOF)
2913                         llapi_printf(LLAPI_MSG_NORMAL, "%s", "EOF");
2914                 else
2915                         llapi_printf(LLAPI_MSG_NORMAL, "%llu",
2916                                         entry->lcme_extent.e_end);
2917                 separator = "\n";
2918         }
2919
2920         if (yaml) {
2921                 llapi_printf(LLAPI_MSG_NORMAL, "%s", separator);
2922                 llapi_printf(LLAPI_MSG_NORMAL, "%4ssub_layout:\n", " ");
2923         } else if (verbose & VERBOSE_DETAIL) {
2924                 llapi_printf(LLAPI_MSG_NORMAL, "%s", separator);
2925                 llapi_printf(LLAPI_MSG_NORMAL, "%4slcme_offset:         %u\n",
2926                              " ", entry->lcme_offset);
2927                 llapi_printf(LLAPI_MSG_NORMAL, "%4slcme_size:           %u\n",
2928                              " ", entry->lcme_size);
2929                 llapi_printf(LLAPI_MSG_NORMAL, "%4ssub_layout:\n", " ");
2930         } else {
2931                 llapi_printf(LLAPI_MSG_NORMAL, "%s", separator);
2932         }
2933 }
2934
2935 /* Check if the value matches 1 of the given criteria (e.g. --atime +/-N).
2936  * @mds indicates if this is MDS timestamps and there are attributes on OSTs.
2937  *
2938  * The result is -1 if it does not match, 0 if not yet clear, 1 if matches.
2939  * The table below gives the answers for the specified parameters (value and
2940  * sign), 1st column is the answer for the MDS value, the 2nd is for the OST:
2941  * --------------------------------------
2942  * 1 | file > limit; sign > 0 | -1 / -1 |
2943  * 2 | file = limit; sign > 0 | -1 / -1 |
2944  * 3 | file < limit; sign > 0 |  ? /  1 |
2945  * 4 | file > limit; sign = 0 | -1 / -1 |
2946  * 5 | file = limit; sign = 0 |  ? /  1 |  <- (see the Note below)
2947  * 6 | file < limit; sign = 0 |  ? / -1 |
2948  * 7 | file > limit; sign < 0 |  1 /  1 |
2949  * 8 | file = limit; sign < 0 |  ? / -1 |
2950  * 9 | file < limit; sign < 0 |  ? / -1 |
2951  * --------------------------------------
2952  * Note: 5th actually means that the value is within the interval
2953  * (limit - margin, limit]. */
2954 static int find_value_cmp(unsigned long long file, unsigned long long limit,
2955                           int sign, int negopt, unsigned long long margin,
2956                           int mds)
2957 {
2958         int ret = -1;
2959
2960         if (sign > 0) {
2961                 /* Drop the fraction of margin (of days). */
2962                 if (file + margin <= limit)
2963                         ret = mds ? 0 : 1;
2964         } else if (sign == 0) {
2965                 if (file <= limit && file + margin > limit)
2966                         ret = mds ? 0 : 1;
2967                 else if (file + margin <= limit)
2968                         ret = mds ? 0 : -1;
2969         } else if (sign < 0) {
2970                 if (file > limit)
2971                         ret = 1;
2972                 else if (mds)
2973                         ret = 0;
2974         }
2975
2976         return negopt ? ~ret + 1 : ret;
2977 }
2978
2979 static inline struct lov_user_md *
2980 lov_comp_entry(struct lov_comp_md_v1 *comp_v1, int ent_idx)
2981 {
2982         return (struct lov_user_md *)((char *)comp_v1 +
2983                         comp_v1->lcm_entries[ent_idx].lcme_offset);
2984 }
2985
2986 static inline struct lov_user_ost_data_v1 *
2987 lov_v1v3_objects(struct lov_user_md *v1)
2988 {
2989         if (v1->lmm_magic == LOV_USER_MAGIC_V3)
2990                 return ((struct lov_user_md_v3 *)v1)->lmm_objects;
2991         else
2992                 return v1->lmm_objects;
2993 }
2994
2995 static inline void
2996 lov_v1v3_pool_name(struct lov_user_md *v1, char *pool_name)
2997 {
2998         if (v1->lmm_magic == LOV_USER_MAGIC_V3)
2999                 strlcpy(pool_name, ((struct lov_user_md_v3 *)v1)->lmm_pool_name,
3000                         LOV_MAXPOOLNAME);
3001         else
3002                 pool_name[0] = '\0';
3003 }
3004
3005 static inline bool
3006 print_last_init_comp(struct find_param *param)
3007 {
3008         /* print all component info */
3009         if ((param->fp_verbose & VERBOSE_DEFAULT) == VERBOSE_DEFAULT)
3010                 return false;
3011
3012         /* print specific component info */
3013         if (param->fp_check_comp_id || param->fp_check_comp_flags ||
3014             param->fp_check_comp_start || param->fp_check_comp_end)
3015                 return false;
3016
3017         return true;
3018 }
3019
3020 static int find_comp_end_cmp(unsigned long long end, struct find_param *param)
3021 {
3022         int match;
3023
3024         if (param->fp_comp_end == LUSTRE_EOF) {
3025                 if (param->fp_comp_end_sign == 0) /* equal to EOF */
3026                         match = end == LUSTRE_EOF ? 1 : -1;
3027                 else if (param->fp_comp_end_sign > 0) /* at most EOF */
3028                         match = end == LUSTRE_EOF ? -1 : 1;
3029                 else /* at least EOF */
3030                         match = -1;
3031                 if (param->fp_exclude_comp_end)
3032                         match = ~match + 1;
3033         } else {
3034                 unsigned long long margin;
3035
3036                 margin = end == LUSTRE_EOF ? 0 : param->fp_comp_end_units;
3037                 match = find_value_cmp(end, param->fp_comp_end,
3038                                        param->fp_comp_end_sign,
3039                                        param->fp_exclude_comp_end, margin, 0);
3040         }
3041
3042         return match;
3043 }
3044
3045 /**
3046  * An example of "getstripe -v" for a two components PFL file:
3047  *
3048  * composite_header:
3049  * lcm_magic:       0x0BD60BD0
3050  * lcm_size:        264
3051  * lcm_flags:       0
3052  * lcm_layout_gen:  2
3053  * lcm_entry_count: 2
3054  * components:
3055  * - lcme_id:             1
3056  *   lcme_flags:          0x10
3057  *   lcme_extent.e_start: 0
3058  *   lcme_extent.e_end:   1048576
3059  *   lcme_offset:         128
3060  *   lcme_size:           56
3061  *   sub_layout:
3062  *     lmm_magic:         0x0BD10BD0
3063  *     lmm_seq:           0x200000401
3064  *     lmm_object_id:     0x1
3065  *     lmm_fid:           [0x200000401:0x1:0x0]
3066  *     lmm_stripe_count:  1
3067  *     lmm_stripe_size:   1048576
3068  *     lmm_pattern:       raid0
3069  *     lmm_layout_gen:    0
3070  *     lmm_stripe_offset: 0
3071  *     lmm_objects:
3072  *     - 0: { l_ost_idx: 0, l_fid: [0x100000000:0x2:0x0] }
3073  *
3074  * - lcme_id:             2
3075  *   lcme_flags:          0x10
3076  *   lcme_extent.e_start: 1048576
3077  *   lcme_extent.e_end:   EOF
3078  *   lcme_offset:         184
3079  *   lcme_size:           80
3080  *     sub_layout:
3081  *     lmm_magic:         0x0BD10BD0
3082  *     lmm_seq:           0x200000401
3083  *     lmm_object_id:     0x1
3084  *     lmm_fid:           [0x200000401:0x1:0x0]
3085  *     lmm_stripe_count:  2
3086  *     lmm_stripe_size:   1048576
3087  *     lmm_pattern:       raid0
3088  *     lmm_layout_gen:    0
3089  *     lmm_stripe_offset: 1
3090  *     lmm_objects:
3091  *     - 0: { l_ost_idx: 1, l_fid: [0x100010000:0x2:0x0] }
3092  *     - 1: { l_ost_idx: 0, l_fid: [0x100000000:0x3:0x0] }
3093  */
3094 static void lov_dump_comp_v1(struct find_param *param, char *path,
3095                              enum lov_dump_flags flags)
3096 {
3097         struct lov_comp_md_entry_v1 *entry;
3098         struct lov_user_ost_data_v1 *objects;
3099         struct lov_comp_md_v1 *comp_v1 = (void *)&param->fp_lmd->lmd_lmm;
3100         struct lov_user_md_v1 *v1;
3101         char pool_name[LOV_MAXPOOLNAME + 1];
3102         int obdindex = param->fp_obd_index;
3103         int i, j, match, obdstripe = 0;
3104
3105         if (obdindex != OBD_NOT_FOUND) {
3106                 for (i = 0; !(flags & LDF_IS_DIR) &&
3107                             i < comp_v1->lcm_entry_count; i++) {
3108                         if (!(comp_v1->lcm_entries[i].lcme_flags &
3109                               LCME_FL_INIT))
3110                                 continue;
3111
3112                         v1 = lov_comp_entry(comp_v1, i);
3113                         objects = lov_v1v3_objects(v1);
3114
3115                         for (j = 0; j < v1->lmm_stripe_count; j++) {
3116                                 if (obdindex == objects[j].l_ost_idx) {
3117                                         obdstripe = 1;
3118                                         break;
3119                                 }
3120                         }
3121                 }
3122         } else {
3123                 obdstripe = 1;
3124         }
3125
3126         if (obdstripe == 0)
3127                 return;
3128
3129         lov_dump_comp_v1_header(param, path, flags);
3130
3131         flags |= LDF_INDENT;
3132
3133         for (i = 0; i < comp_v1->lcm_entry_count; i++) {
3134                 entry = &comp_v1->lcm_entries[i];
3135
3136                 if (param->fp_check_comp_flags) {
3137                         if ((param->fp_exclude_comp_flags &&
3138                              (param->fp_comp_flags & entry->lcme_flags)) ||
3139                             (!param->fp_exclude_comp_flags &&
3140                              !(param->fp_comp_flags & entry->lcme_flags)))
3141                                 continue;
3142                 }
3143
3144                 if (param->fp_check_comp_id &&
3145                     param->fp_comp_id != entry->lcme_id)
3146                         continue;
3147
3148                 if (param->fp_check_comp_start) {
3149                         match = find_value_cmp(entry->lcme_extent.e_start,
3150                                                param->fp_comp_start,
3151                                                param->fp_comp_start_sign,
3152                                                0,
3153                                                param->fp_comp_start_units, 0);
3154                         if (match == -1)
3155                                 continue;
3156                 }
3157
3158                 if (param->fp_check_comp_end) {
3159                         match = find_comp_end_cmp(entry->lcme_extent.e_end,
3160                                                   param);
3161                         if (match == -1)
3162                                 continue;
3163                 }
3164
3165                 if (print_last_init_comp(param)) {
3166                         /**
3167                          * if part of stripe info is needed, we'd print only
3168                          * the last instantiated component info.
3169                          */
3170                         if (entry->lcme_flags & LCME_FL_INIT)
3171                                 continue;
3172                         else
3173                                 break;
3174                 }
3175
3176                 if (entry->lcme_flags & LCME_FL_INIT)
3177                         flags &= ~LDF_SKIP_OBJS;
3178                 else
3179                         flags |= LDF_SKIP_OBJS;
3180
3181                 lov_dump_comp_v1_entry(param, flags, i);
3182
3183                 v1 = lov_comp_entry(comp_v1, i);
3184                 objects = lov_v1v3_objects(v1);
3185                 lov_v1v3_pool_name(v1, pool_name);
3186
3187                 lov_dump_user_lmm_v1v3(v1, pool_name, objects, path, obdindex,
3188                                        param->fp_max_depth, param->fp_verbose,
3189                                        flags);
3190         }
3191         if (print_last_init_comp(param)) {
3192                 /**
3193                  * directory layout contains only layout template, print the
3194                  * last component.
3195                  */
3196                 if (i == 0)
3197                         i = comp_v1->lcm_entry_count - 1;
3198                 else
3199                         i--;
3200                 flags &= ~LDF_SKIP_OBJS;
3201
3202                 lov_dump_comp_v1_entry(param, flags, i);
3203
3204                 v1 = lov_comp_entry(comp_v1, i);
3205                 objects = lov_v1v3_objects(v1);
3206                 lov_v1v3_pool_name(v1, pool_name);
3207
3208                 lov_dump_user_lmm_v1v3(v1, pool_name, objects, path, obdindex,
3209                                        param->fp_max_depth, param->fp_verbose,
3210                                        flags);
3211         }
3212 }
3213
3214 #define VERBOSE_COMP_OPTS       (VERBOSE_COMP_COUNT | VERBOSE_COMP_ID | \
3215                                  VERBOSE_COMP_START | VERBOSE_COMP_END | \
3216                                  VERBOSE_COMP_FLAGS)
3217
3218 static inline bool has_any_comp_options(struct find_param *param)
3219 {
3220         int verbose = param->fp_verbose;
3221
3222         if (param->fp_check_comp_id || param->fp_check_comp_count ||
3223             param->fp_check_comp_start || param->fp_check_comp_end ||
3224             param->fp_check_comp_flags)
3225                 return true;
3226
3227         /* show full layout information, not component specific */
3228         if ((verbose & ~VERBOSE_DETAIL) == VERBOSE_DEFAULT)
3229                 return false;
3230
3231         return verbose & VERBOSE_COMP_OPTS;
3232 }
3233
3234 struct lov_user_mds_data *lov_forge_comp_v1(struct lov_user_mds_data *orig,
3235                                             bool is_dir)
3236 {
3237         struct lov_user_md *lum = &orig->lmd_lmm;
3238         struct lov_user_mds_data *new;
3239         struct lov_comp_md_v1 *comp_v1;
3240         struct lov_comp_md_entry_v1 *ent;
3241         int lum_off = sizeof(*comp_v1) + sizeof(*ent);
3242         int lum_size = lov_user_md_size(is_dir ? 0 : lum->lmm_stripe_count,
3243                                         lum->lmm_magic);
3244
3245         new = malloc(sizeof(lstat_t) + lum_off + lum_size);
3246         if (new == NULL) {
3247                 llapi_printf(LLAPI_MSG_NORMAL, "out of memory\n");
3248                 return new;
3249         }
3250
3251         memcpy(new, orig, sizeof(lstat_t));
3252
3253         comp_v1 = (struct lov_comp_md_v1 *)&new->lmd_lmm;
3254         comp_v1->lcm_magic = lum->lmm_magic;
3255         comp_v1->lcm_size = lum_off + lum_size;
3256         comp_v1->lcm_layout_gen = is_dir ? 0 : lum->lmm_layout_gen;
3257         comp_v1->lcm_flags = 0;
3258         comp_v1->lcm_entry_count = 1;
3259
3260         ent = &comp_v1->lcm_entries[0];
3261         ent->lcme_id = 0;
3262         ent->lcme_flags = is_dir ? 0 : LCME_FL_INIT;
3263         ent->lcme_extent.e_start = 0;
3264         ent->lcme_extent.e_end = LUSTRE_EOF;
3265         ent->lcme_offset = lum_off;
3266         ent->lcme_size = lum_size;
3267
3268         memcpy((char *)comp_v1 + lum_off, lum, lum_size);
3269
3270         return new;
3271 }
3272
3273 static void lov_dump_plain_user_lmm(struct find_param *param, char *path,
3274                                     enum lov_dump_flags flags)
3275 {
3276         __u32 magic = *(__u32 *)&param->fp_lmd->lmd_lmm;
3277
3278         if (has_any_comp_options(param)) {
3279                 struct lov_user_mds_data *new_lmd, *orig_lmd;
3280
3281                 orig_lmd = param->fp_lmd;
3282                 new_lmd = lov_forge_comp_v1(orig_lmd, flags & LDF_IS_DIR);
3283                 if (new_lmd != NULL) {
3284                         param->fp_lmd = new_lmd;
3285                         lov_dump_comp_v1(param, path, flags);
3286                         param->fp_lmd = orig_lmd;
3287                         free(new_lmd);
3288                 }
3289                 return;
3290         }
3291
3292         if (magic == LOV_USER_MAGIC_V1) {
3293                 lov_dump_user_lmm_v1v3(&param->fp_lmd->lmd_lmm, NULL,
3294                                        param->fp_lmd->lmd_lmm.lmm_objects,
3295                                        path, param->fp_obd_index,
3296                                        param->fp_max_depth, param->fp_verbose,
3297                                        flags);
3298         } else {
3299                 char pool_name[LOV_MAXPOOLNAME + 1];
3300                 struct lov_user_ost_data_v1 *objects;
3301                 struct lov_user_md_v3 *lmmv3 = (void *)&param->fp_lmd->lmd_lmm;
3302
3303                 strlcpy(pool_name, lmmv3->lmm_pool_name, sizeof(pool_name));
3304                 objects = lmmv3->lmm_objects;
3305                 lov_dump_user_lmm_v1v3(&param->fp_lmd->lmd_lmm, pool_name,
3306                                        objects, path, param->fp_obd_index,
3307                                        param->fp_max_depth, param->fp_verbose,
3308                                        flags);
3309         }
3310 }
3311
3312 static void llapi_lov_dump_user_lmm(struct find_param *param, char *path,
3313                                     enum lov_dump_flags flags)
3314 {
3315         __u32 magic;
3316
3317         if (param->fp_get_lmv || param->fp_get_default_lmv)
3318                 magic = (__u32)param->fp_lmv_md->lum_magic;
3319         else
3320                 magic = *(__u32 *)&param->fp_lmd->lmd_lmm; /* lum->lmm_magic */
3321
3322         if (param->fp_raw)
3323                 flags |= LDF_IS_RAW;
3324         if (param->fp_yaml)
3325                 flags |= LDF_YAML;
3326
3327         switch (magic) {
3328         case LOV_USER_MAGIC_V1:
3329         case LOV_USER_MAGIC_V3:
3330                 lov_dump_plain_user_lmm(param, path, flags);
3331                 break;
3332         case LMV_MAGIC_V1:
3333         case LMV_USER_MAGIC: {
3334                 char pool_name[LOV_MAXPOOLNAME + 1];
3335                 struct lmv_user_md *lum;
3336
3337                 lum = (struct lmv_user_md *)param->fp_lmv_md;
3338                 strlcpy(pool_name, lum->lum_pool_name, sizeof(pool_name));
3339                 lmv_dump_user_lmm(lum, pool_name, path, param->fp_obd_index,
3340                                   param->fp_max_depth, param->fp_verbose,
3341                                   flags);
3342                 break;
3343         }
3344         case LOV_USER_MAGIC_COMP_V1:
3345                 lov_dump_comp_v1(param, path, flags);
3346                 break;
3347         default:
3348                 llapi_printf(LLAPI_MSG_NORMAL, "unknown lmm_magic:  %#x "
3349                              "(expecting one of %#x %#x %#x %#x)\n",
3350                              *(__u32 *)&param->fp_lmd->lmd_lmm,
3351                              LOV_USER_MAGIC_V1, LOV_USER_MAGIC_V3,
3352                              LMV_USER_MAGIC, LMV_MAGIC_V1);
3353                 return;
3354         }
3355 }
3356
3357 int llapi_file_get_stripe(const char *path, struct lov_user_md *lum)
3358 {
3359         const char *fname;
3360         char *dname;
3361         int fd, rc = 0;
3362
3363         fname = strrchr(path, '/');
3364
3365         /* It should be a file (or other non-directory) */
3366         if (fname == NULL) {
3367                 dname = (char *)malloc(2);
3368                 if (dname == NULL)
3369                         return -ENOMEM;
3370                 strcpy(dname, ".");
3371                 fname = (char *)path;
3372         } else {
3373                 dname = (char *)malloc(fname - path + 1);
3374                 if (dname == NULL)
3375                         return -ENOMEM;
3376                 strncpy(dname, path, fname - path);
3377                 dname[fname - path] = '\0';
3378                 fname++;
3379         }
3380
3381         fd = open(dname, O_RDONLY | O_NONBLOCK);
3382         if (fd == -1) {
3383                 rc = -errno;
3384                 free(dname);
3385                 return rc;
3386         }
3387
3388         strcpy((char *)lum, fname);
3389         if (ioctl(fd, IOC_MDC_GETFILESTRIPE, (void *)lum) == -1)
3390                 rc = -errno;
3391
3392         if (close(fd) == -1 && rc == 0)
3393                 rc = -errno;
3394
3395         free(dname);
3396         return rc;
3397 }
3398
3399 int llapi_file_lookup(int dirfd, const char *name)
3400 {
3401         struct obd_ioctl_data data = { 0 };
3402         char rawbuf[8192];
3403         char *buf = rawbuf;
3404         int rc;
3405
3406         if (dirfd < 0 || name == NULL)
3407                 return -EINVAL;
3408
3409         data.ioc_version = OBD_IOCTL_VERSION;
3410         data.ioc_len = sizeof(data);
3411         data.ioc_inlbuf1 = (char *)name;
3412         data.ioc_inllen1 = strlen(name) + 1;
3413
3414         rc = obd_ioctl_pack(&data, &buf, sizeof(rawbuf));
3415         if (rc) {
3416                 llapi_error(LLAPI_MSG_ERROR, rc,
3417                             "error: IOC_MDC_LOOKUP pack failed for '%s': rc %d",
3418                             name, rc);
3419                 return rc;
3420         }
3421
3422         rc = ioctl(dirfd, IOC_MDC_LOOKUP, buf);
3423         if (rc < 0)
3424                 rc = -errno;
3425         return rc;
3426 }
3427
3428 /* Check if the file time matches all the given criteria (e.g. --atime +/-N).
3429  * Return -1 or 1 if file timestamp does not or does match the given criteria
3430  * correspondingly. Return 0 if the MDS time is being checked and there are
3431  * attributes on OSTs and it is not yet clear if the timespamp matches.
3432  *
3433  * If 0 is returned, we need to do another RPC to the OSTs to obtain the
3434  * updated timestamps. */
3435 static int find_time_check(lstat_t *st, struct find_param *param, int mds)
3436 {
3437         int rc = 1;
3438         int rc2;
3439
3440         /* Check if file is accepted. */
3441         if (param->fp_atime) {
3442                 rc2 = find_value_cmp(st->st_atime, param->fp_atime,
3443                                      param->fp_asign, param->fp_exclude_atime,
3444                                      24 * 60 * 60, mds);
3445                 if (rc2 < 0)
3446                         return rc2;
3447                 rc = rc2;
3448         }
3449
3450         if (param->fp_mtime) {
3451                 rc2 = find_value_cmp(st->st_mtime, param->fp_mtime,
3452                                      param->fp_msign, param->fp_exclude_mtime,
3453                                      24 * 60 * 60, mds);
3454                 if (rc2 < 0)
3455                         return rc2;
3456
3457                 /* If the previous check matches, but this one is not yet clear,
3458                  * we should return 0 to do an RPC on OSTs. */
3459                 if (rc == 1)
3460                         rc = rc2;
3461         }
3462
3463         if (param->fp_ctime) {
3464                 rc2 = find_value_cmp(st->st_ctime, param->fp_ctime,
3465                                      param->fp_csign, param->fp_exclude_ctime,
3466                                      24 * 60 * 60, mds);
3467                 if (rc2 < 0)
3468                         return rc2;
3469
3470                 /* If the previous check matches, but this one is not yet clear,
3471                  * we should return 0 to do an RPC on OSTs. */
3472                 if (rc == 1)
3473                         rc = rc2;
3474         }
3475
3476         return rc;
3477 }
3478
3479 /**
3480  * Check whether the stripes matches the indexes user provided
3481  *       1   : matched
3482  *       0   : Unmatched
3483  */
3484 static int check_obd_match(struct find_param *param)
3485 {
3486         struct lov_user_ost_data_v1 *objects;
3487         struct lov_comp_md_v1 *comp_v1 = NULL;
3488         struct lov_user_md_v1 *v1 = &param->fp_lmd->lmd_lmm;
3489         lstat_t *st = &param->fp_lmd->lmd_st;
3490         int i, j, k, count = 1;
3491
3492         if (param->fp_obd_uuid && param->fp_obd_index == OBD_NOT_FOUND)
3493                 return 0;
3494
3495         if (!S_ISREG(st->st_mode))
3496                 return 0;
3497
3498         /* Only those files should be accepted, which have a
3499          * stripe on the specified OST. */
3500         if (v1->lmm_magic == LOV_USER_MAGIC_COMP_V1) {
3501                 comp_v1 = (struct lov_comp_md_v1 *)v1;
3502                 count = comp_v1->lcm_entry_count;
3503         }
3504
3505         for (i = 0; i < count; i++) {
3506                 if (comp_v1)
3507                         v1 = lov_comp_entry(comp_v1, i);
3508
3509                 objects = lov_v1v3_objects(v1);
3510
3511                 for (j = 0; j < v1->lmm_stripe_count; j++) {
3512                         for (k = 0; k < param->fp_num_obds; k++) {
3513                                 if (param->fp_obd_indexes[k] ==
3514                                     objects[j].l_ost_idx)
3515                                         return !param->fp_exclude_obd;
3516                         }
3517                 }
3518         }
3519
3520         return param->fp_exclude_obd;
3521 }
3522
3523 static int check_mdt_match(struct find_param *param)
3524 {
3525         int i;
3526
3527         if (param->fp_mdt_uuid && param->fp_mdt_index == OBD_NOT_FOUND)
3528                 return 0;
3529
3530         /* FIXME: For striped dir, we should get stripe information and check */
3531         for (i = 0; i < param->fp_num_mdts; i++) {
3532                 if (param->fp_mdt_indexes[i] == param->fp_file_mdt_index)
3533                         return !param->fp_exclude_mdt;
3534         }
3535
3536         if (param->fp_exclude_mdt)
3537                 return 1;
3538
3539         return 0;
3540 }
3541
3542 /**
3543  * Check whether the obd is active or not, if it is
3544  * not active, just print the object affected by this
3545  * failed target
3546  **/
3547 static int print_failed_tgt(struct find_param *param, char *path, int type)
3548 {
3549         struct obd_statfs stat_buf;
3550         struct obd_uuid uuid_buf;
3551         int ret;
3552
3553         if (type != LL_STATFS_LOV && type != LL_STATFS_LMV)
3554                 return -EINVAL;
3555
3556         memset(&stat_buf, 0, sizeof(struct obd_statfs));
3557         memset(&uuid_buf, 0, sizeof(struct obd_uuid));
3558         ret = llapi_obd_statfs(path, type,
3559                                param->fp_obd_index, &stat_buf,
3560                                &uuid_buf);
3561         if (ret) {
3562                 llapi_printf(LLAPI_MSG_NORMAL,
3563                              "obd_uuid: %s failed %s ",
3564                              param->fp_obd_uuid->uuid,
3565                              strerror(errno));
3566         }
3567
3568         return ret;
3569 }
3570
3571 static int find_check_stripe_size(struct find_param *param)
3572 {
3573         struct lov_comp_md_v1 *comp_v1 = NULL;
3574         struct lov_user_md_v1 *v1 = &param->fp_lmd->lmd_lmm;
3575         int ret, i, count = 1;
3576
3577         if (v1->lmm_magic == LOV_USER_MAGIC_COMP_V1) {
3578                 comp_v1 = (struct lov_comp_md_v1 *)v1;
3579                 count = comp_v1->lcm_entry_count;
3580                 ret = param->fp_exclude_stripe_size ? 1 : -1;
3581         }
3582
3583         for (i = 0; i < count; i++) {
3584                 if (comp_v1)
3585                         v1 = lov_comp_entry(comp_v1, i);
3586
3587                 ret = find_value_cmp(v1->lmm_stripe_size, param->fp_stripe_size,
3588                                      param->fp_stripe_size_sign,
3589                                      param->fp_exclude_stripe_size,
3590                                      param->fp_stripe_size_units, 0);
3591                 /* If any stripe_size matches */
3592                 if (ret != -1)
3593                         break;
3594         }
3595
3596         return ret;
3597 }
3598
3599 static __u32 find_get_stripe_count(struct find_param *param)
3600 {
3601         struct lov_comp_md_v1 *comp_v1 = NULL;
3602         struct lov_user_md_v1 *v1 = &param->fp_lmd->lmd_lmm;
3603         int i, count = 1;
3604         __u32 stripe_count = 0;
3605
3606         if (v1->lmm_magic == LOV_USER_MAGIC_COMP_V1) {
3607                 comp_v1 = (struct lov_comp_md_v1 *)v1;
3608                 count = comp_v1->lcm_entry_count;
3609         }
3610
3611         for (i = 0; i < count; i++) {
3612                 if (comp_v1)
3613                         v1 = lov_comp_entry(comp_v1, i);
3614                 stripe_count += v1->lmm_stripe_count;
3615         }
3616
3617         return stripe_count;
3618 }
3619
3620 #define LOV_PATTERN_INVALID     0xFFFFFFFF
3621
3622 static int find_check_layout(struct find_param *param)
3623 {
3624         struct lov_comp_md_v1 *comp_v1 = NULL;
3625         struct lov_user_md_v1 *v1 = &param->fp_lmd->lmd_lmm;
3626         int i, count = 1;
3627         bool found = false, valid = false;
3628
3629         if (v1->lmm_magic == LOV_USER_MAGIC_COMP_V1) {
3630                 comp_v1 = (struct lov_comp_md_v1 *)v1;
3631                 count = comp_v1->lcm_entry_count;
3632         }
3633
3634         for (i = 0; i < count; i++) {
3635                 if (comp_v1)
3636                         v1 = lov_comp_entry(comp_v1, i);
3637
3638                 if (v1->lmm_pattern == LOV_PATTERN_INVALID)
3639                         continue;
3640
3641                 valid = true;
3642                 if (v1->lmm_pattern & param->fp_layout) {
3643                         found = true;
3644                         break;
3645                 }
3646         }
3647
3648         if (!valid)
3649                 return -1;
3650
3651         if ((found && !param->fp_exclude_layout) ||
3652             (!found && param->fp_exclude_layout))
3653                 return 1;
3654
3655         return -1;
3656 }
3657
3658 static int find_check_pool(struct find_param *param)
3659 {
3660         struct lov_comp_md_v1 *comp_v1 = NULL;
3661         struct lov_user_md_v1 *v1 = &param->fp_lmd->lmd_lmm;
3662         struct lov_user_md_v3 *v3 = (void *)v1;
3663         int i, count = 1;
3664         bool found = false;
3665
3666         if (v1->lmm_magic == LOV_USER_MAGIC_COMP_V1) {
3667                 comp_v1 = (struct lov_comp_md_v1 *)v1;
3668                 count = comp_v1->lcm_entry_count;
3669                 /* empty requested pool is taken as no pool search */
3670                 if (count == 0 && param->fp_poolname[0] == '\0')
3671                         found = true;
3672         }
3673
3674         for (i = 0; i < count; i++) {
3675                 if (comp_v1 != NULL)
3676                         v1 = lov_comp_entry(comp_v1, i);
3677
3678                 if (((v1->lmm_magic == LOV_USER_MAGIC_V1) &&
3679                      (param->fp_poolname[0] == '\0')) ||
3680                     ((v1->lmm_magic == LOV_USER_MAGIC_V3) &&
3681                      (strncmp(v3->lmm_pool_name,
3682                               param->fp_poolname, LOV_MAXPOOLNAME) == 0)) ||
3683                     ((v1->lmm_magic == LOV_USER_MAGIC_V3) &&
3684                      (strcmp(param->fp_poolname, "*") == 0))) {
3685                         found = true;
3686                         break;
3687                 }
3688         }
3689
3690         if ((found && !param->fp_exclude_pool) ||
3691             (!found && param->fp_exclude_pool))
3692                 return 1;
3693
3694         return -1;
3695 }
3696
3697 static int find_check_comp_options(struct find_param *param)
3698 {
3699         lstat_t *st = &param->fp_lmd->lmd_st;
3700         struct lov_comp_md_v1 *comp_v1, *forged_v1 = NULL;
3701         struct lov_user_md_v1 *v1 = &param->fp_lmd->lmd_lmm;
3702         struct lov_comp_md_entry_v1 *entry;
3703         int i, ret = 0;
3704
3705         if (v1->lmm_magic == LOV_USER_MAGIC_COMP_V1) {
3706                 comp_v1 = (struct lov_comp_md_v1 *)v1;
3707         } else {
3708                 forged_v1 = malloc(sizeof(*forged_v1) + sizeof(*entry));
3709                 if (forged_v1 == NULL)
3710                         return -1;
3711                 comp_v1 = forged_v1;
3712                 comp_v1->lcm_entry_count = 1;
3713                 entry = &comp_v1->lcm_entries[0];
3714                 entry->lcme_flags = S_ISDIR(st->st_mode) ? 0 : LCME_FL_INIT;
3715                 entry->lcme_extent.e_start = 0;
3716                 entry->lcme_extent.e_end = LUSTRE_EOF;
3717         }
3718
3719         /* invalid case, don't match for any kind of search. */
3720         if (comp_v1->lcm_entry_count == 0) {
3721                 ret = -1;
3722                 goto out;
3723         }
3724
3725         if (param->fp_check_comp_count) {
3726                 ret = find_value_cmp(forged_v1 ? 0 : comp_v1->lcm_entry_count,
3727                                      param->fp_comp_count,
3728                                      param->fp_comp_count_sign,
3729                                      param->fp_exclude_comp_count, 1, 0);
3730                 if (ret == -1)
3731                         goto out;
3732         }
3733
3734         ret = 1;
3735         for (i = 0; i < comp_v1->lcm_entry_count; i++) {
3736                 entry = &comp_v1->lcm_entries[i];
3737
3738                 if (param->fp_check_comp_flags) {
3739                         if (((entry->lcme_flags & param->fp_comp_flags) &&
3740                              param->fp_exclude_comp_flags) ||
3741                             (!(entry->lcme_flags & param->fp_comp_flags) &&
3742                              !param->fp_exclude_comp_flags))
3743                                 ret = -1;
3744                         else
3745                                 ret = 1;
3746
3747                         if (ret == -1)
3748                                 continue;
3749                 }
3750
3751                 if (param->fp_check_comp_start) {
3752                         ret = find_value_cmp(entry->lcme_extent.e_start,
3753                                              param->fp_comp_start,
3754                                              param->fp_comp_start_sign,
3755                                              param->fp_exclude_comp_start,
3756                                              param->fp_comp_start_units, 0);
3757                         if (ret == -1)
3758                                 continue;
3759                 }
3760
3761                 if (param->fp_check_comp_end) {
3762                         ret = find_comp_end_cmp(entry->lcme_extent.e_end,
3763                                                 param);
3764                         if (ret == -1)
3765                                 continue;
3766                 }
3767
3768                 /* the component matches all criteria */
3769                 break;
3770         }
3771 out:
3772         if (forged_v1 != NULL)
3773                 free(forged_v1);
3774         return ret;
3775 }
3776
3777 static bool find_check_lmm_info(struct find_param *param)
3778 {
3779         return param->fp_check_pool || param->fp_check_stripe_count ||
3780                param->fp_check_stripe_size || param->fp_check_layout ||
3781                param->fp_check_comp_count || param->fp_check_comp_end ||
3782                param->fp_check_comp_start || param->fp_check_comp_flags ||
3783                param->fp_check_projid;
3784 }
3785
3786 /*
3787  * Get file/directory project id.
3788  * by the open fd resides on.
3789  * Return 0 and project id on success, or -ve errno.
3790  */
3791 static int fget_projid(int fd, int *projid)
3792 {
3793         struct fsxattr fsx;
3794         int rc;
3795
3796         rc = ioctl(fd, LL_IOC_FSGETXATTR, &fsx);
3797         if (rc)
3798                 return -errno;
3799
3800         *projid = fsx.fsx_projid;
3801         return 0;
3802 }
3803
3804 static int cb_find_init(char *path, DIR *parent, DIR **dirp,
3805                         void *data, struct dirent64 *de)
3806 {
3807         struct find_param *param = (struct find_param *)data;
3808         DIR *dir = dirp == NULL ? NULL : *dirp;
3809         int decision = 1; /* 1 is accepted; -1 is rejected. */
3810         lstat_t *st = &param->fp_lmd->lmd_st;
3811         int lustre_fs = 1;
3812         int checked_type = 0;
3813         int ret = 0;
3814         __u32 stripe_count = 0;
3815         int fd = -2;
3816
3817         if (parent == NULL && dir == NULL)
3818                 return -EINVAL;
3819
3820         /* If a regular expression is presented, make the initial decision */
3821         if (param->fp_pattern != NULL) {
3822                 char *fname = strrchr(path, '/');
3823                 fname = (fname == NULL ? path : fname + 1);
3824                 ret = fnmatch(param->fp_pattern, fname, 0);
3825                 if ((ret == FNM_NOMATCH && !param->fp_exclude_pattern) ||
3826                     (ret == 0 && param->fp_exclude_pattern))
3827                         goto decided;
3828         }
3829
3830         /* See if we can check the file type from the dirent. */
3831         if (param->fp_type != 0 && de != NULL && de->d_type != DT_UNKNOWN) {
3832                 checked_type = 1;
3833
3834                 if (DTTOIF(de->d_type) == param->fp_type) {
3835                         if (param->fp_exclude_type)
3836                                 goto decided;
3837                 } else {
3838                         if (!param->fp_exclude_type)
3839                                 goto decided;
3840                 }
3841         }
3842
3843         ret = 0;
3844
3845         /* Request MDS for the stat info if some of these parameters need
3846          * to be compared. */
3847         if (param->fp_obd_uuid || param->fp_mdt_uuid ||
3848             param->fp_check_uid || param->fp_check_gid ||
3849             param->fp_atime || param->fp_mtime || param->fp_ctime ||
3850             param->fp_check_size || find_check_lmm_info(param) ||
3851             param->fp_check_mdt_count || param->fp_check_hash_type)
3852                 decision = 0;
3853
3854         if (param->fp_type != 0 && checked_type == 0)
3855                 decision = 0;
3856
3857         if (decision == 0) {
3858                 if (param->fp_check_mdt_count || param->fp_check_hash_type) {
3859                         param->fp_get_lmv = 1;
3860                         ret = cb_get_dirstripe(path, dir, param);
3861                         if (ret != 0)
3862                                 return ret;
3863                 }
3864
3865                 param->fp_lmd->lmd_lmm.lmm_magic = 0;
3866                 ret = get_lmd_info(path, parent, dir, param->fp_lmd,
3867                                    param->fp_lum_size);
3868                 if (ret == 0 && param->fp_lmd->lmd_lmm.lmm_magic == 0 &&
3869                     find_check_lmm_info(param)) {
3870                         struct lov_user_md *lmm = &param->fp_lmd->lmd_lmm;
3871
3872                         /* We need to "fake" the "use the default" values
3873                          * since the lmm struct is zeroed out at this point. */
3874                         lmm->lmm_magic = LOV_USER_MAGIC_V1;
3875                         lmm->lmm_pattern = LOV_PATTERN_DEFAULT;
3876                         if (!param->fp_raw)
3877                                 ostid_set_seq(&lmm->lmm_oi,
3878                                               FID_SEQ_LOV_DEFAULT);
3879                         lmm->lmm_stripe_size = 0;
3880                         lmm->lmm_stripe_count = 0;
3881                         lmm->lmm_stripe_offset = -1;
3882                 }
3883                 if (ret == 0 && param->fp_mdt_uuid != NULL) {
3884                         if (dir != NULL) {
3885                                 ret = llapi_file_fget_mdtidx(dirfd(dir),
3886                                                      &param->fp_file_mdt_index);
3887                         } else if (S_ISREG(st->st_mode)) {
3888                                 /* FIXME: we could get the MDT index from the
3889                                  * file's FID in lmd->lmd_lmm.lmm_oi without
3890                                  * opening the file, once we are sure that
3891                                  * LFSCK2 (2.6) has fixed up pre-2.0 LOV EAs.
3892                                  * That would still be an ioctl() to map the
3893                                  * FID to the MDT, but not an open RPC. */
3894                                 fd = open(path, O_RDONLY);
3895                                 if (fd > 0) {
3896                                         ret = llapi_file_fget_mdtidx(fd,
3897                                                      &param->fp_file_mdt_index);
3898                                 } else {
3899                                         ret = -errno;
3900                                 }
3901                         } else {
3902                                 /* For a special file, we assume it resides on
3903                                  * the same MDT as the parent directory. */
3904                                 ret = llapi_file_fget_mdtidx(dirfd(parent),
3905                                                      &param->fp_file_mdt_index);
3906                         }
3907                 }
3908                 if (ret != 0) {
3909                         if (ret == -ENOTTY)
3910                                 lustre_fs = 0;
3911                         if (ret == -ENOENT)
3912                                 goto decided;
3913
3914                         goto out;
3915                 } else {
3916                         stripe_count = find_get_stripe_count(param);
3917                 }
3918         }
3919
3920         if (param->fp_type && !checked_type) {
3921                 if ((st->st_mode & S_IFMT) == param->fp_type) {
3922                         if (param->fp_exclude_type)
3923                                 goto decided;
3924                 } else {
3925                         if (!param->fp_exclude_type)
3926                                 goto decided;
3927                 }
3928         }
3929
3930         /* Prepare odb. */
3931         if (param->fp_obd_uuid || param->fp_mdt_uuid) {
3932                 if (lustre_fs && param->fp_got_uuids &&
3933                     param->fp_dev != st->st_dev) {
3934                         /* A lustre/lustre mount point is crossed. */
3935                         param->fp_got_uuids = 0;
3936                         param->fp_obds_printed = 0;
3937                         param->fp_mdt_index = OBD_NOT_FOUND;
3938                         param->fp_obd_index = OBD_NOT_FOUND;
3939                 }
3940
3941                 if (lustre_fs && !param->fp_got_uuids) {
3942                         ret = setup_target_indexes(dir ? dir : parent, path,
3943                                                    param);
3944                         if (ret)
3945                                 goto out;
3946
3947                         param->fp_dev = st->st_dev;
3948                 } else if (!lustre_fs && param->fp_got_uuids) {
3949                         /* A lustre/non-lustre mount point is crossed. */
3950                         param->fp_got_uuids = 0;
3951                         param->fp_mdt_index = OBD_NOT_FOUND;
3952                         param->fp_obd_index = OBD_NOT_FOUND;
3953                 }
3954         }
3955
3956         if (param->fp_check_stripe_size) {
3957                 decision = find_check_stripe_size(param);
3958                 if (decision == -1)
3959                         goto decided;
3960         }
3961
3962         if (param->fp_check_stripe_count) {
3963                 decision = find_value_cmp(stripe_count, param->fp_stripe_count,
3964                                           param->fp_stripe_count_sign,
3965                                           param->fp_exclude_stripe_count, 1, 0);
3966                 if (decision == -1)
3967                         goto decided;
3968         }
3969
3970         if (param->fp_check_mdt_count) {
3971                 decision = find_value_cmp(
3972                                 param->fp_lmv_md->lum_stripe_count,
3973                                 param->fp_mdt_count,
3974                                 param->fp_mdt_count_sign,
3975                                 param->fp_exclude_mdt_count, 1, 0);
3976                 if (decision == -1)
3977                         goto decided;
3978         }
3979
3980         if (param->fp_check_layout) {
3981                 decision = find_check_layout(param);
3982                 if (decision == -1)
3983                         goto decided;
3984         }
3985
3986         if (param->fp_check_hash_type) {
3987                 __u32 found;
3988
3989                 found = param->fp_lmv_md->lum_hash_type & param->fp_hash_type;
3990                 if ((found && param->fp_exclude_hash_type) ||
3991                     (!found && !param->fp_exclude_hash_type)) {
3992                         decision = -1;
3993                         goto decided;
3994                 }
3995         }
3996
3997         /* If an OBD UUID is specified but none matches, skip this file. */
3998         if ((param->fp_obd_uuid && param->fp_obd_index == OBD_NOT_FOUND) ||
3999             (param->fp_mdt_uuid && param->fp_mdt_index == OBD_NOT_FOUND))
4000                 goto decided;
4001
4002         /* If an OST or MDT UUID is given, and some OST matches,
4003          * check it here. */
4004         if (param->fp_obd_index != OBD_NOT_FOUND ||
4005             param->fp_mdt_index != OBD_NOT_FOUND) {
4006                 if (param->fp_obd_uuid) {
4007                         if (check_obd_match(param)) {
4008                                 /* If no mdtuuid is given, we are done.
4009                                  * Otherwise, fall through to the mdtuuid
4010                                  * check below. */
4011                                 if (!param->fp_mdt_uuid)
4012                                         goto obd_matches;
4013                         } else {
4014                                 goto decided;
4015                         }
4016                 }
4017
4018                 if (param->fp_mdt_uuid) {
4019                         if (check_mdt_match(param))
4020                                 goto obd_matches;
4021                         goto decided;
4022                 }
4023         }
4024
4025 obd_matches:
4026         if (param->fp_check_uid) {
4027                 if (st->st_uid == param->fp_uid) {
4028                         if (param->fp_exclude_uid)
4029                                 goto decided;
4030                 } else {
4031                         if (!param->fp_exclude_uid)
4032                                 goto decided;
4033                 }
4034         }
4035
4036         if (param->fp_check_gid) {
4037                 if (st->st_gid == param->fp_gid) {
4038                         if (param->fp_exclude_gid)
4039                                 goto decided;
4040                 } else {
4041                         if (!param->fp_exclude_gid)
4042                                 goto decided;
4043                 }
4044         }
4045
4046         if (param->fp_check_projid) {
4047                 int projid = 0;
4048
4049                 if (fd == -2)
4050                         fd = open(path, O_RDONLY);
4051
4052                 if (fd > 0)
4053                         ret = fget_projid(fd, &projid);
4054                 else
4055                         ret = -errno;
4056                 if (ret)
4057                         goto out;
4058                 if (projid == param->fp_projid) {
4059                         if (param->fp_exclude_uid)
4060                                 goto decided;
4061                 } else {
4062                         if (!param->fp_exclude_projid)
4063                                 goto decided;
4064                 }
4065         }
4066
4067         if (param->fp_check_pool) {
4068                 decision = find_check_pool(param);
4069                 if (decision == -1)
4070                         goto decided;
4071         }
4072
4073         if (param->fp_check_comp_count || param->fp_check_comp_flags ||
4074             param->fp_check_comp_start || param->fp_check_comp_end) {
4075                 decision = find_check_comp_options(param);
4076                 if (decision == -1)
4077                         goto decided;
4078         }
4079
4080         /* Check the time on mds. */
4081         decision = 1;
4082         if (param->fp_atime || param->fp_mtime || param->fp_ctime) {
4083                 int for_mds;
4084
4085                 for_mds = lustre_fs ?
4086                         (S_ISREG(st->st_mode) && stripe_count) : 0;
4087                 decision = find_time_check(st, param, for_mds);
4088                 if (decision == -1)
4089                         goto decided;
4090         }
4091
4092         /* If file still fits the request, ask ost for updated info.
4093            The regular stat is almost of the same speed as some new
4094            'glimpse-size-ioctl'. */
4095
4096         if (param->fp_check_size && S_ISREG(st->st_mode) && stripe_count)
4097                 decision = 0;
4098
4099         if (param->fp_check_size && S_ISDIR(st->st_mode))
4100                 decision = 0;
4101
4102         if (!decision) {
4103                 /* For regular files with the stripe the decision may have not
4104                  * been taken yet if *time or size is to be checked. */
4105                 if (param->fp_obd_index != OBD_NOT_FOUND)
4106                         print_failed_tgt(param, path, LL_STATFS_LOV);
4107
4108                 if (param->fp_mdt_index != OBD_NOT_FOUND)
4109                         print_failed_tgt(param, path, LL_STATFS_LMV);
4110
4111                 if (dir != NULL)
4112                         ret = fstat_f(dirfd(dir), st);
4113                 else if (de != NULL)
4114                         ret = fstatat_f(dirfd(parent), de->d_name, st,
4115                                         AT_SYMLINK_NOFOLLOW);
4116                 else
4117                         ret = lstat_f(path, st);
4118
4119                 if (ret) {
4120                         if (errno == ENOENT) {
4121                                 llapi_error(LLAPI_MSG_ERROR, -ENOENT,
4122                                             "warning: %s: %s does not exist",
4123                                             __func__, path);
4124                                 goto decided;
4125                         } else {
4126                                 ret = -errno;
4127                                 llapi_error(LLAPI_MSG_ERROR, ret,
4128                                             "%s: IOC_LOV_GETINFO on %s failed",
4129                                             __func__, path);
4130                                 goto out;
4131                         }
4132                 }
4133
4134                 /* Check the time on osc. */
4135                 decision = find_time_check(st, param, 0);
4136                 if (decision == -1)
4137                         goto decided;
4138         }
4139
4140         if (param->fp_check_size)
4141                 decision = find_value_cmp(st->st_size, param->fp_size,
4142                                           param->fp_size_sign,
4143                                           param->fp_exclude_size,
4144                                           param->fp_size_units, 0);
4145
4146         if (decision != -1) {
4147                 llapi_printf(LLAPI_MSG_NORMAL, "%s", path);
4148                 if (param->fp_zero_end)
4149                         llapi_printf(LLAPI_MSG_NORMAL, "%c", '\0');
4150                 else
4151                         llapi_printf(LLAPI_MSG_NORMAL, "\n");
4152         }
4153
4154 decided:
4155         ret = 0;
4156         /* Do not get down anymore? */
4157         if (param->fp_depth == param->fp_max_depth) {
4158                 ret = 1;
4159                 goto out;
4160         }
4161         param->fp_depth++;
4162 out:
4163         if (fd > 0)
4164                 close(fd);
4165         return ret;
4166 }
4167
4168 static int cb_migrate_mdt_init(char *path, DIR *parent, DIR **dirp,
4169                                void *param_data, struct dirent64 *de)
4170 {
4171         struct find_param       *param = (struct find_param *)param_data;
4172         DIR                     *tmp_parent = parent;
4173         char                    raw[MAX_IOC_BUFLEN] = {'\0'};
4174         char                    *rawbuf = raw;
4175         struct obd_ioctl_data   data = { 0 };
4176         int                     fd;
4177         int                     ret;
4178         char                    *path_copy;
4179         char                    *filename;
4180         bool                    retry = false;
4181
4182         if (parent == NULL && dirp == NULL)
4183                 return -EINVAL;
4184
4185         if (dirp != NULL)
4186                 closedir(*dirp);
4187
4188         if (parent == NULL) {
4189                 tmp_parent = opendir_parent(path);
4190                 if (tmp_parent == NULL) {
4191                         *dirp = NULL;
4192                         ret = -errno;
4193                         llapi_error(LLAPI_MSG_ERROR, ret,
4194                                     "can not open %s", path);
4195                         return ret;
4196                 }
4197         }
4198
4199         fd = dirfd(tmp_parent);
4200
4201         path_copy = strdup(path);
4202         filename = basename(path_copy);
4203         data.ioc_inlbuf1 = (char *)filename;
4204         data.ioc_inllen1 = strlen(filename) + 1;
4205         data.ioc_inlbuf2 = (char *)&param->fp_mdt_index;
4206         data.ioc_inllen2 = sizeof(param->fp_mdt_index);
4207         ret = obd_ioctl_pack(&data, &rawbuf, sizeof(raw));
4208         if (ret != 0) {
4209                 llapi_error(LLAPI_MSG_ERROR, ret,
4210                             "llapi_obd_statfs: error packing ioctl data");
4211                 goto out;
4212         }
4213
4214 migrate:
4215         ret = ioctl(fd, LL_IOC_MIGRATE, rawbuf);
4216         if (ret != 0) {
4217                 if (errno == EBUSY && !retry) {
4218                         /* because migrate may not be able to lock all involved
4219                          * objects in order, for some of them it try lock, while
4220                          * there may be conflicting COS locks and cause migrate
4221                          * fail with EBUSY, hope a sync() could cause
4222                          * transaction commit and release these COS locks. */
4223                         sync();
4224                         retry = true;
4225                         goto migrate;
4226                 }
4227                 ret = -errno;
4228                 fprintf(stderr, "%s migrate failed: %s (%d)\n",
4229                         path, strerror(-ret), ret);
4230                 goto out;
4231         } else if (param->fp_verbose & VERBOSE_DETAIL) {
4232                 fprintf(stdout, "migrate %s to MDT%d\n",
4233                         path, param->fp_mdt_index);
4234         }
4235
4236 out:
4237         if (dirp != NULL) {
4238                 /* If the directory is being migration, we need
4239                  * close the directory after migration,
4240                  * so the old directory cache will be cleanup
4241                  * on the client side, and re-open to get the
4242                  * new directory handle */
4243                 *dirp = opendir(path);
4244                 if (*dirp == NULL) {
4245                         ret = -errno;
4246                         llapi_error(LLAPI_MSG_ERROR, ret,
4247                                     "%s: Failed to open '%s'", __func__, path);
4248                 }
4249         }
4250
4251         if (parent == NULL)
4252                 closedir(tmp_parent);
4253
4254         free(path_copy);
4255
4256         return ret;
4257 }
4258
4259 int llapi_migrate_mdt(char *path, struct find_param *param)
4260 {
4261         return param_callback(path, cb_migrate_mdt_init, cb_common_fini, param);
4262 }
4263
4264 int llapi_mv(char *path, struct find_param *param)
4265 {
4266 #if LUSTRE_VERSION_CODE > OBD_OCD_VERSION(2, 9, 59, 0)
4267         static bool printed;
4268
4269         if (!printed) {
4270                 llapi_error(LLAPI_MSG_ERROR, -ESTALE,
4271                             "llapi_mv() is deprecated, use llapi_migrate_mdt()\n");
4272                 printed = true;
4273         }
4274 #endif
4275         return llapi_migrate_mdt(path, param);
4276 }
4277
4278 int llapi_find(char *path, struct find_param *param)
4279 {
4280         return param_callback(path, cb_find_init, cb_common_fini, param);
4281 }
4282
4283 /*
4284  * Get MDT number that the file/directory inode referenced
4285  * by the open fd resides on.
4286  * Return 0 and mdtidx on success, or -ve errno.
4287  */
4288 int llapi_file_fget_mdtidx(int fd, int *mdtidx)
4289 {
4290         if (ioctl(fd, LL_IOC_GET_MDTIDX, mdtidx) < 0)
4291                 return -errno;
4292         return 0;
4293 }
4294
4295 static int cb_get_mdt_index(char *path, DIR *parent, DIR **dirp, void *data,
4296                             struct dirent64 *de)
4297 {
4298         struct find_param *param = (struct find_param *)data;
4299         DIR *d = dirp == NULL ? NULL : *dirp;
4300         int ret;
4301         int mdtidx;
4302
4303         if (parent == NULL && d == NULL)
4304                 return -EINVAL;
4305
4306         if (d != NULL) {
4307                 ret = llapi_file_fget_mdtidx(dirfd(d), &mdtidx);
4308         } else /* if (parent) */ {
4309                 int fd;
4310
4311                 fd = open(path, O_RDONLY | O_NOCTTY);
4312                 if (fd > 0) {
4313                         ret = llapi_file_fget_mdtidx(fd, &mdtidx);
4314                         close(fd);
4315                 } else {
4316                         ret = -errno;
4317                 }
4318         }
4319
4320         if (ret != 0) {
4321                 if (ret == -ENODATA) {
4322                         if (!param->fp_obd_uuid)
4323                                 llapi_printf(LLAPI_MSG_NORMAL,
4324                                              "'%s' has no stripe info\n", path);
4325                         goto out;
4326                 } else if (ret == -ENOENT) {
4327                         llapi_error(LLAPI_MSG_WARN, ret,
4328                                     "warning: %s: '%s' does not exist",
4329                                     __func__, path);
4330                         goto out;
4331                 } else if (ret == -ENOTTY) {
4332                         llapi_error(LLAPI_MSG_ERROR, ret,
4333                                     "%s: '%s' not on a Lustre fs",
4334                                     __func__, path);
4335                 } else {
4336                         llapi_error(LLAPI_MSG_ERROR, ret,
4337                                     "error: %s: '%s' failed get_mdtidx",
4338                                     __func__, path);
4339                 }
4340                 return ret;
4341         }
4342
4343         if (param->fp_quiet || !(param->fp_verbose & VERBOSE_DETAIL))
4344                 llapi_printf(LLAPI_MSG_NORMAL, "%d\n", mdtidx);
4345         else
4346                 llapi_printf(LLAPI_MSG_NORMAL, "%s\nmdt_index:\t%d\n",
4347                              path, mdtidx);
4348
4349 out:
4350         /* Do not go down anymore? */
4351         if (param->fp_depth == param->fp_max_depth)
4352                 return 1;
4353
4354         param->fp_depth++;
4355
4356         return 0;
4357 }
4358
4359 static int cb_getstripe(char *path, DIR *parent, DIR **dirp, void *data,
4360                         struct dirent64 *de)
4361 {
4362         struct find_param *param = (struct find_param *)data;
4363         DIR *d = dirp == NULL ? NULL : *dirp;
4364         int ret = 0;
4365
4366         if (parent == NULL && d == NULL)
4367                 return -EINVAL;
4368
4369         if (param->fp_obd_uuid) {
4370                 param->fp_quiet = 1;
4371                 ret = setup_obd_uuid(d ? dirfd(d) : dirfd(parent), path, param);
4372                 if (ret)
4373                         return ret;
4374         }
4375
4376         if (d) {
4377                 if (param->fp_get_lmv || param->fp_get_default_lmv) {
4378                         ret = cb_get_dirstripe(path, d, param);
4379                 } else {
4380                         ret = ioctl(dirfd(d), LL_IOC_LOV_GETSTRIPE,
4381                                      (void *)&param->fp_lmd->lmd_lmm);
4382                 }
4383
4384         } else if (parent && !param->fp_get_lmv && !param->fp_get_default_lmv) {
4385                 char *fname = strrchr(path, '/');
4386                 fname = (fname == NULL ? path : fname + 1);
4387
4388                 strlcpy((char *)&param->fp_lmd->lmd_lmm, fname,
4389                         param->fp_lum_size);
4390
4391                 ret = ioctl(dirfd(parent), IOC_MDC_GETFILESTRIPE,
4392                             (void *)&param->fp_lmd->lmd_lmm);
4393         } else {
4394                 return 0;
4395         }
4396
4397         if (ret) {
4398                 if (errno == ENODATA && d != NULL) {
4399                         /* We need to "fake" the "use the default" values
4400                          * since the lmm struct is zeroed out at this point.
4401                          * The magic needs to be set in order to satisfy
4402                          * a check later on in the code path.
4403                          * The object_seq needs to be set for the "(Default)"
4404                          * prefix to be displayed. */
4405                         if (param->fp_get_default_lmv) {
4406                                 struct lmv_user_md *lum = param->fp_lmv_md;
4407
4408                                 lum->lum_magic = LMV_USER_MAGIC;
4409                                 lum->lum_stripe_count = 0;
4410                                 lum->lum_stripe_offset = -1;
4411                                 goto dump;
4412                         } else if (param->fp_get_lmv) {
4413                                 struct lmv_user_md *lum = param->fp_lmv_md;
4414                                 int mdtidx;
4415
4416                                 ret = llapi_file_fget_mdtidx(dirfd(d), &mdtidx);
4417                                 if (ret != 0)
4418                                         goto err_out;
4419                                 lum->lum_magic = LMV_MAGIC_V1;
4420                                 lum->lum_stripe_count = 0;
4421                                 lum->lum_stripe_offset = mdtidx;
4422                                 goto dump;
4423                         } else {
4424                                 struct lov_user_md *lmm =
4425                                         &param->fp_lmd->lmd_lmm;
4426
4427                                 lmm->lmm_magic = LOV_USER_MAGIC_V1;
4428                                 if (!param->fp_raw)
4429                                         ostid_set_seq(&lmm->lmm_oi,
4430                                                       FID_SEQ_LOV_DEFAULT);
4431                                 lmm->lmm_stripe_count = 0;
4432                                 lmm->lmm_stripe_size = 0;
4433                                 lmm->lmm_stripe_offset = -1;
4434                                 goto dump;
4435                         }
4436                 } else if (errno == ENODATA && parent != NULL) {
4437                         if (!param->fp_obd_uuid && !param->fp_mdt_uuid)
4438                                 llapi_printf(LLAPI_MSG_NORMAL,
4439                                              "%s has no stripe info\n", path);
4440                         goto out;
4441                 } else if (errno == ENOENT) {
4442                         llapi_error(LLAPI_MSG_WARN, -ENOENT,
4443                                     "warning: %s: %s does not exist",
4444                                     __func__, path);
4445                         goto out;
4446                 } else if (errno == ENOTTY) {
4447                         ret = -errno;
4448                         llapi_error(LLAPI_MSG_ERROR, ret,
4449                                     "%s: '%s' not on a Lustre fs?",
4450                                     __func__, path);
4451                 } else {
4452                         ret = -errno;
4453 err_out:
4454                         llapi_error(LLAPI_MSG_ERROR, ret,
4455                                     "error: %s: %s failed for %s",
4456                                      __func__, d ? "LL_IOC_LOV_GETSTRIPE" :
4457                                     "IOC_MDC_GETFILESTRIPE", path);
4458                 }
4459
4460                 return ret;
4461         }
4462
4463 dump:
4464         if (!(param->fp_verbose & VERBOSE_MDTINDEX))
4465                 llapi_lov_dump_user_lmm(param, path, d ? LDF_IS_DIR : 0);
4466
4467 out:
4468         /* Do not get down anymore? */
4469         if (param->fp_depth == param->fp_max_depth)
4470                 return 1;
4471
4472         param->fp_depth++;
4473
4474         return 0;
4475 }
4476
4477 int llapi_getstripe(char *path, struct find_param *param)
4478 {
4479         return param_callback(path, (param->fp_verbose & VERBOSE_MDTINDEX) ?
4480                               cb_get_mdt_index : cb_getstripe,
4481                               cb_common_fini, param);
4482 }
4483
4484 int llapi_obd_fstatfs(int fd, __u32 type, __u32 index,
4485                       struct obd_statfs *stat_buf, struct obd_uuid *uuid_buf)
4486 {
4487         char raw[MAX_IOC_BUFLEN] = {'\0'};
4488         char *rawbuf = raw;
4489         struct obd_ioctl_data data = { 0 };
4490         int rc = 0;
4491
4492         data.ioc_inlbuf1 = (char *)&type;
4493         data.ioc_inllen1 = sizeof(__u32);
4494         data.ioc_inlbuf2 = (char *)&index;
4495         data.ioc_inllen2 = sizeof(__u32);
4496         data.ioc_pbuf1 = (char *)stat_buf;
4497         data.ioc_plen1 = sizeof(struct obd_statfs);
4498         data.ioc_pbuf2 = (char *)uuid_buf;
4499         data.ioc_plen2 = sizeof(struct obd_uuid);
4500
4501         rc = obd_ioctl_pack(&data, &rawbuf, sizeof(raw));
4502         if (rc != 0) {
4503                 llapi_error(LLAPI_MSG_ERROR, rc,
4504                             "llapi_obd_statfs: error packing ioctl data");
4505                 return rc;
4506         }
4507
4508         rc = ioctl(fd, IOC_OBD_STATFS, (void *)rawbuf);
4509
4510         return rc < 0 ? -errno : 0;
4511 }
4512
4513 int llapi_obd_statfs(char *path, __u32 type, __u32 index,
4514                      struct obd_statfs *stat_buf, struct obd_uuid *uuid_buf)
4515 {
4516         int fd;
4517         int rc;
4518
4519         fd = open(path, O_RDONLY);
4520         if (fd < 0) {
4521                 rc = -errno;
4522                 llapi_error(LLAPI_MSG_ERROR, rc, "error: %s: opening '%s'",
4523                             __func__, path);
4524                 /* If we can't even open a file on the filesystem (e.g. with
4525                  * -ESHUTDOWN), force caller to exit or it will loop forever. */
4526                 return -ENODEV;
4527         }
4528
4529         rc = llapi_obd_fstatfs(fd, type, index, stat_buf, uuid_buf);
4530
4531         close(fd);
4532
4533         return rc;
4534 }
4535
4536 #define MAX_STRING_SIZE 128
4537
4538 int llapi_ping(char *obd_type, char *obd_name)
4539 {
4540         glob_t path;
4541         char buf[1];
4542         int rc, fd;
4543
4544         rc = cfs_get_param_paths(&path, "%s/%s/ping",
4545                                 obd_type, obd_name);
4546         if (rc != 0)
4547                 return -errno;
4548
4549         fd = open(path.gl_pathv[0], O_WRONLY);
4550         if (fd < 0) {
4551                 rc = -errno;
4552                 llapi_error(LLAPI_MSG_ERROR, rc, "error opening %s",
4553                             path.gl_pathv[0]);
4554                 goto failed;
4555         }
4556
4557         /* The purpose is to send a byte as a ping, whatever this byte is. */
4558         /* coverity[uninit_use_in_call] */
4559         rc = write(fd, buf, 1);
4560         if (rc < 0)
4561                 rc = -errno;
4562         close(fd);
4563
4564         if (rc == 1)
4565                 rc = 0;
4566 failed:
4567         cfs_free_param_data(&path);
4568         return rc;
4569 }
4570
4571 int llapi_target_iterate(int type_num, char **obd_type,
4572                          void *args, llapi_cb_t cb)
4573 {
4574         char buf[MAX_STRING_SIZE];
4575         int i, rc = 0;
4576         glob_t param;
4577         FILE *fp;
4578
4579         rc = cfs_get_param_paths(&param, "devices");
4580         if (rc != 0)
4581                 return -ENOENT;
4582
4583         fp = fopen(param.gl_pathv[0], "r");
4584         if (fp == NULL) {
4585                 rc = -errno;
4586                 llapi_error(LLAPI_MSG_ERROR, rc, "error: opening '%s'",
4587                             param.gl_pathv[0]);
4588                 goto free_path;
4589         }
4590
4591         while (fgets(buf, sizeof(buf), fp) != NULL) {
4592                 char *obd_type_name = NULL;
4593                 char *obd_name = NULL;
4594                 char *obd_uuid = NULL;
4595                 char *bufp = buf;
4596                 struct obd_statfs osfs_buffer;
4597
4598                 while(bufp[0] == ' ')
4599                         ++bufp;
4600
4601                 for(i = 0; i < 3; i++) {
4602                         obd_type_name = strsep(&bufp, " ");
4603                 }
4604                 obd_name = strsep(&bufp, " ");
4605                 obd_uuid = strsep(&bufp, " ");
4606
4607                 memset(&osfs_buffer, 0, sizeof (osfs_buffer));
4608
4609                 for (i = 0; i < type_num; i++) {
4610                         if (strcmp(obd_type_name, obd_type[i]) != 0)
4611                                 continue;
4612
4613                         cb(obd_type_name, obd_name, obd_uuid, args);
4614                 }
4615         }
4616         fclose(fp);
4617 free_path:
4618         cfs_free_param_data(&param);
4619         return 0;
4620 }
4621
4622 static void do_target_check(char *obd_type_name, char *obd_name,
4623                             char *obd_uuid, void *args)
4624 {
4625         int rc;
4626
4627         rc = llapi_ping(obd_type_name, obd_name);
4628         if (rc == ENOTCONN) {
4629                 llapi_printf(LLAPI_MSG_NORMAL, "%s inactive.\n", obd_name);
4630         } else if (rc) {
4631                 llapi_error(LLAPI_MSG_ERROR, rc, "error: check '%s'", obd_name);
4632         } else {
4633                 llapi_printf(LLAPI_MSG_NORMAL, "%s active.\n", obd_name);
4634         }
4635 }
4636
4637 int llapi_target_check(int type_num, char **obd_type, char *dir)
4638 {
4639         return llapi_target_iterate(type_num, obd_type, NULL, do_target_check);
4640 }
4641
4642 #undef MAX_STRING_SIZE
4643
4644 /* Is this a lustre fs? */
4645 int llapi_is_lustre_mnttype(const char *type)
4646 {
4647         return (strcmp(type, "lustre") == 0 || strcmp(type,"lustre_lite") == 0);
4648 }
4649
4650 /* Is this a lustre client fs? */
4651 int llapi_is_lustre_mnt(struct mntent *mnt)
4652 {
4653         return (llapi_is_lustre_mnttype(mnt->mnt_type) &&
4654                 strstr(mnt->mnt_fsname, ":/") != NULL);
4655 }
4656
4657 int llapi_quotactl(char *mnt, struct if_quotactl *qctl)
4658 {
4659         char fsname[PATH_MAX + 1];
4660         int root;
4661         int rc;
4662
4663         rc = llapi_search_fsname(mnt, fsname);
4664         if (rc) {
4665                 llapi_err_noerrno(LLAPI_MSG_ERROR,
4666                                   "'%s' isn't on Lustre filesystem", mnt);
4667                 return rc;
4668         }
4669
4670         root = open(mnt, O_RDONLY | O_DIRECTORY);
4671         if (root < 0) {
4672                 rc = -errno;
4673                 llapi_error(LLAPI_MSG_ERROR, rc, "open %s failed", mnt);
4674                 return rc;
4675         }
4676
4677         rc = ioctl(root, OBD_IOC_QUOTACTL, qctl);
4678         if (rc < 0)
4679                 rc = -errno;
4680
4681         close(root);
4682         return rc;
4683 }
4684
4685 /* Print mdtname 'name' into 'buf' using 'format'.  Add -MDT0000 if needed.
4686  * format must have %s%s, buf must be > 16
4687  * Eg: if name = "lustre-MDT0000", "lustre", or "lustre-MDT0000_UUID"
4688  *     then buf = "lustre-MDT0000"
4689  */
4690 static int get_mdtname(char *name, char *format, char *buf)
4691 {
4692         char suffix[]="-MDT0000";
4693         int len = strlen(name);
4694
4695         if ((len > 5) && (strncmp(name + len - 5, "_UUID", 5) == 0)) {
4696                 name[len - 5] = '\0';
4697                 len -= 5;
4698         }
4699
4700         if (len > 8) {
4701                 if ((len <= 16) && strncmp(name + len - 8, "-MDT", 4) == 0) {
4702                         suffix[0] = '\0';
4703                 } else {
4704                         /* Not enough room to add suffix */
4705                         llapi_err_noerrno(LLAPI_MSG_ERROR,
4706                                           "Invalid MDT name |%s|", name);
4707                         return -EINVAL;
4708                 }
4709         }
4710
4711         return sprintf(buf, format, name, suffix);
4712 }
4713
4714 /** ioctl on filsystem root, with mdtindex sent as data
4715  * \param mdtname path, fsname, or mdtname (lutre-MDT0004)
4716  * \param mdtidxp pointer to integer within data to be filled in with the
4717  *    mdt index (0 if no mdt is specified).  NULL won't be filled.
4718  */
4719 int root_ioctl(const char *mdtname, int opc, void *data, int *mdtidxp,
4720                int want_error)
4721 {
4722         char fsname[20];
4723         char *ptr;
4724         int fd, rc;
4725         long index;
4726
4727         /* Take path, fsname, or MDTname.  Assume MDT0000 in the former cases.
4728          Open root and parse mdt index. */
4729         if (mdtname[0] == '/') {
4730                 index = 0;
4731                 rc = get_root_path(WANT_FD | want_error, NULL, &fd,
4732                                    (char *)mdtname, -1);
4733         } else {
4734                 if (get_mdtname((char *)mdtname, "%s%s", fsname) < 0)
4735                         return -EINVAL;
4736                 ptr = fsname + strlen(fsname) - 8;
4737                 *ptr = '\0';
4738                 index = strtol(ptr + 4, NULL, 16);
4739                 rc = get_root_path(WANT_FD | want_error, fsname, &fd, NULL, -1);
4740         }
4741         if (rc < 0) {
4742                 if (want_error)
4743                         llapi_err_noerrno(LLAPI_MSG_ERROR,
4744                                           "Can't open %s: %d\n", mdtname, rc);
4745                 return rc;
4746         }
4747
4748         if (mdtidxp)
4749                 *mdtidxp = index;
4750
4751         rc = ioctl(fd, opc, data);
4752         if (rc == -1)
4753                 rc = -errno;
4754         else
4755                 rc = 0;
4756         close(fd);
4757         return rc;
4758 }
4759
4760 int llapi_fid2path(const char *device, const char *fidstr, char *buf,
4761                    int buflen, long long *recno, int *linkno)
4762 {
4763         const char *fidstr_orig = fidstr;
4764         struct lu_fid fid;
4765         struct getinfo_fid2path *gf;
4766         char *a;
4767         char *b;
4768         int rc;
4769
4770         while (*fidstr == '[')
4771                 fidstr++;
4772
4773         sscanf(fidstr, SFID, RFID(&fid));
4774         if (!fid_is_sane(&fid)) {
4775                 llapi_err_noerrno(LLAPI_MSG_ERROR,
4776                                   "bad FID format '%s', should be [seq:oid:ver]"
4777                                   " (e.g. "DFID")\n", fidstr_orig,
4778                                   (unsigned long long)FID_SEQ_NORMAL, 2, 0);
4779                 return -EINVAL;
4780         }
4781
4782         gf = malloc(sizeof(*gf) + buflen);
4783         if (gf == NULL)
4784                 return -ENOMEM;
4785
4786         gf->gf_fid = fid;
4787         gf->gf_recno = *recno;
4788         gf->gf_linkno = *linkno;
4789         gf->gf_pathlen = buflen;
4790
4791         /* Take path or fsname */
4792         rc = root_ioctl(device, OBD_IOC_FID2PATH, gf, NULL, 0);
4793         if (rc)
4794                 goto out_free;
4795
4796         b = buf;
4797         /* strip out instances of // */
4798         for (a = gf->gf_u.gf_path; *a != '\0'; a++) {
4799                 if ((*a == '/') && (*(a + 1) == '/'))
4800                         continue;
4801                 *b = *a;
4802                 b++;
4803         }
4804         *b = '\0';
4805
4806         if (buf[0] == '\0') { /* ROOT path */
4807                 buf[0] = '/';
4808                 buf[1] = '\0';
4809         }
4810
4811         *recno = gf->gf_recno;
4812         *linkno = gf->gf_linkno;
4813
4814 out_free:
4815         free(gf);
4816         return rc;
4817 }
4818
4819 static int fid_from_lma(const char *path, int fd, struct lu_fid *fid)
4820 {
4821         char                     buf[512];
4822         struct lustre_mdt_attrs *lma;
4823         int                      rc;
4824
4825         if (path == NULL)
4826                 rc = fgetxattr(fd, XATTR_NAME_LMA, buf, sizeof(buf));
4827         else
4828                 rc = lgetxattr(path, XATTR_NAME_LMA, buf, sizeof(buf));
4829         if (rc < 0)
4830                 return -errno;
4831         lma = (struct lustre_mdt_attrs *)buf;
4832         fid_le_to_cpu(fid, &lma->lma_self_fid);
4833         return 0;
4834 }
4835
4836 int llapi_get_mdt_index_by_fid(int fd, const struct lu_fid *fid,
4837                                int *mdt_index)
4838 {
4839         int     rc;
4840
4841         rc = ioctl(fd, LL_IOC_FID2MDTIDX, fid);
4842         if (rc < 0)
4843                 return -errno;
4844
4845         *mdt_index = rc;
4846
4847         return rc;
4848 }
4849
4850 int llapi_fd2fid(int fd, struct lu_fid *fid)
4851 {
4852         int rc;
4853
4854         memset(fid, 0, sizeof(*fid));
4855
4856         rc = ioctl(fd, LL_IOC_PATH2FID, fid) < 0 ? -errno : 0;
4857         if (rc == -EINVAL || rc == -ENOTTY)
4858                 rc = fid_from_lma(NULL, fd, fid);
4859
4860         return rc;
4861 }
4862
4863 int llapi_path2fid(const char *path, struct lu_fid *fid)
4864 {
4865         int fd, rc;
4866
4867         memset(fid, 0, sizeof(*fid));
4868         fd = open(path, O_RDONLY | O_NONBLOCK | O_NOFOLLOW);
4869         if (fd < 0) {
4870                 if (errno == ELOOP || errno == ENXIO)
4871                         return fid_from_lma(path, -1, fid);
4872                 return -errno;
4873         }
4874
4875         rc = llapi_fd2fid(fd, fid);
4876         if (rc == -EINVAL || rc == -ENOTTY)
4877                 rc = fid_from_lma(path, -1, fid);
4878
4879         close(fd);
4880         return rc;
4881 }
4882
4883 int llapi_fd2parent(int fd, unsigned int linkno, struct lu_fid *parent_fid,
4884                     char *name, size_t name_size)
4885 {
4886         struct getparent        *gp;
4887         int                      rc;
4888
4889         gp = malloc(sizeof(*gp) + name_size);
4890         if (gp == NULL)
4891                 return -ENOMEM;
4892
4893         gp->gp_linkno = linkno;
4894         gp->gp_name_size = name_size;
4895
4896         rc = ioctl(fd, LL_IOC_GETPARENT, gp);
4897         if (rc < 0) {
4898                 rc = -errno;
4899                 goto err_free;
4900         }
4901
4902         *parent_fid = gp->gp_fid;
4903
4904         strncpy(name, gp->gp_name, name_size);
4905         name[name_size - 1] = '\0';
4906
4907 err_free:
4908         free(gp);
4909         return rc;
4910 }
4911
4912 int llapi_path2parent(const char *path, unsigned int linkno,
4913                       struct lu_fid *parent_fid, char *name, size_t name_size)
4914 {
4915         int     fd;
4916         int     rc;
4917
4918         fd = open(path, O_RDONLY | O_NONBLOCK | O_NOFOLLOW);
4919         if (fd < 0)
4920                 return -errno;
4921
4922         rc = llapi_fd2parent(fd, linkno, parent_fid, name, name_size);
4923         close(fd);
4924         return rc;
4925 }
4926
4927 int llapi_get_connect_flags(const char *mnt, __u64 *flags)
4928 {
4929         int root;
4930         int rc;
4931
4932         root = open(mnt, O_RDONLY | O_DIRECTORY);
4933         if (root < 0) {
4934                 rc = -errno;
4935                 llapi_error(LLAPI_MSG_ERROR, rc, "open %s failed", mnt);
4936                 return rc;
4937         }
4938
4939         rc = ioctl(root, LL_IOC_GET_CONNECT_FLAGS, flags);
4940         if (rc < 0) {
4941                 rc = -errno;
4942                 llapi_error(LLAPI_MSG_ERROR, rc,
4943                         "ioctl on %s for getting connect flags failed", mnt);
4944         }
4945         close(root);
4946         return rc;
4947 }
4948
4949 /**
4950  * Get a 64-bit value representing the version of file data pointed by fd.
4951  *
4952  * Each write or truncate, flushed on OST, will change this value. You can use
4953  * this value to verify if file data was modified. This only checks the file
4954  * data, not metadata.
4955  *
4956  * \param  flags  0: no flush pages, usually used it the process has already
4957  *                  taken locks;
4958  *                LL_DV_RD_FLUSH: OSTs will take LCK_PR to flush dirty pages
4959  *                  from clients;
4960  *                LL_DV_WR_FLUSH: OSTs will take LCK_PW to flush all caching
4961  *                  pages from clients.
4962  *
4963  * \retval 0 on success.
4964  * \retval -errno on error.
4965  */
4966 int llapi_get_data_version(int fd, __u64 *data_version, __u64 flags)
4967 {
4968         int rc;
4969         struct ioc_data_version idv;
4970
4971         idv.idv_flags = (__u32)flags;
4972
4973         rc = ioctl(fd, LL_IOC_DATA_VERSION, &idv);
4974         if (rc)
4975                 rc = -errno;
4976         else
4977                 *data_version = idv.idv_version;
4978
4979         return rc;
4980 }
4981
4982 /*
4983  * Fetch layout version from OST objects. Layout version on OST objects are
4984  * only set when the file is a mirrored file AND after the file has been
4985  * written at least once.
4986  *
4987  * It actually fetches the least layout version from the objects.
4988  */
4989 int llapi_get_ost_layout_version(int fd, __u32 *layout_version)
4990 {
4991         int rc;
4992         struct ioc_data_version idv = { 0 };
4993
4994         rc = ioctl(fd, LL_IOC_DATA_VERSION, &idv);
4995         if (rc)
4996                 rc = -errno;
4997         else
4998                 *layout_version = idv.idv_layout_version;
4999
5000         return rc;
5001 }
5002
5003 /*
5004  * Create a file without any name open it for read/write
5005  *
5006  * - file is created as if it were a standard file in the given \a directory
5007  * - file does not appear in \a directory and mtime does not change because
5008  *   the filename is handled specially by the Lustre MDS.
5009  * - file is removed at final close
5010  * - file modes are rw------- since it doesn't make sense to have a read-only
5011  *   or write-only file that cannot be opened again.
5012  * - if user wants another mode it must use fchmod() on the open file, no
5013  *   security problems arise because it cannot be opened by another process.
5014  *
5015  * \param[in]   directory       directory from which to inherit layout/MDT idx
5016  * \param[in]   idx             MDT index on which the file is created,
5017  *                              \a idx == -1 means no specific MDT is requested
5018  * \param[in]   open_flags      standard open(2) flags
5019  *
5020  * \retval      0 on success.
5021  * \retval      -errno on error.
5022  */
5023 int llapi_create_volatile_idx(char *directory, int idx, int open_flags)
5024 {
5025         char    file_path[PATH_MAX];
5026         char    filename[PATH_MAX];
5027         int     saved_errno = errno;
5028         int     fd;
5029         int     rnumber;
5030         int     rc;
5031
5032         do {
5033                 rnumber = random();
5034                 if (idx == -1)
5035                         snprintf(filename, sizeof(filename),
5036                                  LUSTRE_VOLATILE_HDR"::%.4X", rnumber);
5037                 else
5038                         snprintf(filename, sizeof(filename),
5039                                  LUSTRE_VOLATILE_HDR":%.4X:%.4X", idx, rnumber);
5040
5041                 rc = snprintf(file_path, sizeof(file_path),
5042                               "%s/%s", directory, filename);
5043                 if (rc >= sizeof(file_path))
5044                         return -E2BIG;
5045
5046                 fd = open(file_path,
5047                           O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW | open_flags,
5048                           S_IRUSR | S_IWUSR);
5049         } while (fd < 0 && errno == EEXIST);
5050
5051         if (fd < 0) {
5052                 llapi_error(LLAPI_MSG_ERROR, errno,
5053                             "Cannot create volatile file '%s' in '%s'",
5054                             filename + LUSTRE_VOLATILE_HDR_LEN,
5055                             directory);
5056                 return -errno;
5057         }
5058
5059         /* Unlink file in case this wasn't a Lustre filesystem and the
5060          * magic volatile filename wasn't handled as intended. The
5061          * effect is the same. If volatile open was supported then we
5062          * expect unlink() to return -ENOENT. */
5063         (void)unlink(file_path);
5064
5065         /* Since we are returning successfully we restore errno (and
5066          * mask out possible EEXIST from open() and ENOENT from
5067          * unlink(). */
5068         errno = saved_errno;
5069
5070         return fd;
5071 }
5072
5073 /**
5074  * Swap the layouts between 2 file descriptors
5075  * the 2 files must be open for writing
5076  * first fd received the ioctl, second fd is passed as arg
5077  * this is assymetric but avoid use of root path for ioctl
5078  */
5079 int llapi_fswap_layouts_grouplock(int fd1, int fd2, __u64 dv1, __u64 dv2,
5080                                   int gid, __u64 flags)
5081 {
5082         struct lustre_swap_layouts      lsl;
5083         struct stat                     st1;
5084         struct stat                     st2;
5085         int                             rc;
5086
5087         if (flags & (SWAP_LAYOUTS_KEEP_ATIME | SWAP_LAYOUTS_KEEP_MTIME)) {
5088                 rc = fstat(fd1, &st1);
5089                 if (rc < 0)
5090                         return -errno;
5091
5092                 rc = fstat(fd2, &st2);
5093                 if (rc < 0)
5094                         return -errno;
5095         }
5096         lsl.sl_fd = fd2;
5097         lsl.sl_flags = flags;
5098         lsl.sl_gid = gid;
5099         lsl.sl_dv1 = dv1;
5100         lsl.sl_dv2 = dv2;
5101         rc = ioctl(fd1, LL_IOC_LOV_SWAP_LAYOUTS, &lsl);
5102         if (rc < 0)
5103                 return -errno;
5104
5105         if (flags & (SWAP_LAYOUTS_KEEP_ATIME | SWAP_LAYOUTS_KEEP_MTIME)) {
5106                 struct timeval  tv1[2];
5107                 struct timeval  tv2[2];
5108
5109                 memset(tv1, 0, sizeof(tv1));
5110                 memset(tv2, 0, sizeof(tv2));
5111
5112                 if (flags & SWAP_LAYOUTS_KEEP_ATIME) {
5113                         tv1[0].tv_sec = st1.st_atime;
5114                         tv2[0].tv_sec = st2.st_atime;
5115                 } else {
5116                         tv1[0].tv_sec = st2.st_atime;
5117                         tv2[0].tv_sec = st1.st_atime;
5118                 }
5119
5120                 if (flags & SWAP_LAYOUTS_KEEP_MTIME) {
5121                         tv1[1].tv_sec = st1.st_mtime;
5122                         tv2[1].tv_sec = st2.st_mtime;
5123                 } else {
5124                         tv1[1].tv_sec = st2.st_mtime;
5125                         tv2[1].tv_sec = st1.st_mtime;
5126                 }
5127
5128                 rc = futimes(fd1, tv1);
5129                 if (rc < 0)
5130                         return -errno;
5131
5132                 rc = futimes(fd2, tv2);
5133                 if (rc < 0)
5134                         return -errno;
5135         }
5136
5137         return 0;
5138 }
5139
5140 int llapi_fswap_layouts(int fd1, int fd2, __u64 dv1, __u64 dv2, __u64 flags)
5141 {
5142         int     rc;
5143         int     grp_id;
5144
5145         do
5146                 grp_id = random();
5147         while (grp_id == 0);
5148
5149         rc = llapi_fswap_layouts_grouplock(fd1, fd2, dv1, dv2, grp_id, flags);
5150         if (rc < 0)
5151                 return rc;
5152
5153         return 0;
5154 }
5155
5156 /**
5157  * Swap the layouts between 2 files
5158  * the 2 files are open in write
5159  */
5160 int llapi_swap_layouts(const char *path1, const char *path2,
5161                        __u64 dv1, __u64 dv2, __u64 flags)
5162 {
5163         int     fd1, fd2, rc;
5164
5165         fd1 = open(path1, O_WRONLY | O_LOV_DELAY_CREATE);
5166         if (fd1 < 0) {
5167                 rc = -errno;
5168                 llapi_error(LLAPI_MSG_ERROR, rc,
5169                             "error: cannot open '%s' for write", path1);
5170                 goto out;
5171         }
5172
5173         fd2 = open(path2, O_WRONLY | O_LOV_DELAY_CREATE);
5174         if (fd2 < 0) {
5175                 rc = -errno;
5176                 llapi_error(LLAPI_MSG_ERROR, rc,
5177                             "error: cannot open '%s' for write", path2);
5178                 goto out_close;
5179         }
5180
5181         rc = llapi_fswap_layouts(fd1, fd2, dv1, dv2, flags);
5182         if (rc < 0)
5183                 llapi_error(LLAPI_MSG_ERROR, rc,
5184                             "error: cannot swap layout between '%s' and '%s'",
5185                             path1, path2);
5186
5187         close(fd2);
5188 out_close:
5189         close(fd1);
5190 out:
5191         return rc;
5192 }
5193
5194 /**
5195  * Attempt to open a file with Lustre file identifier \a fid
5196  * and return an open file descriptor.
5197  *
5198  * \param[in] lustre_dir        path within Lustre filesystem containing \a fid
5199  * \param[in] fid               Lustre file identifier of file to open
5200  * \param[in] flags             open() flags
5201  *
5202  * \retval                      non-negative file descriptor on successful open
5203  * \retval                      -1 if an error occurred
5204  */
5205 int llapi_open_by_fid(const char *lustre_dir, const struct lu_fid *fid,
5206                       int flags)
5207 {
5208         char mntdir[PATH_MAX];
5209         char path[PATH_MAX];
5210         int rc;
5211
5212         rc = llapi_search_mounts(lustre_dir, 0, mntdir, NULL);
5213         if (rc != 0)
5214                 return -1;
5215
5216         snprintf(path, sizeof(path), "%s/.lustre/fid/"DFID, mntdir, PFID(fid));
5217         return open(path, flags);
5218 }
5219
5220 /**
5221  * Take group lock.
5222  *
5223  * \param fd   File to lock.
5224  * \param gid  Group Identifier.
5225  *
5226  * \retval 0 on success.
5227  * \retval -errno on failure.
5228  */
5229 int llapi_group_lock(int fd, int gid)
5230 {
5231         int rc;
5232
5233         rc = ioctl(fd, LL_IOC_GROUP_LOCK, gid);
5234         if (rc < 0) {
5235                 rc = -errno;
5236                 llapi_error(LLAPI_MSG_ERROR, rc, "cannot get group lock");
5237         }
5238         return rc;
5239 }
5240
5241 /**
5242  * Put group lock.
5243  *
5244  * \param fd   File to unlock.
5245  * \param gid  Group Identifier.
5246  *
5247  * \retval 0 on success.
5248  * \retval -errno on failure.
5249  */
5250 int llapi_group_unlock(int fd, int gid)
5251 {
5252         int rc;
5253
5254         rc = ioctl(fd, LL_IOC_GROUP_UNLOCK, gid);
5255         if (rc < 0) {
5256                 rc = -errno;
5257                 llapi_error(LLAPI_MSG_ERROR, rc, "cannot put group lock");
5258         }
5259         return rc;
5260 }