mlx5_core: Fix possible race between mr tree insert/delete
[linux-2.6-block.git] / drivers / net / ethernet / mellanox / mlx5 / core / mr.c
index ac52a0fe2d3af12ccda01d858a4f78d9eb7e2343..184c3615f4799bbda0adc0da0e265cacc6ae8bd6 100644 (file)
@@ -73,7 +73,7 @@ int mlx5_core_create_mkey(struct mlx5_core_dev *dev, struct mlx5_core_mr *mr,
        }
 
        if (err) {
-               mlx5_core_dbg(dev, "cmd exec faile %d\n", err);
+               mlx5_core_dbg(dev, "cmd exec failed %d\n", err);
                return err;
        }
 
@@ -94,6 +94,11 @@ int mlx5_core_create_mkey(struct mlx5_core_dev *dev, struct mlx5_core_mr *mr,
        write_lock_irq(&table->lock);
        err = radix_tree_insert(&table->tree, mlx5_base_mkey(mr->key), mr);
        write_unlock_irq(&table->lock);
+       if (err) {
+               mlx5_core_warn(dev, "failed radix tree insert of mr 0x%x, %d\n",
+                              mlx5_base_mkey(mr->key), err);
+               mlx5_core_destroy_mkey(dev, mr);
+       }
 
        return err;
 }
@@ -104,12 +109,22 @@ int mlx5_core_destroy_mkey(struct mlx5_core_dev *dev, struct mlx5_core_mr *mr)
        struct mlx5_mr_table *table = &dev->priv.mr_table;
        struct mlx5_destroy_mkey_mbox_in in;
        struct mlx5_destroy_mkey_mbox_out out;
+       struct mlx5_core_mr *deleted_mr;
        unsigned long flags;
        int err;
 
        memset(&in, 0, sizeof(in));
        memset(&out, 0, sizeof(out));
 
+       write_lock_irqsave(&table->lock, flags);
+       deleted_mr = radix_tree_delete(&table->tree, mlx5_base_mkey(mr->key));
+       write_unlock_irqrestore(&table->lock, flags);
+       if (!deleted_mr) {
+               mlx5_core_warn(dev, "failed radix tree delete of mr 0x%x\n",
+                              mlx5_base_mkey(mr->key));
+               return -ENOENT;
+       }
+
        in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_DESTROY_MKEY);
        in.mkey = cpu_to_be32(mlx5_mkey_to_idx(mr->key));
        err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out));
@@ -119,10 +134,6 @@ int mlx5_core_destroy_mkey(struct mlx5_core_dev *dev, struct mlx5_core_mr *mr)
        if (out.hdr.status)
                return mlx5_cmd_status_to_err(&out.hdr);
 
-       write_lock_irqsave(&table->lock, flags);
-       radix_tree_delete(&table->tree, mlx5_base_mkey(mr->key));
-       write_unlock_irqrestore(&table->lock, flags);
-
        return err;
 }
 EXPORT_SYMBOL(mlx5_core_destroy_mkey);
@@ -195,7 +206,8 @@ int mlx5_core_create_psv(struct mlx5_core_dev *dev, u32 pdn,
        }
 
        if (out.hdr.status) {
-               mlx5_core_err(dev, "create_psv bad status %d\n", out.hdr.status);
+               mlx5_core_err(dev, "create_psv bad status %d\n",
+                             out.hdr.status);
                return mlx5_cmd_status_to_err(&out.hdr);
        }
 
@@ -224,7 +236,8 @@ int mlx5_core_destroy_psv(struct mlx5_core_dev *dev, int psv_num)
        }
 
        if (out.hdr.status) {
-               mlx5_core_err(dev, "destroy_psv bad status %d\n", out.hdr.status);
+               mlx5_core_err(dev, "destroy_psv bad status %d\n",
+                             out.hdr.status);
                err = mlx5_cmd_status_to_err(&out.hdr);
                goto out;
        }