OpenVZ Forum


Home » Mailing lists » Devel » [PATCH 0/3] Sysctl shadow management
[PATCH 1/3] The sysctl shadows [message #23557 is a reply to message #23556] Tue, 20 November 2007 11:43 Go to previous messageGo to previous message
Pavel Emelianov is currently offline  Pavel Emelianov
Messages: 1149
Registered: September 2006
Senior Member
The sysctl shadow is nothing but a ctl_table_head, that
hides behind some other one and which is used in
proc_sys_readdir, proc_sys_lookup, etc when scanning
through the list of these heads.

Each "shadow" carries its own set of ctl_tables that
are relevant to this shadow. The appropriate shadow
is get via the ->shadow() callback on the head.

When putting the shadow back (unuse it) one should
work with the shadow->origin head.

The API:
 * register_sysctl_table_shadow: registers the ctl
   table and tells that is will be shadowed with
   the specified callback;
 * create_sysctl_shadow: clones the original head's
   table and creates a shadow for it. The caller then
   may move the ctl_table->data pointer on the new
   (shadow) tables to point to another variables.
   It may also change names for tables, etc;
 * free_sysctl_shadow: destroys the shadow.

Signed-off-by: Pavel Emelyanov <xemul@openvz.org>

---

diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h
index 4f5047d..064f132 100644
--- a/include/linux/sysctl.h
+++ b/include/linux/sysctl.h
@@ -1057,9 +1057,16 @@ struct ctl_table_header
 	struct list_head ctl_entry;
 	int used;
 	struct completion *unregistering;
+	struct ctl_table_header *(*shadow)(struct ctl_table_header *);
+	struct ctl_table_header *origin;
 };
 
 struct ctl_table_header *register_sysctl_table(struct ctl_table * table);
+struct ctl_table_header *register_sysctl_table_shadow(struct ctl_table * table,
+		struct ctl_table_header *(*shadow)(struct ctl_table_header *));
+
+struct ctl_table_header *create_sysctl_shadow(struct ctl_table_header *h);
+void free_sysctl_shadow(struct ctl_table_header *h);
 
 void unregister_sysctl_table(struct ctl_table_header * table);
 int sysctl_check_table(struct ctl_table *table);
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 489b0d1..bfea4fa 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -1320,6 +1320,9 @@ void sysctl_head_finish(struct ctl_table_header *head)
 {
 	if (!head)
 		return;
+	if (head->origin)
+		head = head->origin;
+
 	spin_lock(&sysctl_lock);
 	unuse_table(head);
 	spin_unlock(&sysctl_lock);
@@ -1331,6 +1334,9 @@ struct ctl_table_header *sysctl_head_next(struct ctl_table_header *prev)
 	struct list_head *tmp;
 	spin_lock(&sysctl_lock);
 	if (prev) {
+		if (prev->origin != NULL)
+			prev = prev->origin;
+
 		tmp = &prev->ctl_entry;
 		unuse_table(prev);
 		goto next;
@@ -1342,6 +1348,10 @@ struct ctl_table_header *sysctl_head_next(struct ctl_table_header *prev)
 		if (!use_table(head))
 			goto next;
 		spin_unlock(&sysctl_lock);
+
+		if (head->shadow)
+			head = head->shadow(head);
+
 		return head;
 	next:
 		tmp = tmp->next;
@@ -1582,7 +1592,8 @@ core_initcall(sysctl_init);
  * This routine returns %NULL on a failure to register, and a pointer
  * to the table header on success.
  */
-struct ctl_table_header *register_sysctl_table(struct ctl_table * table)
+struct ctl_table_header *register_sysctl_table_shadow(struct ctl_table * table,
+		struct ctl_table_header *(*shadow)(struct ctl_table_header *))
 {
 	struct ctl_table_header *tmp;
 	tmp = kmalloc(sizeof(struct ctl_table_header), GFP_KERNEL);
@@ -1592,6 +1603,8 @@ struct ctl_table_header *register_sysctl_table(struct ctl_table * table)
 	INIT_LIST_HEAD(&tmp->ctl_entry);
 	tmp->used = 0;
 	tmp->unregistering = NULL;
+	tmp->shadow = shadow;
+	tmp->origin = NULL;
 	sysctl_set_parent(NULL, table);
 	if (sysctl_check_table(tmp->ctl_table)) {
 		kfree(tmp);
@@ -1603,6 +1616,11 @@ struct ctl_table_header *register_sysctl_table(struct ctl_table * table)
 	return tmp;
 }
 
+struct ctl_table_header *register_sysctl_table(struct ctl_table * table)
+{
+	return register_sysctl_table_shadow(table, NULL);
+}
+
 /**
  * unregister_sysctl_table - unregister a sysctl table hierarchy
  * @header: the header returned from register_sysctl_table
@@ -1619,6 +1637,84 @@ void unregister_sysctl_table(struct ctl_table_header * header)
 	kfree(header);
 }
 
+/*
+ * ctl tables shadow management
+ */
+static void ctl_free_table(struct ctl_table *t)
+{
+	struct ctl_table *tmp;
+
+	for (tmp = t; tmp->ctl_name || tmp->procname; tmp++)
+		if (tmp->child)
+			ctl_free_table(tmp->child);
+
+	kfree(t);
+}
+
+static struct ctl_table *ctl_dup_table(struct ctl_table *parent,
+		struct ctl_table *t)
+{
+	int i;
+	struct ctl_table *copy;
+
+	for (copy = t, i = 1; copy->ctl_name || copy->procname; copy++, i++);
+
+	copy = kmemdup(t, i * sizeof(struct ctl_table), GFP_KERNEL);
+	if (copy == NULL)
+		goto out;
+
+	for (i = 0; copy[i].ctl_name || copy[i].procname; i++) {
+		copy[i].parent = parent;
+		if (copy[i].child == NULL)
+			continue;
+
+		copy[i].child = ctl_dup_table(&copy[i], t[i].child);
+		if (copy[i].child == NULL)
+			goto unroll;
+	}
+
+	return copy;
+
+unroll:
+	for (i--; i >= 0; i--)
+		if (copy[i].child)
+			ctl_free_table(copy[i].child);
+	kfree(copy);
+out:
+	return NULL;
+}
+
+struct ctl_table_header *create_sysctl_shadow(struct ctl_table_header *h)
+{
+	struct ctl_table_header *ret;
+	struct ctl_table *tbl;
+
+	ret = kmemdup(h, sizeof(struct ctl_table_header *), GFP_KERNEL);
+	if (ret == NULL)
+		goto err_header;
+
+	ret->shadow = NULL;
+	ret->origin = h;
+
+	tbl = ctl_dup_table(NULL, h->ctl_table);
+	if (tbl == NULL)
+		goto err_table;
+
+	ret->ctl_table = tbl;
+	return ret;
+
+err_table:
+	kfree(ret);
+err_header:
+	return NULL;
+}
+
+void free_sysctl_shadow(struct ctl_table_header *shadow)
+{
+	ctl_free_table(shadow->ctl_table);
+	kfree(shadow);
+}
+
 #else /* !CONFIG_SYSCTL */
 struct ctl_table_header *register_sysctl_table(struct ctl_table * table)
 {

_______________________________________________
Containers mailing list
Containers@lists.linux-foundation.org
https://lists.linux-foundation.org/mailman/listinfo/containers
 
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Previous Topic: [PATCH] proc: fix PDE refcounting
Next Topic: [PATCH 0/4] basic infrastructure for routing in the network namespace
Goto Forum:
  


Current Time: Fri Aug 22 03:55:19 GMT 2025

Total time taken to generate the page: 0.06059 seconds