[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH v3 6/8] p2m: change write_p2m_entry to return an error code
On Fri, Feb 15, 2019 at 06:48:25PM +0100, George Dunlap wrote: > > > On Feb 15, 2019, at 2:18 PM, Roger Pau Monne <roger.pau@xxxxxxxxxx> wrote: > > > > This is in preparation for also changing p2m_entry_modify to return an > > error code. > > > > No functional change intended. > > I think you need to explain wheny/why you’re using BUG_ON() rather than > ASSERT() or passing the caller up the stack. > > > Just in general: > > * Passing things up the stack should be used when the caller is already > expecting to handle errors, and the state when the error was discovered isn’t > broken, or too hard to fix. > > * BUG_ON() should be used when you can’t pass things up the stack, and > continuing would certainly cause a vulnerability. > > * ASSERT() should be used when continuing might work, or might have an effect > later whose badness is equal or less than that of a host crash; OR whose > truth can be clearly observed from the code directly surrounding it. > > For instance... > > > diff --git a/xen/arch/x86/mm/p2m-pt.c b/xen/arch/x86/mm/p2m-pt.c > > index 04e9d81cf6..44abd65999 100644 > > --- a/xen/arch/x86/mm/p2m-pt.c > > +++ b/xen/arch/x86/mm/p2m-pt.c > > @@ -202,7 +202,7 @@ p2m_next_level(struct p2m_domain *p2m, void **table, > > new_entry = l1e_from_mfn(mfn, P2M_BASE_FLAGS | _PAGE_RW); > > > > p2m_add_iommu_flags(&new_entry, level, > > IOMMUF_readable|IOMMUF_writable); > > - p2m->write_p2m_entry(p2m, gfn, p2m_entry, new_entry, level + 1); > > + BUG_ON(p2m->write_p2m_entry(p2m, gfn, p2m_entry, new_entry, level > > + 1)); > > In this case, a few lines above we have `return -ENOMEM`; so: > 1. The caller is expecting to handle error values, and > 2. There’s no unusual state to try to clean up. I'm not that familiar with the p2m code, but there's a call to p2m_alloc_ptp just further up, and while I think failing here would only imply that a page has been added to p2m->pages but has not actually been used in the p2m page tables because the addition of the entry failed. I think adding an entry that expands the page table structure should never fail, and hence I think the following: rc = p2m->write_p2m_entry(p2m, gfn, p2m_entry, new_entry, level + 1); if ( rc ) { ASSERT_UNREACHABLE(); return rc; } Would be the best way to handle the return code from write_p2m_entry in p2m_next_level. > It seems like the `rc = … / if ( rc ) return rc` pattern would be better here. > > > } > > else if ( flags & _PAGE_PSE ) > > { > > @@ -250,14 +250,14 @@ p2m_next_level(struct p2m_domain *p2m, void **table, > > { > > new_entry = l1e_from_pfn(pfn | (i << ((level - 1) * > > PAGETABLE_ORDER)), > > flags); > > - p2m->write_p2m_entry(p2m, gfn, l1_entry + i, new_entry, level); > > + BUG_ON(p2m->write_p2m_entry(p2m, gfn, l1_entry + i, new_entry, > > level)); > > } > > Here, we can’t return an error value, because we’re halfway through an > operation and don’t want to have to bother to clean up. Ignoring the error > and leaving it half-done would certainly be worse than a host crash. > > On the other hand… we know that the previous write_entry succeeded; is it > really possible for this one to fail? > > p2m_entry_modify() doesn’t do anything for entries > 4k, and (by the end of > this series) will BUG_ON() if its " > > I’m tempted to say that what we should do is use ASSERT() here (and many > other places) put a comment in p2m_entry_modify() to say that when changing > it, we need to revisit all the direct callers to make sure that ASSERT() is > still suitable. > > > > > unmap_domain_page(l1_entry); > > > > new_entry = l1e_from_mfn(mfn, P2M_BASE_FLAGS | _PAGE_RW); > > p2m_add_iommu_flags(&new_entry, level, > > IOMMUF_readable|IOMMUF_writable); > > - p2m->write_p2m_entry(p2m, gfn, p2m_entry, new_entry, level + 1); > > + BUG_ON(p2m->write_p2m_entry(p2m, gfn, p2m_entry, new_entry, level > > + 1)); > > In this case, we can see from the context that what’s been written is a > mid-level entry that has just been allocated; there’s no code change that > should be able to cause this to fail. I’m inclined to say this should only > be an ASSERT(). > > > } > > else > > ASSERT(flags & _PAGE_PRESENT); > > @@ -321,7 +321,7 @@ static int p2m_pt_set_recalc_range(struct p2m_domain > > *p2m, > > if ( (l1e_get_flags(e) & _PAGE_PRESENT) && !needs_recalc(l1, e) > > ) > > { > > set_recalc(l1, e); > > - p2m->write_p2m_entry(p2m, first_gfn, pent, e, level); > > + BUG_ON(p2m->write_p2m_entry(p2m, first_gfn, pent, e, > > level)); > > } > > Again here; theoretically, the only change has been that RECALC_FLAGS have > been added. > > And so on. > > Thoughts? (Looking for input from Jan here as well.) As you say here and above, the only caller that's expected to fail is p2m_pt_set_entry, the rest just do recalc or add intermediate entries to the p2m, which must always succeed. > If not, it seems like we should also be modifying the places in p2m-ept.c to > do BUG_ON() rather than ASSERT()’ing that the page write succeeded. I can apply the same treatment that's done in p2m-ept.c, so that we have consistency between both implementations. Thanks, Roger. _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxxxxxxxxx https://lists.xenproject.org/mailman/listinfo/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |