Modify the HCA drivers to support querying for attributes using a pageable buffer. Since the query calls block, it seems appropriate for the calls to allow pageable memory, rather than forcing the user to allocate a non-paged buffer in order to obtain a list of attributes. The problem stems from the HCA drivers accessing a user's buffer after acquiring a spinlock that raise IRQL.
This fixes kernel crashes with both the winmad and winverbs drivers. Signed-off-by: Sean Hefty <[email protected]> --- The mthca patch is compile tested only. We need this, or some fix, in winof 2.1. Index: hw/mlx4/kernel/bus/core/cache.c =================================================================== --- hw/mlx4/kernel/bus/core/cache.c (revision 2342) +++ hw/mlx4/kernel/bus/core/cache.c (working copy) @@ -80,9 +80,9 @@ int index, union ib_gid *gid) { + union ib_gid cgid; struct ib_gid_cache *cache; unsigned long flags; - int ret = 0; if (mlx4_is_barred(device->dma_device)) return -EFAULT; @@ -94,14 +94,16 @@ cache = device->cache.gid_cache[port_num - start_port(device)]; - if (index < 0 || index >= cache->table_len) - ret = -EINVAL; - else - *gid = cache->table[index]; - + if (index < 0 || index >= cache->table_len) { + read_unlock_irqrestore(&device->cache.lock, flags); + return -EINVAL; + } + + cgid = cache->table[index]; read_unlock_irqrestore(&device->cache.lock, flags); + *gid = cgid; - return ret; + return 0; } EXPORT_SYMBOL(ib_get_cached_gid); @@ -113,33 +115,34 @@ struct ib_gid_cache *cache; unsigned long flags; int p, i; - int ret = -ENOENT; if (mlx4_is_barred(device->dma_device)) return -EFAULT; - *port_num = (u8)-1; - if (index) - *index = (u16)-1; - read_lock_irqsave(&device->cache.lock, &flags); for (p = 0; p <= end_port(device) - start_port(device); ++p) { cache = device->cache.gid_cache[p]; for (i = 0; i < cache->table_len; ++i) { if (!memcmp(gid, &cache->table[i], sizeof *gid)) { - *port_num = (u8)(p + start_port(device)); - if (index) - *index = (u16)i; - ret = 0; goto found; } } } + + read_unlock_irqrestore(&device->cache.lock, flags); + *port_num = (u8)-1; + if (index) + *index = (u16)-1; + return -ENOENT; + found: read_unlock_irqrestore(&device->cache.lock, flags); + *port_num = (u8)(p + start_port(device)); + if (index) + *index = (u16)i; - return ret; + return 0; } EXPORT_SYMBOL(ib_find_cached_gid); @@ -149,8 +152,8 @@ __be16 *pkey) { struct ib_pkey_cache *cache; + __be16 cpkey; unsigned long flags; - int ret = 0; if (mlx4_is_barred(device->dma_device)) return -EFAULT; @@ -162,14 +165,16 @@ cache = device->cache.pkey_cache[port_num - start_port(device)]; - if (index < 0 || index >= cache->table_len) - ret = -EINVAL; - else - *pkey = cache->table[index]; + if (index < 0 || index >= cache->table_len) { + read_unlock_irqrestore(&device->cache.lock, flags); + return -EINVAL; + } + cpkey = cache->table[index]; read_unlock_irqrestore(&device->cache.lock, flags); + *pkey = cpkey; - return ret; + return 0; } EXPORT_SYMBOL(ib_get_cached_pkey); @@ -181,7 +186,6 @@ struct ib_pkey_cache *cache; unsigned long flags; int i; - int ret = -ENOENT; if (mlx4_is_barred(device->dma_device)) return -EFAULT; @@ -197,14 +201,17 @@ for (i = 0; i < cache->table_len; ++i) if ((cache->table[i] & 0x7fff) == (pkey & 0x7fff)) { - *index = (u16)i; - ret = 0; - break; + goto found; } read_unlock_irqrestore(&device->cache.lock, flags); + *index = (u16)-1; + return -ENOENT; - return ret; +found: + read_unlock_irqrestore(&device->cache.lock, flags); + *index = (u16)i; + return 0; } EXPORT_SYMBOL(ib_find_cached_pkey); @@ -213,14 +220,16 @@ u8 *lmc) { unsigned long flags; + u8 clmc; int ret = 0; if (port_num < start_port(device) || port_num > end_port(device)) return -EINVAL; read_lock_irqsave(&device->cache.lock, &flags); - *lmc = device->cache.lmc_cache[port_num - start_port(device)]; + clmc = device->cache.lmc_cache[port_num - start_port(device)]; read_unlock_irqrestore(&device->cache.lock, flags); + *lmc = clmc; return ret; } Index: hw/mthca/kernel/mt_cache.c =================================================================== --- hw/mthca/kernel/mt_cache.c (revision 2342) +++ hw/mthca/kernel/mt_cache.c (working copy) @@ -71,8 +71,8 @@ int index, union ib_gid *gid) { + union ib_gid cgid; struct ib_gid_cache *cache; - int ret = 0; SPIN_LOCK_PREP(lh); // sanity checks @@ -85,14 +85,16 @@ cache = device->cache.gid_cache[port_num - start_port(device)]; - if (index < 0 || index >= cache->table_len) - ret = -EINVAL; - else - *gid = cache->table[index]; + if (index < 0 || index >= cache->table_len) { + read_unlock_irqrestore(&lh); + return -EINVAL; + } + cgid = cache->table[index]; read_unlock_irqrestore(&lh); + *gid = cgid; - return ret; + return 0; } int ib_find_cached_gid(struct ib_device *device, @@ -103,31 +105,32 @@ struct ib_gid_cache *cache; int i; u8 p; - int ret = -ENOENT; SPIN_LOCK_PREP(lh); - *port_num = (u8)-1; - if (index) - *index = (u16)-1; - read_lock_irqsave(&device->cache.lock, &lh); for (p = 0; p <= end_port(device) - start_port(device); ++p) { cache = device->cache.gid_cache[p]; for (i = 0; i < cache->table_len; ++i) { if (!memcmp(gid, &cache->table[i], sizeof *gid)) { - *port_num = p + start_port(device); - if (index) - *index = (u16)i; - ret = 0; goto found; } } } + + read_unlock_irqrestore(&lh); + *port_num = (u8)-1; + if (index) + *index = (u16)-1; + return -ENOENT; + found: read_unlock_irqrestore(&lh); + *port_num = p + start_port(device); + if (index) + *index = (u16)i; - return ret; + return 0; } int ib_get_cached_pkey(struct ib_device *device, @@ -136,7 +139,7 @@ __be16 *pkey) { struct ib_pkey_cache *cache; - int ret = 0; + __be16 cpkey; SPIN_LOCK_PREP(lh); // sanity checks @@ -149,14 +152,16 @@ cache = device->cache.pkey_cache[port_num - start_port(device)]; - if (index < 0 || index >= cache->table_len) - ret = -EINVAL; - else - *pkey = cache->table[index]; + if (index < 0 || index >= cache->table_len) { + read_unlock_irqrestore(&lh); + return -EINVAL; + } + cpkey = cache->table[index]; read_unlock_irqrestore(&lh); + *pkey = cpkey; - return ret; + return 0; } int ib_find_cached_pkey(struct ib_device *device, @@ -166,7 +171,6 @@ { struct ib_pkey_cache *cache; int i; - int ret = -ENOENT; SPIN_LOCK_PREP(lh); if (port_num < start_port(device) || port_num > end_port(device)) @@ -176,18 +180,19 @@ cache = device->cache.pkey_cache[port_num - start_port(device)]; - *index = (u16)-1; - for (i = 0; i < cache->table_len; ++i) if ((cache->table[i] & 0x7fff) == (pkey & 0x7fff)) { - *index = (u16)i; - ret = 0; - break; + goto found; } read_unlock_irqrestore(&lh); + *index = (u16)-1; + return -ENOENT; - return ret; +found: + read_unlock_irqrestore(&lh); + *index = (u16)i; + return 0; } static void ib_cache_update(struct ib_device *device,
hw-pagepool.diff
Description: Binary data
_______________________________________________ ofw mailing list [email protected] http://lists.openfabrics.org/cgi-bin/mailman/listinfo/ofw
