All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] xen: Fix a grant table resource leak
@ 2012-05-11 14:20 Dominic Curran
  2012-05-11 14:30 ` Jan Beulich
  0 siblings, 1 reply; 4+ messages in thread
From: Dominic Curran @ 2012-05-11 14:20 UTC (permalink / raw)
  To: xen-devel, konrad.wilk

From: Dominic Curran <dominic.curran@citrix.com>
Date: Fri, 11 May 2012 12:24:42 +0100
Subject: [PATCH] xen: Fix a grant table resource leak

If the resource (my testing shows an object in TX/RX ring) still has a
reference held on it, then add to a list and kick-off a timer to try
and free later.

Signed-off-by: Dominic Curran <dominic.curran@citrix.com>
---
  drivers/xen/grant-table.c |   72 
+++++++++++++++++++++++++++++++++++++++++++---
  1 file changed, 68 insertions(+), 4 deletions(-)

Index: linux-2.6/drivers/xen/grant-table.c
===================================================================
--- linux-2.6.orig/drivers/xen/grant-table.c    2012-05-08 
13:52:54.000000000 +0100
+++ linux-2.6/drivers/xen/grant-table.c    2012-05-08 16:53:52.000000000 
+0100
@@ -33,6 +33,7 @@

  #include <linux/module.h>
  #include <linux/sched.h>
+#include <linux/timer.h>
  #include <linux/mm.h>
  #include <linux/slab.h>
  #include <linux/vmalloc.h>
@@ -57,6 +58,7 @@
  (grant_table_version == 1 ?                      \
  (PAGE_SIZE / sizeof(struct grant_entry_v1)) :   \
  (PAGE_SIZE / sizeof(union grant_entry_v2)))
+#define GNTTAB_CLEANUP_TIMER 10

  static grant_ref_t **gnttab_list;
  static unsigned int nr_grant_frames;
@@ -66,6 +68,9 @@ static grant_ref_t gnttab_free_head;
  static DEFINE_SPINLOCK(gnttab_list_lock);
  unsigned long xen_hvm_resume_frames;
  EXPORT_SYMBOL_GPL(xen_hvm_resume_frames);
+static LIST_HEAD(gnttab_used_ref_list);
+static DEFINE_SPINLOCK(gnttab_used_ref_lock);
+static struct timer_list gnttab_timer;

  static union {
      struct grant_entry_v1 *v1;
@@ -145,6 +150,16 @@ struct gnttab_ops {
                     domid_t trans_domid, grant_ref_t trans_gref);
  };

+/* This structure is used to hold references to pages until they become
+   ready to free.
+*/
+struct gnttab_used_ref {
+    struct list_head    list;
+    grant_ref_t            ref;
+    unsigned long        page;
+    int                readonly;
+};
+
  static struct gnttab_ops *gnttab_interface;

  /*This reflects status of grant entries, so act as a global value*/
@@ -464,18 +479,62 @@ int gnttab_end_foreign_access_ref(grant_
  }
  EXPORT_SYMBOL_GPL(gnttab_end_foreign_access_ref);

+static void gnttab_attempt_clean_used_refs(unsigned long arg)
+{
+    struct gnttab_used_ref  *u;
+    struct list_head        *pos, *q;
+    unsigned long            flags;
+
+    spin_lock_irqsave(&gnttab_used_ref_lock, flags);
+
+    list_for_each_safe(pos, q, &gnttab_used_ref_list) {
+        u = list_entry(pos, struct gnttab_used_ref, list);
+
+        if (gnttab_end_foreign_access_ref(u->ref, u->readonly)) {
+            list_del(pos);
+
+            put_free_entry(u->ref);
+            if (u->page != 0)
+                free_page(u->page);
+
+            kfree(u);
+        }
+    }
+    spin_unlock_irqrestore(&gnttab_used_ref_lock, flags);
+
+    if (!list_empty(&gnttab_used_ref_list))
+        mod_timer(&gnttab_timer, jiffies + HZ);
+}
+
  void gnttab_end_foreign_access(grant_ref_t ref, int readonly,
                     unsigned long page)
  {
+    struct gnttab_used_ref *u;
+    unsigned long flags;
+
      if (gnttab_end_foreign_access_ref(ref, readonly)) {
          put_free_entry(ref);
          if (page != 0)
              free_page(page);
      } else {
-        /* XXX This needs to be fixed so that the ref and page are
-           placed on a list to be freed up later. */
-        printk(KERN_WARNING
-               "WARNING: leaking g.e. and page still in use!\n");
+        /* References that aren't cleaned up immediately sit on
+         * a list until they are abandoned & can be cleaned safely.
+         */
+        u = kmalloc(sizeof(struct gnttab_used_ref), GFP_KERNEL);
+        if (!u)
+            return;
+
+        u->page = page;
+        u->ref = ref;
+        u->readonly = readonly;
+
+        spin_lock_irqsave(&gnttab_used_ref_lock, flags);
+        list_add(&(u->list), &gnttab_used_ref_list);
+        spin_unlock_irqrestore(&gnttab_used_ref_lock, flags);
+
+        /* Kick off the cleanup timer. */
+        if (!timer_pending(&gnttab_timer))
+            add_timer(&gnttab_timer);
      }
  }
  EXPORT_SYMBOL_GPL(gnttab_end_foreign_access);
@@ -1068,6 +1127,11 @@ int gnttab_init(void)
      gnttab_free_count = nr_init_grefs - NR_RESERVED_ENTRIES;
      gnttab_free_head  = NR_RESERVED_ENTRIES;

+    init_timer(&gnttab_timer);
+    gnttab_timer.data = 0;
+    gnttab_timer.function = gnttab_attempt_clean_used_refs;
+    gnttab_timer.expires = jiffies + 
msecs_to_jiffies(GNTTAB_CLEANUP_TIMER);
+
      printk("Grant table initialized\n");
      return 0;

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] xen: Fix a grant table resource leak
  2012-05-11 14:20 [PATCH] xen: Fix a grant table resource leak Dominic Curran
@ 2012-05-11 14:30 ` Jan Beulich
  2012-05-11 14:30   ` Konrad Rzeszutek Wilk
  2012-05-11 14:55   ` Dominic Curran
  0 siblings, 2 replies; 4+ messages in thread
