WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-devel

[Xen-devel] Re: Ungranting

On Thu, 2005-11-03 at 08:42 +0000, Keir Fraser wrote:
> On 3 Nov 2005, at 03:03, Rusty Russell wrote:
> 
> >     The simplest implementation I can think of, is to provide a mechanism
> > in Xen to query the reference count of a page (1 meaning no other
> > mappings).  Linux would simply have a thread which, if any pages were 
> > in
> > the "pending" queue, would query them all once a second.  Since speed
> > isn't important, this would be fine IMHO.
> Linux can already tell whether a grant reference is 'in use' and then 
> atomically free the reference while it is not in use, using cmpxchg.
> 
> I agree polling is the right answer -- explicit notification is 
> probably overkill and might slow down fast paths in Xen.

OK, here's a (lightly) tested implementation.  I use a separate bitmap,
although we could probably use a reserved bit in the grant table flags.
OTOH, if we wanted an arbitrary callback (rather than hardcoding
free_page) we'd need an array of pointers.

For the list: we have a problem in that if a driver wants to unload, it
cannot simply ungrant a page then free it, as it may still be in use by
the other side.  The current code prints out a warning in this case and
just returns without ungranting the page.  This patch provides a
mechanism drivers can use to get and grant a page, and to release that
page.  If it can't be release immediately, it's queued internally.

Signed-off-by: Rusty Russell <rusty@xxxxxxxxxxxxxxx>

diff -r 270469d40f02 linux-2.6-xen-sparse/arch/xen/kernel/gnttab.c
--- a/linux-2.6-xen-sparse/arch/xen/kernel/gnttab.c     Sun Nov  6 18:50:33 2005
+++ b/linux-2.6-xen-sparse/arch/xen/kernel/gnttab.c     Mon Nov  7 14:22:13 2005
@@ -10,6 +10,7 @@
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/sched.h>
+#include <linux/kthread.h>
 #include <asm/pgtable.h>
 #include <asm-xen/xen-public/xen.h>
 #include <asm/fixmap.h>
@@ -56,6 +57,8 @@
 static int gnttab_free_count;
 static grant_ref_t gnttab_free_head;
 static spinlock_t gnttab_list_lock = SPIN_LOCK_UNLOCKED;
+static DECLARE_BITMAP(gnttab_freeing, NR_GRANT_ENTRIES);
+static struct task_struct *gnttab_freer;
 
 static grant_entry_t *shared;
 
@@ -454,6 +457,71 @@
        return 0;
 }
 
+void *alloc_granted_page(grant_ref_t *ref, domid_t dom, int readonly)
+{
+       int err;
+       void *page;
+
+       page = (void *)get_zeroed_page(GFP_KERNEL);
+       if (!page)
+               return ERR_PTR(-ENOMEM);
+
+       err = gnttab_grant_foreign_access(dom, virt_to_mfn(page), readonly);
+       if (err == -ENOSPC) {
+               free_page((unsigned long)page);
+               return ERR_PTR(err);
+       }
+       *ref = err;
+       return page;
+}
+
+static int try_free_grant(grant_ref_t ref)
+{
+       u16 flags = shared[ref].flags;
+
+       if (!(flags & (GTF_reading|GTF_writing)) &&
+           synch_cmpxchg(&shared[ref].flags, flags, 0)) {
+               free_page((unsigned long)mfn_to_virt(shared[ref].frame));
+               /* Clear this if set, before it can be reused. */
+               clear_bit(ref, gnttab_freeing);
+               put_free_entry(ref);
+               printk("Grant %i freed\n", ref);
+               return 1;
+       }
+       return 0;
+}
+
+/* Simplest possible code to poll while bits are pending... */
+static int gnttab_try_free(void *unused)
+{
+       for (;;) {
+               int bit, pending = 0;
+
+               set_current_state(TASK_INTERRUPTIBLE);
+
+               for (bit = find_first_bit(gnttab_freeing, NR_GRANT_ENTRIES);
+                    bit < NR_GRANT_ENTRIES;
+                    bit=find_next_bit(gnttab_freeing,bit+1,NR_GRANT_ENTRIES))
+                       if (!try_free_grant(bit))
+                               pending = 1;
+
+               if (pending)
+                       schedule_timeout(HZ);
+               else
+                       schedule();
+       }
+}
+
+void free_granted_page(void *page, grant_ref_t ref)
+{
+       if (try_free_grant(ref))
+               return;
+
+       /* Deferred freeing. */
+       set_bit(ref, gnttab_freeing);
+       wake_up_process(gnttab_freer);
+}
+
 static int __init
 gnttab_init(void)
 {
@@ -488,6 +556,8 @@
        grant_pde->read_proc  = &grant_read;
        grant_pde->write_proc = &grant_write;
 #endif
+
+       gnttab_freer = kthread_run(gnttab_try_free, NULL, "xengnttabd");
 
        printk("Grant table initialized\n");
        return 0;
diff -r 270469d40f02 linux-2.6-xen-sparse/include/asm-xen/gnttab.h
--- a/linux-2.6-xen-sparse/include/asm-xen/gnttab.h     Sun Nov  6 18:50:33 2005
+++ b/linux-2.6-xen-sparse/include/asm-xen/gnttab.h     Mon Nov  7 14:22:13 2005
@@ -57,6 +57,10 @@
 
 int gnttab_query_foreign_access(grant_ref_t ref);
 
+/* Convenient and safe helpers for granting/ungranting page. */
+void *alloc_granted_page(grant_ref_t *ref, domid_t dom, int readonly);
+void free_granted_page(void *page, grant_ref_t ref);
+
 /*
  * operations on reserved batches of grant references
  */

-- 
A bad analogy is like a leaky screwdriver -- Richard Braakman


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel

<Prev in Thread] Current Thread [Next in Thread>
  • [Xen-devel] Re: Ungranting, Rusty Russell <=