summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/nvgpu/gk20a/dbg_gpu_gk20a.c
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/gk20a/dbg_gpu_gk20a.c
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/gk20a/dbg_gpu_gk20a.c')
-rw-r--r--drivers/gpu/nvgpu/gk20a/dbg_gpu_gk20a.c39
1 files changed, 28 insertions, 11 deletions
diff --git a/drivers/gpu/nvgpu/gk20a/dbg_gpu_gk20a.c b/drivers/gpu/nvgpu/gk20a/dbg_gpu_gk20a.c
index 00050850..19433df9 100644
--- a/drivers/gpu/nvgpu/gk20a/dbg_gpu_gk20a.c
+++ b/drivers/gpu/nvgpu/gk20a/dbg_gpu_gk20a.c
@@ -514,7 +514,8 @@ static int dbg_unbind_channel_gk20a(struct dbg_session_gk20a *dbg_s,
514 514
515 if (!channel_found) { 515 if (!channel_found) {
516 gk20a_dbg_fn("channel not bounded, fd=%d\n", args->channel_fd); 516 gk20a_dbg_fn("channel not bounded, fd=%d\n", args->channel_fd);
517 return -EINVAL; 517 err = -EINVAL;
518 goto out;
518 } 519 }
519 520
520 nvgpu_mutex_acquire(&g->dbg_sessions_lock); 521 nvgpu_mutex_acquire(&g->dbg_sessions_lock);
@@ -523,6 +524,8 @@ static int dbg_unbind_channel_gk20a(struct dbg_session_gk20a *dbg_s,
523 nvgpu_mutex_release(&dbg_s->ch_list_lock); 524 nvgpu_mutex_release(&dbg_s->ch_list_lock);
524 nvgpu_mutex_release(&g->dbg_sessions_lock); 525 nvgpu_mutex_release(&g->dbg_sessions_lock);
525 526
527out:
528 gk20a_channel_put(ch);
526 return err; 529 return err;
527} 530}
528 531
@@ -584,13 +587,16 @@ static int dbg_bind_channel_gk20a(struct dbg_session_gk20a *dbg_s,
584 struct channel_gk20a *ch; 587 struct channel_gk20a *ch;
585 struct dbg_session_channel_data *ch_data; 588 struct dbg_session_channel_data *ch_data;
586 struct dbg_session_data *session_data; 589 struct dbg_session_data *session_data;
590 int err = 0;
587 591
588 gk20a_dbg(gpu_dbg_fn|gpu_dbg_gpu_dbg, "%s fd=%d", 592 gk20a_dbg(gpu_dbg_fn|gpu_dbg_gpu_dbg, "%s fd=%d",
589 g->name, args->channel_fd); 593 g->name, args->channel_fd);
590 594
591 /* even though get_file_channel is doing this it releases it as well */ 595 /*
592 /* by holding it here we'll keep it from disappearing while the 596 * Although gk20a_get_channel_from_file gives us a channel ref, need to
593 * debugger is in session */ 597 * hold a ref to the file during the session lifetime. See comment in
598 * struct dbg_session_channel_data.
599 */
594 f = fget(args->channel_fd); 600 f = fget(args->channel_fd);
595 if (!f) 601 if (!f)
596 return -ENODEV; 602 return -ENODEV;
@@ -598,8 +604,8 @@ static int dbg_bind_channel_gk20a(struct dbg_session_gk20a *dbg_s,
598 ch = gk20a_get_channel_from_file(args->channel_fd); 604 ch = gk20a_get_channel_from_file(args->channel_fd);
599 if (!ch) { 605 if (!ch) {
600 gk20a_dbg_fn("no channel found for fd"); 606 gk20a_dbg_fn("no channel found for fd");
601 fput(f); 607 err = -EINVAL;
602 return -EINVAL; 608 goto out_fput;
603 } 609 }
604 610
605 gk20a_dbg_fn("%s hwchid=%d", g->name, ch->chid); 611 gk20a_dbg_fn("%s hwchid=%d", g->name, ch->chid);
@@ -609,8 +615,8 @@ static int dbg_bind_channel_gk20a(struct dbg_session_gk20a *dbg_s,
609 615
610 ch_data = nvgpu_kzalloc(g, sizeof(*ch_data)); 616 ch_data = nvgpu_kzalloc(g, sizeof(*ch_data));
611 if (!ch_data) { 617 if (!ch_data) {
612 fput(f); 618 err = -ENOMEM;
613 return -ENOMEM; 619 goto out_chput;
614 } 620 }
615 ch_data->ch_f = f; 621 ch_data->ch_f = f;
616 ch_data->channel_fd = args->channel_fd; 622 ch_data->channel_fd = args->channel_fd;
@@ -619,9 +625,8 @@ static int dbg_bind_channel_gk20a(struct dbg_session_gk20a *dbg_s,
619 625
620 session_data = nvgpu_kzalloc(g, sizeof(*session_data)); 626 session_data = nvgpu_kzalloc(g, sizeof(*session_data));
621 if (!session_data) { 627 if (!session_data) {
622 nvgpu_kfree(g, ch_data); 628 err = -ENOMEM;
623 fput(f); 629 goto out_kfree;
624 return -ENOMEM;
625 } 630 }
626 session_data->dbg_s = dbg_s; 631 session_data->dbg_s = dbg_s;
627 nvgpu_init_list_node(&session_data->dbg_s_entry); 632 nvgpu_init_list_node(&session_data->dbg_s_entry);
@@ -636,7 +641,19 @@ static int dbg_bind_channel_gk20a(struct dbg_session_gk20a *dbg_s,
636 nvgpu_mutex_release(&ch->dbg_s_lock); 641 nvgpu_mutex_release(&ch->dbg_s_lock);
637 nvgpu_mutex_release(&g->dbg_sessions_lock); 642 nvgpu_mutex_release(&g->dbg_sessions_lock);
638 643
644 gk20a_channel_put(ch);
645
639 return 0; 646 return 0;
647
648out_kfree:
649 nvgpu_kfree(g, ch_data);
650out_chput:
651 gk20a_channel_put(ch);
652 nvgpu_mutex_release(&ch->dbg_s_lock);
653 nvgpu_mutex_release(&g->dbg_sessions_lock);
654out_fput:
655 fput(f);
656 return err;
640} 657}
641 658
642static int nvgpu_ioctl_channel_reg_ops(struct dbg_session_gk20a *dbg_s, 659static int nvgpu_ioctl_channel_reg_ops(struct dbg_session_gk20a *dbg_s,