From: Jan Beulich @ 2012-05-11 14:30 UTC (permalink / raw)
  To: Dominic Curran; +Cc: konrad.wilk, xen-devel

>>> On 11.05.12 at 16:20, Dominic Curran <dominic.curran@citrix.com> wrote:
> From: Dominic Curran <dominic.curran@citrix.com>
> Date: Fri, 11 May 2012 12:24:42 +0100
> Subject: [PATCH] xen: Fix a grant table resource leak
> 
> If the resource (my testing shows an object in TX/RX ring) still has a
> reference held on it, then add to a list and kick-off a timer to try
> and free later.

Did you see

http://lists.xen.org/archives/html/xen-devel/2012-04/msg00406.html

Jan

> Signed-off-by: Dominic Curran <dominic.curran@citrix.com>
> ---
>   drivers/xen/grant-table.c |   72 
> +++++++++++++++++++++++++++++++++++++++++++---
>   1 file changed, 68 insertions(+), 4 deletions(-)
> 
> Index: linux-2.6/drivers/xen/grant-table.c
> ===================================================================
> --- linux-2.6.orig/drivers/xen/grant-table.c    2012-05-08 
> 13:52:54.000000000 +0100
> +++ linux-2.6/drivers/xen/grant-table.c    2012-05-08 16:53:52.000000000 
> +0100
> @@ -33,6 +33,7 @@
> 
>   #include <linux/module.h>
>   #include <linux/sched.h>
> +#include <linux/timer.h>
>   #include <linux/mm.h>
>   #include <linux/slab.h>
>   #include <linux/vmalloc.h>
> @@ -57,6 +58,7 @@
>   (grant_table_version == 1 ?                      \
>   (PAGE_SIZE / sizeof(struct grant_entry_v1)) :   \
>   (PAGE_SIZE / sizeof(union grant_entry_v2)))
> +#define GNTTAB_CLEANUP_TIMER 10
> 
>   static grant_ref_t **gnttab_list;
>   static unsigned int nr_grant_frames;
> @@ -66,6 +68,9 @@ static grant_ref_t gnttab_free_head;
>   static DEFINE_SPINLOCK(gnttab_list_lock);
>   unsigned long xen_hvm_resume_frames;
>   EXPORT_SYMBOL_GPL(xen_hvm_resume_frames);
> +static LIST_HEAD(gnttab_used_ref_list);
> +static DEFINE_SPINLOCK(gnttab_used_ref_lock);
> +static struct timer_list gnttab_timer;
> 
>   static union {
>       struct grant_entry_v1 *v1;
> @@ -145,6 +150,16 @@ struct gnttab_ops {
>                      domid_t trans_domid, grant_ref_t trans_gref);
>   };
> 
> +/* This structure is used to hold references to pages until they become
> +   ready to free.
> +*/
> +struct gnttab_used_ref {
> +    struct list_head    list;
> +    grant_ref_t            ref;
> +    unsigned long        page;
> +    int                readonly;
> +};
> +
>   static struct gnttab_ops *gnttab_interface;
> 
>   /*This reflects status of grant entries, so act as a global value*/
> @@ -464,18 +479,62 @@ int gnttab_end_foreign_access_ref(grant_
>   }
>   EXPORT_SYMBOL_GPL(gnttab_end_foreign_access_ref);
> 
> +static void gnttab_attempt_clean_used_refs(unsigned long arg)
> +{
> +    struct gnttab_used_ref  *u;
> +    struct list_head        *pos, *q;
> +    unsigned long            flags;
> +
> +    spin_lock_irqsave(&gnttab_used_ref_lock, flags);
> +
> +    list_for_each_safe(pos, q, &gnttab_used_ref_list) {
> +        u = list_entry(pos, struct gnttab_used_ref, list);
> +
> +        if (gnttab_end_foreign_access_ref(u->ref, u->readonly)) {
> +            list_del(pos);
> +
> +            put_free_entry(u->ref);
> +            if (u->page != 0)
> +                free_page(u->page);
> +
> +            kfree(u);
> +        }
> +    }
> +    spin_unlock_irqrestore(&gnttab_used_ref_lock, flags);
> +
> +    if (!list_empty(&gnttab_used_ref_list))
> +        mod_timer(&gnttab_timer, jiffies + HZ);
> +}
> +
>   void gnttab_end_foreign_access(grant_ref_t ref, int readonly,
>                      unsigned long page)
>   {
> +    struct gnttab_used_ref *u;
> +    unsigned long flags;
> +
>       if (gnttab_end_foreign_access_ref(ref, readonly)) {
>           put_free_entry(ref);
>           if (page != 0)
>               free_page(page);
>       } else {
> -        /* XXX This needs to be fixed so that the ref and page are
> -           placed on a list to be freed up later. */
> -        printk(KERN_WARNING
> -               "WARNING: leaking g.e. and page still in use!\n");
> +        /* References that aren't cleaned up immediately sit on
> +         * a list until they are abandoned & can be cleaned safely.
> +         */
> +        u = kmalloc(sizeof(struct gnttab_used_ref), GFP_KERNEL);
> +        if (!u)
> +            return;
> +
> +        u->page = page;
> +        u->ref = ref;
> +        u->readonly = readonly;
> +
> +        spin_lock_irqsave(&gnttab_used_ref_lock, flags);
> +        list_add(&(u->list), &gnttab_used_ref_list);
> +        spin_unlock_irqrestore(&gnttab_used_ref_lock, flags);
> +
> +        /* Kick off the cleanup timer. */
> +        if (!timer_pending(&gnttab_timer))
> +            add_timer(&gnttab_timer);
>       }
>   }
>   EXPORT_SYMBOL_GPL(gnttab_end_foreign_access);
> @@ -1068,6 +1127,11 @@ int gnttab_init(void)
>       gnttab_free_count = nr_init_grefs - NR_RESERVED_ENTRIES;
>       gnttab_free_head  = NR_RESERVED_ENTRIES;
> 
> +    init_timer(&gnttab_timer);
> +    gnttab_timer.data = 0;
> +    gnttab_timer.function = gnttab_attempt_clean_used_refs;
> +    gnttab_timer.expires = jiffies + 
> msecs_to_jiffies(GNTTAB_CLEANUP_TIMER);
> +
>       printk("Grant table initialized\n");
>       return 0;
> 
> 
> 
> _______________________________________________
> Xen-devel mailing list
> Xen-devel@lists.xen.org 
> http://lists.xen.org/xen-devel 

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] xen: Fix a grant table resource leak
  2012-05-11 14:30 ` Jan Beulich
@ 2012-05-11 14:30   ` Konrad Rzeszutek Wilk
  2012-05-11 14:55   ` Dominic Curran
  1 sibling, 0 replies; 4+ messages in thread
From: Konrad Rzeszutek Wilk @ 2012-05-11 14:30 UTC (permalink / raw)
  To: Jan Beulich; +Cc: xen-devel

On Fri, May 11, 2012 at 03:30:05PM +0100, Jan Beulich wrote:
> >>> On 11.05.12 at 16:20, Dominic Curran <dominic.curran@citrix.com> wrote:
> > From: Dominic Curran <dominic.curran@citrix.com>
> > Date: Fri, 11 May 2012 12:24:42 +0100
> > Subject: [PATCH] xen: Fix a grant table resource leak
> > 
> > If the resource (my testing shows an object in TX/RX ring) still has a
> > reference held on it, then add to a list and kick-off a timer to try
> > and free later.
> 
> Did you see
> 
> http://lists.xen.org/archives/html/xen-devel/2012-04/msg00406.html

Which is on the 3.5 queue list:
http://git.kernel.org/?p=linux/kernel/git/konrad/xen.git;a=commit;h=569ca5b3f94cd0b3295ec5943aa457cf4a4f6a3a

> 
> Jan
> 
> > Signed-off-by: Dominic Curran <dominic.curran@citrix.com>
> > ---
> >   drivers/xen/grant-table.c |   72 
> > +++++++++++++++++++++++++++++++++++++++++++---
> >   1 file changed, 68 insertions(+), 4 deletions(-)
> > 
> > Index: linux-2.6/drivers/xen/grant-table.c
> > ===================================================================
> > --- linux-2.6.orig/drivers/xen/grant-table.c    2012-05-08 
> > 13:52:54.000000000 +0100
> > +++ linux-2.6/drivers/xen/grant-table.c    2012-05-08 16:53:52.000000000 
> > +0100
> > @@ -33,6 +33,7 @@
> > 
> >   #include <linux/module.h>
> >   #include <linux/sched.h>
> > +#include <linux/timer.h>
> >   #include <linux/mm.h>
> >   #include <linux/slab.h>
> >   #include <linux/vmalloc.h>
> > @@ -57,6 +58,7 @@
> >   (grant_table_version == 1 ?                      \
> >   (PAGE_SIZE / sizeof(struct grant_entry_v1)) :   \
> >   (PAGE_SIZE / sizeof(union grant_entry_v2)))
> > +#define GNTTAB_CLEANUP_TIMER 10
> > 
> >   static grant_ref_t **gnttab_list;
> >   static unsigned int nr_grant_frames;
> > @@ -66,6 +68,9 @@ static grant_ref_t gnttab_free_head;
> >   static DEFINE_SPINLOCK(gnttab_list_lock);
> >   unsigned long xen_hvm_resume_frames;
> >   EXPORT_SYMBOL_GPL(xen_hvm_resume_frames);
> > +static LIST_HEAD(gnttab_used_ref_list);
> > +static DEFINE_SPINLOCK(gnttab_used_ref_lock);
> > +static struct timer_list gnttab_timer;
> > 
> >   static union {
> >       struct grant_entry_v1 *v1;
> > @@ -145,6 +150,16 @@ struct gnttab_ops {
> >                      domid_t trans_domid, grant_ref_t trans_gref);
> >   };
> > 
> > +/* This structure is used to hold references to pages until they become
> > +   ready to free.
> > +*/
> > +struct gnttab_used_ref {
> > +    struct list_head    list;
> > +    grant_ref_t            ref;
> > +    unsigned long        page;
> > +    int                readonly;
> > +};
> > +
> >   static struct gnttab_ops *gnttab_interface;
> > 
> >   /*This reflects status of grant entries, so act as a global value*/
> > @@ -464,18 +479,62 @@ int gnttab_end_foreign_access_ref(grant_
> >   }
> >   EXPORT_SYMBOL_GPL(gnttab_end_foreign_access_ref);
> > 
> > +static void gnttab_attempt_clean_used_refs(unsigned long arg)
> > +{
> > +    struct gnttab_used_ref  *u;
> > +    struct list_head        *pos, *q;
> > +    unsigned long            flags;
> > +
> > +    spin_lock_irqsave(&gnttab_used_ref_lock, flags);
> > +
> > +    list_for_each_safe(pos, q, &gnttab_used_ref_list) {
> > +        u = list_entry(pos, struct gnttab_used_ref, list);
> > +
> > +        if (gnttab_end_foreign_access_ref(u->ref, u->readonly)) {
> > +            list_del(pos);
> > +
> > +            put_free_entry(u->ref);
> > +            if (u->page != 0)
> > +                free_page(u->page);
> > +
> > +            kfree(u);
> > +        }
> > +    }
> > +    spin_unlock_irqrestore(&gnttab_used_ref_lock, flags);
> > +
> > +    if (!list_empty(&gnttab_used_ref_list))
> > +        mod_timer(&gnttab_timer, jiffies + HZ);
> > +}
> > +
> >   void gnttab_end_foreign_access(grant_ref_t ref, int readonly,
> >                      unsigned long page)
> >   {
> > +    struct gnttab_used_ref *u;
> > +    unsigned long flags;
> > +
> >       if (gnttab_end_foreign_access_ref(ref, readonly)) {
> >           put_free_entry(ref);
> >           if (page != 0)
> >               free_page(page);
> >       } else {
> > -        /* XXX This needs to be fixed so that the ref and page are
> > -           placed on a list to be freed up later. */
> > -        printk(KERN_WARNING
> > -               "WARNING: leaking g.e. and page still in use!\n");
> > +        /* References that aren't cleaned up immediately sit on
> > +         * a list until they are abandoned & can be cleaned safely.
> > +         */
> > +        u = kmalloc(sizeof(struct gnttab_used_ref), GFP_KERNEL);
> > +        if (!u)
> > +            return;
> > +
> > +        u->page = page;
> > +        u->ref = ref;
> > +        u->readonly = readonly;
> > +
> > +        spin_lock_irqsave(&gnttab_used_ref_lock, flags);
> > +        list_add(&(u->list), &gnttab_used_ref_list);
> > +        spin_unlock_irqrestore(&gnttab_used_ref_lock, flags);
> > +
> > +        /* Kick off the cleanup timer. */
> > +        if (!timer_pending(&gnttab_timer))
> > +            add_timer(&gnttab_timer);
> >       }
> >   }
> >   EXPORT_SYMBOL_GPL(gnttab_end_foreign_access);
> > @@ -1068,6 +1127,11 @@ int gnttab_init(void)
> >       gnttab_free_count = nr_init_grefs - NR_RESERVED_ENTRIES;
> >       gnttab_free_head  = NR_RESERVED_ENTRIES;
> > 
> > +    init_timer(&gnttab_timer);
> > +    gnttab_timer.data = 0;
> > +    gnttab_timer.function = gnttab_attempt_clean_used_refs;
> > +    gnttab_timer.expires = jiffies + 
> > msecs_to_jiffies(GNTTAB_CLEANUP_TIMER);
> > +
> >       printk("Grant table initialized\n");
> >       return 0;
> > 
> > 
> > 
> > _______________________________________________
> > Xen-devel mailing list
> > Xen-devel@lists.xen.org 
> > http://lists.xen.org/xen-devel 
> 

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] xen: Fix a grant table resource leak
  2012-05-11 14:30 ` Jan Beulich
  2012-05-11 14:30   ` Konrad Rzeszutek Wilk
@ 2012-05-11 14:55   ` Dominic Curran
  1 sibling, 0 replies; 4+ messages in thread
From: Dominic Curran @ 2012-05-11 14:55 UTC (permalink / raw)
  To: Jan Beulich; +Cc: xen-devel

On 11/05/12 15:30, Jan Beulich wrote:
>>>> On 11.05.12 at 16:20, Dominic Curran<dominic.curran@citrix.com>  wrote:
>> From: Dominic Curran<dominic.curran@citrix.com>
>> Date: Fri, 11 May 2012 12:24:42 +0100
>> Subject: [PATCH] xen: Fix a grant table resource leak
>>
>> If the resource (my testing shows an object in TX/RX ring) still has a
>> reference held on it, then add to a list and kick-off a timer to try
>> and free later.
> Did you see
>
> http://lists.xen.org/archives/html/xen-devel/2012-04/msg00406.html
>
> Jan
Oh!

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2012-05-11 14:55 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-05-11 14:20 [PATCH] xen: Fix a grant table resource leak Dominic Curran
2012-05-11 14:30 ` Jan Beulich
2012-05-11 14:30   ` Konrad Rzeszutek Wilk
2012-05-11 14:55   ` Dominic Curran

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.