* [PATCH] media: v4l2-core: make number of video devices configurable
@ 2026-08-10 16:24 Ali Nasrollahi
2026-08-10 16:28 ` Laurent Pinchart
0 siblings, 1 reply; 5+ messages in thread
From: Ali Nasrollahi @ 2026-08-10 16:24 UTC (permalink / raw)
To: linux-media, linux-kernel
Cc: mchehab, laurent.pinchart, Frank.Li, hverkuil+cisco, guoniu.zhou,
Ali Nasrollahi
The V4L2 core currently limits the number of registered video devices to
256. This can become a restriction for workloads that create a large
number of virtual video devices, such as v4l2loopback instances.
Make the maximum number of video devices configurable through a module
parameter. The default and minimum remain at the existing limit of 256,
while the maximum is capped at 4096.
The parameter is only available when CONFIG_VIDEO_FIXED_MINOR_RANGES is
disabled, as the fixed minor allocation scheme relies on the existing
minor ranges.
The device array is allocated according to the configured limit, while
the allocation bitmaps remain statically sized to the maximum supported
limit of 4096.
Signed-off-by: Ali Nasrollahi <A.Nasrolahi01@gmail.com>
---
drivers/media/v4l2-core/v4l2-dev.c | 70 +++++++++++++++++++++++-------
1 file changed, 55 insertions(+), 15 deletions(-)
diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c
index fd267fb74905..5a526b577970 100644
--- a/drivers/media/v4l2-core/v4l2-dev.c
+++ b/drivers/media/v4l2-core/v4l2-dev.c
@@ -31,7 +31,8 @@
#include <media/v4l2-ioctl.h>
#include <media/v4l2-event.h>
-#define VIDEO_NUM_DEVICES 256
+#define VIDEO_MIN_NUM_DEVICES 256
+#define VIDEO_MAX_NUM_DEVICES 4096
#define VIDEO_NAME "video4linux"
#define dprintk(fmt, arg...) do { \
@@ -39,6 +40,27 @@
__func__, ##arg); \
} while (0)
+static unsigned int video_nr_devices = VIDEO_MIN_NUM_DEVICES;
+
+#ifndef CONFIG_VIDEO_FIXED_MINOR_RANGES
+static int param_set_video_nr_devices(const char *val,
+ const struct kernel_param *kp)
+{
+ return param_set_uint_minmax(val, kp, VIDEO_MIN_NUM_DEVICES,
+ VIDEO_MAX_NUM_DEVICES);
+}
+
+static const struct kernel_param_ops param_ops_video_nr_devices = {
+ .set = param_set_video_nr_devices,
+ .get = param_get_uint,
+};
+
+module_param_cb(video_nr_devices, ¶m_ops_video_nr_devices,
+ &video_nr_devices, 0444);
+
+MODULE_PARM_DESC(video_nr_devices, "Maximum number of V4L2 devices (256-4096)");
+#endif
+
/*
* sysfs stuff
*/
@@ -98,9 +120,14 @@ static struct dentry *v4l2_debugfs_root_dir;
/*
* Active devices
*/
-static struct video_device *video_devices[VIDEO_NUM_DEVICES];
+#ifdef CONFIG_VIDEO_FIXED_MINOR_RANGES
+static struct video_device *video_devices[VIDEO_MIN_NUM_DEVICES];
+static DECLARE_BITMAP(devnode_nums[VFL_TYPE_MAX], VIDEO_MIN_NUM_DEVICES);
+#else
+static struct video_device **video_devices;
+static DECLARE_BITMAP(devnode_nums[VFL_TYPE_MAX], VIDEO_MAX_NUM_DEVICES);
+#endif
static DEFINE_MUTEX(videodev_lock);
-static DECLARE_BITMAP(devnode_nums[VFL_TYPE_MAX], VIDEO_NUM_DEVICES);
/* Device node utility functions */
@@ -504,7 +531,7 @@ static const struct file_operations v4l2_fops = {
* in the video_device array, but it was able to obtain a minor number.
*
* This means that we can always obtain a free stream index number since
- * the worst case scenario is that there are VIDEO_NUM_DEVICES - 1 slots in
+ * the worst case scenario is that there are video_nr_devices - 1 slots in
* use of the video_device array.
*
* Returns a free index number.
@@ -513,19 +540,19 @@ static int get_index(struct video_device *vdev)
{
/* This can be static since this function is called with the global
videodev_lock held. */
- static DECLARE_BITMAP(used, VIDEO_NUM_DEVICES);
+ static DECLARE_BITMAP(used, VIDEO_MAX_NUM_DEVICES);
int i;
- bitmap_zero(used, VIDEO_NUM_DEVICES);
+ bitmap_zero(used, VIDEO_MAX_NUM_DEVICES);
- for (i = 0; i < VIDEO_NUM_DEVICES; i++) {
+ for (i = 0; i < video_nr_devices; i++) {
if (video_devices[i] != NULL &&
video_devices[i]->v4l2_dev == vdev->v4l2_dev) {
__set_bit(video_devices[i]->index, used);
}
}
- return find_first_zero_bit(used, VIDEO_NUM_DEVICES);
+ return find_first_zero_bit(used, video_nr_devices);
}
#define SET_VALID_IOCTL(ops, cmd, op) \
@@ -915,7 +942,7 @@ int __video_register_device(struct video_device *vdev,
int i = 0;
int ret;
int minor_offset = 0;
- int minor_cnt = VIDEO_NUM_DEVICES;
+ int minor_cnt = video_nr_devices;
const char *name_base;
/* A minor value of -1 marks this video device as never
@@ -1020,10 +1047,10 @@ int __video_register_device(struct video_device *vdev,
#else
/* The device node number and minor numbers are independent, so
we just find the first free minor number. */
- for (i = 0; i < VIDEO_NUM_DEVICES; i++)
+ for (i = 0; i < video_nr_devices; i++)
if (video_devices[i] == NULL)
break;
- if (i == VIDEO_NUM_DEVICES) {
+ if (i == video_nr_devices) {
mutex_unlock(&videodev_lock);
pr_err("could not get a free minor\n");
return -ENFILE;
@@ -1032,7 +1059,7 @@ int __video_register_device(struct video_device *vdev,
vdev->minor = i + minor_offset;
vdev->num = nr;
- if (WARN_ON(vdev->minor >= VIDEO_NUM_DEVICES)) {
+ if (WARN_ON(vdev->minor >= video_nr_devices)) {
mutex_unlock(&videodev_lock);
return -EINVAL;
}
@@ -1241,7 +1268,7 @@ static int __init videodev_init(void)
int ret;
pr_info("Linux video capture interface: v2.00\n");
- ret = register_chrdev_region(dev, VIDEO_NUM_DEVICES, VIDEO_NAME);
+ ret = register_chrdev_region(dev, video_nr_devices, VIDEO_NAME);
if (ret < 0) {
pr_warn("videodev: unable to get major %d\n",
VIDEO_MAJOR);
@@ -1250,11 +1277,21 @@ static int __init videodev_init(void)
ret = class_register(&video_class);
if (ret < 0) {
- unregister_chrdev_region(dev, VIDEO_NUM_DEVICES);
+ unregister_chrdev_region(dev, video_nr_devices);
pr_warn("video_dev: class_register failed\n");
return -EIO;
}
+#ifndef CONFIG_VIDEO_FIXED_MINOR_RANGES
+ video_devices = kzalloc_objs(*video_devices, video_nr_devices);
+ if (!video_devices) {
+ class_unregister(&video_class);
+ unregister_chrdev_region(dev, video_nr_devices);
+ pr_warn("video_dev: failed to allocate video_devices\n");
+ return -ENOMEM;
+ }
+#endif
+
return 0;
}
@@ -1262,8 +1299,11 @@ static void __exit videodev_exit(void)
{
dev_t dev = MKDEV(VIDEO_MAJOR, 0);
+#ifndef CONFIG_VIDEO_FIXED_MINOR_RANGES
+ kvfree(video_devices);
+#endif
class_unregister(&video_class);
- unregister_chrdev_region(dev, VIDEO_NUM_DEVICES);
+ unregister_chrdev_region(dev, video_nr_devices);
debugfs_remove_recursive(v4l2_debugfs_root_dir);
v4l2_debugfs_root_dir = NULL;
}
--
2.55.0
^ permalink raw reply related [flat|nested] 5+ messages in thread* Re: [PATCH] media: v4l2-core: make number of video devices configurable
2026-08-10 16:24 [PATCH] media: v4l2-core: make number of video devices configurable Ali Nasrollahi
@ 2026-08-10 16:28 ` Laurent Pinchart
2026-08-11 3:59 ` Ali Nasrollahi
0 siblings, 1 reply; 5+ messages in thread
From: Laurent Pinchart @ 2026-08-10 16:28 UTC (permalink / raw)
To: Ali Nasrollahi
Cc: linux-media, linux-kernel, mchehab, Frank.Li, hverkuil+cisco,
guoniu.zhou
On Mon, Aug 10, 2026 at 07:54:07PM +0330, Ali Nasrollahi wrote:
> The V4L2 core currently limits the number of registered video devices to
> 256. This can become a restriction for workloads that create a large
> number of virtual video devices, such as v4l2loopback instances.
We don't support v4l2loopback upstream though.
> Make the maximum number of video devices configurable through a module
> parameter. The default and minimum remain at the existing limit of 256,
> while the maximum is capped at 4096.
>
> The parameter is only available when CONFIG_VIDEO_FIXED_MINOR_RANGES is
> disabled, as the fixed minor allocation scheme relies on the existing
> minor ranges.
>
> The device array is allocated according to the configured limit, while
> the allocation bitmaps remain statically sized to the maximum supported
> limit of 4096.
>
> Signed-off-by: Ali Nasrollahi <A.Nasrolahi01@gmail.com>
> ---
> drivers/media/v4l2-core/v4l2-dev.c | 70 +++++++++++++++++++++++-------
> 1 file changed, 55 insertions(+), 15 deletions(-)
>
> diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c
> index fd267fb74905..5a526b577970 100644
> --- a/drivers/media/v4l2-core/v4l2-dev.c
> +++ b/drivers/media/v4l2-core/v4l2-dev.c
> @@ -31,7 +31,8 @@
> #include <media/v4l2-ioctl.h>
> #include <media/v4l2-event.h>
>
> -#define VIDEO_NUM_DEVICES 256
> +#define VIDEO_MIN_NUM_DEVICES 256
> +#define VIDEO_MAX_NUM_DEVICES 4096
> #define VIDEO_NAME "video4linux"
>
> #define dprintk(fmt, arg...) do { \
> @@ -39,6 +40,27 @@
> __func__, ##arg); \
> } while (0)
>
> +static unsigned int video_nr_devices = VIDEO_MIN_NUM_DEVICES;
> +
> +#ifndef CONFIG_VIDEO_FIXED_MINOR_RANGES
> +static int param_set_video_nr_devices(const char *val,
> + const struct kernel_param *kp)
> +{
> + return param_set_uint_minmax(val, kp, VIDEO_MIN_NUM_DEVICES,
> + VIDEO_MAX_NUM_DEVICES);
> +}
> +
> +static const struct kernel_param_ops param_ops_video_nr_devices = {
> + .set = param_set_video_nr_devices,
> + .get = param_get_uint,
> +};
> +
> +module_param_cb(video_nr_devices, ¶m_ops_video_nr_devices,
> + &video_nr_devices, 0444);
> +
> +MODULE_PARM_DESC(video_nr_devices, "Maximum number of V4L2 devices (256-4096)");
> +#endif
> +
> /*
> * sysfs stuff
> */
> @@ -98,9 +120,14 @@ static struct dentry *v4l2_debugfs_root_dir;
> /*
> * Active devices
> */
> -static struct video_device *video_devices[VIDEO_NUM_DEVICES];
> +#ifdef CONFIG_VIDEO_FIXED_MINOR_RANGES
> +static struct video_device *video_devices[VIDEO_MIN_NUM_DEVICES];
> +static DECLARE_BITMAP(devnode_nums[VFL_TYPE_MAX], VIDEO_MIN_NUM_DEVICES);
> +#else
> +static struct video_device **video_devices;
> +static DECLARE_BITMAP(devnode_nums[VFL_TYPE_MAX], VIDEO_MAX_NUM_DEVICES);
> +#endif
> static DEFINE_MUTEX(videodev_lock);
> -static DECLARE_BITMAP(devnode_nums[VFL_TYPE_MAX], VIDEO_NUM_DEVICES);
>
> /* Device node utility functions */
>
> @@ -504,7 +531,7 @@ static const struct file_operations v4l2_fops = {
> * in the video_device array, but it was able to obtain a minor number.
> *
> * This means that we can always obtain a free stream index number since
> - * the worst case scenario is that there are VIDEO_NUM_DEVICES - 1 slots in
> + * the worst case scenario is that there are video_nr_devices - 1 slots in
> * use of the video_device array.
> *
> * Returns a free index number.
> @@ -513,19 +540,19 @@ static int get_index(struct video_device *vdev)
> {
> /* This can be static since this function is called with the global
> videodev_lock held. */
> - static DECLARE_BITMAP(used, VIDEO_NUM_DEVICES);
> + static DECLARE_BITMAP(used, VIDEO_MAX_NUM_DEVICES);
> int i;
>
> - bitmap_zero(used, VIDEO_NUM_DEVICES);
> + bitmap_zero(used, VIDEO_MAX_NUM_DEVICES);
>
> - for (i = 0; i < VIDEO_NUM_DEVICES; i++) {
> + for (i = 0; i < video_nr_devices; i++) {
> if (video_devices[i] != NULL &&
> video_devices[i]->v4l2_dev == vdev->v4l2_dev) {
> __set_bit(video_devices[i]->index, used);
> }
> }
>
> - return find_first_zero_bit(used, VIDEO_NUM_DEVICES);
> + return find_first_zero_bit(used, video_nr_devices);
> }
>
> #define SET_VALID_IOCTL(ops, cmd, op) \
> @@ -915,7 +942,7 @@ int __video_register_device(struct video_device *vdev,
> int i = 0;
> int ret;
> int minor_offset = 0;
> - int minor_cnt = VIDEO_NUM_DEVICES;
> + int minor_cnt = video_nr_devices;
> const char *name_base;
>
> /* A minor value of -1 marks this video device as never
> @@ -1020,10 +1047,10 @@ int __video_register_device(struct video_device *vdev,
> #else
> /* The device node number and minor numbers are independent, so
> we just find the first free minor number. */
> - for (i = 0; i < VIDEO_NUM_DEVICES; i++)
> + for (i = 0; i < video_nr_devices; i++)
> if (video_devices[i] == NULL)
> break;
> - if (i == VIDEO_NUM_DEVICES) {
> + if (i == video_nr_devices) {
> mutex_unlock(&videodev_lock);
> pr_err("could not get a free minor\n");
> return -ENFILE;
> @@ -1032,7 +1059,7 @@ int __video_register_device(struct video_device *vdev,
> vdev->minor = i + minor_offset;
> vdev->num = nr;
>
> - if (WARN_ON(vdev->minor >= VIDEO_NUM_DEVICES)) {
> + if (WARN_ON(vdev->minor >= video_nr_devices)) {
> mutex_unlock(&videodev_lock);
> return -EINVAL;
> }
> @@ -1241,7 +1268,7 @@ static int __init videodev_init(void)
> int ret;
>
> pr_info("Linux video capture interface: v2.00\n");
> - ret = register_chrdev_region(dev, VIDEO_NUM_DEVICES, VIDEO_NAME);
> + ret = register_chrdev_region(dev, video_nr_devices, VIDEO_NAME);
> if (ret < 0) {
> pr_warn("videodev: unable to get major %d\n",
> VIDEO_MAJOR);
> @@ -1250,11 +1277,21 @@ static int __init videodev_init(void)
>
> ret = class_register(&video_class);
> if (ret < 0) {
> - unregister_chrdev_region(dev, VIDEO_NUM_DEVICES);
> + unregister_chrdev_region(dev, video_nr_devices);
> pr_warn("video_dev: class_register failed\n");
> return -EIO;
> }
>
> +#ifndef CONFIG_VIDEO_FIXED_MINOR_RANGES
> + video_devices = kzalloc_objs(*video_devices, video_nr_devices);
> + if (!video_devices) {
> + class_unregister(&video_class);
> + unregister_chrdev_region(dev, video_nr_devices);
> + pr_warn("video_dev: failed to allocate video_devices\n");
> + return -ENOMEM;
> + }
> +#endif
> +
> return 0;
> }
>
> @@ -1262,8 +1299,11 @@ static void __exit videodev_exit(void)
> {
> dev_t dev = MKDEV(VIDEO_MAJOR, 0);
>
> +#ifndef CONFIG_VIDEO_FIXED_MINOR_RANGES
> + kvfree(video_devices);
> +#endif
> class_unregister(&video_class);
> - unregister_chrdev_region(dev, VIDEO_NUM_DEVICES);
> + unregister_chrdev_region(dev, video_nr_devices);
> debugfs_remove_recursive(v4l2_debugfs_root_dir);
> v4l2_debugfs_root_dir = NULL;
> }
--
Regards,
Laurent Pinchart
^ permalink raw reply [flat|nested] 5+ messages in thread* Re: [PATCH] media: v4l2-core: make number of video devices configurable
2026-08-10 16:28 ` Laurent Pinchart
@ 2026-08-11 3:59 ` Ali Nasrollahi
2026-08-11 4:04 ` Laurent Pinchart
0 siblings, 1 reply; 5+ messages in thread
From: Ali Nasrollahi @ 2026-08-11 3:59 UTC (permalink / raw)
To: Laurent Pinchart
Cc: linux-media, linux-kernel, mchehab, Frank.Li, hverkuil+cisco,
guoniu.zhou
On 26/08/10 07:28PM, Laurent Pinchart wrote:
> On Mon, Aug 10, 2026 at 07:54:07PM +0330, Ali Nasrollahi wrote:
> > The V4L2 core currently limits the number of registered video devices to
> > 256. This can become a restriction for workloads that create a large
> > number of virtual video devices, such as v4l2loopback instances.
>
> We don't support v4l2loopback upstream though.
>
Yes, you are correct.
But perhaps my description was a bit misleading. The main idea of this
patch is not to support out-of-tree modules by any means, but to allow a
configurable number of V4L2 devices to be created and used, whether
through loopback devices or other means.
> > Make the maximum number of video devices configurable through a module
> > parameter. The default and minimum remain at the existing limit of 256,
> > while the maximum is capped at 4096.
> >
> > The parameter is only available when CONFIG_VIDEO_FIXED_MINOR_RANGES is
> > disabled, as the fixed minor allocation scheme relies on the existing
> > minor ranges.
> >
> > The device array is allocated according to the configured limit, while
> > the allocation bitmaps remain statically sized to the maximum supported
> > limit of 4096.
> >
> > Signed-off-by: Ali Nasrollahi <A.Nasrolahi01@gmail.com>
> > ---
> > drivers/media/v4l2-core/v4l2-dev.c | 70 +++++++++++++++++++++++-------
> > 1 file changed, 55 insertions(+), 15 deletions(-)
> >
> > diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c
> > index fd267fb74905..5a526b577970 100644
> > --- a/drivers/media/v4l2-core/v4l2-dev.c
> > +++ b/drivers/media/v4l2-core/v4l2-dev.c
> > @@ -31,7 +31,8 @@
> > #include <media/v4l2-ioctl.h>
> > #include <media/v4l2-event.h>
> >
> > -#define VIDEO_NUM_DEVICES 256
> > +#define VIDEO_MIN_NUM_DEVICES 256
> > +#define VIDEO_MAX_NUM_DEVICES 4096
> > #define VIDEO_NAME "video4linux"
> >
> > #define dprintk(fmt, arg...) do { \
> > @@ -39,6 +40,27 @@
> > __func__, ##arg); \
> > } while (0)
> >
> > +static unsigned int video_nr_devices = VIDEO_MIN_NUM_DEVICES;
> > +
> > +#ifndef CONFIG_VIDEO_FIXED_MINOR_RANGES
> > +static int param_set_video_nr_devices(const char *val,
> > + const struct kernel_param *kp)
> > +{
> > + return param_set_uint_minmax(val, kp, VIDEO_MIN_NUM_DEVICES,
> > + VIDEO_MAX_NUM_DEVICES);
> > +}
> > +
> > +static const struct kernel_param_ops param_ops_video_nr_devices = {
> > + .set = param_set_video_nr_devices,
> > + .get = param_get_uint,
> > +};
> > +
> > +module_param_cb(video_nr_devices, ¶m_ops_video_nr_devices,
> > + &video_nr_devices, 0444);
> > +
> > +MODULE_PARM_DESC(video_nr_devices, "Maximum number of V4L2 devices (256-4096)");
> > +#endif
> > +
> > /*
> > * sysfs stuff
> > */
> > @@ -98,9 +120,14 @@ static struct dentry *v4l2_debugfs_root_dir;
> > /*
> > * Active devices
> > */
> > -static struct video_device *video_devices[VIDEO_NUM_DEVICES];
> > +#ifdef CONFIG_VIDEO_FIXED_MINOR_RANGES
> > +static struct video_device *video_devices[VIDEO_MIN_NUM_DEVICES];
> > +static DECLARE_BITMAP(devnode_nums[VFL_TYPE_MAX], VIDEO_MIN_NUM_DEVICES);
> > +#else
> > +static struct video_device **video_devices;
> > +static DECLARE_BITMAP(devnode_nums[VFL_TYPE_MAX], VIDEO_MAX_NUM_DEVICES);
> > +#endif
> > static DEFINE_MUTEX(videodev_lock);
> > -static DECLARE_BITMAP(devnode_nums[VFL_TYPE_MAX], VIDEO_NUM_DEVICES);
> >
> > /* Device node utility functions */
> >
> > @@ -504,7 +531,7 @@ static const struct file_operations v4l2_fops = {
> > * in the video_device array, but it was able to obtain a minor number.
> > *
> > * This means that we can always obtain a free stream index number since
> > - * the worst case scenario is that there are VIDEO_NUM_DEVICES - 1 slots in
> > + * the worst case scenario is that there are video_nr_devices - 1 slots in
> > * use of the video_device array.
> > *
> > * Returns a free index number.
> > @@ -513,19 +540,19 @@ static int get_index(struct video_device *vdev)
> > {
> > /* This can be static since this function is called with the global
> > videodev_lock held. */
> > - static DECLARE_BITMAP(used, VIDEO_NUM_DEVICES);
> > + static DECLARE_BITMAP(used, VIDEO_MAX_NUM_DEVICES);
> > int i;
> >
> > - bitmap_zero(used, VIDEO_NUM_DEVICES);
> > + bitmap_zero(used, VIDEO_MAX_NUM_DEVICES);
> >
> > - for (i = 0; i < VIDEO_NUM_DEVICES; i++) {
> > + for (i = 0; i < video_nr_devices; i++) {
> > if (video_devices[i] != NULL &&
> > video_devices[i]->v4l2_dev == vdev->v4l2_dev) {
> > __set_bit(video_devices[i]->index, used);
> > }
> > }
> >
> > - return find_first_zero_bit(used, VIDEO_NUM_DEVICES);
> > + return find_first_zero_bit(used, video_nr_devices);
> > }
> >
> > #define SET_VALID_IOCTL(ops, cmd, op) \
> > @@ -915,7 +942,7 @@ int __video_register_device(struct video_device *vdev,
> > int i = 0;
> > int ret;
> > int minor_offset = 0;
> > - int minor_cnt = VIDEO_NUM_DEVICES;
> > + int minor_cnt = video_nr_devices;
> > const char *name_base;
> >
> > /* A minor value of -1 marks this video device as never
> > @@ -1020,10 +1047,10 @@ int __video_register_device(struct video_device *vdev,
> > #else
> > /* The device node number and minor numbers are independent, so
> > we just find the first free minor number. */
> > - for (i = 0; i < VIDEO_NUM_DEVICES; i++)
> > + for (i = 0; i < video_nr_devices; i++)
> > if (video_devices[i] == NULL)
> > break;
> > - if (i == VIDEO_NUM_DEVICES) {
> > + if (i == video_nr_devices) {
> > mutex_unlock(&videodev_lock);
> > pr_err("could not get a free minor\n");
> > return -ENFILE;
> > @@ -1032,7 +1059,7 @@ int __video_register_device(struct video_device *vdev,
> > vdev->minor = i + minor_offset;
> > vdev->num = nr;
> >
> > - if (WARN_ON(vdev->minor >= VIDEO_NUM_DEVICES)) {
> > + if (WARN_ON(vdev->minor >= video_nr_devices)) {
> > mutex_unlock(&videodev_lock);
> > return -EINVAL;
> > }
> > @@ -1241,7 +1268,7 @@ static int __init videodev_init(void)
> > int ret;
> >
> > pr_info("Linux video capture interface: v2.00\n");
> > - ret = register_chrdev_region(dev, VIDEO_NUM_DEVICES, VIDEO_NAME);
> > + ret = register_chrdev_region(dev, video_nr_devices, VIDEO_NAME);
> > if (ret < 0) {
> > pr_warn("videodev: unable to get major %d\n",
> > VIDEO_MAJOR);
> > @@ -1250,11 +1277,21 @@ static int __init videodev_init(void)
> >
> > ret = class_register(&video_class);
> > if (ret < 0) {
> > - unregister_chrdev_region(dev, VIDEO_NUM_DEVICES);
> > + unregister_chrdev_region(dev, video_nr_devices);
> > pr_warn("video_dev: class_register failed\n");
> > return -EIO;
> > }
> >
> > +#ifndef CONFIG_VIDEO_FIXED_MINOR_RANGES
> > + video_devices = kzalloc_objs(*video_devices, video_nr_devices);
> > + if (!video_devices) {
> > + class_unregister(&video_class);
> > + unregister_chrdev_region(dev, video_nr_devices);
> > + pr_warn("video_dev: failed to allocate video_devices\n");
> > + return -ENOMEM;
> > + }
> > +#endif
> > +
> > return 0;
> > }
> >
> > @@ -1262,8 +1299,11 @@ static void __exit videodev_exit(void)
> > {
> > dev_t dev = MKDEV(VIDEO_MAJOR, 0);
> >
> > +#ifndef CONFIG_VIDEO_FIXED_MINOR_RANGES
> > + kvfree(video_devices);
> > +#endif
> > class_unregister(&video_class);
> > - unregister_chrdev_region(dev, VIDEO_NUM_DEVICES);
> > + unregister_chrdev_region(dev, video_nr_devices);
> > debugfs_remove_recursive(v4l2_debugfs_root_dir);
> > v4l2_debugfs_root_dir = NULL;
> > }
>
> --
> Regards,
>
> Laurent Pinchart
Cheers,
Ali
^ permalink raw reply [flat|nested] 5+ messages in thread* Re: [PATCH] media: v4l2-core: make number of video devices configurable
2026-08-11 3:59 ` Ali Nasrollahi
@ 2026-08-11 4:04 ` Laurent Pinchart
2026-08-11 4:29 ` Ali Nasrollahi
0 siblings, 1 reply; 5+ messages in thread
From: Laurent Pinchart @ 2026-08-11 4:04 UTC (permalink / raw)
To: Ali Nasrollahi
Cc: linux-media, linux-kernel, mchehab, Frank.Li, hverkuil+cisco,
guoniu.zhou
On Tue, Aug 11, 2026 at 07:29:36AM +0330, Ali Nasrollahi wrote:
> On 26/08/10 07:28PM, Laurent Pinchart wrote:
> > On Mon, Aug 10, 2026 at 07:54:07PM +0330, Ali Nasrollahi wrote:
> > > The V4L2 core currently limits the number of registered video devices to
> > > 256. This can become a restriction for workloads that create a large
> > > number of virtual video devices, such as v4l2loopback instances.
> >
> > We don't support v4l2loopback upstream though.
>
> Yes, you are correct.
>
> But perhaps my description was a bit misleading. The main idea of this
> patch is not to support out-of-tree modules by any means, but to allow a
> configurable number of V4L2 devices to be created and used, whether
> through loopback devices or other means.
Do you have a use case where you're reaching the limit without
out-of-tree drivers ?
> > > Make the maximum number of video devices configurable through a module
> > > parameter. The default and minimum remain at the existing limit of 256,
> > > while the maximum is capped at 4096.
> > >
> > > The parameter is only available when CONFIG_VIDEO_FIXED_MINOR_RANGES is
> > > disabled, as the fixed minor allocation scheme relies on the existing
> > > minor ranges.
> > >
> > > The device array is allocated according to the configured limit, while
> > > the allocation bitmaps remain statically sized to the maximum supported
> > > limit of 4096.
> > >
> > > Signed-off-by: Ali Nasrollahi <A.Nasrolahi01@gmail.com>
> > > ---
> > > drivers/media/v4l2-core/v4l2-dev.c | 70 +++++++++++++++++++++++-------
> > > 1 file changed, 55 insertions(+), 15 deletions(-)
> > >
> > > diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c
> > > index fd267fb74905..5a526b577970 100644
> > > --- a/drivers/media/v4l2-core/v4l2-dev.c
> > > +++ b/drivers/media/v4l2-core/v4l2-dev.c
> > > @@ -31,7 +31,8 @@
> > > #include <media/v4l2-ioctl.h>
> > > #include <media/v4l2-event.h>
> > >
> > > -#define VIDEO_NUM_DEVICES 256
> > > +#define VIDEO_MIN_NUM_DEVICES 256
> > > +#define VIDEO_MAX_NUM_DEVICES 4096
> > > #define VIDEO_NAME "video4linux"
> > >
> > > #define dprintk(fmt, arg...) do { \
> > > @@ -39,6 +40,27 @@
> > > __func__, ##arg); \
> > > } while (0)
> > >
> > > +static unsigned int video_nr_devices = VIDEO_MIN_NUM_DEVICES;
> > > +
> > > +#ifndef CONFIG_VIDEO_FIXED_MINOR_RANGES
> > > +static int param_set_video_nr_devices(const char *val,
> > > + const struct kernel_param *kp)
> > > +{
> > > + return param_set_uint_minmax(val, kp, VIDEO_MIN_NUM_DEVICES,
> > > + VIDEO_MAX_NUM_DEVICES);
> > > +}
> > > +
> > > +static const struct kernel_param_ops param_ops_video_nr_devices = {
> > > + .set = param_set_video_nr_devices,
> > > + .get = param_get_uint,
> > > +};
> > > +
> > > +module_param_cb(video_nr_devices, ¶m_ops_video_nr_devices,
> > > + &video_nr_devices, 0444);
> > > +
> > > +MODULE_PARM_DESC(video_nr_devices, "Maximum number of V4L2 devices (256-4096)");
> > > +#endif
> > > +
> > > /*
> > > * sysfs stuff
> > > */
> > > @@ -98,9 +120,14 @@ static struct dentry *v4l2_debugfs_root_dir;
> > > /*
> > > * Active devices
> > > */
> > > -static struct video_device *video_devices[VIDEO_NUM_DEVICES];
> > > +#ifdef CONFIG_VIDEO_FIXED_MINOR_RANGES
> > > +static struct video_device *video_devices[VIDEO_MIN_NUM_DEVICES];
> > > +static DECLARE_BITMAP(devnode_nums[VFL_TYPE_MAX], VIDEO_MIN_NUM_DEVICES);
> > > +#else
> > > +static struct video_device **video_devices;
> > > +static DECLARE_BITMAP(devnode_nums[VFL_TYPE_MAX], VIDEO_MAX_NUM_DEVICES);
> > > +#endif
> > > static DEFINE_MUTEX(videodev_lock);
> > > -static DECLARE_BITMAP(devnode_nums[VFL_TYPE_MAX], VIDEO_NUM_DEVICES);
> > >
> > > /* Device node utility functions */
> > >
> > > @@ -504,7 +531,7 @@ static const struct file_operations v4l2_fops = {
> > > * in the video_device array, but it was able to obtain a minor number.
> > > *
> > > * This means that we can always obtain a free stream index number since
> > > - * the worst case scenario is that there are VIDEO_NUM_DEVICES - 1 slots in
> > > + * the worst case scenario is that there are video_nr_devices - 1 slots in
> > > * use of the video_device array.
> > > *
> > > * Returns a free index number.
> > > @@ -513,19 +540,19 @@ static int get_index(struct video_device *vdev)
> > > {
> > > /* This can be static since this function is called with the global
> > > videodev_lock held. */
> > > - static DECLARE_BITMAP(used, VIDEO_NUM_DEVICES);
> > > + static DECLARE_BITMAP(used, VIDEO_MAX_NUM_DEVICES);
> > > int i;
> > >
> > > - bitmap_zero(used, VIDEO_NUM_DEVICES);
> > > + bitmap_zero(used, VIDEO_MAX_NUM_DEVICES);
> > >
> > > - for (i = 0; i < VIDEO_NUM_DEVICES; i++) {
> > > + for (i = 0; i < video_nr_devices; i++) {
> > > if (video_devices[i] != NULL &&
> > > video_devices[i]->v4l2_dev == vdev->v4l2_dev) {
> > > __set_bit(video_devices[i]->index, used);
> > > }
> > > }
> > >
> > > - return find_first_zero_bit(used, VIDEO_NUM_DEVICES);
> > > + return find_first_zero_bit(used, video_nr_devices);
> > > }
> > >
> > > #define SET_VALID_IOCTL(ops, cmd, op) \
> > > @@ -915,7 +942,7 @@ int __video_register_device(struct video_device *vdev,
> > > int i = 0;
> > > int ret;
> > > int minor_offset = 0;
> > > - int minor_cnt = VIDEO_NUM_DEVICES;
> > > + int minor_cnt = video_nr_devices;
> > > const char *name_base;
> > >
> > > /* A minor value of -1 marks this video device as never
> > > @@ -1020,10 +1047,10 @@ int __video_register_device(struct video_device *vdev,
> > > #else
> > > /* The device node number and minor numbers are independent, so
> > > we just find the first free minor number. */
> > > - for (i = 0; i < VIDEO_NUM_DEVICES; i++)
> > > + for (i = 0; i < video_nr_devices; i++)
> > > if (video_devices[i] == NULL)
> > > break;
> > > - if (i == VIDEO_NUM_DEVICES) {
> > > + if (i == video_nr_devices) {
> > > mutex_unlock(&videodev_lock);
> > > pr_err("could not get a free minor\n");
> > > return -ENFILE;
> > > @@ -1032,7 +1059,7 @@ int __video_register_device(struct video_device *vdev,
> > > vdev->minor = i + minor_offset;
> > > vdev->num = nr;
> > >
> > > - if (WARN_ON(vdev->minor >= VIDEO_NUM_DEVICES)) {
> > > + if (WARN_ON(vdev->minor >= video_nr_devices)) {
> > > mutex_unlock(&videodev_lock);
> > > return -EINVAL;
> > > }
> > > @@ -1241,7 +1268,7 @@ static int __init videodev_init(void)
> > > int ret;
> > >
> > > pr_info("Linux video capture interface: v2.00\n");
> > > - ret = register_chrdev_region(dev, VIDEO_NUM_DEVICES, VIDEO_NAME);
> > > + ret = register_chrdev_region(dev, video_nr_devices, VIDEO_NAME);
> > > if (ret < 0) {
> > > pr_warn("videodev: unable to get major %d\n",
> > > VIDEO_MAJOR);
> > > @@ -1250,11 +1277,21 @@ static int __init videodev_init(void)
> > >
> > > ret = class_register(&video_class);
> > > if (ret < 0) {
> > > - unregister_chrdev_region(dev, VIDEO_NUM_DEVICES);
> > > + unregister_chrdev_region(dev, video_nr_devices);
> > > pr_warn("video_dev: class_register failed\n");
> > > return -EIO;
> > > }
> > >
> > > +#ifndef CONFIG_VIDEO_FIXED_MINOR_RANGES
> > > + video_devices = kzalloc_objs(*video_devices, video_nr_devices);
> > > + if (!video_devices) {
> > > + class_unregister(&video_class);
> > > + unregister_chrdev_region(dev, video_nr_devices);
> > > + pr_warn("video_dev: failed to allocate video_devices\n");
> > > + return -ENOMEM;
> > > + }
> > > +#endif
> > > +
> > > return 0;
> > > }
> > >
> > > @@ -1262,8 +1299,11 @@ static void __exit videodev_exit(void)
> > > {
> > > dev_t dev = MKDEV(VIDEO_MAJOR, 0);
> > >
> > > +#ifndef CONFIG_VIDEO_FIXED_MINOR_RANGES
> > > + kvfree(video_devices);
> > > +#endif
> > > class_unregister(&video_class);
> > > - unregister_chrdev_region(dev, VIDEO_NUM_DEVICES);
> > > + unregister_chrdev_region(dev, video_nr_devices);
> > > debugfs_remove_recursive(v4l2_debugfs_root_dir);
> > > v4l2_debugfs_root_dir = NULL;
> > > }
--
Regards,
Laurent Pinchart
^ permalink raw reply [flat|nested] 5+ messages in thread* Re: [PATCH] media: v4l2-core: make number of video devices configurable
2026-08-11 4:04 ` Laurent Pinchart
@ 2026-08-11 4:29 ` Ali Nasrollahi
0 siblings, 0 replies; 5+ messages in thread
From: Ali Nasrollahi @ 2026-08-11 4:29 UTC (permalink / raw)
To: Laurent Pinchart
Cc: linux-media, linux-kernel, mchehab, Frank.Li, hverkuil+cisco,
guoniu.zhou
On 26/08/11 07:04AM, Laurent Pinchart wrote:
> On Tue, Aug 11, 2026 at 07:29:36AM +0330, Ali Nasrollahi wrote:
> > On 26/08/10 07:28PM, Laurent Pinchart wrote:
> > > On Mon, Aug 10, 2026 at 07:54:07PM +0330, Ali Nasrollahi wrote:
> > > > The V4L2 core currently limits the number of registered video devices to
> > > > 256. This can become a restriction for workloads that create a large
> > > > number of virtual video devices, such as v4l2loopback instances.
> > >
> > > We don't support v4l2loopback upstream though.
> >
> > Yes, you are correct.
> >
> > But perhaps my description was a bit misleading. The main idea of this
> > patch is not to support out-of-tree modules by any means, but to allow a
> > configurable number of V4L2 devices to be created and used, whether
> > through loopback devices or other means.
>
> Do you have a use case where you're reaching the limit without
> out-of-tree drivers ?
>
My workloads depend on loopback devices which is how I've reached the
limit, however I haven't had a usecase with a such number of deivces
through physical hardware.
> > > > Make the maximum number of video devices configurable through a module
> > > > parameter. The default and minimum remain at the existing limit of 256,
> > > > while the maximum is capped at 4096.
> > > >
> > > > The parameter is only available when CONFIG_VIDEO_FIXED_MINOR_RANGES is
> > > > disabled, as the fixed minor allocation scheme relies on the existing
> > > > minor ranges.
> > > >
> > > > The device array is allocated according to the configured limit, while
> > > > the allocation bitmaps remain statically sized to the maximum supported
> > > > limit of 4096.
> > > >
> > > > Signed-off-by: Ali Nasrollahi <A.Nasrolahi01@gmail.com>
> > > > ---
> > > > drivers/media/v4l2-core/v4l2-dev.c | 70 +++++++++++++++++++++++-------
> > > > 1 file changed, 55 insertions(+), 15 deletions(-)
> > > >
> > > > diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c
> > > > index fd267fb74905..5a526b577970 100644
> > > > --- a/drivers/media/v4l2-core/v4l2-dev.c
> > > > +++ b/drivers/media/v4l2-core/v4l2-dev.c
> > > > @@ -31,7 +31,8 @@
> > > > #include <media/v4l2-ioctl.h>
> > > > #include <media/v4l2-event.h>
> > > >
> > > > -#define VIDEO_NUM_DEVICES 256
> > > > +#define VIDEO_MIN_NUM_DEVICES 256
> > > > +#define VIDEO_MAX_NUM_DEVICES 4096
> > > > #define VIDEO_NAME "video4linux"
> > > >
> > > > #define dprintk(fmt, arg...) do { \
> > > > @@ -39,6 +40,27 @@
> > > > __func__, ##arg); \
> > > > } while (0)
> > > >
> > > > +static unsigned int video_nr_devices = VIDEO_MIN_NUM_DEVICES;
> > > > +
> > > > +#ifndef CONFIG_VIDEO_FIXED_MINOR_RANGES
> > > > +static int param_set_video_nr_devices(const char *val,
> > > > + const struct kernel_param *kp)
> > > > +{
> > > > + return param_set_uint_minmax(val, kp, VIDEO_MIN_NUM_DEVICES,
> > > > + VIDEO_MAX_NUM_DEVICES);
> > > > +}
> > > > +
> > > > +static const struct kernel_param_ops param_ops_video_nr_devices = {
> > > > + .set = param_set_video_nr_devices,
> > > > + .get = param_get_uint,
> > > > +};
> > > > +
> > > > +module_param_cb(video_nr_devices, ¶m_ops_video_nr_devices,
> > > > + &video_nr_devices, 0444);
> > > > +
> > > > +MODULE_PARM_DESC(video_nr_devices, "Maximum number of V4L2 devices (256-4096)");
> > > > +#endif
> > > > +
> > > > /*
> > > > * sysfs stuff
> > > > */
> > > > @@ -98,9 +120,14 @@ static struct dentry *v4l2_debugfs_root_dir;
> > > > /*
> > > > * Active devices
> > > > */
> > > > -static struct video_device *video_devices[VIDEO_NUM_DEVICES];
> > > > +#ifdef CONFIG_VIDEO_FIXED_MINOR_RANGES
> > > > +static struct video_device *video_devices[VIDEO_MIN_NUM_DEVICES];
> > > > +static DECLARE_BITMAP(devnode_nums[VFL_TYPE_MAX], VIDEO_MIN_NUM_DEVICES);
> > > > +#else
> > > > +static struct video_device **video_devices;
> > > > +static DECLARE_BITMAP(devnode_nums[VFL_TYPE_MAX], VIDEO_MAX_NUM_DEVICES);
> > > > +#endif
> > > > static DEFINE_MUTEX(videodev_lock);
> > > > -static DECLARE_BITMAP(devnode_nums[VFL_TYPE_MAX], VIDEO_NUM_DEVICES);
> > > >
> > > > /* Device node utility functions */
> > > >
> > > > @@ -504,7 +531,7 @@ static const struct file_operations v4l2_fops = {
> > > > * in the video_device array, but it was able to obtain a minor number.
> > > > *
> > > > * This means that we can always obtain a free stream index number since
> > > > - * the worst case scenario is that there are VIDEO_NUM_DEVICES - 1 slots in
> > > > + * the worst case scenario is that there are video_nr_devices - 1 slots in
> > > > * use of the video_device array.
> > > > *
> > > > * Returns a free index number.
> > > > @@ -513,19 +540,19 @@ static int get_index(struct video_device *vdev)
> > > > {
> > > > /* This can be static since this function is called with the global
> > > > videodev_lock held. */
> > > > - static DECLARE_BITMAP(used, VIDEO_NUM_DEVICES);
> > > > + static DECLARE_BITMAP(used, VIDEO_MAX_NUM_DEVICES);
> > > > int i;
> > > >
> > > > - bitmap_zero(used, VIDEO_NUM_DEVICES);
> > > > + bitmap_zero(used, VIDEO_MAX_NUM_DEVICES);
> > > >
> > > > - for (i = 0; i < VIDEO_NUM_DEVICES; i++) {
> > > > + for (i = 0; i < video_nr_devices; i++) {
> > > > if (video_devices[i] != NULL &&
> > > > video_devices[i]->v4l2_dev == vdev->v4l2_dev) {
> > > > __set_bit(video_devices[i]->index, used);
> > > > }
> > > > }
> > > >
> > > > - return find_first_zero_bit(used, VIDEO_NUM_DEVICES);
> > > > + return find_first_zero_bit(used, video_nr_devices);
> > > > }
> > > >
> > > > #define SET_VALID_IOCTL(ops, cmd, op) \
> > > > @@ -915,7 +942,7 @@ int __video_register_device(struct video_device *vdev,
> > > > int i = 0;
> > > > int ret;
> > > > int minor_offset = 0;
> > > > - int minor_cnt = VIDEO_NUM_DEVICES;
> > > > + int minor_cnt = video_nr_devices;
> > > > const char *name_base;
> > > >
> > > > /* A minor value of -1 marks this video device as never
> > > > @@ -1020,10 +1047,10 @@ int __video_register_device(struct video_device *vdev,
> > > > #else
> > > > /* The device node number and minor numbers are independent, so
> > > > we just find the first free minor number. */
> > > > - for (i = 0; i < VIDEO_NUM_DEVICES; i++)
> > > > + for (i = 0; i < video_nr_devices; i++)
> > > > if (video_devices[i] == NULL)
> > > > break;
> > > > - if (i == VIDEO_NUM_DEVICES) {
> > > > + if (i == video_nr_devices) {
> > > > mutex_unlock(&videodev_lock);
> > > > pr_err("could not get a free minor\n");
> > > > return -ENFILE;
> > > > @@ -1032,7 +1059,7 @@ int __video_register_device(struct video_device *vdev,
> > > > vdev->minor = i + minor_offset;
> > > > vdev->num = nr;
> > > >
> > > > - if (WARN_ON(vdev->minor >= VIDEO_NUM_DEVICES)) {
> > > > + if (WARN_ON(vdev->minor >= video_nr_devices)) {
> > > > mutex_unlock(&videodev_lock);
> > > > return -EINVAL;
> > > > }
> > > > @@ -1241,7 +1268,7 @@ static int __init videodev_init(void)
> > > > int ret;
> > > >
> > > > pr_info("Linux video capture interface: v2.00\n");
> > > > - ret = register_chrdev_region(dev, VIDEO_NUM_DEVICES, VIDEO_NAME);
> > > > + ret = register_chrdev_region(dev, video_nr_devices, VIDEO_NAME);
> > > > if (ret < 0) {
> > > > pr_warn("videodev: unable to get major %d\n",
> > > > VIDEO_MAJOR);
> > > > @@ -1250,11 +1277,21 @@ static int __init videodev_init(void)
> > > >
> > > > ret = class_register(&video_class);
> > > > if (ret < 0) {
> > > > - unregister_chrdev_region(dev, VIDEO_NUM_DEVICES);
> > > > + unregister_chrdev_region(dev, video_nr_devices);
> > > > pr_warn("video_dev: class_register failed\n");
> > > > return -EIO;
> > > > }
> > > >
> > > > +#ifndef CONFIG_VIDEO_FIXED_MINOR_RANGES
> > > > + video_devices = kzalloc_objs(*video_devices, video_nr_devices);
> > > > + if (!video_devices) {
> > > > + class_unregister(&video_class);
> > > > + unregister_chrdev_region(dev, video_nr_devices);
> > > > + pr_warn("video_dev: failed to allocate video_devices\n");
> > > > + return -ENOMEM;
> > > > + }
> > > > +#endif
> > > > +
> > > > return 0;
> > > > }
> > > >
> > > > @@ -1262,8 +1299,11 @@ static void __exit videodev_exit(void)
> > > > {
> > > > dev_t dev = MKDEV(VIDEO_MAJOR, 0);
> > > >
> > > > +#ifndef CONFIG_VIDEO_FIXED_MINOR_RANGES
> > > > + kvfree(video_devices);
> > > > +#endif
> > > > class_unregister(&video_class);
> > > > - unregister_chrdev_region(dev, VIDEO_NUM_DEVICES);
> > > > + unregister_chrdev_region(dev, video_nr_devices);
> > > > debugfs_remove_recursive(v4l2_debugfs_root_dir);
> > > > v4l2_debugfs_root_dir = NULL;
> > > > }
>
> --
> Regards,
>
> Laurent Pinchart
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-08-11 4:29 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-10 16:24 [PATCH] media: v4l2-core: make number of video devices configurable Ali Nasrollahi
2026-08-10 16:28 ` Laurent Pinchart
2026-08-11 3:59 ` Ali Nasrollahi
2026-08-11 4:04 ` Laurent Pinchart
2026-08-11 4:29 ` Ali Nasrollahi
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox