From 17451138cf60f5d64eed88cc5defd44981926d9d Mon Sep 17 00:00:00 2001 From: Konsta Holtta Date: Thu, 31 Aug 2017 13:01:26 +0300 Subject: gpu: nvgpu: hold ch ref when getting ch from fd Fix a race condition in gk20a_get_channel_from_file() that returns a channel pointer from an fd: take a reference to the channel before putting the file ref back. Now the caller is responsible of releasing the channel reference eventually. Also document why dbg_session_channel_data has to hold a ref to the channel file instead of just the channel: that might deadlock if the fds were closed in "wrong" order. Change-Id: I8e91b809f5f7b1cb0c1487bd955ad6d643727a53 Signed-off-by: Konsta Holtta Reviewed-on: https://git-master.nvidia.com/r/1549290 Reviewed-by: mobile promotions Tested-by: mobile promotions --- drivers/gpu/nvgpu/common/linux/ioctl_as.c | 11 ++++++++--- drivers/gpu/nvgpu/common/linux/ioctl_channel.c | 10 +++++++++- drivers/gpu/nvgpu/common/linux/ioctl_ctrl.c | 3 +++ drivers/gpu/nvgpu/common/linux/ioctl_tsg.c | 2 ++ 4 files changed, 22 insertions(+), 4 deletions(-) (limited to 'drivers/gpu/nvgpu/common') diff --git a/drivers/gpu/nvgpu/common/linux/ioctl_as.c b/drivers/gpu/nvgpu/common/linux/ioctl_as.c index 6fd0a3d2..d4242955 100644 --- a/drivers/gpu/nvgpu/common/linux/ioctl_as.c +++ b/drivers/gpu/nvgpu/common/linux/ioctl_as.c @@ -42,14 +42,19 @@ static int gk20a_as_ioctl_bind_channel( gk20a_dbg_fn(""); ch = gk20a_get_channel_from_file(args->channel_fd); - if (!ch || gk20a_channel_as_bound(ch)) + if (!ch) return -EINVAL; + if (gk20a_channel_as_bound(ch)) { + err = -EINVAL; + goto out; + } + /* this will set channel_gk20a->vm */ err = ch->g->ops.mm.vm_bind_channel(as_share, ch); - if (err) - return err; +out: + gk20a_channel_put(ch); return err; } diff --git a/drivers/gpu/nvgpu/common/linux/ioctl_channel.c b/drivers/gpu/nvgpu/common/linux/ioctl_channel.c index ab02dc42..5e09c677 100644 --- a/drivers/gpu/nvgpu/common/linux/ioctl_channel.c +++ b/drivers/gpu/nvgpu/common/linux/ioctl_channel.c @@ -260,8 +260,15 @@ static int gk20a_init_error_notifier(struct channel_gk20a *ch, return 0; } +/* + * This returns the channel with a reference. The caller must + * gk20a_channel_put() the ref back after use. + * + * NULL is returned if the channel was not found. + */ struct channel_gk20a *gk20a_get_channel_from_file(int fd) { + struct channel_gk20a *ch; struct channel_priv *priv; struct file *f = fget(fd); @@ -274,8 +281,9 @@ struct channel_gk20a *gk20a_get_channel_from_file(int fd) } priv = (struct channel_priv *)f->private_data; + ch = gk20a_channel_get(priv->c); fput(f); - return priv->c; + return ch; } int gk20a_channel_release(struct inode *inode, struct file *filp) diff --git a/drivers/gpu/nvgpu/common/linux/ioctl_ctrl.c b/drivers/gpu/nvgpu/common/linux/ioctl_ctrl.c index 2c274f23..0d79b143 100644 --- a/drivers/gpu/nvgpu/common/linux/ioctl_ctrl.c +++ b/drivers/gpu/nvgpu/common/linux/ioctl_ctrl.c @@ -354,6 +354,8 @@ static int nvgpu_gpu_ioctl_inval_icache( nvgpu_mutex_acquire(&g->dbg_sessions_lock); err = g->ops.gr.inval_icache(g, ch); nvgpu_mutex_release(&g->dbg_sessions_lock); + + gk20a_channel_put(ch); return err; } @@ -393,6 +395,7 @@ static int nvgpu_gpu_ioctl_set_debug_mode( err = -ENOSYS; nvgpu_mutex_release(&g->dbg_sessions_lock); + gk20a_channel_put(ch); return err; } diff --git a/drivers/gpu/nvgpu/common/linux/ioctl_tsg.c b/drivers/gpu/nvgpu/common/linux/ioctl_tsg.c index c68c907e..d35ea14c 100644 --- a/drivers/gpu/nvgpu/common/linux/ioctl_tsg.c +++ b/drivers/gpu/nvgpu/common/linux/ioctl_tsg.c @@ -49,6 +49,8 @@ static int gk20a_tsg_bind_channel_fd(struct tsg_gk20a *tsg, int ch_fd) return -EINVAL; err = ch->g->ops.fifo.tsg_bind_channel(tsg, ch); + + gk20a_channel_put(ch); return err; } -- cgit v1.2.2