From: James Simmons Date: Sun, 8 Jun 2025 00:45:44 +0000 (-0400) Subject: LU-11850 obd: support target_obd using Netlink X-Git-Url: https://git.whamcloud.com/?a=commitdiff_plain;h=refs%2Fchanges%2F06%2F58506%2F13;p=fs%2Flustre-release.git LU-11850 obd: support target_obd using Netlink Due to "target_obd" being an debugfs file normal users can't access its contents. This breaks standard tools non-root. Implement the same functionality using Netlink. We don't implement it for lod since its an dt_device which we don't have a way to find such a device like obd_devices. The lod layer is server side so only root should have access. Change-Id: I8fce80f6460b4b3f46106bc24d9494ae94e4fd4b Signed-off-by: James Simmons Reviewed-on: https://review.whamcloud.com/c/fs/lustre-release/+/58506 Tested-by: jenkins Tested-by: Maloo Reviewed-by: Arshad Hussain Reviewed-by: Oleg Drokin Reviewed-by: Shaun Tancheff --- diff --git a/lustre/include/lustre/lustreapi.h b/lustre/include/lustre/lustreapi.h index 6d7d5ba..c8b1934 100644 --- a/lustre/include/lustre/lustreapi.h +++ b/lustre/include/lustre/lustreapi.h @@ -516,6 +516,8 @@ enum tgt_type { LMV_TYPE = 2, CLI_TYPE = 3, }; +int llapi_get_target_uuids(int fd, struct obd_uuid *uuidp, int *indices, + char **status, int *ost_count, enum tgt_type type); int llapi_file_get_type_uuid(const char *path, enum tgt_type type, struct obd_uuid *uuid); int llapi_file_fget_type_uuid(int fd, enum tgt_type type, diff --git a/lustre/include/lustre_kernelcomm.h b/lustre/include/lustre_kernelcomm.h index 6cb594c..ed68b44 100644 --- a/lustre/include/lustre_kernelcomm.h +++ b/lustre/include/lustre_kernelcomm.h @@ -159,6 +159,53 @@ unsigned int lustre_stats_scan(struct lustre_stats_list *slist, const char *filt int lustre_stats_dump(struct sk_buff *msg, struct netlink_callback *cb); int lustre_stats_done(struct netlink_callback *cb); +/** + * enum lustre_target_attrs - Lustre general top-level netlink + * attributes that describe lustre + * 'target_obd'. These values are used + * to piece togther messages for + * sending and receiving. + * + * @LUSTRE_TARGET_ATTR_UNSPEC: unspecified attribute to catch errors + * + * @LUSTRE_TARGET_ATTR_HDR: Netlink group this data is for + * (NLA_NUL_STRING) + * @LUSTRE_TARGET_ATTR_SOURCE: obd device targets belong too + * (NLA_STRING) + * @LUSTRE_TARGET_ATTR_PROP_LIST: list of target properties (NLA_NESTED) + */ +enum lustre_target_attrs { + LUSTRE_TARGET_ATTR_UNSPEC = 0, + + LUSTRE_TARGET_ATTR_HDR, + LUSTRE_TARGET_ATTR_SOURCE, + LUSTRE_TARGET_ATTR_PROP_LIST, + + __LUSTRE_TARGET_ATTR_MAX_PLUS_ONE, +}; + +#define LUSTRE_TARGET_ATTR_MAX (__LUSTRE_TARGET_ATTR_MAX_PLUS_ONE - 1) + +/** + * enum lustre_target_props_attrs + * + * @LUSTRE_TARGET_PROP_ATTR_UNSPEC: unspecified attribute to catch errors + * @LUSTRE_TARGET_PROP_ATTR_INDEX: target number used as an index (NLA_U16) + * @LUSTRE_DEVICE_PROP_ATTR_UUID: UUID of the target (NLA_STRING) + * @LUSTRE_DEVICE_PROP_ATTR_STATUS: status of the target (NLA_STRING) + */ +enum lustre_target_prop_attrs { + LUSTRE_TARGET_PROP_ATTR_UNSPEC = 0, + + LUSTRE_TARGET_PROP_ATTR_INDEX, + LUSTRE_TARGET_PROP_ATTR_UUID, + LUSTRE_TARGET_PROP_ATTR_STATUS, + + __LUSTRE_TARGET_PROP_ATTR_MAX_PLUS_ONE, +}; + +#define LUSTRE_TARGET_PROP_ATTR_MAX (__LUSTRE_TARGET_PROP_ATTR_MAX_PLUS_ONE - 1) + /* prototype for callback function on kuc groups */ typedef int (*libcfs_kkuc_cb_t)(void *data, void *cb_arg); diff --git a/lustre/include/uapi/linux/lustre/lustre_kernelcomm.h b/lustre/include/uapi/linux/lustre/lustre_kernelcomm.h index 1a3a448..4eeb495 100644 --- a/lustre/include/uapi/linux/lustre/lustre_kernelcomm.h +++ b/lustre/include/uapi/linux/lustre/lustre_kernelcomm.h @@ -30,12 +30,14 @@ * @LUSTRE_CMD_UNSPEC: unspecified command to catch errors * * @LUSTRE_CMD_DEVICES: command to manage the Lustre devices + * @LUSTRE_CMD_TARGETS: command to manage the Lustre targets * @LUSTRE_CMD_STATS: Lustre stats collection command */ enum lustre_commands { LUSTRE_CMD_UNSPEC = 0, LUSTRE_CMD_DEVICES = 1, + LUSTRE_CMD_TARGETS = 3, LUSTRE_CMD_STATS = 5, __LUSTRE_CMD_MAX_PLUS_ONE diff --git a/lustre/lmv/lproc_lmv.c b/lustre/lmv/lproc_lmv.c index 013ce6f..ef10056 100644 --- a/lustre/lmv/lproc_lmv.c +++ b/lustre/lmv/lproc_lmv.c @@ -179,7 +179,6 @@ static ssize_t qos_threshold_rr_store(struct kobject *kobj, } LUSTRE_RW_ATTR(qos_threshold_rr); -#ifdef CONFIG_PROC_FS /* directories with exclude prefixes will be created on the same MDT as its * parent directory, the prefixes are set with the rule as shell environment * PATH: ':' is used as separator for prefixes. And for convenience, '+/-' is @@ -323,7 +322,13 @@ static ssize_t qos_exclude_prefixes_seq_write(struct file *file, OBD_FREE(buf, count + 1); return count; } -LPROC_SEQ_FOPS(qos_exclude_prefixes); +LDEBUGFS_SEQ_FOPS(qos_exclude_prefixes); + +static struct ldebugfs_vars ldebugfs_lmv_obd_vars[] = { + { .name = "qos_exclude_prefixes", + .fops = &qos_exclude_prefixes_fops }, + { NULL } +}; static void *lmv_tgt_seq_start(struct seq_file *p, loff_t *pos) { @@ -394,27 +399,18 @@ static int lmv_target_seq_open(struct inode *inode, struct file *file) return rc; seq = file->private_data; - seq->private = pde_data(inode); + seq->private = inode->i_private; return 0; } -static const struct proc_ops lmv_proc_target_fops = { - PROC_OWNER(THIS_MODULE) - .proc_open = lmv_target_seq_open, - .proc_read = seq_read, - .proc_lseek = seq_lseek, - .proc_release = seq_release, +static const struct file_operations lmv_debugfs_target_fops = { + .owner = THIS_MODULE, + .open = lmv_target_seq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, }; -static struct lprocfs_vars lprocfs_lmv_obd_vars[] = { - { .name = "qos_exclude_prefixes", - .fops = &qos_exclude_prefixes_fops }, - { .name = "target_obd", - .fops = &lmv_proc_target_fops }, - { NULL } -}; -#endif /* CONFIG_PROC_FS */ - static struct attribute *lmv_attrs[] = { &lustre_attr_activeobd.attr, &lustre_attr_desc_uuid.attr, @@ -432,9 +428,7 @@ int lmv_tunables_init(struct obd_device *obd) int rc; obd->obd_ktype.default_groups = KOBJ_ATTR_GROUPS(lmv); -#ifdef CONFIG_PROC_FS - obd->obd_vars = lprocfs_lmv_obd_vars; -#endif + obd->obd_debugfs_vars = ldebugfs_lmv_obd_vars; rc = lprocfs_obd_setup(obd, false); if (rc) goto out_failed; @@ -445,6 +439,8 @@ int lmv_tunables_init(struct obd_device *obd) goto out_failed; } #endif /* CONFIG_PROC_FS */ + debugfs_create_file("target_obd", 0444, obd->obd_debugfs_entry, + obd, &lmv_debugfs_target_fops); out_failed: return rc; } diff --git a/lustre/lod/lproc_lod.c b/lustre/lod/lproc_lod.c index ddf8ec1..3c3c793 100644 --- a/lustre/lod/lproc_lod.c +++ b/lustre/lod/lproc_lod.c @@ -987,7 +987,7 @@ static int lod_osts_seq_open(struct inode *inode, struct file *file) return rc; seq = file->private_data; - seq->private = pde_data(inode); + seq->private = inode->i_private; return 0; } @@ -1342,12 +1342,12 @@ struct lprocfs_vars lprocfs_lod_spill_vars[] = { { NULL } }; -static struct proc_ops lod_proc_target_fops = { - PROC_OWNER(THIS_MODULE) - .proc_open = lod_osts_seq_open, - .proc_read = seq_read, - .proc_lseek = seq_lseek, - .proc_release = lprocfs_seq_release, +static const struct file_operations lod_debugfs_target_fops = { + .owner = THIS_MODULE, + .open = lod_osts_seq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, }; static struct attribute *lod_attrs[] = { @@ -1533,14 +1533,6 @@ int lod_procfs_init(struct lod_device *lod) GOTO(out, rc); } - rc = lprocfs_seq_create(obd->obd_proc_entry, "target_obd", - 0444, &lod_proc_target_fops, obd); - if (rc) { - CWARN("%s: Error adding the target_obd file %d\n", - obd->obd_name, rc); - GOTO(out, rc); - } - lod->lod_pool_proc_entry = lprocfs_register("pools", obd->obd_proc_entry, NULL, NULL); @@ -1582,6 +1574,9 @@ int lod_procfs_init(struct lod_device *lod) ldebugfs_add_vars(obd->obd_debugfs_entry, ldebugfs_lod_vars, lod); + debugfs_create_file("target_obd", 0444, obd->obd_debugfs_entry, + obd, &lod_debugfs_target_fops); + lod->lod_debugfs = ldebugfs_add_symlink(obd->obd_name, "lov", "../lod/%s", obd->obd_name); if (!lod->lod_debugfs) diff --git a/lustre/lov/lproc_lov.c b/lustre/lov/lproc_lov.c index 699f8b8..4e3263a 100644 --- a/lustre/lov/lproc_lov.c +++ b/lustre/lov/lproc_lov.c @@ -178,7 +178,6 @@ static ssize_t desc_uuid_show(struct kobject *kobj, struct attribute *attr, } LUSTRE_RO_ATTR(desc_uuid); -#ifdef CONFIG_PROC_FS static void *lov_tgt_seq_start(struct seq_file *p, loff_t *pos) { struct obd_device *obd = p->private; @@ -247,18 +246,17 @@ static int lov_target_seq_open(struct inode *inode, struct file *file) return rc; seq = file->private_data; - seq->private = pde_data(inode); + seq->private = inode->i_private; return 0; } -static const struct proc_ops lov_proc_target_fops = { - PROC_OWNER(THIS_MODULE) - .proc_open = lov_target_seq_open, - .proc_read = seq_read, - .proc_lseek = seq_lseek, - .proc_release = lprocfs_seq_release, +static const struct file_operations lov_debugfs_target_fops = { + .owner = THIS_MODULE, + .open = lov_target_seq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, }; -#endif /* CONFIG_PROC_FS */ static struct attribute *lov_attrs[] = { &lustre_attr_activeobd.attr, @@ -283,13 +281,9 @@ int lov_tunables_init(struct obd_device *obd) if (rc) GOTO(out, rc); + debugfs_create_file("target_obd", 0444, obd->obd_debugfs_entry, + obd, &lov_debugfs_target_fops); #ifdef CONFIG_PROC_FS - rc = lprocfs_seq_create(obd->obd_proc_entry, "target_obd", 0444, - &lov_proc_target_fops, obd); - if (rc) - CWARN("%s: Error adding the target_obd file : rc %d\n", - obd->obd_name, rc); - lov->lov_pool_proc_entry = lprocfs_register("pools", obd->obd_proc_entry, NULL, NULL); diff --git a/lustre/obdclass/kernelcomm.c b/lustre/obdclass/kernelcomm.c index bdb2d4d..27bafab 100644 --- a/lustre/obdclass/kernelcomm.c +++ b/lustre/obdclass/kernelcomm.c @@ -18,6 +18,7 @@ #define DEBUG_SUBSYSTEM S_CLASS +#include #include #include #include @@ -270,6 +271,318 @@ static int lustre_device_done(struct netlink_callback *cb) return 0; } +/* target_obd handling */ +struct lu_tgt_list { + char ltl_src[MAX_OBD_NAME * 4]; + struct lu_tgt_descs *ltl_desc; +}; + +struct genl_tgts_list { + unsigned int gol_index; + unsigned int gol_count; + GENRADIX(struct lu_tgt_list) gol_list; +}; + +static inline struct genl_tgts_list * +target_dump_ctx(struct netlink_callback *cb) +{ + return (struct genl_tgts_list *)cb->args[0]; +} + +static int lustre_targets_done(struct netlink_callback *cb) +{ + struct genl_tgts_list *tlist = target_dump_ctx(cb); + + if (tlist) { + genradix_free(&tlist->gol_list); + LIBCFS_FREE(tlist, sizeof(*tlist)); + cb->args[0] = 0; + } + + return 0; +} + +/* generic ->start() handler for GET requests */ +static int lustre_targets_start(struct netlink_callback *cb) +{ + struct genlmsghdr *gnlh = nlmsg_data(cb->nlh); +#ifdef HAVE_NL_PARSE_WITH_EXT_ACK + struct netlink_ext_ack *extack = NULL; +#endif + int msg_len = genlmsg_len(gnlh); + struct genl_tgts_list *tlist; + unsigned long idx = 0; + int rc = 0; + + LIBCFS_ALLOC(tlist, sizeof(*tlist)); + if (!tlist) { + NL_SET_ERR_MSG(extack, "failed to setup obd list"); + return -ENOMEM; + } + genradix_init(&tlist->gol_list); + tlist->gol_index = 0; + tlist->gol_count = 0; + cb->args[0] = (long)tlist; + + if (msg_len > 0) { + struct nlattr *params = genlmsg_data(gnlh); + struct nlattr *target; + int rem; + + if (!(nla_type(params) & LN_SCALAR_ATTR_LIST)) { + NL_SET_ERR_MSG(extack, "no configuration"); + GOTO(report_err, rc = -EINVAL); + } + + nla_for_each_nested(target, params, rem) { + struct nlattr *prop; + int rem2; + + nla_for_each_nested(prop, target, rem2) { + char name[MAX_OBD_NAME * 4], *filter; + struct obd_device *obd; + char type[5]; + ssize_t len; + + if (nla_type(prop) != LN_SCALAR_ATTR_VALUE || + nla_strcmp(prop, "source") != 0) + continue; + + prop = nla_next(prop, &rem2); + if (nla_type(prop) != LN_SCALAR_ATTR_VALUE) + GOTO(report_err, rc = -EINVAL); + + len = nla_strscpy(name, prop, sizeof(name)); + if (len < 0) + GOTO(report_err, rc = (int)len); + + filter = strim(name); /* remove any whitespaces */ + len = strcspn(filter, ".") + 1; + strscpy(type, name, min_t(size_t, len, sizeof(type))); + + obd_device_lock(); + obd_device_for_each(idx, obd) { + struct lu_tgt_descs *ltd = NULL; + struct lu_tgt_list *ltl; + + /* Only look at specific obds */ + if (strncmp(obd->obd_type->typ_name, + LUSTRE_LMV_NAME, + strlen(LUSTRE_LMV_NAME)) == 0) + ltd = &obd->u.lmv.lmv_mdt_descs; + else if (strncmp(obd->obd_type->typ_name, + LUSTRE_LOV_NAME, + strlen(LUSTRE_LOV_NAME)) == 0) + ltd = &obd->u.lov.lov_ost_descs; + if (!ltd) + continue; + + /* Now filter by obd_type */ + if (!glob_match(type, + obd->obd_type->typ_name)) + continue; + + /* Filter by obd_name */ + if (!glob_match(filter + len, + obd->obd_name)) + continue; + + ltl = genradix_ptr_alloc(&tlist->gol_list, + tlist->gol_count++, + GFP_ATOMIC); + if (!ltl) { + NL_SET_ERR_MSG(extack, + "failed to allocate target desc"); + obd_device_unlock(); + GOTO(report_err, rc = -ENOMEM); + } + scnprintf(ltl->ltl_src, + sizeof(ltl->ltl_src), "%s.%s", + obd->obd_type->typ_name, + obd->obd_name); + ltl->ltl_desc = ltd; + } + obd_device_unlock(); + } + } + if (!tlist->gol_count) + rc = -ENOENT; + } else { + struct obd_device *obd; + + obd_device_lock(); + obd_device_for_each(idx, obd) { + struct lu_tgt_descs *ltd = NULL; + struct lu_tgt_list *ltl; + + if (strcmp(obd->obd_type->typ_name, + LUSTRE_LMV_NAME) == 0) + ltd = &obd->u.lmv.lmv_mdt_descs; + else if (strcmp(obd->obd_type->typ_name, + LUSTRE_LOV_NAME) == 0) + ltd = &obd->u.lov.lov_ost_descs; + if (!ltd) + continue; + + ltl = genradix_ptr_alloc(&tlist->gol_list, + tlist->gol_count++, + GFP_ATOMIC); + if (!ltl) { + NL_SET_ERR_MSG(extack, + "failed to allocate target desc"); + obd_device_unlock(); + GOTO(report_err, rc = -ENOMEM); + } + + ltl->ltl_desc = ltd; + } + obd_device_unlock(); + } +report_err: + if (rc < 0) + lustre_targets_done(cb); + + return rc; +} + +static struct ln_key_list tgt_keys = { + .lkl_maxattr = LUSTRE_TARGET_ATTR_MAX, + .lkl_list = { + [LUSTRE_TARGET_ATTR_HDR] = { + .lkp_value = "target_obd", + .lkp_key_format = LNKF_SEQUENCE | LNKF_MAPPING, + .lkp_data_type = NLA_NUL_STRING, + }, + [LUSTRE_TARGET_ATTR_SOURCE] = { + .lkp_value = "source", + .lkp_data_type = NLA_STRING, + }, + [LUSTRE_TARGET_ATTR_PROP_LIST] = { + .lkp_value = "targets", + .lkp_key_format = LNKF_SEQUENCE | LNKF_MAPPING, + .lkp_data_type = NLA_NESTED, + }, + }, +}; + +static struct ln_key_list tgt_prop_keys = { + .lkl_maxattr = LUSTRE_TARGET_PROP_ATTR_MAX, + .lkl_list = { + [LUSTRE_TARGET_PROP_ATTR_INDEX] = { + .lkp_value = "index", + .lkp_data_type = NLA_U16 + }, + [LUSTRE_TARGET_PROP_ATTR_UUID] = { + .lkp_value = "uuid", + .lkp_data_type = NLA_STRING + }, + [LUSTRE_TARGET_PROP_ATTR_STATUS] = { + .lkp_value = "status", + .lkp_data_type = NLA_STRING + }, + }, +}; + +static int lustre_targets_dump(struct sk_buff *msg, + struct netlink_callback *cb) +{ + struct genl_tgts_list *tlist = target_dump_ctx(cb); + struct genlmsghdr *gnlh = nlmsg_data(cb->nlh); +#ifdef HAVE_NL_PARSE_WITH_EXT_ACK + struct netlink_ext_ack *extack = NULL; +#endif + int portid = NETLINK_CB(cb->skb).portid; + int seq = cb->nlh->nlmsg_seq; + int idx = tlist->gol_index; + int rc = 0; + +#ifdef HAVE_NL_DUMP_WITH_EXT_ACK + extack = cb->extack; +#endif + if (!idx) { + const struct ln_key_list *all[] = { + &tgt_keys, &tgt_prop_keys, NULL + }; + + rc = lnet_genl_send_scalar_list(msg, portid, seq, + &lustre_family, + NLM_F_CREATE | NLM_F_MULTI, + LUSTRE_CMD_TARGETS, all); + if (rc < 0) { + NL_SET_ERR_MSG(extack, "failed to send key table"); + GOTO(send_error, rc); + } + rc = 0; + } + + while (idx < tlist->gol_count) { + struct lu_tgt_list *ltl; + struct lu_tgt_desc *tgt; + struct nlattr *tgt_list; + int j = 1; + void *hdr; + + ltl = genradix_ptr(&tlist->gol_list, idx++); + if (!ltl) + continue; + + hdr = genlmsg_put(msg, portid, seq, &lustre_family, + NLM_F_MULTI, LUSTRE_CMD_TARGETS); + if (!hdr) { + NL_SET_ERR_MSG(extack, "failed to send values"); + genlmsg_cancel(msg, hdr); + GOTO(send_error, rc = -EMSGSIZE); + } + + if (idx == 1) + nla_put_string(msg, LUSTRE_TARGET_ATTR_HDR, ""); + + nla_put_string(msg, LUSTRE_TARGET_ATTR_SOURCE, + ltl->ltl_src); + + /* We just want the source */ + if (!gnlh->version) + goto skip_details; + + tgt_list = nla_nest_start(msg, LUSTRE_TARGET_ATTR_PROP_LIST); + ltd_foreach_tgt(ltl->ltl_desc, tgt) { + struct nlattr *tgt_attr; + + tgt_attr = nla_nest_start(msg, j++); + nla_put_u16(msg, LUSTRE_TARGET_PROP_ATTR_INDEX, tgt->ltd_index); + + nla_put_string(msg, LUSTRE_TARGET_PROP_ATTR_STATUS, + tgt->ltd_active ? "ACTIVE" : "INACTIVE"); + + nla_put_string(msg, LUSTRE_TARGET_PROP_ATTR_UUID, + obd_uuid2str(&tgt->ltd_uuid)); + nla_nest_end(msg, tgt_attr); + } + nla_nest_end(msg, tgt_list); +skip_details: + genlmsg_end(msg, hdr); + } + + tlist->gol_index = idx; +send_error: + return lnet_nl_send_error(cb->skb, portid, seq, rc); +} + +#ifndef HAVE_NETLINK_CALLBACK_START +int lustre_old_targets_dump(struct sk_buff *msg, + struct netlink_callback *cb) +{ + if (!cb->args[0]) { + int rc = lustre_targets_start(cb); + + if (rc < 0) + return rc; + } + + return lustre_targets_dump(msg, cb); +} +#endif + static struct ln_key_list stats_params = { .lkl_maxattr = LUSTRE_PARAM_ATTR_MAX, .lkl_list = { @@ -801,6 +1114,7 @@ report_err: static const struct genl_multicast_group lustre_mcast_grps[] = { { .name = "devices", }, + { .name = "target_obd", }, { .name = "stats", }, }; @@ -816,6 +1130,16 @@ static const struct genl_ops lustre_genl_ops[] = { .done = lustre_device_done, }, { + .cmd = LUSTRE_CMD_TARGETS, +#ifdef HAVE_NETLINK_CALLBACK_START + .start = lustre_targets_start, + .dumpit = lustre_targets_dump, +#else + .dumpit = lustre_old_targets_dump, +#endif + .done = lustre_targets_done, + }, + { .cmd = LUSTRE_CMD_STATS, #ifdef HAVE_NETLINK_CALLBACK_START .start = lustre_stats_start, diff --git a/lustre/utils/liblustreapi.c b/lustre/utils/liblustreapi.c index 2685944..fd55190 100644 --- a/lustre/utils/liblustreapi.c +++ b/lustre/utils/liblustreapi.c @@ -1501,8 +1501,6 @@ err: return rc; } -#define OBD_NOT_FOUND (-1) - static bool lmv_is_foreign(__u32 magic) { return magic == LMV_MAGIC_FOREIGN; @@ -2287,76 +2285,6 @@ int llapi_file_get_type_uuid(const char *path, enum tgt_type type, return rc; } -/* - * If uuidp is NULL, return the number of available obd uuids. - * If uuidp is non-NULL, then it will return the uuids of the obds. If - * there are more OSTs than allocated to uuidp, then an error is returned with - * the ost_count set to number of available obd uuids. - */ -static int llapi_get_target_uuids(int fd, struct obd_uuid *uuidp, int *indices, - int *ost_count, enum tgt_type type) -{ - char buf[PATH_MAX], format[32]; - int i, rc = 0; - struct obd_uuid name; - glob_t param; - FILE *fp; - - /* Get the lov name */ - rc = llapi_file_fget_type_uuid(fd, type, &name); - if (rc != 0) - return rc; - - /* Now get the ost uuids */ - rc = get_lustre_param_path(type == LOV_TYPE ? "lov" : "lmv", name.uuid, - FILTER_BY_EXACT, "target_obd", ¶m); - if (rc != 0) - return -ENOENT; - - fp = fopen(param.gl_pathv[0], "r"); - if (fp == NULL) { - rc = -errno; - llapi_error(LLAPI_MSG_ERROR, rc, "error: opening '%s'", - param.gl_pathv[0]); - goto free_param; - } - - snprintf(format, sizeof(format), - "%%d: %%%zus", sizeof(uuidp[0].uuid) - 1); - for (i = 0; fgets(buf, sizeof(buf), fp); i++) { - int index; - - if (sscanf(buf, format, &index, name.uuid) < 2) - break; - - if (i < *ost_count) { - if (uuidp != NULL) - uuidp[i] = name; - if (indices != NULL) - indices[i] = index; - } - } - fclose(fp); - - if (uuidp && (i > *ost_count)) - rc = -EOVERFLOW; - - *ost_count = i; -free_param: - cfs_free_param_data(¶m); - return rc; -} - -int llapi_lmv_get_uuids(int fd, struct obd_uuid *uuidp, int *mdt_count) -{ - return llapi_get_target_uuids(fd, uuidp, NULL, mdt_count, LMV_TYPE); -} - -int llapi_lov_get_uuids(int fd, struct obd_uuid *uuidp, int *ost_count) -{ - return llapi_get_target_uuids(fd, uuidp, NULL, ost_count, LOV_TYPE); -} - int llapi_get_obd_count(char *mnt, int *count, int is_mdt) { int root; @@ -2405,92 +2333,6 @@ int llapi_uuid_match(char *real_uuid, char *search_uuid) } /* - * Here, param->fp_obd_uuid points to a single obduuid, the index of which is - * returned in param->fp_obd_index - */ -static int setup_obd_uuid(int fd, char *dname, struct find_param *param) -{ - struct obd_uuid obd_uuid; - char buf[PATH_MAX]; - glob_t param_data; - char format[32]; - int rc = 0; - FILE *fp; - enum tgt_type type = param->fp_get_lmv ? LMV_TYPE : LOV_TYPE; - - if (param->fp_got_uuids) - return rc; - - /* Get the lov/lmv name */ - rc = llapi_file_fget_type_uuid(fd, type, &obd_uuid); - if (rc) { - if (rc != -ENOTTY) { - llapi_error(LLAPI_MSG_ERROR, rc, - "error: can't get %s name: %s", - param->fp_get_lmv ? "lmv" : "lov", - dname); - } else { - rc = 0; - } - return rc; - } - - param->fp_got_uuids = 1; - - /* Now get the ost uuids */ - rc = get_lustre_param_path(param->fp_get_lmv ? "lmv" : "lov", - obd_uuid.uuid, FILTER_BY_EXACT, - "target_obd", ¶m_data); - if (rc != 0) - return -ENOENT; - - fp = fopen(param_data.gl_pathv[0], "r"); - if (fp == NULL) { - rc = -errno; - llapi_error(LLAPI_MSG_ERROR, rc, "error: opening '%s'", - param_data.gl_pathv[0]); - goto free_param; - } - - if (!param->fp_obd_uuid && !param->fp_quiet && !param->fp_obds_printed) - llapi_printf(LLAPI_MSG_NORMAL, "%s:\n", - param->fp_get_lmv ? "MDTS" : "OBDS"); - - snprintf(format, sizeof(format), - "%%d: %%%zus", sizeof(obd_uuid.uuid) - 1); - while (fgets(buf, sizeof(buf), fp) != NULL) { - int index; - - if (sscanf(buf, format, &index, obd_uuid.uuid) < 2) - break; - - if (param->fp_obd_uuid) { - if (llapi_uuid_match(obd_uuid.uuid, - param->fp_obd_uuid->uuid)) { - param->fp_obd_index = index; - break; - } - } else if (!param->fp_quiet && !param->fp_obds_printed) { - /* Print everything */ - llapi_printf(LLAPI_MSG_NORMAL, "%s", buf); - } - } - param->fp_obds_printed = 1; - - fclose(fp); - - if (param->fp_obd_uuid && (param->fp_obd_index == OBD_NOT_FOUND)) { - llapi_err_noerrno(LLAPI_MSG_ERROR, - "error: %s: unknown obduuid: %s", - __func__, param->fp_obd_uuid->uuid); - rc = -EINVAL; - } -free_param: - cfs_free_param_data(¶m_data); - return rc; -} - -/* * In this case, param->fp_obd_uuid will be an array of obduuids and * obd index for all these obduuids will be returned in * param->fp_obd_indexes @@ -2521,7 +2363,7 @@ static int setup_indexes(int d, char *path, struct obd_uuid *obduuids, } retry_get_uuids: - ret = llapi_get_target_uuids(d, uuids, indices, &obdcount, type); + ret = llapi_get_target_uuids(d, uuids, indices, NULL, &obdcount, type); if (ret) { if (ret == -EOVERFLOW) { struct obd_uuid *uuids_temp; @@ -2623,21 +2465,6 @@ static int setup_target_indexes(int d, char *path, struct find_param *param) return ret; } -int llapi_ostlist(char *path, struct find_param *param) -{ - int fd; - int ret; - - fd = open(path, O_RDONLY | O_DIRECTORY); - if (fd < 0) - return -errno; - - ret = setup_obd_uuid(fd, path, param); - close(fd); - - return ret; -} - /* * Tries to determine the default stripe attributes for a given filesystem. The * filesystem to check should be specified by fsname, or will be determined @@ -6889,7 +6716,7 @@ static int cb_getstripe(char *path, int p, int *dp, void *data, if (param->fp_obd_uuid) { param->fp_quiet = 1; - ret = setup_obd_uuid(d != -1 ? d : p, path, param); + ret = llapi_ostlist(path, param); if (ret) return ret; } diff --git a/lustre/utils/liblustreapi_param.c b/lustre/utils/liblustreapi_param.c index d13fb79..92870d9 100644 --- a/lustre/utils/liblustreapi_param.c +++ b/lustre/utils/liblustreapi_param.c @@ -498,6 +498,86 @@ static int print_out_devices(yaml_parser_t *reply, enum lctl_param_flags flags) return rc; } +static int print_out_targets(yaml_parser_t *reply, int version, int flags) +{ + char buf[PATH_MAX / 2], *tmp = NULL; + size_t buf_len = sizeof(buf); + yaml_event_t event; + bool done = false; + int rc; + + while (!done) { + rc = yaml_parser_parse(reply, &event); + if (rc == 0) + break; + + if (event.type == YAML_SCALAR_EVENT) { + char *value = (char *)event.data.scalar.value; + + if (strcmp(value, "source") == 0) { + rc = yaml_parser_parse(reply, &event); + if (rc == 0) + break; + + if (event.type != YAML_SCALAR_EVENT) + return -EINVAL; + + value = (char *)event.data.scalar.value; + + if (!version) { + fprintf(stdout, "%s.target_obd\n", + value); + } else if (flags & PARAM_FLAGS_SHOW_SOURCE) { + fprintf(stdout, "%s.target_obd=\n", + value); + } + } else if (strcmp(value, "index") == 0 && version) { + memset(buf, 0, buf_len); + tmp = buf; + + rc = yaml_parser_parse(reply, &event); + if (rc == 0) + break; + + if (event.type != YAML_SCALAR_EVENT) + return -EINVAL; + + value = (char *)event.data.scalar.value; + snprintf(tmp, buf_len, "%s: ", value); + tmp += strlen(value) + 2; + buf_len -= strlen(value) + 2; + } else if (strcmp(value, "uuid") == 0 && version) { + rc = yaml_parser_parse(reply, &event); + if (rc == 0) + break; + + if (event.type != YAML_SCALAR_EVENT || + !tmp) + return -EINVAL; + + value = (char *)event.data.scalar.value; + snprintf(tmp, buf_len, "%s", value); + tmp += strlen(value) + 2; + buf_len -= strlen(value) + 2; + } else if (strcmp(value, "status") == 0 && version) { + rc = yaml_parser_parse(reply, &event); + if (rc == 0) + break; + + if (event.type != YAML_SCALAR_EVENT) + return -EINVAL; + + value = (char *)event.data.scalar.value; + fprintf(stdout, "%s %s\n", buf, value); + } + } + + done = (event.type == YAML_DOCUMENT_END_EVENT); + yaml_event_delete(&event); + } + return rc == 1 ? 0 : -EINVAL; +} + static int print_out_stats(yaml_parser_t *reply, int version, int flags) { bool show_path = flags & PARAM_FLAGS_SHOW_SOURCE; @@ -655,6 +735,8 @@ static int lcfg_param_get_yaml(yaml_parser_t *reply, struct nl_sock *sk, if (strcmp(group, "devices") == 0) cmd = LUSTRE_CMD_DEVICES; + else if (strcmp(group, "target_obd") == 0) + cmd = LUSTRE_CMD_TARGETS; else if (strcmp(group, "stats") == 0) cmd = LUSTRE_CMD_STATS; @@ -838,6 +920,9 @@ int llapi_param_display_value(char *path, int version, if (strcmp(value, "devices") == 0) rc = print_out_devices(&reply, flags); + else if (strcmp(value, "target_obd") == 0) + rc = print_out_targets(&reply, version, + flags); else if (strcmp(value, "stats") == 0) rc = print_out_stats(&reply, version, flags); @@ -900,6 +985,255 @@ free_reply: return rc == 1 ? 0 : rc; } +/* + * If uuidp is NULL, return the number of available obd uuids. + * If uuidp is non-NULL, then it will return the uuids of the obds. If + * there are more OSTs than allocated to uuidp, then an error is returned with + * the ost_count set to number of available obd uuids. + */ +int llapi_get_target_uuids(int fd, struct obd_uuid *uuidp, int *indices, + char **status, int *ost_count, enum tgt_type type) +{ + struct obd_uuid name; + char buf[PATH_MAX]; + int rc = 0, i = 0; + glob_t param; + FILE *fp; + + /* Get the lov / lmv name */ + rc = llapi_file_fget_type_uuid(fd, type, &name); + if (rc != 0) + return rc; + + /* Now get the ost uuids */ + rc = get_lustre_param_path(type == LOV_TYPE ? "lov" : "lmv", name.uuid, + FILTER_BY_EXACT, "target_obd", ¶m); + if (rc != 0) { + yaml_parser_t reply; + yaml_event_t event; + struct nl_sock *sk; + bool done = false; + + sk = nl_socket_alloc(); + if (!sk) + return -ENOMEM; + + snprintf(buf, sizeof(buf), "%s.%s.target_obd", + type == LOV_TYPE ? "lov" : "lmv", name.uuid); + + rc = lcfg_param_get_yaml(&reply, sk, LUSTRE_GENL_VERSION, + NLM_F_DUMP, buf); + if (rc < 0) { + if (rc == -EOPNOTSUPP) + goto old_api; + return rc; + } + + while (!done) { + rc = yaml_parser_parse(&reply, &event); + if (rc == 0) + break; + + if ((!*ost_count || i < *ost_count) && + event.type == YAML_SCALAR_EVENT) { + char *value = (char *)event.data.scalar.value; + + if (strcmp(value, "index") == 0) { + if (indices != NULL) { + yaml_event_delete(&event); + rc = yaml_parser_parse(&reply, + &event); + if (rc == 0) + break; + + value = (char *)event.data.scalar.value; + indices[i] = strtoul(value, NULL, 10); + if (indices[i] == ULONG_MAX) + break; + } + } + + if (strcmp(value, "uuid") == 0) { + if (uuidp != NULL) { + yaml_event_delete(&event); + rc = yaml_parser_parse(&reply, + &event); + if (rc == 0) + break; + + strcpy(uuidp[i].uuid, + (char *)event.data.scalar.value); + } + } + + if (strcmp(value, "status") == 0) { + if (status != NULL) { + yaml_event_delete(&event); + rc = yaml_parser_parse(&reply, + &event); + if (rc == 0) + break; + + value = (char *)event.data.scalar.value; + status[i] = strdup(value); + } + i++; /* status is last */ + } + } + + done = (event.type == YAML_STREAM_END_EVENT); + yaml_event_delete(&event); + } + + if (rc == 0) { + yaml_parser_log_error(&reply, stderr, "llapi_get_target_uuids: "); + rc = -EINVAL; + } + + if (indices && indices[i] == ULONG_MAX) + rc = -ERANGE; + + if (uuidp && (i > *ost_count)) + rc = -EOVERFLOW; + + if (status && (i > *ost_count)) + rc = -EOVERFLOW; + + *ost_count = i; + + return rc == 1 ? 0 : rc; + } +old_api: + fp = fopen(param.gl_pathv[0], "r"); + if (fp == NULL) { + rc = -errno; + llapi_error(LLAPI_MSG_ERROR, rc, "error: opening '%s'", + param.gl_pathv[0]); + goto free_param; + } + + for (i = 0; fgets(buf, sizeof(buf), fp); i++) { + char state[10]; + int index; + + if (sscanf(buf, "%d: %s %s", &index, name.uuid, state) < 3) + break; + + if (i < *ost_count) { + if (uuidp != NULL) + uuidp[i] = name; + if (indices != NULL) + indices[i] = index; + if (status != NULL) + status[i] = strdup(state); + } + } + + if (uuidp && (i > *ost_count)) + rc = -EOVERFLOW; + + if (status && (i > *ost_count)) + rc = -EOVERFLOW; + + *ost_count = i; +free_param: + cfs_free_param_data(¶m); + return rc; +} + +int llapi_lmv_get_uuids(int fd, struct obd_uuid *uuidp, int *mdt_count) +{ + return llapi_get_target_uuids(fd, uuidp, NULL, NULL, mdt_count, LMV_TYPE); +} + +int llapi_lov_get_uuids(int fd, struct obd_uuid *uuidp, int *ost_count) +{ + return llapi_get_target_uuids(fd, uuidp, NULL, NULL, ost_count, LOV_TYPE); +} + +int llapi_ostlist(char *path, struct find_param *param) +{ + struct obd_uuid *uuidp; + int *indices, fd; + char **status; + int obdcount; + int i, rc; + + if (param->fp_got_uuids) + return 0; + + rc = llapi_get_obd_count(path, &obdcount, param->fp_get_lmv); + if (rc < 0) + return rc; + + uuidp = calloc(obdcount, sizeof(*uuidp)); + if (uuidp == NULL) + return -ENOMEM; + + indices = calloc(obdcount, sizeof(*indices)); + if (indices == NULL) { + rc = -ENOMEM; + goto out_uuidp; + } + + status = calloc(obdcount, sizeof(*status)); + if (status == NULL) { + rc = -ENOMEM; + goto out_indices; + } + + fd = open(path, O_RDONLY); + if (fd < 0) { + rc = -errno; + goto out_status; + } + + rc = llapi_get_target_uuids(fd, uuidp, indices, status, &obdcount, + param->fp_get_lmv ? LMV_TYPE : LOV_TYPE); + if (rc < 0) { + close(fd); + goto out_status; + } + + param->fp_got_uuids = 1; + + if (!param->fp_obd_uuid && !param->fp_quiet && !param->fp_obds_printed) + llapi_printf(LLAPI_MSG_NORMAL, "%s:\n", + param->fp_get_lmv ? "MDTS" : "OBDS"); + + for (i = 0; i < obdcount; i++) { + if (param->fp_obd_uuid) { + if (llapi_uuid_match(uuidp[i].uuid, + param->fp_obd_uuid->uuid)) { + param->fp_obd_index = indices[i]; + break; + } + } else if (!param->fp_quiet && !param->fp_obds_printed) { + /* Print everything */ + llapi_printf(LLAPI_MSG_NORMAL, "%d: %s %s\n", + indices[i], uuidp[i].uuid, status[i]); + } + } + param->fp_obds_printed = 1; + + if (param->fp_obd_uuid && (param->fp_obd_index == OBD_NOT_FOUND)) { + llapi_err_noerrno(LLAPI_MSG_ERROR, + "error: %s: unknown obduuid: %s", + __func__, param->fp_obd_uuid->uuid); + rc = -EINVAL; + } + + close(fd); +out_status: + free(status); +out_indices: + free(indices); +out_uuidp: + free(uuidp); + + return rc; +} + /** * Read the value of the file with location \a path * into a buffer. diff --git a/lustre/utils/lustre_param.c b/lustre/utils/lustre_param.c index 926a156..f813349 100644 --- a/lustre/utils/lustre_param.c +++ b/lustre/utils/lustre_param.c @@ -1118,10 +1118,11 @@ int jt_lcfg_listparam(int argc, char **argv) if (rc == 0) rc = rc2; - if (rc2 == -ENOENT && getuid() != 0) + if (rc2 == -ENOENT && getuid() != 0) { rc2 = llapi_param_display_value(path, 0, PARAM_FLAGS_SHOW_SOURCE, stdout); + } if (rc2 < 0) { fprintf(stderr, "error: %s: listing '%s': %s\n", jt_cmdname(argv[0]), path, diff --git a/lustre/utils/lustreapi_internal.h b/lustre/utils/lustreapi_internal.h index e81d7f6..163d129 100644 --- a/lustre/utils/lustreapi_internal.h +++ b/lustre/utils/lustreapi_internal.h @@ -62,6 +62,8 @@ #define LUSTRE_ENCRYPTION_UNIT_SIZE ((size_t)1 << LUSTRE_ENCRYPTION_BLOCKBITS) #define LUSTRE_ENCRYPTION_MASK (~(LUSTRE_ENCRYPTION_UNIT_SIZE - 1)) +#define OBD_NOT_FOUND (-1) + /* mount point listings in /proc/mounts */ #ifndef PROC_MOUNTS #define PROC_MOUNTS "/proc/mounts"