# HG changeset patch
# User cl349@xxxxxxxxxxxxxxxxxxxx
# Node ID 5b1ed5b394513cf79f07cece754d2de3b710430a
# Parent eecb74e515fdebadb1a6f5f1b9ee658aad22c2dc
Cleanup grant table code.
- keep count of free references
- let callbacks specify the number of references they need at least
- get rid of terminal reference
- simplify and more correct locking for callbacks
Signed-off-by: Christian Limpach <Christian.Limpach@xxxxxxxxxxxx>
diff -r eecb74e515fd -r 5b1ed5b39451
linux-2.6-xen-sparse/arch/xen/kernel/gnttab.c
--- a/linux-2.6-xen-sparse/arch/xen/kernel/gnttab.c Tue Aug 23 09:33:48 2005
+++ b/linux-2.6-xen-sparse/arch/xen/kernel/gnttab.c Tue Aug 23 13:11:31 2005
@@ -46,55 +46,76 @@
EXPORT_SYMBOL(gnttab_grant_foreign_access_ref);
EXPORT_SYMBOL(gnttab_grant_foreign_transfer_ref);
-static grant_ref_t gnttab_free_list[NR_GRANT_ENTRIES];
+#define NR_GRANT_ENTRIES (NR_GRANT_FRAMES * PAGE_SIZE / sizeof(grant_entry_t))
+#define GNTTAB_LIST_END (NR_GRANT_ENTRIES + 1)
+
+static grant_ref_t gnttab_list[NR_GRANT_ENTRIES];
+static int gnttab_free_count = NR_GRANT_ENTRIES;
static grant_ref_t gnttab_free_head;
+static spinlock_t gnttab_list_lock = SPIN_LOCK_UNLOCKED;
static grant_entry_t *shared;
static struct gnttab_free_callback *gnttab_free_callback_list = NULL;
-static spinlock_t gnttab_free_callback_list_lock = SPIN_LOCK_UNLOCKED;
-
-/*
- * Lock-free grant-entry allocator
- */
-
-static inline int
-get_free_entry(
- void)
-{
- grant_ref_t fh, nfh = gnttab_free_head;
- do { if ( unlikely((fh = nfh) == NR_GRANT_ENTRIES) ) return -1; }
- while ( unlikely((nfh = cmpxchg(&gnttab_free_head, fh,
- gnttab_free_list[fh])) != fh) );
- return fh;
-}
-
-static void do_free_callbacks(unsigned long flags)
+
+static int
+get_free_entries(int count)
+{
+ unsigned long flags;
+ int ref;
+ grant_ref_t head;
+ spin_lock_irqsave(&gnttab_list_lock, flags);
+ if (gnttab_free_count < count) {
+ spin_unlock_irqrestore(&gnttab_list_lock, flags);
+ return -1;
+ }
+ ref = head = gnttab_free_head;
+ gnttab_free_count -= count;
+ while (count-- > 1)
+ head = gnttab_list[head];
+ gnttab_free_head = gnttab_list[head];
+ gnttab_list[head] = GNTTAB_LIST_END;
+ spin_unlock_irqrestore(&gnttab_list_lock, flags);
+ return ref;
+}
+
+#define get_free_entry() get_free_entries(1)
+
+static void
+do_free_callbacks(void)
{
struct gnttab_free_callback *callback = gnttab_free_callback_list, *next;
gnttab_free_callback_list = NULL;
- spin_unlock_irqrestore(&gnttab_free_callback_list_lock, flags);
while (callback) {
next = callback->next;
- callback->next = NULL;
- callback->fn(callback->arg);
+ if (gnttab_free_count >= callback->count) {
+ callback->next = NULL;
+ callback->fn(callback->arg);
+ } else {
+ callback->next = gnttab_free_callback_list;
+ gnttab_free_callback_list = callback;
+ }
callback = next;
}
}
static inline void
-put_free_entry(
- grant_ref_t ref)
-{
- grant_ref_t fh, nfh = gnttab_free_head;
+check_free_callbacks(void)
+{
+ if (unlikely(gnttab_free_callback_list))
+ do_free_callbacks();
+}
+
+static void
+put_free_entry(grant_ref_t ref)
+{
unsigned long flags;
- do { gnttab_free_list[ref] = fh = nfh; wmb(); }
- while ( unlikely((nfh = cmpxchg(&gnttab_free_head, fh, ref)) != fh) );
- spin_lock_irqsave(&gnttab_free_callback_list_lock, flags);
- if ( unlikely(gnttab_free_callback_list) )
- do_free_callbacks(flags);
- else
- spin_unlock_irqrestore(&gnttab_free_callback_list_lock, flags);
+ spin_lock_irqsave(&gnttab_list_lock, flags);
+ gnttab_list[ref] = gnttab_free_head;
+ gnttab_free_head = ref;
+ gnttab_free_count++;
+ check_free_callbacks();
+ spin_unlock_irqrestore(&gnttab_list_lock, flags);
}
/*
@@ -102,8 +123,7 @@
*/
int
-gnttab_grant_foreign_access(
- domid_t domid, unsigned long frame, int readonly)
+gnttab_grant_foreign_access(domid_t domid, unsigned long frame, int readonly)
{
int ref;
@@ -119,8 +139,8 @@
}
void
-gnttab_grant_foreign_access_ref(
- grant_ref_t ref, domid_t domid, unsigned long frame, int readonly)
+gnttab_grant_foreign_access_ref(grant_ref_t ref, domid_t domid,
+ unsigned long frame, int readonly)
{
shared[ref].frame = frame;
shared[ref].domid = domid;
@@ -130,7 +150,7 @@
int
-gnttab_query_foreign_access( grant_ref_t ref )
+gnttab_query_foreign_access(grant_ref_t ref)
{
u16 nflags;
@@ -140,7 +160,7 @@
}
void
-gnttab_end_foreign_access( grant_ref_t ref, int readonly )
+gnttab_end_foreign_access(grant_ref_t ref, int readonly)
{
u16 flags, nflags;
@@ -155,8 +175,7 @@
}
int
-gnttab_grant_foreign_transfer(
- domid_t domid, unsigned long pfn )
+gnttab_grant_foreign_transfer(domid_t domid, unsigned long pfn)
{
int ref;
@@ -172,8 +191,8 @@
}
void
-gnttab_grant_foreign_transfer_ref(
- grant_ref_t ref, domid_t domid, unsigned long pfn )
+gnttab_grant_foreign_transfer_ref(grant_ref_t ref, domid_t domid,
+ unsigned long pfn)
{
shared[ref].frame = pfn;
shared[ref].domid = domid;
@@ -182,8 +201,7 @@
}
unsigned long
-gnttab_end_foreign_transfer(
- grant_ref_t ref)
+gnttab_end_foreign_transfer(grant_ref_t ref)
{
unsigned long frame = 0;
u16 flags;
@@ -212,80 +230,79 @@
}
void
-gnttab_free_grant_reference( grant_ref_t ref )
+gnttab_free_grant_reference(grant_ref_t ref)
{
put_free_entry(ref);
}
void
-gnttab_free_grant_references( grant_ref_t *head,
- grant_ref_t terminal )
-{
- /* TODO: O(N)...? */
+gnttab_free_grant_references(grant_ref_t head)
+{
grant_ref_t ref;
-
- while (*head != terminal) {
- ref = *head;
- *head = gnttab_free_list[*head];
- put_free_entry(ref);
+ unsigned long flags;
+ int count = 1;
+ if (head == GNTTAB_LIST_END)
+ return;
+ spin_lock_irqsave(&gnttab_list_lock, flags);
+ ref = head;
+ while (gnttab_list[ref] != GNTTAB_LIST_END) {
+ ref = gnttab_list[ref];
+ count++;
}
-}
-
-int
-gnttab_alloc_grant_references( u16 count,
- grant_ref_t *head,
- grant_ref_t *terminal )
-{
- int i;
- grant_ref_t h = gnttab_free_head;
-
- for ( i = 0; i < count; i++ )
- if ( unlikely(get_free_entry() == -1) )
- goto not_enough_refs;
+ gnttab_list[ref] = gnttab_free_head;
+ gnttab_free_head = head;
+ gnttab_free_count += count;
+ check_free_callbacks();
+ spin_unlock_irqrestore(&gnttab_list_lock, flags);
+}
+
+int
+gnttab_alloc_grant_references(u16 count, grant_ref_t *head)
+{
+ int h = get_free_entries(count);
+
+ if (h == -1)
+ return -ENOSPC;
*head = h;
- *terminal = gnttab_free_head;
return 0;
-
-not_enough_refs:
- gnttab_free_head = h;
- return -ENOSPC;
-}
-
-int
-gnttab_claim_grant_reference( grant_ref_t *private_head,
- grant_ref_t terminal )
-{
- grant_ref_t g;
- if ( unlikely((g = *private_head) == terminal) )
+}
+
+int
+gnttab_claim_grant_reference(grant_ref_t *private_head)
+{
+ grant_ref_t g = *private_head;
+ if (unlikely(g == GNTTAB_LIST_END))
return -ENOSPC;
- *private_head = gnttab_free_list[g];
+ *private_head = gnttab_list[g];
return g;
}
void
-gnttab_release_grant_reference( grant_ref_t *private_head,
- grant_ref_t release )
-{
- gnttab_free_list[release] = *private_head;
+gnttab_release_grant_reference(grant_ref_t *private_head, grant_ref_t release)
+{
+ gnttab_list[release] = *private_head;
*private_head = release;
}
void
gnttab_request_free_callback(struct gnttab_free_callback *callback,
- void (*fn)(void *), void *arg)
+ void (*fn)(void *), void *arg, u16 count)
{
unsigned long flags;
+ spin_lock_irqsave(&gnttab_list_lock, flags);
if (callback->next)
- return;
+ goto out;
callback->fn = fn;
callback->arg = arg;
- spin_lock_irqsave(&gnttab_free_callback_list_lock, flags);
+ callback->count = count;
callback->next = gnttab_free_callback_list;
gnttab_free_callback_list = callback;
- spin_unlock_irqrestore(&gnttab_free_callback_list_lock, flags);
+ check_free_callbacks();
+ out:
+ spin_unlock_irqrestore(&gnttab_list_lock, flags);
}
/*
@@ -296,8 +313,9 @@
static struct proc_dir_entry *grant_pde;
-static int grant_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long data)
+static int
+grant_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+ unsigned long data)
{
int ret;
privcmd_hypercall_t hypercall;
@@ -335,8 +353,9 @@
ioctl: grant_ioctl,
};
-static int grant_read(char *page, char **start, off_t off,
- int count, int *eof, void *data)
+static int
+grant_read(char *page, char **start, off_t off, int count, int *eof,
+ void *data)
{
int len;
unsigned int i;
@@ -365,8 +384,9 @@
return len;
}
-static int grant_write(struct file *file, const char __user *buffer,
- unsigned long count, void *data)
+static int
+grant_write(struct file *file, const char __user *buffer, unsigned long count,
+ void *data)
{
/* TODO: implement this */
return -ENOSYS;
@@ -374,7 +394,8 @@
#endif /* CONFIG_PROC_FS */
-int gnttab_resume(void)
+int
+gnttab_resume(void)
{
gnttab_setup_table_t setup;
unsigned long frames[NR_GRANT_FRAMES];
@@ -393,7 +414,8 @@
return 0;
}
-int gnttab_suspend(void)
+int
+gnttab_suspend(void)
{
int i;
@@ -403,7 +425,8 @@
return 0;
}
-static int __init gnttab_init(void)
+static int __init
+gnttab_init(void)
{
int i;
@@ -412,7 +435,7 @@
shared = (grant_entry_t *)fix_to_virt(FIX_GNTTAB_END);
for ( i = 0; i < NR_GRANT_ENTRIES; i++ )
- gnttab_free_list[i] = i + 1;
+ gnttab_list[i] = i + 1;
#ifdef CONFIG_PROC_FS
/*
diff -r eecb74e515fd -r 5b1ed5b39451
linux-2.6-xen-sparse/drivers/xen/blkfront/blkfront.c
--- a/linux-2.6-xen-sparse/drivers/xen/blkfront/blkfront.c Tue Aug 23
09:33:48 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/blkfront/blkfront.c Tue Aug 23
13:11:31 2005
@@ -237,15 +237,16 @@
unsigned long id;
unsigned int fsect, lsect;
int ref;
- grant_ref_t gref_head, gref_terminal;
+ grant_ref_t gref_head;
if (unlikely(info->connected != BLKIF_STATE_CONNECTED))
return 1;
if (gnttab_alloc_grant_references(BLKIF_MAX_SEGMENTS_PER_REQUEST,
- &gref_head, &gref_terminal) < 0) {
+ &gref_head) < 0) {
gnttab_request_free_callback(&info->callback,
- blkif_restart_queue_callback, info);
+ blkif_restart_queue_callback, info,
+ BLKIF_MAX_SEGMENTS_PER_REQUEST);
return 1;
}
@@ -270,7 +271,7 @@
fsect = bvec->bv_offset >> 9;
lsect = fsect + (bvec->bv_len >> 9) - 1;
/* install a grant reference. */
- ref = gnttab_claim_grant_reference(&gref_head, gref_terminal);
+ ref = gnttab_claim_grant_reference(&gref_head);
ASSERT( ref != -ENOSPC );
gnttab_grant_foreign_access_ref(
@@ -294,7 +295,7 @@
/* Keep a private copy so we can reissue requests when recovering. */
pickle_request(&blk_shadow[id], ring_req);
- gnttab_free_grant_references(&gref_head, gref_terminal);
+ gnttab_free_grant_references(gref_head);
return 0;
}
@@ -738,7 +739,7 @@
blk_shadow[req->id].request = (unsigned long)id;
/* install a grant reference. */
- ref = gnttab_claim_grant_reference(&gref_head, gref_terminal);
+ ref = gnttab_claim_grant_reference(&gref_head);
ASSERT( ref != -ENOSPC );
gnttab_grant_foreign_access_ref(
@@ -790,7 +791,7 @@
req->handle = handle;
req->nr_segments = 1;
/* install a grant reference. */
- ref = gnttab_claim_grant_reference(&gref_head, gref_terminal);
+ ref = gnttab_claim_grant_reference(&gref_head);
ASSERT( ref != -ENOSPC );
gnttab_grant_foreign_access_ref(
diff -r eecb74e515fd -r 5b1ed5b39451
linux-2.6-xen-sparse/include/asm-xen/gnttab.h
--- a/linux-2.6-xen-sparse/include/asm-xen/gnttab.h Tue Aug 23 09:33:48 2005
+++ b/linux-2.6-xen-sparse/include/asm-xen/gnttab.h Tue Aug 23 13:11:31 2005
@@ -19,68 +19,46 @@
/* NR_GRANT_FRAMES must be less than or equal to that configured in Xen */
#define NR_GRANT_FRAMES 4
-#define NR_GRANT_ENTRIES (NR_GRANT_FRAMES * PAGE_SIZE / sizeof(grant_entry_t))
struct gnttab_free_callback {
struct gnttab_free_callback *next;
void (*fn)(void *);
void *arg;
+ u16 count;
};
-int
-gnttab_grant_foreign_access(
- domid_t domid, unsigned long frame, int readonly);
+int gnttab_grant_foreign_access(domid_t domid, unsigned long frame,
+ int readonly);
-void
-gnttab_end_foreign_access(
- grant_ref_t ref, int readonly);
+void gnttab_end_foreign_access(grant_ref_t ref, int readonly);
-int
-gnttab_grant_foreign_transfer(
- domid_t domid, unsigned long pfn);
+int gnttab_grant_foreign_transfer(domid_t domid, unsigned long pfn);
-unsigned long
-gnttab_end_foreign_transfer(
- grant_ref_t ref);
+unsigned long gnttab_end_foreign_transfer(grant_ref_t ref);
-int
-gnttab_query_foreign_access(
- grant_ref_t ref );
+int gnttab_query_foreign_access(grant_ref_t ref);
/*
* operations on reserved batches of grant references
*/
-int
-gnttab_alloc_grant_references(
- u16 count, grant_ref_t *pprivate_head, grant_ref_t *private_terminal );
+int gnttab_alloc_grant_references(u16 count, grant_ref_t *pprivate_head);
-void
-gnttab_free_grant_reference(
- grant_ref_t ref );
+void gnttab_free_grant_reference(grant_ref_t ref);
-void
-gnttab_free_grant_references(
- grant_ref_t *head, grant_ref_t terminal );
+void gnttab_free_grant_references(grant_ref_t head);
-int
-gnttab_claim_grant_reference( grant_ref_t *pprivate_head, grant_ref_t terminal
-);
+int gnttab_claim_grant_reference(grant_ref_t *pprivate_head);
-void
-gnttab_release_grant_reference(
- grant_ref_t *private_head, grant_ref_t release );
+void gnttab_release_grant_reference(grant_ref_t *private_head,
+ grant_ref_t release);
-void
-gnttab_request_free_callback(
- struct gnttab_free_callback *callback, void (*fn)(void *), void *arg);
+void gnttab_request_free_callback(struct gnttab_free_callback *callback,
+ void (*fn)(void *), void *arg, u16 count);
-void
-gnttab_grant_foreign_access_ref(
- grant_ref_t ref, domid_t domid, unsigned long frame, int readonly);
+void gnttab_grant_foreign_access_ref(grant_ref_t ref, domid_t domid,
+ unsigned long frame, int readonly);
-void
-gnttab_grant_foreign_transfer_ref(
- grant_ref_t, domid_t domid, unsigned long pfn);
-
+void gnttab_grant_foreign_transfer_ref(grant_ref_t, domid_t domid,
+ unsigned long pfn);
#endif /* __ASM_GNTTAB_H__ */
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|