summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/nvgpu/common
diff options
context:
space:
mode:
authorKonsta Holtta <kholtta@nvidia.com>2017-08-31 06:01:26 -0400
committermobile promotions <svcmobile_promotions@nvidia.com>2017-09-11 13:34:57 -0400
commit17451138cf60f5d64eed88cc5defd44981926d9d (patch)
treeea335a05d9e038876d42bcd8a73c56e3b60af1a5 /drivers/gpu/nvgpu/common
parentde0ce3e017decadd3a5049477f17ba770ddf074c (diff)
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 <kholtta@nvidia.com> Reviewed-on: https://git-master.nvidia.com/r/1549290 Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com> Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
Diffstat (limited to 'drivers/gpu/nvgpu/common')
-rw-r--r--drivers/gpu/nvgpu/common/linux/ioctl_as.c11
-rw-r--r--drivers/gpu/nvgpu/common/linux/ioctl_channel.c10
-rw-r--r--drivers/gpu/nvgpu/common/linux/ioctl_ctrl.c3
-rw-r--r--drivers/gpu/nvgpu/common/linux/ioctl_tsg.c2
4 files changed, 22 insertions, 4 deletions
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(
42 gk20a_dbg_fn(""); 42 gk20a_dbg_fn("");
43 43
44 ch = gk20a_get_channel_from_file(args->channel_fd); 44 ch = gk20a_get_channel_from_file(args->channel_fd);
45 if (!ch || gk20a_channel_as_bound(ch)) 45 if (!ch)
46 return -EINVAL; 46 return -EINVAL;
47 47
48 if (gk20a_channel_as_bound(ch)) {
49 err = -EINVAL;
50 goto out;
51 }
52
48 /* this will set channel_gk20a->vm */ 53 /* this will set channel_gk20a->vm */
49 err = ch->g->ops.mm.vm_bind_channel(as_share, ch); 54 err = ch->g->ops.mm.vm_bind_channel(as_share, ch);
50 if (err)
51 return err;
52 55
56out:
57 gk20a_channel_put(ch);
53 return err; 58 return err;
54} 59}
55 60
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,
260 return 0; 260 return 0;
261} 261}
262 262
263/*
264 * This returns the channel with a reference. The caller must
265 * gk20a_channel_put() the ref back after use.
266 *
267 * NULL is returned if the channel was not found.
268 */
263struct channel_gk20a *gk20a_get_channel_from_file(int fd) 269struct channel_gk20a *gk20a_get_channel_from_file(int fd)
264{ 270{
271 struct channel_gk20a *ch;
265 struct channel_priv *priv; 272 struct channel_priv *priv;
266 struct file *f = fget(fd); 273 struct file *f = fget(fd);
267 274
@@ -274,8 +281,9 @@ struct channel_gk20a *gk20a_get_channel_from_file(int fd)
274 } 281 }
275 282
276 priv = (struct channel_priv *)f->private_data; 283 priv = (struct channel_priv *)f->private_data;
284 ch = gk20a_channel_get(priv->c);
277 fput(f); 285 fput(f);
278 return priv->c; 286 return ch;
279} 287}
280 288
281int gk20a_channel_release(struct inode *inode, struct file *filp) 289int 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(
354 nvgpu_mutex_acquire(&g->dbg_sessions_lock); 354 nvgpu_mutex_acquire(&g->dbg_sessions_lock);
355 err = g->ops.gr.inval_icache(g, ch); 355 err = g->ops.gr.inval_icache(g, ch);
356 nvgpu_mutex_release(&g->dbg_sessions_lock); 356 nvgpu_mutex_release(&g->dbg_sessions_lock);
357
358 gk20a_channel_put(ch);
357 return err; 359 return err;
358} 360}
359 361
@@ -393,6 +395,7 @@ static int nvgpu_gpu_ioctl_set_debug_mode(
393 err = -ENOSYS; 395 err = -ENOSYS;
394 nvgpu_mutex_release(&g->dbg_sessions_lock); 396 nvgpu_mutex_release(&g->dbg_sessions_lock);
395 397
398 gk20a_channel_put(ch);
396 return err; 399 return err;
397} 400}
398 401
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)
49 return -EINVAL; 49 return -EINVAL;
50 50
51 err = ch->g->ops.fifo.tsg_bind_channel(tsg, ch); 51 err = ch->g->ops.fifo.tsg_bind_channel(tsg, ch);
52
53 gk20a_channel_put(ch);
52 return err; 54 return err;
53} 55}
54 56