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