diff mbox

[v3,21/23] xsplice: Add support for shadow variables

Message ID 1455300361-13092-22-git-send-email-konrad.wilk@oracle.com (mailing list archive)
State New, archived
Headers show

Commit Message

Konrad Rzeszutek Wilk Feb. 12, 2016, 6:05 p.m. UTC
From: Ross Lagerwall <ross.lagerwall@citrix.com>

Shadow variables are a piece of infrastructure to be used by xsplice
modules. They are used to attach a new piece of data to an existing
structure in memory.

Signed-off-by: Ross Lagerwall <ross.lagerwall@citrix.com>
---
 xen/common/Makefile             |   1 +
 xen/common/xsplice_shadow.c     | 105 ++++++++++++++++++++++++++++++++++++++++
 xen/include/xen/xsplice_patch.h |  39 +++++++++++++++
 3 files changed, 145 insertions(+)
 create mode 100644 xen/common/xsplice_shadow.c
 create mode 100644 xen/include/xen/xsplice_patch.h

Comments

Martin Pohlack March 7, 2016, 7:40 a.m. UTC | #1
On 12.02.2016 19:05, Konrad Rzeszutek Wilk wrote:
> From: Ross Lagerwall <ross.lagerwall@citrix.com>
> 
> Shadow variables are a piece of infrastructure to be used by xsplice
> modules. They are used to attach a new piece of data to an existing
> structure in memory.
> 
> Signed-off-by: Ross Lagerwall <ross.lagerwall@citrix.com>
> ---
>  xen/common/Makefile             |   1 +
>  xen/common/xsplice_shadow.c     | 105 ++++++++++++++++++++++++++++++++++++++++
>  xen/include/xen/xsplice_patch.h |  39 +++++++++++++++
>  3 files changed, 145 insertions(+)
>  create mode 100644 xen/common/xsplice_shadow.c
>  create mode 100644 xen/include/xen/xsplice_patch.h
> 
> diff --git a/xen/common/Makefile b/xen/common/Makefile
> index a8ceaff..f4d54ad 100644
> --- a/xen/common/Makefile
> +++ b/xen/common/Makefile
> @@ -75,3 +75,4 @@ subdir-$(CONFIG_HAS_DEVICE_TREE) += libfdt
>  
>  obj-$(CONFIG_XSPLICE) += xsplice.o
>  obj-$(CONFIG_XSPLICE) += xsplice_elf.o
> +obj-$(CONFIG_XSPLICE) += xsplice_shadow.o
> diff --git a/xen/common/xsplice_shadow.c b/xen/common/xsplice_shadow.c
> new file mode 100644
> index 0000000..619cdee
> --- /dev/null
> +++ b/xen/common/xsplice_shadow.c
> @@ -0,0 +1,105 @@
> +#include <xen/init.h>
> +#include <xen/kernel.h>
> +#include <xen/lib.h>
> +#include <xen/list.h>
> +#include <xen/spinlock.h>
> +#include <xen/xsplice_patch.h>
> +
> +#define SHADOW_SLOTS 256

Using something very round here will give you lot's of hash collisions
at the price of a very fast hash computation as compilers, linkers, and
memory allocators tend to align starting addresses.  I would suggest to
use a small prime here, e.g., 257 or 251, to have a first approximation
of a simple hash function.

Or use existing hash infrastructure (see below).

