We are in need of a fix for the 2.1 release.  Does this patch look acceptable?

>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,
>


_______________________________________________
ofw mailing list
[email protected]
http://lists.openfabrics.org/cgi-bin/mailman/listinfo/ofw

Reply via email to