* [PATCH 0/3] Refactor media IOCTL handling
@ 2016-04-29 8:43 Sakari Ailus
2016-04-29 8:43 ` [PATCH 1/3] media: Determine early whether an IOCTL is supported Sakari Ailus
` (2 more replies)
0 siblings, 3 replies; 4+ messages in thread
From: Sakari Ailus @ 2016-04-29 8:43 UTC (permalink / raw)
To: linux-media; +Cc: mchehab, laurent.pinchart, hverkuil
A number of years ago when someone (read: Laurent) added a new IOCTL to
the MC interface, I wanted IOCTL handling to be refactored. That wasn't
done however, so here are patches to do just that: there are too many
IOCTLs that copy the argument struct from the user and back.
The changes will also make the request API patches a little bit cleaner as
the argument copying is removed there. I'll post an RFC set on those in
the near future.
--
Kind regards,
Sakari
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH 1/3] media: Determine early whether an IOCTL is supported
2016-04-29 8:43 [PATCH 0/3] Refactor media IOCTL handling Sakari Ailus
@ 2016-04-29 8:43 ` Sakari Ailus
2016-04-29 8:43 ` [PATCH 2/3] media: Refactor copying IOCTL arguments from and to user space Sakari Ailus
2016-04-29 8:43 ` [PATCH 3/3] media: Refactor IOCTL handler calling Sakari Ailus
2 siblings, 0 replies; 4+ messages in thread
From: Sakari Ailus @ 2016-04-29 8:43 UTC (permalink / raw)
To: linux-media; +Cc: mchehab, laurent.pinchart, hverkuil
Preparation for refactoring media IOCTL handling to unify common parts.
Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
---
drivers/media/media-device.c | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c
index 898a3cf..6d3ee5c 100644
--- a/drivers/media/media-device.c
+++ b/drivers/media/media-device.c
@@ -419,6 +419,20 @@ static long media_device_get_topology(struct media_device *mdev,
return 0;
}
+#define MEDIA_IOC(__cmd) \
+ [_IOC_NR(MEDIA_IOC_##__cmd)] = { .cmd = MEDIA_IOC_##__cmd }
+
+/* the table is indexed by _IOC_NR(cmd) */
+static struct {
+ unsigned int cmd;
+} media_ioctl_info[] = {
+ MEDIA_IOC(DEVICE_INFO),
+ MEDIA_IOC(ENUM_ENTITIES),
+ MEDIA_IOC(ENUM_LINKS),
+ MEDIA_IOC(SETUP_LINK),
+ MEDIA_IOC(G_TOPOLOGY),
+};
+
static long media_device_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg)
{
@@ -426,6 +440,10 @@ static long media_device_ioctl(struct file *filp, unsigned int cmd,
struct media_device *dev = to_media_device(devnode);
long ret;
+ if (_IOC_NR(cmd) >= ARRAY_SIZE(media_ioctl_info)
+ || media_ioctl_info[_IOC_NR(cmd)].cmd != cmd)
+ return -ENOIOCTLCMD;
+
mutex_lock(&dev->graph_mutex);
switch (cmd) {
case MEDIA_IOC_DEVICE_INFO:
--
1.9.1
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH 2/3] media: Refactor copying IOCTL arguments from and to user space
2016-04-29 8:43 [PATCH 0/3] Refactor media IOCTL handling Sakari Ailus
2016-04-29 8:43 ` [PATCH 1/3] media: Determine early whether an IOCTL is supported Sakari Ailus
@ 2016-04-29 8:43 ` Sakari Ailus
2016-04-29 8:43 ` [PATCH 3/3] media: Refactor IOCTL handler calling Sakari Ailus
2 siblings, 0 replies; 4+ messages in thread
From: Sakari Ailus @ 2016-04-29 8:43 UTC (permalink / raw)
To: linux-media; +Cc: mchehab, laurent.pinchart, hverkuil
Refactor copying the IOCTL argument structs from the user space and back,
in order to reduce code copied around and make the implementation more
robust.
As a result, the copying is done while not holding the graph mutex.
Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
---
drivers/media/media-device.c | 167 +++++++++++++++++--------------------------
1 file changed, 66 insertions(+), 101 deletions(-)
diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c
index 6d3ee5c..4a66a2d5 100644
--- a/drivers/media/media-device.c
+++ b/drivers/media/media-device.c
@@ -59,27 +59,24 @@ static int media_device_close(struct file *filp)
}
static int media_device_get_info(struct media_device *dev,
- struct media_device_info __user *__info)
+ struct media_device_info *info)
{
- struct media_device_info info;
-
- memset(&info, 0, sizeof(info));
+ memset(info, 0, sizeof(*info));
if (dev->driver_name[0])
- strlcpy(info.driver, dev->driver_name, sizeof(info.driver));
+ strlcpy(info->driver, dev->driver_name, sizeof(info->driver));
else
- strlcpy(info.driver, dev->dev->driver->name, sizeof(info.driver));
+ strlcpy(info->driver, dev->dev->driver->name,
+ sizeof(info->driver));
- strlcpy(info.model, dev->model, sizeof(info.model));
- strlcpy(info.serial, dev->serial, sizeof(info.serial));
- strlcpy(info.bus_info, dev->bus_info, sizeof(info.bus_info));
+ strlcpy(info->model, dev->model, sizeof(info->model));
+ strlcpy(info->serial, dev->serial, sizeof(info->serial));
+ strlcpy(info->bus_info, dev->bus_info, sizeof(info->bus_info));
- info.media_version = MEDIA_API_VERSION;
- info.hw_revision = dev->hw_revision;
- info.driver_version = dev->driver_version;
+ info->media_version = MEDIA_API_VERSION;
+ info->hw_revision = dev->hw_revision;
+ info->driver_version = dev->driver_version;
- if (copy_to_user(__info, &info, sizeof(*__info)))
- return -EFAULT;
return 0;
}
@@ -101,29 +98,25 @@ static struct media_entity *find_entity(struct media_device *mdev, u32 id)
}
static long media_device_enum_entities(struct media_device *mdev,
- struct media_entity_desc __user *uent)
+ struct media_entity_desc *entd)
{
struct media_entity *ent;
- struct media_entity_desc u_ent;
-
- memset(&u_ent, 0, sizeof(u_ent));
- if (copy_from_user(&u_ent.id, &uent->id, sizeof(u_ent.id)))
- return -EFAULT;
-
- ent = find_entity(mdev, u_ent.id);
+ ent = find_entity(mdev, entd->id);
if (ent == NULL)
return -EINVAL;
- u_ent.id = media_entity_id(ent);
+ memset(entd, 0, sizeof(*entd));
+
+ entd->id = media_entity_id(ent);
if (ent->name)
- strlcpy(u_ent.name, ent->name, sizeof(u_ent.name));
- u_ent.type = ent->function;
- u_ent.revision = 0; /* Unused */
- u_ent.flags = ent->flags;
- u_ent.group_id = 0; /* Unused */
- u_ent.pads = ent->num_pads;
- u_ent.links = ent->num_links - ent->num_backlinks;
+ strlcpy(entd->name, ent->name, sizeof(entd->name));
+ entd->type = ent->function;
+ entd->revision = 0; /* Unused */
+ entd->flags = ent->flags;
+ entd->group_id = 0; /* Unused */
+ entd->pads = ent->num_pads;
+ entd->links = ent->num_links - ent->num_backlinks;
/*
* Workaround for a bug at media-ctl <= v1.10 that makes it to
@@ -139,14 +132,13 @@ static long media_device_enum_entities(struct media_device *mdev,
if (ent->function < MEDIA_ENT_F_OLD_BASE ||
ent->function > MEDIA_ENT_T_DEVNODE_UNKNOWN) {
if (is_media_entity_v4l2_subdev(ent))
- u_ent.type = MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN;
+ entd->type = MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN;
else if (ent->function != MEDIA_ENT_F_IO_V4L)
- u_ent.type = MEDIA_ENT_T_DEVNODE_UNKNOWN;
+ entd->type = MEDIA_ENT_T_DEVNODE_UNKNOWN;
}
- memcpy(&u_ent.raw, &ent->info, sizeof(ent->info));
- if (copy_to_user(uent, &u_ent, sizeof(u_ent)))
- return -EFAULT;
+ memcpy(&entd->raw, &ent->info, sizeof(ent->info));
+
return 0;
}
@@ -158,8 +150,8 @@ static void media_device_kpad_to_upad(const struct media_pad *kpad,
upad->flags = kpad->flags;
}
-static long __media_device_enum_links(struct media_device *mdev,
- struct media_links_enum *links)
+static long media_device_enum_links(struct media_device *mdev,
+ struct media_links_enum *links)
{
struct media_entity *entity;
@@ -206,64 +198,35 @@ static long __media_device_enum_links(struct media_device *mdev,
return 0;
}
-static long media_device_enum_links(struct media_device *mdev,
- struct media_links_enum __user *ulinks)
-{
- struct media_links_enum links;
- int rval;
-
- if (copy_from_user(&links, ulinks, sizeof(links)))
- return -EFAULT;
-
- rval = __media_device_enum_links(mdev, &links);
- if (rval < 0)
- return rval;
-
- if (copy_to_user(ulinks, &links, sizeof(*ulinks)))
- return -EFAULT;
-
- return 0;
-}
-
static long media_device_setup_link(struct media_device *mdev,
- struct media_link_desc __user *_ulink)
+ struct media_link_desc *linkd)
{
struct media_link *link = NULL;
- struct media_link_desc ulink;
struct media_entity *source;
struct media_entity *sink;
- int ret;
-
- if (copy_from_user(&ulink, _ulink, sizeof(ulink)))
- return -EFAULT;
/* Find the source and sink entities and link.
*/
- source = find_entity(mdev, ulink.source.entity);
- sink = find_entity(mdev, ulink.sink.entity);
+ source = find_entity(mdev, linkd->source.entity);
+ sink = find_entity(mdev, linkd->sink.entity);
if (source == NULL || sink == NULL)
return -EINVAL;
- if (ulink.source.index >= source->num_pads ||
- ulink.sink.index >= sink->num_pads)
+ if (linkd->source.index >= source->num_pads ||
+ linkd->sink.index >= sink->num_pads)
return -EINVAL;
- link = media_entity_find_link(&source->pads[ulink.source.index],
- &sink->pads[ulink.sink.index]);
+ link = media_entity_find_link(&source->pads[linkd->source.index],
+ &sink->pads[linkd->sink.index]);
if (link == NULL)
return -EINVAL;
/* Setup the link on both entities. */
- ret = __media_entity_setup_link(link, ulink.flags);
-
- if (copy_to_user(_ulink, &ulink, sizeof(ulink)))
- return -EFAULT;
-
- return ret;
+ return __media_entity_setup_link(link, linkd->flags);
}
-static long __media_device_get_topology(struct media_device *mdev,
+static long media_device_get_topology(struct media_device *mdev,
struct media_v2_topology *topo)
{
struct media_entity *entity;
@@ -400,30 +363,11 @@ static long __media_device_get_topology(struct media_device *mdev,
return ret;
}
-static long media_device_get_topology(struct media_device *mdev,
- struct media_v2_topology __user *utopo)
-{
- struct media_v2_topology ktopo;
- int ret;
-
- if (copy_from_user(&ktopo, utopo, sizeof(ktopo)))
- return -EFAULT;
-
- ret = __media_device_get_topology(mdev, &ktopo);
- if (ret < 0)
- return ret;
-
- if (copy_to_user(utopo, &ktopo, sizeof(*utopo)))
- return -EFAULT;
-
- return 0;
-}
-
#define MEDIA_IOC(__cmd) \
[_IOC_NR(MEDIA_IOC_##__cmd)] = { .cmd = MEDIA_IOC_##__cmd }
/* the table is indexed by _IOC_NR(cmd) */
-static struct {
+static const struct {
unsigned int cmd;
} media_ioctl_info[] = {
MEDIA_IOC(DEVICE_INFO),
@@ -433,42 +377,60 @@ static struct {
MEDIA_IOC(G_TOPOLOGY),
};
+static unsigned int media_ioctl_max_arg_size(void) {
+ static unsigned int max_size;
+ unsigned int i;
+
+ if (max_size)
+ return max_size;
+
+ for (i = 0; i < ARRAY_SIZE(media_ioctl_info); i++)
+ max_size = max(_IOC_SIZE(media_ioctl_info[i].cmd), max_size);
+
+ return max_size;
+}
+
static long media_device_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg)
{
struct media_devnode *devnode = media_devnode_data(filp);
struct media_device *dev = to_media_device(devnode);
+ char karg[media_ioctl_max_arg_size()];
long ret;
if (_IOC_NR(cmd) >= ARRAY_SIZE(media_ioctl_info)
|| media_ioctl_info[_IOC_NR(cmd)].cmd != cmd)
return -ENOIOCTLCMD;
+ /* All media IOCTLs are _IOWR() */
+ if (copy_from_user(karg, (void *)arg, _IOC_SIZE(cmd)))
+ return -EFAULT;
+
mutex_lock(&dev->graph_mutex);
switch (cmd) {
case MEDIA_IOC_DEVICE_INFO:
ret = media_device_get_info(dev,
- (struct media_device_info __user *)arg);
+ (struct media_device_info *)karg);
break;
case MEDIA_IOC_ENUM_ENTITIES:
ret = media_device_enum_entities(dev,
- (struct media_entity_desc __user *)arg);
+ (struct media_entity_desc *)karg);
break;
case MEDIA_IOC_ENUM_LINKS:
ret = media_device_enum_links(dev,
- (struct media_links_enum __user *)arg);
+ (struct media_links_enum *)karg);
break;
case MEDIA_IOC_SETUP_LINK:
ret = media_device_setup_link(dev,
- (struct media_link_desc __user *)arg);
+ (struct media_link_desc *)karg);
break;
case MEDIA_IOC_G_TOPOLOGY:
ret = media_device_get_topology(dev,
- (struct media_v2_topology __user *)arg);
+ (struct media_v2_topology *)karg);
break;
default:
@@ -476,6 +438,9 @@ static long media_device_ioctl(struct file *filp, unsigned int cmd,
}
mutex_unlock(&dev->graph_mutex);
+ if (!ret && copy_to_user((void *)arg, karg, _IOC_SIZE(cmd)))
+ return -EFAULT;
+
return ret;
}
@@ -504,7 +469,7 @@ static long media_device_enum_links32(struct media_device *mdev,
links.pads = compat_ptr(pads_ptr);
links.links = compat_ptr(links_ptr);
- return __media_device_enum_links(mdev, &links);
+ return media_device_enum_links(mdev, &links);
}
#define MEDIA_IOC_ENUM_LINKS32 _IOWR('|', 0x02, struct media_links_enum32)
--
1.9.1
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH 3/3] media: Refactor IOCTL handler calling
2016-04-29 8:43 [PATCH 0/3] Refactor media IOCTL handling Sakari Ailus
2016-04-29 8:43 ` [PATCH 1/3] media: Determine early whether an IOCTL is supported Sakari Ailus
2016-04-29 8:43 ` [PATCH 2/3] media: Refactor copying IOCTL arguments from and to user space Sakari Ailus
@ 2016-04-29 8:43 ` Sakari Ailus
2 siblings, 0 replies; 4+ messages in thread
From: Sakari Ailus @ 2016-04-29 8:43 UTC (permalink / raw)
To: linux-media; +Cc: mchehab, laurent.pinchart, hverkuil
Replace the switch by a nice array of supported IOCTLs, just like in V4L2.
Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
---
drivers/media/media-device.c | 58 +++++++++++++++-----------------------------
1 file changed, 19 insertions(+), 39 deletions(-)
diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c
index 4a66a2d5..8a4daf9 100644
--- a/drivers/media/media-device.c
+++ b/drivers/media/media-device.c
@@ -363,18 +363,22 @@ static long media_device_get_topology(struct media_device *mdev,
return ret;
}
-#define MEDIA_IOC(__cmd) \
- [_IOC_NR(MEDIA_IOC_##__cmd)] = { .cmd = MEDIA_IOC_##__cmd }
+#define MEDIA_IOC(__cmd, func) \
+ [_IOC_NR(MEDIA_IOC_##__cmd)] = { \
+ .cmd = MEDIA_IOC_##__cmd, \
+ .fn = (long (*)(struct media_device *, void *))func, \
+ }
/* the table is indexed by _IOC_NR(cmd) */
-static const struct {
+static const struct media_ioctl_info {
unsigned int cmd;
+ long (*fn)(struct media_device *dev, void *arg);
} media_ioctl_info[] = {
- MEDIA_IOC(DEVICE_INFO),
- MEDIA_IOC(ENUM_ENTITIES),
- MEDIA_IOC(ENUM_LINKS),
- MEDIA_IOC(SETUP_LINK),
- MEDIA_IOC(G_TOPOLOGY),
+ MEDIA_IOC(DEVICE_INFO, media_device_get_info),
+ MEDIA_IOC(ENUM_ENTITIES, media_device_enum_entities),
+ MEDIA_IOC(ENUM_LINKS, media_device_enum_links),
+ MEDIA_IOC(SETUP_LINK, media_device_setup_link),
+ MEDIA_IOC(G_TOPOLOGY, media_device_get_topology),
};
static unsigned int media_ioctl_max_arg_size(void) {
@@ -395,11 +399,15 @@ static long media_device_ioctl(struct file *filp, unsigned int cmd,
{
struct media_devnode *devnode = media_devnode_data(filp);
struct media_device *dev = to_media_device(devnode);
+ const struct media_ioctl_info *info;
char karg[media_ioctl_max_arg_size()];
long ret;
- if (_IOC_NR(cmd) >= ARRAY_SIZE(media_ioctl_info)
- || media_ioctl_info[_IOC_NR(cmd)].cmd != cmd)
+ if (_IOC_NR(cmd) >= ARRAY_SIZE(media_ioctl_info))
+ return -ENOIOCTLCMD;
+
+ info = &media_ioctl_info[_IOC_NR(cmd)];
+ if (info->cmd != cmd)
return -ENOIOCTLCMD;
/* All media IOCTLs are _IOWR() */
@@ -407,35 +415,7 @@ static long media_device_ioctl(struct file *filp, unsigned int cmd,
return -EFAULT;
mutex_lock(&dev->graph_mutex);
- switch (cmd) {
- case MEDIA_IOC_DEVICE_INFO:
- ret = media_device_get_info(dev,
- (struct media_device_info *)karg);
- break;
-
- case MEDIA_IOC_ENUM_ENTITIES:
- ret = media_device_enum_entities(dev,
- (struct media_entity_desc *)karg);
- break;
-
- case MEDIA_IOC_ENUM_LINKS:
- ret = media_device_enum_links(dev,
- (struct media_links_enum *)karg);
- break;
-
- case MEDIA_IOC_SETUP_LINK:
- ret = media_device_setup_link(dev,
- (struct media_link_desc *)karg);
- break;
-
- case MEDIA_IOC_G_TOPOLOGY:
- ret = media_device_get_topology(dev,
- (struct media_v2_topology *)karg);
- break;
-
- default:
- ret = -ENOIOCTLCMD;
- }
+ ret = info->fn(dev, karg);
mutex_unlock(&dev->graph_mutex);
if (!ret && copy_to_user((void *)arg, karg, _IOC_SIZE(cmd)))
--
1.9.1
^ permalink raw reply related [flat|nested] 4+ messages in thread
end of thread, other threads:[~2016-04-29 8:47 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-04-29 8:43 [PATCH 0/3] Refactor media IOCTL handling Sakari Ailus
2016-04-29 8:43 ` [PATCH 1/3] media: Determine early whether an IOCTL is supported Sakari Ailus
2016-04-29 8:43 ` [PATCH 2/3] media: Refactor copying IOCTL arguments from and to user space Sakari Ailus
2016-04-29 8:43 ` [PATCH 3/3] media: Refactor IOCTL handler calling Sakari Ailus
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).