ia64/xen-unstable
changeset 14851:76f9a8e730ea
hvm: Clean up treatment of is_dying per-domain boolean. All critical
checks are done under an appropriate lock, allowing the lock-free
protocols surrounding this boolean to be removed.
Also simplification and fixes to code for setting/zapping the ioreq
and buf_ioreq shared pages.
Signed-off-by: Keir Fraser <keir@xensource.com>
checks are done under an appropriate lock, allowing the lock-free
protocols surrounding this boolean to be removed.
Also simplification and fixes to code for setting/zapping the ioreq
and buf_ioreq shared pages.
Signed-off-by: Keir Fraser <keir@xensource.com>
author | Keir Fraser <keir@xensource.com> |
---|---|
date | Fri Apr 13 14:59:06 2007 +0100 (2007-04-13) |
parents | d51b3bc40ca5 |
children | 22460cfaca71 |
files | xen/arch/x86/hvm/hvm.c xen/arch/x86/hvm/intercept.c xen/arch/x86/hvm/io.c xen/arch/x86/hvm/platform.c xen/arch/x86/mm.c xen/arch/x86/x86_32/domain_page.c xen/common/domain.c xen/include/asm-x86/hvm/domain.h xen/include/asm-x86/hvm/support.h xen/include/xen/domain_page.h |
line diff
1.1 --- a/xen/arch/x86/hvm/hvm.c Fri Apr 13 13:55:10 2007 +0100 1.2 +++ b/xen/arch/x86/hvm/hvm.c Fri Apr 13 14:59:06 2007 +0100 1.3 @@ -101,7 +101,7 @@ void hvm_set_guest_time(struct vcpu *v, 1.4 1.5 u64 hvm_get_guest_time(struct vcpu *v) 1.6 { 1.7 - u64 host_tsc; 1.8 + u64 host_tsc; 1.9 1.10 rdtscll(host_tsc); 1.11 return host_tsc + v->arch.hvm_vcpu.cache_tsc_offset; 1.12 @@ -125,7 +125,7 @@ void hvm_do_resume(struct vcpu *v) 1.13 pt_thaw_time(v); 1.14 1.15 /* NB. Optimised for common case (p->state == STATE_IOREQ_NONE). */ 1.16 - p = &get_vio(v->domain, v->vcpu_id)->vp_ioreq; 1.17 + p = &get_ioreq(v)->vp_ioreq; 1.18 while ( p->state != STATE_IOREQ_NONE ) 1.19 { 1.20 switch ( p->state ) 1.21 @@ -146,54 +146,68 @@ void hvm_do_resume(struct vcpu *v) 1.22 } 1.23 } 1.24 1.25 -static void hvm_clear_ioreq_pfn( 1.26 - struct domain *d, unsigned long *pva) 1.27 +static void hvm_init_ioreq_page( 1.28 + struct domain *d, struct hvm_ioreq_page *iorp) 1.29 { 1.30 - unsigned long va, mfn; 1.31 - 1.32 - BUG_ON(!d->is_dying); 1.33 - 1.34 - if ( (va = xchg(pva, 0UL)) == 0UL ) 1.35 - return; 1.36 - 1.37 - mfn = mfn_from_mapped_domain_page((void *)va); 1.38 - unmap_domain_page_global((void *)va); 1.39 - put_page_and_type(mfn_to_page(mfn)); 1.40 + memset(iorp, 0, sizeof(*iorp)); 1.41 + spin_lock_init(&iorp->lock); 1.42 + domain_pause(d); 1.43 } 1.44 1.45 -static int hvm_set_ioreq_pfn( 1.46 - struct domain *d, unsigned long *pva, unsigned long gmfn) 1.47 +static void hvm_destroy_ioreq_page( 1.48 + struct domain *d, struct hvm_ioreq_page *iorp) 1.49 { 1.50 + spin_lock(&iorp->lock); 1.51 + 1.52 + ASSERT(d->is_dying); 1.53 + 1.54 + if ( iorp->va != NULL ) 1.55 + { 1.56 + unmap_domain_page_global(iorp->va); 1.57 + put_page_and_type(iorp->page); 1.58 + iorp->va = NULL; 1.59 + } 1.60 + 1.61 + spin_unlock(&iorp->lock); 1.62 +} 1.63 + 1.64 +static int hvm_set_ioreq_page( 1.65 + struct domain *d, struct hvm_ioreq_page *iorp, unsigned long gmfn) 1.66 +{ 1.67 + struct page_info *page; 1.68 unsigned long mfn; 1.69 void *va; 1.70 1.71 mfn = gmfn_to_mfn(d, gmfn); 1.72 - if ( !mfn_valid(mfn) || 1.73 - !get_page_and_type(mfn_to_page(mfn), d, PGT_writable_page) ) 1.74 + if ( !mfn_valid(mfn) ) 1.75 + return -EINVAL; 1.76 + 1.77 + page = mfn_to_page(mfn); 1.78 + if ( !get_page_and_type(page, d, PGT_writable_page) ) 1.79 return -EINVAL; 1.80 1.81 va = map_domain_page_global(mfn); 1.82 if ( va == NULL ) 1.83 { 1.84 - put_page_and_type(mfn_to_page(mfn)); 1.85 + put_page_and_type(page); 1.86 return -ENOMEM; 1.87 } 1.88 1.89 - if ( cmpxchg(pva, 0UL, (unsigned long)va) != 0UL ) 1.90 + spin_lock(&iorp->lock); 1.91 + 1.92 + if ( (iorp->va != NULL) || d->is_dying ) 1.93 { 1.94 + spin_unlock(&iorp->lock); 1.95 unmap_domain_page_global(va); 1.96 put_page_and_type(mfn_to_page(mfn)); 1.97 return -EINVAL; 1.98 } 1.99 1.100 - /* 1.101 - * Check dying status /after/ setting *pva. cmpxchg() is a barrier. 1.102 - * We race against hvm_domain_relinquish_resources(). 1.103 - */ 1.104 - if ( d->is_dying ) 1.105 - hvm_clear_ioreq_pfn(d, pva); 1.106 + iorp->va = va; 1.107 + iorp->page = page; 1.108 1.109 - /* Balance the domain_pause() in hvm_domain_initialise(). */ 1.110 + spin_unlock(&iorp->lock); 1.111 + 1.112 domain_unpause(d); 1.113 1.114 return 0; 1.115 @@ -211,7 +225,6 @@ int hvm_domain_initialise(struct domain 1.116 } 1.117 1.118 spin_lock_init(&d->arch.hvm_domain.pbuf_lock); 1.119 - spin_lock_init(&d->arch.hvm_domain.buffered_io_lock); 1.120 spin_lock_init(&d->arch.hvm_domain.irq_lock); 1.121 1.122 rc = paging_enable(d, PG_refcounts|PG_translate|PG_external); 1.123 @@ -221,17 +234,16 @@ int hvm_domain_initialise(struct domain 1.124 vpic_init(d); 1.125 vioapic_init(d); 1.126 1.127 - /* Do not allow domain to run until it has ioreq shared pages. */ 1.128 - domain_pause(d); /* HVM_PARAM_IOREQ_PFN */ 1.129 - domain_pause(d); /* HVM_PARAM_BUFIOREQ_PFN */ 1.130 + hvm_init_ioreq_page(d, &d->arch.hvm_domain.ioreq); 1.131 + hvm_init_ioreq_page(d, &d->arch.hvm_domain.buf_ioreq); 1.132 1.133 return 0; 1.134 } 1.135 1.136 void hvm_domain_relinquish_resources(struct domain *d) 1.137 { 1.138 - hvm_clear_ioreq_pfn(d, &d->arch.hvm_domain.shared_page_va); 1.139 - hvm_clear_ioreq_pfn(d, &d->arch.hvm_domain.buffered_io_va); 1.140 + hvm_destroy_ioreq_page(d, &d->arch.hvm_domain.ioreq); 1.141 + hvm_destroy_ioreq_page(d, &d->arch.hvm_domain.buf_ioreq); 1.142 } 1.143 1.144 void hvm_domain_destroy(struct domain *d) 1.145 @@ -379,10 +391,20 @@ int hvm_vcpu_initialise(struct vcpu *v) 1.146 } 1.147 1.148 /* Create ioreq event channel. */ 1.149 - v->arch.hvm_vcpu.xen_port = alloc_unbound_xen_event_channel(v, 0); 1.150 - if ( get_sp(v->domain) && get_vio(v->domain, v->vcpu_id) ) 1.151 - get_vio(v->domain, v->vcpu_id)->vp_eport = 1.152 - v->arch.hvm_vcpu.xen_port; 1.153 + rc = alloc_unbound_xen_event_channel(v, 0); 1.154 + if ( rc < 0 ) 1.155 + { 1.156 + hvm_funcs.vcpu_destroy(v); 1.157 + vlapic_destroy(v); 1.158 + return rc; 1.159 + } 1.160 + 1.161 + /* Register ioreq event channel. */ 1.162 + v->arch.hvm_vcpu.xen_port = rc; 1.163 + spin_lock(&v->domain->arch.hvm_domain.ioreq.lock); 1.164 + if ( v->domain->arch.hvm_domain.ioreq.va != NULL ) 1.165 + get_ioreq(v)->vp_eport = v->arch.hvm_vcpu.xen_port; 1.166 + spin_unlock(&v->domain->arch.hvm_domain.ioreq.lock); 1.167 1.168 INIT_LIST_HEAD(&v->arch.hvm_vcpu.tm_list); 1.169 1.170 @@ -463,7 +485,7 @@ void hvm_send_assist_req(struct vcpu *v) 1.171 if ( unlikely(!vcpu_start_shutdown_deferral(v)) ) 1.172 return; /* implicitly bins the i/o operation */ 1.173 1.174 - p = &get_vio(v->domain, v->vcpu_id)->vp_ioreq; 1.175 + p = &get_ioreq(v)->vp_ioreq; 1.176 if ( unlikely(p->state != STATE_IOREQ_NONE) ) 1.177 { 1.178 /* This indicates a bug in the device model. Crash the domain. */ 1.179 @@ -981,6 +1003,7 @@ long do_hvm_op(unsigned long op, XEN_GUE 1.180 case HVMOP_get_param: 1.181 { 1.182 struct xen_hvm_param a; 1.183 + struct hvm_ioreq_page *iorp; 1.184 struct domain *d; 1.185 struct vcpu *v; 1.186 1.187 @@ -1009,19 +1032,18 @@ long do_hvm_op(unsigned long op, XEN_GUE 1.188 switch ( a.index ) 1.189 { 1.190 case HVM_PARAM_IOREQ_PFN: 1.191 - rc = hvm_set_ioreq_pfn( 1.192 - d, &d->arch.hvm_domain.shared_page_va, a.value); 1.193 - if ( rc == 0 ) 1.194 - { 1.195 + iorp = &d->arch.hvm_domain.ioreq; 1.196 + rc = hvm_set_ioreq_page(d, iorp, a.value); 1.197 + spin_lock(&iorp->lock); 1.198 + if ( (rc == 0) && (iorp->va != NULL) ) 1.199 /* Initialise evtchn port info if VCPUs already created. */ 1.200 for_each_vcpu ( d, v ) 1.201 - get_vio(d, v->vcpu_id)->vp_eport = 1.202 - v->arch.hvm_vcpu.xen_port; 1.203 - } 1.204 + get_ioreq(v)->vp_eport = v->arch.hvm_vcpu.xen_port; 1.205 + spin_unlock(&iorp->lock); 1.206 break; 1.207 - case HVM_PARAM_BUFIOREQ_PFN: 1.208 - rc = hvm_set_ioreq_pfn( 1.209 - d, &d->arch.hvm_domain.buffered_io_va, a.value); 1.210 + case HVM_PARAM_BUFIOREQ_PFN: 1.211 + iorp = &d->arch.hvm_domain.buf_ioreq; 1.212 + rc = hvm_set_ioreq_page(d, iorp, a.value); 1.213 break; 1.214 case HVM_PARAM_CALLBACK_IRQ: 1.215 hvm_set_callback_via(d, a.value);
2.1 --- a/xen/arch/x86/hvm/intercept.c Fri Apr 13 13:55:10 2007 +0100 2.2 +++ b/xen/arch/x86/hvm/intercept.c Fri Apr 13 14:59:06 2007 +0100 2.3 @@ -158,34 +158,26 @@ static inline void hvm_mmio_access(struc 2.4 int hvm_buffered_io_send(ioreq_t *p) 2.5 { 2.6 struct vcpu *v = current; 2.7 - spinlock_t *buffered_io_lock; 2.8 - buffered_iopage_t *buffered_iopage = 2.9 - (buffered_iopage_t *)(v->domain->arch.hvm_domain.buffered_io_va); 2.10 - unsigned long tmp_write_pointer = 0; 2.11 + struct hvm_ioreq_page *iorp = &v->domain->arch.hvm_domain.buf_ioreq; 2.12 + buffered_iopage_t *pg = iorp->va; 2.13 2.14 - buffered_io_lock = &v->domain->arch.hvm_domain.buffered_io_lock; 2.15 - spin_lock(buffered_io_lock); 2.16 + spin_lock(&iorp->lock); 2.17 2.18 - if ( buffered_iopage->write_pointer - buffered_iopage->read_pointer == 2.19 - (unsigned int)IOREQ_BUFFER_SLOT_NUM ) { 2.20 - /* the queue is full. 2.21 - * send the iopacket through the normal path. 2.22 - * NOTE: The arithimetic operation could handle the situation for 2.23 - * write_pointer overflow. 2.24 - */ 2.25 - spin_unlock(buffered_io_lock); 2.26 + if ( (pg->write_pointer - pg->read_pointer) == IOREQ_BUFFER_SLOT_NUM ) 2.27 + { 2.28 + /* The queue is full: send the iopacket through the normal path. */ 2.29 + spin_unlock(&iorp->lock); 2.30 return 0; 2.31 } 2.32 2.33 - tmp_write_pointer = buffered_iopage->write_pointer % IOREQ_BUFFER_SLOT_NUM; 2.34 - 2.35 - memcpy(&buffered_iopage->ioreq[tmp_write_pointer], p, sizeof(ioreq_t)); 2.36 + memcpy(&pg->ioreq[pg->write_pointer % IOREQ_BUFFER_SLOT_NUM], 2.37 + p, sizeof(ioreq_t)); 2.38 2.39 - /*make the ioreq_t visible before write_pointer*/ 2.40 + /* Make the ioreq_t visible /before/ write_pointer. */ 2.41 wmb(); 2.42 - buffered_iopage->write_pointer++; 2.43 + pg->write_pointer++; 2.44 2.45 - spin_unlock(buffered_io_lock); 2.46 + spin_unlock(&iorp->lock); 2.47 2.48 return 1; 2.49 }
3.1 --- a/xen/arch/x86/hvm/io.c Fri Apr 13 13:55:10 2007 +0100 3.2 +++ b/xen/arch/x86/hvm/io.c Fri Apr 13 14:59:06 2007 +0100 3.3 @@ -832,7 +832,7 @@ void hvm_io_assist(void) 3.4 3.5 io_opp = &v->arch.hvm_vcpu.io_op; 3.6 regs = &io_opp->io_context; 3.7 - vio = get_vio(d, v->vcpu_id); 3.8 + vio = get_ioreq(v); 3.9 3.10 p = &vio->vp_ioreq; 3.11 if ( p->state != STATE_IORESP_READY )
4.1 --- a/xen/arch/x86/hvm/platform.c Fri Apr 13 13:55:10 2007 +0100 4.2 +++ b/xen/arch/x86/hvm/platform.c Fri Apr 13 14:59:06 2007 +0100 4.3 @@ -866,7 +866,7 @@ void send_pio_req(unsigned long port, un 4.4 port, count, size, value, dir, value_is_ptr); 4.5 } 4.6 4.7 - vio = get_vio(v->domain, v->vcpu_id); 4.8 + vio = get_ioreq(v); 4.9 if ( vio == NULL ) { 4.10 printk("bad shared page: %lx\n", (unsigned long) vio); 4.11 domain_crash_synchronous(); 4.12 @@ -915,7 +915,7 @@ static void send_mmio_req(unsigned char 4.13 type, gpa, count, size, value, dir, value_is_ptr); 4.14 } 4.15 4.16 - vio = get_vio(v->domain, v->vcpu_id); 4.17 + vio = get_ioreq(v); 4.18 if (vio == NULL) { 4.19 printk("bad shared page\n"); 4.20 domain_crash_synchronous(); 4.21 @@ -976,7 +976,7 @@ void send_invalidate_req(void) 4.22 vcpu_iodata_t *vio; 4.23 ioreq_t *p; 4.24 4.25 - vio = get_vio(v->domain, v->vcpu_id); 4.26 + vio = get_ioreq(v); 4.27 if ( vio == NULL ) 4.28 { 4.29 printk("bad shared page: %lx\n", (unsigned long) vio);
5.1 --- a/xen/arch/x86/mm.c Fri Apr 13 13:55:10 2007 +0100 5.2 +++ b/xen/arch/x86/mm.c Fri Apr 13 14:59:06 2007 +0100 5.3 @@ -2041,7 +2041,7 @@ int do_mmuext_op( 5.4 MEM_LOG("Error while pinning mfn %lx", mfn); 5.5 break; 5.6 } 5.7 - 5.8 + 5.9 if ( unlikely(test_and_set_bit(_PGT_pinned, 5.10 &page->u.inuse.type_info)) ) 5.11 { 5.12 @@ -2054,14 +2054,18 @@ int do_mmuext_op( 5.13 /* A page is dirtied when its pin status is set. */ 5.14 mark_dirty(d, mfn); 5.15 5.16 - /* 5.17 - * We can race domain destruction (domain_relinquish_resources). 5.18 - * NB. The dying-flag test must happen /after/ setting PGT_pinned. 5.19 - */ 5.20 - if ( unlikely(this_cpu(percpu_mm_info).foreign != NULL) && 5.21 - this_cpu(percpu_mm_info).foreign->is_dying && 5.22 - test_and_clear_bit(_PGT_pinned, &page->u.inuse.type_info) ) 5.23 - put_page_and_type(page); 5.24 + /* We can race domain destruction (domain_relinquish_resources). */ 5.25 + if ( unlikely(this_cpu(percpu_mm_info).foreign != NULL) ) 5.26 + { 5.27 + int drop_ref; 5.28 + spin_lock(&FOREIGNDOM->page_alloc_lock); 5.29 + drop_ref = (FOREIGNDOM->is_dying && 5.30 + test_and_clear_bit(_PGT_pinned, 5.31 + &page->u.inuse.type_info)); 5.32 + spin_unlock(&FOREIGNDOM->page_alloc_lock); 5.33 + if ( drop_ref ) 5.34 + put_page_and_type(page); 5.35 + } 5.36 5.37 break; 5.38
6.1 --- a/xen/arch/x86/x86_32/domain_page.c Fri Apr 13 13:55:10 2007 +0100 6.2 +++ b/xen/arch/x86/x86_32/domain_page.c Fri Apr 13 14:59:06 2007 +0100 6.3 @@ -251,24 +251,3 @@ void unmap_domain_page_global(void *va) 6.4 idx = (__va - IOREMAP_VIRT_START) >> PAGE_SHIFT; 6.5 set_bit(idx, garbage); 6.6 } 6.7 - 6.8 -unsigned long mfn_from_mapped_domain_page(void *va) 6.9 -{ 6.10 - unsigned long __va = (unsigned long)va; 6.11 - l2_pgentry_t *pl2e; 6.12 - l1_pgentry_t *pl1e; 6.13 - unsigned int idx; 6.14 - struct mapcache *cache; 6.15 - 6.16 - if ( (__va >= MAPCACHE_VIRT_START) && (__va < MAPCACHE_VIRT_END) ) 6.17 - { 6.18 - cache = &mapcache_current_vcpu()->domain->arch.mapcache; 6.19 - idx = ((unsigned long)va - MAPCACHE_VIRT_START) >> PAGE_SHIFT; 6.20 - return l1e_get_pfn(cache->l1tab[idx]); 6.21 - } 6.22 - 6.23 - ASSERT(__va >= IOREMAP_VIRT_START); 6.24 - pl2e = virt_to_xen_l2e(__va); 6.25 - pl1e = l2e_to_l1e(*pl2e) + l1_table_offset(__va); 6.26 - return l1e_get_pfn(*pl1e); 6.27 -}
7.1 --- a/xen/common/domain.c Fri Apr 13 13:55:10 2007 +0100 7.2 +++ b/xen/common/domain.c Fri Apr 13 14:59:06 2007 +0100 7.3 @@ -313,9 +313,6 @@ void domain_kill(struct domain *d) 7.4 return; 7.5 } 7.6 7.7 - /* Tear down state /after/ setting the dying flag. */ 7.8 - smp_mb(); 7.9 - 7.10 gnttab_release_mappings(d); 7.11 domain_relinquish_resources(d); 7.12 put_domain(d);
8.1 --- a/xen/include/asm-x86/hvm/domain.h Fri Apr 13 13:55:10 2007 +0100 8.2 +++ b/xen/include/asm-x86/hvm/domain.h Fri Apr 13 14:59:06 2007 +0100 8.3 @@ -28,10 +28,16 @@ 8.4 #include <public/hvm/params.h> 8.5 #include <public/hvm/save.h> 8.6 8.7 +struct hvm_ioreq_page { 8.8 + spinlock_t lock; 8.9 + struct page_info *page; 8.10 + void *va; 8.11 +}; 8.12 + 8.13 struct hvm_domain { 8.14 - unsigned long shared_page_va; 8.15 - unsigned long buffered_io_va; 8.16 - spinlock_t buffered_io_lock; 8.17 + struct hvm_ioreq_page ioreq; 8.18 + struct hvm_ioreq_page buf_ioreq; 8.19 + 8.20 s64 tsc_frequency; 8.21 struct pl_time pl_time; 8.22
9.1 --- a/xen/include/asm-x86/hvm/support.h Fri Apr 13 13:55:10 2007 +0100 9.2 +++ b/xen/include/asm-x86/hvm/support.h Fri Apr 13 14:59:06 2007 +0100 9.3 @@ -32,14 +32,13 @@ 9.4 #define HVM_DEBUG 1 9.5 #endif 9.6 9.7 -static inline shared_iopage_t *get_sp(struct domain *d) 9.8 +static inline vcpu_iodata_t *get_ioreq(struct vcpu *v) 9.9 { 9.10 - return (shared_iopage_t *) d->arch.hvm_domain.shared_page_va; 9.11 -} 9.12 - 9.13 -static inline vcpu_iodata_t *get_vio(struct domain *d, unsigned long cpu) 9.14 -{ 9.15 - return &get_sp(d)->vcpu_iodata[cpu]; 9.16 + struct domain *d = v->domain; 9.17 + shared_iopage_t *p = d->arch.hvm_domain.ioreq.va; 9.18 + ASSERT((v == current) || spin_is_locked(&d->arch.hvm_domain.ioreq.lock)); 9.19 + ASSERT(d->arch.hvm_domain.ioreq.va != NULL); 9.20 + return &p->vcpu_iodata[v->vcpu_id]; 9.21 } 9.22 9.23 /* XXX these are really VMX specific */
10.1 --- a/xen/include/xen/domain_page.h Fri Apr 13 13:55:10 2007 +0100 10.2 +++ b/xen/include/xen/domain_page.h Fri Apr 13 14:59:06 2007 +0100 10.3 @@ -34,13 +34,6 @@ void unmap_domain_page(void *va); 10.4 void *map_domain_page_global(unsigned long mfn); 10.5 void unmap_domain_page_global(void *va); 10.6 10.7 -/* 10.8 - * Convert a VA (within a page previously mapped in the context of the 10.9 - * currently-executing VCPU via a call to map_domain_page(), or via a 10.10 - * previous call to map_domain_page_global()) to the mapped page frame. 10.11 - */ 10.12 -unsigned long mfn_from_mapped_domain_page(void *va); 10.13 - 10.14 #define DMCACHE_ENTRY_VALID 1U 10.15 #define DMCACHE_ENTRY_HELD 2U 10.16 10.17 @@ -109,8 +102,6 @@ domain_mmap_cache_destroy(struct domain_ 10.18 #define map_domain_page_global(mfn) mfn_to_virt(mfn) 10.19 #define unmap_domain_page_global(va) ((void)(va)) 10.20 10.21 -#define mfn_from_mapped_domain_page(va) virt_to_mfn(va) 10.22 - 10.23 struct domain_mmap_cache { 10.24 }; 10.25