+struct llog_pool_name {
+ char lpn_name[UUID_MAX];
+ struct list_head lpn_list;
+};
+
+struct llog_pool_list_data {
+ char lpld_fsname[LUSTRE_MAXFSNAME + 1];
+ char lpld_poolname[LOV_MAXPOOLNAME + 1];
+ bool lpld_exists;
+ struct list_head lpld_list_head;
+};
+
+/**
+ * Callback to list pool information in llog
+ * - { index: 74, event: new_pool, device: tfs-clilov, fsname: tfs, pool: tmp }
+ * - { index: 77, event: add_pool, device: tfs-clilov, fsname: tfs, pool: tmp,
+ * ost: tfs-OST0000_UUID }
+ * - { index: 224, event: remove_pool, device: tfs-clilov, fsname: tfs,
+ * pool: tmp, ost: tfs-OST0003_UUID }
+ * - { index: 227, event: del_pool, device: tfs-clilov, fsname: tfs, pool: tmp }
+ *
+ * \param record[in] pointer to llog record
+ * \param data[in] pointer to struct llog_pool_list_data
+ *
+ * \retval 0 on success
+ * <0 on error
+ */
+static int llog_poollist_cb(const char *record, void *data)
+{
+ struct llog_pool_list_data *lpld = data;
+ char pool_filter[MAX_STRING_SIZE] = "";
+ char *new_record, *del_record, *del_pool, *found;
+ char type[10] = "";
+ int filter_len, rc = 0;
+
+ filter_len = snprintf(pool_filter, sizeof(pool_filter), " fsname: %s,",
+ lpld->lpld_fsname);
+ if (lpld->lpld_poolname[0] == '\0') {
+ new_record = get_event_filter(LCFG_POOL_NEW);
+ del_record = get_event_filter(LCFG_POOL_DEL);
+ strncpy(type, " pool: ", sizeof(type));
+ } else {
+ filter_len += snprintf(pool_filter + filter_len,
+ sizeof(pool_filter) - filter_len,
+ " pool: %s", lpld->lpld_poolname);
+ new_record = get_event_filter(LCFG_POOL_ADD);
+ del_record = get_event_filter(LCFG_POOL_REM);
+ strncpy(type, " ost: ", sizeof(type));
+ }
+ del_pool = get_event_filter(LCFG_POOL_DEL);
+
+ if (!new_record || !del_record || !del_pool) {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ found = strstr(record, pool_filter);
+ if (found &&
+ (found[filter_len] == ' ' || found[filter_len] == ',')) {
+ struct llog_pool_name *tmp = NULL;
+ struct list_head *head = &lpld->lpld_list_head;
+ char *name;
+ int name_len, type_len = strlen(type);
+
+ lpld->lpld_exists = true;
+ if (strstr(record, new_record)) {
+ name = strstr(record, type);
+ /* 2 bytes for " }" */
+ name_len = strlen(name) - type_len - 2;
+ if (name_len <= 0 || name_len > sizeof(tmp->lpn_name))
+ return -EINVAL;
+ tmp = malloc(sizeof(struct llog_pool_name));
+ if (tmp == NULL) {
+ rc = -ENOMEM;
+ goto out;
+ }
+ memset(tmp, 0, sizeof(struct llog_pool_name));
+ strncpy(tmp->lpn_name, name + type_len, name_len);
+ list_add_tail(&tmp->lpn_list, &lpld->lpld_list_head);
+ } else if (strstr(record, del_record)) {
+ name = strstr(record, type);
+ name_len = strlen(name) - type_len - 2;
+ list_for_each_entry(tmp, head, lpn_list) {
+ if (strncmp(tmp->lpn_name, name + type_len,
+ name_len) == 0 &&
+ tmp->lpn_name[name_len] == '\0') {
+ list_del(&tmp->lpn_list);
+ free(tmp);
+ break;
+ }
+ }
+ }
+ /* verify if the specified pool still exists */
+ if (lpld->lpld_poolname[0] && strstr(record, del_pool))
+ lpld->lpld_exists = false;
+ }
+out:
+ if (new_record)
+ free(new_record);
+ if (del_record)
+ free(del_record);
+ if (del_pool)
+ free(del_pool);
+
+ return rc;
+}
+
+/**
+ * List pool information by config log
+ *
+ * \param fsname[in] pointer to filesystem name
+ * \param poolname[in] pointer to pool name
+ *
+ * \retval 0 on success
+ * < 0 on error
+ */
+int llog_poollist(char *fsname, char *poolname)
+{
+ char logname[MAX_OBD_NAME] = {'\0'};
+ struct llog_pool_list_data lpld;
+ struct llog_pool_name *tmp;
+ struct list_head *head;
+ int rc = 0;
+
+ if (fsname && fsname[0] == '\0')
+ fsname = NULL;
+ if (!fsname)
+ return -EINVAL;
+
+ memset(&lpld, 0, sizeof(lpld));
+ INIT_LIST_HEAD(&lpld.lpld_list_head);
+ lpld.lpld_exists = false;
+ strncpy(lpld.lpld_fsname, fsname, sizeof(lpld.lpld_fsname) - 1);
+ if (poolname && poolname[0])
+ strncpy(lpld.lpld_poolname, poolname,
+ sizeof(lpld.lpld_poolname) - 1);
+ snprintf(logname, sizeof(logname), "%s-client", fsname);
+ rc = jt_llog_print_iter(logname, 0, -1, llog_poollist_cb, &lpld, false);
+
+ if (poolname && poolname[0])
+ printf("Pool: %s.%s\n", fsname, poolname);
+ else
+ printf("Pools from %s:\n", fsname);
+
+ head = &lpld.lpld_list_head;
+ if (poolname && poolname[0] && !lpld.lpld_exists && list_empty(head))
+ return -ENOENT;
+
+ list_for_each_entry(tmp, head, lpn_list) {
+ if (poolname && poolname[0])
+ printf("%s\n", tmp->lpn_name);
+ else
+ printf("%s.%s\n", fsname, tmp->lpn_name);
+ list_del(&tmp->lpn_list);
+ free(tmp);
+ }
+
+ return rc;
+}
+
+static bool get_pools_path(char *fsname)
+{
+ glob_t path;
+ int rc;
+
+ rc = cfs_get_param_paths(&path, "lov/%s-*/pools", fsname);
+ if (!rc)
+ cfs_free_param_data(&path);
+
+ return (rc == 0);
+}
+
+static int extract_fsname_poolname(char **argv, char *fsname,