This is quite similar to 'pci_walk_bus.' We walk the
XenStore keys, starting at the initial path, calling the
callback with each key that has a value. If the callback
returns a negative value we stop, clean up, and return the
value back.
Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@xxxxxxxxxx>
---
drivers/xen/xenbus/xenbus_xs.c | 130 ++++++++++++++++++++++++++++++++++++++++
include/xen/xenbus.h | 2 +
2 files changed, 132 insertions(+), 0 deletions(-)
diff --git a/drivers/xen/xenbus/xenbus_xs.c b/drivers/xen/xenbus/xenbus_xs.c
index eab33f1..6a03d22 100644
--- a/drivers/xen/xenbus/xenbus_xs.c
+++ b/drivers/xen/xenbus/xenbus_xs.c
@@ -67,6 +67,13 @@ struct xs_stored_msg {
} u;
};
+/* Temporary structure used by xenbus_walk to collect all of the
+ * paths in a stack for traversing. */
+struct xs_data_tuple {
+ struct list_head list;
+ char *path;
+};
+
struct xs_handle {
/* A list of replies. Currently only one will ever be outstanding. */
struct list_head reply_list;
@@ -111,6 +118,35 @@ static pid_t xenwatch_pid;
static DEFINE_MUTEX(xenwatch_mutex);
static DECLARE_WAIT_QUEUE_HEAD(watch_events_waitq);
+static struct xs_data_tuple *add_tuple(struct list_head *list, char *path)
+{
+ struct xs_data_tuple *data;
+
+ data = kzalloc(sizeof(struct xs_data_tuple), GFP_KERNEL);
+ if (!data) {
+ printk(KERN_ERR "%s: could not allocate memory\n", __func__);
+ return NULL;
+ }
+
+ data->path = path;
+ list_add_tail(&data->list, list);
+
+ return data;
+}
+
+static int free_tuple(struct xs_data_tuple *data)
+{
+
+ if (!data)
+ return 0;
+
+ kfree(data->path);
+
+ kfree(data);
+ return 0;
+}
+
+
static int get_error(const char *errorstring)
{
unsigned int i;
@@ -367,6 +403,100 @@ void *xenbus_read(struct xenbus_transaction t,
}
EXPORT_SYMBOL_GPL(xenbus_read);
+
+/*
+ * A traverse of XenStore directory using a stack based
+ * implementation. For each file the callback function
+ * is called with:
+ * cb(path, filename, value, userdata);
+ *
+ * Zero return value continues the walk, while any other
+ * exits and returns the value. The value passed in the callback
+ * are automatically free-d.
+ *
+ */
+int xenbus_walk(char *start_path,
+ int (*cb)(char *, char *, char *, void *),
+ void *userdata)
+{
+
+ struct list_head list;
+ struct xs_data_tuple *tuple, *tmp;
+ char **dir;
+ char *newpath, *val;
+ unsigned int i, dir_n;
+ int rc = 0;
+
+ if (!cb)
+ return -ENONET;
+
+ if (!xenstored_ready)
+ return -EBUSY;
+
+ INIT_LIST_HEAD(&list);
+
+ /* Item added to the top. */
+ newpath = kasprintf(GFP_KERNEL, "%s", start_path);
+ if (!add_tuple(&list, newpath))
+ goto err_start;
+
+ tuple = list_entry(&list, struct xs_data_tuple, list);
+ while (!list_empty(&list) && !rc) {
+ /* Pop first element. */
+ tuple = list_entry(list.next, struct xs_data_tuple, list);
+ if (!tuple)
+ goto err_while;
+ list_del(&tuple->list);
+ /* And start listening 'em. */
+ dir = xenbus_directory(XBT_NIL, tuple->path, "", &dir_n);
+ if (IS_ERR(dir)) {
+ /* This will happen on XenStore directories we don't
+ * have access to. (Like for other domains).*/
+ free_tuple(tuple);
+ continue;
+ }
+ for (i = 0; i < dir_n; i++) {
+ if (tuple->path &&
+ tuple->path[strlen(tuple->path)-1] != '/') {
+ val = xenbus_read(XBT_NIL, tuple->path, dir[i],
+ NULL);
+ if (!IS_ERR(val)) {
+ /* Same thing as with xenbus_directory.
+ * Some values are protected.*/
+ rc = cb(tuple->path, dir[i],
+ val, userdata);
+ kfree(val);
+ }
+ }
+ if (rc)
+ break;
+ newpath = kasprintf(GFP_KERNEL, "%s%s%s", tuple->path,
+ tuple->path[strlen(tuple->path)-1] ==
+ '/' ? "" : "/",
+ dir[i]);
+
+ if (!newpath)
+ goto err_loop;
+ if (!add_tuple(&list, newpath))
+ goto err_loop;
+ }
+ kfree(dir);
+ free_tuple(tuple);
+ }
+ goto err_while;
+err_loop:
+ kfree(dir);
+err_start:
+ kfree(newpath);
+err_while:
+ list_for_each_entry_safe(tuple, tmp, &list, list) {
+ list_del(&tuple->list);
+ free_tuple(tuple);
+ }
+ return rc;
+}
+EXPORT_SYMBOL_GPL(xenbus_walk);
+
/* Write the value of a single file.
* Returns -err on failure.
*/
diff --git a/include/xen/xenbus.h b/include/xen/xenbus.h
index 542ca7c..84dc8b0 100644
--- a/include/xen/xenbus.h
+++ b/include/xen/xenbus.h
@@ -229,4 +229,6 @@ const char *xenbus_strstate(enum xenbus_state state);
int xenbus_dev_is_online(struct xenbus_device *dev);
int xenbus_frontend_closed(struct xenbus_device *dev);
+int xenbus_walk(char *start_path, int (*cb)(char *, char *, char *, void *),
+ void *userdata);
#endif /* _XEN_XENBUS_H */
--
1.6.2.5
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel
|