Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 89877e42827f16fa5f86b1df0c2860b1 > files > 2765

kernel-2.6.18-128.1.10.el5.src.rpm

From: Chris Lalancette <clalance@redhat.com>
Date: Tue, 18 Nov 2008 12:17:31 +0100
Subject: [xen] x86: fix highmem-xen.c BUG()
Message-id: 4922A44B.8020200@redhat.com
O-Subject: [RHEL5.3 PATCH]: Fix i686 highmem-xen.c bug
Bugzilla: 452175
RH-Acked-by: Mark McLoughlin <markmc@redhat.com>
RH-Acked-by: Bill Burns <bburns@redhat.com>
RH-Acked-by: Don Dutile <ddutile@redhat.com>
RH-Acked-by: Rik van Riel <riel@redhat.com>

All,
    Attached is a patch to fix BZ 452175.  What's happening is that we are
hitting a BUG in arch/i386/mm/highmem-xen.c when doing a kmap_atomic, here:

if (!pte_none(*(kmap_pte-idx)))
    BUG();

Since this is a kmap_atomic, we don't expect this kmap slot, on this processor,
to be in use when we get here.  However, we can run into situations where this
is occuring, so we BUG.  It happens because this kmap slot isn't being properly
protected from pre-emption.  In this particular case, what happened was that we
started writing to disk on CPU 0 via a sys_write, which went through the swiotlb
code path and took the KM_SWIOTLB kmap entry.  However, midway through that
operation, we were pre-empted by an interrupt for the IDE controller, which also
went through the swiotlb path and then hit the above BUG, since the kmap slot
was already in use on this CPU by the sys_write path.
     The fix is simple; make sure to disable interrupts right before doing the
kmap_atomic, and re-enable interrupts after we do the kunmap_atomic.  This patch
is a simple backport of upstream xen-3.1-testing.hg c/s 13346, and fixes the
issue for the customer.  Note that c/s 13346 goes further and changes the name
of the kmap slot from KM_SWIOTLB to KM_BOUNCE_READ in order to get rid of the
custom include/asm-i386/mach-xen/asm/kmap_types.h header file, but we can't do
this since it breaks kABI.
     Initial testing by the customer indicates this fix works for them; I'm
still waiting on feedback from the more extensive testing they were going to run
overnight.  I've tested it locally on both i386 and x86_64, in dom0, PV guests,
and FV guests, and I didn't notice any regressions in my basic smoke testing.
    Please review and ACK.

--
Chris Lalancette

diff --git a/arch/i386/kernel/swiotlb.c b/arch/i386/kernel/swiotlb.c
index ae9e3b7..0d1e72c 100644
--- a/arch/i386/kernel/swiotlb.c
+++ b/arch/i386/kernel/swiotlb.c
@@ -225,8 +225,11 @@ __sync_single(struct phys_addr buffer, char *dma_addr, size_t size, int dir)
 		char *dev, *host, *kmp;
 		len = size;
 		while (len != 0) {
+			unsigned long flags;
+
 			if (((bytes = len) + buffer.offset) > PAGE_SIZE)
 				bytes = PAGE_SIZE - buffer.offset;
+			local_irq_save(flags); /* protects KM_SWIOTLB */
 			kmp  = kmap_atomic(buffer.page, KM_SWIOTLB);
 			dev  = dma_addr + size - len;
 			host = kmp + buffer.offset;
@@ -236,6 +239,7 @@ __sync_single(struct phys_addr buffer, char *dma_addr, size_t size, int dir)
 			} else
 				memcpy(dev, host, bytes);
 			kunmap_atomic(kmp, KM_SWIOTLB);
+			local_irq_restore(flags);
 			len -= bytes;
 			buffer.page++;
 			buffer.offset = 0;