Whamcloud - gitweb
LU-11850 obd: support target_obd using Netlink 06/58506/13
authorJames Simmons <jsimmons@infradead.org>
Sun, 8 Jun 2025 00:45:44 +0000 (20:45 -0400)
committerOleg Drokin <green@whamcloud.com>
Thu, 3 Jul 2025 13:19:50 +0000 (13:19 +0000)
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 <jsimmons@infradead.org>
Reviewed-on: https://review.whamcloud.com/c/fs/lustre-release/+/58506
Tested-by: jenkins <devops@whamcloud.com>
Tested-by: Maloo <maloo@whamcloud.com>
Reviewed-by: Arshad Hussain <arshad.hussain@aeoncomputing.com>
Reviewed-by: Oleg Drokin <green@whamcloud.com>
Reviewed-by: Shaun Tancheff <shaun.tancheff@hpe.com>
lustre/include/lustre/lustreapi.h
lustre/include/lustre_kernelcomm.h
lustre/include/uapi/linux/lustre/lustre_kernelcomm.h
lustre/lmv/lproc_lmv.c
lustre/lod/lproc_lod.c
lustre/lov/lproc_lov.c
lustre/obdclass/kernelcomm.c
lustre/utils/liblustreapi.c
lustre/utils/liblustreapi_param.c
lustre/utils/lustre_param.c
lustre/utils/lustreapi_internal.h

index 6d7d5ba..c8b1934 100644 (file)
@@ -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,
index 6cb594c..ed68b44 100644 (file)
@@ -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);
 
index 1a3a448..4eeb495 100644 (file)
  * @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
index 013ce6f..ef10056 100644 (file)
@@ -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;
 }
index ddf8ec1..3c3c793 100644 (file)
@@ -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)
index 699f8b8..4e3263a 100644 (file)
@@ -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);
index bdb2d4d..27bafab 100644 (file)
@@ -18,6 +18,7 @@
 
 #define DEBUG_SUBSYSTEM S_CLASS
 
+#include <lustre_compat/linux/generic-radix-tree.h>
 #include <linux/file.h>
 #include <lustre_compat/linux/glob.h>
 #include <linux/types.h>
@@ -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,
index 2685944..fd55190 100644 (file)
@@ -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", &param);
-       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(&param);
-       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", &param_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(&param_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;
        }
index d13fb79..92870d9 100644 (file)
@@ -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", &param);
+       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(&param);
+       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.
index 926a156..f813349 100644 (file)
@@ -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,
index e81d7f6..163d129 100644 (file)
@@ -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"