From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751529Ab1GSRlt (ORCPT ); Tue, 19 Jul 2011 13:41:49 -0400 Received: from charlotte.tuxdriver.com ([70.61.120.58]:40799 "EHLO smtp.tuxdriver.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751043Ab1GSRls (ORCPT ); Tue, 19 Jul 2011 13:41:48 -0400 From: Neil Horman To: linux-kernel@vger.kernel.org Cc: Neil Horman , Divy LeRay , Stanislaw Gruszka , Joerg Roedel , Arnd Bergmann Subject: [PATCH] dma-debug: hash_bucket_find needs to allow for offsets within an entry Date: Tue, 19 Jul 2011 13:41:18 -0400 Message-Id: <1311097278-30841-1-git-send-email-nhorman@tuxdriver.com> X-Mailer: git-send-email 1.7.6 X-Spam-Score: -2.6 (--) Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Users of the pci_dma_sync_single_* api allow users to sync address ranges within the range of a mapped entry (i.e. you can dma map address X to dma_addr_t A and then pci_dma_sync_single on dma_addr_t A+1. The dma-debug library however assume dma syncs will always occur using the base address of a mapped region, and uses that assumption to find entries in its hash table. Since thats often (but not always the case), the dma debug library can give us false errors about missing entries, which are reported as syncing of memory not allocated by the driver. This was noted in the cxgb3 driver as this error: WARNING: at lib/dma-debug.c:902 check_sync+0xdd/0x48c() Hardware name: To be filled by O.E.M. cxgb3 0000:01:00.0: DMA-API: device driver tries to sync DMA memory it has not allocated [device address=0x00000000fff97800] [size=1984 bytes] Modules linked in: autofs4 sunrpc cpufreq_ondemand acpi_cpufreq freq_table mperf ip6t_REJECT nf_conntrack_ipv6 ip6table_filter ip6_tables ipv6 uinput snd_hda_codec_intelhdmi snd_hda_codec_realtek snd_hda_intel snd_hda_codec snd_hwdep snd_seq snd_seq_device snd_pcm snd_timer e1000e snd soundcore r8169 cxgb3 iTCO_wdt snd_page_alloc mii shpchp i2c_i801 iTCO_vendor_support mdio microcode firewire_ohci firewire_core crc_itu_t ata_generic pata_acpi i915 drm_kms_helper drm i2c_algo_bit i2c_core video output [last unloaded: scsi_wait_scan] Pid: 1818, comm: ifconfig Not tainted 2.6.35-0.23.rc3.git6.fc14.x86_64 #1 Call Trace: [] warn_slowpath_common+0x85/0x9d [] warn_slowpath_fmt+0x46/0x48 [] ? check_sync+0x39/0x48c [] ? trace_hardirqs_on+0xd/0xf [] check_sync+0xdd/0x48c [] debug_dma_sync_single_for_device+0x3f/0x41 [] ? pci_map_page+0x84/0x97 [cxgb3] [] pci_dma_sync_single_for_device.clone.0+0x65/0x6e [cxgb3] [] refill_fl+0x305/0x30a [cxgb3] [] t3_sge_alloc_qset+0x6a7/0x821 [cxgb3] [] cxgb_up+0x4d0/0xe62 [cxgb3] [] ? __module_text_address+0x12/0x58 [] cxgb_open+0x3f/0x309 [cxgb3] [] __dev_open+0x8e/0xbc [] __dev_change_flags+0xbe/0x142 [] dev_change_flags+0x21/0x57 [] devinet_ioctl+0x29a/0x54b [] ? inode_has_perm+0xaa/0xce [] inet_ioctl+0x8f/0xa7 [] sock_do_ioctl+0x29/0x48 [] sock_ioctl+0x213/0x222 [] vfs_ioctl+0x32/0xa6 [] do_vfs_ioctl+0x47a/0x4b3 [] sys_ioctl+0x56/0x79 [] system_call_fastpath+0x16/0x1b ---[ end trace 69a4d4cc77b58004 ]--- This patch corrects the issue by changing the hash_bucket_find function so that it matches on entries where the referenced address and size fall within the range of a given entry without overlapping. Signed-off-by: Neil Horman Reported-by: Jay Fenalson CC: Divy LeRay CC: Stanislaw Gruszka CC: Joerg Roedel CC: Arnd Bergmann --- lib/dma-debug.c | 17 +++++++++++++++-- 1 files changed, 15 insertions(+), 2 deletions(-) diff --git a/lib/dma-debug.c b/lib/dma-debug.c index db07bfd..333f0ee 100644 --- a/lib/dma-debug.c +++ b/lib/dma-debug.c @@ -248,10 +248,23 @@ static struct dma_debug_entry *hash_bucket_find(struct hash_bucket *bucket, { struct dma_debug_entry *entry, *ret = NULL; int matches = 0, match_lvl, last_lvl = 0; + u64 estart, eend, rstart, rend; + + rstart = ref->dev_addr; + rend = rstart + ref->size; list_for_each_entry(entry, &bucket->list, list) { - if ((entry->dev_addr != ref->dev_addr) || - (entry->dev != ref->dev)) + estart = entry->dev_addr; + eend = estart + entry->size; + + /* + * An entry matches if the address range specified by the ref + * dev_addr and size falls entirely within the range specified + * by the entries dev_addr and size and the devices match + */ + if (entry->dev != ref->dev) + continue; + if ((estart > rstart) || (eend < rend)) continue; /* -- 1.7.6