On 3/26/2015 1:42 AM, Bart Van Assche wrote:
On 03/25/2015 02:19 PM, Somnath Kotur wrote:
+    if (cache->data_vec[ix].attr.ndev &&
+        cache->data_vec[ix].attr.ndev != old_net_dev)

A few lines earlier the memory old_net_dev points at was freed. If two
instances of this function run concurrently, what prevents that the
old_net_dev memory has been reallocated and hence that attr.ndev ==
old_net_dev although both pointers refer(red) to different network
devices ?


write_gid is *almost* always called in a mutex. The only case it's not protected is in free_roce_gid_cache. free_roce_gid_cache is called only in the error flow of roce_gid_cache_setup_one, when no concurrent write_gid could be made (as the cache isn't setup yet) and in roce_gid_cache_cleanup_one. roce_gid_cache_client_setup_one is called in the error flow of roce_gid_cache_client_setup_one (where no other write_gid are expected for the same above reason) and in roce_gid_cache_client_cleanup_work_handler, where it's called after flush_workqueue(roce_gid_mgmt_wq). Since all write_gids are called through roce_gid_mgmt_wq and we set the cache to inactive mode before flushing the wq and freeing the cache, I think we can conclude no concurrent write_gid on the same cache are possible.

+    ACCESS_ONCE(cache->data_vec[ix].seq) = orig_seq;

Invoking write_gid() is only safe if the caller serializes write_gid()
calls. Apparently the cache->lock mutex is used for that purpose. So why
is it necessary to use ACCESS_ONCE() here ? Why is it needed to prevent
that the compiler coalesces this write with another write into the same
structure ?


The mutex only serializes cache writes. Cache reads could be done in concurrent with writes and are protected by the ACCESS_ONCE.

+        /* Make sure the sequence number we remeber was read

This looks like a typo - shouldn't the above read "remember" ?


Will be fixed in V4, thanks.

BTW, the style of that comment is recommended only for networking code
and not for IB code. Have you verified this patch with checkpatch ?


Of course and I've just re-run checkpatch on this patch. It doesn't catch this.

+    mutex_lock(&cache->lock);
+
+    for (ix = 0; ix < cache->sz; ix++)
+        if (cache->data_vec[ix].attr.ndev == ndev)
+            write_gid(ib_dev, port, cache, ix, &zgid, &zattr);
+
+    mutex_unlock(&cache->lock);
+    return 0;

The traditional Linux kernel coding style is one blank line before
mutex_lock() and after mutex_unlock() but not after mutex_lock() nor
before mutex_unlock().


I didn't find this in the CodingStyle doc. Could you please quote or post a link?

+    orig_seq = ACCESS_ONCE(cache->data_vec[index].seq);
+    /* Make sure we read the sequence number before copying the
+     * gid to local storage. */
+    smp_rmb();

Please use READ_ONCE() instead of ACCESS_ONCE() as recommended in
<linux/compiler.h>.


Ok, I'll change that in V4. I see that READ_ONCE and WRITE_ONCE is different from ACCESS_ONCE only for aggregated data types (which isn't our case), but it won't hurt to change that.

+static void free_roce_gid_cache(struct ib_device *ib_dev, u8 port)
+{
+    int i;
+    struct ib_roce_gid_cache *cache =
+        ib_dev->cache.roce_gid_cache[port - 1];
+
+    if (!cache)
+        return;
+
+    for (i = 0; i < cache->sz; ++i) {
+        if (memcmp(&cache->data_vec[i].gid, &zgid,
+               sizeof(cache->data_vec[i].gid)))
+            write_gid(ib_dev, port, cache, i, &zgid, &zattr);
+    }
 > +    kfree(cache->data_vec);
 > +    kfree(cache);
 > +}

Overwriting data just before it is freed is not useful. Please use
CONFIG_SLUB_DEBUG=y to debug use-after-free issues instead of such code.


It's mandatory as write_gid with zgid might cause the vendor driver to free memory it allocated for this GID entry (like in the mlx4 case).

Bart.

Thanks for the review :)

Matan
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to