+ int sign, int negopt, unsigned long long margin,
+ int mds)
+{
+ int ret = -1;
+
+ if (sign > 0) {
+ /* Drop the fraction of margin (of days). */
+ if (file + margin <= limit)
+ ret = mds ? 0 : 1;
+ } else if (sign == 0) {
+ if (file <= limit && file + margin > limit)
+ ret = mds ? 0 : 1;
+ else if (file + margin <= limit)
+ ret = mds ? 0 : -1;
+ } else if (sign < 0) {
+ if (file > limit)
+ ret = 1;
+ else if (mds)
+ ret = 0;
+ }
+
+ return negopt ? ~ret + 1 : ret;
+}
+
+static inline struct lov_user_md *
+lov_comp_entry(struct lov_comp_md_v1 *comp_v1, int ent_idx)
+{
+ return (struct lov_user_md *)((char *)comp_v1 +
+ comp_v1->lcm_entries[ent_idx].lcme_offset);
+}
+
+static inline struct lov_user_ost_data_v1 *
+lov_v1v3_objects(struct lov_user_md *v1)
+{
+ if (v1->lmm_magic == LOV_USER_MAGIC_V3)
+ return ((struct lov_user_md_v3 *)v1)->lmm_objects;
+ else
+ return v1->lmm_objects;
+}
+
+static inline void
+lov_v1v3_pool_name(struct lov_user_md *v1, char *pool_name)
+{
+ if (v1->lmm_magic == LOV_USER_MAGIC_V3)
+ snprintf(pool_name, LOV_MAXPOOLNAME, "%s",
+ ((struct lov_user_md_v3 *)v1)->lmm_pool_name);
+ else
+ pool_name[0] = '\0';
+}
+
+static inline bool
+print_last_init_comp(struct find_param *param)
+{
+ /* print all component info */
+ if ((param->fp_verbose & VERBOSE_DEFAULT) == VERBOSE_DEFAULT)
+ return false;
+
+ /* print specific component info */
+ if (param->fp_check_comp_id || param->fp_check_comp_flags ||
+ param->fp_check_comp_start || param->fp_check_comp_end)
+ return false;
+
+ return true;
+}
+
+static int find_comp_end_cmp(unsigned long long end, struct find_param *param)
+{
+ int match;
+
+ if (param->fp_comp_end == LUSTRE_EOF) {
+ if (param->fp_comp_end_sign == 0) /* equal to EOF */
+ match = end == LUSTRE_EOF ? 1 : -1;
+ else if (param->fp_comp_end_sign > 0) /* at most EOF */
+ match = end == LUSTRE_EOF ? -1 : 1;
+ else /* at least EOF */
+ match = -1;
+ if (param->fp_exclude_comp_end)
+ match = ~match + 1;
+ } else {
+ unsigned long long margin;
+
+ margin = end == LUSTRE_EOF ? 0 : param->fp_comp_end_units;
+ match = find_value_cmp(end, param->fp_comp_end,
+ param->fp_comp_end_sign,
+ param->fp_exclude_comp_end, margin, 0);
+ }
+
+ return match;
+}
+
+/**
+ * An example of "getstripe -v" for a two components PFL file:
+ *
+ * composite_header:
+ * lcm_magic: 0x0BD60BD0
+ * lcm_size: 264
+ * lcm_flags: 0
+ * lcm_layout_gen: 2
+ * lcm_entry_count: 2
+ * components:
+ * - lcme_id: 1
+ * lcme_flags: 0x10
+ * lcme_extent.e_start: 0
+ * lcme_extent.e_end: 1048576
+ * lcme_offset: 128
+ * lcme_size: 56
+ * sub_layout:
+ * lmm_magic: 0x0BD10BD0
+ * lmm_seq: 0x200000401
+ * lmm_object_id: 0x1
+ * lmm_fid: [0x200000401:0x1:0x0]
+ * lmm_stripe_count: 1
+ * lmm_stripe_size: 1048576
+ * lmm_pattern: raid0
+ * lmm_layout_gen: 0
+ * lmm_stripe_offset: 0
+ * lmm_objects:
+ * - 0: { l_ost_idx: 0, l_fid: [0x100000000:0x2:0x0] }
+ *
+ * - lcme_id: 2
+ * lcme_flags: 0x10
+ * lcme_extent.e_start: 1048576
+ * lcme_extent.e_end: EOF
+ * lcme_offset: 184
+ * lcme_size: 80
+ * sub_layout:
+ * lmm_magic: 0x0BD10BD0
+ * lmm_seq: 0x200000401
+ * lmm_object_id: 0x1
+ * lmm_fid: [0x200000401:0x1:0x0]
+ * lmm_stripe_count: 2
+ * lmm_stripe_size: 1048576
+ * lmm_pattern: raid0
+ * lmm_layout_gen: 0
+ * lmm_stripe_offset: 1
+ * lmm_objects:
+ * - 0: { l_ost_idx: 1, l_fid: [0x100010000:0x2:0x0] }
+ * - 1: { l_ost_idx: 0, l_fid: [0x100000000:0x3:0x0] }
+ */
+static void lov_dump_comp_v1(struct find_param *param, char *path,
+ enum lov_dump_flags flags)
+{
+ struct lov_comp_md_entry_v1 *entry;
+ struct lov_user_ost_data_v1 *objects;
+ struct lov_comp_md_v1 *comp_v1 = (void *)¶m->fp_lmd->lmd_lmm;
+ struct lov_user_md_v1 *v1;
+ char pool_name[LOV_MAXPOOLNAME + 1];
+ int obdindex = param->fp_obd_index;
+ int i, j, match;
+ bool obdstripe = false;
+
+ if (obdindex != OBD_NOT_FOUND) {
+ for (i = 0; !(flags & LDF_IS_DIR) && !obdstripe &&
+ i < comp_v1->lcm_entry_count; i++) {
+ if (!(comp_v1->lcm_entries[i].lcme_flags &
+ LCME_FL_INIT))
+ continue;
+
+ v1 = lov_comp_entry(comp_v1, i);
+ objects = lov_v1v3_objects(v1);
+
+ for (j = 0; j < v1->lmm_stripe_count; j++) {
+ if (obdindex == objects[j].l_ost_idx) {
+ obdstripe = true;
+ break;
+ }
+ }
+ }
+ } else {
+ obdstripe = true;
+ }
+
+ if (!obdstripe)
+ return;
+
+ lov_dump_comp_v1_header(param, path, flags);
+
+ flags |= LDF_INDENT;
+
+ for (i = 0; i < comp_v1->lcm_entry_count; i++) {
+ entry = &comp_v1->lcm_entries[i];
+
+ if (param->fp_check_comp_flags) {
+ if (((param->fp_comp_flags & entry->lcme_flags) !=
+ param->fp_comp_flags) ||
+ (param->fp_comp_neg_flags & entry->lcme_flags))
+ continue;
+ }
+
+ if (param->fp_check_comp_id &&
+ param->fp_comp_id != entry->lcme_id)
+ continue;
+
+ if (param->fp_check_comp_start) {
+ match = find_value_cmp(entry->lcme_extent.e_start,
+ param->fp_comp_start,
+ param->fp_comp_start_sign,
+ 0,
+ param->fp_comp_start_units, 0);
+ if (match == -1)
+ continue;
+ }
+
+ if (param->fp_check_comp_end) {
+ match = find_comp_end_cmp(entry->lcme_extent.e_end,
+ param);
+ if (match == -1)
+ continue;
+ }
+
+ if (print_last_init_comp(param)) {
+ /**
+ * if part of stripe info is needed, we'd print only
+ * the last instantiated component info.
+ */
+ if (entry->lcme_flags & LCME_FL_INIT)
+ continue;
+ else
+ break;
+ }
+
+ if (entry->lcme_flags & LCME_FL_INIT) {
+ if (obdindex != OBD_NOT_FOUND) {
+ flags |= LDF_SKIP_OBJS;
+ v1 = lov_comp_entry(comp_v1, i);
+ objects = lov_v1v3_objects(v1);
+
+ for (j = 0; j < v1->lmm_stripe_count; j++) {
+ if (obdindex == objects[j].l_ost_idx) {
+ flags &= ~LDF_SKIP_OBJS;
+ break;
+ }
+ }
+ } else {
+ flags &= ~LDF_SKIP_OBJS;
+ }
+ } else {
+ flags |= LDF_SKIP_OBJS;
+ }
+
+ if (obdindex != OBD_NOT_FOUND && (flags & LDF_SKIP_OBJS))
+ continue;
+ lov_dump_comp_v1_entry(param, flags, i);
+
+ v1 = lov_comp_entry(comp_v1, i);
+ objects = lov_v1v3_objects(v1);
+ lov_v1v3_pool_name(v1, pool_name);
+
+ lov_dump_user_lmm_v1v3(v1, pool_name, objects, path, obdindex,
+ param->fp_max_depth, param->fp_verbose,
+ flags);
+ }
+ if (print_last_init_comp(param)) {
+ /**
+ * directory layout contains only layout template, print the
+ * last component.
+ */
+ if (i == 0)
+ i = comp_v1->lcm_entry_count - 1;
+ else
+ i--;
+ flags &= ~LDF_SKIP_OBJS;
+
+ lov_dump_comp_v1_entry(param, flags, i);
+
+ v1 = lov_comp_entry(comp_v1, i);
+ objects = lov_v1v3_objects(v1);
+ lov_v1v3_pool_name(v1, pool_name);
+
+ lov_dump_user_lmm_v1v3(v1, pool_name, objects, path, obdindex,
+ param->fp_max_depth, param->fp_verbose,
+ flags);
+ }
+}
+
+#define VERBOSE_COMP_OPTS (VERBOSE_COMP_COUNT | VERBOSE_COMP_ID | \
+ VERBOSE_COMP_START | VERBOSE_COMP_END | \
+ VERBOSE_COMP_FLAGS)
+
+static inline bool has_any_comp_options(struct find_param *param)
+{
+ int verbose = param->fp_verbose;
+
+ if (param->fp_check_comp_id || param->fp_check_comp_count ||
+ param->fp_check_comp_start || param->fp_check_comp_end ||
+ param->fp_check_comp_flags)
+ return true;
+
+ /* show full layout information, not component specific */
+ if ((verbose & ~VERBOSE_DETAIL) == VERBOSE_DEFAULT)
+ return false;
+
+ return verbose & VERBOSE_COMP_OPTS;
+}
+
+struct lov_user_mds_data *lov_forge_comp_v1(struct lov_user_mds_data *orig,
+ bool is_dir)
+{
+ struct lov_user_md *lum = &orig->lmd_lmm;
+ struct lov_user_mds_data *new;
+ struct lov_comp_md_v1 *comp_v1;
+ struct lov_comp_md_entry_v1 *ent;
+ int lum_off = sizeof(*comp_v1) + sizeof(*ent);
+ int lum_size = lov_user_md_size(is_dir ? 0 : lum->lmm_stripe_count,
+ lum->lmm_magic);
+
+ new = malloc(sizeof(lstat_t) + lum_off + lum_size);
+ if (new == NULL) {
+ llapi_printf(LLAPI_MSG_NORMAL, "out of memory\n");
+ return new;
+ }
+
+ memcpy(new, orig, sizeof(lstat_t));
+
+ comp_v1 = (struct lov_comp_md_v1 *)&new->lmd_lmm;
+ comp_v1->lcm_magic = lum->lmm_magic;
+ comp_v1->lcm_size = lum_off + lum_size;
+ comp_v1->lcm_layout_gen = is_dir ? 0 : lum->lmm_layout_gen;
+ comp_v1->lcm_flags = 0;
+ comp_v1->lcm_entry_count = 1;
+
+ ent = &comp_v1->lcm_entries[0];
+ ent->lcme_id = 0;
+ ent->lcme_flags = is_dir ? 0 : LCME_FL_INIT;
+ ent->lcme_extent.e_start = 0;
+ ent->lcme_extent.e_end = LUSTRE_EOF;
+ ent->lcme_offset = lum_off;
+ ent->lcme_size = lum_size;
+
+ memcpy((char *)comp_v1 + lum_off, lum, lum_size);
+
+ return new;
+}
+
+static void lov_dump_plain_user_lmm(struct find_param *param, char *path,
+ enum lov_dump_flags flags)
+{
+ __u32 magic = *(__u32 *)¶m->fp_lmd->lmd_lmm;
+
+ if (has_any_comp_options(param)) {
+ struct lov_user_mds_data *new_lmd, *orig_lmd;
+
+ orig_lmd = param->fp_lmd;
+ new_lmd = lov_forge_comp_v1(orig_lmd, flags & LDF_IS_DIR);
+ if (new_lmd != NULL) {
+ param->fp_lmd = new_lmd;
+ lov_dump_comp_v1(param, path, flags);
+ param->fp_lmd = orig_lmd;
+ free(new_lmd);
+ }
+ return;
+ }
+
+ if (magic == LOV_USER_MAGIC_V1) {
+ lov_dump_user_lmm_v1v3(¶m->fp_lmd->lmd_lmm, NULL,
+ param->fp_lmd->lmd_lmm.lmm_objects,
+ path, param->fp_obd_index,
+ param->fp_max_depth, param->fp_verbose,
+ flags);
+ } else {
+ char pool_name[LOV_MAXPOOLNAME + 1];
+ struct lov_user_ost_data_v1 *objects;
+ struct lov_user_md_v3 *lmmv3 = (void *)¶m->fp_lmd->lmd_lmm;
+
+ snprintf(pool_name, sizeof(pool_name), "%s",
+ lmmv3->lmm_pool_name);
+ objects = lmmv3->lmm_objects;
+ lov_dump_user_lmm_v1v3(¶m->fp_lmd->lmd_lmm, pool_name,
+ objects, path, param->fp_obd_index,
+ param->fp_max_depth, param->fp_verbose,
+ flags);
+ }
+}
+
+static void llapi_lov_dump_user_lmm(struct find_param *param, char *path,
+ enum lov_dump_flags flags)
+{
+ __u32 magic;
+
+ if (param->fp_get_lmv || param->fp_get_default_lmv)
+ magic = (__u32)param->fp_lmv_md->lum_magic;
+ else
+ magic = *(__u32 *)¶m->fp_lmd->lmd_lmm; /* lum->lmm_magic */
+
+ if (param->fp_raw)
+ flags |= LDF_IS_RAW;
+ if (param->fp_yaml)
+ flags |= LDF_YAML;
+
+ switch (magic) {
+ case LOV_USER_MAGIC_V1:
+ case LOV_USER_MAGIC_V3:
+ lov_dump_plain_user_lmm(param, path, flags);
+ break;
+ case LMV_MAGIC_V1:
+ case LMV_USER_MAGIC: {
+ char pool_name[LOV_MAXPOOLNAME + 1];
+ struct lmv_user_md *lum;
+
+ lum = (struct lmv_user_md *)param->fp_lmv_md;
+ snprintf(pool_name, sizeof(pool_name), "%s",
+ lum->lum_pool_name);
+ lmv_dump_user_lmm(lum, pool_name, path, param->fp_obd_index,
+ param->fp_max_depth, param->fp_verbose,
+ flags);
+ break;
+ }
+ case LOV_USER_MAGIC_COMP_V1:
+ lov_dump_comp_v1(param, path, flags);
+ break;
+ default:
+ llapi_printf(LLAPI_MSG_NORMAL, "unknown lmm_magic: %#x "
+ "(expecting one of %#x %#x %#x %#x)\n",
+ *(__u32 *)¶m->fp_lmd->lmd_lmm,
+ LOV_USER_MAGIC_V1, LOV_USER_MAGIC_V3,
+ LMV_USER_MAGIC, LMV_MAGIC_V1);
+ return;
+ }
+}
+
+int llapi_file_get_stripe(const char *path, struct lov_user_md *lum)
+{
+ const char *fname;
+ char *dname;
+ int fd, rc = 0;
+
+ fname = strrchr(path, '/');
+
+ /* It should be a file (or other non-directory) */
+ if (fname == NULL) {
+ dname = (char *)malloc(2);
+ if (dname == NULL)
+ return -ENOMEM;
+ strcpy(dname, ".");
+ fname = (char *)path;
+ } else {
+ dname = (char *)malloc(fname - path + 1);
+ if (dname == NULL)
+ return -ENOMEM;
+ strncpy(dname, path, fname - path);
+ dname[fname - path] = '\0';
+ fname++;
+ }
+
+ fd = open(dname, O_RDONLY | O_NONBLOCK);
+ if (fd == -1) {
+ rc = -errno;
+ free(dname);
+ return rc;
+ }
+
+ strcpy((char *)lum, fname);
+ if (ioctl(fd, IOC_MDC_GETFILESTRIPE, (void *)lum) == -1)
+ rc = -errno;
+
+ if (close(fd) == -1 && rc == 0)
+ rc = -errno;
+
+ free(dname);
+ return rc;
+}
+
+int llapi_file_lookup(int dirfd, const char *name)
+{
+ struct obd_ioctl_data data = { 0 };
+ char rawbuf[8192];
+ char *buf = rawbuf;
+ int rc;
+
+ if (dirfd < 0 || name == NULL)
+ return -EINVAL;
+
+ data.ioc_version = OBD_IOCTL_VERSION;
+ data.ioc_len = sizeof(data);
+ data.ioc_inlbuf1 = (char *)name;
+ data.ioc_inllen1 = strlen(name) + 1;
+
+ rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
+ if (rc) {
+ llapi_error(LLAPI_MSG_ERROR, rc,
+ "error: IOC_MDC_LOOKUP pack failed for '%s': rc %d",
+ name, rc);
+ return rc;