From: cl349@firebug.cl.cam.ac.uk Date: Tue, 23 Aug 2005 13:11:31 +0000 (+0000) Subject: Cleanup grant table code. X-Git-Tag: archive/raspbian/4.8.0-1+rpi1~1^2~16871^2~9 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=54a17fbc8346d20d3ad6c7628caebdc7f4b7af06;p=xen.git 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 --- diff --git a/linux-2.6-xen-sparse/arch/xen/kernel/gnttab.c b/linux-2.6-xen-sparse/arch/xen/kernel/gnttab.c index 7363377ad2..e03e78a759 100644 --- a/linux-2.6-xen-sparse/arch/xen/kernel/gnttab.c +++ b/linux-2.6-xen-sparse/arch/xen/kernel/gnttab.c @@ -46,55 +46,76 @@ EXPORT_SYMBOL(gnttab_release_grant_reference); 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) +static int +get_free_entries(int count) { - 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; + 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; } -static void do_free_callbacks(unsigned long flags) +#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) +check_free_callbacks(void) +{ + if (unlikely(gnttab_free_callback_list)) + do_free_callbacks(); +} + +static void +put_free_entry(grant_ref_t ref) { - grant_ref_t fh, nfh = gnttab_free_head; 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 @@ put_free_entry( */ 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 @@ gnttab_grant_foreign_access( } 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 @@ gnttab_grant_foreign_access_ref( int -gnttab_query_foreign_access( grant_ref_t ref ) +gnttab_query_foreign_access(grant_ref_t ref) { u16 nflags; @@ -140,7 +160,7 @@ gnttab_query_foreign_access( grant_ref_t ref ) } 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 @@ gnttab_end_foreign_access( grant_ref_t ref, int readonly ) } 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 @@ gnttab_grant_foreign_transfer( } 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 @@ gnttab_grant_foreign_transfer_ref( } 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 @@ gnttab_end_foreign_transfer( } 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 ) +gnttab_free_grant_references(grant_ref_t head) { - /* TODO: O(N)...? */ 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++; } + 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, - grant_ref_t *terminal ) +gnttab_alloc_grant_references(u16 count, grant_ref_t *head) { - int i; - grant_ref_t h = gnttab_free_head; + int h = get_free_entries(count); - for ( i = 0; i < count; i++ ) - if ( unlikely(get_free_entry() == -1) ) - goto not_enough_refs; + 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 ) +gnttab_claim_grant_reference(grant_ref_t *private_head) { - grant_ref_t g; - if ( unlikely((g = *private_head) == terminal) ) + 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_release_grant_reference(grant_ref_t *private_head, grant_ref_t release) { - gnttab_free_list[release] = *private_head; + 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 @@ gnttab_request_free_callback(struct gnttab_free_callback *callback, 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 @@ static struct file_operations grant_file_ops = { 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 @@ static int grant_read(char *page, char **start, off_t off, 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 @@ static int grant_write(struct file *file, const char __user *buffer, #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 @@ int gnttab_resume(void) return 0; } -int gnttab_suspend(void) +int +gnttab_suspend(void) { int i; @@ -403,7 +425,8 @@ int gnttab_suspend(void) return 0; } -static int __init gnttab_init(void) +static int __init +gnttab_init(void) { int i; @@ -412,7 +435,7 @@ static int __init gnttab_init(void) 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 --git a/linux-2.6-xen-sparse/drivers/xen/blkfront/blkfront.c b/linux-2.6-xen-sparse/drivers/xen/blkfront/blkfront.c index 47576b7d77..161c3107bf 100644 --- a/linux-2.6-xen-sparse/drivers/xen/blkfront/blkfront.c +++ b/linux-2.6-xen-sparse/drivers/xen/blkfront/blkfront.c @@ -237,15 +237,16 @@ static int blkif_queue_request(struct request *req) 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 @@ static int blkif_queue_request(struct request *req) 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 @@ static int blkif_queue_request(struct request *req) /* 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 @@ static int blkif_queue_request(unsigned long id, 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 @@ static int blkif_queue_request(unsigned long id, 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 --git a/linux-2.6-xen-sparse/include/asm-xen/gnttab.h b/linux-2.6-xen-sparse/include/asm-xen/gnttab.h index a8c76cb9b5..5a1f214b16 100644 --- a/linux-2.6-xen-sparse/include/asm-xen/gnttab.h +++ b/linux-2.6-xen-sparse/include/asm-xen/gnttab.h @@ -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_transfer_ref( - grant_ref_t, domid_t domid, unsigned long pfn); +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); #endif /* __ASM_GNTTAB_H__ */