[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [PATCH V3 01/23] x86/ioreq: Prepare IOREQ feature for making it common
On 07.12.2020 16:27, Oleksandr wrote: > On 07.12.20 13:13, Jan Beulich wrote: >> On 30.11.2020 11:31, Oleksandr Tyshchenko wrote: >>> @@ -601,7 +610,7 @@ static int hvm_ioreq_server_map_pages(struct >>> hvm_ioreq_server *s) >>> return rc; >>> } >>> >>> -static void hvm_ioreq_server_unmap_pages(struct hvm_ioreq_server *s) >>> +void arch_ioreq_server_unmap_pages(struct hvm_ioreq_server *s) >>> { >>> hvm_unmap_ioreq_gfn(s, true); >>> hvm_unmap_ioreq_gfn(s, false); >> How is this now different from ... >> >>> @@ -674,6 +683,12 @@ static int hvm_ioreq_server_alloc_rangesets(struct >>> hvm_ioreq_server *s, >>> return rc; >>> } >>> >>> +void arch_ioreq_server_enable(struct hvm_ioreq_server *s) >>> +{ >>> + hvm_remove_ioreq_gfn(s, false); >>> + hvm_remove_ioreq_gfn(s, true); >>> +} >> ... this? Imo if at all possible there should be no such duplication >> (i.e. at least have this one simply call the earlier one). > > I am afraid, I don't see any duplication between mentioned functions. > Would you mind explaining? Ouch - somehow my eyes considered "unmap" == "remove". I'm sorry for the noise. >>> @@ -1080,6 +1105,24 @@ int hvm_unmap_io_range_from_ioreq_server(struct >>> domain *d, ioservid_t id, >>> return rc; >>> } >>> >>> +/* Called with ioreq_server lock held */ >>> +int arch_ioreq_server_map_mem_type(struct domain *d, >>> + struct hvm_ioreq_server *s, >>> + uint32_t flags) >>> +{ >>> + int rc = p2m_set_ioreq_server(d, flags, s); >>> + >>> + if ( rc == 0 && flags == 0 ) >>> + { >>> + const struct p2m_domain *p2m = p2m_get_hostp2m(d); >>> + >>> + if ( read_atomic(&p2m->ioreq.entry_count) ) >>> + p2m_change_entry_type_global(d, p2m_ioreq_server, p2m_ram_rw); >>> + } >>> + >>> + return rc; >>> +} >>> + >>> /* >>> * Map or unmap an ioreq server to specific memory type. For now, only >>> * HVMMEM_ioreq_server is supported, and in the future new types can be >>> @@ -1112,19 +1155,11 @@ int hvm_map_mem_type_to_ioreq_server(struct domain >>> *d, ioservid_t id, >>> if ( s->emulator != current->domain ) >>> goto out; >>> >>> - rc = p2m_set_ioreq_server(d, flags, s); >>> + rc = arch_ioreq_server_map_mem_type(d, s, flags); >>> >>> out: >>> spin_unlock_recursive(&d->arch.hvm.ioreq_server.lock); >>> >>> - if ( rc == 0 && flags == 0 ) >>> - { >>> - struct p2m_domain *p2m = p2m_get_hostp2m(d); >>> - >>> - if ( read_atomic(&p2m->ioreq.entry_count) ) >>> - p2m_change_entry_type_global(d, p2m_ioreq_server, p2m_ram_rw); >>> - } >>> - >>> return rc; >>> } >> While you mention this change in the description, I'm still >> missing justification as to why the change is safe to make. I >> continue to think p2m_change_entry_type_global() would better >> not be called inside the locked region, if at all possible. > Well. I am afraid, I don't have a 100% justification why the change is > safe to make as well > as I don't see an obvious reason why it is not safe to make (at least I > didn't find a possible deadlock scenario while investigating the code). > I raised a question earlier whether I can fold this check in, which > implied calling p2m_change_entry_type_global() with ioreq_server lock held. I'm aware of the earlier discussion. But "didn't find" isn't good enough in a case like this, and since it's likely hard to indeed prove there's no deadlock possible, I think it's best to avoid having to provide such a proof by avoiding the nesting. > If there is a concern with calling this inside the locked region > (unfortunately still unclear for me at the moment), I will try to find > another way how to split hvm_map_mem_type_to_ioreq_server() without > potentially unsafe change here *and* exposing > p2m_change_entry_type_global() to the common code. Right now, I don't > have any ideas how this could be split other than > introducing one more hook here to deal with p2m_change_entry_type_global > (probably arch_ioreq_server_map_mem_type_complete?), but I don't expect > it to be accepted. > I appreciate any ideas on that. Is there a reason why the simplest solution (two independent arch_*() calls) won't do? If so, what are the constraints? Can the first one e.g. somehow indicate what needs to happen after the lock was dropped? But the two calls look independent right now, so I don't see any complicating factors. >>> --- a/xen/include/asm-x86/hvm/ioreq.h >>> +++ b/xen/include/asm-x86/hvm/ioreq.h >>> @@ -19,6 +19,25 @@ >>> #ifndef __ASM_X86_HVM_IOREQ_H__ >>> #define __ASM_X86_HVM_IOREQ_H__ >>> >>> +#define HANDLE_BUFIOREQ(s) \ >>> + ((s)->bufioreq_handling != HVM_IOREQSRV_BUFIOREQ_OFF) >>> + >>> +bool arch_vcpu_ioreq_completion(enum hvm_io_completion io_completion); >>> +int arch_ioreq_server_map_pages(struct hvm_ioreq_server *s); >>> +void arch_ioreq_server_unmap_pages(struct hvm_ioreq_server *s); >>> +void arch_ioreq_server_enable(struct hvm_ioreq_server *s); >>> +void arch_ioreq_server_disable(struct hvm_ioreq_server *s); >>> +void arch_ioreq_server_destroy(struct hvm_ioreq_server *s); >>> +int arch_ioreq_server_map_mem_type(struct domain *d, >>> + struct hvm_ioreq_server *s, >>> + uint32_t flags); >>> +bool arch_ioreq_server_destroy_all(struct domain *d); >>> +int arch_ioreq_server_get_type_addr(const struct domain *d, >>> + const ioreq_t *p, >>> + uint8_t *type, >>> + uint64_t *addr); >>> +void arch_ioreq_domain_init(struct domain *d); >>> + >>> bool hvm_io_pending(struct vcpu *v); >>> bool handle_hvm_io_completion(struct vcpu *v); >>> bool is_ioreq_server_page(struct domain *d, const struct page_info *page); >> What's the plan here? Introduce them into the x86 header just >> to later move the entire block into the common one? Wouldn't >> it make sense to introduce the common header here right away? >> Or do you expect to convert some of the simpler ones to inline >> functions later on? > The former. The subsequent patch is moving the the entire block(s) from > here and from x86/hvm/ioreq.c to the common code in one go. I think I saw it move the _other_ pieces there, and this block left here. (FAOD my comment is about the arch_*() declarations you add, not the patch context in view.) > I thought it was a little bit odd to expose a header before exposing an > implementation to the common code. Another reason is to minimize places > that need touching by current patch. By exposing arch_*() declarations you don't give the impression of exposing any "implementation". These are helpers the implementation is to invoke; I'm fine with you moving the declarations of the functions actually constituting this component's external interface only once you also move the implementation to common code. Jan
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |