net/mlx5: Fix command bad flow on command entry allocation failure
authorMoshe Shemesh <moshe@mellanox.com>
Sun, 25 Jun 2017 15:45:32 +0000 (18:45 +0300)
committerSaeed Mahameed <saeedm@mellanox.com>
Thu, 27 Jul 2017 13:40:16 +0000 (16:40 +0300)
When driver fail to allocate an entry to send command to FW, it must
notify the calling function and release the memory allocated for
this command.

Fixes: e126ba97dba9e ('mlx5: Add driver for Mellanox Connect-IB adapters')
Signed-off-by: Moshe Shemesh <moshe@mellanox.com>
Cc: kernel-team@fb.com
Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
drivers/net/ethernet/mellanox/mlx5/core/cmd.c

index 25fd32fcdf79495c49f01e39e34f57e46ab66bac..31cbe5e86a01300bacd92db829d9ddc186e5db7a 100644 (file)
@@ -786,6 +786,10 @@ static void cb_timeout_handler(struct work_struct *work)
        mlx5_cmd_comp_handler(dev, 1UL << ent->idx, true);
 }
 
+static void free_msg(struct mlx5_core_dev *dev, struct mlx5_cmd_msg *msg);
+static void mlx5_free_cmd_msg(struct mlx5_core_dev *dev,
+                             struct mlx5_cmd_msg *msg);
+
 static void cmd_work_handler(struct work_struct *work)
 {
        struct mlx5_cmd_work_ent *ent = container_of(work, struct mlx5_cmd_work_ent, work);
@@ -796,17 +800,28 @@ static void cmd_work_handler(struct work_struct *work)
        struct semaphore *sem;
        unsigned long flags;
        bool poll_cmd = ent->polling;
+       int alloc_ret;
 
 
        sem = ent->page_queue ? &cmd->pages_sem : &cmd->sem;
        down(sem);
        if (!ent->page_queue) {
-               ent->idx = alloc_ent(cmd);
-               if (ent->idx < 0) {
+               alloc_ret = alloc_ent(cmd);
+               if (alloc_ret < 0) {
                        mlx5_core_err(dev, "failed to allocate command entry\n");
+                       if (ent->callback) {
+                               ent->callback(-EAGAIN, ent->context);
+                               mlx5_free_cmd_msg(dev, ent->out);
+                               free_msg(dev, ent->in);
+                               free_cmd(ent);
+                       } else {
+                               ent->ret = -EAGAIN;
+                               complete(&ent->done);
+                       }
                        up(sem);
                        return;
                }
+               ent->idx = alloc_ret;
        } else {
                ent->idx = cmd->max_reg_cmds;
                spin_lock_irqsave(&cmd->alloc_lock, flags);