diff options
author | Sagar Kamble <skamble@nvidia.com> | 2020-10-10 00:04:13 -0400 |
---|---|---|
committer | mobile promotions <svcmobile_promotions@nvidia.com> | 2021-05-10 23:40:10 -0400 |
commit | 24a08ffaf92b57699e8cb90880eb94b14a0429f5 (patch) | |
tree | 5a841d5593b62362b0075604d55319f9ae93b49b /drivers/video/tegra | |
parent | a3c08fdbdb3508ac4895fd159aaabff576fdcd14 (diff) |
video: tegra: nvmap: export dma_buf as RO when NVMAP_HANDLE_RO is set
Following kernel BUG is encountered when closing the file whose mode is
overridden to RO throgh fmode field as inode->i_readcount is not
initialized for the file. This is seen when running the test
NvRmGpuTest_Channel_SimplestPb_RoMappedBuffer_From_CPUVA on
K5.9.
The correct way to set the file mode as RO is to export the dma_buf as
RO that will initialize inode->i_readcount properly.
[ 1228.027800] kernel BUG at kernel/kernel-5.9/include/linux/fs.h:2842!
[ 1228.035330] Internal error: Oops - BUG: 0 [#3] PREEMPT SMP
[ 1228.115034] Hardware name: Jetson-AGX (DT)
[ 1228.119234] pstate: 60400009 (nZCv daif +PAN -UAO BTYPE=--)
[ 1228.125023] pc : __fput+0x22c/0x230
[ 1228.128690] lr : __fput+0xa4/0x230
[ 1228.216800] Call trace:
[ 1228.219258] __fput+0x22c/0x230
[ 1228.222407] ____fput+0x20/0x30
[ 1228.225388] task_work_run+0x88/0x140
[ 1228.228886] do_notify_resume+0x204/0x868
[ 1228.233080] work_pending+0x8/0x204
[ 1228.236583] Code: 17ffff8e aa1703e0 9400b26f 17ffffa6 (d4210000)
[ 1228.242702] ---[ end trace af706a6663eb46e5 ]---
[ 1228.247252] note: nvrm_gpu_tests[1156] exited with preempt_count 1
Bug 200660013
Change-Id: Ie238f59a46aa7b016249a01e39e7bbd73ecfab02
Signed-off-by: Sagar Kamble <skamble@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvidia/+/2515024
(cherry picked from commit 891dc46b2e85424fc81544a83d6752eb1ea57dae)
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvidia/+/2521315
Reviewed-by: svc-mobile-coverity <svc-mobile-coverity@nvidia.com>
Reviewed-by: Puneet Saxena <puneets@nvidia.com>
Reviewed-by: Bibek Basu <bbasu@nvidia.com>
Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com>
Tested-by: Amulya Yarlagadda <ayarlagadda@nvidia.com>
Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
GVS: Gerrit_Virtual_Submit
Diffstat (limited to 'drivers/video/tegra')
-rw-r--r-- | drivers/video/tegra/nvmap/nvmap_dmabuf.c | 20 | ||||
-rw-r--r-- | drivers/video/tegra/nvmap/nvmap_handle.c | 6 | ||||
-rw-r--r-- | drivers/video/tegra/nvmap/nvmap_ioctl.c | 4 | ||||
-rw-r--r-- | drivers/video/tegra/nvmap/nvmap_priv.h | 4 |
4 files changed, 17 insertions, 17 deletions
diff --git a/drivers/video/tegra/nvmap/nvmap_dmabuf.c b/drivers/video/tegra/nvmap/nvmap_dmabuf.c index 3424bb7f8..54f514546 100644 --- a/drivers/video/tegra/nvmap/nvmap_dmabuf.c +++ b/drivers/video/tegra/nvmap/nvmap_dmabuf.c | |||
@@ -607,14 +607,20 @@ EXPORT_SYMBOL(dmabuf_is_nvmap); | |||
607 | 607 | ||
608 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0) | 608 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0) |
609 | static struct dma_buf *__dma_buf_export(struct nvmap_handle_info *info, | 609 | static struct dma_buf *__dma_buf_export(struct nvmap_handle_info *info, |
610 | size_t size) | 610 | size_t size, bool ro_buf) |
611 | { | 611 | { |
612 | DEFINE_DMA_BUF_EXPORT_INFO(exp_info); | 612 | DEFINE_DMA_BUF_EXPORT_INFO(exp_info); |
613 | 613 | ||
614 | exp_info.priv = info; | 614 | exp_info.priv = info; |
615 | exp_info.ops = &nvmap_dma_buf_ops; | 615 | exp_info.ops = &nvmap_dma_buf_ops; |
616 | exp_info.size = size; | 616 | exp_info.size = size; |
617 | exp_info.flags = O_RDWR; | 617 | |
618 | if (ro_buf) { | ||
619 | exp_info.flags = O_RDONLY; | ||
620 | } else { | ||
621 | exp_info.flags = O_RDWR; | ||
622 | } | ||
623 | |||
618 | exp_info.exp_flags = DMABUF_CAN_DEFER_UNMAP | | 624 | exp_info.exp_flags = DMABUF_CAN_DEFER_UNMAP | |
619 | DMABUF_SKIP_CACHE_SYNC; | 625 | DMABUF_SKIP_CACHE_SYNC; |
620 | 626 | ||
@@ -629,7 +635,7 @@ static struct dma_buf *__dma_buf_export(struct nvmap_handle_info *info, | |||
629 | * Make a dmabuf object for an nvmap handle. | 635 | * Make a dmabuf object for an nvmap handle. |
630 | */ | 636 | */ |
631 | struct dma_buf *__nvmap_make_dmabuf(struct nvmap_client *client, | 637 | struct dma_buf *__nvmap_make_dmabuf(struct nvmap_client *client, |
632 | struct nvmap_handle *handle) | 638 | struct nvmap_handle *handle, bool ro_buf) |
633 | { | 639 | { |
634 | int err; | 640 | int err; |
635 | struct dma_buf *dmabuf; | 641 | struct dma_buf *dmabuf; |
@@ -644,7 +650,7 @@ struct dma_buf *__nvmap_make_dmabuf(struct nvmap_client *client, | |||
644 | INIT_LIST_HEAD(&info->maps); | 650 | INIT_LIST_HEAD(&info->maps); |
645 | mutex_init(&info->maps_lock); | 651 | mutex_init(&info->maps_lock); |
646 | 652 | ||
647 | dmabuf = __dma_buf_export(info, handle->size); | 653 | dmabuf = __dma_buf_export(info, handle->size, ro_buf); |
648 | if (IS_ERR(dmabuf)) { | 654 | if (IS_ERR(dmabuf)) { |
649 | err = PTR_ERR(dmabuf); | 655 | err = PTR_ERR(dmabuf); |
650 | goto err_export; | 656 | goto err_export; |
@@ -689,12 +695,6 @@ int nvmap_get_dmabuf_fd(struct nvmap_client *client, struct nvmap_handle *h) | |||
689 | dmabuf = __nvmap_dmabuf_export(client, h); | 695 | dmabuf = __nvmap_dmabuf_export(client, h); |
690 | if (IS_ERR(dmabuf)) | 696 | if (IS_ERR(dmabuf)) |
691 | return PTR_ERR(dmabuf); | 697 | return PTR_ERR(dmabuf); |
692 | /* | ||
693 | * If the user allocated buffer is ReadOnly, make | ||
694 | * dma_buf ReadOnly. | ||
695 | */ | ||
696 | if (h->is_ro) | ||
697 | dmabuf->file->f_mode &= ~(FMODE_WRITE | FMODE_PWRITE); | ||
698 | 698 | ||
699 | fd = __nvmap_dmabuf_fd(client, dmabuf, O_CLOEXEC); | 699 | fd = __nvmap_dmabuf_fd(client, dmabuf, O_CLOEXEC); |
700 | if (IS_ERR_VALUE((uintptr_t)fd)) | 700 | if (IS_ERR_VALUE((uintptr_t)fd)) |
diff --git a/drivers/video/tegra/nvmap/nvmap_handle.c b/drivers/video/tegra/nvmap/nvmap_handle.c index 8df4b3a71..7a58f1c68 100644 --- a/drivers/video/tegra/nvmap/nvmap_handle.c +++ b/drivers/video/tegra/nvmap/nvmap_handle.c | |||
@@ -186,7 +186,7 @@ struct nvmap_handle_ref *nvmap_create_handle_from_va(struct nvmap_client *client | |||
186 | if (!(vm_flags & VM_WRITE) && !(flags & NVMAP_HANDLE_RO)) | 186 | if (!(vm_flags & VM_WRITE) && !(flags & NVMAP_HANDLE_RO)) |
187 | return ERR_PTR(-EINVAL); | 187 | return ERR_PTR(-EINVAL); |
188 | 188 | ||
189 | ref = nvmap_create_handle(client, size); | 189 | ref = nvmap_create_handle(client, size, flags & NVMAP_HANDLE_RO); |
190 | if (!IS_ERR(ref)) | 190 | if (!IS_ERR(ref)) |
191 | ref->handle->orig_size = size; | 191 | ref->handle->orig_size = size; |
192 | 192 | ||
@@ -194,7 +194,7 @@ struct nvmap_handle_ref *nvmap_create_handle_from_va(struct nvmap_client *client | |||
194 | } | 194 | } |
195 | 195 | ||
196 | struct nvmap_handle_ref *nvmap_create_handle(struct nvmap_client *client, | 196 | struct nvmap_handle_ref *nvmap_create_handle(struct nvmap_client *client, |
197 | size_t size) | 197 | size_t size, bool ro_buf) |
198 | { | 198 | { |
199 | void *err = ERR_PTR(-ENOMEM); | 199 | void *err = ERR_PTR(-ENOMEM); |
200 | struct nvmap_handle *h; | 200 | struct nvmap_handle *h; |
@@ -231,7 +231,7 @@ struct nvmap_handle_ref *nvmap_create_handle(struct nvmap_client *client, | |||
231 | * This takes out 1 ref on the dambuf. This corresponds to the | 231 | * This takes out 1 ref on the dambuf. This corresponds to the |
232 | * handle_ref that gets automatically made by nvmap_create_handle(). | 232 | * handle_ref that gets automatically made by nvmap_create_handle(). |
233 | */ | 233 | */ |
234 | h->dmabuf = __nvmap_make_dmabuf(client, h); | 234 | h->dmabuf = __nvmap_make_dmabuf(client, h, ro_buf); |
235 | if (IS_ERR(h->dmabuf)) { | 235 | if (IS_ERR(h->dmabuf)) { |
236 | err = h->dmabuf; | 236 | err = h->dmabuf; |
237 | goto make_dmabuf_fail; | 237 | goto make_dmabuf_fail; |
diff --git a/drivers/video/tegra/nvmap/nvmap_ioctl.c b/drivers/video/tegra/nvmap/nvmap_ioctl.c index e67077768..a6a29b9e0 100644 --- a/drivers/video/tegra/nvmap/nvmap_ioctl.c +++ b/drivers/video/tegra/nvmap/nvmap_ioctl.c | |||
@@ -223,7 +223,7 @@ int nvmap_ioctl_create(struct file *filp, unsigned int cmd, void __user *arg) | |||
223 | op.size64 = op.size; | 223 | op.size64 = op.size; |
224 | 224 | ||
225 | if ((cmd == NVMAP_IOC_CREATE) || (cmd == NVMAP_IOC_CREATE_64)) { | 225 | if ((cmd == NVMAP_IOC_CREATE) || (cmd == NVMAP_IOC_CREATE_64)) { |
226 | ref = nvmap_create_handle(client, op.size64); | 226 | ref = nvmap_create_handle(client, op.size64, false); |
227 | if (!IS_ERR(ref)) | 227 | if (!IS_ERR(ref)) |
228 | ref->handle->orig_size = op.size64; | 228 | ref->handle->orig_size = op.size64; |
229 | } else if (cmd == NVMAP_IOC_FROM_FD) { | 229 | } else if (cmd == NVMAP_IOC_FROM_FD) { |
@@ -632,7 +632,7 @@ int nvmap_ioctl_create_from_ivc(struct file *filp, void __user *arg) | |||
632 | ((1ULL << NVMAP_IVM_LENGTH_WIDTH) - 1)) << PAGE_SHIFT; | 632 | ((1ULL << NVMAP_IVM_LENGTH_WIDTH) - 1)) << PAGE_SHIFT; |
633 | peer = (op.ivm_id >> NVMAP_IVM_IVMID_SHIFT); | 633 | peer = (op.ivm_id >> NVMAP_IVM_IVMID_SHIFT); |
634 | 634 | ||
635 | ref = nvmap_create_handle(client, size); | 635 | ref = nvmap_create_handle(client, size, false); |
636 | if (IS_ERR(ref)) { | 636 | if (IS_ERR(ref)) { |
637 | nvmap_heap_free(block); | 637 | nvmap_heap_free(block); |
638 | return PTR_ERR(ref); | 638 | return PTR_ERR(ref); |
diff --git a/drivers/video/tegra/nvmap/nvmap_priv.h b/drivers/video/tegra/nvmap/nvmap_priv.h index 1e7b01f1f..0d6ea52f1 100644 --- a/drivers/video/tegra/nvmap/nvmap_priv.h +++ b/drivers/video/tegra/nvmap/nvmap_priv.h | |||
@@ -382,7 +382,7 @@ struct nvmap_handle_ref *__nvmap_validate_locked(struct nvmap_client *priv, | |||
382 | struct nvmap_handle *nvmap_validate_get(struct nvmap_handle *h); | 382 | struct nvmap_handle *nvmap_validate_get(struct nvmap_handle *h); |
383 | 383 | ||
384 | struct nvmap_handle_ref *nvmap_create_handle(struct nvmap_client *client, | 384 | struct nvmap_handle_ref *nvmap_create_handle(struct nvmap_client *client, |
385 | size_t size); | 385 | size_t size, bool ro_buf); |
386 | 386 | ||
387 | struct nvmap_handle_ref *nvmap_create_handle_from_va(struct nvmap_client *client, | 387 | struct nvmap_handle_ref *nvmap_create_handle_from_va(struct nvmap_client *client, |
388 | ulong addr, size_t size, | 388 | ulong addr, size_t size, |
@@ -468,7 +468,7 @@ int nvmap_cache_debugfs_init(struct dentry *nvmap_root); | |||
468 | struct dma_buf *__nvmap_dmabuf_export(struct nvmap_client *client, | 468 | struct dma_buf *__nvmap_dmabuf_export(struct nvmap_client *client, |
469 | struct nvmap_handle *handle); | 469 | struct nvmap_handle *handle); |
470 | struct dma_buf *__nvmap_make_dmabuf(struct nvmap_client *client, | 470 | struct dma_buf *__nvmap_make_dmabuf(struct nvmap_client *client, |
471 | struct nvmap_handle *handle); | 471 | struct nvmap_handle *handle, bool ro_buf); |
472 | struct sg_table *__nvmap_sg_table(struct nvmap_client *client, | 472 | struct sg_table *__nvmap_sg_table(struct nvmap_client *client, |
473 | struct nvmap_handle *h); | 473 | struct nvmap_handle *h); |
474 | void __nvmap_free_sg_table(struct nvmap_client *client, | 474 | void __nvmap_free_sg_table(struct nvmap_client *client, |