Skip to content

Commit

Permalink
IB/umad: Fix error handling
Browse files Browse the repository at this point in the history
Avoid leaking a kref count in ib_umad_open() if port->ib_dev == NULL
or if nonseekable_open() fails.

Avoid leaking a kref count, that sm_sem is kept down and also that the
IB_PORT_SM capability mask is not cleared in ib_umad_sm_open() if
nonseekable_open() fails.

Since container_of() never returns NULL, remove the code that tests
whether container_of() returns NULL.

Moving the kref_get() call from the start of ib_umad_*open() to the
end is safe since it is the responsibility of the caller of these
functions to ensure that the cdev pointer remains valid until at least
when these functions return.

Signed-off-by: Bart Van Assche <bvanassche@acm.org>
Cc: <stable@vger.kernel.org>

[ydroneaud@opteya.com: rework a bit to reduce the amount of code changed]

Signed-off-by: Yann Droneaud <ydroneaud@opteya.com>

[ nonseekable_open() can't actually fail, but....  - Roland ]

Signed-off-by: Roland Dreier <roland@purestorage.com>
  • Loading branch information
bvanassche authored and rolandd committed May 30, 2014
1 parent d6d211d commit 8ec0a0e
Showing 1 changed file with 27 additions and 22 deletions.
49 changes: 27 additions & 22 deletions drivers/infiniband/core/user_mad.c
Original file line number Diff line number Diff line change
Expand Up @@ -780,27 +780,19 @@ static int ib_umad_open(struct inode *inode, struct file *filp)
{
struct ib_umad_port *port;
struct ib_umad_file *file;
int ret;
int ret = -ENXIO;

port = container_of(inode->i_cdev, struct ib_umad_port, cdev);
if (port)
kref_get(&port->umad_dev->ref);
else
return -ENXIO;

mutex_lock(&port->file_mutex);

if (!port->ib_dev) {
ret = -ENXIO;
if (!port->ib_dev)
goto out;
}

ret = -ENOMEM;
file = kzalloc(sizeof *file, GFP_KERNEL);
if (!file) {
kref_put(&port->umad_dev->ref, ib_umad_release_dev);
ret = -ENOMEM;
if (!file)
goto out;
}

mutex_init(&file->mutex);
spin_lock_init(&file->send_lock);
Expand All @@ -814,6 +806,13 @@ static int ib_umad_open(struct inode *inode, struct file *filp)
list_add_tail(&file->port_list, &port->file_list);

ret = nonseekable_open(inode, filp);
if (ret) {
list_del(&file->port_list);
kfree(file);
goto out;
}

kref_get(&port->umad_dev->ref);

out:
mutex_unlock(&port->file_mutex);
Expand Down Expand Up @@ -880,10 +879,6 @@ static int ib_umad_sm_open(struct inode *inode, struct file *filp)
int ret;

port = container_of(inode->i_cdev, struct ib_umad_port, sm_cdev);
if (port)
kref_get(&port->umad_dev->ref);
else
return -ENXIO;

if (filp->f_flags & O_NONBLOCK) {
if (down_trylock(&port->sm_sem)) {
Expand All @@ -898,17 +893,27 @@ static int ib_umad_sm_open(struct inode *inode, struct file *filp)
}

ret = ib_modify_port(port->ib_dev, port->port_num, 0, &props);
if (ret) {
up(&port->sm_sem);
goto fail;
}
if (ret)
goto err_up_sem;

filp->private_data = port;

return nonseekable_open(inode, filp);
ret = nonseekable_open(inode, filp);
if (ret)
goto err_clr_sm_cap;

kref_get(&port->umad_dev->ref);

return 0;

err_clr_sm_cap:
swap(props.set_port_cap_mask, props.clr_port_cap_mask);
ib_modify_port(port->ib_dev, port->port_num, 0, &props);

err_up_sem:
up(&port->sm_sem);

fail:
kref_put(&port->umad_dev->ref, ib_umad_release_dev);
return ret;
}

Expand Down

0 comments on commit 8ec0a0e

Please sign in to comment.