4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
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.
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).
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
23 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Use is subject to license terms.
26 * Copyright (c) 2011, 2017, Intel Corporation.
29 * This file is part of Lustre, http://www.lustre.org/
31 * lustre/utils/liblustreapi.c
33 * Author: Peter J. Braam <braam@clusterfs.com>
34 * Author: Phil Schwan <phil@clusterfs.com>
35 * Author: Robert Read <rread@clusterfs.com>
49 #include <sys/ioctl.h>
56 #include <sys/statfs.h>
57 #include <sys/syscall.h>
59 #include <sys/types.h>
60 #include <sys/xattr.h>
61 #include <sys/sysmacros.h>
64 #include <libgen.h> /* for dirname() */
65 #include <linux/limits.h>
66 #ifdef HAVE_LINUX_UNISTD_H
67 #include <linux/unistd.h>
76 #include <libcfs/util/ioctl.h>
77 #include <libcfs/util/param.h>
78 #include <libcfs/util/string.h>
79 #include <linux/lnet/lnetctl.h>
80 #include <lustre/lustreapi.h>
81 #include <linux/lustre/lustre_ostid.h>
82 #include <linux/lustre/lustre_ioctl.h>
83 #include "lustreapi_internal.h"
86 #define FORMATTED_BUF_LEN 1024
88 static int llapi_msg_level = LLAPI_MSG_MAX;
89 const char *liblustreapi_cmd;
91 struct lustre_foreign_type lu_foreign_types[] = {
92 {.lft_type = LU_FOREIGN_TYPE_NONE, .lft_name = "none"},
93 {.lft_type = LU_FOREIGN_TYPE_SYMLINK, .lft_name = "symlink"},
94 /* must be the last element */
95 {.lft_type = LU_FOREIGN_TYPE_UNKNOWN, .lft_name = NULL}
96 /* array max dimension must be <= UINT32_MAX */
99 void llapi_msg_set_level(int level)
101 /* ensure level is in the good range */
102 if (level < LLAPI_MSG_OFF)
103 llapi_msg_level = LLAPI_MSG_OFF;
104 else if (level > LLAPI_MSG_MAX)
105 llapi_msg_level = LLAPI_MSG_MAX;
107 llapi_msg_level = level;
110 int llapi_msg_get_level(void)
112 return llapi_msg_level;
115 void llapi_set_command_name(const char *cmd)
117 liblustreapi_cmd = cmd;
120 void llapi_clear_command_name(void)
122 liblustreapi_cmd = NULL;
125 static void error_callback_default(enum llapi_message_level level, int err,
126 const char *fmt, va_list ap)
128 bool has_nl = strchr(fmt, '\n') != NULL;
130 if (liblustreapi_cmd != NULL)
131 fprintf(stderr, "%s %s: ", program_invocation_short_name,
134 fprintf(stderr, "%s: ", program_invocation_short_name);
137 if (level & LLAPI_MSG_NO_ERRNO) {
138 vfprintf(stderr, fmt, ap);
140 fprintf(stderr, "\n");
145 * Remove trailing linefeed so error string can be appended.
146 * @fmt is a const string, so we can't modify it directly.
148 if (has_nl && (newfmt = strdup(fmt)))
149 *strrchr(newfmt, '\n') = '\0';
151 newfmt = (char *)fmt;
153 vfprintf(stderr, newfmt, ap);
156 fprintf(stderr, ": %s (%d)\n", strerror(err), err);
160 static void info_callback_default(enum llapi_message_level level, int err,
161 const char *fmt, va_list ap)
164 if (liblustreapi_cmd != NULL) {
165 fprintf(stdout, "%s %s: ",
166 program_invocation_short_name,
169 fprintf(stdout, "%s: ", program_invocation_short_name);
172 vfprintf(stdout, fmt, ap);
175 static llapi_log_callback_t llapi_error_callback = error_callback_default;
176 static llapi_log_callback_t llapi_info_callback = info_callback_default;
179 /* llapi_error will preserve errno */
180 void llapi_error(enum llapi_message_level level, int err, const char *fmt, ...)
183 int tmp_errno = errno;
185 if ((level & LLAPI_MSG_MASK) > llapi_msg_level)
189 llapi_error_callback(level, abs(err), fmt, args);
194 /* llapi_printf will preserve errno */
195 void llapi_printf(enum llapi_message_level level, const char *fmt, ...)
198 int tmp_errno = errno;
200 if ((level & LLAPI_MSG_MASK) > llapi_msg_level)
204 llapi_info_callback(level, 0, fmt, args);
210 * Set a custom error logging function. Passing in NULL will reset the logging
211 * callback to its default value.
213 * This function returns the value of the old callback.
215 llapi_log_callback_t llapi_error_callback_set(llapi_log_callback_t cb)
217 llapi_log_callback_t old = llapi_error_callback;
220 llapi_error_callback = cb;
222 llapi_error_callback = error_callback_default;
228 * Set a custom info logging function. Passing in NULL will reset the logging
229 * callback to its default value.
231 * This function returns the value of the old callback.
233 llapi_log_callback_t llapi_info_callback_set(llapi_log_callback_t cb)
235 llapi_log_callback_t old = llapi_info_callback;
238 llapi_info_callback = cb;
240 llapi_info_callback = info_callback_default;
246 * size_units is to be initialized (or zeroed) by caller.
248 int llapi_parse_size(const char *optarg, unsigned long long *size,
249 unsigned long long *size_units, int bytes_spec)
252 char *argbuf = (char *)optarg;
253 unsigned long long frac = 0, frac_d = 1;
255 if (strncmp(optarg, "-", 1) == 0)
258 if (*size_units == 0)
261 *size = strtoull(argbuf, &end, 0);
262 if (end != NULL && *end == '.') {
266 frac = strtoull(argbuf, &end, 10);
267 /* count decimal places */
268 for (i = 0; i < (end - argbuf); i++)
273 if ((*end == 'b') && *(end + 1) == '\0' &&
274 (*size & (~0ULL << (64 - 9))) == 0 &&
276 *size_units = 1 << 9;
277 } else if ((*end == 'b') &&
278 *(end + 1) == '\0' &&
281 } else if ((*end == 'k' || *end == 'K') &&
282 *(end + 1) == '\0' &&
283 (*size & (~0ULL << (64 - 10))) == 0) {
284 *size_units = 1 << 10;
285 } else if ((*end == 'm' || *end == 'M') &&
286 *(end + 1) == '\0' &&
287 (*size & (~0ULL << (64 - 20))) == 0) {
288 *size_units = 1 << 20;
289 } else if ((*end == 'g' || *end == 'G') &&
290 *(end + 1) == '\0' &&
291 (*size & (~0ULL << (64 - 30))) == 0) {
292 *size_units = 1 << 30;
293 } else if ((*end == 't' || *end == 'T') &&
294 *(end + 1) == '\0' &&
295 (*size & (~0ULL << (64 - 40))) == 0) {
296 *size_units = 1ULL << 40;
297 } else if ((*end == 'p' || *end == 'P') &&
298 *(end + 1) == '\0' &&
299 (*size & (~0ULL << (64 - 50))) == 0) {
300 *size_units = 1ULL << 50;
301 } else if ((*end == 'e' || *end == 'E') &&
302 *(end + 1) == '\0' &&
303 (*size & (~0ULL << (64 - 60))) == 0) {
304 *size_units = 1ULL << 60;
309 *size = *size * *size_units + frac * *size_units / frac_d;
314 int llapi_ioctl_pack(struct obd_ioctl_data *data, char **pbuf, int max_len)
316 struct obd_ioctl_data *overlay;
319 data->ioc_len = obd_ioctl_packlen(data);
320 data->ioc_version = OBD_IOCTL_VERSION;
322 if (*pbuf != NULL && data->ioc_len > max_len) {
323 llapi_error(LLAPI_MSG_ERROR, -EINVAL,
324 "pbuf = %p, ioc_len = %u, max_len = %d",
325 *pbuf, data->ioc_len, max_len);
330 *pbuf = malloc(data->ioc_len);
335 overlay = (struct obd_ioctl_data *)*pbuf;
336 memcpy(*pbuf, data, sizeof(*data));
338 ptr = overlay->ioc_bulk;
339 if (data->ioc_inlbuf1) {
340 memcpy(ptr, data->ioc_inlbuf1, data->ioc_inllen1);
341 ptr += __ALIGN_KERNEL(data->ioc_inllen1, 8);
344 if (data->ioc_inlbuf2) {
345 memcpy(ptr, data->ioc_inlbuf2, data->ioc_inllen2);
346 ptr += __ALIGN_KERNEL(data->ioc_inllen2, 8);
349 if (data->ioc_inlbuf3) {
350 memcpy(ptr, data->ioc_inlbuf3, data->ioc_inllen3);
351 ptr += __ALIGN_KERNEL(data->ioc_inllen3, 8);
354 if (data->ioc_inlbuf4) {
355 memcpy(ptr, data->ioc_inlbuf4, data->ioc_inllen4);
356 ptr += __ALIGN_KERNEL(data->ioc_inllen4, 8);
362 int llapi_ioctl_unpack(struct obd_ioctl_data *data, char *pbuf, int max_len)
364 struct obd_ioctl_data *overlay;
370 overlay = (struct obd_ioctl_data *)pbuf;
372 /* Preserve the caller's buffer pointers */
373 overlay->ioc_inlbuf1 = data->ioc_inlbuf1;
374 overlay->ioc_inlbuf2 = data->ioc_inlbuf2;
375 overlay->ioc_inlbuf3 = data->ioc_inlbuf3;
376 overlay->ioc_inlbuf4 = data->ioc_inlbuf4;
378 memcpy(data, pbuf, sizeof(*data));
380 ptr = overlay->ioc_bulk;
381 if (data->ioc_inlbuf1) {
382 memcpy(data->ioc_inlbuf1, ptr, data->ioc_inllen1);
383 ptr += __ALIGN_KERNEL(data->ioc_inllen1, 8);
386 if (data->ioc_inlbuf2) {
387 memcpy(data->ioc_inlbuf2, ptr, data->ioc_inllen2);
388 ptr += __ALIGN_KERNEL(data->ioc_inllen2, 8);
391 if (data->ioc_inlbuf3) {
392 memcpy(data->ioc_inlbuf3, ptr, data->ioc_inllen3);
393 ptr += __ALIGN_KERNEL(data->ioc_inllen3, 8);
396 if (data->ioc_inlbuf4) {
397 memcpy(data->ioc_inlbuf4, ptr, data->ioc_inllen4);
398 ptr += __ALIGN_KERNEL(data->ioc_inllen4, 8);
405 * Verify the setstripe parameters before using.
406 * This is a pair method for comp_args_to_layout()/llapi_layout_sanity_cb()
407 * when just 1 component or a non-PFL layout is given.
409 * \param[in] param stripe parameters
410 * \param[in] pool_name pool name
411 * \param[in] fsname lustre FS name
414 * < 0, error code on failre
416 static int llapi_stripe_param_verify(const struct llapi_stripe_param *param,
417 const char **pool_name)
420 static int page_size;
423 if (page_size == 0) {
425 * 64 KB is the largest common page size (on ia64/PPC/ARM),
426 * but check the local page size just in case. The page_size
427 * will not change for the lifetime of this process at least.
429 page_size = LOV_MIN_STRIPE_SIZE;
430 if (getpagesize() > page_size) {
431 page_size = getpagesize();
432 llapi_err_noerrno(LLAPI_MSG_WARN,
433 "warning: page size (%u) larger than expected (%u)",
434 page_size, LOV_MIN_STRIPE_SIZE);
437 if (!llapi_stripe_size_is_aligned(param->lsp_stripe_size)) {
439 llapi_error(LLAPI_MSG_ERROR, rc,
440 "error: bad stripe_size %llu, must be an even multiple of %d bytes",
441 param->lsp_stripe_size, page_size);
444 if (!llapi_stripe_index_is_valid(param->lsp_stripe_offset)) {
446 llapi_error(LLAPI_MSG_ERROR, rc, "error: bad stripe offset %d",
447 param->lsp_stripe_offset);
450 if (llapi_stripe_size_is_too_big(param->lsp_stripe_size)) {
452 llapi_error(LLAPI_MSG_ERROR, rc,
453 "error: stripe size '%llu' over 4GB limit",
454 param->lsp_stripe_size);
458 count = param->lsp_stripe_count;
459 if (param->lsp_stripe_pattern == LOV_PATTERN_MDT) {
461 llapi_error(LLAPI_MSG_ERROR, rc,
462 "Invalid pattern: '-L mdt', must be specified "
466 if (!llapi_stripe_count_is_valid(count)) {
468 llapi_error(LLAPI_MSG_ERROR, rc,
469 "Invalid stripe count %d\n", count);
474 /* Make sure we have a good pool */
475 if (*pool_name != NULL) {
476 if (!llapi_pool_name_is_valid(pool_name)) {
478 llapi_error(LLAPI_MSG_ERROR, rc,
479 "Invalid Poolname '%s'", *pool_name);
489 int llapi_dir_stripe_limit_check(int stripe_offset, int stripe_count,
494 if (!llapi_dir_stripe_index_is_valid(stripe_offset)) {
496 llapi_error(LLAPI_MSG_ERROR, rc, "error: bad stripe offset %d",
500 if (!llapi_dir_stripe_count_is_valid(stripe_count)) {
502 llapi_error(LLAPI_MSG_ERROR, rc, "error: bad stripe count %d",
507 if (!llapi_dir_hash_type_is_valid(hash_type)) {
509 llapi_error(LLAPI_MSG_ERROR, rc, "error: bad hash type %d",
517 * Trim a trailing newline from a string, if it exists.
519 int llapi_chomp_string(char *buf)
535 * Wrapper to grab parameter settings for lov.*-clilov-*.* values
537 static int get_param_lov(const char *path, const char *param,
538 char *buf, size_t buf_size)
540 struct obd_uuid uuid;
543 rc = llapi_file_get_lov_uuid(path, &uuid);
547 return get_lustre_param_value("lov", uuid.uuid, FILTER_BY_EXACT, param,
552 * Wrapper to grab parameter settings for lmv.*-clilov-*.* values
554 static int get_param_lmv(const char *path, const char *param,
555 char *buf, size_t buf_size)
557 struct obd_uuid uuid;
560 rc = llapi_file_get_lmv_uuid(path, &uuid);
564 return get_lustre_param_value("lmv", uuid.uuid, FILTER_BY_EXACT, param,
568 static int get_mds_md_size(const char *path)
570 int md_size = lov_user_md_size(LOV_MAX_STRIPE_COUNT, LOV_USER_MAGIC_V3);
573 * Rather than open the file and do the ioctl to get the
574 * instance name and close the file and search for the param
575 * file and open the param file and read the param file and
576 * parse the value and close the param file, let's just return
577 * a large enough value. It's 2020, RAM is cheap and this is
581 if (md_size < XATTR_SIZE_MAX)
582 md_size = XATTR_SIZE_MAX;
587 int llapi_get_agent_uuid(char *path, char *buf, size_t bufsize)
589 return get_param_lmv(path, "uuid", buf, bufsize);
593 * Open a Lustre file.
595 * \param name the name of the file to be opened
596 * \param flags access mode, see flags in open(2)
597 * \param mode permission of the file if it is created, see mode in open(2)
598 * \param param stripe pattern of the newly created file
600 * \retval file descriptor of opened file
601 * \retval negative errno on failure
603 int llapi_file_open_param(const char *name, int flags, mode_t mode,
604 const struct llapi_stripe_param *param)
606 struct lov_user_md *lum = NULL;
607 const char *pool_name = param->lsp_pool;
611 /* Check if the stripe pattern is sane. */
612 rc = llapi_stripe_param_verify(param, &pool_name);
616 if (param->lsp_is_specific)
617 lum_size = lov_user_md_size(param->lsp_stripe_count,
618 LOV_USER_MAGIC_SPECIFIC);
620 lum_size = sizeof(struct lov_user_md_v3);
622 lum_size = sizeof(*lum);
624 lum = calloc(1, lum_size);
629 fd = open(name, flags | O_LOV_DELAY_CREATE, mode);
631 if (errno == EISDIR && !(flags & O_DIRECTORY)) {
632 flags = O_DIRECTORY | O_RDONLY;
639 llapi_error(LLAPI_MSG_ERROR, rc, "unable to open '%s'", name);
644 /* Initialize IOCTL striping pattern structure */
645 lum->lmm_magic = LOV_USER_MAGIC_V1;
646 lum->lmm_pattern = param->lsp_stripe_pattern;
647 lum->lmm_stripe_size = param->lsp_stripe_size;
648 lum->lmm_stripe_count = param->lsp_stripe_count;
649 lum->lmm_stripe_offset = param->lsp_stripe_offset;
650 if (pool_name != NULL) {
651 struct lov_user_md_v3 *lumv3 = (void *)lum;
653 lumv3->lmm_magic = LOV_USER_MAGIC_V3;
654 strncpy(lumv3->lmm_pool_name, pool_name, LOV_MAXPOOLNAME);
656 if (param->lsp_is_specific) {
657 struct lov_user_md_v3 *lumv3 = (void *)lum;
660 lumv3->lmm_magic = LOV_USER_MAGIC_SPECIFIC;
661 if (pool_name == NULL) {
663 * LOV_USER_MAGIC_SPECIFIC uses v3 format plus specified
664 * OST list, therefore if pool is not specified we have
665 * to pack a null pool name for placeholder.
667 memset(lumv3->lmm_pool_name, 0, LOV_MAXPOOLNAME);
670 for (i = 0; i < param->lsp_stripe_count; i++)
671 lumv3->lmm_objects[i].l_ost_idx = param->lsp_osts[i];
674 if (ioctl(fd, LL_IOC_LOV_SETSTRIPE, lum) != 0) {
675 char errmsg[512] = "stripe already set";
678 if (errno != EEXIST && errno != EALREADY)
679 strncpy(errmsg, strerror(errno), sizeof(errmsg) - 1);
680 if (rc == -EREMOTEIO)
681 snprintf(errmsg, sizeof(errmsg),
682 "inactive OST among your specified %d OST(s)",
683 param->lsp_stripe_count);
685 llapi_err_noerrno(LLAPI_MSG_ERROR,
686 "setstripe error for '%s': %s", name, errmsg);
697 int llapi_file_is_encrypted(int fd)
702 rc = ioctl(fd, FS_IOC_GETFLAGS, &flags);
706 return !!(flags & LUSTRE_ENCRYPT_FL);
709 int llapi_file_open_pool(const char *name, int flags, int mode,
710 unsigned long long stripe_size, int stripe_offset,
711 int stripe_count, int stripe_pattern, char *pool_name)
713 const struct llapi_stripe_param param = {
714 .lsp_stripe_size = stripe_size,
715 .lsp_stripe_count = stripe_count,
716 .lsp_stripe_pattern = stripe_pattern,
717 .lsp_stripe_offset = stripe_offset,
718 .lsp_pool = pool_name
720 return llapi_file_open_param(name, flags, mode, ¶m);
723 int llapi_file_open(const char *name, int flags, int mode,
724 unsigned long long stripe_size, int stripe_offset,
725 int stripe_count, int stripe_pattern)
727 return llapi_file_open_pool(name, flags, mode, stripe_size,
728 stripe_offset, stripe_count,
729 stripe_pattern, NULL);
732 int llapi_file_create_foreign(const char *name, mode_t mode, __u32 type,
733 __u32 flags, char *foreign_lov)
736 struct lov_foreign_md *lfm;
739 if (foreign_lov == NULL) {
741 llapi_error(LLAPI_MSG_ERROR, rc,
742 "foreign LOV EA content must be provided");
746 len = strlen(foreign_lov);
747 if (len > XATTR_SIZE_MAX - offsetof(struct lov_foreign_md, lfm_value) ||
750 llapi_error(LLAPI_MSG_ERROR, rc,
751 "foreign LOV EA size %zu (must be 0 < len < %zu)",
752 len, XATTR_SIZE_MAX -
753 offsetof(struct lov_foreign_md, lfm_value));
757 lfm = malloc(len + offsetof(struct lov_foreign_md, lfm_value));
760 llapi_error(LLAPI_MSG_ERROR, rc,
761 "failed to allocate lov_foreign_md");
765 fd = open(name, O_WRONLY|O_CREAT|O_LOV_DELAY_CREATE, mode);
768 llapi_error(LLAPI_MSG_ERROR, fd, "open '%s' failed", name);
772 lfm->lfm_magic = LOV_USER_MAGIC_FOREIGN;
773 lfm->lfm_length = len;
774 lfm->lfm_type = type;
775 lfm->lfm_flags = flags;
776 memcpy(lfm->lfm_value, foreign_lov, len);
778 if (ioctl(fd, LL_IOC_LOV_SETSTRIPE, lfm) != 0) {
779 char *errmsg = "stripe already set";
783 errmsg = "not on a Lustre filesystem";
784 else if (errno == EEXIST || errno == EALREADY)
785 errmsg = "stripe already set";
787 errmsg = strerror(errno);
789 llapi_err_noerrno(LLAPI_MSG_ERROR,
790 "setstripe error for '%s': %s", name, errmsg);
806 int llapi_file_create(const char *name, unsigned long long stripe_size,
807 int stripe_offset, int stripe_count, int stripe_pattern)
811 fd = llapi_file_open_pool(name, O_CREAT | O_WRONLY, 0644, stripe_size,
812 stripe_offset, stripe_count, stripe_pattern,
821 int llapi_file_create_pool(const char *name, unsigned long long stripe_size,
822 int stripe_offset, int stripe_count,
823 int stripe_pattern, char *pool_name)
827 fd = llapi_file_open_pool(name, O_CREAT | O_WRONLY, 0644, stripe_size,
828 stripe_offset, stripe_count, stripe_pattern,
837 static int verify_dir_param(const char *name,
838 const struct llapi_stripe_param *param)
840 char fsname[MAX_OBD_NAME + 1] = { 0 };
841 char *pool_name = param->lsp_pool;
844 /* Make sure we are on a Lustre file system */
845 rc = llapi_search_fsname(name, fsname);
847 llapi_error(LLAPI_MSG_ERROR, rc,
848 "'%s' is not on a Lustre filesystem",
853 /* Check if the stripe pattern is sane. */
854 rc = llapi_dir_stripe_limit_check(param->lsp_stripe_offset,
855 param->lsp_stripe_count,
856 param->lsp_stripe_pattern);
860 /* Make sure we have a good pool */
861 if (pool_name != NULL) {
863 * in case user gives the full pool name <fsname>.<poolname>,
866 char *ptr = strchr(pool_name, '.');
870 if (strcmp(pool_name, fsname) != 0) {
872 llapi_err_noerrno(LLAPI_MSG_ERROR,
873 "Pool '%s' is not on filesystem '%s'",
880 /* Make sure the pool exists and is non-empty */
881 rc = llapi_search_tgt(fsname, pool_name, NULL, true);
883 char *err = rc == 0 ? "has no OSTs" : "does not exist";
885 llapi_err_noerrno(LLAPI_MSG_ERROR, "pool '%s.%s' %s",
886 fsname, pool_name, err);
891 /* sanity check of target list */
892 if (param->lsp_is_specific) {
893 char mdtname[MAX_OBD_NAME + 64];
897 for (i = 0; i < param->lsp_stripe_count; i++) {
898 snprintf(mdtname, sizeof(mdtname), "%s-MDT%04x_UUID",
899 fsname, param->lsp_tgts[i]);
900 rc = llapi_search_tgt(fsname, pool_name, mdtname, true);
905 llapi_error(LLAPI_MSG_ERROR, rc,
906 "%s: cannot find MDT %s in %s",
913 /* Make sure stripe offset is in MDT list. */
914 if (param->lsp_tgts[i] == param->lsp_stripe_offset)
918 llapi_error(LLAPI_MSG_ERROR, -EINVAL,
919 "%s: stripe offset '%d' is not in the target list",
920 __func__, param->lsp_stripe_offset);
928 static inline void param2lmu(struct lmv_user_md *lmu,
929 const struct llapi_stripe_param *param)
931 lmu->lum_magic = param->lsp_is_specific ? LMV_USER_MAGIC_SPECIFIC :
933 lmu->lum_stripe_count = param->lsp_stripe_count;
934 lmu->lum_stripe_offset = param->lsp_stripe_offset;
935 lmu->lum_hash_type = param->lsp_stripe_pattern;
936 lmu->lum_max_inherit = param->lsp_max_inherit;
937 lmu->lum_max_inherit_rr = param->lsp_max_inherit_rr;
938 if (param->lsp_pool != NULL)
939 strncpy(lmu->lum_pool_name, param->lsp_pool, LOV_MAXPOOLNAME);
940 if (param->lsp_is_specific) {
943 for (i = 0; i < param->lsp_stripe_count; i++)
944 lmu->lum_objects[i].lum_mds = param->lsp_tgts[i];
948 int llapi_dir_set_default_lmv(const char *name,
949 const struct llapi_stripe_param *param)
951 struct lmv_user_md lmu = { 0 };
955 rc = verify_dir_param(name, param);
959 /* TODO: default lmv doesn't support specific targets yet */
960 if (param->lsp_is_specific)
963 param2lmu(&lmu, param);
965 fd = open(name, O_DIRECTORY | O_RDONLY);
968 llapi_error(LLAPI_MSG_ERROR, rc, "unable to open '%s'", name);
972 rc = ioctl(fd, LL_IOC_LMV_SET_DEFAULT_STRIPE, &lmu);
974 char *errmsg = "stripe already set";
977 if (errno != EEXIST && errno != EALREADY)
978 errmsg = strerror(errno);
980 llapi_err_noerrno(LLAPI_MSG_ERROR,
981 "default dirstripe error on '%s': %s",
988 int llapi_dir_set_default_lmv_stripe(const char *name, int stripe_offset,
989 int stripe_count, int stripe_pattern,
990 const char *pool_name)
992 const struct llapi_stripe_param param = {
993 .lsp_stripe_count = stripe_count,
994 .lsp_stripe_offset = stripe_offset,
995 .lsp_stripe_pattern = stripe_pattern,
996 .lsp_pool = (char *)pool_name
999 return llapi_dir_set_default_lmv(name, ¶m);
1003 * Create a Lustre directory.
1005 * \param name the name of the directory to be created
1006 * \param mode permission of the file if it is created, see mode in open(2)
1007 * \param param stripe pattern of the newly created directory
1009 * \retval 0 on success
1010 * \retval negative errno on failure
1012 int llapi_dir_create(const char *name, mode_t mode,
1013 const struct llapi_stripe_param *param)
1015 struct lmv_user_md *lmu = NULL;
1017 struct obd_ioctl_data data = { 0 };
1020 char *dirpath = NULL;
1021 char *namepath = NULL;
1026 rc = verify_dir_param(name, param);
1030 lmu_size = lmv_user_md_size(param->lsp_stripe_count,
1031 param->lsp_is_specific ?
1032 LMV_USER_MAGIC_SPECIFIC :
1035 lmu = calloc(1, lmu_size);
1039 dirpath = strdup(name);
1045 namepath = strdup(name);
1052 param2lmu(lmu, param);
1054 filename = basename(namepath);
1055 dir = dirname(dirpath);
1057 data.ioc_inlbuf1 = (char *)filename;
1058 data.ioc_inllen1 = strlen(filename) + 1;
1059 data.ioc_inlbuf2 = (char *)lmu;
1060 data.ioc_inllen2 = lmu_size;
1061 data.ioc_type = mode;
1062 if (param->lsp_is_create)
1063 /* borrow obdo1.o_flags to store this flag */
1064 data.ioc_obdo1.o_flags = OBD_FL_OBDMDEXISTS;
1065 rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
1067 llapi_error(LLAPI_MSG_ERROR, rc,
1068 "error: LL_IOC_LMV_SETSTRIPE pack failed '%s'.",
1073 fd = open(dir, O_DIRECTORY | O_RDONLY);
1076 llapi_error(LLAPI_MSG_ERROR, rc, "unable to open '%s'", name);
1080 if (ioctl(fd, LL_IOC_LMV_SETSTRIPE, buf)) {
1081 char *errmsg = "stripe already set";
1084 if (errno != EEXIST && errno != EALREADY)
1085 errmsg = strerror(errno);
1087 llapi_err_noerrno(LLAPI_MSG_ERROR,
1088 "dirstripe error on '%s': %s", name, errmsg);
1099 * Create a foreign directory.
1101 * \param name the name of the directory to be created
1102 * \param mode permission of the file if it is created, see mode in open(2)
1103 * \param type foreign type to be set in LMV EA
1104 * \param flags foreign flags to be set in LMV EA
1105 * \param value foreign pattern to be set in LMV EA
1107 * \retval 0 on success
1108 * \retval negative errno on failure
1110 int llapi_dir_create_foreign(const char *name, mode_t mode, __u32 type,
1111 __u32 flags, const char *value)
1113 struct lmv_foreign_md *lfm = NULL;
1114 size_t lfm_size, len;
1115 struct obd_ioctl_data data = { 0 };
1118 char *dirpath = NULL;
1119 char *namepath = NULL;
1124 len = strlen(value);
1125 if (len > XATTR_SIZE_MAX - offsetof(struct lmv_foreign_md, lfm_value) ||
1128 llapi_error(LLAPI_MSG_ERROR, rc,
1129 "invalid LOV EA length %zu (must be 0 < len < %zu)",
1130 len, XATTR_SIZE_MAX -
1131 offsetof(struct lmv_foreign_md, lfm_value));
1134 lfm_size = len + offsetof(struct lmv_foreign_md, lfm_value);
1135 lfm = calloc(1, lfm_size);
1139 dirpath = strdup(name);
1145 namepath = strdup(name);
1152 lfm->lfm_magic = LMV_MAGIC_FOREIGN;
1153 lfm->lfm_length = len;
1154 lfm->lfm_type = type;
1155 lfm->lfm_flags = flags;
1156 memcpy(lfm->lfm_value, value, len);
1158 filename = basename(namepath);
1159 dir = dirname(dirpath);
1161 data.ioc_inlbuf1 = (char *)filename;
1162 data.ioc_inllen1 = strlen(filename) + 1;
1163 data.ioc_inlbuf2 = (char *)lfm;
1164 data.ioc_inllen2 = lfm_size;
1165 data.ioc_type = mode;
1166 rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
1168 llapi_error(LLAPI_MSG_ERROR, rc,
1169 "error: LL_IOC_LMV_SETSTRIPE pack failed '%s'.",
1174 fd = open(dir, O_DIRECTORY | O_RDONLY);
1177 llapi_error(LLAPI_MSG_ERROR, rc, "unable to open '%s'", name);
1181 if (ioctl(fd, LL_IOC_LMV_SETSTRIPE, buf)) {
1182 char *errmsg = "stripe already set";
1185 if (errno != EEXIST && errno != EALREADY)
1186 errmsg = strerror(errno);
1188 llapi_err_noerrno(LLAPI_MSG_ERROR,
1189 "dirstripe error on '%s': %s", name, errmsg);
1199 int llapi_dir_create_pool(const char *name, int mode, int stripe_offset,
1200 int stripe_count, int stripe_pattern,
1201 const char *pool_name)
1203 const struct llapi_stripe_param param = {
1204 .lsp_stripe_count = stripe_count,
1205 .lsp_stripe_offset = stripe_offset,
1206 .lsp_stripe_pattern = stripe_pattern,
1207 .lsp_pool = (char *)pool_name
1210 return llapi_dir_create(name, mode, ¶m);
1213 static int get_file_dev(const char *path, dev_t *dev)
1220 if (statx(AT_FDCWD, path, 0, 0, &stx))
1222 *dev = makedev(stx.stx_dev_major, stx.stx_dev_minor);
1228 if (stat(path, &st) != 0)
1236 static int get_root_fd(const char *rootpath, int *outfd)
1241 fd = open(rootpath, O_RDONLY | O_DIRECTORY | O_NONBLOCK);
1244 llapi_error(LLAPI_MSG_ERROR, rc,
1245 "cannot open '%s'", rootpath);
1255 char fsname[PATH_MAX];
1256 char mnt_dir[PATH_MAX];
1257 } root_cached = { 0 };
1259 static pthread_rwlock_t root_cached_lock = PTHREAD_RWLOCK_INITIALIZER;
1261 static int get_root_path_fast(int want, char *fsname, int *outfd, char *path,
1268 pthread_rwlock_rdlock(&root_cached_lock);
1269 if (root_cached.dev == 0)
1272 fsnamelen = strlen(root_cached.fsname);
1273 mntlen = strlen(root_cached.mnt_dir);
1275 /* Check the fsname for a match, if given */
1276 if (!(want & WANT_FSNAME) && fsname &&
1277 strlen(fsname) == fsnamelen &&
1278 (strncmp(root_cached.fsname, fsname, fsnamelen) == 0)) {
1280 /* Check the dev for a match, if given */
1281 } else if (!(want & WANT_DEV) && dev && *dev == root_cached.dev) {
1283 /* Otherwise find the longest matching path */
1284 } else if (path && strlen(path) >= mntlen &&
1285 (strncmp(root_cached.mnt_dir, path, mntlen) == 0) &&
1286 (strlen(path) == mntlen || path[mntlen] == '/')) {
1293 if ((want & WANT_FSNAME) && fsname)
1294 strcpy(fsname, root_cached.fsname);
1295 if ((want & WANT_PATH) && path)
1296 strcpy(path, root_cached.mnt_dir);
1297 if ((want & WANT_DEV) && dev)
1298 *dev = root_cached.dev;
1299 if ((want & WANT_FD) && outfd)
1300 rc = get_root_fd(root_cached.mnt_dir, outfd);
1303 pthread_rwlock_unlock(&root_cached_lock);
1307 static int get_root_path_slow(int want, char *fsname, int *outfd, char *path,
1308 int index, dev_t *dev)
1312 char *ptr, *ptr_end;
1314 int idx = -1, mntlen = 0;
1319 /* get the mount point */
1320 fp = setmntent(PROC_MOUNTS, "r");
1323 llapi_error(LLAPI_MSG_ERROR, rc,
1324 "cannot retrieve filesystem mount point");
1327 while (getmntent_r(fp, &mnt, buf, sizeof(buf))) {
1329 if (!llapi_is_lustre_mnt(&mnt))
1333 mntlen = strlen(mnt.mnt_dir);
1334 ptr = strchr(mnt.mnt_fsname, '/');
1335 while (ptr && *ptr == '/')
1338 * thanks to the call to llapi_is_lustre_mnt() above,
1339 * we are sure that mnt.mnt_fsname contains ":/",
1340 * so ptr should never be NULL
1345 while (*ptr_end != '/' && *ptr_end != '\0')
1348 fsnamelen = ptr_end - ptr;
1350 /* ignore unaccessible filesystem */
1351 if (get_file_dev(mnt.mnt_dir, &devmnt))
1354 if ((want & WANT_INDEX) && idx == index) {
1359 /* Check the fsname for a match, if given */
1360 if (!(want & WANT_FSNAME) && fsname &&
1361 strlen(fsname) == fsnamelen &&
1362 (strncmp(ptr, fsname, fsnamelen) == 0)) {
1367 /* Check the dev for a match, if given */
1368 if (!(want & WANT_DEV) && dev && *dev == devmnt) {
1373 /* Otherwise find the longest matching path */
1374 if (path && strlen(path) >= mntlen &&
1375 (strncmp(mnt.mnt_dir, path, mntlen) == 0) &&
1376 (strlen(path) == mntlen || path[mntlen] == '/')) {
1386 if (!(want & WANT_INDEX)) {
1387 /* Cache the mount point information */
1388 pthread_rwlock_wrlock(&root_cached_lock);
1390 strncpy(root_cached.fsname, ptr, fsnamelen);
1391 root_cached.fsname[fsnamelen] = '\0';
1392 strncpy(root_cached.mnt_dir, mnt.mnt_dir, mntlen);
1393 root_cached.mnt_dir[mntlen] = '\0';
1394 root_cached.dev = devmnt;
1396 pthread_rwlock_unlock(&root_cached_lock);
1399 if ((want & WANT_FSNAME) && fsname) {
1400 strncpy(fsname, ptr, fsnamelen);
1401 fsname[fsnamelen] = '\0';
1403 if ((want & WANT_PATH) && path) {
1404 strncpy(path, mnt.mnt_dir, mntlen);
1405 path[mntlen] = '\0';
1407 if ((want & WANT_DEV) && dev)
1409 if ((want & WANT_FD) && outfd)
1410 rc = get_root_fd(mnt.mnt_dir, outfd);
1418 * Find the fsname, the full path, and/or an open fd.
1419 * Either the fsname or path must not be NULL
1421 int get_root_path(int want, char *fsname, int *outfd, char *path, int index,
1426 if (!(want & WANT_INDEX))
1427 rc = get_root_path_fast(want, fsname, outfd, path, dev);
1429 rc = get_root_path_slow(want, fsname, outfd, path, index, dev);
1431 if (!rc || !(want & WANT_ERROR))
1434 if (dev || !(want & WANT_DEV))
1435 llapi_err_noerrno(LLAPI_MSG_ERROR,
1436 "'%u/%u' dev not on a mounted Lustre filesystem",
1437 major(*dev), minor(*dev));
1439 llapi_err_noerrno(LLAPI_MSG_ERROR,
1440 "'%s' not on a mounted Lustre filesystem",
1441 (want & WANT_PATH) ? fsname : path);
1446 * search lustre mounts
1448 * Calling this function will return to the user the mount point, mntdir, and
1449 * the file system name, fsname, if the user passed a buffer to this routine.
1451 * The user inputs are pathname and index. If the pathname is supplied then
1452 * the value of the index will be ignored. The pathname will return data if
1453 * the pathname is located on a lustre mount. Index is used to pick which
1454 * mount point you want in the case of multiple mounted lustre file systems.
1455 * See function lfs_osts in lfs.c for an example of the index use.
1457 int llapi_search_mounts(const char *pathname, int index, char *mntdir,
1460 int want = WANT_PATH, idx = -1;
1462 if (!pathname || pathname[0] == '\0') {
1466 strcpy(mntdir, pathname);
1470 want |= WANT_FSNAME;
1471 return get_root_path(want, fsname, NULL, mntdir, idx, NULL);
1474 /* Given a path, find the corresponding Lustre fsname */
1475 int llapi_search_fsname(const char *pathname, char *fsname)
1480 rc = get_file_dev(pathname, &dev);
1486 /* file does not exist try the parent */
1487 len = readlink(pathname, tmp, PATH_MAX);
1491 strncpy(tmp, pathname, PATH_MAX - 1);
1493 parent = dirname(tmp);
1494 rc = get_file_dev(parent, &dev);
1498 llapi_error(LLAPI_MSG_ERROR, rc,
1499 "cannot resolve path '%s'", pathname);
1503 rc = get_root_path(WANT_FSNAME | WANT_ERROR, fsname, NULL, NULL, -1,
1509 int llapi_search_rootpath(char *pathname, const char *fsname)
1515 * pathname can be used as an argument by get_root_path(),
1516 * clear it for safety
1519 return get_root_path(WANT_PATH, (char *)fsname, NULL, pathname, -1,
1523 int llapi_search_rootpath_by_dev(char *pathname, dev_t dev)
1529 * pathname can be used as an argument by get_root_path(),
1530 * clear it for safety
1533 return get_root_path(WANT_PATH, NULL, NULL, pathname, -1, &dev);
1537 * Get the list of pool members.
1538 * \param poolname string of format \<fsname\>.\<poolname\>
1539 * \param members caller-allocated array of char*
1540 * \param list_size size of the members array
1541 * \param buffer caller-allocated buffer for storing OST names
1542 * \param buffer_size size of the buffer
1544 * \return number of members retrieved for this pool
1545 * \retval -error failure
1547 int llapi_get_poolmembers(const char *poolname, char **members,
1548 int list_size, char *buffer, int buffer_size)
1550 char fsname[PATH_MAX];
1559 /* name is FSNAME.POOLNAME */
1560 if (strlen(poolname) >= sizeof(fsname))
1563 snprintf(fsname, sizeof(fsname), "%s", poolname);
1564 pool = strchr(fsname, '.');
1571 rc = poolpath(&pathname, fsname, NULL);
1573 llapi_error(LLAPI_MSG_ERROR, rc,
1574 "Lustre filesystem '%s' not found",
1579 llapi_printf(LLAPI_MSG_NORMAL, "Pool: %s.%s\n", fsname, pool);
1580 rc = snprintf(buf, sizeof(buf), "%s/%s", pathname.gl_pathv[0], pool);
1581 cfs_free_param_data(&pathname);
1582 if (rc >= sizeof(buf))
1584 fd = fopen(buf, "r");
1587 llapi_error(LLAPI_MSG_ERROR, rc, "cannot open %s", buf);
1592 while (fgets(buf, sizeof(buf), fd) != NULL) {
1593 if (nb_entries >= list_size) {
1597 buf[sizeof(buf) - 1] = '\0';
1599 tmp = strchr(buf, '\n');
1602 if (used + strlen(buf) + 1 > buffer_size) {
1607 strcpy(buffer + used, buf);
1608 members[nb_entries] = buffer + used;
1609 used += strlen(buf) + 1;
1619 * Get the list of pools in a filesystem.
1620 * \param name filesystem name or path
1621 * \param poollist caller-allocated array of char*
1622 * \param list_size size of the poollist array
1623 * \param buffer caller-allocated buffer for storing pool names
1624 * \param buffer_size size of the buffer
1626 * \return number of pools retrieved for this filesystem
1627 * \retval -error failure
1629 int llapi_get_poollist(const char *name, char **poollist, int list_size,
1630 char *buffer, int buffer_size)
1636 struct dirent *pool;
1638 unsigned int nb_entries = 0;
1639 unsigned int used = 0;
1642 /* initialize output array */
1643 for (i = 0; i < list_size; i++)
1646 /* is name a pathname ? */
1647 ptr = strchr(name, '/');
1649 char fsname_buf[MAXNAMLEN];
1651 /* We will need fsname for printing later */
1652 rc = llapi_getname(name, fsname_buf, sizeof(fsname_buf));
1656 ptr = strrchr(fsname_buf, '-');
1660 fsname = strdup(fsname_buf);
1664 /* name is FSNAME */
1665 fsname = strdup(name);
1670 rc = poolpath(&pathname, fsname, NULL);
1672 llapi_error(LLAPI_MSG_ERROR, rc,
1673 "Lustre filesystem '%s' not found", name);
1677 dir = opendir(pathname.gl_pathv[0]);
1680 llapi_error(LLAPI_MSG_ERROR, rc,
1681 "Could not open pool list for '%s'",
1688 pool = readdir(dir);
1694 /* ignore . and .. */
1695 if (!strcmp(pool->d_name, ".") || !strcmp(pool->d_name, ".."))
1698 /* check output bounds */
1699 if (nb_entries >= list_size) {
1701 goto free_dir_no_msg;
1704 /* +2 for '.' and final '\0' */
1705 if (used + strlen(pool->d_name) + strlen(fsname) + 2
1708 goto free_dir_no_msg;
1711 sprintf(buffer + used, "%s.%s", fsname, pool->d_name);
1712 poollist[nb_entries] = buffer + used;
1713 used += strlen(pool->d_name) + strlen(fsname) + 2;
1719 llapi_error(LLAPI_MSG_ERROR, rc,
1720 "Error reading pool list for '%s'", name);
1722 llapi_printf(LLAPI_MSG_NORMAL, "Pools from %s:\n", fsname);
1727 cfs_free_param_data(&pathname);
1730 return rc != 0 ? rc : nb_entries;
1733 /* wrapper for lfs.c and obd.c */
1734 int llapi_poollist(const char *name)
1736 int poolcount, rc, i;
1739 rc = llapi_get_poolbuf(name, &buf, &pools, &poolcount);
1743 for (i = 0; i < poolcount; i++)
1744 llapi_printf(LLAPI_MSG_NORMAL, "%s\n", pools[i]);
1751 * Get buffer that holds uuids and the list of pools in a filesystem.
1753 * \param name filesystem name or path
1754 * \param buf bufffer that has to be freed if function returns 0
1755 * \param pools pointer to the list of pools in buffer
1756 * \param poolcount number of pools
1758 * \return 0 when found at least 1 pool, i.e. poolcount > 0
1759 * \retval -error failure
1761 int llapi_get_poolbuf(const char *name, char **buf,
1762 char ***pools, int *poolcount)
1765 * list of pool names (assume that pool count is smaller
1768 char **list, *buffer = NULL, *fsname = (char *)name;
1769 char *poolname = NULL, *tmp = NULL, data[16];
1770 enum param_filter type = FILTER_BY_PATH;
1771 int obdcount, bufsize, rc, nb;
1776 if (name[0] != '/') {
1777 fsname = strdup(name);
1781 poolname = strchr(fsname, '.');
1784 type = FILTER_BY_FS_NAME;
1787 rc = get_lustre_param_value("lov", fsname, type, "numobd",
1788 data, sizeof(data));
1791 obdcount = atoi(data);
1794 * Allocate space for each fsname-OST0000_UUID, 1 per OST,
1795 * and also an array to store the pointers for all that
1799 bufsize = sizeof(struct obd_uuid) * obdcount;
1800 buffer = realloc(tmp, bufsize + sizeof(*list) * obdcount);
1801 if (buffer == NULL) {
1805 list = (char **) (buffer + bufsize);
1808 /* name is a path or fsname */
1809 nb = llapi_get_poollist(name, list, obdcount,
1812 /* name is a pool name (<fsname>.<poolname>) */
1813 nb = llapi_get_poolmembers(name, list, obdcount,
1817 if (nb == -EOVERFLOW) {
1820 goto retry_get_pools;
1823 rc = (nb < 0 ? nb : 0);
1830 /* Don't free buffer, it will be used later */
1833 if (fsname != NULL && type == FILTER_BY_FS_NAME)
1838 typedef int (semantic_func_t)(char *path, int p, int *d,
1839 void *data, struct dirent64 *de);
1841 #define OBD_NOT_FOUND (-1)
1843 static bool lmv_is_foreign(__u32 magic)
1845 return magic == LMV_MAGIC_FOREIGN;
1848 static void find_param_fini(struct find_param *param)
1850 if (param->fp_migrate)
1853 if (param->fp_obd_indexes) {
1854 free(param->fp_obd_indexes);
1855 param->fp_obd_indexes = NULL;
1858 if (param->fp_lmd) {
1859 free(param->fp_lmd);
1860 param->fp_lmd = NULL;
1863 if (param->fp_lmv_md) {
1864 free(param->fp_lmv_md);
1865 param->fp_lmv_md = NULL;
1869 static int common_param_init(struct find_param *param, char *path)
1871 int lum_size = get_mds_md_size(path);
1876 /* migrate has fp_lmv_md initialized outside */
1877 if (param->fp_migrate)
1880 if (lum_size < PATH_MAX + 1)
1881 lum_size = PATH_MAX + 1;
1883 param->fp_lum_size = lum_size;
1884 param->fp_lmd = calloc(1, offsetof(typeof(*param->fp_lmd), lmd_lmm) +
1886 if (param->fp_lmd == NULL) {
1887 llapi_error(LLAPI_MSG_ERROR, -ENOMEM,
1888 "error: allocate %zu bytes for layout failed",
1889 sizeof(lstat_t) + param->fp_lum_size);
1893 param->fp_lmv_stripe_count = 256;
1894 param->fp_lmv_md = calloc(1,
1895 lmv_user_md_size(param->fp_lmv_stripe_count,
1896 LMV_USER_MAGIC_SPECIFIC));
1897 if (param->fp_lmv_md == NULL) {
1898 llapi_error(LLAPI_MSG_ERROR, -ENOMEM,
1899 "error: allocation of %d bytes for ioctl",
1900 lmv_user_md_size(param->fp_lmv_stripe_count,
1901 LMV_USER_MAGIC_SPECIFIC));
1902 find_param_fini(param);
1906 param->fp_got_uuids = 0;
1907 param->fp_obd_indexes = NULL;
1908 param->fp_obd_index = OBD_NOT_FOUND;
1909 param->fp_mdt_index = OBD_NOT_FOUND;
1913 static int cb_common_fini(char *path, int p, int *dp, void *data,
1914 struct dirent64 *de)
1916 struct find_param *param = data;
1922 /* set errno upon failure */
1923 static int open_parent(const char *path)
1929 path_copy = strdup(path);
1930 if (path_copy == NULL)
1933 parent_path = dirname(path_copy);
1934 parent = open(parent_path, O_RDONLY|O_NDELAY|O_DIRECTORY);
1940 static int cb_get_dirstripe(char *path, int *d, struct find_param *param)
1943 bool did_nofollow = false;
1948 param->fp_lmv_md->lum_stripe_count = param->fp_lmv_stripe_count;
1949 if (param->fp_get_default_lmv) {
1953 /* open() may not fetch LOOKUP lock, statx() to ensure dir depth
1956 statx(*d, "", AT_EMPTY_PATH, STATX_MODE, &stx);
1962 param->fp_lmv_md->lum_magic = LMV_USER_MAGIC;
1964 param->fp_lmv_md->lum_magic = LMV_MAGIC_V1;
1967 ret = ioctl(*d, LL_IOC_LMV_GETSTRIPE, param->fp_lmv_md);
1969 /* if ENOTTY likely to be a fake symlink, so try again after
1970 * new open() with O_NOFOLLOW, but only once to prevent any
1971 * loop like for the path of a file/dir not on Lustre !!
1973 if (ret < 0 && errno == ENOTTY && !did_nofollow) {
1976 did_nofollow = true;
1977 fd = open(path, O_RDONLY | O_NOFOLLOW);
1979 /* restore original errno */
1984 /* close original fd and set new */
1987 ret2 = ioctl(fd, LL_IOC_LMV_GETSTRIPE, param->fp_lmv_md);
1988 if (ret2 < 0 && errno != E2BIG) {
1989 /* restore original errno */
1993 /* LMV is ok or need to handle E2BIG case now */
1997 if (errno == E2BIG && ret != 0) {
2001 /* if foreign LMV case, fake stripes number */
2002 if (lmv_is_foreign(param->fp_lmv_md->lum_magic)) {
2003 struct lmv_foreign_md *lfm;
2005 lfm = (struct lmv_foreign_md *)param->fp_lmv_md;
2006 if (lfm->lfm_length < XATTR_SIZE_MAX -
2007 offsetof(typeof(*lfm), lfm_value)) {
2008 uint32_t size = lfm->lfm_length +
2009 offsetof(typeof(*lfm), lfm_value);
2011 stripe_count = lmv_foreign_to_md_stripes(size);
2013 llapi_error(LLAPI_MSG_ERROR, -EINVAL,
2014 "error: invalid %d foreign size returned from ioctl",
2019 stripe_count = param->fp_lmv_md->lum_stripe_count;
2021 if (stripe_count <= param->fp_lmv_stripe_count)
2024 free(param->fp_lmv_md);
2025 param->fp_lmv_stripe_count = stripe_count;
2026 lmv_size = lmv_user_md_size(stripe_count,
2027 LMV_USER_MAGIC_SPECIFIC);
2028 param->fp_lmv_md = malloc(lmv_size);
2029 if (param->fp_lmv_md == NULL) {
2030 llapi_error(LLAPI_MSG_ERROR, -ENOMEM,
2031 "error: allocation of %d bytes for ioctl",
2032 lmv_user_md_size(param->fp_lmv_stripe_count,
2033 LMV_USER_MAGIC_SPECIFIC));
2042 static void convert_lmd_statx(struct lov_user_mds_data *lmd_v2, lstat_t *st,
2045 memset(&lmd_v2->lmd_stx, 0, sizeof(lmd_v2->lmd_stx));
2046 lmd_v2->lmd_stx.stx_blksize = st->st_blksize;
2047 lmd_v2->lmd_stx.stx_nlink = st->st_nlink;
2048 lmd_v2->lmd_stx.stx_uid = st->st_uid;
2049 lmd_v2->lmd_stx.stx_gid = st->st_gid;
2050 lmd_v2->lmd_stx.stx_mode = st->st_mode;
2051 lmd_v2->lmd_stx.stx_ino = st->st_ino;
2052 lmd_v2->lmd_stx.stx_size = st->st_size;
2053 lmd_v2->lmd_stx.stx_blocks = st->st_blocks;
2054 lmd_v2->lmd_stx.stx_atime.tv_sec = st->st_atime;
2055 lmd_v2->lmd_stx.stx_ctime.tv_sec = st->st_ctime;
2056 lmd_v2->lmd_stx.stx_mtime.tv_sec = st->st_mtime;
2057 lmd_v2->lmd_stx.stx_rdev_major = major(st->st_rdev);
2058 lmd_v2->lmd_stx.stx_rdev_minor = minor(st->st_rdev);
2059 lmd_v2->lmd_stx.stx_dev_major = major(st->st_dev);
2060 lmd_v2->lmd_stx.stx_dev_minor = minor(st->st_dev);
2061 lmd_v2->lmd_stx.stx_mask |= STATX_BASIC_STATS;
2063 lmd_v2->lmd_flags = 0;
2065 lmd_v2->lmd_flags |= OBD_MD_FLSIZE | OBD_MD_FLBLOCKS;
2067 lmd_v2->lmd_stx.stx_mask &= ~(STATX_SIZE | STATX_BLOCKS);
2068 if (lmd_v2->lmd_stx.stx_size)
2069 lmd_v2->lmd_flags |= OBD_MD_FLLAZYSIZE;
2070 if (lmd_v2->lmd_stx.stx_blocks)
2071 lmd_v2->lmd_flags |= OBD_MD_FLLAZYBLOCKS;
2073 lmd_v2->lmd_flags |= OBD_MD_FLATIME | OBD_MD_FLMTIME | OBD_MD_FLCTIME |
2074 OBD_MD_FLBLKSZ | OBD_MD_FLMODE | OBD_MD_FLTYPE |
2075 OBD_MD_FLUID | OBD_MD_FLGID | OBD_MD_FLNLINK |
2080 static int convert_lmdbuf_v1v2(void *lmdbuf, int lmdlen)
2082 struct lov_user_mds_data_v1 *lmd_v1 = lmdbuf;
2083 struct lov_user_mds_data *lmd_v2 = lmdbuf;
2087 size = lov_comp_md_size((struct lov_comp_md_v1 *)&lmd_v1->lmd_lmm);
2091 if (lmdlen < sizeof(lmd_v1->lmd_st) + size)
2094 st = lmd_v1->lmd_st;
2095 memmove(&lmd_v2->lmd_lmm, &lmd_v1->lmd_lmm,
2096 lmdlen - (&lmd_v2->lmd_lmm - &lmd_v1->lmd_lmm));
2097 convert_lmd_statx(lmd_v2, &st, false);
2098 lmd_v2->lmd_lmmsize = 0;
2099 lmd_v2->lmd_padding = 0;
2104 int get_lmd_info_fd(const char *path, int parent_fd, int dir_fd,
2105 void *lmdbuf, int lmdlen, enum get_lmd_info_type type)
2107 struct lov_user_mds_data *lmd = lmdbuf;
2108 static bool use_old_ioctl;
2112 if (parent_fd < 0 && dir_fd < 0)
2114 if (type != GET_LMD_INFO && type != GET_LMD_STRIPE)
2119 * LL_IOC_MDC_GETINFO operates on the current directory inode
2120 * and returns struct lov_user_mds_data, while
2121 * LL_IOC_LOV_GETSTRIPE returns only struct lov_user_md.
2123 if (type == GET_LMD_INFO)
2124 cmd = use_old_ioctl ? LL_IOC_MDC_GETINFO_V1 :
2125 LL_IOC_MDC_GETINFO_V2;
2127 cmd = LL_IOC_LOV_GETSTRIPE;
2130 ret = ioctl(dir_fd, cmd, lmdbuf);
2131 if (ret < 0 && errno == ENOTTY &&
2132 cmd == LL_IOC_MDC_GETINFO_V2) {
2133 cmd = LL_IOC_MDC_GETINFO_V1;
2134 use_old_ioctl = true;
2138 if (cmd == LL_IOC_MDC_GETINFO_V1 && !ret)
2139 ret = convert_lmdbuf_v1v2(lmdbuf, lmdlen);
2141 if (ret < 0 && errno == ENOTTY && type == GET_LMD_STRIPE) {
2144 /* retry ioctl() after new open() with O_NOFOLLOW
2145 * just in case it could be a fake symlink
2146 * need using a new open() as dir_fd is being closed
2150 dir_fd2 = open(path, O_RDONLY | O_NDELAY | O_NOFOLLOW);
2152 /* return original error */
2155 ret = ioctl(dir_fd2, cmd, lmdbuf);
2156 /* pass new errno or success back to caller */
2162 } else if (parent_fd >= 0) {
2163 const char *fname = strrchr(path, '/');
2166 * IOC_MDC_GETFILEINFO takes as input the filename (relative to
2167 * the parent directory) and returns struct lov_user_mds_data,
2168 * while IOC_MDC_GETFILESTRIPE returns only struct lov_user_md.
2170 * This avoids opening, locking, and closing each file on the
2171 * client if that is not needed. Multiple of these ioctl() can
2172 * be done on the parent dir with a single open for all
2173 * files in that directory, and it also doesn't pollute the
2174 * client dcache with millions of dentries when traversing
2175 * a large filesystem.
2177 fname = (fname == NULL ? path : fname + 1);
2179 ret = snprintf(lmdbuf, lmdlen, "%s", fname);
2182 else if (ret >= lmdlen || ret++ == 0)
2185 if (type == GET_LMD_INFO)
2186 cmd = use_old_ioctl ? IOC_MDC_GETFILEINFO_V1 :
2187 IOC_MDC_GETFILEINFO_V2;
2189 cmd = IOC_MDC_GETFILESTRIPE;
2192 ret = ioctl(parent_fd, cmd, lmdbuf);
2193 if (ret < 0 && errno == ENOTTY &&
2194 cmd == IOC_MDC_GETFILEINFO_V2) {
2195 cmd = IOC_MDC_GETFILEINFO_V1;
2196 use_old_ioctl = true;
2197 goto retry_getfileinfo;
2200 if (cmd == IOC_MDC_GETFILEINFO_V1 && !ret)
2201 ret = convert_lmdbuf_v1v2(lmdbuf, lmdlen);
2205 if (ret && type == GET_LMD_INFO) {
2206 if (errno == ENOTTY) {
2210 * ioctl is not supported, it is not a lustre fs.
2211 * Do the regular lstat(2) instead.
2213 ret = lstat_f(path, &st);
2216 llapi_error(LLAPI_MSG_ERROR, ret,
2217 "error: %s: lstat failed for %s",
2221 convert_lmd_statx(lmd, &st, true);
2223 * It may be wrong to set use_old_ioctl with true as
2224 * the file is not a lustre fs. So reset it with false
2227 use_old_ioctl = false;
2228 } else if (errno == ENOENT) {
2230 llapi_error(LLAPI_MSG_WARN, ret,
2231 "warning: %s does not exist", path);
2232 } else if (errno != EISDIR && errno != ENODATA) {
2234 llapi_error(LLAPI_MSG_ERROR, ret,
2235 "%s ioctl failed for %s.",
2236 dir_fd >= 0 ? "LL_IOC_MDC_GETINFO" :
2237 "IOC_MDC_GETFILEINFO", path);
2244 static int llapi_semantic_traverse(char *path, int size, int parent,
2245 semantic_func_t sem_init,
2246 semantic_func_t sem_fini, void *data,
2247 struct dirent64 *de)
2249 struct find_param *param = (struct find_param *)data;
2250 struct dirent64 *dent;
2251 int len, ret, d, p = -1;
2257 d = open(path, O_RDONLY|O_NDELAY|O_DIRECTORY);
2258 /* if an invalid fake dir symlink, opendir() will return EINVAL
2259 * instead of ENOTDIR. If a valid but dangling faked or real file/dir
2260 * symlink ENOENT will be returned. For a valid/resolved fake or real
2261 * file symlink ENOTDIR will be returned as for a regular file.
2262 * opendir() will be successful for a valid and resolved fake or real
2263 * dir simlink or a regular dir.
2265 if (d == -1 && errno != ENOTDIR && errno != EINVAL && errno != ENOENT) {
2267 llapi_error(LLAPI_MSG_ERROR, ret, "%s: Failed to open '%s'",
2270 } else if (d == -1) {
2271 if (errno == ENOENT || errno == EINVAL) {
2272 int old_errno = errno;
2274 /* try to open with O_NOFOLLOW this will help
2275 * differentiate fake vs real symlinks
2276 * it is ok to not use O_DIRECTORY with O_RDONLY
2277 * and it will prevent the need to deal with ENOTDIR
2278 * error, instead of ELOOP, being returned by recent
2279 * kernels for real symlinks
2281 d = open(path, O_RDONLY|O_NDELAY|O_NOFOLLOW);
2282 /* if a dangling real symlink should return ELOOP, or
2283 * again ENOENT if really non-existing path, or E...??
2284 * So return original error. If success or ENOTDIR, path
2285 * is likely to be a fake dir/file symlink, so continue
2295 if (parent == -1 && d == -1) {
2296 /* Open the parent dir. */
2297 p = open_parent(path);
2303 } else { /* d != -1 */
2306 /* try to reopen dir with O_NOFOLLOW just in case of a foreign
2309 d2 = open(path, O_RDONLY|O_NDELAY|O_NOFOLLOW);
2314 /* continue with d */
2320 ret = sem_init(path, (parent != -1) ? parent : p, &d, data, de);
2330 /* ENOTDIR if fake symlink, do not consider it as an error */
2331 if (errno != ENOTDIR)
2332 llapi_error(LLAPI_MSG_ERROR, errno,
2333 "fdopendir() failed");
2340 while ((dent = readdir64(dir)) != NULL) {
2343 if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
2347 if ((len + dent->d_reclen + 2) > size) {
2348 llapi_err_noerrno(LLAPI_MSG_ERROR,
2349 "error: %s: string buffer too small for %s",
2354 strcat(path, dent->d_name);
2356 if (dent->d_type == DT_UNKNOWN) {
2357 struct lov_user_mds_data *lmd = param->fp_lmd;
2359 rc = get_lmd_info_fd(path, d, -1, param->fp_lmd,
2360 param->fp_lum_size, GET_LMD_INFO);
2362 dent->d_type = IFTODT(lmd->lmd_stx.stx_mode);
2369 switch (dent->d_type) {
2371 llapi_err_noerrno(LLAPI_MSG_ERROR,
2372 "error: %s: '%s' is UNKNOWN type %d",
2373 __func__, dent->d_name, dent->d_type);
2376 rc = llapi_semantic_traverse(path, size, d, sem_init,
2377 sem_fini, data, dent);
2378 if (rc != 0 && ret == 0)
2380 if (rc < 0 && rc != -EALREADY &&
2381 param->fp_stop_on_error)
2387 rc = sem_init(path, d, NULL, data, dent);
2388 if (rc < 0 && ret == 0) {
2390 if (rc && rc != -EALREADY &&
2391 param->fp_stop_on_error)
2396 if (sem_fini && rc == 0)
2397 sem_fini(path, d, NULL, data, dent);
2405 sem_fini(path, parent, &d, data, de);
2418 static int param_callback(char *path, semantic_func_t sem_init,
2419 semantic_func_t sem_fini, struct find_param *param)
2421 int ret, len = strlen(path);
2424 if (len > PATH_MAX) {
2426 llapi_error(LLAPI_MSG_ERROR, ret,
2427 "Path name '%s' is too long", path);
2431 buf = (char *)malloc(2 * PATH_MAX);
2435 snprintf(buf, PATH_MAX + 1, "%s", path);
2436 ret = common_param_init(param, buf);
2440 param->fp_depth = 0;
2442 ret = llapi_semantic_traverse(buf, 2 * PATH_MAX, -1, sem_init,
2443 sem_fini, param, NULL);
2445 find_param_fini(param);
2447 return ret < 0 ? ret : 0;
2450 int llapi_file_fget_lov_uuid(int fd, struct obd_uuid *lov_name)
2454 rc = ioctl(fd, OBD_IOC_GETDTNAME, lov_name);
2455 if (rc && errno == ENOTTY)
2456 rc = ioctl(fd, OBD_IOC_GETNAME_OLD, lov_name);
2459 llapi_error(LLAPI_MSG_ERROR, rc, "cannot get lov name");
2465 int llapi_file_fget_lmv_uuid(int fd, struct obd_uuid *lov_name)
2469 rc = ioctl(fd, OBD_IOC_GETMDNAME, lov_name);
2472 llapi_error(LLAPI_MSG_ERROR, rc, "error: can't get lmv name.");
2478 int llapi_file_get_lov_uuid(const char *path, struct obd_uuid *lov_uuid)
2482 /* do not follow faked symlinks */
2483 fd = open(path, O_RDONLY | O_NONBLOCK | O_NOFOLLOW);
2485 /* real symlink should have failed with ELOOP so retry without
2486 * O_NOFOLLOW just in case
2488 fd = open(path, O_RDONLY | O_NONBLOCK);
2491 llapi_error(LLAPI_MSG_ERROR, rc, "cannot open '%s'",
2497 rc = llapi_file_fget_lov_uuid(fd, lov_uuid);
2503 int llapi_file_get_lmv_uuid(const char *path, struct obd_uuid *lov_uuid)
2507 fd = open(path, O_RDONLY | O_NONBLOCK);
2510 llapi_error(LLAPI_MSG_ERROR, rc, "error opening %s", path);
2514 rc = llapi_file_fget_lmv_uuid(fd, lov_uuid);
2526 * If uuidp is NULL, return the number of available obd uuids.
2527 * If uuidp is non-NULL, then it will return the uuids of the obds. If
2528 * there are more OSTs than allocated to uuidp, then an error is returned with
2529 * the ost_count set to number of available obd uuids.
2531 static int llapi_get_target_uuids(int fd, struct obd_uuid *uuidp,
2532 int *ost_count, enum tgt_type type)
2534 char buf[PATH_MAX], format[32];
2535 int rc = 0, index = 0;
2536 struct obd_uuid name;
2540 /* Get the lov name */
2541 if (type == LOV_TYPE)
2542 rc = llapi_file_fget_lov_uuid(fd, &name);
2544 rc = llapi_file_fget_lmv_uuid(fd, &name);
2548 /* Now get the ost uuids */
2549 rc = get_lustre_param_path(type == LOV_TYPE ? "lov" : "lmv", name.uuid,
2550 FILTER_BY_EXACT, "target_obd", ¶m);
2554 fp = fopen(param.gl_pathv[0], "r");
2557 llapi_error(LLAPI_MSG_ERROR, rc, "error: opening '%s'",
2562 snprintf(format, sizeof(format),
2563 "%%d: %%%zus", sizeof(uuidp[0].uuid) - 1);
2564 while (fgets(buf, sizeof(buf), fp) != NULL) {
2565 if (uuidp && (index < *ost_count)) {
2566 if (sscanf(buf, format, &index, uuidp[index].uuid) < 2)
2574 if (uuidp && (index > *ost_count))
2579 cfs_free_param_data(¶m);
2583 int llapi_lov_get_uuids(int fd, struct obd_uuid *uuidp, int *ost_count)
2585 return llapi_get_target_uuids(fd, uuidp, ost_count, LOV_TYPE);
2588 int llapi_get_obd_count(char *mnt, int *count, int is_mdt)
2593 root = open(mnt, O_RDONLY | O_DIRECTORY);
2596 llapi_error(LLAPI_MSG_ERROR, rc, "open %s failed", mnt);
2601 rc = ioctl(root, LL_IOC_GETOBDCOUNT, count);
2610 * Check if user specified value matches a real uuid. Ignore _UUID,
2611 * -osc-4ba41334, other trailing gunk in comparison.
2612 * @param real_uuid ends in "_UUID"
2613 * @param search_uuid may or may not end in "_UUID"
2615 int llapi_uuid_match(char *real_uuid, char *search_uuid)
2617 int cmplen = strlen(real_uuid);
2618 int searchlen = strlen(search_uuid);
2620 if (cmplen > 5 && strcmp(real_uuid + cmplen - 5, "_UUID") == 0)
2622 if (searchlen > 5 && strcmp(search_uuid + searchlen - 5, "_UUID") == 0)
2626 * The UUIDs may legitimately be different lengths, if
2627 * the system was upgraded from an older version.
2629 if (cmplen != searchlen)
2632 return (strncmp(search_uuid, real_uuid, cmplen) == 0);
2636 * Here, param->fp_obd_uuid points to a single obduuid, the index of which is
2637 * returned in param->fp_obd_index
2639 static int setup_obd_uuid(int fd, char *dname, struct find_param *param)
2641 struct obd_uuid obd_uuid;
2648 if (param->fp_got_uuids)
2651 /* Get the lov/lmv name */
2652 if (param->fp_get_lmv)
2653 rc = llapi_file_fget_lmv_uuid(fd, &obd_uuid);
2655 rc = llapi_file_fget_lov_uuid(fd, &obd_uuid);
2657 if (rc != -ENOTTY) {
2658 llapi_error(LLAPI_MSG_ERROR, rc,
2659 "error: can't get %s name: %s",
2660 param->fp_get_lmv ? "lmv" : "lov",
2668 param->fp_got_uuids = 1;
2670 /* Now get the ost uuids */
2671 rc = get_lustre_param_path(param->fp_get_lmv ? "lmv" : "lov",
2672 obd_uuid.uuid, FILTER_BY_EXACT,
2673 "target_obd", ¶m_data);
2677 fp = fopen(param_data.gl_pathv[0], "r");
2680 llapi_error(LLAPI_MSG_ERROR, rc, "error: opening '%s'",
2681 param_data.gl_pathv[0]);
2685 if (!param->fp_obd_uuid && !param->fp_quiet && !param->fp_obds_printed)
2686 llapi_printf(LLAPI_MSG_NORMAL, "%s:\n",
2687 param->fp_get_lmv ? "MDTS" : "OBDS");
2689 snprintf(format, sizeof(format),
2690 "%%d: %%%zus", sizeof(obd_uuid.uuid) - 1);
2691 while (fgets(buf, sizeof(buf), fp) != NULL) {
2694 if (sscanf(buf, format, &index, obd_uuid.uuid) < 2)
2697 if (param->fp_obd_uuid) {
2698 if (llapi_uuid_match(obd_uuid.uuid,
2699 param->fp_obd_uuid->uuid)) {
2700 param->fp_obd_index = index;
2703 } else if (!param->fp_quiet && !param->fp_obds_printed) {
2704 /* Print everything */
2705 llapi_printf(LLAPI_MSG_NORMAL, "%s", buf);
2708 param->fp_obds_printed = 1;
2712 if (param->fp_obd_uuid && (param->fp_obd_index == OBD_NOT_FOUND)) {
2713 llapi_err_noerrno(LLAPI_MSG_ERROR,
2714 "error: %s: unknown obduuid: %s",
2715 __func__, param->fp_obd_uuid->uuid);
2719 cfs_free_param_data(¶m_data);
2724 * In this case, param->fp_obd_uuid will be an array of obduuids and
2725 * obd index for all these obduuids will be returned in
2726 * param->fp_obd_indexes
2728 static int setup_indexes(int d, char *path, struct obd_uuid *obduuids,
2729 int num_obds, int **obdindexes, int *obdindex,
2732 int ret, obdcount, obd_valid = 0, obdnum;
2734 struct obd_uuid *uuids = NULL;
2738 if (type == LOV_TYPE)
2739 ret = get_param_lov(path, "numobd", buf, sizeof(buf));
2741 ret = get_param_lmv(path, "numobd", buf, sizeof(buf));
2745 obdcount = atoi(buf);
2746 uuids = malloc(obdcount * sizeof(struct obd_uuid));
2751 ret = llapi_get_target_uuids(d, uuids, &obdcount, type);
2753 if (ret == -EOVERFLOW) {
2754 struct obd_uuid *uuids_temp;
2756 uuids_temp = realloc(uuids, obdcount *
2757 sizeof(struct obd_uuid));
2758 if (uuids_temp != NULL) {
2760 goto retry_get_uuids;
2765 llapi_error(LLAPI_MSG_ERROR, ret, "cannot get ost uuid");
2769 indexes = malloc(num_obds * sizeof(*obdindex));
2770 if (indexes == NULL) {
2775 for (obdnum = 0; obdnum < num_obds; obdnum++) {
2778 /* The user may have specified a simple index */
2779 i = strtol(obduuids[obdnum].uuid, &end, 0);
2780 if (end && *end == '\0' && i < obdcount) {
2781 indexes[obdnum] = i;
2784 for (i = 0; i < obdcount; i++) {
2785 if (llapi_uuid_match(uuids[i].uuid,
2786 obduuids[obdnum].uuid)) {
2787 indexes[obdnum] = i;
2793 if (i >= obdcount) {
2794 indexes[obdnum] = OBD_NOT_FOUND;
2795 llapi_err_noerrno(LLAPI_MSG_ERROR,
2796 "invalid obduuid '%s'",
2797 obduuids[obdnum].uuid);
2803 *obdindex = OBD_NOT_FOUND;
2805 *obdindex = obd_valid;
2807 *obdindexes = indexes;
2815 static int setup_target_indexes(int d, char *path, struct find_param *param)
2819 if (param->fp_mdt_uuid) {
2820 ret = setup_indexes(d, path, param->fp_mdt_uuid,
2822 ¶m->fp_mdt_indexes,
2823 ¶m->fp_mdt_index, LMV_TYPE);
2828 if (param->fp_obd_uuid) {
2829 ret = setup_indexes(d, path, param->fp_obd_uuid,
2831 ¶m->fp_obd_indexes,
2832 ¶m->fp_obd_index, LOV_TYPE);
2837 param->fp_got_uuids = 1;
2842 int llapi_ostlist(char *path, struct find_param *param)
2847 fd = open(path, O_RDONLY | O_DIRECTORY);
2851 ret = setup_obd_uuid(fd, path, param);
2858 * Tries to determine the default stripe attributes for a given filesystem. The
2859 * filesystem to check should be specified by fsname, or will be determined
2862 static int sattr_get_defaults(const char *const fsname,
2863 unsigned int *scount,
2864 unsigned int *ssize,
2865 unsigned int *soffset)
2871 rc = get_lustre_param_value("lov", fsname, FILTER_BY_FS_NAME,
2872 "stripecount", val, sizeof(val));
2875 *scount = atoi(val);
2879 rc = get_lustre_param_value("lov", fsname, FILTER_BY_FS_NAME,
2880 "stripesize", val, sizeof(val));
2887 rc = get_lustre_param_value("lov", fsname, FILTER_BY_FS_NAME,
2888 "stripeoffset", val, sizeof(val));
2891 *soffset = atoi(val);
2898 * Tries to gather the default stripe attributes for a given filesystem. If
2899 * the attributes can be determined, they are cached for easy retreival the
2900 * next time they are needed. Only a single filesystem's attributes are
2903 int sattr_cache_get_defaults(const char *const fsname,
2904 const char *const pathname, unsigned int *scount,
2905 unsigned int *ssize, unsigned int *soffset)
2908 char fsname[PATH_MAX + 1];
2909 unsigned int stripecount;
2910 unsigned int stripesize;
2911 unsigned int stripeoffset;
2917 char fsname_buf[PATH_MAX + 1];
2918 unsigned int tmp[3];
2920 if (fsname == NULL) {
2921 rc = llapi_search_fsname(pathname, fsname_buf);
2925 snprintf(fsname_buf, sizeof(fsname_buf), "%s", fsname);
2928 if (strncmp(fsname_buf, cache.fsname, sizeof(fsname_buf) - 1) != 0) {
2930 * Ensure all 3 sattrs (count, size, and offset) are
2931 * successfully retrieved and stored in tmp before writing to
2934 rc = sattr_get_defaults(fsname_buf, &tmp[0], &tmp[1], &tmp[2]);
2938 cache.stripecount = tmp[0];
2939 cache.stripesize = tmp[1];
2940 cache.stripeoffset = tmp[2];
2941 snprintf(cache.fsname, sizeof(cache.fsname), "%s", fsname_buf);
2945 *scount = cache.stripecount;
2947 *ssize = cache.stripesize;
2949 *soffset = cache.stripeoffset;
2954 static char *layout2name(__u32 layout_pattern)
2956 if (layout_pattern & LOV_PATTERN_F_RELEASED)
2958 else if (layout_pattern == LOV_PATTERN_MDT)
2960 else if (layout_pattern == LOV_PATTERN_RAID0)
2962 else if (layout_pattern ==
2963 (LOV_PATTERN_RAID0 | LOV_PATTERN_OVERSTRIPING))
2964 return "raid0,overstriped";
2969 enum lov_dump_flags {
2970 LDF_IS_DIR = 0x0001,
2971 LDF_IS_RAW = 0x0002,
2972 LDF_INDENT = 0x0004,
2973 LDF_SKIP_OBJS = 0x0008,
2975 LDF_EXTENSION = 0x0020,
2978 static void lov_dump_user_lmm_header(struct lov_user_md *lum, char *path,
2979 struct lov_user_ost_data_v1 *objects,
2980 enum llapi_layout_verbose verbose,
2981 int depth, char *pool_name,
2982 enum lov_dump_flags flags)
2984 bool is_dir = flags & LDF_IS_DIR;
2985 bool is_raw = flags & LDF_IS_RAW;
2986 bool indent = flags & LDF_INDENT;
2987 bool yaml = flags & LDF_YAML;
2988 bool skip_objs = flags & LDF_SKIP_OBJS;
2989 bool extension = flags & LDF_EXTENSION;
2990 char *prefix = is_dir ? "" : "lmm_";
2991 char *separator = "";
2992 char *space = indent ? " " : "";
2995 if (is_dir && lmm_oi_seq(&lum->lmm_oi) == FID_SEQ_LOV_DEFAULT) {
2996 lmm_oi_set_seq(&lum->lmm_oi, 0);
2997 if (!indent && (verbose & VERBOSE_DETAIL))
2998 llapi_printf(LLAPI_MSG_NORMAL, "%s(Default) ", space);
3001 if (!yaml && !indent && depth && path &&
3002 ((verbose != VERBOSE_OBJID) || !is_dir))
3003 llapi_printf(LLAPI_MSG_NORMAL, "%s\n", path);
3005 if ((verbose & VERBOSE_DETAIL) && !is_dir) {
3006 llapi_printf(LLAPI_MSG_NORMAL, "%s%smagic: 0x%08X\n",
3007 space, prefix, lum->lmm_magic);
3008 llapi_printf(LLAPI_MSG_NORMAL, "%s%sseq: %#jx\n",
3010 (uintmax_t)lmm_oi_seq(&lum->lmm_oi));
3011 llapi_printf(LLAPI_MSG_NORMAL, "%s%sobject_id: %#jx\n",
3013 (uintmax_t)lmm_oi_id(&lum->lmm_oi));
3016 if (verbose & (VERBOSE_DETAIL | VERBOSE_DFID)) {
3021 if (verbose & ~VERBOSE_DFID)
3022 llapi_printf(LLAPI_MSG_NORMAL, "%slmm_fid: ",
3026 struct lu_fid dir_fid;
3028 rc = llapi_path2fid(path, &dir_fid);
3030 llapi_error(LLAPI_MSG_ERROR, rc,
3031 "Cannot determine directory fid.");
3033 seq = dir_fid.f_seq;
3034 oid = dir_fid.f_oid;
3035 ver = dir_fid.f_ver;
3038 * This needs a bit of hand-holding since old 1.x
3039 * lmm_oi have { oi.oi_id = mds_inum, oi.oi_seq = 0 }
3040 * and 2.x lmm_oi have { oi.oi_id = mds_oid,
3041 * oi.oi_seq = mds_seq } instead of a real FID.
3042 * Ideally the 2.x code would have stored this like a
3043 * FID with { oi_id = mds_seq, oi_seq = mds_oid } so
3044 * the ostid union lu_fid { f_seq = mds_seq,
3045 * f_oid = mds_oid } worked properly (especially since
3046 * IGIF FIDs use mds_inum as the FID SEQ), but
3047 * unfortunately that didn't happen.
3049 * Print it to look like an IGIF FID, even though the
3050 * fields are reversed on disk, so that it makes sense
3053 * Don't use ostid_id() and ostid_seq(), since they
3054 * assume the oi_fid fields are in the right order.
3055 * This is why there are separate lmm_oi_seq() and
3056 * lmm_oi_id() routines for this.
3058 * For newer layout types hopefully this will be a
3061 seq = lmm_oi_seq(&lum->lmm_oi) == 0 ?
3062 lmm_oi_id(&lum->lmm_oi) :
3063 lmm_oi_seq(&lum->lmm_oi);
3064 oid = lmm_oi_seq(&lum->lmm_oi) == 0 ?
3065 0 : (__u32)lmm_oi_id(&lum->lmm_oi);
3066 ver = (__u32)(lmm_oi_id(&lum->lmm_oi) >> 32);
3070 llapi_printf(LLAPI_MSG_NORMAL, DFID_NOBRACE"\n",
3071 (unsigned long long)seq, oid, ver);
3073 llapi_printf(LLAPI_MSG_NORMAL, DFID"\n",
3074 (unsigned long long)seq, oid, ver);
3077 if (verbose & VERBOSE_STRIPE_COUNT) {
3078 if (verbose & ~VERBOSE_STRIPE_COUNT)
3079 llapi_printf(LLAPI_MSG_NORMAL, "%s%sstripe_count: ",
3082 if (!is_raw && lum->lmm_stripe_count == 0 &&
3083 lov_pattern(lum->lmm_pattern) != LOV_PATTERN_MDT) {
3084 unsigned int scount;
3086 rc = sattr_cache_get_defaults(NULL, path,
3090 llapi_printf(LLAPI_MSG_NORMAL, "%d",
3093 llapi_error(LLAPI_MSG_ERROR, rc,
3094 "Cannot determine default stripe count.");
3096 llapi_printf(LLAPI_MSG_NORMAL, "%d",
3098 (__s16)lum->lmm_stripe_count);
3101 llapi_printf(LLAPI_MSG_NORMAL, "%hd",
3103 (__s16)lum->lmm_stripe_count);
3105 if (!yaml && is_dir)
3111 if (((verbose & VERBOSE_STRIPE_SIZE) && !extension) ||
3112 ((verbose & VERBOSE_EXT_SIZE) && extension)) {
3113 llapi_printf(LLAPI_MSG_NORMAL, "%s", separator);
3114 if (verbose & ~VERBOSE_EXT_SIZE && extension)
3115 llapi_printf(LLAPI_MSG_NORMAL, "%s%sextension_size: ",
3117 if (verbose & ~VERBOSE_STRIPE_SIZE && !extension)
3118 llapi_printf(LLAPI_MSG_NORMAL, "%s%sstripe_size: ",
3120 if (is_dir && !is_raw && lum->lmm_stripe_size == 0) {
3123 rc = sattr_cache_get_defaults(NULL, path, NULL, &ssize,
3126 llapi_printf(LLAPI_MSG_NORMAL, "%u", ssize);
3128 llapi_error(LLAPI_MSG_ERROR, rc,
3129 "Cannot determine default stripe size.");
3131 /* Extension size is in KiB */
3132 llapi_printf(LLAPI_MSG_NORMAL, "%llu",
3134 (unsigned long long)(lum->lmm_stripe_size * SEL_UNIT_SIZE) :
3135 (unsigned long long)lum->lmm_stripe_size);
3137 if (!yaml && is_dir)
3143 if ((verbose & VERBOSE_PATTERN)) {
3144 llapi_printf(LLAPI_MSG_NORMAL, "%s", separator);
3145 if (verbose & ~VERBOSE_PATTERN)
3146 llapi_printf(LLAPI_MSG_NORMAL, "%s%spattern: ",
3148 if (lov_pattern_supported(lum->lmm_pattern))
3149 llapi_printf(LLAPI_MSG_NORMAL, "%s",
3150 layout2name(lum->lmm_pattern));
3152 llapi_printf(LLAPI_MSG_NORMAL, "%x", lum->lmm_pattern);
3153 separator = (!yaml && is_dir) ? " " : "\n";
3156 if ((verbose & VERBOSE_GENERATION) && !is_dir) {
3157 llapi_printf(LLAPI_MSG_NORMAL, "%s", separator);
3158 if (verbose & ~VERBOSE_GENERATION)
3159 llapi_printf(LLAPI_MSG_NORMAL, "%s%slayout_gen: ",
3161 llapi_printf(LLAPI_MSG_NORMAL, "%u",
3162 skip_objs ? 0 : (int)lum->lmm_layout_gen);
3166 if (verbose & VERBOSE_STRIPE_OFFSET) {
3167 llapi_printf(LLAPI_MSG_NORMAL, "%s", separator);
3168 if (verbose & ~VERBOSE_STRIPE_OFFSET)
3169 llapi_printf(LLAPI_MSG_NORMAL, "%s%sstripe_offset: ",
3171 if (is_dir || skip_objs)
3172 llapi_printf(LLAPI_MSG_NORMAL, "%d",
3173 lum->lmm_stripe_offset ==
3174 (typeof(lum->lmm_stripe_offset))(-1) ? -1 :
3175 lum->lmm_stripe_offset);
3176 else if (lov_pattern(lum->lmm_pattern) == LOV_PATTERN_MDT)
3177 llapi_printf(LLAPI_MSG_NORMAL, "0");
3179 llapi_printf(LLAPI_MSG_NORMAL, "%u",
3180 objects[0].l_ost_idx);
3181 if (!yaml && is_dir)
3187 if ((verbose & VERBOSE_POOL) && pool_name && (pool_name[0] != '\0')) {
3188 llapi_printf(LLAPI_MSG_NORMAL, "%s", separator);
3189 if (verbose & ~VERBOSE_POOL)
3190 llapi_printf(LLAPI_MSG_NORMAL, "%s%spool: ",
3192 llapi_printf(LLAPI_MSG_NORMAL, "%s", pool_name);
3193 if (!yaml && is_dir)
3199 if (strlen(separator) != 0)
3200 llapi_printf(LLAPI_MSG_NORMAL, "\n");
3203 void lov_dump_user_lmm_v1v3(struct lov_user_md *lum, char *pool_name,
3204 struct lov_user_ost_data_v1 *objects,
3205 char *path, int obdindex, int depth,
3206 enum llapi_layout_verbose verbose,
3207 enum lov_dump_flags flags)
3209 bool is_dir = flags & LDF_IS_DIR;
3210 bool indent = flags & LDF_INDENT;
3211 bool skip_objs = flags & LDF_SKIP_OBJS;
3212 bool yaml = flags & LDF_YAML;
3213 bool obdstripe = obdindex == OBD_NOT_FOUND;
3216 if (!obdstripe && !skip_objs) {
3217 for (i = 0; !is_dir && i < lum->lmm_stripe_count; i++) {
3218 if (obdindex == objects[i].l_ost_idx) {
3228 lov_dump_user_lmm_header(lum, path, objects, verbose, depth, pool_name,
3231 if (!is_dir && !skip_objs && (verbose & VERBOSE_OBJID) &&
3232 !(lum->lmm_pattern & LOV_PATTERN_F_RELEASED ||
3233 lov_pattern(lum->lmm_pattern) == LOV_PATTERN_MDT)) {
3234 char *space = " - ";
3237 llapi_printf(LLAPI_MSG_NORMAL,
3238 "%6slmm_objects:\n", " ");
3240 llapi_printf(LLAPI_MSG_NORMAL, "lmm_objects:\n");
3242 llapi_printf(LLAPI_MSG_NORMAL,
3243 "\tobdidx\t\t objid\t\t objid\t\t group\n");
3245 for (i = 0; i < lum->lmm_stripe_count; i++) {
3246 int idx = objects[i].l_ost_idx;
3247 long long oid = ostid_id(&objects[i].l_ost_oi);
3248 long long gr = ostid_seq(&objects[i].l_ost_oi);
3250 if (obdindex != OBD_NOT_FOUND && obdindex != idx)
3254 struct lu_fid fid = { 0 };
3256 ostid_to_fid(&fid, &objects[i].l_ost_oi, idx);
3257 llapi_printf(LLAPI_MSG_NORMAL,
3258 "%sl_ost_idx: %d\n", space, idx);
3259 llapi_printf(LLAPI_MSG_NORMAL,
3260 "%8sl_fid: "DFID_NOBRACE"\n",
3262 } else if (indent) {
3263 struct lu_fid fid = { 0 };
3265 ostid_to_fid(&fid, &objects[i].l_ost_oi, idx);
3266 llapi_printf(LLAPI_MSG_NORMAL,
3267 "%s%d: { l_ost_idx: %d, l_fid: "DFID" }\n",
3268 space, i, idx, PFID(&fid));
3272 sprintf(fmt, "%s%s%s\n",
3273 "\t%6u\t%14llu\t%#13llx\t",
3274 (fid_seq_is_rsvd(gr) ||
3275 fid_seq_is_mdt0(gr)) ?
3276 "%14llu" : "%#14llx", "%s");
3277 llapi_printf(LLAPI_MSG_NORMAL, fmt, idx, oid,
3279 obdindex == idx ? " *" : "");
3283 llapi_printf(LLAPI_MSG_NORMAL, "\n");
3286 void lmv_dump_user_lmm(struct lmv_user_md *lum, char *pool_name,
3287 char *path, int obdindex, int depth,
3288 enum llapi_layout_verbose verbose,
3289 enum lov_dump_flags flags)
3291 struct lmv_user_mds_data *objects = lum->lum_objects;
3292 char *prefix = lum->lum_magic == LMV_USER_MAGIC ? "(Default)" : "";
3293 char *separator = "";
3294 bool yaml = flags & LDF_YAML;
3295 bool obdstripe = false;
3298 if (obdindex != OBD_NOT_FOUND) {
3299 if (lum->lum_stripe_count == 0) {
3300 if (obdindex == lum->lum_stripe_offset)
3303 for (i = 0; i < lum->lum_stripe_count; i++) {
3304 if (obdindex == objects[i].lum_mds) {
3305 llapi_printf(LLAPI_MSG_NORMAL,
3320 /* show all information default */
3322 if (lum->lum_magic == LMV_USER_MAGIC)
3323 verbose = VERBOSE_POOL | VERBOSE_STRIPE_COUNT |
3324 VERBOSE_STRIPE_OFFSET | VERBOSE_HASH_TYPE;
3326 verbose = VERBOSE_OBJID;
3329 if (depth && path && ((verbose != VERBOSE_OBJID)))
3330 llapi_printf(LLAPI_MSG_NORMAL, "%s%s\n", prefix, path);
3332 if (verbose & VERBOSE_STRIPE_COUNT) {
3333 llapi_printf(LLAPI_MSG_NORMAL, "%s", separator);
3334 if (verbose & ~VERBOSE_STRIPE_COUNT)
3335 llapi_printf(LLAPI_MSG_NORMAL, "lmv_stripe_count: ");
3336 llapi_printf(LLAPI_MSG_NORMAL, "%d",
3337 (int)lum->lum_stripe_count);
3338 if ((verbose & VERBOSE_STRIPE_OFFSET) && !yaml)
3344 if (verbose & VERBOSE_STRIPE_OFFSET) {
3345 llapi_printf(LLAPI_MSG_NORMAL, "%s", separator);
3346 if (verbose & ~VERBOSE_STRIPE_OFFSET)
3347 llapi_printf(LLAPI_MSG_NORMAL, "lmv_stripe_offset: ");
3348 llapi_printf(LLAPI_MSG_NORMAL, "%d",
3349 (int)lum->lum_stripe_offset);
3350 if (verbose & VERBOSE_HASH_TYPE && !yaml)
3356 if (verbose & VERBOSE_HASH_TYPE) {
3357 unsigned int type = lum->lum_hash_type & LMV_HASH_TYPE_MASK;
3358 unsigned int flags = lum->lum_hash_type & ~LMV_HASH_TYPE_MASK;
3360 llapi_printf(LLAPI_MSG_NORMAL, "%s", separator);
3361 if (verbose & ~VERBOSE_HASH_TYPE)
3362 llapi_printf(LLAPI_MSG_NORMAL, "lmv_hash_type: ");
3363 if (type < LMV_HASH_TYPE_MAX)
3364 llapi_printf(LLAPI_MSG_NORMAL, "%s",
3365 mdt_hash_name[type]);
3367 llapi_printf(LLAPI_MSG_NORMAL, "%#x", type);
3369 if (flags & LMV_HASH_FLAG_MIGRATION)
3370 llapi_printf(LLAPI_MSG_NORMAL, ",migrating");
3371 if (flags & LMV_HASH_FLAG_BAD_TYPE)
3372 llapi_printf(LLAPI_MSG_NORMAL, ",bad_type");
3373 if (flags & LMV_HASH_FLAG_LOST_LMV)
3374 llapi_printf(LLAPI_MSG_NORMAL, ",lost_lmv");
3375 if (flags & LMV_HASH_FLAG_FIXED)
3376 llapi_printf(LLAPI_MSG_NORMAL, ",fixed");
3377 if (flags & ~LMV_HASH_FLAG_KNOWN)
3378 llapi_printf(LLAPI_MSG_NORMAL, ",unknown_%04x",
3379 flags & ~LMV_HASH_FLAG_KNOWN);
3381 if (verbose & VERBOSE_HASH_TYPE && !yaml)
3387 if ((verbose & VERBOSE_INHERIT) && lum->lum_magic == LMV_USER_MAGIC) {
3388 llapi_printf(LLAPI_MSG_NORMAL, "%s", separator);
3389 if (verbose & ~VERBOSE_INHERIT)
3390 llapi_printf(LLAPI_MSG_NORMAL, "lmv_max_inherit: ");
3391 if (lum->lum_max_inherit == LMV_INHERIT_UNLIMITED)
3392 llapi_printf(LLAPI_MSG_NORMAL, "-1");
3393 else if (lum->lum_max_inherit == LMV_INHERIT_NONE)
3394 llapi_printf(LLAPI_MSG_NORMAL, "0");
3396 llapi_printf(LLAPI_MSG_NORMAL, "%hhu",
3397 lum->lum_max_inherit);
3398 if (verbose & VERBOSE_INHERIT && !yaml)
3404 if ((verbose & VERBOSE_INHERIT_RR) &&
3405 lum->lum_magic == LMV_USER_MAGIC &&
3406 lum->lum_stripe_offset == LMV_OFFSET_DEFAULT) {
3407 llapi_printf(LLAPI_MSG_NORMAL, "%s", separator);
3408 if (verbose & ~VERBOSE_INHERIT_RR)
3409 llapi_printf(LLAPI_MSG_NORMAL, "lmv_max_inherit_rr: ");
3410 if (lum->lum_max_inherit_rr == LMV_INHERIT_RR_UNLIMITED)
3411 llapi_printf(LLAPI_MSG_NORMAL, "-1");
3412 else if (lum->lum_max_inherit_rr == LMV_INHERIT_RR_NONE)
3413 llapi_printf(LLAPI_MSG_NORMAL, "0");
3415 llapi_printf(LLAPI_MSG_NORMAL, "%hhu",
3416 lum->lum_max_inherit_rr);
3417 if (verbose & VERBOSE_INHERIT_RR && !yaml)
3425 if (verbose & VERBOSE_OBJID && lum->lum_magic != LMV_USER_MAGIC) {
3426 llapi_printf(LLAPI_MSG_NORMAL, "%s", separator);
3427 if (lum->lum_stripe_count > 0)
3428 llapi_printf(LLAPI_MSG_NORMAL,
3429 "mdtidx\t\t FID[seq:oid:ver]\n");
3430 for (i = 0; i < lum->lum_stripe_count; i++) {
3431 int idx = objects[i].lum_mds;
3432 struct lu_fid *fid = &objects[i].lum_fid;
3434 if ((obdindex == OBD_NOT_FOUND) || (obdindex == idx))
3435 llapi_printf(LLAPI_MSG_NORMAL,
3436 "%6u\t\t "DFID"\t\t%s\n",
3438 obdindex == idx ? " *" : "");
3442 if ((verbose & VERBOSE_POOL) && pool_name != NULL &&
3443 pool_name[0] != '\0') {
3444 llapi_printf(LLAPI_MSG_NORMAL, "%s", separator);
3445 if (verbose & ~VERBOSE_POOL)
3446 llapi_printf(LLAPI_MSG_NORMAL, "%slmv_pool: ",
3448 llapi_printf(LLAPI_MSG_NORMAL, "%s%c ", pool_name, ' ');
3452 if (!(verbose & VERBOSE_OBJID) || lum->lum_magic == LMV_USER_MAGIC)
3453 llapi_printf(LLAPI_MSG_NORMAL, "\n");
3456 static void lov_dump_comp_v1_header(struct find_param *param, char *path,
3457 enum lov_dump_flags flags)
3459 struct lov_comp_md_v1 *comp_v1 = (void *)¶m->fp_lmd->lmd_lmm;
3460 int depth = param->fp_max_depth;
3461 enum llapi_layout_verbose verbose = param->fp_verbose;
3462 bool yaml = flags & LDF_YAML;
3464 if (depth && path && ((verbose != VERBOSE_OBJID) ||
3465 !(flags & LDF_IS_DIR)) && !yaml)
3466 llapi_printf(LLAPI_MSG_NORMAL, "%s\n", path);
3468 if (verbose & VERBOSE_DETAIL) {
3469 llapi_printf(LLAPI_MSG_NORMAL, "composite_header:\n");
3470 llapi_printf(LLAPI_MSG_NORMAL, "%2slcm_magic: 0x%08X\n",
3471 " ", comp_v1->lcm_magic);
3472 llapi_printf(LLAPI_MSG_NORMAL, "%2slcm_size: %u\n",
3473 " ", comp_v1->lcm_size);
3474 if (flags & LDF_IS_DIR)
3475 llapi_printf(LLAPI_MSG_NORMAL,
3476 "%2slcm_flags: %s\n", " ",
3477 comp_v1->lcm_mirror_count > 0 ?
3480 llapi_printf(LLAPI_MSG_NORMAL,
3481 "%2slcm_flags: %s\n", " ",
3482 llapi_layout_flags_string(comp_v1->lcm_flags));
3485 if (verbose & VERBOSE_GENERATION) {
3486 if (verbose & ~VERBOSE_GENERATION)
3487 llapi_printf(LLAPI_MSG_NORMAL, "%2slcm_layout_gen: ",
3489 llapi_printf(LLAPI_MSG_NORMAL, "%u\n", comp_v1->lcm_layout_gen);
3492 if (verbose & VERBOSE_MIRROR_COUNT) {
3493 if (verbose & ~VERBOSE_MIRROR_COUNT)
3494 llapi_printf(LLAPI_MSG_NORMAL, "%2slcm_mirror_count: ",
3496 llapi_printf(LLAPI_MSG_NORMAL, "%u\n",
3497 comp_v1->lcm_magic == LOV_USER_MAGIC_COMP_V1 ?
3498 comp_v1->lcm_mirror_count + 1 : 1);
3501 if (verbose & VERBOSE_COMP_COUNT) {
3502 if (verbose & ~VERBOSE_COMP_COUNT)
3503 llapi_printf(LLAPI_MSG_NORMAL, "%2slcm_entry_count: ",
3505 llapi_printf(LLAPI_MSG_NORMAL, "%u\n",
3506 comp_v1->lcm_magic == LOV_USER_MAGIC_COMP_V1 ?
3507 comp_v1->lcm_entry_count : 0);
3510 if (verbose & VERBOSE_DETAIL && !yaml)
3511 llapi_printf(LLAPI_MSG_NORMAL, "components:\n");
3514 static void lcme_flags2str(__u32 comp_flags)
3520 llapi_printf(LLAPI_MSG_NORMAL, "0");
3523 for (i = 0; i < ARRAY_SIZE(comp_flags_table); i++) {
3524 if (comp_flags & comp_flags_table[i].cfn_flag) {
3526 llapi_printf(LLAPI_MSG_NORMAL, ",");
3527 llapi_printf(LLAPI_MSG_NORMAL, "%s",
3528 comp_flags_table[i].cfn_name);
3529 comp_flags &= ~comp_flags_table[i].cfn_flag;
3535 llapi_printf(LLAPI_MSG_NORMAL, ",");
3536 llapi_printf(LLAPI_MSG_NORMAL, "%#x", comp_flags);
3540 static void lov_dump_comp_v1_entry(struct find_param *param,
3541 enum lov_dump_flags flags, int index)
3543 struct lov_comp_md_v1 *comp_v1 = (void *)¶m->fp_lmd->lmd_lmm;
3544 struct lov_comp_md_entry_v1 *entry;
3545 char *separator = "";
3546 enum llapi_layout_verbose verbose = param->fp_verbose;
3547 bool yaml = flags & LDF_YAML;
3549 entry = &comp_v1->lcm_entries[index];
3552 llapi_printf(LLAPI_MSG_NORMAL, "%2scomponent%d:\n", " ", index);
3554 if (verbose & VERBOSE_COMP_ID) {
3555 if (verbose & VERBOSE_DETAIL && !yaml)
3556 llapi_printf(LLAPI_MSG_NORMAL,
3557 "%slcme_id: ", " - ");
3558 else if (verbose & ~VERBOSE_COMP_ID)
3559 llapi_printf(LLAPI_MSG_NORMAL,
3560 "%4slcme_id: ", " ");
3561 if (entry->lcme_id != LCME_ID_INVAL)
3562 llapi_printf(LLAPI_MSG_NORMAL, "%u", entry->lcme_id);
3564 llapi_printf(LLAPI_MSG_NORMAL, "N/A");
3568 if (verbose & VERBOSE_MIRROR_ID) {
3569 llapi_printf(LLAPI_MSG_NORMAL, "%s", separator);
3570 if (verbose & ~VERBOSE_MIRROR_ID)
3571 llapi_printf(LLAPI_MSG_NORMAL,
3572 "%4slcme_mirror_id: ", " ");
3573 if (entry->lcme_id != LCME_ID_INVAL)
3574 llapi_printf(LLAPI_MSG_NORMAL, "%u",
3575 mirror_id_of(entry->lcme_id));
3577 llapi_printf(LLAPI_MSG_NORMAL, "N/A");
3581 if (verbose & VERBOSE_COMP_FLAGS) {
3582 llapi_printf(LLAPI_MSG_NORMAL, "%s", separator);
3583 if (verbose & ~VERBOSE_COMP_FLAGS)
3584 llapi_printf(LLAPI_MSG_NORMAL,
3585 "%4slcme_flags: ", " ");
3586 lcme_flags2str(entry->lcme_flags);
3589 /* print snapshot timestamp if its a nosync comp */
3590 if ((verbose & VERBOSE_COMP_FLAGS) &&
3591 (entry->lcme_flags & LCME_FL_NOSYNC)) {
3592 llapi_printf(LLAPI_MSG_NORMAL, "%s", separator);
3593 if (verbose & ~VERBOSE_COMP_FLAGS)
3594 llapi_printf(LLAPI_MSG_NORMAL,
3595 "%4slcme_timestamp: ", " ");
3597 llapi_printf(LLAPI_MSG_NORMAL, "%llu",
3598 (unsigned long long)entry->lcme_timestamp);
3600 time_t stamp = entry->lcme_timestamp;
3601 char *date_str = asctime(localtime(&stamp));
3603 date_str[strlen(date_str) - 1] = '\0';
3604 llapi_printf(LLAPI_MSG_NORMAL, "'%s'", date_str);
3610 if (verbose & VERBOSE_COMP_START) {
3611 llapi_printf(LLAPI_MSG_NORMAL, "%s", separator);
3612 if (verbose & ~VERBOSE_COMP_START)
3613 llapi_printf(LLAPI_MSG_NORMAL,
3614 "%4slcme_extent.e_start: ", " ");
3615 llapi_printf(LLAPI_MSG_NORMAL, "%llu",
3616 (unsigned long long)entry->lcme_extent.e_start);
3620 if (verbose & VERBOSE_COMP_END) {
3621 llapi_printf(LLAPI_MSG_NORMAL, "%s", separator);
3622 if (verbose & ~VERBOSE_COMP_END)
3623 llapi_printf(LLAPI_MSG_NORMAL,
3624 "%4slcme_extent.e_end: ", " ");
3625 if (entry->lcme_extent.e_end == LUSTRE_EOF)
3626 llapi_printf(LLAPI_MSG_NORMAL, "%s", "EOF");
3628 llapi_printf(LLAPI_MSG_NORMAL, "%llu",
3629 (unsigned long long)entry->lcme_extent.e_end);
3634 llapi_printf(LLAPI_MSG_NORMAL, "%s", separator);
3635 llapi_printf(LLAPI_MSG_NORMAL, "%4ssub_layout:\n", " ");
3636 } else if (verbose & VERBOSE_DETAIL) {
3637 llapi_printf(LLAPI_MSG_NORMAL, "%s", separator);
3638 llapi_printf(LLAPI_MSG_NORMAL, "%4slcme_offset: %u\n",
3639 " ", entry->lcme_offset);
3640 llapi_printf(LLAPI_MSG_NORMAL, "%4slcme_size: %u\n",
3641 " ", entry->lcme_size);
3642 llapi_printf(LLAPI_MSG_NORMAL, "%4ssub_layout:\n", " ");
3644 llapi_printf(LLAPI_MSG_NORMAL, "%s", separator);
3649 * Check if the value matches 1 of the given criteria (e.g. --atime +/-N).
3650 * @mds indicates if this is MDS timestamps and there are attributes on OSTs.
3652 * The result is -1 if it does not match, 0 if not yet clear, 1 if matches.
3653 * The table below gives the answers for the specified parameters (value and
3654 * sign), 1st column is the answer for the MDS value, the 2nd is for the OST:
3655 * --------------------------------------
3656 * 1 | file > limit; sign > 0 | -1 / -1 |
3657 * 2 | file = limit; sign > 0 | -1 / -1 |
3658 * 3 | file < limit; sign > 0 | ? / 1 |
3659 * 4 | file > limit; sign = 0 | -1 / -1 |
3660 * 5 | file = limit; sign = 0 | ? / 1 | <- (see the Note below)
3661 * 6 | file < limit; sign = 0 | ? / -1 |
3662 * 7 | file > limit; sign < 0 | 1 / 1 |
3663 * 8 | file = limit; sign < 0 | ? / -1 |
3664 * 9 | file < limit; sign < 0 | ? / -1 |
3665 * --------------------------------------
3666 * Note: 5th actually means that the value is within the interval
3667 * (limit - margin, limit].
3669 static int find_value_cmp(unsigned long long file, unsigned long long limit,
3670 int sign, int negopt, unsigned long long margin,
3676 /* Drop the fraction of margin (of days or size). */
3677 if (file + margin <= limit)
3679 } else if (sign == 0) {
3680 if (file <= limit && file + margin > limit)
3682 else if (file + margin <= limit)
3684 } else if (sign < 0) {
3691 return negopt ? ~ret + 1 : ret;
3694 static inline struct lov_user_md *
3695 lov_comp_entry(struct lov_comp_md_v1 *comp_v1, int ent_idx)
3697 return (struct lov_user_md *)((char *)comp_v1 +
3698 comp_v1->lcm_entries[ent_idx].lcme_offset);
3701 static inline struct lov_user_ost_data_v1 *
3702 lov_v1v3_objects(struct lov_user_md *v1)
3704 if (v1->lmm_magic == LOV_USER_MAGIC_V3)
3705 return ((struct lov_user_md_v3 *)v1)->lmm_objects;
3707 return v1->lmm_objects;
3711 lov_v1v3_pool_name(struct lov_user_md *v1, char *pool_name)
3713 if (v1->lmm_magic == LOV_USER_MAGIC_V3)
3714 snprintf(pool_name, LOV_MAXPOOLNAME + 1, "%s",
3715 ((struct lov_user_md_v3 *)v1)->lmm_pool_name);
3717 pool_name[0] = '\0';
3721 print_last_init_comp(struct find_param *param)
3723 /* print all component info */
3724 if ((param->fp_verbose & VERBOSE_DEFAULT) == VERBOSE_DEFAULT)
3727 /* print specific component info */
3728 if (param->fp_check_comp_id || param->fp_check_comp_flags ||
3729 param->fp_check_comp_start || param->fp_check_comp_end ||
3730 param->fp_check_mirror_id || param->fp_check_mirror_index)
3736 static int find_comp_end_cmp(unsigned long long end, struct find_param *param)
3740 if (param->fp_comp_end == LUSTRE_EOF) {
3741 if (param->fp_comp_end_sign == 0) /* equal to EOF */
3742 match = end == LUSTRE_EOF ? 1 : -1;
3743 else if (param->fp_comp_end_sign > 0) /* at most EOF */
3744 match = end == LUSTRE_EOF ? -1 : 1;
3745 else /* at least EOF */
3747 if (param->fp_exclude_comp_end)
3750 unsigned long long margin;
3752 margin = end == LUSTRE_EOF ? 0 : param->fp_comp_end_units;
3753 match = find_value_cmp(end, param->fp_comp_end,
3754 param->fp_comp_end_sign,
3755 param->fp_exclude_comp_end, margin, 0);
3762 * An example of "getstripe -v" for a two components PFL file:
3765 * lcm_magic: 0x0BD60BD0
3769 * lcm_entry_count: 2
3773 * lcme_extent.e_start: 0
3774 * lcme_extent.e_end: 1048576
3778 * lmm_magic: 0x0BD10BD0
3779 * lmm_seq: 0x200000401
3780 * lmm_object_id: 0x1
3781 * lmm_fid: [0x200000401:0x1:0x0]
3782 * lmm_stripe_count: 1
3783 * lmm_stripe_size: 1048576
3784 * lmm_pattern: raid0
3786 * lmm_stripe_offset: 0
3788 * - 0: { l_ost_idx: 0, l_fid: [0x100000000:0x2:0x0] }
3792 * lcme_extent.e_start: 1048576
3793 * lcme_extent.e_end: EOF
3797 * lmm_magic: 0x0BD10BD0
3798 * lmm_seq: 0x200000401
3799 * lmm_object_id: 0x1
3800 * lmm_fid: [0x200000401:0x1:0x0]
3801 * lmm_stripe_count: 2
3802 * lmm_stripe_size: 1048576
3803 * lmm_pattern: raid0
3805 * lmm_stripe_offset: 1
3807 * - 0: { l_ost_idx: 1, l_fid: [0x100010000:0x2:0x0] }
3808 * - 1: { l_ost_idx: 0, l_fid: [0x100000000:0x3:0x0] }
3810 static void lov_dump_comp_v1(struct find_param *param, char *path,
3811 enum lov_dump_flags flags)
3813 struct lov_comp_md_entry_v1 *entry;
3814 struct lov_user_ost_data_v1 *objects;
3815 struct lov_comp_md_v1 *comp_v1 = (void *)¶m->fp_lmd->lmd_lmm;
3816 struct lov_user_md_v1 *v1;
3817 char pool_name[LOV_MAXPOOLNAME + 1];
3818 int obdindex = param->fp_obd_index;
3819 int i, j, match, ext;
3820 bool obdstripe = false;
3821 __u16 mirror_index = 0;
3822 __u16 mirror_id = 0;
3824 if (obdindex != OBD_NOT_FOUND) {
3825 for (i = 0; !(flags & LDF_IS_DIR) && !obdstripe &&
3826 i < comp_v1->lcm_entry_count; i++) {
3827 if (!(comp_v1->lcm_entries[i].lcme_flags &
3831 v1 = lov_comp_entry(comp_v1, i);
3832 objects = lov_v1v3_objects(v1);
3834 for (j = 0; j < v1->lmm_stripe_count; j++) {
3835 if (obdindex == objects[j].l_ost_idx) {
3848 lov_dump_comp_v1_header(param, path, flags);
3850 flags |= LDF_INDENT;
3852 for (i = 0; i < comp_v1->lcm_entry_count; i++) {
3853 entry = &comp_v1->lcm_entries[i];
3855 if (param->fp_check_comp_flags) {
3856 if (((param->fp_comp_flags & entry->lcme_flags) !=
3857 param->fp_comp_flags) ||
3858 (param->fp_comp_neg_flags & entry->lcme_flags))
3862 if (param->fp_check_comp_id &&
3863 param->fp_comp_id != entry->lcme_id)
3866 if (param->fp_check_comp_start) {
3867 match = find_value_cmp(entry->lcme_extent.e_start,
3868 param->fp_comp_start,
3869 param->fp_comp_start_sign,
3871 param->fp_comp_start_units, 0);
3876 if (param->fp_check_comp_end) {
3877 match = find_comp_end_cmp(entry->lcme_extent.e_end,
3883 if (param->fp_check_mirror_index) {
3884 if (mirror_id != mirror_id_of(entry->lcme_id)) {
3886 mirror_id = mirror_id_of(entry->lcme_id);
3889 match = find_value_cmp(mirror_index,
3890 param->fp_mirror_index,
3891 param->fp_mirror_index_sign,
3892 param->fp_exclude_mirror_index,
3896 } else if (param->fp_check_mirror_id) {
3897 if (mirror_id != mirror_id_of(entry->lcme_id))
3898 mirror_id = mirror_id_of(entry->lcme_id);
3900 match = find_value_cmp(mirror_id,
3901 param->fp_mirror_id,
3902 param->fp_mirror_id_sign,
3903 param->fp_exclude_mirror_id,
3909 if (print_last_init_comp(param)) {
3911 * if part of stripe info is needed, we'd print only
3912 * the last instantiated component info.
3914 if (entry->lcme_flags & LCME_FL_INIT)
3917 if (param->fp_verbose & VERBOSE_EXT_SIZE) {
3918 if (entry->lcme_flags & LCME_FL_EXTENSION)
3919 /* moved back below */
3927 if (entry->lcme_flags & LCME_FL_INIT) {
3928 if (obdindex != OBD_NOT_FOUND) {
3929 flags |= LDF_SKIP_OBJS;
3930 v1 = lov_comp_entry(comp_v1, i);
3931 objects = lov_v1v3_objects(v1);
3933 for (j = 0; j < v1->lmm_stripe_count; j++) {
3934 if (obdindex == objects[j].l_ost_idx) {
3935 flags &= ~LDF_SKIP_OBJS;
3940 flags &= ~LDF_SKIP_OBJS;
3943 flags |= LDF_SKIP_OBJS;
3946 if (obdindex != OBD_NOT_FOUND && (flags & LDF_SKIP_OBJS))
3948 lov_dump_comp_v1_entry(param, flags, i);
3950 v1 = lov_comp_entry(comp_v1, i);
3951 objects = lov_v1v3_objects(v1);
3952 lov_v1v3_pool_name(v1, pool_name);
3954 ext = entry->lcme_flags & LCME_FL_EXTENSION ? LDF_EXTENSION : 0;
3955 lov_dump_user_lmm_v1v3(v1, pool_name, objects, path, obdindex,
3956 param->fp_max_depth, param->fp_verbose,
3959 if (print_last_init_comp(param)) {
3961 * directory layout contains only layout template, print the
3965 i = comp_v1->lcm_entry_count - 1;
3968 flags &= ~LDF_SKIP_OBJS;
3970 lov_dump_comp_v1_entry(param, flags, i);
3972 v1 = lov_comp_entry(comp_v1, i);
3973 objects = lov_v1v3_objects(v1);
3974 lov_v1v3_pool_name(v1, pool_name);
3976 entry = &comp_v1->lcm_entries[i];
3977 ext = entry->lcme_flags & LCME_FL_EXTENSION ? LDF_EXTENSION : 0;
3978 lov_dump_user_lmm_v1v3(v1, pool_name, objects, path, obdindex,
3979 param->fp_max_depth, param->fp_verbose,
3984 #define VERBOSE_COMP_OPTS (VERBOSE_COMP_COUNT | VERBOSE_COMP_ID | \
3985 VERBOSE_COMP_START | VERBOSE_COMP_END | \
3988 static inline bool has_any_comp_options(struct find_param *param)
3990 enum llapi_layout_verbose verbose = param->fp_verbose;
3992 if (param->fp_check_comp_id || param->fp_check_comp_count ||
3993 param->fp_check_comp_start || param->fp_check_comp_end ||
3994 param->fp_check_comp_flags)
3997 /* show full layout information, not component specific */
3998 if ((verbose & ~VERBOSE_DETAIL) == VERBOSE_DEFAULT)
4001 return verbose & VERBOSE_COMP_OPTS;
4004 struct lov_user_mds_data *lov_forge_comp_v1(struct lov_user_mds_data *orig,
4007 struct lov_user_md *lum = &orig->lmd_lmm;
4008 struct lov_user_mds_data *new;
4009 struct lov_comp_md_v1 *comp_v1;
4010 struct lov_comp_md_entry_v1 *ent;
4011 int lum_off = sizeof(*comp_v1) + sizeof(*ent);
4012 int lum_size = lov_user_md_size(is_dir ? 0 : lum->lmm_stripe_count,
4015 new = malloc(offsetof(typeof(*new), lmd_lmm) + lum_off + lum_size);
4017 llapi_printf(LLAPI_MSG_NORMAL, "out of memory\n");
4021 memcpy(new, orig, sizeof(new->lmd_stx) + sizeof(new->lmd_flags)
4022 + sizeof(new->lmd_lmmsize));
4024 comp_v1 = (struct lov_comp_md_v1 *)&new->lmd_lmm;
4025 comp_v1->lcm_magic = lum->lmm_magic;
4026 comp_v1->lcm_size = lum_off + lum_size;
4027 comp_v1->lcm_layout_gen = is_dir ? 0 : lum->lmm_layout_gen;
4028 comp_v1->lcm_flags = 0;
4029 comp_v1->lcm_entry_count = 1;
4031 ent = &comp_v1->lcm_entries[0];
4033 ent->lcme_flags = is_dir ? 0 : LCME_FL_INIT;
4034 ent->lcme_extent.e_start = 0;
4035 ent->lcme_extent.e_end = LUSTRE_EOF;
4036 ent->lcme_offset = lum_off;
4037 ent->lcme_size = lum_size;
4039 memcpy((char *)comp_v1 + lum_off, lum, lum_size);
4044 static void lov_dump_plain_user_lmm(struct find_param *param, char *path,
4045 enum lov_dump_flags flags)
4047 __u32 magic = *(__u32 *)¶m->fp_lmd->lmd_lmm;
4049 if (has_any_comp_options(param)) {
4050 struct lov_user_mds_data *new_lmd, *orig_lmd;
4052 orig_lmd = param->fp_lmd;
4053 new_lmd = lov_forge_comp_v1(orig_lmd, flags & LDF_IS_DIR);
4054 if (new_lmd != NULL) {
4055 param->fp_lmd = new_lmd;
4056 lov_dump_comp_v1(param, path, flags);
4057 param->fp_lmd = orig_lmd;
4063 if (magic == LOV_USER_MAGIC_V1) {
4064 lov_dump_user_lmm_v1v3(¶m->fp_lmd->lmd_lmm, NULL,
4065 param->fp_lmd->lmd_lmm.lmm_objects,
4066 path, param->fp_obd_index,
4067 param->fp_max_depth, param->fp_verbose,
4070 char pool_name[LOV_MAXPOOLNAME + 1];
4071 struct lov_user_ost_data_v1 *objects;
4072 struct lov_user_md_v3 *lmmv3 = (void *)¶m->fp_lmd->lmd_lmm;
4074 snprintf(pool_name, sizeof(pool_name), "%s",
4075 lmmv3->lmm_pool_name);
4076 objects = lmmv3->lmm_objects;
4077 lov_dump_user_lmm_v1v3(¶m->fp_lmd->lmd_lmm, pool_name,
4078 objects, path, param->fp_obd_index,
4079 param->fp_max_depth, param->fp_verbose,
4084 static uint32_t check_foreign_type(uint32_t foreign_type)
4088 for (i = 0; i < LU_FOREIGN_TYPE_UNKNOWN; i++) {
4089 if (lu_foreign_types[i].lft_name == NULL)
4091 if (foreign_type == lu_foreign_types[i].lft_type)
4095 return LU_FOREIGN_TYPE_UNKNOWN;
4098 static void lov_dump_foreign_lmm(struct find_param *param, char *path,
4099 enum lov_dump_flags flags)
4101 struct lov_foreign_md *lfm = (void *)¶m->fp_lmd->lmd_lmm;
4102 bool yaml = flags & LDF_YAML;
4104 if (!yaml && param->fp_depth && path)
4105 llapi_printf(LLAPI_MSG_NORMAL, "%s\n", path);
4107 if (param->fp_verbose & VERBOSE_DETAIL) {
4108 uint32_t type = check_foreign_type(lfm->lfm_type);
4110 llapi_printf(LLAPI_MSG_NORMAL, "lfm_magic: 0x%08X\n",
4112 llapi_printf(LLAPI_MSG_NORMAL, "lfm_length: %u\n",
4114 llapi_printf(LLAPI_MSG_NORMAL, "lfm_type: 0x%08X",
4116 if (type < LU_FOREIGN_TYPE_UNKNOWN)
4117 llapi_printf(LLAPI_MSG_NORMAL, " (%s)\n",
4118 lu_foreign_types[type].lft_name);
4120 llapi_printf(LLAPI_MSG_NORMAL, " (unknown)\n");
4122 llapi_printf(LLAPI_MSG_NORMAL, "lfm_flags: 0x%08X\n",
4125 llapi_printf(LLAPI_MSG_NORMAL, "lfm_value: '%.*s'\n",
4126 lfm->lfm_length, lfm->lfm_value);
4127 llapi_printf(LLAPI_MSG_NORMAL, "\n");
4130 static void lmv_dump_foreign_lmm(struct find_param *param, char *path,
4131 enum lov_dump_flags flags)
4133 struct lmv_foreign_md *lfm = (struct lmv_foreign_md *)param->fp_lmv_md;
4134 bool yaml = flags & LDF_YAML;
4136 if (!yaml && param->fp_depth && path)
4137 llapi_printf(LLAPI_MSG_NORMAL, "%s\n", path);
4139 if (param->fp_verbose & VERBOSE_DETAIL) {
4140 uint32_t type = check_foreign_type(lfm->lfm_type);
4142 llapi_printf(LLAPI_MSG_NORMAL, "lfm_magic: 0x%08X\n",
4144 llapi_printf(LLAPI_MSG_NORMAL, "lfm_length: %u\n",
4146 llapi_printf(LLAPI_MSG_NORMAL, "lfm_type: 0x%08X",
4148 if (type < LU_FOREIGN_TYPE_UNKNOWN)
4149 llapi_printf(LLAPI_MSG_NORMAL, " (%s)\n",
4150 lu_foreign_types[type].lft_name);
4152 llapi_printf(LLAPI_MSG_NORMAL, " (unknown)\n");
4154 llapi_printf(LLAPI_MSG_NORMAL, "lfm_flags: 0x%08X\n",
4157 llapi_printf(LLAPI_MSG_NORMAL, "lfm_value: '%.*s'\n",
4158 lfm->lfm_length, lfm->lfm_value);
4159 llapi_printf(LLAPI_MSG_NORMAL, "\n");
4162 static void llapi_lov_dump_user_lmm(struct find_param *param, char *path,
4163 enum lov_dump_flags flags)
4167 if (param->fp_get_lmv || param->fp_get_default_lmv)
4168 magic = (__u32)param->fp_lmv_md->lum_magic;
4170 magic = *(__u32 *)¶m->fp_lmd->lmd_lmm; /* lum->lmm_magic */
4173 flags |= LDF_IS_RAW;
4178 case LOV_USER_MAGIC_V1:
4179 case LOV_USER_MAGIC_V3:
4180 case LOV_USER_MAGIC_SPECIFIC:
4181 lov_dump_plain_user_lmm(param, path, flags);
4183 case LOV_USER_MAGIC_FOREIGN:
4184 lov_dump_foreign_lmm(param, path, flags);
4187 case LMV_USER_MAGIC: {
4188 char pool_name[LOV_MAXPOOLNAME + 1];
4189 struct lmv_user_md *lum;
4191 lum = (struct lmv_user_md *)param->fp_lmv_md;
4192 snprintf(pool_name, sizeof(pool_name), "%s",
4193 lum->lum_pool_name);
4194 lmv_dump_user_lmm(lum, pool_name, path, param->fp_obd_index,
4195 param->fp_max_depth, param->fp_verbose,
4199 case LOV_USER_MAGIC_COMP_V1:
4200 lov_dump_comp_v1(param, path, flags);
4202 case LMV_MAGIC_FOREIGN:
4203 lmv_dump_foreign_lmm(param, path, flags);
4206 llapi_printf(LLAPI_MSG_NORMAL,
4207 "unknown lmm_magic: %#x (expecting one of %#x %#x %#x %#x)\n",
4208 *(__u32 *)¶m->fp_lmd->lmd_lmm,
4209 LOV_USER_MAGIC_V1, LOV_USER_MAGIC_V3,
4210 LMV_USER_MAGIC, LMV_MAGIC_V1);
4215 static int llapi_file_get_stripe1(const char *path, struct lov_user_md *lum)
4221 fname = strrchr(path, '/');
4223 /* It should be a file (or other non-directory) */
4224 if (fname == NULL) {
4225 dname = (char *)malloc(2);
4229 fname = (char *)path;
4231 dname = (char *)malloc(fname - path + 1);
4234 strncpy(dname, path, fname - path);
4235 dname[fname - path] = '\0';
4239 fd = open(dname, O_RDONLY | O_NONBLOCK);
4245 strcpy((char *)lum, fname);
4246 if (ioctl(fd, IOC_MDC_GETFILESTRIPE, (void *)lum) == -1)
4249 if (close(fd) == -1 && rc == 0)
4257 int llapi_file_get_stripe(const char *path, struct lov_user_md *lum)
4259 char *canon_path = NULL;
4262 rc = llapi_file_get_stripe1(path, lum);
4263 if (!(rc == -ENOTTY || rc == -ENODATA))
4266 /* Handle failure due to symlinks by dereferencing path manually. */
4267 canon_path = canonicalize_file_name(path);
4268 if (canon_path == NULL)
4269 goto out; /* Keep original rc. */
4271 rc2 = llapi_file_get_stripe1(canon_path, lum);
4273 goto out; /* Keep original rc. */
4282 int llapi_file_lookup(int dirfd, const char *name)
4284 struct obd_ioctl_data data = { 0 };
4289 if (dirfd < 0 || name == NULL)
4292 data.ioc_version = OBD_IOCTL_VERSION;
4293 data.ioc_len = sizeof(data);
4294 data.ioc_inlbuf1 = (char *)name;
4295 data.ioc_inllen1 = strlen(name) + 1;
4297 rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
4299 llapi_error(LLAPI_MSG_ERROR, rc,
4300 "error: IOC_MDC_LOOKUP pack failed for '%s': rc %d",
4305 rc = ioctl(dirfd, IOC_MDC_LOOKUP, buf);
4312 * Check if the file time matches all the given criteria (e.g. --atime +/-N).
4313 * Return -1 or 1 if file timestamp does not or does match the given criteria
4314 * correspondingly. Return 0 if the MDS time is being checked and there are
4315 * attributes on OSTs and it is not yet clear if the timespamp matches.
4317 * If 0 is returned, we need to do another RPC to the OSTs to obtain the
4318 * updated timestamps.
4320 static int find_time_check(struct find_param *param, int mds)
4322 struct lov_user_mds_data *lmd = param->fp_lmd;
4326 /* Check if file is accepted. */
4327 if (param->fp_atime) {
4328 rc2 = find_value_cmp(lmd->lmd_stx.stx_atime.tv_sec,
4329 param->fp_atime, param->fp_asign,
4330 param->fp_exclude_atime,
4331 param->fp_time_margin, mds);
4337 if (param->fp_mtime) {
4338 rc2 = find_value_cmp(lmd->lmd_stx.stx_mtime.tv_sec,
4339 param->fp_mtime, param->fp_msign,
4340 param->fp_exclude_mtime,
4341 param->fp_time_margin, mds);
4346 * If the previous check matches, but this one is not yet clear,
4347 * we should return 0 to do an RPC on OSTs.
4353 if (param->fp_ctime) {
4354 rc2 = find_value_cmp(lmd->lmd_stx.stx_ctime.tv_sec,
4355 param->fp_ctime, param->fp_csign,
4356 param->fp_exclude_ctime,
4357 param->fp_time_margin, mds);
4362 * If the previous check matches, but this one is not yet clear,
4363 * we should return 0 to do an RPC on OSTs.
4372 static int find_newerxy_check(struct find_param *param, int mds, bool from_mdt)
4374 struct lov_user_mds_data *lmd = param->fp_lmd;
4379 for (i = 0; i < 2; i++) {
4380 /* Check if file is accepted. */
4381 if (param->fp_newery[NEWERXY_ATIME][i]) {
4382 rc2 = find_value_cmp(lmd->lmd_stx.stx_atime.tv_sec,
4383 param->fp_newery[NEWERXY_ATIME][i],
4390 if (param->fp_newery[NEWERXY_MTIME][i]) {
4391 rc2 = find_value_cmp(lmd->lmd_stx.stx_mtime.tv_sec,
4392 param->fp_newery[NEWERXY_MTIME][i],
4398 * If the previous check matches, but this one is not
4399 * yet clear, we should return 0 to do an RPC on OSTs.
4405 if (param->fp_newery[NEWERXY_CTIME][i]) {
4406 rc2 = find_value_cmp(lmd->lmd_stx.stx_ctime.tv_sec,
4407 param->fp_newery[NEWERXY_CTIME][i],
4413 * If the previous check matches, but this one is not
4414 * yet clear, we should return 0 to do an RPC on OSTs.
4421 * File birth time (btime) can get from MDT directly.
4422 * if @from_mdt is true, it means the input file attributs are
4423 * obtained directly from MDT.
4424 * Thus, if @from_mdt is false, we should skip the following
4430 if (param->fp_newery[NEWERXY_BTIME][i]) {
4431 if (!(lmd->lmd_stx.stx_mask & STATX_BTIME))
4434 rc2 = find_value_cmp(lmd->lmd_stx.stx_btime.tv_sec,
4435 param->fp_newery[NEWERXY_BTIME][i],
4446 * Check whether the stripes matches the indexes user provided
4450 static int check_obd_match(struct find_param *param)
4452 struct lov_user_ost_data_v1 *objects;
4453 struct lov_comp_md_v1 *comp_v1 = NULL;
4454 struct lov_user_mds_data *lmd = param->fp_lmd;
4455 struct lov_user_md_v1 *v1 = &lmd->lmd_lmm;
4456 int i, j, k, count = 1;
4458 if (param->fp_obd_uuid && param->fp_obd_index == OBD_NOT_FOUND)
4461 if (!S_ISREG(lmd->lmd_stx.stx_mode))
4464 /* exclude foreign */
4465 if (v1->lmm_magic == LOV_USER_MAGIC_FOREIGN)
4466 return param->fp_exclude_obd;
4469 * Only those files should be accepted, which have a
4470 * stripe on the specified OST.
4472 if (v1->lmm_magic == LOV_USER_MAGIC_COMP_V1) {
4473 comp_v1 = (struct lov_comp_md_v1 *)v1;
4474 count = comp_v1->lcm_entry_count;
4477 for (i = 0; i < count; i++) {
4479 v1 = lov_comp_entry(comp_v1, i);
4481 objects = lov_v1v3_objects(v1);
4483 for (j = 0; j < v1->lmm_stripe_count; j++) {
4484 if (comp_v1 && !(comp_v1->lcm_entries[i].lcme_flags &
4487 for (k = 0; k < param->fp_num_obds; k++) {
4488 if (param->fp_obd_indexes[k] ==
4489 objects[j].l_ost_idx)
4490 return !param->fp_exclude_obd;
4495 return param->fp_exclude_obd;
4498 static int check_mdt_match(struct find_param *param)
4502 if (param->fp_mdt_uuid && param->fp_mdt_index == OBD_NOT_FOUND)
4505 /* FIXME: For striped dir, we should get stripe information and check */
4506 for (i = 0; i < param->fp_num_mdts; i++) {
4507 if (param->fp_mdt_indexes[i] == param->fp_file_mdt_index)
4508 return !param->fp_exclude_mdt;
4511 if (param->fp_exclude_mdt)
4518 * Check whether the obd is active or not, if it is
4519 * not active, just print the object affected by this
4522 static void print_failed_tgt(struct find_param *param, char *path, int type)
4524 struct obd_statfs stat_buf;
4525 struct obd_uuid uuid_buf;
4526 int tgt_nr, i, *indexes;
4529 if (type != LL_STATFS_LOV && type != LL_STATFS_LMV) {
4530 llapi_error(LLAPI_MSG_NORMAL, ret, "%s: wrong statfs type(%d)",
4535 tgt_nr = (type == LL_STATFS_LOV) ? param->fp_obd_index :
4536 param->fp_mdt_index;
4537 indexes = (type == LL_STATFS_LOV) ? param->fp_obd_indexes :
4538 param->fp_mdt_indexes;
4540 for (i = 0; i < tgt_nr; i++) {
4541 memset(&stat_buf, 0, sizeof(struct obd_statfs));
4542 memset(&uuid_buf, 0, sizeof(struct obd_uuid));
4544 ret = llapi_obd_statfs(path, type, indexes[i], &stat_buf,
4547 llapi_error(LLAPI_MSG_NORMAL, ret,
4548 "%s: obd_uuid: %s failed",
4549 __func__, param->fp_obd_uuid->uuid);
4553 static int find_check_stripe_size(struct find_param *param)
4555 struct lov_comp_md_v1 *comp_v1 = NULL;
4556 struct lov_user_md_v1 *v1 = ¶m->fp_lmd->lmd_lmm;
4557 __u32 stripe_size = 0;
4558 int ret, i, count = 1;
4560 if (v1->lmm_magic == LOV_USER_MAGIC_FOREIGN)
4561 return param->fp_exclude_stripe_size ? 1 : -1;
4563 ret = param->fp_exclude_stripe_size ? 1 : -1;
4564 if (v1->lmm_magic == LOV_USER_MAGIC_COMP_V1) {
4565 comp_v1 = (struct lov_comp_md_v1 *)v1;
4566 count = comp_v1->lcm_entry_count;
4569 for (i = 0; i < count; i++) {
4570 struct lov_comp_md_entry_v1 *ent;
4573 v1 = lov_comp_entry(comp_v1, i);
4575 ent = &comp_v1->lcm_entries[i];
4576 if (ent->lcme_flags & LCME_FL_EXTENSION)
4578 if (!(ent->lcme_flags & LCME_FL_INIT))
4581 stripe_size = v1->lmm_stripe_size;
4584 ret = find_value_cmp(stripe_size, param->fp_stripe_size,
4585 param->fp_stripe_size_sign,
4586 param->fp_exclude_stripe_size,
4587 param->fp_stripe_size_units, 0);
4592 static int find_check_ext_size(struct find_param *param)
4594 struct lov_comp_md_v1 *comp_v1;
4595 struct lov_user_md_v1 *v1;
4598 ret = param->fp_exclude_ext_size ? 1 : -1;
4599 comp_v1 = (struct lov_comp_md_v1 *)¶m->fp_lmd->lmd_lmm;
4600 if (comp_v1->lcm_magic != LOV_USER_MAGIC_COMP_V1)
4603 for (i = 0; i < comp_v1->lcm_entry_count; i++) {
4604 struct lov_comp_md_entry_v1 *ent;
4606 v1 = lov_comp_entry(comp_v1, i);
4608 ent = &comp_v1->lcm_entries[i];
4609 if (!(ent->lcme_flags & LCME_FL_EXTENSION))
4612 ret = find_value_cmp(v1->lmm_stripe_size, param->fp_ext_size,
4613 param->fp_ext_size_sign,
4614 param->fp_exclude_ext_size,
4615 param->fp_ext_size_units, 0);
4616 /* If any ext_size matches */
4624 static __u32 find_get_stripe_count(struct find_param *param)
4626 struct lov_comp_md_v1 *comp_v1 = NULL;
4627 struct lov_user_md_v1 *v1 = ¶m->fp_lmd->lmd_lmm;
4629 __u32 stripe_count = 0;
4631 if (v1->lmm_magic == LOV_USER_MAGIC_FOREIGN)
4634 if (v1->lmm_magic == LOV_USER_MAGIC_COMP_V1) {
4635 comp_v1 = (struct lov_comp_md_v1 *)v1;
4636 count = comp_v1->lcm_entry_count;
4639 for (i = 0; i < count; i++) {
4641 struct lov_comp_md_entry_v1 *ent;
4643 v1 = lov_comp_entry(comp_v1, i);
4645 ent = &comp_v1->lcm_entries[i];
4646 if (!(ent->lcme_flags & LCME_FL_INIT))
4649 if (ent->lcme_flags & LCME_FL_EXTENSION)
4652 stripe_count = v1->lmm_stripe_count;
4655 return stripe_count;
4658 #define LOV_PATTERN_INVALID 0xFFFFFFFF
4660 static int find_check_layout(struct find_param *param)
4662 struct lov_comp_md_v1 *comp_v1 = NULL;
4663 struct lov_user_md_v1 *v1 = ¶m->fp_lmd->lmd_lmm;
4665 bool found = false, valid = false;
4667 if (v1->lmm_magic == LOV_USER_MAGIC_COMP_V1) {
4668 comp_v1 = (struct lov_comp_md_v1 *)v1;
4669 count = comp_v1->lcm_entry_count;
4672 for (i = 0; i < count; i++) {
4674 v1 = lov_comp_entry(comp_v1, i);
4676 /* foreign file have a special magic but no pattern field */
4677 if (v1->lmm_magic == LOV_USER_MAGIC_FOREIGN)
4680 if (v1->lmm_pattern == LOV_PATTERN_INVALID)
4684 if (v1->lmm_pattern & param->fp_layout) {
4693 if ((found && !param->fp_exclude_layout) ||
4694 (!found && param->fp_exclude_layout))
4701 * if no type specified, check/exclude all foreign
4702 * if type specified, check all foreign&type and exclude !foreign + foreign&type
4704 static int find_check_foreign(struct find_param *param)
4706 if (S_ISREG(param->fp_lmd->lmd_stx.stx_mode)) {
4707 struct lov_foreign_md *lfm;
4709 lfm = (void *)¶m->fp_lmd->lmd_lmm;
4710 if (lfm->lfm_magic != LOV_USER_MAGIC_FOREIGN) {
4711 if (param->fp_foreign_type == LU_FOREIGN_TYPE_UNKNOWN)
4712 return param->fp_exclude_foreign ? 1 : -1;
4716 if (param->fp_foreign_type == LU_FOREIGN_TYPE_UNKNOWN ||
4717 lfm->lfm_type == param->fp_foreign_type)
4718 return param->fp_exclude_foreign ? -1 : 1;
4719 return param->fp_exclude_foreign ? 1 : -1;
4722 if (S_ISDIR(param->fp_lmd->lmd_stx.stx_mode)) {
4723 struct lmv_foreign_md *lfm;
4725 lfm = (void *)param->fp_lmv_md;
4726 if (lmv_is_foreign(lfm->lfm_magic)) {
4727 if (param->fp_foreign_type == LU_FOREIGN_TYPE_UNKNOWN)
4728 return param->fp_exclude_foreign ? 1 : -1;
4732 if (param->fp_foreign_type == LU_FOREIGN_TYPE_UNKNOWN ||
4733 lfm->lfm_type == param->fp_foreign_type)
4734 return param->fp_exclude_foreign ? -1 : 1;
4735 return param->fp_exclude_foreign ? 1 : -1;
4740 static int find_check_pool(struct find_param *param)
4742 struct lov_comp_md_v1 *comp_v1 = NULL;
4743 struct lov_user_md_v3 *v3 = (void *)¶m->fp_lmd->lmd_lmm;
4747 if (v3->lmm_magic == LOV_USER_MAGIC_COMP_V1) {
4748 comp_v1 = (struct lov_comp_md_v1 *)v3;
4749 count = comp_v1->lcm_entry_count;
4750 /* empty requested pool is taken as no pool search */
4751 if (count == 0 && param->fp_poolname[0] == '\0') {
4757 for (i = 0; i < count; i++) {
4758 if (comp_v1 != NULL) {
4759 if (!(comp_v1->lcm_entries[i].lcme_flags &
4763 v3 = (void *)lov_comp_entry(comp_v1, i);
4766 if (v3->lmm_magic == LOV_USER_MAGIC_FOREIGN)
4769 if (((v3->lmm_magic == LOV_USER_MAGIC_V1) &&
4770 (param->fp_poolname[0] == '\0')) ||
4771 ((v3->lmm_magic == LOV_USER_MAGIC_V3) &&
4772 (strncmp(v3->lmm_pool_name,
4773 param->fp_poolname, LOV_MAXPOOLNAME) == 0)) ||
4774 ((v3->lmm_magic == LOV_USER_MAGIC_V3) &&
4775 (strcmp(param->fp_poolname, "*") == 0))) {
4782 if ((found && !param->fp_exclude_pool) ||
4783 (!found && param->fp_exclude_pool))
4789 static int find_check_comp_options(struct find_param *param)
4791 struct lov_comp_md_v1 *comp_v1, *forged_v1 = NULL;
4792 struct lov_user_mds_data *lmd = param->fp_lmd;
4793 struct lov_user_md_v1 *v1 = &lmd->lmd_lmm;
4794 struct lov_comp_md_entry_v1 *entry;
4797 if (v1->lmm_magic == LOV_USER_MAGIC_FOREIGN)
4800 if (v1->lmm_magic == LOV_USER_MAGIC_COMP_V1) {
4801 comp_v1 = (struct lov_comp_md_v1 *)v1;
4803 forged_v1 = malloc(sizeof(*forged_v1) + sizeof(*entry));
4804 if (forged_v1 == NULL)
4806 comp_v1 = forged_v1;
4807 comp_v1->lcm_entry_count = 1;
4808 entry = &comp_v1->lcm_entries[0];
4809 entry->lcme_flags = S_ISDIR(lmd->lmd_stx.stx_mode) ?
4811 entry->lcme_extent.e_start = 0;
4812 entry->lcme_extent.e_end = LUSTRE_EOF;
4815 /* invalid case, don't match for any kind of search. */
4816 if (comp_v1->lcm_entry_count == 0) {
4821 if (param->fp_check_comp_count) {
4822 ret = find_value_cmp(forged_v1 ? 0 : comp_v1->lcm_entry_count,
4823 param->fp_comp_count,
4824 param->fp_comp_count_sign,
4825 param->fp_exclude_comp_count, 1, 0);
4831 for (i = 0; i < comp_v1->lcm_entry_count; i++) {
4832 entry = &comp_v1->lcm_entries[i];
4834 if (param->fp_check_comp_flags) {
4836 if (((param->fp_comp_flags & entry->lcme_flags) !=
4837 param->fp_comp_flags) ||
4838 (param->fp_comp_neg_flags & entry->lcme_flags)) {
4844 if (param->fp_check_comp_start) {
4845 ret = find_value_cmp(entry->lcme_extent.e_start,
4846 param->fp_comp_start,
4847 param->fp_comp_start_sign,
4848 param->fp_exclude_comp_start,
4849 param->fp_comp_start_units, 0);
4854 if (param->fp_check_comp_end) {
4855 ret = find_comp_end_cmp(entry->lcme_extent.e_end,
4861 /* the component matches all criteria */
4870 static int find_check_mirror_options(struct find_param *param)
4872 struct lov_comp_md_v1 *comp_v1;
4873 struct lov_user_md_v1 *v1 = ¶m->fp_lmd->lmd_lmm;
4876 if (v1->lmm_magic != LOV_USER_MAGIC_COMP_V1)
4879 comp_v1 = (struct lov_comp_md_v1 *)v1;
4881 if (param->fp_check_mirror_count) {
4882 ret = find_value_cmp(comp_v1->lcm_mirror_count + 1,
4883 param->fp_mirror_count,
4884 param->fp_mirror_count_sign,
4885 param->fp_exclude_mirror_count, 1, 0);
4890 if (param->fp_check_mirror_state) {
4892 __u16 file_state = comp_v1->lcm_flags & LCM_FL_FLR_MASK;
4894 if ((param->fp_mirror_state != 0 &&
4895 file_state != param->fp_mirror_state) ||
4896 file_state == param->fp_mirror_neg_state)
4903 static bool find_check_lmm_info(struct find_param *param)
4905 return param->fp_check_pool || param->fp_check_stripe_count ||
4906 param->fp_check_stripe_size || param->fp_check_layout ||
4907 param->fp_check_comp_count || param->fp_check_comp_end ||
4908 param->fp_check_comp_start || param->fp_check_comp_flags ||
4909 param->fp_check_mirror_count || param->fp_check_foreign ||
4910 param->fp_check_mirror_state || param->fp_check_ext_size ||
4911 param->fp_check_projid;
4915 * Interpret backslash escape sequences and write output into buffer.
4916 * Anything written to the buffer will be null terminated.
4918 * @param[in] seq String being parsed for escape sequence. The leading
4919 * '\' character is not included in this string (only the
4920 * characters after it)
4921 * @param[out] buffer Location where interpreted escape sequence is written
4922 * @param[in] size Size of the available buffer. (Needs to be large enough
4923 * to handle escape sequence output plus null terminator.)
4924 * @param[out] wrote Number of bytes written to the buffer.
4925 * @return Number of characters from input string processed
4926 * as part of the escape sequence (0 for an unrecognized
4929 int printf_format_escape(char *seq, char *buffer, size_t size, int *wrote)
4932 /* For now, only handle single char escape sequences: \n, \t, \\ */
4955 * Interpret formats for timestamps (%a, %A@, etc)
4957 * @param[in] seq String being parsed for timestamp format. The leading
4958 * '%' character is not included in this string
4959 * @param[out] buffer Location where timestamp info is written
4960 * @param[in] size Size of the available buffer.
4961 * @param[out] wrote Number of bytes written to the buffer.
4962 * @return Number of characters from input string processed
4963 * as part of the format (0 for an unknown format)
4966 int printf_format_timestamp(char *seq, char *buffer, size_t size, int *wrote,
4967 struct find_param *param)
4969 struct statx_timestamp ts = { 0, 0 };
4973 char *fmt = "%c"; /* Print in ctime format by default */
4978 ts = param->fp_lmd->lmd_stx.stx_atime;
4982 if (*(seq + 1) == '@') {
4983 ts = param->fp_lmd->lmd_stx.stx_atime;
4989 ts = param->fp_lmd->lmd_stx.stx_ctime;
4993 if (*(seq + 1) == '@') {
4994 ts = param->fp_lmd->lmd_stx.stx_ctime;
5000 ts = param->fp_lmd->lmd_stx.stx_mtime;
5004 if (*(seq + 1) == '@') {
5005 ts = param->fp_lmd->lmd_stx.stx_mtime;
5011 ts = param->fp_lmd->lmd_stx.stx_btime;
5015 if (*(seq + 1) == '@') {
5016 ts = param->fp_lmd->lmd_stx.stx_btime;
5026 /* Found valid format, print to buffer */
5029 *wrote = strftime(buffer, size, fmt, tm);
5036 * Print all ost indices associated with a file layout using a commma separated
5037 * list. For a file with mutliple components, the list of indices for each
5038 * component will be enclosed in brackets.
5040 * @param[out] buffer Location where OST indices are written
5041 * @param[in] size Size of the available buffer.
5042 * @pararm[in] layout Pointer to layout structure for the file
5043 * @return Number of bytes written to output buffer
5045 static int printf_format_ost_indices(char *buffer, size_t size,
5046 struct llapi_layout *layout)
5048 uint64_t count, idx, i;
5049 int err, bytes, wrote = 0;
5051 /* Make sure to start at the first component */
5052 err = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_FIRST);
5054 llapi_error(LLAPI_MSG_ERROR, err,
5055 "error: layout component iteration failed\n");
5059 err = llapi_layout_stripe_count_get(layout, &count);
5061 llapi_error(LLAPI_MSG_ERROR, err,
5062 "error: cannot get stripe_count\n");
5066 bytes = snprintf(buffer, (size - wrote), "%s", "[");
5071 for (i = 0; i < count; i++) {
5072 err = llapi_layout_ost_index_get(layout, i, &idx);
5074 llapi_error(LLAPI_MSG_ERROR, err,
5075 "error: cannot get OST index\n");
5076 bytes = snprintf(buffer, (size - wrote),
5079 bytes = snprintf(buffer, (size - wrote),
5087 /* Overwrite last comma with closing bracket */
5088 *(buffer - 1) = ']';
5090 err = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_NEXT);
5091 if (err == 0) /* next component is found */
5094 llapi_error(LLAPI_MSG_ERROR, err,
5095 "error: layout component iteration failed\n");
5096 /* At this point, either got error or reached last component */
5107 * Parse Lustre-specific format sequences of the form %L{x}.
5109 * @param[in] seq String being parsed for format sequence. The leading
5110 * '%' character is not included in this string
5111 * @param[out] buffer Location where interpreted format info is written
5112 * @param[in] size Size of the available buffer.
5113 * @param[out] wrote Number of bytes written to the buffer.
5114 * @param[in] param The find_param structure associated with the file/dir
5115 * @param[in] path Pathname of the current file/dir being handled
5116 * @param[in] projid Project ID associated with the current file/dir
5117 * @param[in] d File descriptor for the directory (or -1 for a
5118 * non-directory file)
5119 * @return Number of characters from input string processed
5120 * as part of the format (0 for an unknown format)
5122 int printf_format_lustre(char *seq, char *buffer, size_t size, int *wrote,
5123 struct find_param *param, char *path, int projid,
5126 struct lmv_user_md *lum;
5127 struct lmv_user_mds_data *objects;
5128 struct llapi_layout *layout = NULL;
5130 unsigned int hash_type;
5131 uint64_t str_cnt, str_size, idx;
5132 char pool_name[LOV_MAXPOOLNAME + 1] = { '\0' };
5134 int rc = 2; /* all current valid sequences are 2 chars */
5137 /* Sanity check. Formats always look like %L{X} */
5138 if (*seq++ != 'L') {
5144 * Some formats like %LF or %LP are handled the same for both files
5145 * and dirs, so handle all of those here.
5149 err = llapi_path2fid(path, &fid);
5151 llapi_error(LLAPI_MSG_ERROR, err,
5152 "error: cannot get fid\n");
5155 *wrote = snprintf(buffer, size, DFID_NOBRACE, PFID(&fid));
5158 *wrote = snprintf(buffer, size, "%d", projid);
5162 /* Other formats for files/dirs need to be handled differently */
5163 if (d == -1) { /* file */
5164 //layout = llapi_layout_get_by_xattr(¶m->fp_lmd->lmd_lmm,
5165 // param->fp_lum_size, 0);
5166 layout = llapi_layout_get_by_path(path, 0);
5167 if (layout == NULL) {
5168 llapi_error(LLAPI_MSG_ERROR, errno,
5169 "error: cannot get file layout\n");
5174 * Set the layout pointer to the last init component
5175 * since that is the component used for most of these
5176 * formats. (This also works for non-composite files)
5178 err = llapi_layout_get_last_init_comp(layout);
5180 llapi_error(LLAPI_MSG_ERROR, err,
5181 "error: cannot get last initialized compomnent\n");
5186 case 'c': /* stripe count */
5187 err = llapi_layout_stripe_count_get(layout, &str_cnt);
5189 llapi_error(LLAPI_MSG_ERROR, err,
5190 "error: cannot get stripe_count\n");
5193 *wrote = snprintf(buffer, size, "%"PRIu64, str_cnt);
5195 case 'h': /* hash info */
5196 /* Not applicable to files. Skip it. */
5198 case 'i': /* starting index */
5199 err = llapi_layout_ost_index_get(layout, 0, &idx);
5201 llapi_error(LLAPI_MSG_ERROR, err,
5202 "error: cannot get OST index of last initialized component\n");
5205 *wrote = snprintf(buffer, size, "%"PRIu64, idx);
5207 case 'o': /* list of object indices */
5208 *wrote = printf_format_ost_indices(buffer, size, layout);
5210 case 'p': /* pool name */
5211 err = llapi_layout_pool_name_get(layout, pool_name,
5214 llapi_error(LLAPI_MSG_ERROR, rc,
5215 "error: cannot get pool name\n");
5218 *wrote = snprintf(buffer, size, "%s", pool_name);
5220 case 'S': /* stripe size */
5221 err = llapi_layout_stripe_size_get(layout, &str_size);
5223 llapi_error(LLAPI_MSG_ERROR, rc,
5224 "error: cannot get stripe_size\n");
5227 *wrote = snprintf(buffer, size, "%"PRIu64, str_size);
5233 } else { /* directory */
5234 lum = (struct lmv_user_md *)param->fp_lmv_md;
5235 objects = lum->lum_objects;
5238 case 'c': /* stripe count */
5239 *wrote = snprintf(buffer, size, "%d",
5240 (int)lum->lum_stripe_count);
5242 case 'h': /* hash info */
5243 hash_type = lum->lum_hash_type & LMV_HASH_TYPE_MASK;
5244 if (hash_type < LMV_HASH_TYPE_MAX)
5245 *wrote = snprintf(buffer, size, "%s",
5246 mdt_hash_name[hash_type]);
5248 *wrote = snprintf(buffer, size, "%#x",
5251 case 'i': /* starting index */
5252 *wrote = snprintf(buffer, size, "%d",
5253 lum->lum_stripe_offset);
5255 case 'o': /* list of object indices */
5256 str_cnt = (int) lum->lum_stripe_count;
5257 *wrote = snprintf(buffer, size, "%s", "[");
5261 for (i = 0; i < str_cnt; i++) {
5262 bytes = snprintf(buffer, (size - *wrote),
5263 "%d,", objects[i].lum_mds);
5270 /* Use lum_offset as the only list entry */
5271 bytes = snprintf(buffer, (size - *wrote),
5272 "%d]", lum->lum_stripe_offset);
5275 /* Overwrite last comma with closing bracket */
5276 *(buffer - 1) = ']';
5279 case 'p': /* pool name */
5280 *wrote = snprintf(buffer, size, "%s",
5281 lum->lum_pool_name);
5283 case 'S': /* stripe size */
5284 /* This has no meaning for directories. Skip it. */
5294 llapi_layout_free(layout);
5297 /* output of snprintf was truncated */
5304 * Interpret format specifiers beginning with '%'.
5306 * @param[in] seq String being parsed for format specifier. The leading
5307 * '%' character is not included in this string
5308 * @param[out] buffer Location where formatted info is written
5309 * @param[in] size Size of the available buffer.
5310 * @param[out] wrote Number of bytes written to the buffer.
5311 * @param[in] param The find_param structure associated with the file/dir
5312 * @param[in] path Pathname of the current file/dir being handled
5313 * @param[in] projid Project ID associated with the current file/dir
5314 * @param[in] d File descriptor for the directory (or -1 for a
5315 * non-directory file)
5316 * @return Number of characters from input string processed
5317 * as part of the format (0 for an unknown format)
5319 int printf_format_directive(char *seq, char *buffer, size_t size, int *wrote,
5320 struct find_param *param, char *path, int projid,
5323 __u16 mode = param->fp_lmd->lmd_stx.stx_mode;
5324 uint64_t blocks = param->fp_lmd->lmd_stx.stx_blocks;
5325 int rc = 1; /* most specifiers are single character */
5333 case 'w': case 'W': /* timestamps */
5334 rc = printf_format_timestamp(seq, buffer, size, wrote, param);
5336 case 'b': /* file size (in 512B blocks) */
5337 *wrote = snprintf(buffer, size, "%"PRIu64, blocks);
5339 case 'G': /* GID of owner */
5340 *wrote = snprintf(buffer, size, "%u",
5341 param->fp_lmd->lmd_stx.stx_gid);
5343 case 'k': /* file size (in 1K blocks) */
5344 *wrote = snprintf(buffer, size, "%"PRIu64, (blocks + 1)/2);
5346 case 'L': /* Lustre-specific formats */
5347 rc = printf_format_lustre(seq, buffer, size, wrote, param,
5350 case 'm': /* file mode in octal */
5351 *wrote = snprintf(buffer, size, "%#o", (mode & (~S_IFMT)));
5353 case 'p': /* Path name of file */
5354 *wrote = snprintf(buffer, size, "%s", path);
5356 case 's': /* file size (in bytes) */
5357 *wrote = snprintf(buffer, size, "%"PRIu64,
5358 (uint64_t) param->fp_lmd->lmd_stx.stx_size);
5360 case 'U': /* UID of owner */
5361 *wrote = snprintf(buffer, size, "%u",
5362 param->fp_lmd->lmd_stx.stx_uid);
5364 case 'y': /* file type */
5367 else if (S_ISDIR(mode))
5369 else if (S_ISLNK(mode))
5371 else if (S_ISBLK(mode))
5373 else if (S_ISCHR(mode))
5375 else if (S_ISFIFO(mode))
5377 else if (S_ISSOCK(mode))
5387 default: /* invalid format specifier */
5393 /* output of snprintf was truncated */
5400 * Parse user-supplied string for the -printf option and interpret any
5401 * '%' format specifiers or '\' escape sequences.
5403 * @param[in] param The find_param struct containing the -printf string
5404 * as well as info about the current file/dir that mathced
5405 * the lfs find search criteria
5406 * @param[in] path Path name for current file/dir
5407 * @param[in] projid Project ID associated with current file/dir
5408 * @param[in] d File descriptor for current directory (or -1 for a
5409 * non-directory file)
5411 void printf_format_string(struct find_param *param, char *path,
5414 char output[FORMATTED_BUF_LEN];
5415 char *fmt_char = param->fp_format_printf_str;
5416 char *buff = output;
5422 buff_size = FORMATTED_BUF_LEN;
5424 /* Always leave one free byte in buffer for trailing NUL */
5425 while (*fmt_char && (buff_size > 1)) {
5428 if (*fmt_char == '%') {
5429 rc = printf_format_directive(fmt_char + 1, buff,
5430 buff_size, &written, param,
5432 } else if (*fmt_char == '\\')
5433 rc = printf_format_escape(fmt_char + 1, buff,
5434 buff_size, &written);
5437 /* Either a '\' escape or '%' format was processed.
5438 * Increment pointers accordingly.
5440 fmt_char += (rc + 1);
5442 buff_size -= written;
5444 /* Regular char or invalid escape/format.
5445 * Either way, copy current character.
5447 *buff++ = *fmt_char++;
5452 /* Terminate output buffer and print */
5454 llapi_printf(LLAPI_MSG_NORMAL, "%s", output);
5458 * Get file/directory project id.
5459 * by the open fd resides on.
5460 * Return 0 and project id on success, or -ve errno.
5462 static int fget_projid(int fd, int *projid)
5467 rc = ioctl(fd, FS_IOC_FSGETXATTR, &fsx);
5471 *projid = fsx.fsx_projid;
5476 * Check that the file's permissions in *st matches the one in find_param
5478 static int check_file_permissions(const struct find_param *param,
5485 switch (param->fp_perm_sign) {
5486 case LFS_FIND_PERM_EXACT:
5487 decision = (mode == param->fp_perm);
5489 case LFS_FIND_PERM_ALL:
5490 decision = ((mode & param->fp_perm) == param->fp_perm);
5492 case LFS_FIND_PERM_ANY:
5493 decision = ((mode & param->fp_perm) != 0);
5497 if ((param->fp_exclude_perm && decision)
5498 || (!param->fp_exclude_perm && !decision))
5504 static int cb_find_init(char *path, int p, int *dp,
5505 void *data, struct dirent64 *de)
5507 struct find_param *param = (struct find_param *)data;
5508 struct lov_user_mds_data *lmd = param->fp_lmd;
5509 int d = dp == NULL ? -1 : *dp;
5510 int decision = 1; /* 1 is accepted; -1 is rejected. */
5512 int checked_type = 0;
5514 __u32 stripe_count = 0;
5518 bool gather_all = false;
5520 if (p == -1 && d == -1)
5523 /* Reset this value between invocations */
5524 param->fp_get_lmv = 0;
5526 /* Gather all file/dir info, not just what's needed for search params */
5527 if (param->fp_format_printf_str)
5530 /* If a regular expression is presented, make the initial decision */
5531 if (param->fp_pattern != NULL) {
5532 char *fname = strrchr(path, '/');
5534 fname = (fname == NULL ? path : fname + 1);
5535 ret = fnmatch(param->fp_pattern, fname, 0);
5536 if ((ret == FNM_NOMATCH && !param->fp_exclude_pattern) ||
5537 (ret == 0 && param->fp_exclude_pattern))
5541 /* See if we can check the file type from the dirent. */
5542 if (de != NULL && de->d_type != DT_UNKNOWN) {
5543 if (param->fp_type != 0) {
5546 if (DTTOIF(de->d_type) == param->fp_type) {
5547 if (param->fp_exclude_type)
5550 if (!param->fp_exclude_type)
5554 if ((param->fp_check_mdt_count || param->fp_hash_type ||
5555 param->fp_check_hash_flag) && de->d_type != DT_DIR)
5562 * Request MDS for the stat info if some of these parameters need
5565 if (param->fp_obd_uuid || param->fp_mdt_uuid ||
5566 param->fp_check_uid || param->fp_check_gid ||
5567 param->fp_newerxy || param->fp_btime ||
5568 param->fp_atime || param->fp_mtime || param->fp_ctime ||
5569 param->fp_check_size || param->fp_check_blocks ||
5570 find_check_lmm_info(param) ||
5571 param->fp_check_mdt_count || param->fp_hash_type ||
5572 param->fp_check_hash_flag || param->fp_perm_sign ||
5576 if (param->fp_type != 0 && checked_type == 0)
5579 if (decision == 0) {
5581 (param->fp_check_mdt_count || param->fp_hash_type ||
5582 param->fp_check_hash_flag || param->fp_check_foreign ||
5584 param->fp_get_lmv = 1;
5585 ret = cb_get_dirstripe(path, &d, param);
5587 if (errno == ENODATA) {
5588 /* Fill in struct for unstriped dir */
5590 param->fp_lmv_md->lum_magic = LMV_MAGIC_V1;
5591 /* Use 0 until we find actual offset */
5592 param->fp_lmv_md->lum_stripe_offset = 0;
5593 param->fp_lmv_md->lum_stripe_count = 0;
5594 param->fp_lmv_md->lum_hash_type = 0;
5596 if (param->fp_check_foreign) {
5597 if (param->fp_exclude_foreign)
5606 if (param->fp_check_mdt_count) {
5607 if (lmv_is_foreign(param->fp_lmv_md->lum_magic))
5610 decision = find_value_cmp(param->fp_lmv_md->lum_stripe_count,
5611 param->fp_mdt_count,
5612 param->fp_mdt_count_sign,
5613 param->fp_exclude_mdt_count, 1, 0);
5618 if (param->fp_hash_type) {
5620 __u32 type = param->fp_lmv_md->lum_hash_type &
5623 if (lmv_is_foreign(param->fp_lmv_md->lum_magic))
5626 found = (1 << type) & param->fp_hash_type;
5627 if ((found && param->fp_exclude_hash_type) ||
5628 (!found && !param->fp_exclude_hash_type))
5632 if (param->fp_check_hash_flag) {
5633 __u32 flags = param->fp_lmv_md->lum_hash_type &
5634 ~LMV_HASH_TYPE_MASK;
5636 if (lmv_is_foreign(param->fp_lmv_md->lum_magic))
5639 if (!(flags & param->fp_hash_inflags) ||
5640 (flags & param->fp_hash_exflags))
5645 param->fp_lmd->lmd_lmm.lmm_magic = 0;
5646 ret = get_lmd_info_fd(path, p, d, param->fp_lmd,
5647 param->fp_lum_size, GET_LMD_INFO);
5648 if (ret == 0 && param->fp_lmd->lmd_lmm.lmm_magic == 0 &&
5649 find_check_lmm_info(param)) {
5650 struct lov_user_md *lmm = ¶m->fp_lmd->lmd_lmm;
5653 * We need to "fake" the "use the default" values
5654 * since the lmm struct is zeroed out at this point.
5656 lmm->lmm_magic = LOV_USER_MAGIC_V1;
5657 lmm->lmm_pattern = LOV_PATTERN_DEFAULT;
5659 ostid_set_seq(&lmm->lmm_oi,
5660 FID_SEQ_LOV_DEFAULT);
5661 lmm->lmm_stripe_size = 0;
5662 lmm->lmm_stripe_count = 0;
5663 lmm->lmm_stripe_offset = -1;
5665 if (ret == 0 && (param->fp_mdt_uuid != NULL || gather_all)) {
5667 ret = llapi_file_fget_mdtidx(d,
5668 ¶m->fp_file_mdt_index);
5670 * Make sure lum_stripe_offset matches
5671 * mdt_index even for unstriped directories.
5673 if (ret == 0 && param->fp_get_lmv)
5674 param->fp_lmv_md->lum_stripe_offset =
5675 param->fp_file_mdt_index;
5676 } else if (S_ISREG(lmd->lmd_stx.stx_mode)) {
5678 * FIXME: we could get the MDT index from the
5679 * file's FID in lmd->lmd_lmm.lmm_oi without
5680 * opening the file, once we are sure that
5681 * LFSCK2 (2.6) has fixed up pre-2.0 LOV EAs.
5682 * That would still be an ioctl() to map the
5683 * FID to the MDT, but not an open RPC.
5685 fd = open(path, O_RDONLY);
5687 ret = llapi_file_fget_mdtidx(fd,
5688 ¶m->fp_file_mdt_index);
5694 * For a special file, we assume it resides on
5695 * the same MDT as the parent directory.
5697 ret = llapi_file_fget_mdtidx(p,
5698 ¶m->fp_file_mdt_index);
5709 stripe_count = find_get_stripe_count(param);
5713 /* Check the file permissions from the stat info */
5714 if (param->fp_perm_sign) {
5715 decision = check_file_permissions(param, lmd->lmd_stx.stx_mode);
5720 if (param->fp_type && !checked_type) {
5721 if ((param->fp_check_mdt_count || param->fp_check_hash_flag ||
5722 param->fp_hash_type) && !S_ISDIR(lmd->lmd_stx.stx_mode))
5725 if ((lmd->lmd_stx.stx_mode & S_IFMT) == param->fp_type) {
5726 if (param->fp_exclude_type)
5729 if (!param->fp_exclude_type)
5735 if (param->fp_obd_uuid || param->fp_mdt_uuid) {
5736 if (lustre_fs && param->fp_got_uuids &&
5737 param->fp_dev != makedev(lmd->lmd_stx.stx_dev_major,
5738 lmd->lmd_stx.stx_dev_minor)) {
5739 /* A lustre/lustre mount point is crossed. */
5740 param->fp_got_uuids = 0;
5741 param->fp_obds_printed = 0;
5742 param->fp_mdt_index = OBD_NOT_FOUND;
5743 param->fp_obd_index = OBD_NOT_FOUND;
5746 if (lustre_fs && !param->fp_got_uuids) {
5747 ret = setup_target_indexes((d != -1) ? d : p, path,
5752 param->fp_dev = makedev(lmd->lmd_stx.stx_dev_major,
5753 lmd->lmd_stx.stx_dev_minor);
5754 } else if (!lustre_fs && param->fp_got_uuids) {
5755 /* A lustre/non-lustre mount point is crossed. */
5756 param->fp_got_uuids = 0;
5757 param->fp_mdt_index = OBD_NOT_FOUND;
5758 param->fp_obd_index = OBD_NOT_FOUND;
5762 if (param->fp_check_foreign) {
5763 decision = find_check_foreign(param);
5768 if (param->fp_check_stripe_size) {
5769 decision = find_check_stripe_size(param);
5774 if (param->fp_check_ext_size) {
5775 decision = find_check_ext_size(param);
5780 if (param->fp_check_stripe_count) {
5781 decision = find_value_cmp(stripe_count, param->fp_stripe_count,
5782 param->fp_stripe_count_sign,
5783 param->fp_exclude_stripe_count, 1, 0);
5788 if (param->fp_check_layout) {
5789 decision = find_check_layout(param);
5794 /* If an OBD UUID is specified but none matches, skip this file. */
5795 if ((param->fp_obd_uuid && param->fp_obd_index == OBD_NOT_FOUND) ||
5796 (param->fp_mdt_uuid && param->fp_mdt_index == OBD_NOT_FOUND))
5800 * If an OST or MDT UUID is given, and some OST matches,
5803 if (param->fp_obd_index != OBD_NOT_FOUND ||
5804 param->fp_mdt_index != OBD_NOT_FOUND) {
5805 if (param->fp_obd_uuid) {
5806 if (check_obd_match(param)) {
5808 * If no mdtuuid is given, we are done.
5809 * Otherwise, fall through to the mdtuuid
5812 if (!param->fp_mdt_uuid)
5819 if (param->fp_mdt_uuid) {
5820 if (check_mdt_match(param))
5827 if (param->fp_check_uid) {
5828 if (lmd->lmd_stx.stx_uid == param->fp_uid) {
5829 if (param->fp_exclude_uid)
5832 if (!param->fp_exclude_uid)
5837 if (param->fp_check_gid) {
5838 if (lmd->lmd_stx.stx_gid == param->fp_gid) {
5839 if (param->fp_exclude_gid)
5842 if (!param->fp_exclude_gid)
5847 if (param->fp_check_projid || gather_all) {
5851 fd = open(path, O_RDONLY);
5854 ret = fget_projid(fd, &projid);
5859 if (projid == param->fp_projid) {
5860 if (param->fp_exclude_projid)
5863 if (!param->fp_exclude_projid)
5868 if (param->fp_check_pool) {
5869 decision = find_check_pool(param);
5874 if (param->fp_check_comp_count || param->fp_check_comp_flags ||
5875 param->fp_check_comp_start || param->fp_check_comp_end) {
5876 decision = find_check_comp_options(param);
5881 if (param->fp_check_mirror_count || param->fp_check_mirror_state) {
5882 decision = find_check_mirror_options(param);
5887 /* Check the time on mds. */
5889 if (param->fp_atime || param->fp_mtime || param->fp_ctime) {
5892 for_mds = lustre_fs ?
5893 (S_ISREG(lmd->lmd_stx.stx_mode) && stripe_count) : 0;
5894 decision = find_time_check(param, for_mds);
5899 if (param->fp_btime) {
5900 if (!(lmd->lmd_stx.stx_mask & STATX_BTIME)) {
5905 decision = find_value_cmp(lmd->lmd_stx.stx_btime.tv_sec,
5906 param->fp_btime, param->fp_bsign,
5907 param->fp_exclude_btime,
5908 param->fp_time_margin, 0);
5913 if (param->fp_newerxy) {
5916 for_mds = lustre_fs ?
5917 (S_ISREG(lmd->lmd_stx.stx_mode) && stripe_count) : 0;
5918 decision = find_newerxy_check(param, for_mds, true);
5927 flags = param->fp_lmd->lmd_flags;
5928 if (param->fp_check_size &&
5929 ((S_ISREG(lmd->lmd_stx.stx_mode) && stripe_count) ||
5930 S_ISDIR(lmd->lmd_stx.stx_mode)) &&
5931 !(flags & OBD_MD_FLSIZE ||
5932 (param->fp_lazy && flags & OBD_MD_FLLAZYSIZE)))
5935 if (param->fp_check_blocks &&
5936 ((S_ISREG(lmd->lmd_stx.stx_mode) && stripe_count) ||
5937 S_ISDIR(lmd->lmd_stx.stx_mode)) &&
5938 !(flags & OBD_MD_FLBLOCKS ||
5939 (param->fp_lazy && flags & OBD_MD_FLLAZYBLOCKS)))
5943 * If file still fits the request, ask ost for updated info.
5944 * The regular stat is almost of the same speed as some new
5945 * 'glimpse-size-ioctl'.
5947 if (!decision || gather_all) {
5951 * For regular files with the stripe the decision may have not
5952 * been taken yet if *time or size is to be checked.
5954 if (param->fp_obd_index != OBD_NOT_FOUND)
5955 print_failed_tgt(param, path, LL_STATFS_LOV);
5957 if (param->fp_mdt_index != OBD_NOT_FOUND)
5958 print_failed_tgt(param, path, LL_STATFS_LMV);
5961 ret = fstat_f(d, &st);
5962 else if (de != NULL)
5963 ret = fstatat_f(p, de->d_name, &st,
5964 AT_SYMLINK_NOFOLLOW);
5966 ret = lstat_f(path, &st);
5969 if (errno == ENOENT) {
5970 llapi_error(LLAPI_MSG_ERROR, -ENOENT,
5971 "warning: %s: %s does not exist",
5976 llapi_error(LLAPI_MSG_ERROR, ret,
5977 "%s: stat on %s failed",
5983 convert_lmd_statx(param->fp_lmd, &st, true);
5984 /* Check the time on osc. */
5985 decision = find_time_check(param, 0);
5989 if (param->fp_newerxy) {
5990 decision = find_newerxy_check(param, 0, false);
6000 if (param->fp_check_size) {
6001 decision = find_value_cmp(lmd->lmd_stx.stx_size,
6003 param->fp_size_sign,
6004 param->fp_exclude_size,
6005 param->fp_size_units, 0);
6010 if (param->fp_check_blocks) { /* convert st_blocks to bytes */
6011 decision = find_value_cmp(lmd->lmd_stx.stx_blocks * 512,
6013 param->fp_blocks_sign,
6014 param->fp_exclude_blocks,
6015 param->fp_blocks_units, 0);
6021 if (param->fp_format_printf_str)
6022 printf_format_string(param, path, projid, d);
6024 llapi_printf(LLAPI_MSG_NORMAL, "%s%c", path,
6025 param->fp_zero_end ? '\0' : '\n');
6029 /* Do not get down anymore? */
6030 if (param->fp_depth == param->fp_max_depth) {
6041 static int cb_migrate_mdt_init(char *path, int p, int *dp,
6042 void *param_data, struct dirent64 *de)
6044 struct find_param *param = (struct find_param *)param_data;
6045 struct lmv_user_md *lmu = param->fp_lmv_md;
6047 char raw[MAX_IOC_BUFLEN] = {'\0'};
6049 struct obd_ioctl_data data = { 0 };
6055 if (p == -1 && dp == NULL)
6061 if (dp != NULL && *dp != -1)
6065 tmp_p = open_parent(path);
6069 llapi_error(LLAPI_MSG_ERROR, ret,
6070 "can not open %s", path);
6075 path_copy = strdup(path);
6076 filename = basename(path_copy);
6078 data.ioc_inlbuf1 = (char *)filename;
6079 data.ioc_inllen1 = strlen(filename) + 1;
6080 data.ioc_inlbuf2 = (char *)lmu;
6081 data.ioc_inllen2 = lmv_user_md_size(lmu->lum_stripe_count,
6084 if (param->fp_depth == param->fp_max_depth)
6085 data.ioc_type = MDS_MIGRATE_NSONLY;
6086 ret = llapi_ioctl_pack(&data, &rawbuf, sizeof(raw));
6088 llapi_error(LLAPI_MSG_ERROR, ret,
6089 "%s: error packing ioctl data", __func__);
6094 ret = ioctl(tmp_p, LL_IOC_MIGRATE, rawbuf);
6096 if (errno == EBUSY && !retry) {
6098 * because migrate may not be able to lock all involved
6099 * objects in order, for some of them it try lock, while
6100 * there may be conflicting COS locks and cause migrate
6101 * fail with EBUSY, hope a sync() could cause
6102 * transaction commit and release these COS locks.
6107 } else if (errno == EALREADY) {
6108 if (param->fp_verbose & VERBOSE_DETAIL)
6109 llapi_printf(LLAPI_MSG_NORMAL,
6110 "%s migrated to MDT%d already\n",
6111 path, lmu->lum_stripe_offset);
6115 llapi_error(LLAPI_MSG_ERROR, ret, "%s migrate failed",
6119 } else if (param->fp_verbose & VERBOSE_DETAIL) {
6120 llapi_printf(LLAPI_MSG_NORMAL,
6121 "migrate %s to MDT%d stripe count %d\n",
6122 path, lmu->lum_stripe_offset,
6123 lmu->lum_stripe_count);
6127 /* Do not get down anymore? */
6128 if (param->fp_depth == param->fp_max_depth)
6135 * If the directory is being migration, we need
6136 * close the directory after migration,
6137 * so the old directory cache will be cleanup
6138 * on the client side, and re-open to get the
6139 * new directory handle
6141 *dp = open(path, O_RDONLY|O_NDELAY|O_DIRECTORY);
6144 llapi_error(LLAPI_MSG_ERROR, ret,
6145 "%s: Failed to open '%s'", __func__, path);
6157 /* dir migration finished, shrink its stripes */
6158 static int cb_migrate_mdt_fini(char *path, int p, int *dp, void *data,
6159 struct dirent64 *de)
6161 struct find_param *param = data;
6162 struct lmv_user_md *lmu = param->fp_lmv_md;
6163 int lmulen = lmv_user_md_size(lmu->lum_stripe_count, lmu->lum_magic);
6166 if (de && de->d_type != DT_DIR)
6171 * close it before setxattr because the latter may destroy the
6172 * original object, and cause close fail.
6180 ret = setxattr(path, XATTR_NAME_LMV, lmu, lmulen, 0);
6181 if (ret == -EALREADY)
6184 cb_common_fini(path, p, dp, data, de);
6188 int llapi_migrate_mdt(char *path, struct find_param *param)
6190 param->fp_stop_on_error = 1;
6191 return param_callback(path, cb_migrate_mdt_init, cb_migrate_mdt_fini,
6195 int llapi_mv(char *path, struct find_param *param)
6197 #if LUSTRE_VERSION_CODE > OBD_OCD_VERSION(2, 9, 59, 0)
6198 static bool printed;
6201 llapi_error(LLAPI_MSG_ERROR, -ESTALE,
6202 "%s() is deprecated, use llapi_migrate_mdt() instead",
6207 return llapi_migrate_mdt(path, param);
6211 * Check string for escape sequences and print a message to stdout
6212 * if any invalid escapes are found.
6214 * @param[in] c Pointer to character immediately following the
6215 * '\' character indicating the start of an escape
6217 * @return Number of characters examined in the escape sequence
6218 * (regardless of whether the sequence is valid or not).
6220 int validate_printf_esc(char *c)
6222 char *valid_esc = "nt\\";
6225 /* backslash at end of string */
6226 llapi_err_noerrno(LLAPI_MSG_WARN,
6227 "warning: '\\' at end of -printf format string\n");
6231 if (!strchr(valid_esc, *c))
6232 /* Invalid escape character */
6233 llapi_err_noerrno(LLAPI_MSG_WARN,
6234 "warning: unrecognized escape: '\\%c'\n", *c);
6240 * Check string for format directives and print a message to stdout
6241 * if any invalid directives are found.
6243 * @param[in] c Pointer to character immediately following the
6244 * '%' character indicating the start of a format
6246 * @return Number of characters examined in the format directive
6247 * (regardless of whether the directive is valid or not).
6249 int validate_printf_fmt(char *c)
6251 char *valid_fmt_single = "abcGkmpstUwy%";
6252 char *valid_fmt_double = "ACTW";
6253 char *valid_fmt_lustre = "cFhioPpS";
6254 char curr = *c, next;
6257 llapi_err_noerrno(LLAPI_MSG_WARN,
6258 "warning: '%%' at end of -printf format string\n");
6263 if ((next == '\0') || (next == '%') || (next == '\\'))
6264 /* Treat as single char format directive */
6267 /* Check format directives with multiple characters */
6268 if (strchr(valid_fmt_double, curr)) {
6269 /* For now, only valid formats are followed by '@' char */
6271 llapi_err_noerrno(LLAPI_MSG_WARN,
6272 "warning: unrecognized format directive: '%%%c%c'\n",
6277 /* Lustre formats always start with 'L' */
6279 if (!strchr(valid_fmt_lustre, next))
6280 llapi_err_noerrno(LLAPI_MSG_WARN,
6281 "warning: unrecognized format directive: '%%%c%c'\n",
6288 if (!strchr(valid_fmt_single, curr))
6289 llapi_err_noerrno(LLAPI_MSG_WARN,
6290 "warning: unrecognized format directive: '%%%c'\n", curr);
6295 * Validate the user-supplied string for the -printf option and report
6296 * any invalid backslash escape sequences or format directives.
6298 * @param[in] param Structure containing info about invocation of lfs find
6301 void validate_printf_str(struct find_param *param)
6303 char *c = param->fp_format_printf_str;
6309 ret = validate_printf_fmt(++c);
6313 ret = validate_printf_esc(++c);
6323 int llapi_find(char *path, struct find_param *param)
6325 if (param->fp_format_printf_str)
6326 validate_printf_str(param);
6327 return param_callback(path, cb_find_init, cb_common_fini, param);
6331 * Get MDT number that the file/directory inode referenced
6332 * by the open fd resides on.
6333 * Return 0 and mdtidx on success, or -ve errno.
6335 int llapi_file_fget_mdtidx(int fd, int *mdtidx)
6337 if (ioctl(fd, LL_IOC_GET_MDTIDX, mdtidx) < 0)
6342 static int cb_get_mdt_index(char *path, int p, int *dp, void *data,
6343 struct dirent64 *de)
6345 struct find_param *param = (struct find_param *)data;
6346 int d = dp == NULL ? -1 : *dp;
6350 if (p == -1 && d == -1)
6354 ret = llapi_file_fget_mdtidx(d, &mdtidx);
6355 } else /* if (p != -1) */ {
6358 fd = open(path, O_RDONLY | O_NOCTTY);
6360 ret = llapi_file_fget_mdtidx(fd, &mdtidx);
6368 if (ret == -ENODATA) {
6369 if (!param->fp_obd_uuid)
6370 llapi_printf(LLAPI_MSG_NORMAL,
6371 "'%s' has no stripe info\n", path);
6373 } else if (ret == -ENOENT) {
6374 llapi_error(LLAPI_MSG_WARN, ret,
6375 "warning: %s: '%s' does not exist",
6378 } else if (ret == -ENOTTY) {
6379 llapi_error(LLAPI_MSG_ERROR, ret,
6380 "%s: '%s' not on a Lustre fs",
6383 llapi_error(LLAPI_MSG_ERROR, ret,
6384 "error: %s: '%s' failed get_mdtidx",
6390 if (param->fp_quiet || !(param->fp_verbose & VERBOSE_DETAIL))
6391 llapi_printf(LLAPI_MSG_NORMAL, "%d\n", mdtidx);
6393 llapi_printf(LLAPI_MSG_NORMAL, "%s\nmdt_index:\t%d\n",
6397 /* Do not go down anymore? */
6398 if (param->fp_depth == param->fp_max_depth)
6406 static int cb_getstripe(char *path, int p, int *dp, void *data,
6407 struct dirent64 *de)
6409 struct find_param *param = (struct find_param *)data;
6410 int d = dp == NULL ? -1 : *dp;
6413 if (p == -1 && d == -1)
6416 if (param->fp_obd_uuid) {
6417 param->fp_quiet = 1;
6418 ret = setup_obd_uuid(d != -1 ? d : p, path, param);
6423 if (d != -1 && (param->fp_get_lmv || param->fp_get_default_lmv))
6424 ret = cb_get_dirstripe(path, &d, param);
6426 (p != -1 && !param->fp_get_lmv && !param->fp_get_default_lmv))
6427 ret = get_lmd_info_fd(path, p, d, ¶m->fp_lmd->lmd_lmm,
6428 param->fp_lum_size, GET_LMD_STRIPE);
6429 else if (d == -1 && (param->fp_get_lmv || param->fp_get_default_lmv)) {
6430 /* in case of a dangling or valid faked symlink dir, opendir()
6431 * should have return either EINVAL or ENOENT, so let's try
6432 * to get LMV just in case, and by opening it as a file but
6433 * with O_NOFOLLOW ...
6435 int fd = open(path, O_RDONLY | O_NOFOLLOW);
6439 ret = cb_get_dirstripe(path, &fd, param);
6441 llapi_lov_dump_user_lmm(param, path, LDF_IS_DIR);
6448 if (errno == ENODATA && d != -1) {
6450 * We need to "fake" the "use the default" values
6451 * since the lmm struct is zeroed out at this point.
6452 * The magic needs to be set in order to satisfy
6453 * a check later on in the code path.
6454 * The object_seq needs to be set for the "(Default)"
6455 * prefix to be displayed.
6457 if (param->fp_get_default_lmv) {
6458 struct lmv_user_md *lum = param->fp_lmv_md;
6460 lum->lum_magic = LMV_USER_MAGIC;
6461 lum->lum_stripe_count = 0;
6462 lum->lum_stripe_offset = LMV_OFFSET_DEFAULT;
6464 } else if (param->fp_get_lmv) {
6465 struct lmv_user_md *lum = param->fp_lmv_md;
6468 ret = llapi_file_fget_mdtidx(d, &mdtidx);
6471 lum->lum_magic = LMV_MAGIC_V1;
6472 lum->lum_stripe_count = 0;
6473 lum->lum_stripe_offset = mdtidx;
6476 struct lov_user_md *lmm =
6477 ¶m->fp_lmd->lmd_lmm;
6479 lmm->lmm_magic = LOV_USER_MAGIC_V1;
6481 ostid_set_seq(&lmm->lmm_oi,
6482 FID_SEQ_LOV_DEFAULT);
6483 lmm->lmm_stripe_count = 0;
6484 lmm->lmm_stripe_size = 0;
6485 lmm->lmm_stripe_offset = -1;
6488 } else if (errno == ENODATA && p != -1) {
6489 if (!param->fp_obd_uuid && !param->fp_mdt_uuid)
6490 llapi_printf(LLAPI_MSG_NORMAL,
6491 "%s has no stripe info\n", path);
6493 } else if (errno == ENOENT) {
6494 llapi_error(LLAPI_MSG_WARN, -ENOENT,
6495 "warning: %s: %s does not exist",
6498 } else if (errno == ENOTTY) {
6500 llapi_error(LLAPI_MSG_ERROR, ret,
6501 "%s: '%s' not on a Lustre fs?",
6506 llapi_error(LLAPI_MSG_ERROR, ret,
6507 "error: %s: %s failed for %s",
6509 "LL_IOC_LOV_GETSTRIPE" :
6510 "IOC_MDC_GETFILESTRIPE", path);
6517 if (!(param->fp_verbose & VERBOSE_MDTINDEX))
6518 llapi_lov_dump_user_lmm(param, path, d != -1 ? LDF_IS_DIR : 0);
6521 /* Do not get down anymore? */
6522 if (param->fp_depth == param->fp_max_depth)
6530 int llapi_getstripe(char *path, struct find_param *param)
6532 return param_callback(path, (param->fp_verbose & VERBOSE_MDTINDEX) ?
6533 cb_get_mdt_index : cb_getstripe,
6534 cb_common_fini, param);
6537 int llapi_obd_fstatfs(int fd, __u32 type, __u32 index,
6538 struct obd_statfs *stat_buf, struct obd_uuid *uuid_buf)
6540 char raw[MAX_IOC_BUFLEN] = {'\0'};
6542 struct obd_ioctl_data data = { 0 };
6545 data.ioc_inlbuf1 = (char *)&type;
6546 data.ioc_inllen1 = sizeof(__u32);
6547 data.ioc_inlbuf2 = (char *)&index;
6548 data.ioc_inllen2 = sizeof(__u32);
6549 data.ioc_pbuf1 = (char *)stat_buf;
6550 data.ioc_plen1 = sizeof(struct obd_statfs);
6551 data.ioc_pbuf2 = (char *)uuid_buf;
6552 data.ioc_plen2 = sizeof(struct obd_uuid);
6554 rc = llapi_ioctl_pack(&data, &rawbuf, sizeof(raw));
6556 llapi_error(LLAPI_MSG_ERROR, rc,
6557 "%s: error packing ioctl data", __func__);
6561 rc = ioctl(fd, IOC_OBD_STATFS, (void *)rawbuf);
6563 return rc < 0 ? -errno : 0;
6566 int llapi_obd_statfs(char *path, __u32 type, __u32 index,
6567 struct obd_statfs *stat_buf, struct obd_uuid *uuid_buf)
6572 fd = open(path, O_RDONLY);
6575 llapi_error(LLAPI_MSG_ERROR, rc, "error: %s: opening '%s'",
6578 * If we can't even open a file on the filesystem (e.g. with
6579 * -ESHUTDOWN), force caller to exit or it will loop forever.
6584 rc = llapi_obd_fstatfs(fd, type, index, stat_buf, uuid_buf);
6591 #define MAX_STRING_SIZE 128
6593 int llapi_ping(char *obd_type, char *obd_name)
6595 int flags = O_RDONLY;
6596 char buf[1] = { 0 };
6600 rc = cfs_get_param_paths(&path, "%s/%s/ping",
6601 obd_type, obd_name);
6605 fd = open(path.gl_pathv[0], flags);
6607 if (errno == EACCES && flags == O_RDONLY) {
6612 llapi_error(LLAPI_MSG_ERROR, rc, "error opening %s",
6617 if (flags == O_RDONLY)
6618 rc = read(fd, buf, sizeof(buf));
6620 rc = write(fd, buf, sizeof(buf));
6628 cfs_free_param_data(&path);
6632 int llapi_target_iterate(int type_num, char **obd_type,
6633 void *args, llapi_cb_t cb)
6639 for (i = 0; i < type_num; i++) {
6642 rc = cfs_get_param_paths(¶m, "%s/*/uuid", obd_type[i]);
6646 for (j = 0; j < param.gl_pathc; j++) {
6647 char obd_uuid[UUID_MAX + 1];
6651 fp = fopen(param.gl_pathv[j], "r");
6654 llapi_error(LLAPI_MSG_ERROR, rc,
6655 "error: opening '%s'",
6660 if (fgets(obd_uuid, sizeof(obd_uuid), fp) == NULL) {
6662 llapi_error(LLAPI_MSG_ERROR, rc,
6663 "error: reading '%s'",
6668 /* Extract the obd_name from the sysfs path.
6669 * 'topsysfs'/fs/lustre/'obd_type'/'obd_name'.
6671 obd_name = strstr(param.gl_pathv[j], "/fs/lustre/");
6677 /* skip /fs/lustre/'obd_type'/ */
6678 obd_name += strlen(obd_type[i]) + 12;
6679 /* chop off after obd_name */
6680 ptr = strrchr(obd_name, '/');
6684 cb(obd_type[i], obd_name, obd_uuid, args);
6693 cfs_free_param_data(¶m);
6697 static void do_target_check(char *obd_type_name, char *obd_name,
6698 char *obd_uuid, void *args)
6702 rc = llapi_ping(obd_type_name, obd_name);
6704 llapi_printf(LLAPI_MSG_NORMAL, "%s inactive.\n", obd_name);
6706 llapi_error(LLAPI_MSG_ERROR, rc, "error: check '%s'", obd_name);
6708 llapi_printf(LLAPI_MSG_NORMAL, "%s active.\n", obd_name);
6711 int llapi_target_check(int type_num, char **obd_type, char *dir)
6713 return llapi_target_iterate(type_num, obd_type, NULL, do_target_check);
6716 #undef MAX_STRING_SIZE
6718 /* Is this a lustre fs? */
6719 int llapi_is_lustre_mnttype(const char *type)
6721 return strcmp(type, "lustre") == 0 || strcmp(type, "lustre_tgt") == 0;
6724 /* Is this a lustre client fs? */
6725 int llapi_is_lustre_mnt(struct mntent *mnt)
6727 return (llapi_is_lustre_mnttype(mnt->mnt_type) &&
6728 strstr(mnt->mnt_fsname, ":/") != NULL);
6731 int llapi_quotactl(char *mnt, struct if_quotactl *qctl)
6733 char fsname[PATH_MAX + 1];
6737 rc = llapi_search_fsname(mnt, fsname);
6741 root = open(mnt, O_RDONLY | O_DIRECTORY);
6744 llapi_error(LLAPI_MSG_ERROR, rc, "cannot open '%s'", mnt);
6748 rc = ioctl(root, OBD_IOC_QUOTACTL, qctl);
6751 if (rc == -ENOENT && LUSTRE_Q_CMD_IS_POOL(qctl->qc_cmd))
6752 llapi_error(LLAPI_MSG_ERROR | LLAPI_MSG_NO_ERRNO, rc,
6753 "Cannot find pool '%s'", qctl->qc_poolname);
6759 int llapi_get_connect_flags(const char *mnt, __u64 *flags)
6764 root = open(mnt, O_RDONLY | O_DIRECTORY);
6767 llapi_error(LLAPI_MSG_ERROR, rc, "open %s failed", mnt);
6771 rc = ioctl(root, LL_IOC_GET_CONNECT_FLAGS, flags);
6774 llapi_error(LLAPI_MSG_ERROR, rc,
6775 "ioctl on %s for getting connect flags failed", mnt);
6782 * Flush cached pages from all clients.
6784 * \param fd File descriptor
6788 int llapi_file_flush(int fd)
6792 return llapi_get_data_version(fd, &dv, LL_DV_WR_FLUSH);