> +struct hlist_head shadow_tbl[SHADOW_SLOTS];
> +static DEFINE_SPINLOCK(shadow_lock);
> +
> +struct shadow_var {
> +    struct hlist_node list;         /* Linked to 'shadow_tbl' */
> +    void *data;
> +    const void *obj;
> +    char var[16];
> +};
> +
> +void *xsplice_shadow_alloc(const void *obj, const char *var, size_t size)
> +{
> +    struct shadow_var *shadow;
> +    unsigned int slot;
> +
> +    shadow = xmalloc(struct shadow_var);
> +    if ( !shadow )
> +        return NULL;
> +
> +    shadow->obj = obj;
> +    strlcpy(shadow->var, var, sizeof shadow->var);
> +    shadow->data = xmalloc_bytes(size);
> +    if ( !shadow->data )
> +    {
> +        xfree(shadow);
> +        return NULL;
> +    }
> +
> +    slot = (unsigned long)obj % SHADOW_SLOTS;

hash.h has an earlier import from Linux and provides hash_long().  That
looks like it would not suffer from direct hash collisions.

(also for all other occurrences of "obj % SHADOW_SLOTS" below)

> +    spin_lock(&shadow_lock);
> +    hlist_add_head(&shadow->list, &shadow_tbl[slot]);
> +    spin_unlock(&shadow_lock);
> +
> +    return shadow->data;
> +}
> +
> +void xsplice_shadow_free(const void *obj, const char *var)
> +{
> +    struct shadow_var *entry, *shadow = NULL;
> +    unsigned int slot;
> +    struct hlist_node *next;
> +
> +    slot = (unsigned long)obj % SHADOW_SLOTS;
> +
> +    spin_lock(&shadow_lock);
> +    hlist_for_each_entry(entry, next, &shadow_tbl[slot], list)
> +    {
> +        if ( entry->obj == obj &&
> +             !strcmp(entry->var, var) )
> +        {
> +            shadow = entry;
> +            break;
> +        }
> +    }
> +    if (shadow)
> +    {
> +        hlist_del(&shadow->list);
> +        xfree(shadow->data);
> +        xfree(shadow);
> +    }
> +    spin_unlock(&shadow_lock);
> +}
> +
> +void *xsplice_shadow_get(const void *obj, const char *var)
> +{
> +    struct shadow_var *entry;
> +    unsigned int slot;
> +    struct hlist_node *next;
> +    void *ret = NULL;
> +
> +    slot = (unsigned long)obj % SHADOW_SLOTS;
> +
> +    spin_lock(&shadow_lock);
> +    hlist_for_each_entry(entry, next, &shadow_tbl[slot], list)
> +    {
> +        if ( entry->obj == obj &&
> +             !strcmp(entry->var, var) )
> +        {
> +            ret = entry->data;
> +            break;
> +        }
> +    }
> +
> +    spin_unlock(&shadow_lock);
> +    return ret;
> +}
> +
> +static int __init xsplice_shadow_init(void)
> +{
> +    int i;
> +
> +    for ( i = 0; i < SHADOW_SLOTS; i++ )
> +        INIT_HLIST_HEAD(&shadow_tbl[i]);
> +
> +    return 0;
> +}
> +__initcall(xsplice_shadow_init);
> diff --git a/xen/include/xen/xsplice_patch.h b/xen/include/xen/xsplice_patch.h
> new file mode 100644
> index 0000000..e3f344b
> --- /dev/null
> +++ b/xen/include/xen/xsplice_patch.h
> @@ -0,0 +1,39 @@
> +#ifndef __XEN_XSPLICE_PATCH_H__
> +#define __XEN_XSPLICE_PATCH_H__
> +
> +/*
> + * The following definitions are to be used in patches. They are taken
> + * from kpatch.
> + */
> +
> +/*
> + * xsplice shadow variables
> + *
> + * These functions can be used to add new "shadow" fields to existing data
> + * structures.  For example, to allocate a "newpid" variable associated with an
> + * instance of task_struct, and assign it a value of 1000:
> + *
> + * struct task_struct *tsk = current;
> + * int *newpid;
> + * newpid = xsplice_shadow_alloc(tsk, "newpid", sizeof(int));
> + * if (newpid)
> + * 	*newpid = 1000;
> + *
> + * To retrieve a pointer to the variable:
> + *
> + * struct task_struct *tsk = current;
> + * int *newpid;
> + * newpid = xsplice_shadow_get(tsk, "newpid");
> + * if (newpid)
> + * 	printk("task newpid = %d\n", *newpid); // prints "task newpid = 1000"
> + *
> + * To free it:
> + *
> + * xsplice_shadow_free(tsk, "newpid");
> + */
> +
> +void *xsplice_shadow_alloc(const void *obj, const char *var, size_t size);
> +void xsplice_shadow_free(const void *obj, const char *var);
> +void *xsplice_shadow_get(const void *obj, const char *var);
> +
> +#endif /* __XEN_XSPLICE_PATCH_H__ */
> 

