1 // SPDX-License-Identifier: LGPL-2.1+
3 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
4 * Use is subject to license terms.
6 * Copyright (c) 2011, 2017, Intel Corporation.
9 * This file is part of Lustre, http://www.lustre.org/
11 * Author: Peter J. Braam <braam@clusterfs.com>
12 * Author: Phil Schwan <phil@clusterfs.com>
13 * Author: Robert Read <rread@clusterfs.com>
32 #include <sys/ioctl.h>
36 #include <sys/statfs.h>
37 #include <sys/syscall.h>
39 #include <sys/types.h>
40 #include <sys/xattr.h>
41 #include <sys/sysmacros.h>
44 #include <libgen.h> /* for dirname() */
45 #include <linux/limits.h>
46 #ifdef HAVE_LINUX_UNISTD_H
47 #include <linux/unistd.h>
56 #include <libcfs/util/ioctl.h>
57 #include <libcfs/util/param.h>
58 #include <libcfs/util/string.h>
59 #include <linux/lnet/lnetctl.h>
60 #include <lustre/lustreapi.h>
61 #include <linux/lustre/lustre_ostid.h>
62 #include <linux/lustre/lustre_ioctl.h>
64 #include "lustreapi_internal.h"
66 #define FORMATTED_BUF_LEN 1024
68 #ifndef DEFAULT_PROJID
69 #define DEFAULT_PROJID 0
72 static int llapi_msg_level = LLAPI_MSG_MAX;
73 const char *liblustreapi_cmd;
75 struct lustre_foreign_type lu_foreign_types[] = {
76 {.lft_type = LU_FOREIGN_TYPE_NONE, .lft_name = "none"},
77 {.lft_type = LU_FOREIGN_TYPE_POSIX, .lft_name = "posix"},
78 {.lft_type = LU_FOREIGN_TYPE_PCCRW, .lft_name = "pccrw"},
79 {.lft_type = LU_FOREIGN_TYPE_PCCRO, .lft_name = "pccro"},
80 {.lft_type = LU_FOREIGN_TYPE_S3, .lft_name = "S3"},
81 {.lft_type = LU_FOREIGN_TYPE_SYMLINK, .lft_name = "symlink"},
82 /* must be the last element */
83 {.lft_type = LU_FOREIGN_TYPE_UNKNOWN, .lft_name = NULL}
84 /* array max dimension must be <= UINT32_MAX */
87 void llapi_msg_set_level(int level)
89 /* ensure level is in the good range */
90 if (level < LLAPI_MSG_OFF)
91 llapi_msg_level = LLAPI_MSG_OFF;
92 else if (level > LLAPI_MSG_MAX)
93 llapi_msg_level = LLAPI_MSG_MAX;
95 llapi_msg_level = level;
98 int llapi_msg_get_level(void)
100 return llapi_msg_level;
103 void llapi_set_command_name(const char *cmd)
105 liblustreapi_cmd = cmd;
108 void llapi_clear_command_name(void)
110 liblustreapi_cmd = NULL;
113 static void error_callback_default(enum llapi_message_level level, int err,
114 const char *fmt, va_list ap)
116 bool has_nl = strchr(fmt, '\n') != NULL;
118 if (liblustreapi_cmd != NULL)
119 fprintf(stderr, "%s %s: ", program_invocation_short_name,
122 fprintf(stderr, "%s: ", program_invocation_short_name);
125 if (level & LLAPI_MSG_NO_ERRNO) {
126 vfprintf(stderr, fmt, ap);
128 fprintf(stderr, "\n");
133 * Remove trailing linefeed so error string can be appended.
134 * @fmt is a const string, so we can't modify it directly.
136 if (has_nl && (newfmt = strdup(fmt)))
137 *strrchr(newfmt, '\n') = '\0';
139 newfmt = (char *)fmt;
141 vfprintf(stderr, newfmt, ap);
144 fprintf(stderr, ": %s (%d)\n", strerror(err), err);
148 static void info_callback_default(enum llapi_message_level level, int err,
149 const char *fmt, va_list ap)
152 if (liblustreapi_cmd != NULL) {
153 fprintf(stdout, "%s %s: ",
154 program_invocation_short_name,
157 fprintf(stdout, "%s: ", program_invocation_short_name);
160 vfprintf(stdout, fmt, ap);
163 static llapi_log_callback_t llapi_error_callback = error_callback_default;
164 static llapi_log_callback_t llapi_info_callback = info_callback_default;
167 /* llapi_error will preserve errno */
168 void llapi_error(enum llapi_message_level level, int err, const char *fmt, ...)
171 int tmp_errno = errno;
173 if ((level & LLAPI_MSG_MASK) > llapi_msg_level)
177 llapi_error_callback(level, abs(err), fmt, args);
182 /* llapi_printf will preserve errno */
183 void llapi_printf(enum llapi_message_level level, const char *fmt, ...)
186 int tmp_errno = errno;
188 if ((level & LLAPI_MSG_MASK) > llapi_msg_level)
192 llapi_info_callback(level, 0, fmt, args);
198 * Set a custom error logging function. Passing in NULL will reset the logging
199 * callback to its default value.
201 * This function returns the value of the old callback.
203 llapi_log_callback_t llapi_error_callback_set(llapi_log_callback_t cb)
205 llapi_log_callback_t old = llapi_error_callback;
208 llapi_error_callback = cb;
210 llapi_error_callback = error_callback_default;
216 * Set a custom info logging function. Passing in NULL will reset the logging
217 * callback to its default value.
219 * This function returns the value of the old callback.
221 llapi_log_callback_t llapi_info_callback_set(llapi_log_callback_t cb)
223 llapi_log_callback_t old = llapi_info_callback;
226 llapi_info_callback = cb;
228 llapi_info_callback = info_callback_default;
234 * Convert a size string (with optional suffix) into binary value.
236 * \param optarg [in] string containing numeric value with optional
237 * KMGTPE suffix to specify the unit size.
238 * The \a string may be a decimal value.
239 * \param size [out] pointer to integer numeric value to be returned
240 * \param size_units [in] units of \a string if dimensionless. Must be
241 * initialized by caller. If zero, units = bytes.
242 * \param bytes_spec [in] if suffix 'b' means bytes or 512-byte sectors.
245 * \retval -EINVAL negative or too large size, or unknown suffix
247 int llapi_parse_size(const char *optarg, unsigned long long *size,
248 unsigned long long *size_units, int bytes_spec)
251 char *argbuf = (char *)optarg;
252 unsigned long long frac = 0, frac_d = 1;
254 if (strncmp(optarg, "-", 1) == 0)
257 if (*size_units == 0)
260 *size = strtoull(argbuf, &end, 0);
261 if (end != NULL && *end == '.') {
265 frac = strtoull(argbuf, &end, 10);
266 /* count decimal places */
267 for (i = 0; i < (end - argbuf); i++)
272 char next = tolower(*(end + 1));
274 switch (tolower(*end)) {
279 if (*size & (~0ULL << (64 - 9)))
281 *size_units = 1 << 9;
288 if (*size & (~0ULL << (64 - 10)))
290 *size_units = 1 << 10;
293 if (*size & (~0ULL << (64 - 20)))
295 *size_units = 1 << 20;
298 if (*size & (~0ULL << (64 - 30)))
300 *size_units = 1 << 30;
303 if (*size & (~0ULL << (64 - 40)))
305 *size_units = 1ULL << 40;
308 if (*size & (~0ULL << (64 - 50)))
310 *size_units = 1ULL << 50;
313 if (*size & (~0ULL << (64 - 60)))
315 *size_units = 1ULL << 60;
320 if (next != '\0' && next != 'i' && next != 'b')
323 *size = *size * *size_units + frac * *size_units / frac_d;
329 * Verify the setstripe parameters before using.
330 * This is a pair method for comp_args_to_layout()/llapi_layout_sanity_cb()
331 * when just 1 component or a non-PFL layout is given.
333 * \param[in] param stripe parameters
334 * \param[in] pool_name pool name
335 * \param[in] fsname lustre FS name
338 * < 0, error code on failre
340 static int llapi_stripe_param_verify(const struct llapi_stripe_param *param,
341 const char **pool_name, char *fsname)
344 static int page_size;
347 if (page_size == 0) {
349 * 64 KB is the largest common page size (on ia64/PPC/ARM),
350 * but check the local page size just in case. The page_size
351 * will not change for the lifetime of this process at least.
353 page_size = LOV_MIN_STRIPE_SIZE;
354 if (getpagesize() > page_size) {
355 page_size = getpagesize();
356 llapi_err_noerrno(LLAPI_MSG_WARN,
357 "warning: page size (%u) larger than expected (%u)",
358 page_size, LOV_MIN_STRIPE_SIZE);
361 if (!llapi_stripe_size_is_aligned(param->lsp_stripe_size)) {
363 llapi_error(LLAPI_MSG_ERROR, rc,
364 "error: bad stripe_size %llu, must be an even multiple of %d bytes",
365 param->lsp_stripe_size, page_size);
368 if (!llapi_stripe_index_is_valid(param->lsp_stripe_offset)) {
370 llapi_error(LLAPI_MSG_ERROR, rc, "error: bad stripe offset %d",
371 param->lsp_stripe_offset);
374 if (llapi_stripe_size_is_too_big(param->lsp_stripe_size)) {
376 llapi_error(LLAPI_MSG_ERROR, rc,
377 "error: stripe size '%llu' over 4GB limit",
378 param->lsp_stripe_size);
382 count = param->lsp_stripe_count;
383 if (param->lsp_stripe_pattern & LOV_PATTERN_MDT) {
385 llapi_error(LLAPI_MSG_ERROR, rc,
386 "Invalid pattern: '-L mdt', must be specified "
390 if (!llapi_stripe_count_is_valid(count)) {
392 llapi_error(LLAPI_MSG_ERROR, rc,
393 "Invalid stripe count %d\n", count);
398 /* Make sure we have a good pool */
399 if (*pool_name != NULL) {
400 if (!llapi_pool_name_is_valid(pool_name)) {
402 llapi_error(LLAPI_MSG_ERROR, rc,
403 "Invalid Poolname '%s'", *pool_name);
407 if (!lov_pool_is_ignored((const char *) *pool_name)) {
408 /* Make sure the pool exists */
409 rc = llapi_search_ost(fsname, *pool_name, NULL);
411 llapi_error(LLAPI_MSG_ERROR, rc,
412 "pool '%s fsname %s' does not exist",
425 static int dir_stripe_limit_check(int stripe_offset, int stripe_count,
430 if (!llapi_dir_stripe_index_is_valid(stripe_offset)) {
432 llapi_error(LLAPI_MSG_ERROR, rc, "error: bad stripe offset %d",
436 if (!llapi_dir_stripe_count_is_valid(stripe_count)) {
438 llapi_error(LLAPI_MSG_ERROR, rc, "error: bad stripe count %d",
443 if (!llapi_dir_hash_type_is_valid(hash_type)) {
445 llapi_error(LLAPI_MSG_ERROR, rc, "error: bad hash type %d",
453 * Trim a trailing newline from a string, if it exists.
455 int llapi_chomp_string(char *buf)
471 * Wrapper to grab parameter settings for {lov,lmv}.*-clilov-*.* values
473 static int get_param_tgt(const char *path, enum tgt_type type,
474 const char *param, char *buf, size_t buf_size)
476 const char *typestr = type == LOV_TYPE ? "lov" : "lmv";
477 struct obd_uuid uuid;
480 rc = llapi_file_get_type_uuid(path, type, &uuid);
484 rc = get_lustre_param_value(typestr, uuid.uuid, FILTER_BY_EXACT, param,
489 static int get_mds_md_size(const char *path)
491 int md_size = lov_user_md_size(LOV_MAX_STRIPE_COUNT, LOV_USER_MAGIC_V3);
494 * Rather than open the file and do the ioctl to get the
495 * instance name and close the file and search for the param
496 * file and open the param file and read the param file and
497 * parse the value and close the param file, let's just return
498 * a large enough value. It's 2020, RAM is cheap and this is
502 if (md_size < XATTR_SIZE_MAX)
503 md_size = XATTR_SIZE_MAX;
508 int llapi_get_agent_uuid(char *path, char *buf, size_t bufsize)
510 return get_param_tgt(path, LMV_TYPE, "uuid", buf, bufsize);
514 * Open a Lustre file.
516 * \param name the name of the file to be opened
517 * \param flags access mode, see flags in open(2)
518 * \param mode permission of the file if it is created, see mode in open(2)
519 * \param param stripe pattern of the newly created file
521 * \retval file descriptor of opened file
522 * \retval negative errno on failure
524 int llapi_file_open_param(const char *name, int flags, mode_t mode,
525 const struct llapi_stripe_param *param)
527 char fsname[MAX_OBD_NAME + 1] = { 0 };
528 struct lov_user_md *lum = NULL;
529 const char *pool_name = param->lsp_pool;
530 bool use_default_striping = false;
534 /* Make sure we are on a Lustre file system */
535 if (pool_name && !lov_pool_is_ignored(pool_name)) {
536 rc = llapi_search_fsname(name, fsname);
538 llapi_error(LLAPI_MSG_ERROR, rc,
539 "'%s' is not on a Lustre filesystem", name);
544 /* Check if the stripe pattern is sane. */
545 rc = llapi_stripe_param_verify(param, &pool_name, fsname);
549 if (param->lsp_is_specific)
550 lum_size = lov_user_md_size(param->lsp_stripe_count,
551 LOV_USER_MAGIC_SPECIFIC);
553 lum_size = sizeof(struct lov_user_md_v3);
555 lum_size = sizeof(*lum);
557 lum = calloc(1, lum_size);
562 if (!use_default_striping)
563 fd = open(name, flags | O_LOV_DELAY_CREATE, mode);
565 fd = open(name, flags, mode);
567 if (errno == EISDIR && !(flags & O_DIRECTORY)) {
568 flags = O_DIRECTORY | O_RDONLY;
575 llapi_error(LLAPI_MSG_ERROR, rc, "unable to open '%s'", name);
580 /* Initialize IOCTL striping pattern structure */
581 lum->lmm_magic = LOV_USER_MAGIC_V1;
582 lum->lmm_pattern = param->lsp_stripe_pattern;
583 lum->lmm_stripe_size = param->lsp_stripe_size;
584 lum->lmm_stripe_count = param->lsp_stripe_count;
585 lum->lmm_stripe_offset = param->lsp_stripe_offset;
586 if (pool_name != NULL) {
587 struct lov_user_md_v3 *lumv3 = (void *)lum;
589 lumv3->lmm_magic = LOV_USER_MAGIC_V3;
590 snprintf(lumv3->lmm_pool_name, sizeof(lumv3->lmm_pool_name),
593 if (param->lsp_is_specific) {
594 struct lov_user_md_v3 *lumv3 = (void *)lum;
597 lumv3->lmm_magic = LOV_USER_MAGIC_SPECIFIC;
598 if (pool_name == NULL) {
600 * LOV_USER_MAGIC_SPECIFIC uses v3 format plus specified
601 * OST list, therefore if pool is not specified we have
602 * to pack a null pool name for placeholder.
604 memset(lumv3->lmm_pool_name, 0,
605 sizeof(lumv3->lmm_pool_name));
608 for (i = 0; i < param->lsp_stripe_count; i++)
609 lumv3->lmm_objects[i].l_ost_idx = param->lsp_osts[i];
612 if (!use_default_striping && ioctl(fd, LL_IOC_LOV_SETSTRIPE, lum) != 0) {
613 char errbuf[512] = "stripe already set";
614 char *errmsg = errbuf;
617 if (rc != -EEXIST && rc != -EALREADY)
618 strncpy(errbuf, strerror(errno), sizeof(errbuf) - 1);
619 if (rc == -EREMOTEIO)
620 snprintf(errbuf, sizeof(errbuf),
621 "inactive OST among your specified %d OST(s)",
622 param->lsp_stripe_count);
624 /* the only reason we get EACESS on the ioctl is if setstripe
625 * has been explicitly restricted, normal permission errors
626 * happen earlier on open() and we never call ioctl()
629 errmsg = "Setstripe is restricted by your administrator, default striping applied";
630 llapi_err_noerrno(LLAPI_MSG_WARN,
631 "setstripe warning for '%s': %s",
635 llapi_err_noerrno(LLAPI_MSG_ERROR,
636 "setstripe error for '%s': %s",
637 name, strerror(errno));
640 use_default_striping = true;
643 llapi_err_noerrno(LLAPI_MSG_ERROR,
644 "setstripe error for '%s': %s", name,
656 int llapi_file_is_encrypted(int fd)
661 rc = ioctl(fd, FS_IOC_GETFLAGS, &flags);
665 return !!(flags & LUSTRE_ENCRYPT_FL);
668 int llapi_file_open_pool(const char *name, int flags, int mode,
669 unsigned long long stripe_size, int stripe_offset,
670 int stripe_count, enum lov_pattern stripe_pattern,
673 const struct llapi_stripe_param param = {
674 .lsp_stripe_size = stripe_size,
675 .lsp_stripe_count = stripe_count,
676 .lsp_stripe_pattern = stripe_pattern,
677 .lsp_stripe_offset = stripe_offset,
678 .lsp_pool = pool_name
680 return llapi_file_open_param(name, flags, mode, ¶m);
683 int llapi_file_open(const char *name, int flags, int mode,
684 unsigned long long stripe_size, int stripe_offset,
685 int stripe_count, enum lov_pattern stripe_pattern)
687 return llapi_file_open_pool(name, flags, mode, stripe_size,
688 stripe_offset, stripe_count,
689 stripe_pattern, NULL);
692 int llapi_file_create_foreign(const char *name, mode_t mode, __u32 type,
693 __u32 flags, char *foreign_lov)
696 struct lov_foreign_md *lfm;
697 bool use_default_striping = false;
700 if (foreign_lov == NULL) {
702 llapi_error(LLAPI_MSG_ERROR, rc,
703 "foreign LOV EA content must be provided");
707 len = strlen(foreign_lov);
708 if (len > XATTR_SIZE_MAX - offsetof(struct lov_foreign_md, lfm_value) ||
711 llapi_error(LLAPI_MSG_ERROR, rc,
712 "foreign LOV EA size %zu (must be 0 < len < %zu)",
713 len, XATTR_SIZE_MAX -
714 offsetof(struct lov_foreign_md, lfm_value));
718 lfm = malloc(len + offsetof(struct lov_foreign_md, lfm_value));
721 llapi_error(LLAPI_MSG_ERROR, rc,
722 "failed to allocate lov_foreign_md");
727 if (!use_default_striping)
728 fd = open(name, O_WRONLY|O_CREAT|O_LOV_DELAY_CREATE, mode);
730 fd = open(name, O_WRONLY|O_CREAT, mode);
733 llapi_error(LLAPI_MSG_ERROR, fd, "open '%s' failed", name);
737 lfm->lfm_magic = LOV_USER_MAGIC_FOREIGN;
738 lfm->lfm_length = len;
739 lfm->lfm_type = type;
740 lfm->lfm_flags = flags;
741 memcpy(lfm->lfm_value, foreign_lov, len);
743 if (!use_default_striping && ioctl(fd, LL_IOC_LOV_SETSTRIPE, lfm) != 0) {
748 errmsg = "not on a Lustre filesystem";
749 else if (errno == EEXIST || errno == EALREADY)
750 errmsg = "stripe already set";
751 else if (errno == EACCES)
752 errmsg = "Setstripe is restricted by your administrator, default striping applied";
754 errmsg = strerror(errno);
757 /* the only reason we get ENOPERM on the ioctl is if setstripe
758 * has been explicitly restricted, normal permission errors
759 * happen earlier on open() and we never call ioctl()
762 llapi_err_noerrno(LLAPI_MSG_WARN,
763 "setstripe warning for '%s': %s",
767 llapi_err_noerrno(LLAPI_MSG_ERROR,
768 "setstripe error for '%s': %s",
769 name, strerror(errno));
772 use_default_striping = true;
775 llapi_err_noerrno(LLAPI_MSG_ERROR,
776 "setstripe error for '%s': %s", name,
793 int llapi_file_create(const char *name, unsigned long long stripe_size,
794 int stripe_offset, int stripe_count,
795 enum lov_pattern stripe_pattern)
799 fd = llapi_file_open_pool(name, O_CREAT | O_WRONLY, 0644, stripe_size,
800 stripe_offset, stripe_count, stripe_pattern,
809 int llapi_file_create_pool(const char *name, unsigned long long stripe_size,
810 int stripe_offset, int stripe_count,
811 enum lov_pattern stripe_pattern, char *pool_name)
815 fd = llapi_file_open_pool(name, O_CREAT | O_WRONLY, 0644, stripe_size,
816 stripe_offset, stripe_count, stripe_pattern,
825 static int verify_dir_param(const char *name,
826 const struct llapi_stripe_param *param)
828 char fsname[MAX_OBD_NAME + 1] = { 0 };
829 char *pool_name = param->lsp_pool;
832 /* Make sure we are on a Lustre file system */
833 rc = llapi_search_fsname(name, fsname);
835 llapi_error(LLAPI_MSG_ERROR, rc,
836 "'%s' is not on a Lustre filesystem",
841 /* Check if the stripe pattern is sane. */
842 rc = dir_stripe_limit_check(param->lsp_stripe_offset,
843 param->lsp_stripe_count,
844 param->lsp_stripe_pattern);
848 /* Make sure we have a good pool */
849 if (pool_name != NULL) {
851 * in case user gives the full pool name <fsname>.<poolname>,
854 char *ptr = strchr(pool_name, '.');
858 if (strcmp(pool_name, fsname) != 0) {
860 llapi_err_noerrno(LLAPI_MSG_ERROR,
861 "Pool '%s' is not on filesystem '%s'",
868 /* Make sure the pool exists and is non-empty */
869 rc = llapi_search_tgt(fsname, pool_name, NULL, true);
871 char *err = rc == 0 ? "has no OSTs" : "does not exist";
873 llapi_err_noerrno(LLAPI_MSG_ERROR, "pool '%s.%s' %s",
874 fsname, pool_name, err);
879 /* sanity check of target list */
880 if (param->lsp_is_specific) {
881 char mdtname[MAX_OBD_NAME + 64];
885 for (i = 0; i < param->lsp_stripe_count; i++) {
886 snprintf(mdtname, sizeof(mdtname), "%s-MDT%04x_UUID",
887 fsname, param->lsp_tgts[i]);
888 rc = llapi_search_tgt(fsname, pool_name, mdtname, true);
893 llapi_error(LLAPI_MSG_ERROR, rc,
894 "%s: cannot find MDT %s in %s",
901 /* Make sure stripe offset is in MDT list. */
902 if (param->lsp_tgts[i] == param->lsp_stripe_offset)
906 llapi_error(LLAPI_MSG_ERROR, -EINVAL,
907 "%s: stripe offset '%d' is not in the target list",
908 __func__, param->lsp_stripe_offset);
916 static inline void param2lmu(struct lmv_user_md *lmu,
917 const struct llapi_stripe_param *param)
919 lmu->lum_magic = param->lsp_is_specific ? LMV_USER_MAGIC_SPECIFIC :
921 lmu->lum_stripe_count = param->lsp_stripe_count;
922 lmu->lum_stripe_offset = param->lsp_stripe_offset;
923 lmu->lum_hash_type = param->lsp_stripe_pattern;
924 lmu->lum_max_inherit = param->lsp_max_inherit;
925 lmu->lum_max_inherit_rr = param->lsp_max_inherit_rr;
926 if (param->lsp_is_specific) {
929 for (i = 0; i < param->lsp_stripe_count; i++)
930 lmu->lum_objects[i].lum_mds = param->lsp_tgts[i];
933 snprintf(lmu->lum_pool_name, sizeof(lmu->lum_pool_name), "%s",
937 int llapi_dir_set_default_lmv(const char *name,
938 const struct llapi_stripe_param *param)
940 struct lmv_user_md lmu = { 0 };
944 rc = verify_dir_param(name, param);
948 /* TODO: default lmv doesn't support specific targets yet */
949 if (param->lsp_is_specific)
952 param2lmu(&lmu, param);
954 fd = open(name, O_DIRECTORY | O_RDONLY);
957 llapi_error(LLAPI_MSG_ERROR, rc, "unable to open '%s'", name);
961 rc = ioctl(fd, LL_IOC_LMV_SET_DEFAULT_STRIPE, &lmu);
963 char *errmsg = "stripe already set";
966 if (errno != EEXIST && errno != EALREADY)
967 errmsg = strerror(errno);
969 llapi_err_noerrno(LLAPI_MSG_ERROR,
970 "default dirstripe error on '%s': %s",
977 int llapi_dir_set_default_lmv_stripe(const char *name, int stripe_offset,
978 int stripe_count, int stripe_pattern,
979 const char *pool_name)
981 const struct llapi_stripe_param param = {
982 .lsp_stripe_count = stripe_count,
983 .lsp_stripe_offset = stripe_offset,
984 .lsp_stripe_pattern = stripe_pattern,
985 .lsp_pool = (char *)pool_name
988 return llapi_dir_set_default_lmv(name, ¶m);
992 * Create a Lustre directory.
994 * \param name the name of the directory to be created
995 * \param mode permission of the file if it is created, see mode in open(2)
996 * \param param stripe pattern of the newly created directory
998 * \retval 0 on success
999 * \retval negative errno on failure
1001 int llapi_dir_create(const char *name, mode_t mode,
1002 const struct llapi_stripe_param *param)
1004 struct lmv_user_md *lmu = NULL;
1006 struct obd_ioctl_data data = { 0 };
1009 char *dirpath = NULL;
1010 char *namepath = NULL;
1015 rc = verify_dir_param(name, param);
1019 lmu_size = lmv_user_md_size(param->lsp_stripe_count,
1020 param->lsp_is_specific ?
1021 LMV_USER_MAGIC_SPECIFIC :
1024 lmu = calloc(1, lmu_size);
1028 dirpath = strdup(name);
1034 namepath = strdup(name);
1041 param2lmu(lmu, param);
1043 filename = basename(namepath);
1044 dir = dirname(dirpath);
1046 data.ioc_inlbuf1 = (char *)filename;
1047 data.ioc_inllen1 = strlen(filename) + 1;
1048 data.ioc_inlbuf2 = (char *)lmu;
1049 data.ioc_inllen2 = lmu_size;
1050 data.ioc_type = mode;
1051 if (param->lsp_is_create)
1052 /* borrow obdo1.o_flags to store this flag */
1053 data.ioc_obdo1.o_flags = OBD_FL_OBDMDEXISTS;
1054 rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
1056 llapi_error(LLAPI_MSG_ERROR, rc,
1057 "error: LL_IOC_LMV_SETSTRIPE pack failed '%s'.",
1062 fd = open(dir, O_DIRECTORY | O_RDONLY);
1065 llapi_error(LLAPI_MSG_ERROR, rc, "unable to open '%s'", name);
1069 if (ioctl(fd, LL_IOC_LMV_SETSTRIPE, buf)) {
1070 char *errmsg = "stripe already set";
1073 if (errno != EEXIST && errno != EALREADY)
1074 errmsg = strerror(errno);
1076 llapi_err_noerrno(LLAPI_MSG_ERROR,
1077 "dirstripe error on '%s': %s", name, errmsg);
1088 * Create a foreign directory.
1090 * \param name the name of the directory to be created
1091 * \param mode permission of the file if it is created, see mode in open(2)
1092 * \param type foreign type to be set in LMV EA
1093 * \param flags foreign flags to be set in LMV EA
1094 * \param value foreign pattern to be set in LMV EA
1096 * \retval 0 on success
1097 * \retval negative errno on failure
1099 int llapi_dir_create_foreign(const char *name, mode_t mode, __u32 type,
1100 __u32 flags, const char *value)
1102 struct lmv_foreign_md *lfm = NULL;
1103 size_t lfm_size, len;
1104 struct obd_ioctl_data data = { 0 };
1107 char *dirpath = NULL;
1108 char *namepath = NULL;
1113 len = strlen(value);
1114 if (len > XATTR_SIZE_MAX - offsetof(struct lmv_foreign_md, lfm_value) ||
1117 llapi_error(LLAPI_MSG_ERROR, rc,
1118 "invalid LOV EA length %zu (must be 0 < len < %zu)",
1119 len, XATTR_SIZE_MAX -
1120 offsetof(struct lmv_foreign_md, lfm_value));
1123 lfm_size = len + offsetof(struct lmv_foreign_md, lfm_value);
1124 lfm = calloc(1, lfm_size);
1128 dirpath = strdup(name);
1134 namepath = strdup(name);
1141 lfm->lfm_magic = LMV_MAGIC_FOREIGN;
1142 lfm->lfm_length = len;
1143 lfm->lfm_type = type;
1144 lfm->lfm_flags = flags;
1145 memcpy(lfm->lfm_value, value, len);
1147 filename = basename(namepath);
1148 dir = dirname(dirpath);
1150 data.ioc_inlbuf1 = (char *)filename;
1151 data.ioc_inllen1 = strlen(filename) + 1;
1152 data.ioc_inlbuf2 = (char *)lfm;
1153 data.ioc_inllen2 = lfm_size;
1154 data.ioc_type = mode;
1155 rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
1157 llapi_error(LLAPI_MSG_ERROR, rc,
1158 "error: LL_IOC_LMV_SETSTRIPE pack failed '%s'.",
1163 fd = open(dir, O_DIRECTORY | O_RDONLY);
1166 llapi_error(LLAPI_MSG_ERROR, rc, "unable to open '%s'", name);
1170 if (ioctl(fd, LL_IOC_LMV_SETSTRIPE, buf)) {
1171 char *errmsg = "stripe already set";
1174 if (errno != EEXIST && errno != EALREADY)
1175 errmsg = strerror(errno);
1177 llapi_err_noerrno(LLAPI_MSG_ERROR,
1178 "dirstripe error on '%s': %s", name, errmsg);
1188 int llapi_dir_create_pool(const char *name, int mode, int stripe_offset,
1189 int stripe_count, enum lov_pattern stripe_pattern,
1190 const char *pool_name)
1192 const struct llapi_stripe_param param = {
1193 .lsp_stripe_count = stripe_count,
1194 .lsp_stripe_offset = stripe_offset,
1195 .lsp_stripe_pattern = stripe_pattern,
1196 .lsp_pool = (char *)pool_name
1199 return llapi_dir_create(name, mode, ¶m);
1203 * Get the list of pool members.
1204 * \param poolname string of format \<fsname\>.\<poolname\>
1205 * \param members caller-allocated array of char*
1206 * \param list_size size of the members array
1207 * \param buffer caller-allocated buffer for storing OST names
1208 * \param buffer_size size of the buffer
1210 * \return number of members retrieved for this pool
1211 * \retval -error failure
1213 int llapi_get_poolmembers(const char *poolname, char **members,
1214 int list_size, char *buffer, int buffer_size)
1216 char fsname[PATH_MAX];
1225 /* name is FSNAME.POOLNAME */
1226 if (strlen(poolname) >= sizeof(fsname))
1229 snprintf(fsname, sizeof(fsname), "%s", poolname);
1230 pool = strchr(fsname, '.');
1237 rc = poolpath(&pathname, fsname, NULL);
1239 llapi_error(LLAPI_MSG_ERROR, rc,
1240 "Lustre filesystem '%s' not found",
1245 llapi_printf(LLAPI_MSG_NORMAL, "Pool: %s.%s\n", fsname, pool);
1246 rc = snprintf(buf, sizeof(buf), "%s/%s", pathname.gl_pathv[0], pool);
1247 cfs_free_param_data(&pathname);
1248 if (rc >= sizeof(buf))
1250 fd = fopen(buf, "r");
1253 llapi_error(LLAPI_MSG_ERROR, rc, "cannot open %s", buf);
1258 while (fgets(buf, sizeof(buf), fd) != NULL) {
1259 if (nb_entries >= list_size) {
1263 buf[sizeof(buf) - 1] = '\0';
1265 tmp = strchr(buf, '\n');
1268 if (used + strlen(buf) + 1 > buffer_size) {
1273 strcpy(buffer + used, buf);
1274 members[nb_entries] = buffer + used;
1275 used += strlen(buf) + 1;
1285 * Get the list of pools in a filesystem.
1286 * \param name filesystem name or path
1287 * \param poollist caller-allocated array of char*
1288 * \param list_size size of the poollist array
1289 * \param buffer caller-allocated buffer for storing pool names
1290 * \param buffer_size size of the buffer
1292 * \return number of pools retrieved for this filesystem
1293 * \retval -error failure
1295 int llapi_get_poollist(const char *name, char **poollist, int list_size,
1296 char *buffer, int buffer_size)
1302 struct dirent *pool;
1304 unsigned int nb_entries = 0;
1305 unsigned int used = 0;
1308 /* initialize output array */
1309 for (i = 0; i < list_size; i++)
1312 /* is name a pathname ? */
1313 ptr = strchr(name, '/');
1315 char fsname_buf[MAXNAMLEN];
1317 /* We will need fsname for printing later */
1318 rc = llapi_getname(name, fsname_buf, sizeof(fsname_buf));
1322 ptr = strrchr(fsname_buf, '-');
1326 fsname = strdup(fsname_buf);
1330 /* name is FSNAME */
1331 fsname = strdup(name);
1336 rc = poolpath(&pathname, fsname, NULL);
1338 llapi_error(LLAPI_MSG_ERROR, rc,
1339 "Lustre filesystem '%s' not found", name);
1343 dir = opendir(pathname.gl_pathv[0]);
1346 llapi_error(LLAPI_MSG_ERROR, rc,
1347 "Could not open pool list for '%s'",
1354 pool = readdir(dir);
1360 /* ignore . and .. */
1361 if (!strcmp(pool->d_name, ".") || !strcmp(pool->d_name, ".."))
1364 /* check output bounds */
1365 if (nb_entries >= list_size) {
1367 goto free_dir_no_msg;
1370 /* +2 for '.' and final '\0' */
1371 if (used + strlen(pool->d_name) + strlen(fsname) + 2
1374 goto free_dir_no_msg;
1377 sprintf(buffer + used, "%s.%s", fsname, pool->d_name);
1378 poollist[nb_entries] = buffer + used;
1379 used += strlen(pool->d_name) + strlen(fsname) + 2;
1385 llapi_error(LLAPI_MSG_ERROR, rc,
1386 "Error reading pool list for '%s'", name);
1388 llapi_printf(LLAPI_MSG_NORMAL, "Pools from %s:\n", fsname);
1393 cfs_free_param_data(&pathname);
1396 return rc != 0 ? rc : nb_entries;
1399 /* wrapper for lfs.c and obd.c */
1400 int llapi_poollist(const char *name)
1402 int poolcount, rc, i;
1405 rc = llapi_get_poolbuf(name, &buf, &pools, &poolcount);
1409 for (i = 0; i < poolcount; i++)
1410 llapi_printf(LLAPI_MSG_NORMAL, "%s\n", pools[i]);
1417 * Get buffer that holds uuids and the list of pools in a filesystem.
1419 * \param name filesystem name or path
1420 * \param buf bufffer that has to be freed if function returns 0
1421 * \param pools pointer to the list of pools in buffer
1422 * \param poolcount number of pools
1424 * \return 0 when found at least 1 pool, i.e. poolcount > 0
1425 * \retval -error failure
1427 int llapi_get_poolbuf(const char *name, char **buf,
1428 char ***pools, int *poolcount)
1431 * list of pool names (assume that pool count is smaller
1434 char **list, *buffer = NULL, *fsname = (char *)name;
1435 char *poolname = NULL, *tmp = NULL, data[16];
1436 enum param_filter type = FILTER_BY_PATH;
1437 int obdcount, bufsize, rc, nb;
1442 if (name[0] != '/') {
1443 fsname = strdup(name);
1447 poolname = strchr(fsname, '.');
1450 type = FILTER_BY_FS_NAME;
1453 rc = get_lustre_param_value("lov", fsname, type, "numobd",
1454 data, sizeof(data));
1457 obdcount = atoi(data);
1460 * Allocate space for each fsname-OST0000_UUID, 1 per OST,
1461 * and also an array to store the pointers for all that
1465 bufsize = sizeof(struct obd_uuid) * obdcount;
1466 buffer = realloc(tmp, bufsize + sizeof(*list) * obdcount);
1467 if (buffer == NULL) {
1471 list = (char **) (buffer + bufsize);
1474 /* name is a path or fsname */
1475 nb = llapi_get_poollist(name, list, obdcount,
1478 /* name is a pool name (<fsname>.<poolname>) */
1479 nb = llapi_get_poolmembers(name, list, obdcount,
1483 if (nb == -EOVERFLOW) {
1486 goto retry_get_pools;
1489 rc = (nb < 0 ? nb : 0);
1496 /* Don't free buffer, it will be used later */
1499 if (fsname != NULL && type == FILTER_BY_FS_NAME)
1504 #define OBD_NOT_FOUND (-1)
1506 static bool lmv_is_foreign(__u32 magic)
1508 return magic == LMV_MAGIC_FOREIGN;
1511 void find_param_fini(struct find_param *param)
1513 if (param->fp_migrate)
1516 if (param->fp_obd_indexes) {
1517 free(param->fp_obd_indexes);
1518 param->fp_obd_indexes = NULL;
1521 if (param->fp_lmd) {
1522 free(param->fp_lmd);
1523 param->fp_lmd = NULL;
1526 if (param->fp_lmv_md) {
1527 free(param->fp_lmv_md);
1528 param->fp_lmv_md = NULL;
1532 int common_param_init(struct find_param *param, char *path)
1534 int lum_size = get_mds_md_size(path);
1539 /* migrate has fp_lmv_md initialized outside */
1540 if (param->fp_migrate)
1543 if (lum_size < PATH_MAX + 1)
1544 lum_size = PATH_MAX + 1;
1546 param->fp_lum_size = lum_size;
1547 param->fp_lmd = calloc(1, offsetof(typeof(*param->fp_lmd), lmd_lmm) +
1549 if (param->fp_lmd == NULL) {
1550 llapi_error(LLAPI_MSG_ERROR, -ENOMEM,
1551 "error: allocate %zu bytes for layout failed",
1552 sizeof(lstat_t) + param->fp_lum_size);
1556 param->fp_lmv_stripe_count = 256;
1557 param->fp_lmv_md = calloc(1,
1558 lmv_user_md_size(param->fp_lmv_stripe_count,
1559 LMV_USER_MAGIC_SPECIFIC));
1560 if (param->fp_lmv_md == NULL) {
1561 llapi_error(LLAPI_MSG_ERROR, -ENOMEM,
1562 "error: allocation of %d bytes for ioctl",
1563 lmv_user_md_size(param->fp_lmv_stripe_count,
1564 LMV_USER_MAGIC_SPECIFIC));
1565 find_param_fini(param);
1569 param->fp_got_uuids = 0;
1570 param->fp_obd_indexes = NULL;
1571 param->fp_obd_index = OBD_NOT_FOUND;
1572 param->fp_mdt_index = OBD_NOT_FOUND;
1576 int cb_common_fini(char *path, int p, int *dp, void *data,
1577 struct dirent64 *de)
1579 struct find_param *param = data;
1585 /* set errno upon failure */
1586 int open_parent(const char *path)
1592 path_copy = strdup(path);
1593 if (path_copy == NULL)
1596 parent_path = dirname(path_copy);
1597 parent = open(parent_path, O_RDONLY|O_NDELAY|O_DIRECTORY);
1603 static int cb_get_dirstripe(char *path, int *d, struct find_param *param)
1606 bool did_nofollow = false;
1611 param->fp_lmv_md->lum_stripe_count = param->fp_lmv_stripe_count;
1612 if (param->fp_get_default_lmv) {
1616 /* open() may not fetch LOOKUP lock, statx() to ensure dir depth
1619 statx(*d, "", AT_EMPTY_PATH, STATX_MODE, &stx);
1625 param->fp_lmv_md->lum_magic = LMV_USER_MAGIC;
1627 param->fp_lmv_md->lum_magic = LMV_MAGIC_V1;
1630 param->fp_lmv_md->lum_type = LMV_TYPE_RAW;
1632 ret = ioctl(*d, LL_IOC_LMV_GETSTRIPE, param->fp_lmv_md);
1634 /* if ENOTTY likely to be a fake symlink, so try again after
1635 * new open() with O_NOFOLLOW, but only once to prevent any
1636 * loop like for the path of a file/dir not on Lustre !!
1638 if (ret < 0 && errno == ENOTTY && !did_nofollow) {
1642 did_nofollow = true;
1643 fd = open(path, O_RDONLY | O_NOFOLLOW | O_NONBLOCK);
1645 /* restore original errno */
1649 if (fstat(fd, &st) != 0) {
1654 if (!S_ISFIFO(st.st_mode))
1655 fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) & ~O_NONBLOCK);
1656 /* close original fd and set new */
1659 ret2 = ioctl(fd, LL_IOC_LMV_GETSTRIPE, param->fp_lmv_md);
1660 if (ret2 < 0 && errno != E2BIG) {
1661 /* restore original errno */
1665 /* LMV is ok or need to handle E2BIG case now */
1669 if (errno == E2BIG && ret != 0) {
1673 /* if foreign LMV case, fake stripes number */
1674 if (lmv_is_foreign(param->fp_lmv_md->lum_magic)) {
1675 struct lmv_foreign_md *lfm;
1677 lfm = (struct lmv_foreign_md *)param->fp_lmv_md;
1678 if (lfm->lfm_length < XATTR_SIZE_MAX -
1679 offsetof(typeof(*lfm), lfm_value)) {
1680 uint32_t size = lfm->lfm_length +
1681 offsetof(typeof(*lfm), lfm_value);
1683 stripe_count = lmv_foreign_to_md_stripes(size);
1685 llapi_error(LLAPI_MSG_ERROR, -EINVAL,
1686 "error: invalid %d foreign size returned from ioctl",
1691 stripe_count = param->fp_lmv_md->lum_stripe_count;
1693 if (stripe_count <= param->fp_lmv_stripe_count)
1696 free(param->fp_lmv_md);
1697 param->fp_lmv_stripe_count = stripe_count;
1698 lmv_size = lmv_user_md_size(stripe_count,
1699 LMV_USER_MAGIC_SPECIFIC);
1700 param->fp_lmv_md = malloc(lmv_size);
1701 if (param->fp_lmv_md == NULL) {
1702 llapi_error(LLAPI_MSG_ERROR, -ENOMEM,
1703 "error: allocation of %d bytes for ioctl",
1704 lmv_user_md_size(param->fp_lmv_stripe_count,
1705 LMV_USER_MAGIC_SPECIFIC));
1714 static void convert_lmd_statx(struct lov_user_mds_data *lmd_v2, lstat_t *st,
1717 lmd_v2->lmd_stx.stx_blksize = st->st_blksize;
1718 lmd_v2->lmd_stx.stx_nlink = st->st_nlink;
1719 lmd_v2->lmd_stx.stx_uid = st->st_uid;
1720 lmd_v2->lmd_stx.stx_gid = st->st_gid;
1721 lmd_v2->lmd_stx.stx_mode = st->st_mode;
1722 lmd_v2->lmd_stx.stx_ino = st->st_ino;
1723 lmd_v2->lmd_stx.stx_size = st->st_size;
1724 lmd_v2->lmd_stx.stx_blocks = st->st_blocks;
1725 lmd_v2->lmd_stx.stx_atime.tv_sec = st->st_atime;
1726 lmd_v2->lmd_stx.stx_ctime.tv_sec = st->st_ctime;
1727 lmd_v2->lmd_stx.stx_mtime.tv_sec = st->st_mtime;
1728 lmd_v2->lmd_stx.stx_rdev_major = major(st->st_rdev);
1729 lmd_v2->lmd_stx.stx_rdev_minor = minor(st->st_rdev);
1730 lmd_v2->lmd_stx.stx_dev_major = major(st->st_dev);
1731 lmd_v2->lmd_stx.stx_dev_minor = minor(st->st_dev);
1732 lmd_v2->lmd_stx.stx_mask |= STATX_BASIC_STATS;
1734 lmd_v2->lmd_flags = 0;
1736 lmd_v2->lmd_flags |= OBD_MD_FLSIZE | OBD_MD_FLBLOCKS;
1738 lmd_v2->lmd_stx.stx_mask &= ~(STATX_SIZE | STATX_BLOCKS);
1739 if (lmd_v2->lmd_stx.stx_size)
1740 lmd_v2->lmd_flags |= OBD_MD_FLLAZYSIZE;
1741 if (lmd_v2->lmd_stx.stx_blocks)
1742 lmd_v2->lmd_flags |= OBD_MD_FLLAZYBLOCKS;
1744 lmd_v2->lmd_flags |= OBD_MD_FLATIME | OBD_MD_FLMTIME | OBD_MD_FLCTIME |
1745 OBD_MD_FLBLKSZ | OBD_MD_FLMODE | OBD_MD_FLTYPE |
1746 OBD_MD_FLUID | OBD_MD_FLGID | OBD_MD_FLNLINK |
1751 static int convert_lmdbuf_v1v2(void *lmdbuf, int lmdlen)
1753 struct lov_user_mds_data_v1 *lmd_v1 = lmdbuf;
1754 struct lov_user_mds_data *lmd_v2 = lmdbuf;
1758 size = lov_comp_md_size((struct lov_comp_md_v1 *)&lmd_v1->lmd_lmm);
1762 if (lmdlen < sizeof(lmd_v1->lmd_st) + size)
1765 st = lmd_v1->lmd_st;
1766 memmove(&lmd_v2->lmd_lmm, &lmd_v1->lmd_lmm,
1767 lmdlen - (&lmd_v2->lmd_lmm - &lmd_v1->lmd_lmm));
1768 convert_lmd_statx(lmd_v2, &st, false);
1769 lmd_v2->lmd_lmmsize = 0;
1770 lmd_v2->lmd_padding = 0;
1775 int get_lmd_info_fd(const char *path, int parent_fd, int dir_fd,
1776 void *lmdbuf, int lmdlen, enum get_lmd_info_type type)
1778 struct lov_user_mds_data *lmd = lmdbuf;
1779 static bool use_old_ioctl;
1783 if (parent_fd < 0 && dir_fd < 0)
1785 if (type != GET_LMD_INFO && type != GET_LMD_STRIPE)
1790 * LL_IOC_MDC_GETINFO operates on the current directory inode
1791 * and returns struct lov_user_mds_data, while
1792 * LL_IOC_LOV_GETSTRIPE returns only struct lov_user_md.
1794 if (type == GET_LMD_INFO)
1795 cmd = use_old_ioctl ? LL_IOC_MDC_GETINFO_V1 :
1796 LL_IOC_MDC_GETINFO_V2;
1798 cmd = LL_IOC_LOV_GETSTRIPE;
1801 ret = ioctl(dir_fd, cmd, lmdbuf);
1802 if (ret < 0 && errno == ENOTTY &&
1803 cmd == LL_IOC_MDC_GETINFO_V2) {
1804 cmd = LL_IOC_MDC_GETINFO_V1;
1805 use_old_ioctl = true;
1809 if (cmd == LL_IOC_MDC_GETINFO_V1 && !ret)
1810 ret = convert_lmdbuf_v1v2(lmdbuf, lmdlen);
1812 if (ret < 0 && errno == ENOTTY && type == GET_LMD_STRIPE) {
1815 /* retry ioctl() after new open() with O_NOFOLLOW
1816 * just in case it could be a fake symlink
1817 * need using a new open() as dir_fd is being closed
1821 dir_fd2 = open(path, O_RDONLY | O_NDELAY | O_NOFOLLOW);
1823 /* return original error */
1826 ret = ioctl(dir_fd2, cmd, lmdbuf);
1827 /* pass new errno or success back to caller */
1833 } else if (parent_fd >= 0) {
1834 const char *fname = strrchr(path, '/');
1837 * IOC_MDC_GETFILEINFO takes as input the filename (relative to
1838 * the parent directory) and returns struct lov_user_mds_data,
1839 * while IOC_MDC_GETFILESTRIPE returns only struct lov_user_md.
1841 * This avoids opening, locking, and closing each file on the
1842 * client if that is not needed. Multiple of these ioctl() can
1843 * be done on the parent dir with a single open for all
1844 * files in that directory, and it also doesn't pollute the
1845 * client dcache with millions of dentries when traversing
1846 * a large filesystem.
1848 fname = (fname == NULL ? path : fname + 1);
1850 ret = snprintf(lmdbuf, lmdlen, "%s", fname);
1853 else if (ret >= lmdlen || ret++ == 0)
1856 if (type == GET_LMD_INFO)
1857 cmd = use_old_ioctl ? IOC_MDC_GETFILEINFO_V1 :
1858 IOC_MDC_GETFILEINFO_V2;
1860 cmd = IOC_MDC_GETFILESTRIPE;
1863 ret = ioctl(parent_fd, cmd, lmdbuf);
1864 if (ret < 0 && errno == ENOTTY &&
1865 cmd == IOC_MDC_GETFILEINFO_V2) {
1866 cmd = IOC_MDC_GETFILEINFO_V1;
1867 use_old_ioctl = true;
1868 goto retry_getfileinfo;
1871 if (cmd == IOC_MDC_GETFILEINFO_V1 && !ret)
1872 ret = convert_lmdbuf_v1v2(lmdbuf, lmdlen);
1876 if (ret && type == GET_LMD_INFO) {
1877 if (errno == ENOTTY) {
1881 * ioctl is not supported, it is not a lustre fs.
1882 * Do the regular lstat(2) instead.
1884 ret = lstat_f(path, &st);
1887 llapi_error(LLAPI_MSG_ERROR, ret,
1888 "error: %s: lstat failed for %s",
1892 convert_lmd_statx(lmd, &st, true);
1894 * It may be wrong to set use_old_ioctl with true as
1895 * the file is not a lustre fs. So reset it with false
1898 use_old_ioctl = false;
1899 } else if (errno == ENOENT) {
1901 llapi_error(LLAPI_MSG_WARN, ret,
1902 "warning: %s does not exist", path);
1903 } else if (errno != EISDIR && errno != ENODATA) {
1905 llapi_error(LLAPI_MSG_ERROR, ret,
1906 "%s ioctl failed for %s.",
1907 dir_fd >= 0 ? "LL_IOC_MDC_GETINFO" :
1908 "IOC_MDC_GETFILEINFO", path);
1916 * Get the mirror layout info from a file.
1918 * \param path [in] a string containing the file path
1919 * \param lmmbuf [out] pointer to an lov_user_md_v1 buffer
1920 * that will be set with the mirror layout info
1921 * from the file specified by \a path.
1924 * \retval -errno on error
1926 int llapi_get_lmm_from_path(const char *path, struct lov_user_md_v1 **lmmbuf)
1932 lmmlen = get_mds_md_size(path);
1936 p = open_parent(path);
1940 *lmmbuf = calloc(1, lmmlen);
1941 if (*lmmbuf == NULL) {
1946 rc = get_lmd_info_fd(path, p, 0, *lmmbuf, lmmlen, GET_LMD_STRIPE);
1957 int llapi_semantic_traverse(char *path, int size, int parent,
1958 semantic_func_t sem_init,
1959 semantic_func_t sem_fini, void *data,
1960 struct dirent64 *de)
1962 struct find_param *param = (struct find_param *)data;
1963 struct dirent64 *dent;
1964 int len, ret, d, p = -1;
1970 d = open(path, O_RDONLY|O_NDELAY|O_DIRECTORY);
1971 /* if an invalid fake dir symlink, opendir() will return EINVAL
1972 * instead of ENOTDIR. If a valid but dangling faked or real file/dir
1973 * symlink ENOENT will be returned. For a valid/resolved fake or real
1974 * file symlink ENOTDIR will be returned as for a regular file.
1975 * opendir() will be successful for a valid and resolved fake or real
1976 * dir simlink or a regular dir.
1978 if (d == -1 && errno != ENOTDIR && errno != EINVAL && errno != ENOENT) {
1980 llapi_error(LLAPI_MSG_ERROR, ret, "%s: Failed to open '%s'",
1983 } else if (d == -1) {
1984 if (errno == ENOENT || errno == EINVAL) {
1985 int old_errno = errno;
1987 /* try to open with O_NOFOLLOW this will help
1988 * differentiate fake vs real symlinks
1989 * it is ok to not use O_DIRECTORY with O_RDONLY
1990 * and it will prevent the need to deal with ENOTDIR
1991 * error, instead of ELOOP, being returned by recent
1992 * kernels for real symlinks
1994 d = open(path, O_RDONLY|O_NDELAY|O_NOFOLLOW);
1995 /* if a dangling real symlink should return ELOOP, or
1996 * again ENOENT if really non-existing path, or E...??
1997 * So return original error. If success or ENOTDIR, path
1998 * is likely to be a fake dir/file symlink, so continue
2008 if (parent == -1 && d == -1) {
2009 /* Open the parent dir. */
2010 p = open_parent(path);
2016 } else { /* d != -1 */
2019 /* try to reopen dir with O_NOFOLLOW just in case of a foreign
2022 d2 = open(path, O_RDONLY|O_NDELAY|O_NOFOLLOW);
2027 /* continue with d */
2033 ret = sem_init(path, (parent != -1) ? parent : p, &d, data, de);
2043 /* ENOTDIR if fake symlink, do not consider it as an error */
2044 if (errno != ENOTDIR)
2045 llapi_error(LLAPI_MSG_ERROR, errno,
2046 "fdopendir() failed");
2053 while ((dent = readdir64(dir)) != NULL) {
2056 if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
2060 if ((len + dent->d_reclen + 2) > size) {
2061 llapi_err_noerrno(LLAPI_MSG_ERROR,
2062 "error: %s: string buffer too small for %s",
2067 strcat(path, dent->d_name);
2069 if (dent->d_type == DT_UNKNOWN) {
2070 struct lov_user_mds_data *lmd = param->fp_lmd;
2072 rc = get_lmd_info_fd(path, d, -1, param->fp_lmd,
2073 param->fp_lum_size, GET_LMD_INFO);
2075 dent->d_type = IFTODT(lmd->lmd_stx.stx_mode);
2083 switch (dent->d_type) {
2085 llapi_err_noerrno(LLAPI_MSG_ERROR,
2086 "error: %s: '%s' is UNKNOWN type %d",
2087 __func__, dent->d_name, dent->d_type);
2090 /* recursion down into a new subdirectory here */
2091 if (param->fp_thread_count) {
2092 rc = work_unit_create_and_add(path, param,
2095 rc = llapi_semantic_traverse(path, size, d,
2099 if (rc != 0 && ret == 0)
2101 if (rc < 0 && rc != -EALREADY &&
2102 param->fp_stop_on_error)
2108 rc = sem_init(path, d, NULL, data, dent);
2109 if (rc < 0 && ret == 0) {
2111 if (rc && rc != -EALREADY &&
2112 param->fp_stop_on_error)
2117 if (sem_fini && rc == 0)
2118 sem_fini(path, d, NULL, data, dent);
2126 sem_fini(path, parent, &d, data, de);
2139 int param_callback(char *path, semantic_func_t sem_init,
2140 semantic_func_t sem_fini, struct find_param *param)
2142 int ret, len = strlen(path);
2145 if (len > PATH_MAX) {
2147 llapi_error(LLAPI_MSG_ERROR, ret,
2148 "Path name '%s' is too long", path);
2152 buf = (char *)malloc(2 * PATH_MAX);
2156 ret = snprintf(buf, PATH_MAX + 1, "%s", path);
2157 if (ret < 0 || ret >= PATH_MAX + 1) {
2158 ret = -ENAMETOOLONG;
2161 ret = common_param_init(param, buf);
2165 param->fp_depth = 0;
2167 ret = llapi_semantic_traverse(buf, 2 * PATH_MAX + 1, -1, sem_init,
2168 sem_fini, param, NULL);
2170 find_param_fini(param);
2172 return ret < 0 ? ret : 0;
2175 int llapi_file_fget_lov_uuid(int fd, struct obd_uuid *lov_name)
2179 rc = llapi_ioctl(fd, OBD_IOC_GETDTNAME, lov_name);
2182 llapi_error(LLAPI_MSG_ERROR, rc, "cannot get lov name");
2188 int llapi_file_fget_lmv_uuid(int fd, struct obd_uuid *lov_name)
2192 rc = llapi_ioctl(fd, OBD_IOC_GETMDNAME, lov_name);
2195 llapi_error(LLAPI_MSG_ERROR, rc, "error: can't get lmv name.");
2201 int llapi_file_get_lov_uuid(const char *path, struct obd_uuid *lov_uuid)
2205 /* do not follow faked symlinks */
2206 fd = open(path, O_RDONLY | O_NONBLOCK | O_NOFOLLOW);
2208 /* real symlink should have failed with ELOOP so retry without
2209 * O_NOFOLLOW just in case
2211 fd = open(path, O_RDONLY | O_NONBLOCK);
2214 llapi_error(LLAPI_MSG_ERROR, rc, "cannot open '%s'",
2220 rc = llapi_file_fget_lov_uuid(fd, lov_uuid);
2226 int llapi_file_get_lmv_uuid(const char *path, struct obd_uuid *lov_uuid)
2230 fd = open(path, O_RDONLY | O_NONBLOCK);
2233 llapi_error(LLAPI_MSG_ERROR, rc, "error opening %s", path);
2237 rc = llapi_file_fget_lmv_uuid(fd, lov_uuid);
2243 int llapi_file_fget_type_uuid(int fd, enum tgt_type type, struct obd_uuid *uuid)
2245 unsigned int cmd = 0;
2248 if (type == LOV_TYPE)
2249 cmd = OBD_IOC_GETDTNAME;
2250 else if (type == LMV_TYPE)
2251 cmd = OBD_IOC_GETMDNAME;
2252 else if (type == CLI_TYPE)
2253 cmd = OBD_IOC_GETUUID;
2255 rc = llapi_ioctl(fd, cmd, uuid);
2258 llapi_error(LLAPI_MSG_ERROR, rc, "cannot get uuid");
2264 int llapi_file_get_type_uuid(const char *path, enum tgt_type type,
2265 struct obd_uuid *uuid)
2269 /* do not follow faked symlinks */
2270 fd = open(path, O_RDONLY | O_NONBLOCK | O_NOFOLLOW);
2272 /* real symlink should have failed with ELOOP so retry without
2273 * O_NOFOLLOW just in case
2275 fd = open(path, O_RDONLY | O_NONBLOCK);
2278 llapi_error(LLAPI_MSG_ERROR, rc, "cannot open '%s'",
2284 rc = llapi_file_fget_type_uuid(fd, type, uuid);
2291 * If uuidp is NULL, return the number of available obd uuids.
2292 * If uuidp is non-NULL, then it will return the uuids of the obds. If
2293 * there are more OSTs than allocated to uuidp, then an error is returned with
2294 * the ost_count set to number of available obd uuids.
2296 static int llapi_get_target_uuids(int fd, struct obd_uuid *uuidp, int *indices,
2297 int *ost_count, enum tgt_type type)
2299 char buf[PATH_MAX], format[32];
2301 struct obd_uuid name;
2305 /* Get the lov name */
2306 rc = llapi_file_fget_type_uuid(fd, type, &name);
2310 /* Now get the ost uuids */
2311 rc = get_lustre_param_path(type == LOV_TYPE ? "lov" : "lmv", name.uuid,
2312 FILTER_BY_EXACT, "target_obd", ¶m);
2316 fp = fopen(param.gl_pathv[0], "r");
2319 llapi_error(LLAPI_MSG_ERROR, rc, "error: opening '%s'",
2324 snprintf(format, sizeof(format),
2325 "%%d: %%%zus", sizeof(uuidp[0].uuid) - 1);
2326 for (i = 0; fgets(buf, sizeof(buf), fp); i++) {
2329 if (sscanf(buf, format, &index, name.uuid) < 2)
2332 if (i < *ost_count) {
2335 if (indices != NULL)
2341 if (uuidp && (i > *ost_count))
2346 cfs_free_param_data(¶m);
2350 int llapi_lmv_get_uuids(int fd, struct obd_uuid *uuidp, int *mdt_count)
2352 return llapi_get_target_uuids(fd, uuidp, NULL, mdt_count, LMV_TYPE);
2355 int llapi_lov_get_uuids(int fd, struct obd_uuid *uuidp, int *ost_count)
2357 return llapi_get_target_uuids(fd, uuidp, NULL, ost_count, LOV_TYPE);
2360 int llapi_get_obd_count(char *mnt, int *count, int is_mdt)
2365 root = open(mnt, O_RDONLY | O_DIRECTORY);
2368 llapi_error(LLAPI_MSG_ERROR, rc, "open %s failed", mnt);
2373 rc = ioctl(root, LL_IOC_GETOBDCOUNT, count);
2382 * Check if user specified value matches a real uuid. Ignore _UUID,
2383 * -osc-4ba41334, other trailing gunk in comparison.
2384 * @param real_uuid ends in "_UUID"
2385 * @param search_uuid may or may not end in "_UUID"
2387 int llapi_uuid_match(char *real_uuid, char *search_uuid)
2389 int cmplen = strlen(real_uuid);
2390 int searchlen = strlen(search_uuid);
2392 if (cmplen > 5 && strcmp(real_uuid + cmplen - 5, "_UUID") == 0)
2394 if (searchlen > 5 && strcmp(search_uuid + searchlen - 5, "_UUID") == 0)
2398 * The UUIDs may legitimately be different lengths, if
2399 * the system was upgraded from an older version.
2401 if (cmplen != searchlen)
2404 return (strncmp(search_uuid, real_uuid, cmplen) == 0);
2408 * Here, param->fp_obd_uuid points to a single obduuid, the index of which is
2409 * returned in param->fp_obd_index
2411 static int setup_obd_uuid(int fd, char *dname, struct find_param *param)
2413 struct obd_uuid obd_uuid;
2419 enum tgt_type type = param->fp_get_lmv ? LMV_TYPE : LOV_TYPE;
2421 if (param->fp_got_uuids)
2424 /* Get the lov/lmv name */
2425 rc = llapi_file_fget_type_uuid(fd, type, &obd_uuid);
2427 if (rc != -ENOTTY) {
2428 llapi_error(LLAPI_MSG_ERROR, rc,
2429 "error: can't get %s name: %s",
2430 param->fp_get_lmv ? "lmv" : "lov",
2438 param->fp_got_uuids = 1;
2440 /* Now get the ost uuids */
2441 rc = get_lustre_param_path(param->fp_get_lmv ? "lmv" : "lov",
2442 obd_uuid.uuid, FILTER_BY_EXACT,
2443 "target_obd", ¶m_data);
2447 fp = fopen(param_data.gl_pathv[0], "r");
2450 llapi_error(LLAPI_MSG_ERROR, rc, "error: opening '%s'",
2451 param_data.gl_pathv[0]);
2455 if (!param->fp_obd_uuid && !param->fp_quiet && !param->fp_obds_printed)
2456 llapi_printf(LLAPI_MSG_NORMAL, "%s:\n",
2457 param->fp_get_lmv ? "MDTS" : "OBDS");
2459 snprintf(format, sizeof(format),
2460 "%%d: %%%zus", sizeof(obd_uuid.uuid) - 1);
2461 while (fgets(buf, sizeof(buf), fp) != NULL) {
2464 if (sscanf(buf, format, &index, obd_uuid.uuid) < 2)
2467 if (param->fp_obd_uuid) {
2468 if (llapi_uuid_match(obd_uuid.uuid,
2469 param->fp_obd_uuid->uuid)) {
2470 param->fp_obd_index = index;
2473 } else if (!param->fp_quiet && !param->fp_obds_printed) {
2474 /* Print everything */
2475 llapi_printf(LLAPI_MSG_NORMAL, "%s", buf);
2478 param->fp_obds_printed = 1;
2482 if (param->fp_obd_uuid && (param->fp_obd_index == OBD_NOT_FOUND)) {
2483 llapi_err_noerrno(LLAPI_MSG_ERROR,
2484 "error: %s: unknown obduuid: %s",
2485 __func__, param->fp_obd_uuid->uuid);
2489 cfs_free_param_data(¶m_data);
2494 * In this case, param->fp_obd_uuid will be an array of obduuids and
2495 * obd index for all these obduuids will be returned in
2496 * param->fp_obd_indexes
2498 static int setup_indexes(int d, char *path, struct obd_uuid *obduuids,
2499 int num_obds, int **obdindexes, int *obdindex,
2502 int ret, obdcount, obd_valid = 0, obdnum;
2503 int *indices = NULL;
2504 struct obd_uuid *uuids = NULL;
2509 ret = get_param_tgt(path, type, "numobd", buf, sizeof(buf));
2513 obdcount = atoi(buf);
2514 uuids = malloc(obdcount * sizeof(struct obd_uuid));
2517 indices = malloc(obdcount * sizeof(int));
2518 if (indices == NULL) {
2524 ret = llapi_get_target_uuids(d, uuids, indices, &obdcount, type);
2526 if (ret == -EOVERFLOW) {
2527 struct obd_uuid *uuids_temp;
2528 int *indices_temp = NULL;
2530 uuids_temp = realloc(uuids, obdcount *
2531 sizeof(struct obd_uuid));
2534 indices_temp = realloc(indices, obdcount * sizeof(int));
2536 indices = indices_temp;
2537 if (uuids_temp && indices_temp)
2538 goto retry_get_uuids;
2542 llapi_error(LLAPI_MSG_ERROR, ret, "cannot fetch %u OST UUIDs",
2547 indexes = malloc(num_obds * sizeof(*obdindex));
2548 if (indexes == NULL) {
2553 for (obdnum = 0; obdnum < num_obds; obdnum++) {
2554 int maxidx = LOV_V1_INSANE_STRIPE_COUNT;
2557 /* The user may have specified a simple index */
2558 i = strtol(obduuids[obdnum].uuid, &end, 0);
2559 if (end && *end == '\0' && i < LOV_V1_INSANE_STRIPE_COUNT) {
2560 indexes[obdnum] = i;
2564 for (i = 0; i < obdcount; i++) {
2565 if (llapi_uuid_match(uuids[i].uuid,
2566 obduuids[obdnum].uuid)) {
2567 indexes[obdnum] = indices[i];
2575 indexes[obdnum] = OBD_NOT_FOUND;
2576 llapi_err_noerrno(LLAPI_MSG_ERROR,
2577 "invalid obduuid '%s'",
2578 obduuids[obdnum].uuid);
2584 *obdindex = OBD_NOT_FOUND;
2586 *obdindex = obd_valid;
2588 *obdindexes = indexes;
2599 static int setup_target_indexes(int d, char *path, struct find_param *param)
2603 if (param->fp_mdt_uuid) {
2604 ret = setup_indexes(d, path, param->fp_mdt_uuid,
2606 ¶m->fp_mdt_indexes,
2607 ¶m->fp_mdt_index, LMV_TYPE);
2612 if (param->fp_obd_uuid) {
2613 ret = setup_indexes(d, path, param->fp_obd_uuid,
2615 ¶m->fp_obd_indexes,
2616 ¶m->fp_obd_index, LOV_TYPE);
2621 param->fp_got_uuids = 1;
2626 int llapi_ostlist(char *path, struct find_param *param)
2631 fd = open(path, O_RDONLY | O_DIRECTORY);
2635 ret = setup_obd_uuid(fd, path, param);
2642 * Tries to determine the default stripe attributes for a given filesystem. The
2643 * filesystem to check should be specified by fsname, or will be determined
2646 static int sattr_get_defaults(const char *const fsname,
2647 unsigned int *scount,
2648 unsigned int *ssize,
2649 unsigned int *soffset)
2655 rc = get_lustre_param_value("lov", fsname, FILTER_BY_FS_NAME,
2656 "stripecount", val, sizeof(val));
2659 *scount = atoi(val);
2663 rc = get_lustre_param_value("lov", fsname, FILTER_BY_FS_NAME,
2664 "stripesize", val, sizeof(val));
2671 rc = get_lustre_param_value("lov", fsname, FILTER_BY_FS_NAME,
2672 "stripeoffset", val, sizeof(val));
2675 *soffset = atoi(val);
2682 * Tries to gather the default stripe attributes for a given filesystem. If
2683 * the attributes can be determined, they are cached for easy retreival the
2684 * next time they are needed. Only a single filesystem's attributes are
2687 int sattr_cache_get_defaults(const char *const fsname,
2688 const char *const pathname, unsigned int *scount,
2689 unsigned int *ssize, unsigned int *soffset)
2692 char fsname[PATH_MAX + 1];
2693 unsigned int stripecount;
2694 unsigned int stripesize;
2695 unsigned int stripeoffset;
2701 char fsname_buf[PATH_MAX + 1];
2702 unsigned int tmp[3];
2704 if (fsname == NULL) {
2705 rc = llapi_search_fsname(pathname, fsname_buf);
2709 snprintf(fsname_buf, sizeof(fsname_buf), "%s", fsname);
2712 if (strncmp(fsname_buf, cache.fsname, sizeof(fsname_buf) - 1) != 0) {
2714 * Ensure all 3 sattrs (count, size, and offset) are
2715 * successfully retrieved and stored in tmp before writing to
2718 rc = sattr_get_defaults(fsname_buf, &tmp[0], &tmp[1], &tmp[2]);
2722 cache.stripecount = tmp[0];
2723 cache.stripesize = tmp[1];
2724 cache.stripeoffset = tmp[2];
2725 snprintf(cache.fsname, sizeof(cache.fsname), "%s", fsname_buf);
2729 *scount = cache.stripecount;
2731 *ssize = cache.stripesize;
2733 *soffset = cache.stripeoffset;
2738 enum lov_dump_flags {
2739 LDF_IS_DIR = 0x0001,
2740 LDF_IS_RAW = 0x0002,
2741 LDF_INDENT = 0x0004,
2742 LDF_SKIP_OBJS = 0x0008,
2744 LDF_EXTENSION = 0x0020,
2745 LDF_HEX_IDX = 0x0040,
2748 static void lov_dump_user_lmm_header(struct lov_user_md *lum, char *path,
2749 struct lov_user_ost_data_v1 *objects,
2750 enum llapi_layout_verbose verbose,
2751 int depth, char *pool_name,
2752 enum lov_dump_flags flags)
2754 bool is_dir = flags & LDF_IS_DIR;
2755 bool is_raw = flags & LDF_IS_RAW;
2756 bool indent = flags & LDF_INDENT;
2757 bool yaml = flags & LDF_YAML;
2758 bool skip_objs = flags & LDF_SKIP_OBJS;
2759 bool extension = flags & LDF_EXTENSION;
2760 char *prefix = is_dir ? "" : "lmm_";
2761 char *separator = "";
2762 char *space = indent ? " " : "";
2763 char *fmt_idx = flags & LDF_HEX_IDX ? "%#x" : "%d";
2766 if (is_dir && lmm_oi_seq(&lum->lmm_oi) == FID_SEQ_LOV_DEFAULT) {
2767 lmm_oi_set_seq(&lum->lmm_oi, 0);
2768 if (!indent && (verbose & VERBOSE_DETAIL))
2769 llapi_printf(LLAPI_MSG_NORMAL, "%s(Default) ", space);
2772 if (!yaml && !indent && depth && path &&
2773 ((verbose != VERBOSE_OBJID) || !is_dir))
2774 llapi_printf(LLAPI_MSG_NORMAL, "%s\n", path);
2776 if ((verbose & VERBOSE_DETAIL) && !is_dir) {
2777 llapi_printf(LLAPI_MSG_NORMAL, "%s%smagic: 0x%08X\n",
2778 space, prefix, lum->lmm_magic);
2779 llapi_printf(LLAPI_MSG_NORMAL, "%s%sseq: %#jx\n",
2781 (uintmax_t)lmm_oi_seq(&lum->lmm_oi));
2782 llapi_printf(LLAPI_MSG_NORMAL, "%s%sobject_id: %#jx\n",
2784 (uintmax_t)lmm_oi_id(&lum->lmm_oi));
2787 if (verbose & (VERBOSE_DETAIL | VERBOSE_DFID)) {
2792 if (verbose & ~VERBOSE_DFID)
2793 llapi_printf(LLAPI_MSG_NORMAL, "%slmm_fid: ",
2797 struct lu_fid dir_fid;
2799 rc = llapi_path2fid(path, &dir_fid);
2801 llapi_error(LLAPI_MSG_ERROR, rc,
2802 "Cannot determine directory fid.");
2804 seq = dir_fid.f_seq;
2805 oid = dir_fid.f_oid;
2806 ver = dir_fid.f_ver;
2809 * This needs a bit of hand-holding since old 1.x
2810 * lmm_oi have { oi.oi_id = mds_inum, oi.oi_seq = 0 }
2811 * and 2.x lmm_oi have { oi.oi_id = mds_oid,
2812 * oi.oi_seq = mds_seq } instead of a real FID.
2813 * Ideally the 2.x code would have stored this like a
2814 * FID with { oi_id = mds_seq, oi_seq = mds_oid } so
2815 * the ostid union lu_fid { f_seq = mds_seq,
2816 * f_oid = mds_oid } worked properly (especially since
2817 * IGIF FIDs use mds_inum as the FID SEQ), but
2818 * unfortunately that didn't happen.
2820 * Print it to look like an IGIF FID, even though the
2821 * fields are reversed on disk, so that it makes sense
2824 * Don't use ostid_id() and ostid_seq(), since they
2825 * assume the oi_fid fields are in the right order.
2826 * This is why there are separate lmm_oi_seq() and
2827 * lmm_oi_id() routines for this.
2829 * For newer layout types hopefully this will be a
2832 seq = lmm_oi_seq(&lum->lmm_oi) == 0 ?
2833 lmm_oi_id(&lum->lmm_oi) :
2834 lmm_oi_seq(&lum->lmm_oi);
2835 oid = lmm_oi_seq(&lum->lmm_oi) == 0 ?
2836 0 : (__u32)lmm_oi_id(&lum->lmm_oi);
2837 ver = (__u32)(lmm_oi_id(&lum->lmm_oi) >> 32);
2841 llapi_printf(LLAPI_MSG_NORMAL, DFID_NOBRACE"\n",
2842 (unsigned long long)seq, oid, ver);
2844 llapi_printf(LLAPI_MSG_NORMAL, DFID"\n",
2845 (unsigned long long)seq, oid, ver);
2848 if (verbose & VERBOSE_STRIPE_COUNT) {
2849 if (verbose & ~VERBOSE_STRIPE_COUNT)
2850 llapi_printf(LLAPI_MSG_NORMAL, "%s%sstripe_count: ",
2853 if (!is_raw && lum->lmm_stripe_count == 0 &&
2854 !(lov_pattern(lum->lmm_pattern) & LOV_PATTERN_MDT)){
2855 unsigned int scount;
2857 rc = sattr_cache_get_defaults(NULL, path,
2861 llapi_printf(LLAPI_MSG_NORMAL, "%d",
2864 llapi_error(LLAPI_MSG_ERROR, rc,
2865 "Cannot determine default stripe count.");
2867 llapi_printf(LLAPI_MSG_NORMAL, "%d",
2869 (__s16)lum->lmm_stripe_count);
2872 llapi_printf(LLAPI_MSG_NORMAL, "%i",
2874 (__s16)lum->lmm_stripe_count);
2876 if (!yaml && is_dir)
2882 if (((verbose & VERBOSE_STRIPE_SIZE) && !extension) ||
2883 ((verbose & VERBOSE_EXT_SIZE) && extension)) {
2884 llapi_printf(LLAPI_MSG_NORMAL, "%s", separator);
2885 if (verbose & ~VERBOSE_EXT_SIZE && extension)
2886 llapi_printf(LLAPI_MSG_NORMAL, "%s%sextension_size: ",
2888 if (verbose & ~VERBOSE_STRIPE_SIZE && !extension)
2889 llapi_printf(LLAPI_MSG_NORMAL, "%s%sstripe_size: ",
2891 if (is_dir && !is_raw && lum->lmm_stripe_size == 0) {
2894 rc = sattr_cache_get_defaults(NULL, path, NULL, &ssize,
2897 llapi_printf(LLAPI_MSG_NORMAL, "%u", ssize);
2899 llapi_error(LLAPI_MSG_ERROR, rc,
2900 "Cannot determine default stripe size.");
2902 /* Extension size is in KiB */
2903 llapi_printf(LLAPI_MSG_NORMAL, "%llu",
2905 (unsigned long long)(lum->lmm_stripe_size * SEL_UNIT_SIZE) :
2906 (unsigned long long)lum->lmm_stripe_size);
2908 if (!yaml && is_dir)
2914 if ((verbose & VERBOSE_PATTERN)) {
2917 llapi_printf(LLAPI_MSG_NORMAL, "%s", separator);
2918 if (verbose & ~VERBOSE_PATTERN)
2919 llapi_printf(LLAPI_MSG_NORMAL, "%s%spattern: ",
2921 if (lov_pattern_supported(lum->lmm_pattern))
2922 llapi_printf(LLAPI_MSG_NORMAL, "%s",
2923 llapi_lov_pattern_string(lum->lmm_pattern,
2924 buf, sizeof(buf)) ?:
2927 llapi_printf(LLAPI_MSG_NORMAL, "%x", lum->lmm_pattern);
2928 separator = (!yaml && is_dir) ? " " : "\n";
2931 if ((verbose & VERBOSE_GENERATION) && !is_dir) {
2932 llapi_printf(LLAPI_MSG_NORMAL, "%s", separator);
2933 if (verbose & ~VERBOSE_GENERATION)
2934 llapi_printf(LLAPI_MSG_NORMAL, "%s%slayout_gen: ",
2936 llapi_printf(LLAPI_MSG_NORMAL, "%u",
2937 skip_objs ? 0 : (int)lum->lmm_layout_gen);
2941 if (verbose & VERBOSE_STRIPE_OFFSET) {
2942 llapi_printf(LLAPI_MSG_NORMAL, "%s", separator);
2943 if (verbose & ~VERBOSE_STRIPE_OFFSET)
2944 llapi_printf(LLAPI_MSG_NORMAL, "%s%sstripe_offset: ",
2946 if (is_dir || skip_objs)
2947 if (lum->lmm_stripe_offset ==
2948 (typeof(lum->lmm_stripe_offset))(-1))
2949 llapi_printf(LLAPI_MSG_NORMAL, "-1");
2951 llapi_printf(LLAPI_MSG_NORMAL, fmt_idx,
2952 lum->lmm_stripe_offset);
2953 else if (lov_pattern(lum->lmm_pattern) & LOV_PATTERN_MDT)
2954 llapi_printf(LLAPI_MSG_NORMAL, "0");
2956 llapi_printf(LLAPI_MSG_NORMAL, fmt_idx,
2957 objects[0].l_ost_idx);
2958 if (!yaml && is_dir)
2964 if ((verbose & VERBOSE_POOL) && pool_name && (pool_name[0] != '\0') &&
2965 (!lov_pool_is_ignored(pool_name) || is_raw)) {
2966 llapi_printf(LLAPI_MSG_NORMAL, "%s", separator);
2967 if (verbose & ~VERBOSE_POOL)
2968 llapi_printf(LLAPI_MSG_NORMAL, "%s%spool: ",
2970 llapi_printf(LLAPI_MSG_NORMAL, "%s", pool_name);
2971 if (!yaml && is_dir)
2977 if (strlen(separator) != 0)
2978 llapi_printf(LLAPI_MSG_NORMAL, "\n");
2981 static void lov_dump_user_lmm_v1v3(struct lov_user_md *lum, char *pool_name,
2982 struct lov_user_ost_data_v1 *objects,
2983 char *path, int obdindex, int depth,
2984 enum llapi_layout_verbose verbose,
2985 enum lov_dump_flags flags)
2987 bool is_dir = flags & LDF_IS_DIR;
2988 bool indent = flags & LDF_INDENT;
2989 bool skip_objs = flags & LDF_SKIP_OBJS;
2990 bool yaml = flags & LDF_YAML;
2991 bool hex = flags & LDF_HEX_IDX;
2992 bool obdstripe = obdindex == OBD_NOT_FOUND;
2995 if (!obdstripe && !skip_objs) {
2996 for (i = 0; !is_dir && i < lum->lmm_stripe_count; i++) {
2997 if (obdindex == objects[i].l_ost_idx) {
3007 lov_dump_user_lmm_header(lum, path, objects, verbose, depth, pool_name,
3010 if (!skip_objs && (verbose & VERBOSE_OBJID) &&
3011 ((!is_dir && !(lum->lmm_pattern & LOV_PATTERN_F_RELEASED ||
3012 lov_pattern(lum->lmm_pattern) & LOV_PATTERN_MDT)) ||
3013 (is_dir && (lum->lmm_magic == LOV_USER_MAGIC_SPECIFIC)))) {
3014 char *space = " - ";
3017 llapi_printf(LLAPI_MSG_NORMAL,
3018 "%6slmm_objects:\n", " ");
3020 llapi_printf(LLAPI_MSG_NORMAL, "lmm_objects:\n");
3022 llapi_printf(LLAPI_MSG_NORMAL,
3023 "\tobdidx\t\t objid\t\t objid\t\t group\n");
3025 for (i = 0; i < lum->lmm_stripe_count; i++) {
3026 int idx = objects[i].l_ost_idx;
3027 long long oid = ostid_id(&objects[i].l_ost_oi);
3028 long long gr = ostid_seq(&objects[i].l_ost_oi);
3030 if (obdindex != OBD_NOT_FOUND && obdindex != idx)
3034 struct lu_fid fid = { 0 };
3035 ostid_to_fid(&fid, &objects[i].l_ost_oi, idx);
3036 llapi_printf(LLAPI_MSG_NORMAL,
3037 hex ? "%sl_ost_idx: %#x\n"
3038 : "%sl_ost_idx: %d\n",
3040 llapi_printf(LLAPI_MSG_NORMAL,
3041 "%8sl_fid: "DFID_NOBRACE"\n",
3043 } else if (indent) {
3044 struct lu_fid fid = { 0 };
3046 ostid_to_fid(&fid, &objects[i].l_ost_oi, idx);
3047 llapi_printf(LLAPI_MSG_NORMAL, hex ?
3048 "%s%3d: { l_ost_idx: %#5x, l_fid: "DFID" }\n" :
3049 "%s%3d: { l_ost_idx: %3d, l_fid: "DFID" }\n",
3050 space, i, idx, PFID(&fid));
3051 } else if (is_dir) {
3052 llapi_printf(LLAPI_MSG_NORMAL,
3053 "\t%6u\t%14s\t%13s\t%14s\n", idx, "N/A",
3056 char fmt[48] = { 0 };
3058 sprintf(fmt, "%s%s%s\n",
3059 hex ? "\t%#6x\t%14llu\t%#13llx\t"
3060 : "\t%6u\t%14llu\t%#13llx\t",
3061 (fid_seq_is_rsvd(gr) ||
3062 fid_seq_is_mdt0(gr)) ?
3063 "%14llu" : "%#14llx", "%s");
3064 llapi_printf(LLAPI_MSG_NORMAL, fmt, idx, oid,
3066 obdindex == idx ? " *" : "");
3071 llapi_printf(LLAPI_MSG_NORMAL, "\n");
3074 static void hsm_flags2str(__u32 hsm_flags)
3080 llapi_printf(LLAPI_MSG_NORMAL, "0");
3083 for (i = 0; i < ARRAY_SIZE(hsm_flags_table); i++) {
3084 if (hsm_flags & hsm_flags_table[i].hfn_flag) {
3086 llapi_printf(LLAPI_MSG_NORMAL, ",");
3087 llapi_printf(LLAPI_MSG_NORMAL, "%s",
3088 hsm_flags_table[i].hfn_name);
3094 llapi_printf(LLAPI_MSG_NORMAL, ",");
3095 llapi_printf(LLAPI_MSG_NORMAL, "%#x", hsm_flags);
3099 static uint32_t check_foreign_type(uint32_t foreign_type)
3103 for (i = 0; i < LU_FOREIGN_TYPE_UNKNOWN; i++) {
3104 if (lu_foreign_types[i].lft_name == NULL)
3106 if (foreign_type == lu_foreign_types[i].lft_type)
3110 return LU_FOREIGN_TYPE_UNKNOWN;
3113 void lov_dump_hsm_lmm(void *lum, char *path, int depth,
3114 enum llapi_layout_verbose verbose,
3115 enum lov_dump_flags flags)
3117 struct lov_hsm_md *lhm = lum;
3118 bool indent = flags & LDF_INDENT;
3119 bool is_dir = flags & LDF_IS_DIR;
3120 char *space = indent ? " " : "";
3123 uint32_t type = check_foreign_type(lhm->lhm_type);
3125 llapi_printf(LLAPI_MSG_NORMAL, "%slhm_magic: 0x%08X\n",
3126 space, lhm->lhm_magic);
3127 llapi_printf(LLAPI_MSG_NORMAL, "%slhm_pattern: hsm\n",
3129 llapi_printf(LLAPI_MSG_NORMAL, "%slhm_length: %u\n",
3130 space, lhm->lhm_length);
3131 llapi_printf(LLAPI_MSG_NORMAL, "%slhm_type: 0x%08X",
3132 space, lhm->lhm_type);
3133 if (type < LU_FOREIGN_TYPE_UNKNOWN)
3134 llapi_printf(LLAPI_MSG_NORMAL, " (%s)\n",
3135 lu_foreign_types[type].lft_name);
3137 llapi_printf(LLAPI_MSG_NORMAL, " (unknown)\n");
3139 llapi_printf(LLAPI_MSG_NORMAL, "%slhm_flags: ", space);
3140 hsm_flags2str(lhm->lhm_flags);
3141 llapi_printf(LLAPI_MSG_NORMAL, "\n");
3143 if (!lov_hsm_type_supported(lhm->lhm_type))
3146 llapi_printf(LLAPI_MSG_NORMAL, "%slhm_archive_id: %llu\n",
3147 space, (unsigned long long)lhm->lhm_archive_id);
3148 llapi_printf(LLAPI_MSG_NORMAL, "%slhm_archive_ver: %llu\n",
3149 space, (unsigned long long)lhm->lhm_archive_ver);
3150 llapi_printf(LLAPI_MSG_NORMAL, "%slhm_archive_uuid: '%.*s'\n",
3151 space, UUID_MAX, lhm->lhm_archive_uuid);
3155 static void lmv_dump_user_lmm(struct lmv_user_md *lum, char *pool_name,
3156 char *path, int obdindex, int depth,
3157 enum llapi_layout_verbose verbose,
3158 enum lov_dump_flags flags)
3160 struct lmv_user_mds_data *objects = lum->lum_objects;
3161 char *prefix = lum->lum_magic == LMV_USER_MAGIC ? "(Default)" : "";
3162 char *separator = "";
3163 bool yaml = flags & LDF_YAML;
3164 bool hex = flags & LDF_HEX_IDX;
3165 bool obdstripe = false;
3166 struct lu_fid dir_fid;
3170 if (obdindex != OBD_NOT_FOUND) {
3171 if (lum->lum_stripe_count == 0) {
3172 if (obdindex == lum->lum_stripe_offset)
3175 for (i = 0; i < lum->lum_stripe_count; i++) {
3176 if (obdindex == objects[i].lum_mds) {
3177 llapi_printf(LLAPI_MSG_NORMAL,
3192 /* show all information default */
3194 if (lum->lum_magic == LMV_USER_MAGIC)
3195 verbose = VERBOSE_POOL | VERBOSE_STRIPE_COUNT |
3196 VERBOSE_STRIPE_OFFSET | VERBOSE_HASH_TYPE;
3198 verbose = VERBOSE_OBJID;
3201 if (verbose & (VERBOSE_DETAIL | VERBOSE_DFID) ||
3202 (verbose & VERBOSE_OBJID && lum->lum_stripe_count >= 0)) {
3203 rc = llapi_path2fid(path, &dir_fid);
3205 llapi_error(LLAPI_MSG_ERROR, rc,
3206 "Cannot determine directory FID: %s", path);
3209 if (depth && path && (verbose != VERBOSE_OBJID))
3210 llapi_printf(LLAPI_MSG_NORMAL, "%s%s\n", prefix, path);
3212 if (verbose & (VERBOSE_DETAIL | VERBOSE_DFID)) {
3213 if (verbose & ~VERBOSE_DFID)
3214 llapi_printf(LLAPI_MSG_NORMAL,
3215 "lmv_fid: %s", yaml ? " " : "");
3216 llapi_printf(LLAPI_MSG_NORMAL, DFID_NOBRACE, PFID(&dir_fid));
3218 separator = yaml ? "\n" : " ";
3221 if (verbose & VERBOSE_DETAIL) {
3222 llapi_printf(LLAPI_MSG_NORMAL, "%s", separator);
3223 llapi_printf(LLAPI_MSG_NORMAL, "lmv_magic: %s%#x",
3224 yaml ? " " : "", (int)lum->lum_magic);
3225 separator = yaml ? "\n" : " ";
3228 if (verbose & VERBOSE_STRIPE_COUNT) {
3229 llapi_printf(LLAPI_MSG_NORMAL, "%s", separator);
3230 if (verbose & ~VERBOSE_STRIPE_COUNT)
3231 llapi_printf(LLAPI_MSG_NORMAL, "lmv_stripe_count: %s",
3233 llapi_printf(LLAPI_MSG_NORMAL, "%d",
3234 (int)lum->lum_stripe_count);
3235 separator = yaml ? "\n" : " ";
3238 if (verbose & VERBOSE_STRIPE_OFFSET) {
3239 llapi_printf(LLAPI_MSG_NORMAL, "%s", separator);
3240 if (verbose & ~VERBOSE_STRIPE_OFFSET)
3241 llapi_printf(LLAPI_MSG_NORMAL, "lmv_stripe_offset: ");
3242 llapi_printf(LLAPI_MSG_NORMAL, hex ? "%#x" : "%d",
3243 (int)lum->lum_stripe_offset);
3244 separator = yaml ? "\n" : " ";
3247 if (verbose & VERBOSE_HASH_TYPE) {
3248 unsigned int type = lum->lum_hash_type & LMV_HASH_TYPE_MASK;
3249 unsigned int flags = lum->lum_hash_type & ~LMV_HASH_TYPE_MASK;
3251 llapi_printf(LLAPI_MSG_NORMAL, "%s", separator);
3252 if (verbose & ~VERBOSE_HASH_TYPE)
3253 llapi_printf(LLAPI_MSG_NORMAL, "lmv_hash_type: %s",
3255 if (type < LMV_HASH_TYPE_MAX)
3256 llapi_printf(LLAPI_MSG_NORMAL, "%s",
3257 mdt_hash_name[type]);
3259 llapi_printf(LLAPI_MSG_NORMAL, "%#x", type);
3261 if (flags & LMV_HASH_FLAG_OVERSTRIPED)
3262 llapi_printf(LLAPI_MSG_NORMAL, ",overstriped");
3263 if (flags & LMV_HASH_FLAG_MIGRATION)
3264 llapi_printf(LLAPI_MSG_NORMAL, ",migrating");
3265 if (flags & LMV_HASH_FLAG_BAD_TYPE)
3266 llapi_printf(LLAPI_MSG_NORMAL, ",bad_type");
3267 if (flags & LMV_HASH_FLAG_LOST_LMV)
3268 llapi_printf(LLAPI_MSG_NORMAL, ",lost_lmv");
3269 if (flags & LMV_HASH_FLAG_FIXED)
3270 llapi_printf(LLAPI_MSG_NORMAL, ",fixed");
3271 if (flags & ~LMV_HASH_FLAG_KNOWN)
3272 llapi_printf(LLAPI_MSG_NORMAL, ",unknown_%04x",
3273 flags & ~LMV_HASH_FLAG_KNOWN);
3274 separator = yaml ? "\n" : " ";
3277 if ((verbose & VERBOSE_INHERIT) && lum->lum_magic == LMV_USER_MAGIC) {
3278 llapi_printf(LLAPI_MSG_NORMAL, "%s", separator);
3279 if (verbose & ~VERBOSE_INHERIT)
3280 llapi_printf(LLAPI_MSG_NORMAL, "lmv_max_inherit: %s",
3282 if (lum->lum_max_inherit == LMV_INHERIT_UNLIMITED)
3283 llapi_printf(LLAPI_MSG_NORMAL, "-1");
3284 else if (lum->lum_max_inherit == LMV_INHERIT_NONE)
3285 llapi_printf(LLAPI_MSG_NORMAL, "0");
3287 llapi_printf(LLAPI_MSG_NORMAL, "%hhu",
3288 lum->lum_max_inherit);
3289 separator = yaml ? "\n" : " ";
3292 if ((verbose & VERBOSE_INHERIT_RR) &&
3293 lum->lum_magic == LMV_USER_MAGIC) {
3294 llapi_printf(LLAPI_MSG_NORMAL, "%s", separator);
3295 if (verbose & ~VERBOSE_INHERIT_RR)
3296 llapi_printf(LLAPI_MSG_NORMAL, "lmv_max_inherit_rr: ");
3297 if (lum->lum_max_inherit_rr == LMV_INHERIT_RR_UNLIMITED)
3298 llapi_printf(LLAPI_MSG_NORMAL, "-1");
3299 else if (lum->lum_max_inherit_rr == LMV_INHERIT_RR_NONE)
3300 llapi_printf(LLAPI_MSG_NORMAL, "0");
3302 llapi_printf(LLAPI_MSG_NORMAL, "%hhu",
3303 lum->lum_max_inherit_rr);
3304 separator = yaml ? "\n" : " ";
3307 if ((verbose & VERBOSE_POOL) && pool_name != NULL &&
3308 pool_name[0] != '\0') {
3309 llapi_printf(LLAPI_MSG_NORMAL, "%s", separator);
3310 if (verbose & ~VERBOSE_POOL)
3311 llapi_printf(LLAPI_MSG_NORMAL, "%slmv_pool: %s",
3312 prefix, yaml ? " " : "");
3313 llapi_printf(LLAPI_MSG_NORMAL, "%s%c ", pool_name, ' ');
3318 if ((verbose & VERBOSE_OBJID) && lum->lum_magic != LMV_USER_MAGIC) {
3321 llapi_printf(LLAPI_MSG_NORMAL, "%s", separator);
3323 llapi_printf(LLAPI_MSG_NORMAL,
3325 else if (lum->lum_stripe_count >= 0)
3326 llapi_printf(LLAPI_MSG_NORMAL,
3327 "mdtidx\t\t FID[seq:oid:ver]\n");
3330 snprintf(fmt, sizeof(fmt),
3331 " - l_mdt_idx: %s\n%s\n",
3333 " l_fid: "DFID_NOBRACE);
3335 snprintf(fmt, sizeof(fmt), "%s%s", hex ? "%#6x" : "%6u",
3336 "\t\t "DFID"\t\t%s\n");
3337 if (lum->lum_stripe_count == 0 && yaml) {
3338 llapi_printf(LLAPI_MSG_NORMAL, fmt,
3339 lum->lum_stripe_offset,
3340 PFID(&dir_fid), "");
3342 for (i = 0; i < lum->lum_stripe_count; i++) {
3343 int idx = objects[i].lum_mds;
3344 struct lu_fid *fid = &objects[i].lum_fid;
3346 if ((obdindex == OBD_NOT_FOUND) || (obdindex == idx))
3347 llapi_printf(LLAPI_MSG_NORMAL, fmt, idx,
3349 obdindex == idx ? " *":"");
3353 if (!(verbose & VERBOSE_OBJID) || lum->lum_magic == LMV_USER_MAGIC)
3354 llapi_printf(LLAPI_MSG_NORMAL, "\n");
3357 static void lov_dump_comp_v1_header(struct find_param *param, char *path,
3358 enum lov_dump_flags flags)
3360 struct lov_comp_md_v1 *comp_v1 = (void *)¶m->fp_lmd->lmd_lmm;
3361 int depth = param->fp_max_depth;
3362 enum llapi_layout_verbose verbose = param->fp_verbose;
3363 bool yaml = flags & LDF_YAML;
3365 if (depth && path && ((verbose != VERBOSE_OBJID) ||
3366 !(flags & LDF_IS_DIR)) && !yaml)
3367 llapi_printf(LLAPI_MSG_NORMAL, "%s\n", path);
3369 if (verbose & VERBOSE_DETAIL) {
3370 llapi_printf(LLAPI_MSG_NORMAL, "composite_header:\n");
3371 llapi_printf(LLAPI_MSG_NORMAL, "%2slcm_magic: 0x%08X\n",
3372 " ", comp_v1->lcm_magic);
3373 llapi_printf(LLAPI_MSG_NORMAL, "%2slcm_size: %u\n",
3374 " ", comp_v1->lcm_size);
3375 if (flags & LDF_IS_DIR)
3376 llapi_printf(LLAPI_MSG_NORMAL,
3377 "%2slcm_flags: %s\n", " ",
3378 comp_v1->lcm_mirror_count > 0 ?
3381 llapi_printf(LLAPI_MSG_NORMAL,
3382 "%2slcm_flags: %s\n", " ",
3383 llapi_layout_flags_string(comp_v1->lcm_flags));
3386 if (verbose & VERBOSE_GENERATION) {
3387 if (verbose & ~VERBOSE_GENERATION)
3388 llapi_printf(LLAPI_MSG_NORMAL, "%slcm_layout_gen: ",
3390 llapi_printf(LLAPI_MSG_NORMAL, "%u\n", comp_v1->lcm_layout_gen);
3393 if (verbose & VERBOSE_MIRROR_COUNT) {
3394 if (verbose & ~VERBOSE_MIRROR_COUNT)
3395 llapi_printf(LLAPI_MSG_NORMAL, "%slcm_mirror_count: ",
3397 llapi_printf(LLAPI_MSG_NORMAL, "%u\n",
3398 comp_v1->lcm_magic == LOV_USER_MAGIC_COMP_V1 ?
3399 comp_v1->lcm_mirror_count + 1 : 1);
3402 if (verbose & VERBOSE_COMP_COUNT) {
3403 if (verbose & ~VERBOSE_COMP_COUNT)
3404 llapi_printf(LLAPI_MSG_NORMAL, "%slcm_entry_count: ",
3406 llapi_printf(LLAPI_MSG_NORMAL, "%u\n",
3407 comp_v1->lcm_magic == LOV_USER_MAGIC_COMP_V1 ?
3408 comp_v1->lcm_entry_count : 0);
3411 if (verbose & VERBOSE_DETAIL || yaml)
3412 llapi_printf(LLAPI_MSG_NORMAL, "components:\n");
3415 static void lcme_flags2str(__u32 comp_flags)
3421 llapi_printf(LLAPI_MSG_NORMAL, "0");
3424 for (i = 0; i < ARRAY_SIZE(comp_flags_table); i++) {
3425 const char *cfn_name = comp_flags_table[i].cfn_name;
3426 __u32 cfn_flag = comp_flags_table[i].cfn_flag;
3428 if ((comp_flags & cfn_flag) == cfn_flag) {
3430 llapi_printf(LLAPI_MSG_NORMAL, ",");
3431 llapi_printf(LLAPI_MSG_NORMAL, "%s", cfn_name);
3432 comp_flags &= ~comp_flags_table[i].cfn_flag;
3438 llapi_printf(LLAPI_MSG_NORMAL, ",");
3439 llapi_printf(LLAPI_MSG_NORMAL, "%#x", comp_flags);
3443 static void lov_dump_comp_v1_entry(struct find_param *param,
3444 enum lov_dump_flags flags, int index)
3446 struct lov_comp_md_v1 *comp_v1 = (void *)¶m->fp_lmd->lmd_lmm;
3447 struct lov_comp_md_entry_v1 *entry;
3448 char *separator = "";
3449 enum llapi_layout_verbose verbose = param->fp_verbose;
3450 bool yaml = flags & LDF_YAML;
3452 entry = &comp_v1->lcm_entries[index];
3454 if (verbose & VERBOSE_COMP_ID || yaml) {
3455 if (verbose & VERBOSE_DETAIL || yaml)
3456 llapi_printf(LLAPI_MSG_NORMAL,
3457 "%slcme_id: ", " - ");
3458 else if (verbose & ~VERBOSE_COMP_ID)
3459 llapi_printf(LLAPI_MSG_NORMAL,
3460 "%4slcme_id: ", " ");
3461 if (entry->lcme_id != LCME_ID_INVAL)
3462 llapi_printf(LLAPI_MSG_NORMAL, "%u", entry->lcme_id);
3464 llapi_printf(LLAPI_MSG_NORMAL, "N/A");
3468 if (verbose & VERBOSE_MIRROR_ID) {
3469 llapi_printf(LLAPI_MSG_NORMAL, "%s", separator);
3470 if (verbose & ~VERBOSE_MIRROR_ID)
3471 llapi_printf(LLAPI_MSG_NORMAL,
3472 "%4slcme_mirror_id: ", " ");
3473 if (entry->lcme_id != LCME_ID_INVAL)
3474 llapi_printf(LLAPI_MSG_NORMAL, "%u",
3475 mirror_id_of(entry->lcme_id));
3477 llapi_printf(LLAPI_MSG_NORMAL, "N/A");
3481 if (verbose & VERBOSE_COMP_FLAGS) {
3482 llapi_printf(LLAPI_MSG_NORMAL, "%s", separator);
3483 if (verbose & ~VERBOSE_COMP_FLAGS)
3484 llapi_printf(LLAPI_MSG_NORMAL,
3485 "%4slcme_flags: ", " ");
3486 lcme_flags2str(entry->lcme_flags);
3489 /* print snapshot timestamp if its a nosync comp */
3490 if ((verbose & VERBOSE_COMP_FLAGS) &&
3491 (entry->lcme_flags & LCME_FL_NOSYNC)) {
3492 llapi_printf(LLAPI_MSG_NORMAL, "%s", separator);
3493 if (verbose & ~VERBOSE_COMP_FLAGS)
3494 llapi_printf(LLAPI_MSG_NORMAL,
3495 "%4slcme_timestamp: ", " ");
3497 llapi_printf(LLAPI_MSG_NORMAL, "%llu",
3498 (unsigned long long)entry->lcme_timestamp);
3500 time_t stamp = entry->lcme_timestamp;
3501 char *date_str = asctime(localtime(&stamp));
3503 date_str[strlen(date_str) - 1] = '\0';
3504 llapi_printf(LLAPI_MSG_NORMAL, "'%s'", date_str);
3510 if (verbose & VERBOSE_COMP_START) {
3511 llapi_printf(LLAPI_MSG_NORMAL, "%s", separator);
3512 if (verbose & ~VERBOSE_COMP_START)
3513 llapi_printf(LLAPI_MSG_NORMAL,
3514 "%4slcme_extent.e_start: ", " ");
3515 llapi_printf(LLAPI_MSG_NORMAL, "%llu",
3516 (unsigned long long)entry->lcme_extent.e_start);
3520 if (verbose & VERBOSE_COMP_END) {
3521 llapi_printf(LLAPI_MSG_NORMAL, "%s", separator);
3522 if (verbose & ~VERBOSE_COMP_END)
3523 llapi_printf(LLAPI_MSG_NORMAL,
3524 "%4slcme_extent.e_end: ", " ");
3525 if (entry->lcme_extent.e_end == LUSTRE_EOF)
3526 llapi_printf(LLAPI_MSG_NORMAL, "%s", "EOF");
3528 llapi_printf(LLAPI_MSG_NORMAL, "%llu",
3529 (unsigned long long)entry->lcme_extent.e_end);
3534 llapi_printf(LLAPI_MSG_NORMAL, "%s", separator);
3535 llapi_printf(LLAPI_MSG_NORMAL, "%4ssub_layout:\n", " ");
3536 } else if (verbose & VERBOSE_DETAIL) {
3537 llapi_printf(LLAPI_MSG_NORMAL, "%s", separator);
3538 llapi_printf(LLAPI_MSG_NORMAL, "%4slcme_offset: %u\n",
3539 " ", entry->lcme_offset);
3540 llapi_printf(LLAPI_MSG_NORMAL, "%4slcme_size: %u\n",
3541 " ", entry->lcme_size);
3542 llapi_printf(LLAPI_MSG_NORMAL, "%4ssub_layout:\n", " ");
3544 llapi_printf(LLAPI_MSG_NORMAL, "%s", separator);
3549 * Check if the value matches 1 of the given criteria (e.g. --atime +/-N).
3550 * @mds indicates if this is MDS timestamps and there are attributes on OSTs.
3552 * The result is -1 if it does not match, 0 if not yet clear, 1 if matches.
3553 * The table below gives the answers for the specified parameters (value and
3554 * sign), 1st column is the answer for the MDS value, the 2nd is for the OST:
3555 * --------------------------------------
3556 * 1 | file > limit; sign > 0 | -1 / -1 |
3557 * 2 | file = limit; sign > 0 | -1 / -1 |
3558 * 3 | file < limit; sign > 0 | ? / 1 |
3559 * 4 | file > limit; sign = 0 | -1 / -1 |
3560 * 5 | file = limit; sign = 0 | ? / 1 | <- (see the Note below)
3561 * 6 | file < limit; sign = 0 | ? / -1 |
3562 * 7 | file > limit; sign < 0 | 1 / 1 |
3563 * 8 | file = limit; sign < 0 | ? / -1 |
3564 * 9 | file < limit; sign < 0 | ? / -1 |
3565 * --------------------------------------
3566 * Note: 5th actually means that the value is within the interval
3567 * (limit - margin, limit].
3569 static int find_value_cmp(unsigned long long file, unsigned long long limit,
3570 int sign, int negopt, unsigned long long margin,
3576 /* Drop the fraction of margin (of days or size). */
3577 if (file + margin <= limit)
3579 } else if (sign == 0) {
3580 if (file <= limit && file + margin > limit)
3582 else if (file + margin <= limit)
3584 } else if (sign < 0) {
3591 return negopt ? ~ret + 1 : ret;
3594 static inline struct lov_user_md *
3595 lov_comp_entry(struct lov_comp_md_v1 *comp_v1, int ent_idx)
3597 return (struct lov_user_md *)((char *)comp_v1 +
3598 comp_v1->lcm_entries[ent_idx].lcme_offset);
3601 static inline struct lov_user_ost_data_v1 *
3602 lov_v1v3_objects(struct lov_user_md *v1)
3604 if (v1->lmm_magic == LOV_USER_MAGIC_V3)
3605 return ((struct lov_user_md_v3 *)v1)->lmm_objects;
3607 return v1->lmm_objects;
3611 lov_v1v3_pool_name(struct lov_user_md *v1, char *pool_name)
3613 if (v1->lmm_magic == LOV_USER_MAGIC_V3)
3614 snprintf(pool_name, LOV_MAXPOOLNAME + 1, "%s",
3615 ((struct lov_user_md_v3 *)v1)->lmm_pool_name);
3617 pool_name[0] = '\0';
3621 print_last_init_comp(struct find_param *param)
3623 /* print all component info */
3624 if ((param->fp_verbose & VERBOSE_DEFAULT) == VERBOSE_DEFAULT)
3627 /* print specific component info */
3628 if (param->fp_check_comp_id || param->fp_check_comp_flags ||
3629 param->fp_check_comp_start || param->fp_check_comp_end ||
3630 param->fp_check_mirror_id || param->fp_check_mirror_index)
3636 static int find_comp_end_cmp(unsigned long long end, struct find_param *param)
3640 if (param->fp_comp_end == LUSTRE_EOF) {
3641 if (param->fp_comp_end_sign == 0) /* equal to EOF */
3642 match = end == LUSTRE_EOF ? 1 : -1;
3643 else if (param->fp_comp_end_sign > 0) /* at most EOF */
3644 match = end == LUSTRE_EOF ? -1 : 1;
3645 else /* at least EOF */
3647 if (param->fp_exclude_comp_end)
3650 unsigned long long margin;
3652 margin = end == LUSTRE_EOF ? 0 : param->fp_comp_end_units;
3653 match = find_value_cmp(end, param->fp_comp_end,
3654 param->fp_comp_end_sign,
3655 param->fp_exclude_comp_end, margin, 0);
3662 * An example of "getstripe -v" for a two components PFL file:
3665 * lcm_magic: 0x0BD60BD0
3669 * lcm_entry_count: 2
3673 * lcme_extent.e_start: 0
3674 * lcme_extent.e_end: 1048576
3678 * lmm_magic: 0x0BD10BD0
3679 * lmm_seq: 0x200000401
3680 * lmm_object_id: 0x1
3681 * lmm_fid: [0x200000401:0x1:0x0]
3682 * lmm_stripe_count: 1
3683 * lmm_stripe_size: 1048576
3684 * lmm_pattern: raid0
3686 * lmm_stripe_offset: 0
3688 * - 0: { l_ost_idx: 0, l_fid: [0x100000000:0x2:0x0] }
3692 * lcme_extent.e_start: 1048576
3693 * lcme_extent.e_end: EOF
3697 * lmm_magic: 0x0BD10BD0
3698 * lmm_seq: 0x200000401
3699 * lmm_object_id: 0x1
3700 * lmm_fid: [0x200000401:0x1:0x0]
3701 * lmm_stripe_count: 2
3702 * lmm_stripe_size: 1048576
3703 * lmm_pattern: raid0
3705 * lmm_stripe_offset: 1
3707 * - 0: { l_ost_idx: 1, l_fid: [0x100010000:0x2:0x0] }
3708 * - 1: { l_ost_idx: 0, l_fid: [0x100000000:0x3:0x0] }
3710 static void lov_dump_comp_v1(struct find_param *param, char *path,
3711 enum lov_dump_flags flags)
3713 struct lov_comp_md_entry_v1 *entry;
3714 struct lov_user_ost_data_v1 *objects;
3715 struct lov_comp_md_v1 *comp_v1 = (void *)¶m->fp_lmd->lmd_lmm;
3716 struct lov_user_md_v1 *v1;
3717 char pool_name[LOV_MAXPOOLNAME + 1];
3718 int obdindex = param->fp_obd_index;
3719 int i, j, match, ext;
3720 bool obdstripe = false;
3721 __u16 mirror_index = 0;
3722 __u16 mirror_id = 0;
3724 if (obdindex != OBD_NOT_FOUND) {
3725 for (i = 0; !(flags & LDF_IS_DIR) && !obdstripe &&
3726 i < comp_v1->lcm_entry_count; i++) {
3727 if (!(comp_v1->lcm_entries[i].lcme_flags &
3731 v1 = lov_comp_entry(comp_v1, i);
3732 if (v1->lmm_magic == LOV_MAGIC_FOREIGN)
3735 objects = lov_v1v3_objects(v1);
3737 for (j = 0; j < v1->lmm_stripe_count; j++) {
3738 if (obdindex == objects[j].l_ost_idx) {
3751 lov_dump_comp_v1_header(param, path, flags);
3753 flags |= LDF_INDENT;
3755 for (i = 0; i < comp_v1->lcm_entry_count; i++) {
3756 entry = &comp_v1->lcm_entries[i];
3758 if (param->fp_check_comp_flags) {
3759 if (((param->fp_comp_flags & entry->lcme_flags) !=
3760 param->fp_comp_flags) ||
3761 (param->fp_comp_neg_flags & entry->lcme_flags))
3765 if (param->fp_check_comp_id &&
3766 param->fp_comp_id != entry->lcme_id)
3769 if (param->fp_check_comp_start) {
3770 match = find_value_cmp(entry->lcme_extent.e_start,
3771 param->fp_comp_start,
3772 param->fp_comp_start_sign,
3774 param->fp_comp_start_units, 0);
3779 if (param->fp_check_comp_end) {
3780 match = find_comp_end_cmp(entry->lcme_extent.e_end,
3786 if (param->fp_check_mirror_index) {
3787 if (mirror_id != mirror_id_of(entry->lcme_id)) {
3789 mirror_id = mirror_id_of(entry->lcme_id);
3792 match = find_value_cmp(mirror_index,
3793 param->fp_mirror_index,
3794 param->fp_mirror_index_sign,
3795 param->fp_exclude_mirror_index,
3799 } else if (param->fp_check_mirror_id) {
3800 if (mirror_id != mirror_id_of(entry->lcme_id))
3801 mirror_id = mirror_id_of(entry->lcme_id);
3803 match = find_value_cmp(mirror_id,
3804 param->fp_mirror_id,
3805 param->fp_mirror_id_sign,
3806 param->fp_exclude_mirror_id,
3812 if (print_last_init_comp(param)) {
3814 * if part of stripe info is needed, we'd print only
3815 * the last instantiated component info.
3817 if (entry->lcme_flags & LCME_FL_INIT)
3820 if (param->fp_verbose & VERBOSE_EXT_SIZE) {
3821 if (entry->lcme_flags & LCME_FL_EXTENSION)
3822 /* moved back below */
3830 if (entry->lcme_flags & LCME_FL_INIT) {
3831 if (obdindex != OBD_NOT_FOUND) {
3832 flags |= LDF_SKIP_OBJS;
3833 v1 = lov_comp_entry(comp_v1, i);
3834 if (v1->lmm_magic == LOV_MAGIC_FOREIGN)
3837 objects = lov_v1v3_objects(v1);
3839 for (j = 0; j < v1->lmm_stripe_count; j++) {
3840 if (obdindex == objects[j].l_ost_idx) {
3841 flags &= ~LDF_SKIP_OBJS;
3846 flags &= ~LDF_SKIP_OBJS;
3849 flags |= LDF_SKIP_OBJS;
3852 if (obdindex != OBD_NOT_FOUND && (flags & LDF_SKIP_OBJS))
3854 lov_dump_comp_v1_entry(param, flags, i);
3856 v1 = lov_comp_entry(comp_v1, i);
3857 if (v1->lmm_magic == LOV_MAGIC_FOREIGN) {
3858 lov_dump_hsm_lmm(v1, path, param->fp_max_depth,
3859 param->fp_verbose, flags);
3861 objects = lov_v1v3_objects(v1);
3862 lov_v1v3_pool_name(v1, pool_name);
3864 ext = entry->lcme_flags & LCME_FL_EXTENSION ?
3866 lov_dump_user_lmm_v1v3(v1, pool_name, objects, path,
3867 obdindex, param->fp_max_depth,
3868 param->fp_verbose, flags | ext);
3871 if (print_last_init_comp(param)) {
3873 * directory layout contains only layout template, print the
3877 i = comp_v1->lcm_entry_count - 1;
3880 flags &= ~LDF_SKIP_OBJS;
3882 lov_dump_comp_v1_entry(param, flags, i);
3884 v1 = lov_comp_entry(comp_v1, i);
3885 if (v1->lmm_magic == LOV_MAGIC_FOREIGN) {
3886 lov_dump_hsm_lmm(v1, path, param->fp_max_depth,
3887 param->fp_verbose, flags);
3889 objects = lov_v1v3_objects(v1);
3890 lov_v1v3_pool_name(v1, pool_name);
3892 entry = &comp_v1->lcm_entries[i];
3893 ext = entry->lcme_flags & LCME_FL_EXTENSION ?
3895 lov_dump_user_lmm_v1v3(v1, pool_name, objects, path,
3896 obdindex, param->fp_max_depth,
3897 param->fp_verbose, flags | ext);
3902 #define VERBOSE_COMP_OPTS (VERBOSE_COMP_COUNT | VERBOSE_COMP_ID | \
3903 VERBOSE_COMP_START | VERBOSE_COMP_END | \
3906 static inline bool has_any_comp_options(struct find_param *param)
3908 enum llapi_layout_verbose verbose = param->fp_verbose;
3910 if (param->fp_check_comp_id || param->fp_check_comp_count ||
3911 param->fp_check_comp_start || param->fp_check_comp_end ||
3912 param->fp_check_comp_flags)
3915 /* show full layout information, not component specific */
3916 if ((verbose & ~VERBOSE_DETAIL) == VERBOSE_DEFAULT)
3919 return verbose & VERBOSE_COMP_OPTS;
3922 static struct lov_user_mds_data *
3923 lov_forge_comp_v1(struct lov_user_mds_data *orig, bool is_dir)
3925 struct lov_user_md *lum = &orig->lmd_lmm;
3926 struct lov_user_mds_data *new;
3927 struct lov_comp_md_v1 *comp_v1;
3928 struct lov_comp_md_entry_v1 *ent;
3929 int lumd_hdr = offsetof(typeof(*new), lmd_lmm);
3930 int lum_off = sizeof(*comp_v1) + sizeof(*ent);
3931 int lum_size = lov_user_md_size(is_dir ? 0 : lum->lmm_stripe_count,
3934 new = malloc(sizeof(*new) + sizeof(*ent) + lum_size);
3936 llapi_printf(LLAPI_MSG_NORMAL, "out of memory\n");
3939 /* struct lov_user_mds_data header */
3940 memcpy(new, orig, lumd_hdr);
3942 comp_v1 = (struct lov_comp_md_v1 *)&new->lmd_lmm;
3943 comp_v1->lcm_magic = lum->lmm_magic;
3944 comp_v1->lcm_size = lum_off + lum_size;
3945 comp_v1->lcm_layout_gen = is_dir ? 0 : lum->lmm_layout_gen;
3946 comp_v1->lcm_flags = 0;
3947 comp_v1->lcm_entry_count = 1;
3949 ent = &comp_v1->lcm_entries[0];
3951 ent->lcme_flags = is_dir ? 0 : LCME_FL_INIT;
3952 ent->lcme_extent.e_start = 0;
3953 ent->lcme_extent.e_end = LUSTRE_EOF;
3954 ent->lcme_offset = lum_off;
3955 ent->lcme_size = lum_size;
3956 /* fill blob at end of entry */
3957 memcpy((char *)&comp_v1->lcm_entries[1], lum, lum_size);
3962 static void lov_dump_plain_user_lmm(struct find_param *param, char *path,
3963 enum lov_dump_flags flags)
3965 __u32 magic = *(__u32 *)¶m->fp_lmd->lmd_lmm;
3967 if (has_any_comp_options(param)) {
3968 struct lov_user_mds_data *new_lmd, *orig_lmd;
3970 orig_lmd = param->fp_lmd;
3971 new_lmd = lov_forge_comp_v1(orig_lmd, flags & LDF_IS_DIR);
3972 if (new_lmd != NULL) {
3973 param->fp_lmd = new_lmd;
3974 lov_dump_comp_v1(param, path, flags);
3975 param->fp_lmd = orig_lmd;
3981 if (magic == LOV_USER_MAGIC_V1) {
3982 lov_dump_user_lmm_v1v3(¶m->fp_lmd->lmd_lmm, NULL,
3983 param->fp_lmd->lmd_lmm.lmm_objects,
3984 path, param->fp_obd_index,
3985 param->fp_max_depth, param->fp_verbose,
3988 char pool_name[LOV_MAXPOOLNAME + 1];
3989 struct lov_user_ost_data_v1 *objects;
3990 struct lov_user_md_v3 *lmmv3 = (void *)¶m->fp_lmd->lmd_lmm;
3992 snprintf(pool_name, sizeof(pool_name), "%s",
3993 lmmv3->lmm_pool_name);
3994 objects = lmmv3->lmm_objects;
3995 lov_dump_user_lmm_v1v3(¶m->fp_lmd->lmd_lmm, pool_name,
3996 objects, path, param->fp_obd_index,
3997 param->fp_max_depth, param->fp_verbose,
4002 static void lov_dump_foreign_lmm(struct find_param *param, char *path,
4003 enum lov_dump_flags flags)
4005 struct lov_foreign_md *lfm = (void *)¶m->fp_lmd->lmd_lmm;
4006 bool yaml = flags & LDF_YAML;
4008 if (!yaml && param->fp_depth && path)
4009 llapi_printf(LLAPI_MSG_NORMAL, "%s\n", path);
4011 if (param->fp_verbose & VERBOSE_DETAIL) {
4012 uint32_t type = check_foreign_type(lfm->lfm_type);
4014 llapi_printf(LLAPI_MSG_NORMAL, "lfm_magic: 0x%08X\n",
4016 llapi_printf(LLAPI_MSG_NORMAL, "lfm_length: %u\n",
4018 llapi_printf(LLAPI_MSG_NORMAL, "lfm_type: 0x%08X",
4020 if (type < LU_FOREIGN_TYPE_UNKNOWN)
4021 llapi_printf(LLAPI_MSG_NORMAL, " (%s)\n",
4022 lu_foreign_types[type].lft_name);
4024 llapi_printf(LLAPI_MSG_NORMAL, " (unknown)\n");
4026 llapi_printf(LLAPI_MSG_NORMAL, "lfm_flags: 0x%08X\n",
4029 llapi_printf(LLAPI_MSG_NORMAL, "lfm_value: '%.*s'\n",
4030 lfm->lfm_length, lfm->lfm_value);
4031 llapi_printf(LLAPI_MSG_NORMAL, "\n");
4034 static void lmv_dump_foreign_lmm(struct find_param *param, char *path,
4035 enum lov_dump_flags flags)
4037 struct lmv_foreign_md *lfm = (struct lmv_foreign_md *)param->fp_lmv_md;
4038 bool yaml = flags & LDF_YAML;
4040 if (!yaml && param->fp_depth && path)
4041 llapi_printf(LLAPI_MSG_NORMAL, "%s\n", path);
4043 if (param->fp_verbose & VERBOSE_DETAIL) {
4044 uint32_t type = check_foreign_type(lfm->lfm_type);
4046 llapi_printf(LLAPI_MSG_NORMAL, "lfm_magic: 0x%08X\n",
4048 llapi_printf(LLAPI_MSG_NORMAL, "lfm_length: %u\n",
4050 llapi_printf(LLAPI_MSG_NORMAL, "lfm_type: 0x%08X",
4052 if (type < LU_FOREIGN_TYPE_UNKNOWN)
4053 llapi_printf(LLAPI_MSG_NORMAL, " (%s)\n",
4054 lu_foreign_types[type].lft_name);
4056 llapi_printf(LLAPI_MSG_NORMAL, " (unknown)\n");
4058 llapi_printf(LLAPI_MSG_NORMAL, "lfm_flags: 0x%08X\n",
4061 llapi_printf(LLAPI_MSG_NORMAL, "lfm_value: '%.*s'\n",
4062 lfm->lfm_length, lfm->lfm_value);
4063 llapi_printf(LLAPI_MSG_NORMAL, "\n");
4066 static void llapi_lov_dump_user_lmm(struct find_param *param, char *path,
4067 enum lov_dump_flags flags)
4071 if (param->fp_get_lmv || param->fp_get_default_lmv)
4072 magic = (__u32)param->fp_lmv_md->lum_magic;
4074 magic = *(__u32 *)¶m->fp_lmd->lmd_lmm; /* lum->lmm_magic */
4077 flags |= LDF_IS_RAW;
4080 if (param->fp_hex_idx)
4081 flags |= LDF_HEX_IDX;
4084 case LOV_USER_MAGIC_V1:
4085 case LOV_USER_MAGIC_V3:
4086 case LOV_USER_MAGIC_SPECIFIC:
4087 lov_dump_plain_user_lmm(param, path, flags);
4089 case LOV_USER_MAGIC_FOREIGN:
4090 lov_dump_foreign_lmm(param, path, flags);
4093 case LMV_USER_MAGIC: {
4094 char pool_name[LOV_MAXPOOLNAME + 1];
4095 struct lmv_user_md *lum;
4097 lum = (struct lmv_user_md *)param->fp_lmv_md;
4098 snprintf(pool_name, sizeof(pool_name), "%s",
4099 lum->lum_pool_name);
4100 lmv_dump_user_lmm(lum, pool_name, path, param->fp_obd_index,
4101 param->fp_max_depth, param->fp_verbose,
4105 case LOV_USER_MAGIC_COMP_V1:
4106 lov_dump_comp_v1(param, path, flags);
4108 case LMV_MAGIC_FOREIGN:
4109 lmv_dump_foreign_lmm(param, path, flags);
4112 llapi_printf(LLAPI_MSG_NORMAL,
4113 "unknown lmm_magic: %#x (expecting one of %#x %#x %#x %#x)\n",
4114 *(__u32 *)¶m->fp_lmd->lmd_lmm,
4115 LOV_USER_MAGIC_V1, LOV_USER_MAGIC_V3,
4116 LMV_USER_MAGIC, LMV_MAGIC_V1);
4121 static int llapi_file_get_stripe1(const char *path, struct lov_user_md *lum)
4127 fname = strrchr(path, '/');
4129 /* It should be a file (or other non-directory) */
4130 if (fname == NULL) {
4131 dname = (char *)malloc(2);
4135 fname = (char *)path;
4137 dname = (char *)malloc(fname - path + 1);
4140 strncpy(dname, path, fname - path);
4141 dname[fname - path] = '\0';
4145 fd = open(dname, O_RDONLY | O_NONBLOCK);
4151 strcpy((char *)lum, fname);
4152 if (ioctl(fd, IOC_MDC_GETFILESTRIPE, (void *)lum) == -1)
4155 if (close(fd) == -1 && rc == 0)
4163 int llapi_file_get_stripe(const char *path, struct lov_user_md *lum)
4165 char *canon_path = NULL;
4168 rc = llapi_file_get_stripe1(path, lum);
4169 if (!(rc == -ENOTTY || rc == -ENODATA))
4172 /* Handle failure due to symlinks by dereferencing path manually. */
4173 canon_path = canonicalize_file_name(path);
4174 if (canon_path == NULL)
4175 goto out; /* Keep original rc. */
4177 rc2 = llapi_file_get_stripe1(canon_path, lum);
4179 goto out; /* Keep original rc. */
4188 int llapi_file_lookup(int dirfd, const char *name)
4190 struct obd_ioctl_data data = { 0 };
4195 if (dirfd < 0 || name == NULL)
4198 data.ioc_version = OBD_IOCTL_VERSION;
4199 data.ioc_len = sizeof(data);
4200 data.ioc_inlbuf1 = (char *)name;
4201 data.ioc_inllen1 = strlen(name) + 1;
4203 rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
4205 llapi_error(LLAPI_MSG_ERROR, rc,
4206 "error: IOC_MDC_LOOKUP pack failed for '%s': rc %d",
4211 rc = ioctl(dirfd, IOC_MDC_LOOKUP, buf);
4218 * Check if the file time matches all the given criteria (e.g. --atime +/-N).
4219 * Return -1 or 1 if file timestamp does not or does match the given criteria
4220 * correspondingly. Return 0 if the MDS time is being checked and there are
4221 * attributes on OSTs and it is not yet clear if the timespamp matches.
4223 * If 0 is returned, we need to do another RPC to the OSTs to obtain the
4224 * updated timestamps.
4226 static int find_time_check(struct find_param *param, int mds)
4228 struct lov_user_mds_data *lmd = param->fp_lmd;
4232 /* Check if file is accepted. */
4233 if (param->fp_atime) {
4234 rc2 = find_value_cmp(lmd->lmd_stx.stx_atime.tv_sec,
4235 param->fp_atime, param->fp_asign,
4236 param->fp_exclude_atime,
4237 param->fp_time_margin, mds);
4243 if (param->fp_mtime) {
4244 rc2 = find_value_cmp(lmd->lmd_stx.stx_mtime.tv_sec,
4245 param->fp_mtime, param->fp_msign,
4246 param->fp_exclude_mtime,
4247 param->fp_time_margin, mds);
4252 * If the previous check matches, but this one is not yet clear,
4253 * we should return 0 to do an RPC on OSTs.
4259 if (param->fp_ctime) {
4260 rc2 = find_value_cmp(lmd->lmd_stx.stx_ctime.tv_sec,
4261 param->fp_ctime, param->fp_csign,
4262 param->fp_exclude_ctime,
4263 param->fp_time_margin, mds);
4268 * If the previous check matches, but this one is not yet clear,
4269 * we should return 0 to do an RPC on OSTs.
4278 static int find_newerxy_check(struct find_param *param, int mds, bool from_mdt)
4280 struct lov_user_mds_data *lmd = param->fp_lmd;
4285 for (i = 0; i < 2; i++) {
4286 /* Check if file is accepted. */
4287 if (param->fp_newery[NEWERXY_ATIME][i]) {
4288 rc2 = find_value_cmp(lmd->lmd_stx.stx_atime.tv_sec,
4289 param->fp_newery[NEWERXY_ATIME][i],
4296 if (param->fp_newery[NEWERXY_MTIME][i]) {
4297 rc2 = find_value_cmp(lmd->lmd_stx.stx_mtime.tv_sec,
4298 param->fp_newery[NEWERXY_MTIME][i],
4304 * If the previous check matches, but this one is not
4305 * yet clear, we should return 0 to do an RPC on OSTs.
4311 if (param->fp_newery[NEWERXY_CTIME][i]) {
4312 rc2 = find_value_cmp(lmd->lmd_stx.stx_ctime.tv_sec,
4313 param->fp_newery[NEWERXY_CTIME][i],
4319 * If the previous check matches, but this one is not
4320 * yet clear, we should return 0 to do an RPC on OSTs.
4327 * File birth time (btime) can get from MDT directly.
4328 * if @from_mdt is true, it means the input file attributs are
4329 * obtained directly from MDT.
4330 * Thus, if @from_mdt is false, we should skip the following
4336 if (param->fp_newery[NEWERXY_BTIME][i]) {
4337 if (!(lmd->lmd_stx.stx_mask & STATX_BTIME))
4340 rc2 = find_value_cmp(lmd->lmd_stx.stx_btime.tv_sec,
4341 param->fp_newery[NEWERXY_BTIME][i],
4352 * Check whether the stripes matches the indexes user provided
4356 static int check_obd_match(struct find_param *param)
4358 struct lov_user_ost_data_v1 *objects;
4359 struct lov_comp_md_v1 *comp_v1 = NULL;
4360 struct lov_user_mds_data *lmd = param->fp_lmd;
4361 struct lov_user_md_v1 *v1 = &lmd->lmd_lmm;
4362 int i, j, k, count = 1;
4364 if (param->fp_obd_uuid && param->fp_obd_index == OBD_NOT_FOUND)
4367 if (!S_ISREG(lmd->lmd_stx.stx_mode))
4370 /* exclude foreign */
4371 if (v1->lmm_magic == LOV_USER_MAGIC_FOREIGN)
4372 return param->fp_exclude_obd;
4375 * Only those files should be accepted, which have a
4376 * stripe on the specified OST.
4378 if (v1->lmm_magic == LOV_USER_MAGIC_COMP_V1) {
4379 comp_v1 = (struct lov_comp_md_v1 *)v1;
4380 count = comp_v1->lcm_entry_count;
4383 for (i = 0; i < count; i++) {
4385 v1 = lov_comp_entry(comp_v1, i);
4387 objects = lov_v1v3_objects(v1);
4389 for (j = 0; j < v1->lmm_stripe_count; j++) {
4390 if (comp_v1 && !(comp_v1->lcm_entries[i].lcme_flags &
4393 for (k = 0; k < param->fp_num_obds; k++) {
4394 if (param->fp_obd_indexes[k] ==
4395 objects[j].l_ost_idx)
4396 return !param->fp_exclude_obd;
4401 return param->fp_exclude_obd;
4404 static int check_mdt_match(struct find_param *param)
4408 if (param->fp_mdt_uuid && param->fp_mdt_index == OBD_NOT_FOUND)
4411 /* FIXME: For striped dir, we should get stripe information and check */
4412 for (i = 0; i < param->fp_num_mdts; i++) {
4413 if (param->fp_mdt_indexes[i] == param->fp_file_mdt_index)
4414 return !param->fp_exclude_mdt;
4417 if (param->fp_exclude_mdt)
4424 * Check whether the obd is active or not, if it is
4425 * not active, just print the object affected by this
4428 static void print_failed_tgt(struct find_param *param, char *path, int type)
4430 struct obd_statfs stat_buf;
4431 struct obd_uuid uuid_buf;
4432 int tgt_nr, i, *indexes;
4435 if (type != LL_STATFS_LOV && type != LL_STATFS_LMV) {
4436 llapi_error(LLAPI_MSG_NORMAL, ret, "%s: wrong statfs type(%d)",
4441 tgt_nr = (type == LL_STATFS_LOV) ? param->fp_obd_index :
4442 param->fp_mdt_index;
4443 indexes = (type == LL_STATFS_LOV) ? param->fp_obd_indexes :
4444 param->fp_mdt_indexes;
4446 for (i = 0; i < tgt_nr; i++) {
4447 memset(&stat_buf, 0, sizeof(struct obd_statfs));
4448 memset(&uuid_buf, 0, sizeof(struct obd_uuid));
4450 ret = llapi_obd_statfs(path, type, indexes[i], &stat_buf,
4453 llapi_error(LLAPI_MSG_NORMAL, ret,
4454 "%s: obd_uuid: %s failed",
4455 __func__, param->fp_obd_uuid->uuid);
4459 static int find_check_stripe_size(struct find_param *param)
4461 struct lov_comp_md_v1 *comp_v1 = NULL;
4462 struct lov_user_md_v1 *v1 = ¶m->fp_lmd->lmd_lmm;
4463 __u32 stripe_size = 0;
4464 int ret, i, count = 1;
4466 if (v1->lmm_magic == LOV_USER_MAGIC_FOREIGN)
4467 return param->fp_exclude_stripe_size ? 1 : -1;
4469 ret = param->fp_exclude_stripe_size ? 1 : -1;
4470 if (v1->lmm_magic == LOV_USER_MAGIC_COMP_V1) {
4471 comp_v1 = (struct lov_comp_md_v1 *)v1;
4472 count = comp_v1->lcm_entry_count;
4475 for (i = 0; i < count; i++) {
4476 struct lov_comp_md_entry_v1 *ent;
4479 v1 = lov_comp_entry(comp_v1, i);
4481 ent = &comp_v1->lcm_entries[i];
4482 if (ent->lcme_flags & LCME_FL_EXTENSION)
4484 if (!(ent->lcme_flags & LCME_FL_INIT))
4487 stripe_size = v1->lmm_stripe_size;
4490 ret = find_value_cmp(stripe_size, param->fp_stripe_size,
4491 param->fp_stripe_size_sign,
4492 param->fp_exclude_stripe_size,
4493 param->fp_stripe_size_units, 0);
4498 static int find_check_ext_size(struct find_param *param)
4500 struct lov_comp_md_v1 *comp_v1;
4501 struct lov_user_md_v1 *v1;
4504 ret = param->fp_exclude_ext_size ? 1 : -1;
4505 comp_v1 = (struct lov_comp_md_v1 *)¶m->fp_lmd->lmd_lmm;
4506 if (comp_v1->lcm_magic != LOV_USER_MAGIC_COMP_V1)
4509 for (i = 0; i < comp_v1->lcm_entry_count; i++) {
4510 struct lov_comp_md_entry_v1 *ent;
4512 v1 = lov_comp_entry(comp_v1, i);
4514 ent = &comp_v1->lcm_entries[i];
4515 if (!(ent->lcme_flags & LCME_FL_EXTENSION))
4518 ret = find_value_cmp(v1->lmm_stripe_size, param->fp_ext_size,
4519 param->fp_ext_size_sign,
4520 param->fp_exclude_ext_size,
4521 param->fp_ext_size_units, 0);
4522 /* If any ext_size matches */
4530 static __u32 find_get_stripe_count(struct find_param *param)
4532 struct lov_comp_md_v1 *comp_v1 = NULL;
4533 struct lov_user_md_v1 *v1 = ¶m->fp_lmd->lmd_lmm;
4535 __u32 stripe_count = 0;
4537 if (v1->lmm_magic == LOV_USER_MAGIC_FOREIGN)
4540 if (v1->lmm_magic == LOV_USER_MAGIC_COMP_V1) {
4541 comp_v1 = (struct lov_comp_md_v1 *)v1;
4542 count = comp_v1->lcm_entry_count;
4545 for (i = 0; i < count; i++) {
4547 struct lov_comp_md_entry_v1 *ent;
4549 v1 = lov_comp_entry(comp_v1, i);
4551 ent = &comp_v1->lcm_entries[i];
4552 if (!(ent->lcme_flags & LCME_FL_INIT))
4555 if (ent->lcme_flags & LCME_FL_EXTENSION)
4558 stripe_count = v1->lmm_stripe_count;
4561 return stripe_count;
4564 #define LOV_PATTERN_INVALID 0xFFFFFFFF
4566 static int find_check_layout(struct find_param *param)
4568 struct lov_comp_md_v1 *comp_v1 = NULL;
4569 struct lov_user_md_v1 *v1 = ¶m->fp_lmd->lmd_lmm;
4571 bool found = false, valid = false;
4573 if (v1->lmm_magic == LOV_USER_MAGIC_COMP_V1) {
4574 comp_v1 = (struct lov_comp_md_v1 *)v1;
4575 count = comp_v1->lcm_entry_count;
4578 for (i = 0; i < count; i++) {
4580 v1 = lov_comp_entry(comp_v1, i);
4582 /* foreign file have a special magic but no pattern field */
4583 if (v1->lmm_magic == LOV_USER_MAGIC_FOREIGN)
4586 if (v1->lmm_pattern == LOV_PATTERN_INVALID)
4590 if (v1->lmm_pattern & param->fp_layout) {
4599 if ((found && !param->fp_exclude_layout) ||
4600 (!found && param->fp_exclude_layout))
4607 * if no type specified, check/exclude all foreign
4608 * if type specified, check all foreign&type and exclude !foreign + foreign&type
4610 static int find_check_foreign(struct find_param *param)
4612 if (S_ISREG(param->fp_lmd->lmd_stx.stx_mode)) {
4613 struct lov_foreign_md *lfm;
4615 lfm = (void *)¶m->fp_lmd->lmd_lmm;
4616 if (lfm->lfm_magic != LOV_USER_MAGIC_FOREIGN) {
4617 if (param->fp_foreign_type == LU_FOREIGN_TYPE_UNKNOWN)
4618 return param->fp_exclude_foreign ? 1 : -1;
4622 if (param->fp_foreign_type == LU_FOREIGN_TYPE_UNKNOWN ||
4623 lfm->lfm_type == param->fp_foreign_type)
4624 return param->fp_exclude_foreign ? -1 : 1;
4625 return param->fp_exclude_foreign ? 1 : -1;
4628 if (S_ISDIR(param->fp_lmd->lmd_stx.stx_mode)) {
4629 struct lmv_foreign_md *lfm;
4631 lfm = (void *)param->fp_lmv_md;
4632 if (lmv_is_foreign(lfm->lfm_magic)) {
4633 if (param->fp_foreign_type == LU_FOREIGN_TYPE_UNKNOWN)
4634 return param->fp_exclude_foreign ? 1 : -1;
4638 if (param->fp_foreign_type == LU_FOREIGN_TYPE_UNKNOWN ||
4639 lfm->lfm_type == param->fp_foreign_type)
4640 return param->fp_exclude_foreign ? -1 : 1;
4641 return param->fp_exclude_foreign ? 1 : -1;
4646 static int find_check_pool(struct find_param *param)
4648 struct lov_comp_md_v1 *comp_v1 = NULL;
4649 struct lov_user_md_v3 *v3 = (void *)¶m->fp_lmd->lmd_lmm;
4653 if (v3->lmm_magic == LOV_USER_MAGIC_COMP_V1) {
4654 comp_v1 = (struct lov_comp_md_v1 *)v3;
4655 count = comp_v1->lcm_entry_count;
4656 /* empty requested pool is taken as no pool search */
4657 if (count == 0 && param->fp_poolname[0] == '\0') {
4663 for (i = 0; i < count; i++) {
4664 if (comp_v1 != NULL) {
4665 if (!(comp_v1->lcm_entries[i].lcme_flags &
4669 v3 = (void *)lov_comp_entry(comp_v1, i);
4672 if (v3->lmm_magic == LOV_USER_MAGIC_FOREIGN)
4675 if (((v3->lmm_magic == LOV_USER_MAGIC_V1) &&
4676 (param->fp_poolname[0] == '\0')) ||
4677 ((v3->lmm_magic == LOV_USER_MAGIC_V3) &&
4678 (strncmp(v3->lmm_pool_name,
4679 param->fp_poolname, LOV_MAXPOOLNAME) == 0)) ||
4680 ((v3->lmm_magic == LOV_USER_MAGIC_V3) &&
4681 (strcmp(param->fp_poolname, "*") == 0))) {
4688 if ((found && !param->fp_exclude_pool) ||
4689 (!found && param->fp_exclude_pool))
4695 static int find_check_comp_options(struct find_param *param)
4697 struct lov_comp_md_v1 *comp_v1, *forged_v1 = NULL;
4698 struct lov_user_mds_data *lmd = param->fp_lmd;
4699 struct lov_user_md_v1 *v1 = &lmd->lmd_lmm;
4700 struct lov_comp_md_entry_v1 *entry;
4703 if (v1->lmm_magic == LOV_USER_MAGIC_FOREIGN)
4706 if (v1->lmm_magic == LOV_USER_MAGIC_COMP_V1) {
4707 comp_v1 = (struct lov_comp_md_v1 *)v1;
4709 forged_v1 = malloc(sizeof(*forged_v1) + sizeof(*entry));
4710 if (forged_v1 == NULL)
4712 comp_v1 = forged_v1;
4713 comp_v1->lcm_entry_count = 1;
4714 entry = &comp_v1->lcm_entries[0];
4715 entry->lcme_flags = S_ISDIR(lmd->lmd_stx.stx_mode) ?
4717 entry->lcme_extent.e_start = 0;
4718 entry->lcme_extent.e_end = LUSTRE_EOF;
4721 /* invalid case, don't match for any kind of search. */
4722 if (comp_v1->lcm_entry_count == 0) {
4727 if (param->fp_check_comp_count) {
4728 ret = find_value_cmp(forged_v1 ? 0 : comp_v1->lcm_entry_count,
4729 param->fp_comp_count,
4730 param->fp_comp_count_sign,
4731 param->fp_exclude_comp_count, 1, 0);
4737 for (i = 0; i < comp_v1->lcm_entry_count; i++) {
4738 entry = &comp_v1->lcm_entries[i];
4740 if (param->fp_check_comp_flags) {
4742 if (((param->fp_comp_flags & entry->lcme_flags) !=
4743 param->fp_comp_flags) ||
4744 (param->fp_comp_neg_flags & entry->lcme_flags)) {
4750 if (param->fp_check_comp_start) {
4751 ret = find_value_cmp(entry->lcme_extent.e_start,
4752 param->fp_comp_start,
4753 param->fp_comp_start_sign,
4754 param->fp_exclude_comp_start,
4755 param->fp_comp_start_units, 0);
4760 if (param->fp_check_comp_end) {
4761 ret = find_comp_end_cmp(entry->lcme_extent.e_end,
4767 /* the component matches all criteria */
4776 static int find_check_mirror_options(struct find_param *param)
4778 struct lov_comp_md_v1 *comp_v1;
4779 struct lov_user_md_v1 *v1 = ¶m->fp_lmd->lmd_lmm;
4782 if (v1->lmm_magic != LOV_USER_MAGIC_COMP_V1)
4785 comp_v1 = (struct lov_comp_md_v1 *)v1;
4787 if (param->fp_check_mirror_count) {
4788 ret = find_value_cmp(comp_v1->lcm_mirror_count + 1,
4789 param->fp_mirror_count,
4790 param->fp_mirror_count_sign,
4791 param->fp_exclude_mirror_count, 1, 0);
4796 if (param->fp_check_mirror_state) {
4798 __u16 file_state = comp_v1->lcm_flags & LCM_FL_FLR_MASK;
4800 if ((param->fp_mirror_state != 0 &&
4801 file_state != param->fp_mirror_state) ||
4802 file_state == param->fp_mirror_neg_state)
4809 static int find_check_attr_options(struct find_param *param)
4814 attrs = param->fp_lmd->lmd_stx.stx_attributes_mask &
4815 param->fp_lmd->lmd_stx.stx_attributes;
4817 /* This is a AND between all (negated) specified attributes */
4818 if ((param->fp_attrs && (param->fp_attrs & attrs) != param->fp_attrs) ||
4819 (param->fp_neg_attrs && (param->fp_neg_attrs & attrs)))
4822 if ((found && param->fp_exclude_attrs) ||
4823 (!found && !param->fp_exclude_attrs))
4830 * xattr_reg_match() - return true if the supplied string matches the pattern.
4832 * This requires the regex to match the entire supplied string, not just a
4835 * str must be null-terminated. len should be passed in anyways to avoid an
4836 * extra call to strlen(str) when the length is already known.
4838 static bool xattr_reg_match(regex_t *pattern, const char *str, int len)
4843 ret = regexec(pattern, str, 1, &pmatch, 0);
4844 if (ret == 0 && pmatch.rm_so == 0 && pmatch.rm_eo == len)
4851 * xattr_done_matching() - return true if all supplied patterns have been
4852 * matched, allowing to skip checking any remaining xattrs on a file.
4854 * This is only allowed if there are no "exclude" patterns.
4856 static int xattr_done_matching(struct xattr_match_info *xmi)
4860 for (i = 0; i < xmi->xattr_regex_count; i++) {
4861 /* if any pattern still undecided, need to keep going */
4862 if (!xmi->xattr_regex_matched[i])
4869 static int find_check_xattrs(char *path, struct xattr_match_info *xmi)
4871 ssize_t list_len = 0;
4872 ssize_t val_len = 0;
4877 for (i = 0; i < xmi->xattr_regex_count; i++)
4878 xmi->xattr_regex_matched[i] = false;
4880 list_len = llistxattr(path, xmi->xattr_name_buf, XATTR_LIST_MAX);
4882 llapi_error(LLAPI_MSG_ERROR, errno,
4883 "error: listxattr: %s", path);
4887 /* loop over all xattr names on the file */
4888 for (p = xmi->xattr_name_buf;
4889 p - xmi->xattr_name_buf < list_len;
4890 p = strchr(p, '\0'), p++) {
4891 fetched_val = false;
4892 /* loop over all regex patterns specified and check them */
4893 for (i = 0; i < xmi->xattr_regex_count; i++) {
4894 if (xmi->xattr_regex_matched[i])
4897 if (!xattr_reg_match(xmi->xattr_regex_name[i],
4901 if (xmi->xattr_regex_value[i] == NULL)
4905 * even if multiple patterns match the same xattr name,
4906 * don't call getxattr() more than once
4909 val_len = lgetxattr(path, p,
4910 xmi->xattr_value_buf,
4914 llapi_error(LLAPI_MSG_ERROR, errno,
4915 "error: getxattr: %s",
4921 * the value returned by getxattr might or
4922 * might not be null terminated.
4923 * if it is, then decrement val_len so it
4924 * matches what strlen() would return.
4925 * if it is not, then add a null terminator
4926 * since regexec() expects that.
4929 xmi->xattr_value_buf[val_len - 1] == '\0') {
4932 xmi->xattr_value_buf[val_len] = '\0';
4936 if (!xattr_reg_match(xmi->xattr_regex_value[i],
4937 xmi->xattr_value_buf, val_len))
4942 * if exclude this xattr, we can exit early
4945 if (xmi->xattr_regex_exclude[i])
4948 xmi->xattr_regex_matched[i] = true;
4951 * if all "include" patterns have matched, and there are
4952 * no "exclude" patterns, we can exit early with match
4954 if (xattr_done_matching(xmi) == 1)
4960 * finally, check that all supplied patterns either matched, or were
4961 * "exclude" patterns if they did not match.
4963 for (i = 0; i < xmi->xattr_regex_count; i++) {
4964 if (!xmi->xattr_regex_matched[i]) {
4965 if (!xmi->xattr_regex_exclude[i]) {
4974 static bool find_skip_file(struct find_param *param)
4976 if (param->fp_skip_count * 100 <
4977 param->fp_skip_percent * param->fp_skip_total++) {
4978 param->fp_skip_count++;
4984 static bool find_check_lmm_info(struct find_param *param)
4986 return param->fp_check_pool || param->fp_check_stripe_count ||
4987 param->fp_check_stripe_size || param->fp_check_layout ||
4988 param->fp_check_comp_count || param->fp_check_comp_end ||
4989 param->fp_check_comp_start || param->fp_check_comp_flags ||
4990 param->fp_check_mirror_count || param->fp_check_foreign ||
4991 param->fp_check_mirror_state || param->fp_check_ext_size ||
4992 param->fp_check_projid;
4996 * Interpret backslash escape sequences and write output into buffer.
4997 * Anything written to the buffer will be null terminated.
4999 * @param[in] seq String being parsed for escape sequence. The leading
5000 * '\' character is not included in this string (only the
5001 * characters after it)
5002 * @param[out] buffer Location where interpreted escape sequence is written
5003 * @param[in] size Size of the available buffer. (Needs to be large enough
5004 * to handle escape sequence output plus null terminator.)
5005 * @param[out] wrote Number of bytes written to the buffer.
5006 * @return Number of characters from input string processed
5007 * as part of the escape sequence (0 for an unrecognized
5010 static int printf_format_escape(char *seq, char *buffer, size_t size,
5014 /* For now, only handle single char escape sequences: \n, \t, \\ */
5037 * Interpret formats for timestamps (%a, %A@, etc)
5039 * @param[in] seq String being parsed for timestamp format. The leading
5040 * '%' character is not included in this string
5041 * @param[out] buffer Location where timestamp info is written
5042 * @param[in] size Size of the available buffer.
5043 * @param[out] wrote Number of bytes written to the buffer.
5044 * @return Number of characters from input string processed
5045 * as part of the format (0 for an unknown format)
5047 static int printf_format_timestamp(char *seq, char *buffer, size_t size,
5048 int *wrote, struct find_param *param)
5050 struct statx_timestamp ts = { 0, 0 };
5054 char *fmt = "%c"; /* Print in ctime format by default */
5059 ts = param->fp_lmd->lmd_stx.stx_atime;
5063 if (*(seq + 1) == '@') {
5064 ts = param->fp_lmd->lmd_stx.stx_atime;
5070 ts = param->fp_lmd->lmd_stx.stx_ctime;
5074 if (*(seq + 1) == '@') {
5075 ts = param->fp_lmd->lmd_stx.stx_ctime;
5081 ts = param->fp_lmd->lmd_stx.stx_mtime;
5085 if (*(seq + 1) == '@') {
5086 ts = param->fp_lmd->lmd_stx.stx_mtime;
5092 ts = param->fp_lmd->lmd_stx.stx_btime;
5096 if (*(seq + 1) == '@') {
5097 ts = param->fp_lmd->lmd_stx.stx_btime;
5107 /* Found valid format, print to buffer */
5110 *wrote = strftime(buffer, size, fmt, tm);
5117 * Print all ost indices associated with a file layout using a commma separated
5118 * list. For a file with mutliple components, the list of indices for each
5119 * component will be enclosed in brackets.
5121 * @param[out] buffer Location where OST indices are written
5122 * @param[in] size Size of the available buffer.
5123 * @pararm[in] layout Pointer to layout structure for the file
5124 * @return Number of bytes written to output buffer
5126 static int printf_format_ost_indices(char *buffer, size_t size,
5127 struct llapi_layout *layout)
5129 uint64_t count, idx, i;
5130 int err, bytes, wrote = 0;
5132 /* Make sure to start at the first component */
5133 err = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_FIRST);
5135 llapi_error(LLAPI_MSG_ERROR, err,
5136 "error: layout component iteration failed\n");
5140 err = llapi_layout_stripe_count_get(layout, &count);
5142 llapi_error(LLAPI_MSG_ERROR, err,
5143 "error: cannot get stripe_count\n");
5147 bytes = snprintf(buffer, (size - wrote), "%s", "[");
5152 for (i = 0; i < count; i++) {
5153 err = llapi_layout_ost_index_get(layout, i, &idx);
5155 llapi_error(LLAPI_MSG_ERROR, err,
5156 "error: cannot get OST index\n");
5157 bytes = snprintf(buffer, (size - wrote),
5160 bytes = snprintf(buffer, (size - wrote),
5168 /* Overwrite last comma with closing bracket */
5169 *(buffer - 1) = ']';
5171 err = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_NEXT);
5172 if (err == 0) /* next component is found */
5175 llapi_error(LLAPI_MSG_ERROR, err,
5176 "error: layout component iteration failed\n");
5177 /* At this point, either got error or reached last component */
5188 * Print file attributes as a comma-separated list of named attribute flags,
5189 * and hex value of any unknown attributes.
5191 * @param[out] buffer Location where file attributes are written
5192 * @param[in] size Size of the available buffer.
5193 * @pararm[in] lstx Void pointer holding address of struct statx. Which is
5194 * containing attributes to be printed
5195 * @return Number of bytes written to output buffer
5197 static int printf_format_file_attributes(char *buffer, size_t size,
5198 void *lstx, bool longopt)
5200 lstatx_t *stx = (lstatx_t *)lstx;
5201 uint64_t attrs = stx->stx_attributes_mask & stx->stx_attributes;
5202 int bytes = 0, wrote = 0, first = 1;
5203 uint64_t known_attrs = 0;
5204 struct attrs_name *ap;
5206 /* before all, print '---' if no attributes, and exit */
5208 bytes = snprintf(buffer, size - wrote, "---");
5213 /* first, browse list of known attributes */
5214 for (ap = (struct attrs_name *)attrs_array; ap->an_attr != 0; ap++) {
5215 known_attrs |= ap->an_attr;
5216 if (attrs & ap->an_attr) {
5218 bytes = snprintf(buffer, size - wrote, "%s%s",
5219 first ? "" : ",", ap->an_name);
5221 bytes = snprintf(buffer, size - wrote, "%c",
5231 /* second, print hex value for unknown attributes */
5232 attrs &= ~known_attrs;
5234 bytes = snprintf(buffer, size - wrote, "%s0x%lx",
5235 first ? "" : ",", attrs);
5246 * Parse Lustre-specific format sequences of the form %L{x}.
5248 * @param[in] seq String being parsed for format sequence. The leading
5249 * '%' character is not included in this string
5250 * @param[out] buffer Location where interpreted format info is written
5251 * @param[in] size Size of the available buffer.
5252 * @param[out] wrote Number of bytes written to the buffer.
5253 * @param[in] param The find_param structure associated with the file/dir
5254 * @param[in] path Pathname of the current file/dir being handled
5255 * @param[in] projid Project ID associated with the current file/dir
5256 * @param[in] d File descriptor for the directory (or -1 for a
5257 * non-directory file)
5258 * @return Number of characters from input string processed
5259 * as part of the format (0 for an unknown format)
5261 static int printf_format_lustre(char *seq, char *buffer, size_t size,
5262 int *wrote, struct find_param *param,
5263 char *path, __u32 projid, int d)
5265 struct lmv_user_md *lum;
5266 struct lmv_user_mds_data *objects;
5267 struct llapi_layout *layout = NULL;
5269 unsigned int hash_type;
5270 uint64_t str_cnt, str_size, idx;
5271 char pool_name[LOV_MAXPOOLNAME + 1] = { '\0' };
5273 bool longopt = true;
5274 int rc = 2; /* all current valid sequences are 2 chars */
5278 /* Sanity check. Formats always look like %L{X} */
5279 if (*seq++ != 'L') {
5285 * Some formats like %LF or %LP are handled the same for both files
5286 * and dirs, so handle all of those here.
5290 err = llapi_path2fid(path, &fid);
5292 llapi_error(LLAPI_MSG_ERROR, err,
5293 "error: cannot get fid\n");
5296 *wrote = snprintf(buffer, size, DFID_NOBRACE, PFID(&fid));
5299 *wrote = snprintf(buffer, size, "%u", projid);
5301 case 'a': /* file attributes */
5305 lstx = ¶m->fp_lmd->lmd_stx;
5307 *wrote = printf_format_file_attributes(buffer, size, lstx,
5312 /* Other formats for files/dirs need to be handled differently */
5313 if (d == -1) { /* file */
5314 //layout = llapi_layout_get_by_xattr(¶m->fp_lmd->lmd_lmm,
5315 // param->fp_lum_size, 0);
5316 layout = llapi_layout_get_by_path(path, 0);
5317 if (layout == NULL) {
5318 llapi_error(LLAPI_MSG_ERROR, errno,
5319 "error: cannot get file layout\n");
5324 * Set the layout pointer to the last init component
5325 * since that is the component used for most of these
5326 * formats. (This also works for non-composite files)
5328 err = llapi_layout_get_last_init_comp(layout);
5330 llapi_error(LLAPI_MSG_ERROR, err,
5331 "error: cannot get last initialized compomnent\n");
5336 case 'c': /* stripe count */
5337 err = llapi_layout_stripe_count_get(layout, &str_cnt);
5339 llapi_error(LLAPI_MSG_ERROR, err,
5340 "error: cannot get stripe_count\n");
5343 *wrote = snprintf(buffer, size, "%"PRIu64, str_cnt);
5345 case 'h': /* hash info */
5346 /* Not applicable to files. Skip it. */
5348 case 'i': /* starting index */
5349 err = llapi_layout_ost_index_get(layout, 0, &idx);
5351 llapi_error(LLAPI_MSG_ERROR, err,
5352 "error: cannot get OST index of last initialized component\n");
5355 *wrote = snprintf(buffer, size, "%"PRIu64, idx);
5357 case 'o': /* list of object indices */
5358 *wrote = printf_format_ost_indices(buffer, size, layout);
5360 case 'p': /* pool name */
5361 err = llapi_layout_pool_name_get(layout, pool_name,
5364 llapi_error(LLAPI_MSG_ERROR, rc,
5365 "error: cannot get pool name\n");
5368 *wrote = snprintf(buffer, size, "%s", pool_name);
5370 case 'S': /* stripe size */
5371 err = llapi_layout_stripe_size_get(layout, &str_size);
5373 llapi_error(LLAPI_MSG_ERROR, rc,
5374 "error: cannot get stripe_size\n");
5377 *wrote = snprintf(buffer, size, "%"PRIu64, str_size);
5383 } else { /* directory */
5384 lum = (struct lmv_user_md *)param->fp_lmv_md;
5385 objects = lum->lum_objects;
5388 case 'c': /* stripe count */
5389 *wrote = snprintf(buffer, size, "%d",
5390 (int)lum->lum_stripe_count);
5392 case 'h': /* hash info */
5393 hash_type = lum->lum_hash_type & LMV_HASH_TYPE_MASK;
5394 if (hash_type < LMV_HASH_TYPE_MAX)
5395 *wrote = snprintf(buffer, size, "%s",
5396 mdt_hash_name[hash_type]);
5398 *wrote = snprintf(buffer, size, "%#x",
5401 case 'i': /* starting index */
5402 *wrote = snprintf(buffer, size, "%d",
5403 lum->lum_stripe_offset);
5405 case 'o': /* list of object indices */
5406 str_cnt = (int) lum->lum_stripe_count;
5407 *wrote = snprintf(buffer, size, "%s", "[");
5411 for (i = 0; i < str_cnt; i++) {
5412 bytes = snprintf(buffer, (size - *wrote),
5413 "%d,", objects[i].lum_mds);
5420 /* Use lum_offset as the only list entry */
5421 bytes = snprintf(buffer, (size - *wrote),
5422 "%d]", lum->lum_stripe_offset);
5425 /* Overwrite last comma with closing bracket */
5426 *(buffer - 1) = ']';
5429 case 'p': /* pool name */
5430 *wrote = snprintf(buffer, size, "%s",
5431 lum->lum_pool_name);
5433 case 'S': /* stripe size */
5434 /* This has no meaning for directories. Skip it. */
5444 llapi_layout_free(layout);
5447 /* output of snprintf was truncated */
5454 * Create a formated access mode string
5456 * @param[in] param->fp_lmd->lmd_stx.stx_mode
5460 static int snprintf_access_mode(char *buffer, size_t size, __u16 mode)
5462 char access_string[16];
5463 char *p = access_string;
5465 switch (mode & S_IFMT) {
5492 *p++ = (mode & S_IRUSR) ? 'r' : '-';
5493 *p++ = (mode & S_IWUSR) ? 'w' : '-';
5494 *p++ = (mode & S_IXUSR) ? ((mode & S_ISUID) ? 's' : 'x') :
5495 ((mode & S_ISUID) ? 'S' : '-');
5496 *p++ = (mode & S_IRGRP) ? 'r' : '-';
5497 *p++ = (mode & S_IWGRP) ? 'w' : '-';
5498 *p++ = (mode & S_IXGRP) ? ((mode & S_ISGID) ? 's' : 'x') :
5499 ((mode & S_ISGID) ? 'S' : '-');
5500 *p++ = (mode & S_IROTH) ? 'r' : '-';
5501 *p++ = (mode & S_IWOTH) ? 'w' : '-';
5502 *p++ = (mode & S_IXOTH) ? ((mode & S_ISVTX) ? 't' : 'x') :
5503 ((mode & S_ISVTX) ? 'T' : '-');
5506 return snprintf(buffer, size, "%s", access_string);
5509 static int parse_format_width(char **seq, size_t buf_size, int *width,
5512 bool negative_width = false;
5519 /* GNU find supports formats such as "%----10s" */
5520 while (**seq == '-') {
5523 negative_width = true;
5526 /* GNU find and printf only do 0 padding on the left (width > 0)
5529 if (**seq == '0' && !negative_width)
5533 *width = strtol(*seq, &end, 10);
5536 if (*width >= buf_size)
5537 *width = buf_size - 1;
5539 /* increase the number of processed characters */
5540 parsed += end - *seq;
5545 /* GNU find only does 0 padding for %S, %d and %m. */
5560 * Interpret format specifiers beginning with '%'.
5562 * @param[in] seq String being parsed for format specifier. The leading
5563 * '%' character is not included in this string
5564 * @param[out] buffer Location where formatted info is written
5565 * @param[in] size Size of the available buffer.
5566 * @param[out] wrote Number of bytes written to the buffer.
5567 * @param[in] param The find_param structure associated with the file/dir
5568 * @param[in] path Pathname of the current file/dir being handled
5569 * @param[in] projid Project ID associated with the current file/dir
5570 * @param[in] d File descriptor for the directory (or -1 for a
5571 * non-directory file)
5572 * @return Number of characters from input string processed
5573 * as part of the format (0 for an unknown format)
5575 static int printf_format_directive(char *seq, char *buffer, size_t size,
5576 int *wrote, struct find_param *param,
5577 char *path, __u32 projid, int d)
5579 uint64_t blocks = param->fp_lmd->lmd_stx.stx_blocks;
5580 __u16 mode = param->fp_lmd->lmd_stx.stx_mode;
5583 int rc = 1; /* most specifiers are single character */
5588 width_rc = parse_format_width(&seq, size, &width, &padding);
5596 case 'w': case 'W': /* timestamps */
5597 rc = printf_format_timestamp(seq, buffer, size, wrote, param);
5599 case 'b': /* file size (in 512B blocks) */
5600 *wrote = snprintf(buffer, size, "%"PRIu64, blocks);
5602 case 'g': { /* groupname of owner*/
5603 static char save_gr_name[LOGIN_NAME_MAX + 1];
5604 static gid_t save_gid = -1;
5606 if (save_gid != param->fp_lmd->lmd_stx.stx_gid) {
5609 gr = getgrgid(param->fp_lmd->lmd_stx.stx_gid);
5611 save_gid = param->fp_lmd->lmd_stx.stx_gid;
5612 strncpy(save_gr_name, gr->gr_name,
5613 sizeof(save_gr_name) - 1);
5616 if (save_gr_name[0]) {
5617 *wrote = snprintf(buffer, size, "%s", save_gr_name);
5622 case 'G': /* GID of owner */
5623 *wrote = snprintf(buffer, size, "%u",
5624 param->fp_lmd->lmd_stx.stx_gid);
5626 case 'i': /* inode number */
5627 *wrote = snprintf(buffer, size, "%llu",
5628 param->fp_lmd->lmd_stx.stx_ino);
5630 case 'k': /* file size (in 1K blocks) */
5631 *wrote = snprintf(buffer, size, "%"PRIu64, (blocks + 1)/2);
5633 case 'L': /* Lustre-specific formats */
5634 rc = printf_format_lustre(seq, buffer, size, wrote, param,
5637 case 'm': /* file mode in octal */
5638 *wrote = snprintf(buffer, size, "%o", (mode & (~S_IFMT)));
5640 case 'M': /* file access mode */
5641 *wrote = snprintf_access_mode(buffer, size, mode);
5643 case 'n': /* number of links */
5644 *wrote = snprintf(buffer, size, "%u",
5645 param->fp_lmd->lmd_stx.stx_nlink);
5647 case 'p': /* Path name of file */
5648 *wrote = snprintf(buffer, size, "%s", path);
5650 case 's': /* file size (in bytes) */
5651 *wrote = snprintf(buffer, size, "%"PRIu64,
5652 (uint64_t) param->fp_lmd->lmd_stx.stx_size);
5654 case 'u': {/* username of owner */
5655 static char save_username[LOGIN_NAME_MAX + 1];
5656 static uid_t save_uid = -1;
5658 if (save_uid != param->fp_lmd->lmd_stx.stx_uid) {
5661 pw = getpwuid(param->fp_lmd->lmd_stx.stx_uid);
5663 save_uid = param->fp_lmd->lmd_stx.stx_uid;
5664 strncpy(save_username, pw->pw_name,
5665 sizeof(save_username) - 1);
5668 if (save_username[0]) {
5669 *wrote = snprintf(buffer, size, "%s", save_username);
5674 case 'U': /* UID of owner */
5675 *wrote = snprintf(buffer, size, "%u",
5676 param->fp_lmd->lmd_stx.stx_uid);
5678 case 'y': /* file type */
5681 else if (S_ISDIR(mode))
5683 else if (S_ISLNK(mode))
5685 else if (S_ISBLK(mode))
5687 else if (S_ISCHR(mode))
5689 else if (S_ISFIFO(mode))
5691 else if (S_ISSOCK(mode))
5701 default: /* invalid format specifier */
5707 /* if parsing failed, return 0 to avoid skipping width_rc */
5710 if (width > 0 && width > *wrote) {
5712 int shift = width - *wrote;
5714 /* '\0' is added by caller if necessary */
5715 memmove(buffer + shift, buffer, *wrote);
5716 memset(buffer, padding, shift);
5718 } else if (width < 0 && -width > *wrote) {
5720 int shift = -width - *wrote;
5722 memset(buffer + *wrote, padding, shift);
5727 /* output of snprintf was truncated */
5730 return width_rc + rc;
5734 * Parse user-supplied string for the -printf option and interpret any
5735 * '%' format specifiers or '\' escape sequences.
5737 * @param[in] param The find_param struct containing the -printf string
5738 * as well as info about the current file/dir that mathced
5739 * the lfs find search criteria
5740 * @param[in] path Path name for current file/dir
5741 * @param[in] projid Project ID associated with current file/dir
5742 * @param[in] d File descriptor for current directory (or -1 for a
5743 * non-directory file)
5745 static void printf_format_string(struct find_param *param, char *path,
5746 __u32 projid, int d)
5748 char output[FORMATTED_BUF_LEN];
5749 char *fmt_char = param->fp_format_printf_str;
5750 char *buff = output;
5756 buff_size = FORMATTED_BUF_LEN;
5758 /* Always leave one free byte in buffer for trailing NUL */
5759 while (*fmt_char && (buff_size > 1)) {
5762 if (*fmt_char == '%') {
5763 rc = printf_format_directive(fmt_char + 1, buff,
5764 buff_size, &written, param,
5766 } else if (*fmt_char == '\\') {
5767 rc = printf_format_escape(fmt_char + 1, buff,
5768 buff_size, &written);
5772 /* Either a '\' escape or '%' format was processed.
5773 * Increment pointers accordingly.
5775 fmt_char += (rc + 1);
5777 buff_size -= written;
5778 } else if (rc < 0) {
5781 /* Regular char or invalid escape/format.
5782 * Either way, copy current character.
5784 *buff++ = *fmt_char++;
5789 /* Terminate output buffer and print */
5791 llapi_printf(LLAPI_MSG_NORMAL, "%s", output);
5795 * Gets the project id of a file, directory, or special file,
5796 * and stores it at the projid memory address passed in.
5797 * Returns 0 on success, or -errno for failure.
5799 * @param[in] path The full path of the file or directory we're trying
5800 * to retrieve the project id for.
5801 * @param[in] fd A reference to the file descriptor of either the file
5802 * or directory we're inspecting. The file/dir may or may
5803 * not have been already opened, but if not, we'll open
5804 * it here (for regular files/directories).
5805 * @param[in] mode The mode type of the file. This will tell us if the file
5806 * is a regular file/dir or if it's a special file type.
5807 * @param[out] projid A reference to where to store the projid of the file/dir
5809 static int get_projid(const char *path, int *fd, mode_t mode, __u32 *projid)
5811 struct fsxattr fsx = { 0 };
5812 struct lu_project lu_project = { 0 };
5815 /* Check the mode of the file */
5816 if (S_ISREG(mode) || S_ISDIR(mode)) {
5817 /* This is a regular file type or directory */
5819 /* If we haven't yet opened the file,
5820 * open it in read-only mode
5822 *fd = open(path, O_RDONLY | O_NOCTTY | O_NDELAY);
5824 llapi_error(LLAPI_MSG_ERROR, -ENOENT,
5825 "warning: %s: unable to open file \"%s\"to get project id",
5830 ret = ioctl(*fd, FS_IOC_FSGETXATTR, &fsx);
5834 *projid = fsx.fsx_projid;
5836 /* This is a special file type, like a symbolic link, block or
5837 * character device file. We'll have to open its parent
5838 * directory and get metadata about the file through that.
5840 char dir_path[PATH_MAX + 1] = { 0 };
5841 char base_path[PATH_MAX + 1] = { 0 };
5843 strncpy(dir_path, path, PATH_MAX);
5844 strncpy(base_path, path, PATH_MAX);
5845 char *dir_name = dirname(dir_path);
5846 char *base_name = basename(base_path);
5847 int dir_fd = open(dir_name, O_RDONLY | O_NOCTTY | O_NDELAY);
5850 llapi_error(LLAPI_MSG_ERROR, -ENOENT,
5851 "warning: %s: unable to open dir \"%s\"to get project id",
5855 lu_project.project_type = LU_PROJECT_GET;
5857 strncpy(lu_project.project_name, base_name, NAME_MAX);
5859 ret = ioctl(dir_fd, LL_IOC_PROJECT, &lu_project);
5862 llapi_error(LLAPI_MSG_ERROR, -ENOENT,
5863 "warning: %s: failed to get xattr for '%s': %s",
5864 __func__, path, strerror(errno));
5867 *projid = lu_project.project_id;
5874 * Check that the file's permissions in *st matches the one in find_param
5876 static int check_file_permissions(const struct find_param *param,
5883 switch (param->fp_perm_sign) {
5884 case LFS_FIND_PERM_EXACT:
5885 decision = (mode == param->fp_perm);
5887 case LFS_FIND_PERM_ALL:
5888 decision = ((mode & param->fp_perm) == param->fp_perm);
5890 case LFS_FIND_PERM_ANY:
5891 decision = ((mode & param->fp_perm) != 0);
5895 if ((param->fp_exclude_perm && decision)
5896 || (!param->fp_exclude_perm && !decision))
5902 int cb_find_init(char *path, int p, int *dp,
5903 void *data, struct dirent64 *de)
5905 struct find_param *param = (struct find_param *)data;
5906 struct lov_user_mds_data *lmd = param->fp_lmd;
5907 int d = dp == NULL ? -1 : *dp;
5908 int decision = 1; /* 1 is accepted; -1 is rejected. */
5910 int checked_type = 0;
5912 __u32 stripe_count = 0;
5915 __u32 projid = DEFAULT_PROJID;
5916 bool gather_all = false;
5918 if (p == -1 && d == -1)
5920 /* if below minimum depth do not process further */
5921 if (param->fp_depth < param->fp_min_depth)
5924 /* Reset this value between invocations */
5925 param->fp_get_lmv = 0;
5927 /* Gather all file/dir info, not just what's needed for search params */
5928 if (param->fp_format_printf_str)
5931 /* If a regular expression is presented, make the initial decision */
5932 if (param->fp_pattern != NULL) {
5933 char *fname = strrchr(path, '/');
5935 fname = (fname == NULL ? path : fname + 1);
5936 ret = fnmatch(param->fp_pattern, fname, 0);
5937 if ((ret == FNM_NOMATCH && !param->fp_exclude_pattern) ||
5938 (ret == 0 && param->fp_exclude_pattern))
5942 /* See if we can check the file type from the dirent. */
5943 if (de != NULL && de->d_type != DT_UNKNOWN) {
5944 if (param->fp_type != 0) {
5947 if (DTTOIF(de->d_type) == param->fp_type) {
5948 if (param->fp_exclude_type)
5951 if (!param->fp_exclude_type)
5955 if ((param->fp_check_mdt_count || param->fp_hash_type ||
5956 param->fp_check_hash_flag) && de->d_type != DT_DIR)
5963 * Request MDS for the stat info if some of these parameters need
5966 if (param->fp_obd_uuid || param->fp_mdt_uuid ||
5967 param->fp_check_uid || param->fp_check_gid ||
5968 param->fp_newerxy || param->fp_btime ||
5969 param->fp_atime || param->fp_mtime || param->fp_ctime ||
5970 param->fp_check_size || param->fp_check_blocks ||
5971 find_check_lmm_info(param) ||
5972 param->fp_check_mdt_count || param->fp_hash_type ||
5973 param->fp_check_hash_flag || param->fp_perm_sign ||
5974 param->fp_nlink || param->fp_attrs || param->fp_neg_attrs ||
5978 if (param->fp_type != 0 && checked_type == 0)
5981 if (decision == 0) {
5983 (param->fp_check_mdt_count || param->fp_hash_type ||
5984 param->fp_check_hash_flag || param->fp_check_foreign ||
5986 * cb_get_dirstripe is needed when checking nlink because
5987 * nlink is handled differently for multi-stripe directory
5988 * vs. single-stripe directory
5990 param->fp_nlink || gather_all)) {
5991 param->fp_get_lmv = 1;
5992 ret = cb_get_dirstripe(path, &d, param);
5994 if (errno == ENODATA) {
5995 /* Fill in struct for unstriped dir */
5997 param->fp_lmv_md->lum_magic = LMV_MAGIC_V1;
5998 /* Use 0 until we find actual offset */
5999 param->fp_lmv_md->lum_stripe_offset = 0;
6000 param->fp_lmv_md->lum_stripe_count = 0;
6001 param->fp_lmv_md->lum_hash_type = 0;
6003 if (param->fp_check_foreign) {
6004 if (param->fp_exclude_foreign)
6013 if (param->fp_check_mdt_count) {
6014 if (lmv_is_foreign(param->fp_lmv_md->lum_magic))
6017 decision = find_value_cmp(param->fp_lmv_md->lum_stripe_count,
6018 param->fp_mdt_count,
6019 param->fp_mdt_count_sign,
6020 param->fp_exclude_mdt_count, 1, 0);
6025 if (param->fp_hash_type) {
6027 __u32 type = param->fp_lmv_md->lum_hash_type &
6030 if (lmv_is_foreign(param->fp_lmv_md->lum_magic))
6033 found = (1 << type) & param->fp_hash_type;
6034 if ((found && param->fp_exclude_hash_type) ||
6035 (!found && !param->fp_exclude_hash_type))
6039 if (param->fp_check_hash_flag) {
6040 __u32 flags = param->fp_lmv_md->lum_hash_type &
6041 ~LMV_HASH_TYPE_MASK;
6043 if (lmv_is_foreign(param->fp_lmv_md->lum_magic))
6046 if (!(flags & param->fp_hash_inflags) ||
6047 (flags & param->fp_hash_exflags))
6052 param->fp_lmd->lmd_lmm.lmm_magic = 0;
6053 ret = get_lmd_info_fd(path, p, d, param->fp_lmd,
6054 param->fp_lum_size, GET_LMD_INFO);
6055 if (ret == 0 && param->fp_lmd->lmd_lmm.lmm_magic == 0 &&
6056 find_check_lmm_info(param)) {
6057 struct lov_user_md *lmm = ¶m->fp_lmd->lmd_lmm;
6060 * We need to "fake" the "use the default" values
6061 * since the lmm struct is zeroed out at this point.
6063 lmm->lmm_magic = LOV_USER_MAGIC_V1;
6064 lmm->lmm_pattern = LOV_PATTERN_DEFAULT;
6066 ostid_set_seq(&lmm->lmm_oi,
6067 FID_SEQ_LOV_DEFAULT);
6068 lmm->lmm_stripe_size = 0;
6069 lmm->lmm_stripe_count = 0;
6070 lmm->lmm_stripe_offset = -1;
6072 if (ret == 0 && (param->fp_mdt_uuid != NULL || gather_all)) {
6074 ret = llapi_file_fget_mdtidx(d,
6075 ¶m->fp_file_mdt_index);
6077 * Make sure lum_stripe_offset matches
6078 * mdt_index even for unstriped directories.
6080 if (ret == 0 && param->fp_get_lmv)
6081 param->fp_lmv_md->lum_stripe_offset =
6082 param->fp_file_mdt_index;
6083 } else if (S_ISREG(lmd->lmd_stx.stx_mode)) {
6085 * FIXME: we could get the MDT index from the
6086 * file's FID in lmd->lmd_lmm.lmm_oi without
6087 * opening the file, once we are sure that
6088 * LFSCK2 (2.6) has fixed up pre-2.0 LOV EAs.
6089 * That would still be an ioctl() to map the
6090 * FID to the MDT, but not an open RPC.
6092 fd = open(path, O_RDONLY);
6094 ret = llapi_file_fget_mdtidx(fd,
6095 ¶m->fp_file_mdt_index);
6101 * For a special file, we assume it resides on
6102 * the same MDT as the parent directory.
6104 ret = llapi_file_fget_mdtidx(p,
6105 ¶m->fp_file_mdt_index);
6116 stripe_count = find_get_stripe_count(param);
6120 /* Check the file permissions from the stat info */
6121 if (param->fp_perm_sign) {
6122 decision = check_file_permissions(param, lmd->lmd_stx.stx_mode);
6127 if (param->fp_type && !checked_type) {
6128 if ((param->fp_check_mdt_count || param->fp_check_hash_flag ||
6129 param->fp_hash_type) && !S_ISDIR(lmd->lmd_stx.stx_mode))
6132 if ((lmd->lmd_stx.stx_mode & S_IFMT) == param->fp_type) {
6133 if (param->fp_exclude_type)
6136 if (!param->fp_exclude_type)
6142 if (param->fp_obd_uuid || param->fp_mdt_uuid) {
6143 if (lustre_fs && param->fp_got_uuids &&
6144 param->fp_dev != makedev(lmd->lmd_stx.stx_dev_major,
6145 lmd->lmd_stx.stx_dev_minor)) {
6146 /* A lustre/lustre mount point is crossed. */
6147 param->fp_got_uuids = 0;
6148 param->fp_obds_printed = 0;
6149 param->fp_mdt_index = OBD_NOT_FOUND;
6150 param->fp_obd_index = OBD_NOT_FOUND;
6153 if (lustre_fs && !param->fp_got_uuids) {
6154 ret = setup_target_indexes((d != -1) ? d : p, path,
6159 param->fp_dev = makedev(lmd->lmd_stx.stx_dev_major,
6160 lmd->lmd_stx.stx_dev_minor);
6161 } else if (!lustre_fs && param->fp_got_uuids) {
6162 /* A lustre/non-lustre mount point is crossed. */
6163 param->fp_got_uuids = 0;
6164 param->fp_mdt_index = OBD_NOT_FOUND;
6165 param->fp_obd_index = OBD_NOT_FOUND;
6169 if (param->fp_check_foreign) {
6170 decision = find_check_foreign(param);
6175 if (param->fp_check_stripe_size) {
6176 decision = find_check_stripe_size(param);
6181 if (param->fp_check_ext_size) {
6182 decision = find_check_ext_size(param);
6187 if (param->fp_check_stripe_count) {
6188 decision = find_value_cmp(stripe_count, param->fp_stripe_count,
6189 param->fp_stripe_count_sign,
6190 param->fp_exclude_stripe_count, 1, 0);
6195 if (param->fp_check_layout) {
6196 decision = find_check_layout(param);
6201 /* If an OBD UUID is specified but none matches, skip this file. */
6202 if ((param->fp_obd_uuid && param->fp_obd_index == OBD_NOT_FOUND) ||
6203 (param->fp_mdt_uuid && param->fp_mdt_index == OBD_NOT_FOUND))
6207 * If an OST or MDT UUID is given, and some OST matches,
6210 if (param->fp_obd_index != OBD_NOT_FOUND ||
6211 param->fp_mdt_index != OBD_NOT_FOUND) {
6212 if (param->fp_obd_uuid) {
6213 if (check_obd_match(param)) {
6215 * If no mdtuuid is given, we are done.
6216 * Otherwise, fall through to the mdtuuid
6219 if (!param->fp_mdt_uuid)
6226 if (param->fp_mdt_uuid) {
6227 if (check_mdt_match(param))
6234 if (param->fp_check_uid) {
6235 if (lmd->lmd_stx.stx_uid == param->fp_uid) {
6236 if (param->fp_exclude_uid)
6239 if (!param->fp_exclude_uid)
6244 if (param->fp_check_gid) {
6245 if (lmd->lmd_stx.stx_gid == param->fp_gid) {
6246 if (param->fp_exclude_gid)
6249 if (!param->fp_exclude_gid)
6254 /* Retrieve project id from file/dir */
6255 if (param->fp_check_projid || gather_all) {
6256 ret = get_projid(path, &fd, lmd->lmd_stx.stx_mode, &projid);
6258 llapi_error(LLAPI_MSG_ERROR, -ENOENT,
6259 "warning: %s: failed to get project id from file \"%s\"",
6263 if (param->fp_check_projid) {
6264 /* Conditionally filter this result based on --projid
6265 * param, and whether or not we're including or
6266 * excluding matching results.
6267 * fp_exclude_projid = 0 means only include exact match.
6268 * fp_exclude_projid = 1 means exclude exact match.
6270 bool matches = projid == param->fp_projid;
6272 if (matches == param->fp_exclude_projid)
6277 if (param->fp_check_pool) {
6278 decision = find_check_pool(param);
6283 if (param->fp_check_comp_count || param->fp_check_comp_flags ||
6284 param->fp_check_comp_start || param->fp_check_comp_end) {
6285 decision = find_check_comp_options(param);
6290 if (param->fp_check_mirror_count || param->fp_check_mirror_state) {
6291 decision = find_check_mirror_options(param);
6296 /* Check the time on mds. */
6298 if (param->fp_atime || param->fp_mtime || param->fp_ctime) {
6301 for_mds = lustre_fs ?
6302 (S_ISREG(lmd->lmd_stx.stx_mode) && stripe_count) : 0;
6303 decision = find_time_check(param, for_mds);
6308 if (param->fp_btime) {
6309 if (!(lmd->lmd_stx.stx_mask & STATX_BTIME)) {
6314 decision = find_value_cmp(lmd->lmd_stx.stx_btime.tv_sec,
6315 param->fp_btime, param->fp_bsign,
6316 param->fp_exclude_btime,
6317 param->fp_time_margin, 0);
6322 if (param->fp_newerxy) {
6325 for_mds = lustre_fs ?
6326 (S_ISREG(lmd->lmd_stx.stx_mode) && stripe_count) : 0;
6327 decision = find_newerxy_check(param, for_mds, true);
6336 if (param->fp_attrs || param->fp_neg_attrs) {
6337 decision = find_check_attr_options(param);
6342 flags = param->fp_lmd->lmd_flags;
6343 if (param->fp_check_size &&
6344 ((S_ISREG(lmd->lmd_stx.stx_mode) && stripe_count) ||
6345 S_ISDIR(lmd->lmd_stx.stx_mode)) &&
6346 !(flags & OBD_MD_FLSIZE ||
6347 (param->fp_lazy && flags & OBD_MD_FLLAZYSIZE)))
6350 if (param->fp_check_blocks &&
6351 ((S_ISREG(lmd->lmd_stx.stx_mode) && stripe_count) ||
6352 S_ISDIR(lmd->lmd_stx.stx_mode)) &&
6353 !(flags & OBD_MD_FLBLOCKS ||
6354 (param->fp_lazy && flags & OBD_MD_FLLAZYBLOCKS)))
6357 if (param->fp_xattr_match_info) {
6358 decision = find_check_xattrs(path, param->fp_xattr_match_info);
6364 * When checking nlink, stat(2) is needed for multi-striped directories
6365 * because the nlink value retrieved from the MDS above comes from
6366 * the number of stripes for the dir.
6367 * The posix stat call below fills in the correct number of links.
6368 * Single-stripe directories and regular files already have the
6369 * correct nlink value.
6371 if (param->fp_nlink && S_ISDIR(lmd->lmd_stx.stx_mode) &&
6372 (param->fp_lmv_md->lum_stripe_count != 0))
6376 * If file still fits the request, ask ost for updated info.
6377 * The regular stat is almost of the same speed as some new
6378 * 'glimpse-size-ioctl'.
6380 if (!decision || gather_all) {
6384 * For regular files with the stripe the decision may have not
6385 * been taken yet if *time or size is to be checked.
6387 if (param->fp_obd_index != OBD_NOT_FOUND)
6388 print_failed_tgt(param, path, LL_STATFS_LOV);
6390 if (param->fp_mdt_index != OBD_NOT_FOUND)
6391 print_failed_tgt(param, path, LL_STATFS_LMV);
6394 ret = fstat_f(d, &st);
6395 else if (de != NULL)
6396 ret = fstatat_f(p, de->d_name, &st,
6397 AT_SYMLINK_NOFOLLOW);
6399 ret = lstat_f(path, &st);
6402 if (errno == ENOENT) {
6403 llapi_error(LLAPI_MSG_ERROR, -ENOENT,
6404 "warning: %s: %s does not exist",
6409 llapi_error(LLAPI_MSG_ERROR, ret,
6410 "%s: stat on %s failed",
6416 convert_lmd_statx(param->fp_lmd, &st, true);
6417 /* Check the time on osc. */
6418 decision = find_time_check(param, 0);
6422 if (param->fp_newerxy) {
6423 decision = find_newerxy_check(param, 0, false);
6433 if (param->fp_nlink) {
6434 decision = find_value_cmp(lmd->lmd_stx.stx_nlink,
6435 param->fp_nlink, param->fp_nlink_sign,
6436 param->fp_exclude_nlink, 1, 0);
6441 if (param->fp_check_size) {
6442 decision = find_value_cmp(lmd->lmd_stx.stx_size,
6444 param->fp_size_sign,
6445 param->fp_exclude_size,
6446 param->fp_size_units, 0);
6451 if (param->fp_check_blocks) { /* convert st_blocks to bytes */
6452 decision = find_value_cmp(lmd->lmd_stx.stx_blocks * 512,
6454 param->fp_blocks_sign,
6455 param->fp_exclude_blocks,
6456 param->fp_blocks_units, 0);
6462 if (param->fp_skip_percent && find_skip_file(param))
6465 if (param->fp_format_printf_str)
6466 printf_format_string(param, path, projid, d);
6468 llapi_printf(LLAPI_MSG_NORMAL, "%s%c", path,
6469 param->fp_zero_end ? '\0' : '\n');
6474 /* Do not get down anymore? */
6475 if (param->fp_depth == param->fp_max_depth) {
6486 static int cb_migrate_mdt_init(char *path, int p, int *dp,
6487 void *param_data, struct dirent64 *de)
6489 struct find_param *param = (struct find_param *)param_data;
6490 struct lmv_user_md *lmu = param->fp_lmv_md;
6492 char raw[MAX_IOC_BUFLEN] = {'\0'};
6494 struct obd_ioctl_data data = { 0 };
6500 if (p == -1 && dp == NULL)
6506 if (dp != NULL && *dp != -1)
6510 tmp_p = open_parent(path);
6514 llapi_error(LLAPI_MSG_ERROR, ret,
6515 "can not open %s", path);
6520 path_copy = strdup(path);
6521 filename = basename(path_copy);
6523 data.ioc_inlbuf1 = (char *)filename;
6524 data.ioc_inllen1 = strlen(filename) + 1;
6525 data.ioc_inlbuf2 = (char *)lmu;
6526 data.ioc_inllen2 = lmv_user_md_size(lmu->lum_stripe_count,
6529 if (param->fp_depth == param->fp_max_depth)
6530 data.ioc_type = MDS_MIGRATE_NSONLY;
6531 ret = llapi_ioctl_pack(&data, &rawbuf, sizeof(raw));
6533 llapi_error(LLAPI_MSG_ERROR, ret,
6534 "%s: error packing ioctl data", __func__);
6539 ret = ioctl(tmp_p, LL_IOC_MIGRATE, rawbuf);
6541 if (errno == EBUSY && !retry) {
6543 * because migrate may not be able to lock all involved
6544 * objects in order, for some of them it try lock, while
6545 * there may be conflicting COS locks and cause migrate
6546 * fail with EBUSY, hope a sync() could cause
6547 * transaction commit and release these COS locks.
6552 } else if (errno == EALREADY) {
6553 if (param->fp_verbose & VERBOSE_DETAIL)
6554 llapi_printf(LLAPI_MSG_NORMAL,
6555 "%s migrated to MDT%d already\n",
6556 path, lmu->lum_stripe_offset);
6560 llapi_error(LLAPI_MSG_ERROR, ret, "%s migrate failed",
6564 } else if (param->fp_verbose & VERBOSE_DETAIL) {
6565 llapi_printf(LLAPI_MSG_NORMAL,
6566 "migrate %s to MDT%d stripe count %d\n",
6567 path, lmu->lum_stripe_offset,
6568 lmu->lum_stripe_count);
6572 /* Do not get down anymore? */
6573 if (param->fp_depth == param->fp_max_depth)
6580 * If the directory is being migration, we need
6581 * close the directory after migration,
6582 * so the old directory cache will be cleanup
6583 * on the client side, and re-open to get the
6584 * new directory handle
6586 *dp = open(path, O_RDONLY|O_NDELAY|O_DIRECTORY);
6589 llapi_error(LLAPI_MSG_ERROR, ret,
6590 "%s: Failed to open '%s'", __func__, path);
6602 /* dir migration finished, shrink its stripes */
6603 static int cb_migrate_mdt_fini(char *path, int p, int *dp, void *data,
6604 struct dirent64 *de)
6606 struct find_param *param = data;
6607 struct lmv_user_md *lmu = param->fp_lmv_md;
6608 int lmulen = lmv_user_md_size(lmu->lum_stripe_count, lmu->lum_magic);
6611 if (de && de->d_type != DT_DIR)
6616 * close it before setxattr because the latter may destroy the
6617 * original object, and cause close fail.
6625 ret = setxattr(path, XATTR_NAME_LMV, lmu, lmulen, 0);
6627 if (errno == EALREADY) {
6630 llapi_error(LLAPI_MSG_ERROR, errno,
6631 "%s: error completing migration of %s",
6638 cb_common_fini(path, p, dp, data, de);
6642 int llapi_migrate_mdt(char *path, struct find_param *param)
6644 param->fp_stop_on_error = 1;
6645 return param_callback(path, cb_migrate_mdt_init, cb_migrate_mdt_fini,
6649 int llapi_mv(char *path, struct find_param *param)
6651 #if LUSTRE_VERSION_CODE > OBD_OCD_VERSION(2, 9, 59, 0)
6652 static bool printed;
6655 llapi_error(LLAPI_MSG_ERROR, -ESTALE,
6656 "%s() is deprecated, use llapi_migrate_mdt() instead",
6661 return llapi_migrate_mdt(path, param);
6665 * Check string for escape sequences and print a message to stdout
6666 * if any invalid escapes are found.
6668 * @param[in] c Pointer to character immediately following the
6669 * '\' character indicating the start of an escape
6671 * @return Number of characters examined in the escape sequence
6672 * (regardless of whether the sequence is valid or not).
6674 static int validate_printf_esc(char *c)
6676 char *valid_esc = "nt\\";
6679 /* backslash at end of string */
6680 llapi_err_noerrno(LLAPI_MSG_WARN,
6681 "warning: '\\' at end of -printf format string\n");
6685 if (!strchr(valid_esc, *c))
6686 /* Invalid escape character */
6687 llapi_err_noerrno(LLAPI_MSG_WARN,
6688 "warning: unrecognized escape: '\\%c'\n", *c);
6694 * Check string for format directives and print a message to stdout
6695 * if any invalid directives are found.
6697 * @param[in] c Pointer to character immediately following the
6698 * '%' character indicating the start of a format
6700 * @return Number of characters examined in the format directive
6701 * (regardless of whether the directive is valid or not).
6703 static int validate_printf_fmt(char *c)
6705 char *valid_fmt_single = "abcigGkmMnpstuUwy%";
6706 char *valid_fmt_double = "ACTW";
6707 char *valid_fmt_lustre = "aAcFhioPpS";
6708 char curr = *c, next;
6711 llapi_err_noerrno(LLAPI_MSG_WARN,
6712 "warning: '%%' at end of -printf format string\n");
6716 /* GNU find supports formats such as "%----10s" */
6720 if (isdigit(curr)) {
6721 /* skip width format specifier */
6729 if ((next == '\0') || (next == '%') || (next == '\\'))
6730 /* Treat as single char format directive */
6733 /* Check format directives with multiple characters */
6734 if (strchr(valid_fmt_double, curr)) {
6735 /* For now, only valid formats are followed by '@' char */
6737 llapi_err_noerrno(LLAPI_MSG_WARN,
6738 "warning: unrecognized format directive: '%%%c%c'\n",
6743 /* Lustre formats always start with 'L' */
6745 if (!strchr(valid_fmt_lustre, next))
6746 llapi_err_noerrno(LLAPI_MSG_WARN,
6747 "warning: unrecognized format directive: '%%%c%c'\n",
6754 if (!strchr(valid_fmt_single, curr))
6755 llapi_err_noerrno(LLAPI_MSG_WARN,
6756 "warning: unrecognized format directive: '%%%c'\n", curr);
6761 * Validate the user-supplied string for the -printf option and report
6762 * any invalid backslash escape sequences or format directives.
6764 * @param[in] param Structure containing info about invocation of lfs find
6767 void validate_printf_str(struct find_param *param)
6769 char *c = param->fp_format_printf_str;
6775 ret = validate_printf_fmt(++c);
6779 ret = validate_printf_esc(++c);
6789 int llapi_find(char *path, struct find_param *param)
6791 if (param->fp_format_printf_str)
6792 validate_printf_str(param);
6793 if (param->fp_thread_count) {
6794 return parallel_find(path, param);
6796 return param_callback(path, cb_find_init, cb_common_fini,
6802 * Get MDT number that the file/directory inode referenced
6803 * by the open fd resides on.
6804 * Return 0 and mdtidx on success, or -ve errno.
6806 int llapi_file_fget_mdtidx(int fd, int *mdtidx)
6808 if (ioctl(fd, LL_IOC_GET_MDTIDX, mdtidx) < 0)
6813 static int cb_get_mdt_index(char *path, int p, int *dp, void *data,
6814 struct dirent64 *de)
6816 struct find_param *param = (struct find_param *)data;
6817 int d = dp == NULL ? -1 : *dp;
6820 bool hex = param->fp_hex_idx;
6822 if (p == -1 && d == -1)
6826 ret = llapi_file_fget_mdtidx(d, &mdtidx);
6827 } else /* if (p != -1) */ {
6830 fd = open(path, O_RDONLY | O_NOCTTY);
6832 ret = llapi_file_fget_mdtidx(fd, &mdtidx);
6840 if (ret == -ENODATA) {
6841 if (!param->fp_obd_uuid)
6842 llapi_printf(LLAPI_MSG_NORMAL,
6843 "'%s' has no stripe info\n", path);
6845 } else if (ret == -ENOENT) {
6846 llapi_error(LLAPI_MSG_WARN, ret,
6847 "warning: %s: '%s' does not exist",
6850 } else if (ret == -ENOTTY) {
6851 llapi_error(LLAPI_MSG_ERROR, ret,
6852 "%s: '%s' not on a Lustre fs",
6855 llapi_error(LLAPI_MSG_ERROR, ret,
6856 "error: %s: '%s' failed get_mdtidx",
6862 if (param->fp_quiet || !(param->fp_verbose & VERBOSE_DETAIL))
6863 llapi_printf(LLAPI_MSG_NORMAL, hex ? "%#x\n" : "%d\n", mdtidx);
6865 llapi_printf(LLAPI_MSG_NORMAL, hex ? "%s\nmdt_index:\t%#x\n"
6866 : "%s\nmdt_index:\t%d\n",
6870 /* Do not go down anymore? */
6871 if (param->fp_depth == param->fp_max_depth)
6879 static int cb_getstripe(char *path, int p, int *dp, void *data,
6880 struct dirent64 *de)
6882 struct find_param *param = (struct find_param *)data;
6883 int d = dp == NULL ? -1 : *dp, fd = -1;
6887 if (p == -1 && d == -1)
6890 if (param->fp_obd_uuid) {
6891 param->fp_quiet = 1;
6892 ret = setup_obd_uuid(d != -1 ? d : p, path, param);
6897 if (!param->fp_no_follow && de && de->d_type == DT_LNK && d == -1)
6898 d = fd = open(path, O_RDONLY | O_DIRECTORY);
6900 if (d != -1 && (param->fp_get_lmv || param->fp_get_default_lmv))
6901 ret = cb_get_dirstripe(path, &d, param);
6903 ret = get_lmd_info_fd(path, p, d, ¶m->fp_lmd->lmd_lmm,
6904 param->fp_lum_size, GET_LMD_STRIPE);
6905 else if (d == -1 && (param->fp_get_lmv || param->fp_get_default_lmv)) {
6906 /* in case of a dangling or valid faked symlink dir, opendir()
6907 * should have return either EINVAL or ENOENT, so let's try
6908 * to get LMV just in case, and by opening it as a file but
6909 * with O_NOFOLLOW ...
6911 int flag = O_RDONLY | O_NONBLOCK;
6913 if (param->fp_no_follow)
6916 fd = open(path, flag);
6919 if (fstat(fd, &st) != 0) {
6924 /* clear O_NONBLOCK for non-PIPEs */
6925 if (!S_ISFIFO(st.st_mode))
6926 fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) & ~O_NONBLOCK);
6927 ret = cb_get_dirstripe(path, &fd, param);
6929 llapi_lov_dump_user_lmm(param, path, LDF_IS_DIR);
6932 } else if (d == -1) {
6933 if (!param->fp_no_follow && de && de->d_type == DT_LNK) {
6934 /* open the target of symlink as a file */
6935 fd = open(path, O_RDONLY);
6939 ret = get_lmd_info_fd(path, p, fd, ¶m->fp_lmd->lmd_lmm,
6940 param->fp_lum_size, GET_LMD_STRIPE);
6948 if (errno == ENODATA && d != -1) {
6950 * We need to "fake" the "use the default" values
6951 * since the lmm struct is zeroed out at this point.
6952 * The magic needs to be set in order to satisfy
6953 * a check later on in the code path.
6954 * The object_seq needs to be set for the "(Default)"
6955 * prefix to be displayed.
6957 if (param->fp_get_default_lmv) {
6958 struct lmv_user_md *lum = param->fp_lmv_md;
6962 lum->lum_magic = LMV_USER_MAGIC;
6963 lum->lum_stripe_count = 0;
6964 lum->lum_stripe_offset = LMV_OFFSET_DEFAULT;
6966 } else if (param->fp_get_lmv) {
6967 struct lmv_user_md *lum = param->fp_lmv_md;
6970 ret = llapi_file_fget_mdtidx(d, &mdtidx);
6973 lum->lum_magic = LMV_MAGIC_V1;
6974 lum->lum_stripe_count = 0;
6975 lum->lum_stripe_offset = mdtidx;
6978 struct lov_user_md *lmm =
6979 ¶m->fp_lmd->lmd_lmm;
6981 lmm->lmm_magic = LOV_USER_MAGIC_V1;
6983 ostid_set_seq(&lmm->lmm_oi,
6984 FID_SEQ_LOV_DEFAULT);
6985 lmm->lmm_stripe_count = 0;
6986 lmm->lmm_stripe_size = 0;
6987 lmm->lmm_stripe_offset = -1;
6990 } else if (errno == ENODATA && p != -1) {
6991 if (!param->fp_obd_uuid && !param->fp_mdt_uuid)
6992 llapi_printf(LLAPI_MSG_NORMAL,
6993 "%s has no stripe info\n", path);
6995 } else if (errno == ENOENT) {
6996 llapi_error(LLAPI_MSG_WARN, -ENOENT,
6997 "warning: %s: %s does not exist",
7000 } else if (errno == ENOTTY) {
7002 llapi_error(LLAPI_MSG_ERROR, ret,
7003 "%s: '%s' not on a Lustre fs?",
7008 llapi_error(LLAPI_MSG_ERROR, ret,
7009 "error: %s: %s failed for %s",
7011 "LL_IOC_LOV_GETSTRIPE" :
7012 "IOC_MDC_GETFILESTRIPE", path);
7019 if (!(param->fp_verbose & VERBOSE_MDTINDEX))
7020 llapi_lov_dump_user_lmm(param, path, d != -1 ? LDF_IS_DIR : 0);
7023 /* Do not get down anymore? */
7024 if (param->fp_depth == param->fp_max_depth)
7032 int llapi_getstripe(char *path, struct find_param *param)
7034 return param_callback(path, (param->fp_verbose & VERBOSE_MDTINDEX) ?
7035 cb_get_mdt_index : cb_getstripe,
7036 cb_common_fini, param);
7039 int llapi_obd_fstatfs(int fd, __u32 type, __u32 index,
7040 struct obd_statfs *stat_buf, struct obd_uuid *uuid_buf)
7042 char raw[MAX_IOC_BUFLEN] = {'\0'};
7044 struct obd_ioctl_data data = { 0 };
7047 data.ioc_inlbuf1 = (char *)&type;
7048 data.ioc_inllen1 = sizeof(__u32);
7049 data.ioc_inlbuf2 = (char *)&index;
7050 data.ioc_inllen2 = sizeof(__u32);
7051 data.ioc_pbuf1 = (char *)stat_buf;
7052 data.ioc_plen1 = sizeof(struct obd_statfs);
7053 data.ioc_pbuf2 = (char *)uuid_buf;
7054 data.ioc_plen2 = sizeof(struct obd_uuid);
7056 rc = llapi_ioctl_pack(&data, &rawbuf, sizeof(raw));
7058 llapi_error(LLAPI_MSG_ERROR, rc,
7059 "%s: error packing ioctl data", __func__);
7063 rc = ioctl(fd, IOC_OBD_STATFS, (void *)rawbuf);
7065 return rc < 0 ? -errno : 0;
7068 int llapi_obd_statfs(char *path, __u32 type, __u32 index,
7069 struct obd_statfs *stat_buf, struct obd_uuid *uuid_buf)
7074 fd = open(path, O_RDONLY);
7077 llapi_error(LLAPI_MSG_ERROR, rc, "error: %s: opening '%s'",
7080 * If we can't even open a file on the filesystem (e.g. with
7081 * -ESHUTDOWN), force caller to exit or it will loop forever.
7086 rc = llapi_obd_fstatfs(fd, type, index, stat_buf, uuid_buf);
7093 #define MAX_STRING_SIZE 128
7095 int llapi_ping(char *obd_type, char *obd_name)
7097 int flags = O_RDONLY;
7098 char buf[1] = { 0 };
7102 rc = cfs_get_param_paths(&path, "%s/%s/ping",
7103 obd_type, obd_name);
7107 fd = open(path.gl_pathv[0], flags);
7109 if (errno == EACCES && flags == O_RDONLY) {
7114 llapi_error(LLAPI_MSG_ERROR, rc, "error opening %s",
7119 if (flags == O_RDONLY)
7120 rc = read(fd, buf, sizeof(buf));
7122 rc = write(fd, buf, sizeof(buf));
7130 cfs_free_param_data(&path);
7134 int llapi_target_iterate(int type_num, char **obd_type,
7135 void *args, llapi_cb_t cb)
7141 for (i = 0; i < type_num; i++) {
7144 rc = cfs_get_param_paths(¶m, "%s/*/uuid", obd_type[i]);
7148 for (j = 0; j < param.gl_pathc; j++) {
7149 char obd_uuid[UUID_MAX + 1];
7153 fp = fopen(param.gl_pathv[j], "r");
7156 llapi_error(LLAPI_MSG_ERROR, rc,
7157 "error: opening '%s'",
7162 if (fgets(obd_uuid, sizeof(obd_uuid), fp) == NULL) {
7164 llapi_error(LLAPI_MSG_ERROR, rc,
7165 "error: reading '%s'",
7170 /* Extract the obd_name from the sysfs path.
7171 * 'topsysfs'/fs/lustre/'obd_type'/'obd_name'.
7173 obd_name = strstr(param.gl_pathv[j], "/fs/lustre/");
7179 /* skip /fs/lustre/'obd_type'/ */
7180 obd_name += strlen(obd_type[i]) + 12;
7181 /* chop off after obd_name */
7182 ptr = strrchr(obd_name, '/');
7186 cb(obd_type[i], obd_name, obd_uuid, args);
7191 cfs_free_param_data(¶m);
7196 cfs_free_param_data(¶m);
7200 struct check_target_filter {
7205 static void do_target_check(char *obd_type_name, char *obd_name,
7206 char *obd_uuid, void *args)
7209 struct check_target_filter *filter = args;
7211 if (filter != NULL) {
7212 /* check NIDs if obd type is mgc */
7213 if (strcmp(obd_type_name, "mgc") == 0) {
7214 char *delimiter = filter->nid;
7215 char *nidstr = filter->nid;
7218 while (*nidstr && *delimiter) {
7219 delimiter = cfs_nidstr_find_delimiter(nidstr);
7220 if (!strncmp(obd_name + 3, nidstr,
7221 delimiter - nidstr)) {
7225 nidstr = delimiter + 1;
7230 /* check instance for other types of device (osc/mdc) */
7231 else if (strstr(obd_name, filter->instance) == NULL)
7235 rc = llapi_ping(obd_type_name, obd_name);
7237 llapi_printf(LLAPI_MSG_NORMAL, "%s inactive.\n", obd_name);
7239 llapi_error(LLAPI_MSG_ERROR, rc, "error: check '%s'", obd_name);
7241 llapi_printf(LLAPI_MSG_NORMAL, "%s active.\n", obd_name);
7244 int llapi_target_check(int type_num, char **obd_type, char *dir)
7246 char instance[MAX_INSTANCE_LEN];
7247 struct check_target_filter filter = {NULL, NULL};
7251 if (dir == NULL || dir[0] == '\0')
7252 return llapi_target_iterate(type_num, obd_type, NULL,
7255 rc = get_root_path(WANT_NID | WANT_ERROR, NULL, NULL, dir, -1, NULL,
7258 llapi_error(LLAPI_MSG_ERROR, rc,
7259 "cannot get nid of path '%s'", dir);
7264 rc = llapi_get_instance(dir, instance, ARRAY_SIZE(instance));
7268 filter.instance = instance;
7270 rc = llapi_target_iterate(type_num, obd_type, &filter,
7278 #undef MAX_STRING_SIZE
7280 /* Is this a lustre fs? */
7281 int llapi_is_lustre_mnttype(const char *type)
7283 return strcmp(type, "lustre") == 0 || strcmp(type, "lustre_tgt") == 0;
7286 /* Is this a lustre client fs? */
7287 int llapi_is_lustre_mnt(struct mntent *mnt)
7289 return (llapi_is_lustre_mnttype(mnt->mnt_type) &&
7290 strstr(mnt->mnt_fsname, ":/") != NULL);
7293 int llapi_quotactl(char *mnt, struct if_quotactl *qctl)
7295 char fsname[PATH_MAX + 1];
7299 rc = llapi_search_fsname(mnt, fsname);
7303 root = open(mnt, O_RDONLY | O_DIRECTORY);
7306 llapi_error(LLAPI_MSG_ERROR, rc, "cannot open '%s'", mnt);
7310 rc = ioctl(root, OBD_IOC_QUOTACTL, qctl);
7313 if (rc == -ENOENT && LUSTRE_Q_CMD_IS_POOL(qctl->qc_cmd))
7314 llapi_error(LLAPI_MSG_ERROR | LLAPI_MSG_NO_ERRNO, rc,
7315 "Cannot find pool '%s'", qctl->qc_poolname);
7321 int llapi_get_connect_flags(const char *mnt, __u64 *flags)
7326 root = open(mnt, O_RDONLY | O_DIRECTORY);
7329 llapi_error(LLAPI_MSG_ERROR, rc, "open %s failed", mnt);
7333 rc = ioctl(root, LL_IOC_GET_CONNECT_FLAGS, flags);
7336 llapi_error(LLAPI_MSG_ERROR, rc,
7337 "ioctl on %s for getting connect flags failed", mnt);
7344 * Flush cached pages from all clients.
7346 * \param fd File descriptor
7350 int llapi_file_flush(int fd)
7354 return llapi_get_data_version(fd, &dv, LL_DV_WR_FLUSH);
7358 * Flush dirty pages from all clients.
7360 * OSTs will take LCK_PR to flush dirty pages from clients.
7362 * \param[in] fd File descriptor
7364 * \retval 0 on success.
7365 * \retval -errno on error.
7367 int llapi_fsync(int fd)
7371 return llapi_get_data_version(fd, &dv, LL_DV_RD_FLUSH);