diff options
author | Arto Merilainen <amerilainen@nvidia.com> | 2014-10-14 10:12:26 +0300 |
---|---|---|
committer | Winnie Hsu <whsu@nvidia.com> | 2017-05-05 14:56:39 -0700 |
commit | b05568ec3820faf539b307deb4ae8ac036994cf5 (patch) | |
tree | 867dc1d4c40c39f4ad78fff32aa103744fddcd6e /drivers | |
parent | 5cbb7a316b9c0d530f2d64f98946ce064d075857 (diff) |
video: tegra: host: Protect channel ioctl
Channel ioctl interface is not multithreading safe and as the
common case is that we have only a single active user for an open
fd, add a mutex to force serialization of ioctl calls.
Bug 1830021
Change-Id: Ifa6595a105b913345104f216f0541c371e89efe5
(cherry picked from commit 7b24caa9a8d2ab08fe0c7be112e805e44906d956)
Signed-off-by: Gagan Grover <ggrover@nvidia.com>
Reviewed-on: http://git-master/r/1248801
Reviewed-by: Bibek Basu <bbasu@nvidia.com>
Reviewed-by: Automatic_Commit_Validation_User
GVS: Gerrit_Virtual_Submit
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/video/tegra/host/bus_client.c | 58 |
1 files changed, 43 insertions, 15 deletions
diff --git a/drivers/video/tegra/host/bus_client.c b/drivers/video/tegra/host/bus_client.c index ee21c80e6871..4a5e2f558451 100644 --- a/drivers/video/tegra/host/bus_client.c +++ b/drivers/video/tegra/host/bus_client.c @@ -173,6 +173,9 @@ struct nvhost_channel_userctx { u32 priority; int clientid; bool timeout_debug_dump; + + /* lock to protect this structure from concurrent ioctl usage */ + struct mutex ioctl_lock; }; static int nvhost_channelrelease(struct inode *inode, struct file *filp) @@ -276,6 +279,7 @@ static int __nvhost_channelopen(struct inode *inode, pdata = dev_get_drvdata(ch->dev->dev.parent); priv->timeout = pdata->nvhost_timeout_default; priv->timeout_debug_dump = true; + mutex_init(&priv->ioctl_lock); if (!tegra_platform_is_silicon()) priv->timeout = 0; mutex_unlock(&channel_lock); @@ -752,8 +756,12 @@ static long nvhost_channelctl(struct file *filp, return -EFAULT; } + /* serialize calls from this fd */ + mutex_lock(&priv->ioctl_lock); + if (!priv->ch->dev) { pr_warn("Channel already unmapped\n"); + mutex_unlock(&priv->ioctl_lock); return -EFAULT; } @@ -811,8 +819,12 @@ static long nvhost_channelctl(struct file *filp, platform_get_drvdata(priv->ch->dev); struct nvhost_get_param_arg *arg = (struct nvhost_get_param_arg *)buf; - if (arg->param >= NVHOST_MODULE_MAX_SYNCPTS) - return -EINVAL; + + if (arg->param >= NVHOST_MODULE_MAX_SYNCPTS) { + err = -EINVAL; + break; + } + /* if we already have required syncpt then return it ... */ if (pdata->syncpts[arg->param]) { arg->value = pdata->syncpts[arg->param]; @@ -821,8 +833,10 @@ static long nvhost_channelctl(struct file *filp, /* ... otherwise get a new syncpt dynamically */ arg->value = nvhost_get_syncpt_host_managed(pdata->pdev, arg->param); - if (!arg->value) - return -EAGAIN; + if (!arg->value) { + err = -EAGAIN; + break; + } /* ... and store it for further references */ pdata->syncpts[arg->param] = arg->value; break; @@ -840,8 +854,10 @@ static long nvhost_channelctl(struct file *filp, if (args_name) { if (strncpy_from_user(name, args_name, - sizeof(name)) < 0) - return -EFAULT; + sizeof(name)) < 0) { + err = -EFAULT; + break; + } name[sizeof(name) - 1] = '\0'; } else { name[0] = '\0'; @@ -855,8 +871,10 @@ static long nvhost_channelctl(struct file *filp, snprintf(set_name, sizeof(set_name), "%s_%s", dev_name(&pdata->pdev->dev), name); args->value = nvhost_get_syncpt_client_managed(set_name); - if (!args->value) - return -EAGAIN; + if (!args->value) { + err = -EAGAIN; + break; + } /* ... and store it for further references */ pdata->client_managed_syncpt = args->value; break; @@ -869,8 +887,10 @@ static long nvhost_channelctl(struct file *filp, platform_get_drvdata(priv->ch->dev); if (!args->value) break; - if (args->value != pdata->client_managed_syncpt) - return -EINVAL; + if (args->value != pdata->client_managed_syncpt) { + err = -EINVAL; + break; + } nvhost_free_syncpt(args->value); pdata->client_managed_syncpt = 0; break; @@ -891,8 +911,10 @@ static long nvhost_channelctl(struct file *filp, struct nvhost_get_param_arg *arg = (struct nvhost_get_param_arg *)buf; if (arg->param >= NVHOST_MODULE_MAX_WAITBASES - || !pdata->waitbases[arg->param]) - return -EINVAL; + || !pdata->waitbases[arg->param]) { + err = -EINVAL; + break; + } arg->value = pdata->waitbases[arg->param]; break; } @@ -911,9 +933,13 @@ static long nvhost_channelctl(struct file *filp, platform_get_drvdata(priv->ch->dev); struct nvhost_get_param_arg *arg = (struct nvhost_get_param_arg *)buf; - if (arg->param >= NVHOST_MODULE_MAX_MODMUTEXES - || !pdata->modulemutexes[arg->param]) - return -EINVAL; + + if (arg->param >= NVHOST_MODULE_MAX_MODMUTEXES || + !pdata->modulemutexes[arg->param]) { + err = -EINVAL; + break; + } + arg->value = pdata->modulemutexes[arg->param]; break; } @@ -1032,6 +1058,8 @@ static long nvhost_channelctl(struct file *filp, break; } + mutex_unlock(&priv->ioctl_lock); + if ((err == 0) && (_IOC_DIR(cmd) & _IOC_READ)) err = copy_to_user((void __user *)arg, buf, _IOC_SIZE(cmd)); |