Amazon Development Center Germany GmbH
Krausenstr. 38
10117 Berlin
Geschaeftsfuehrer: Dr. Ralf Herbrich, Christian Schlaeger
Ust-ID: DE289237879
Eingetragen am Amtsgericht Charlottenburg HRB 149173 B
Martin Pohlack March 7, 2016, 6:52 p.m. UTC | #2
On 12.02.2016 19:05, Konrad Rzeszutek Wilk wrote:
> From: Ross Lagerwall <ross.lagerwall@citrix.com>
> 
> Shadow variables are a piece of infrastructure to be used by xsplice
> modules. They are used to attach a new piece of data to an existing
> structure in memory.
> 
> Signed-off-by: Ross Lagerwall <ross.lagerwall@citrix.com>
> ---
>  xen/common/Makefile             |   1 +
>  xen/common/xsplice_shadow.c     | 105 ++++++++++++++++++++++++++++++++++++++++
>  xen/include/xen/xsplice_patch.h |  39 +++++++++++++++
>  3 files changed, 145 insertions(+)
>  create mode 100644 xen/common/xsplice_shadow.c
>  create mode 100644 xen/include/xen/xsplice_patch.h
> 
> diff --git a/xen/common/Makefile b/xen/common/Makefile
> index a8ceaff..f4d54ad 100644
> --- a/xen/common/Makefile
> +++ b/xen/common/Makefile
> @@ -75,3 +75,4 @@ subdir-$(CONFIG_HAS_DEVICE_TREE) += libfdt
>  
>  obj-$(CONFIG_XSPLICE) += xsplice.o
>  obj-$(CONFIG_XSPLICE) += xsplice_elf.o
> +obj-$(CONFIG_XSPLICE) += xsplice_shadow.o
> diff --git a/xen/common/xsplice_shadow.c b/xen/common/xsplice_shadow.c
> new file mode 100644
> index 0000000..619cdee
> --- /dev/null
> +++ b/xen/common/xsplice_shadow.c
> @@ -0,0 +1,105 @@
> +#include <xen/init.h>
> +#include <xen/kernel.h>
> +#include <xen/lib.h>
> +#include <xen/list.h>
> +#include <xen/spinlock.h>
> +#include <xen/xsplice_patch.h>
> +
> +#define SHADOW_SLOTS 256
> +struct hlist_head shadow_tbl[SHADOW_SLOTS];

Thinking about this more, how would a module using this global hash ever
be unloadable again without leaking memory?

For unloading you would need some iterator that walks all the
dynamically created shadow elements and frees them.  The simplest
approach would be if each hotpatch would bring its own instance of the
hash table (if it needs it).  That would allow it to fully walk and
release the hash content on its unload path.

Martin

Amazon Development Center Germany GmbH
Berlin - Dresden - Aachen
main office: Krausenstr. 38, 10117 Berlin
Geschaeftsfuehrer: Dr. Ralf Herbrich, Christian Schlaeger
Ust-ID: DE289237879
Eingetragen am Amtsgericht Charlottenburg HRB 149173 B
Konrad Rzeszutek Wilk March 15, 2016, 6:02 p.m. UTC | #3
On Mon, Mar 07, 2016 at 08:40:47AM +0100, Martin Pohlack wrote:
> On 12.02.2016 19:05, Konrad Rzeszutek Wilk wrote:
> > From: Ross Lagerwall <ross.lagerwall@citrix.com>
> > 
> > Shadow variables are a piece of infrastructure to be used by xsplice
> > modules. They are used to attach a new piece of data to an existing
> > structure in memory.
> > 
> > Signed-off-by: Ross Lagerwall <ross.lagerwall@citrix.com>
> > ---
> >  xen/common/Makefile             |   1 +
> >  xen/common/xsplice_shadow.c     | 105 ++++++++++++++++++++++++++++++++++++++++
> >  xen/include/xen/xsplice_patch.h |  39 +++++++++++++++
> >  3 files changed, 145 insertions(+)
> >  create mode 100644 xen/common/xsplice_shadow.c
> >  create mode 100644 xen/include/xen/xsplice_patch.h
> > 
> > diff --git a/xen/common/Makefile b/xen/common/Makefile
> > index a8ceaff..f4d54ad 100644
> > --- a/xen/common/Makefile
> > +++ b/xen/common/Makefile
> > @@ -75,3 +75,4 @@ subdir-$(CONFIG_HAS_DEVICE_TREE) += libfdt
> >  
> >  obj-$(CONFIG_XSPLICE) += xsplice.o
> >  obj-$(CONFIG_XSPLICE) += xsplice_elf.o
> > +obj-$(CONFIG_XSPLICE) += xsplice_shadow.o
> > diff --git a/xen/common/xsplice_shadow.c b/xen/common/xsplice_shadow.c
> > new file mode 100644
> > index 0000000..619cdee
> > --- /dev/null
> > +++ b/xen/common/xsplice_shadow.c
> > @@ -0,0 +1,105 @@
> > +#include <xen/init.h>
> > +#include <xen/kernel.h>
> > +#include <xen/lib.h>
> > +#include <xen/list.h>
> > +#include <xen/spinlock.h>
> > +#include <xen/xsplice_patch.h>
> > +
> > +#define SHADOW_SLOTS 256
> 
> Using something very round here will give you lot's of hash collisions
> at the price of a very fast hash computation as compilers, linkers, and
> memory allocators tend to align starting addresses.  I would suggest to
> use a small prime here, e.g., 257 or 251, to have a first approximation
> of a simple hash function.

Hey!

I totally missed this comment. Let me spoll this up in my TODO to
change this to 257 for v5.
diff mbox

Patch

diff --git a/xen/common/Makefile b/xen/common/Makefile
index a8ceaff..f4d54ad 100644
--- a/xen/common/Makefile
+++ b/xen/common/Makefile
@@ -75,3 +75,4 @@  subdir-$(CONFIG_HAS_DEVICE_TREE) += libfdt
 
 obj-$(CONFIG_XSPLICE) += xsplice.o
 obj-$(CONFIG_XSPLICE) += xsplice_elf.o
+obj-$(CONFIG_XSPLICE) += xsplice_shadow.o
diff --git a/xen/common/xsplice_shadow.c b/xen/common/xsplice_shadow.c
new file mode 100644
index 0000000..619cdee
--- /dev/null
+++ b/xen/common/xsplice_shadow.c
@@ -0,0 +1,105 @@ 
+#include <xen/init.h>
+#include <xen/kernel.h>
+#include <xen/lib.h>
+#include <xen/list.h>
+#include <xen/spinlock.h>
+#include <xen/xsplice_patch.h>
+
+#define SHADOW_SLOTS 256
+struct hlist_head shadow_tbl[SHADOW_SLOTS];
+static DEFINE_SPINLOCK(shadow_lock);
+
+struct shadow_var {
+    struct hlist_node list;         /* Linked to 'shadow_tbl' */
+    void *data;
+    const void *obj;
+    char var[16];
+};
+
+void *xsplice_shadow_alloc(const void *obj, const char *var, size_t size)
+{
+    struct shadow_var *shadow;
+    unsigned int slot;
+
+    shadow = xmalloc(struct shadow_var);
+    if ( !shadow )
+        return NULL;
+
+    shadow->obj = obj;
+    strlcpy(shadow->var, var, sizeof shadow->var);
+    shadow->data = xmalloc_bytes(size);
+    if ( !shadow->data )
+    {
+        xfree(shadow);
+        return NULL;
+    }
+
+    slot = (unsigned long)obj % SHADOW_SLOTS;
+    spin_lock(&shadow_lock);
+    hlist_add_head(&shadow->list, &shadow_tbl[slot]);
+    spin_unlock(&shadow_lock);
+
+    return shadow->data;
+}
+
+void xsplice_shadow_free(const void *obj, const char *var)
+{
+    struct shadow_var *entry, *shadow = NULL;
+    unsigned int slot;
+    struct hlist_node *next;
+
+    slot = (unsigned long)obj % SHADOW_SLOTS;
+
+    spin_lock(&shadow_lock);
+    hlist_for_each_entry(entry, next, &shadow_tbl[slot], list)
+    {
+        if ( entry->obj == obj &&
+             !strcmp(entry->var, var) )
+        {
+            shadow = entry;
+            break;
+        }
+    }
+    if (shadow)
+    {
+        hlist_del(&shadow->list);
+        xfree(shadow->data);
+        xfree(shadow);
+    }
+    spin_unlock(&shadow_lock);
+}
+
+void *xsplice_shadow_get(const void *obj, const char *var)
+{
+    struct shadow_var *entry;
+    unsigned int slot;
+    struct hlist_node *next;
+    void *ret = NULL;
+
+    slot = (unsigned long)obj % SHADOW_SLOTS;
+
+    spin_lock(&shadow_lock);
+    hlist_for_each_entry(entry, next, &shadow_tbl[slot], list)
+    {
+        if ( entry->obj == obj &&
+             !strcmp(entry->var, var) )
+        {
+            ret = entry->data;
+            break;
+        }
+    }
+
+    spin_unlock(&shadow_lock);
+    return ret;
+}
+
+static int __init xsplice_shadow_init(void)
+{
+    int i;
+
+    for ( i = 0; i < SHADOW_SLOTS; i++ )
+        INIT_HLIST_HEAD(&shadow_tbl[i]);
+
+    return 0;
+}
+__initcall(xsplice_shadow_init);
diff --git a/xen/include/xen/xsplice_patch.h b/xen/include/xen/xsplice_patch.h
new file mode 100644
index 0000000..e3f344b
--- /dev/null
+++ b/xen/include/xen/xsplice_patch.h
@@ -0,0 +1,39 @@ 
+#ifndef __XEN_XSPLICE_PATCH_H__
+#define __XEN_XSPLICE_PATCH_H__
+
+/*
+ * The following definitions are to be used in patches. They are taken
+ * from kpatch.
+ */
+
+/*
+ * xsplice shadow variables
+ *
+ * These functions can be used to add new "shadow" fields to existing data
+ * structures.  For example, to allocate a "newpid" variable associated with an
+ * instance of task_struct, and assign it a value of 1000:
+ *
+ * struct task_struct *tsk = current;
+ * int *newpid;
+ * newpid = xsplice_shadow_alloc(tsk, "newpid", sizeof(int));
+ * if (newpid)
+ * 	*newpid = 1000;
+ *
+ * To retrieve a pointer to the variable:
+ *
+ * struct task_struct *tsk = current;
+ * int *newpid;
+ * newpid = xsplice_shadow_get(tsk, "newpid");
+ * if (newpid)
+ * 	printk("task newpid = %d\n", *newpid); // prints "task newpid = 1000"
+ *
+ * To free it:
+ *
+ * xsplice_shadow_free(tsk, "newpid");
+ */
+
+void *xsplice_shadow_alloc(const void *obj, const char *var, size_t size);
+void xsplice_shadow_free(const void *obj, const char *var);
+void *xsplice_shadow_get(const void *obj, const char *var);
+
+#endif /* __XEN_XSPLICE_PATCH_H__ */