Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package v4l2loopback for openSUSE:Factory checked in at 2026-07-18 22:25:00 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/v4l2loopback (Old) and /work/SRC/openSUSE:Factory/.v4l2loopback.new.24530 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "v4l2loopback" Sat Jul 18 22:25:00 2026 rev:29 rq:1366517 version:0.15.4 Changes: -------- --- /work/SRC/openSUSE:Factory/v4l2loopback/v4l2loopback.changes 2026-04-28 12:02:03.507685811 +0200 +++ /work/SRC/openSUSE:Factory/.v4l2loopback.new.24530/v4l2loopback.changes 2026-07-18 22:26:14.456612708 +0200 @@ -1,0 +2,11 @@ +Sat Jul 18 04:57:47 UTC 2026 - <[email protected]> + +- Update to version 0.15.4: + * Released 0.15.4 + * Make sure that user-provided max_buffers does not exceed MAX_BUFFERS + * Lock image during memcpy access + * Use full ordering for buffer mapped flag + * trim req_count early + * [ci] try again to run kmod-compile on fedora>=41 + +------------------------------------------------------------------- Old: ---- v4l2loopback-0.15.3.tar.xz New: ---- v4l2loopback-0.15.4.tar.xz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ v4l2loopback.spec ++++++ --- /var/tmp/diff_new_pack.EoGC5S/_old 2026-07-18 22:26:15.356642926 +0200 +++ /var/tmp/diff_new_pack.EoGC5S/_new 2026-07-18 22:26:15.356642926 +0200 @@ -1,7 +1,7 @@ # # spec file for package v4l2loopback # -# Copyright (c) 2025 SUSE LLC +# Copyright (c) 2026 SUSE LLC and contributors # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -30,7 +30,7 @@ %{!?_modulesloaddir: %define _modulesloaddir /usr/lib/modules-load.d/} Name: v4l2loopback -Version: 0.15.3 +Version: 0.15.4 Release: 0 Summary: A kernel module to create V4L2 loopback devices License: GPL-2.0-or-later ++++++ _service ++++++ --- /var/tmp/diff_new_pack.EoGC5S/_old 2026-07-18 22:26:15.392644135 +0200 +++ /var/tmp/diff_new_pack.EoGC5S/_new 2026-07-18 22:26:15.396644269 +0200 @@ -4,7 +4,7 @@ <param name="scm">git</param> <param name="versionformat">@PARENT_TAG@</param> <param name="versionrewrite-pattern">v(.*)</param> - <param name="revision">v0.15.3</param> + <param name="revision">v0.15.4</param> <param name="changesgenerate">enable</param> </service> <service name="recompress" mode="manual"> ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.EoGC5S/_old 2026-07-18 22:26:15.420645075 +0200 +++ /var/tmp/diff_new_pack.EoGC5S/_new 2026-07-18 22:26:15.424645209 +0200 @@ -1,6 +1,6 @@ <servicedata> <service name="tar_scm"> <param name="url">https://github.com/v4l2loopback/v4l2loopback.git</param> - <param name="changesrevision">a7e4a4dea36187ad3550c797d647bcc50faced42</param></service></servicedata> + <param name="changesrevision">0f9ee86760b7f2bea174b7e3e7a1d38845da0ab4</param></service></servicedata> (No newline at EOF) ++++++ v4l2loopback-0.15.3.tar.xz -> v4l2loopback-0.15.4.tar.xz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/v4l2loopback-0.15.3/.github/workflows/kmod-compatibility-checks.yml new/v4l2loopback-0.15.4/.github/workflows/kmod-compatibility-checks.yml --- old/v4l2loopback-0.15.3/.github/workflows/kmod-compatibility-checks.yml 2025-11-24 14:15:11.000000000 +0100 +++ new/v4l2loopback-0.15.4/.github/workflows/kmod-compatibility-checks.yml 2026-06-24 15:50:52.000000000 +0200 @@ -96,7 +96,7 @@ not_dnf5=true; if dnf5 --version >/dev/null; then not_dnf5=false; fi ${not_dnf5} || echo "running dnf5-based distribution (Fedora>=41,...)" ${not_dnf5} || dnf5 upgrade -y --refresh - ${not_dnf5} || dnf5 install -y --setopt=install_weak_deps=False --skip-unavailable lsb-release dkms kernel-devel kernel-headers kernel-modules-core + ${not_dnf5} || dnf5 install -y --setopt=install_weak_deps=False --skip-unavailable lsb-release dkms kernel-devel kernel-headers kernel-modules-core || dnf5 install -y --setopt=install_weak_deps=False --skip-unavailable lsb-release dkms kernel-devel kernel-headers kernel-modules-cor not_dnf=true; if ${not_dnf5} && dnf --version>/dev/null; then not_dnf=false; fi ${not_dnf} || echo "running dnf-based distribution (Fedora<41,...)" ${not_dnf} || dnf upgrade -y --refresh diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/v4l2loopback-0.15.3/ChangeLog new/v4l2loopback-0.15.4/ChangeLog --- old/v4l2loopback-0.15.3/ChangeLog 2025-11-24 14:15:11.000000000 +0100 +++ new/v4l2loopback-0.15.4/ChangeLog 2026-06-24 15:50:52.000000000 +0200 @@ -1,3 +1,20 @@ +v4l2loopback (0.15.4) unstable; urgency=medium + + [ IOhannes m zmölnig ] + * [ci] try again to run kmod-compile on fedora>=41 + * Make sure that user-provided max_buffers does not exceed MAX_BUFFERS + Thanks: Team 42-b3yond-6ug <https://b3yond.org/> + Thanks: snpshtwrx & Johnny Nguyen + + [ Jakub Acs ] + * Trim req_count early + + [ stephematician ] + * Use full ordering for buffer mapped flag + * Lock image during memcpy access + + -- IOhannes m zmölnig (Debian/GNU) <[email protected]> Wed, 24 Jun 2026 15:45:41 +0200 + v4l2loopback (0.15.3) unstable; urgency=medium [ IOhannes m zmölnig ] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/v4l2loopback-0.15.3/dkms.conf new/v4l2loopback-0.15.4/dkms.conf --- old/v4l2loopback-0.15.3/dkms.conf 2025-11-24 14:15:11.000000000 +0100 +++ new/v4l2loopback-0.15.4/dkms.conf 2026-06-24 15:50:52.000000000 +0200 @@ -1,5 +1,5 @@ PACKAGE_NAME="v4l2loopback" -PACKAGE_VERSION="0.15.3" +PACKAGE_VERSION="0.15.4" # V4L2_COLORSPACE_DCI_P3 BUILD_EXCLUSIVE_KERNEL_MIN="4.4" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/v4l2loopback-0.15.3/v4l2loopback.c new/v4l2loopback-0.15.4/v4l2loopback.c --- old/v4l2loopback-0.15.3/v4l2loopback.c 2025-11-24 14:15:11.000000000 +0100 +++ new/v4l2loopback-0.15.4/v4l2loopback.c 2026-06-24 15:50:52.000000000 +0200 @@ -879,7 +879,9 @@ /* forward declarations */ static void client_usage_queue_event(struct video_device *vdev); -static bool any_buffers_mapped(struct v4l2_loopback_device *dev); +static bool any_mapped_buffer(struct v4l2_loopback_device *dev); +static void get_buffer(struct v4l2l_buffer *buf); +static void put_buffer(struct v4l2l_buffer *buf); static int allocate_buffers(struct v4l2_loopback_device *dev, struct v4l2_pix_format *pix_format); static void init_buffers(struct v4l2_loopback_device *dev, u32 bytes_used, @@ -1372,7 +1374,7 @@ if (result < 0) return result; if (!dev->keep_format) { - if (has_no_owners(dev) && !any_buffers_mapped(dev)) + if (has_no_owners(dev) && !any_mapped_buffer(dev)) free_buffers(dev); } mutex_unlock(&dev->image_mutex); @@ -1585,7 +1587,7 @@ flags |= V4L2_BUF_FLAG_DONE; \ } while (0) -static bool any_buffers_mapped(struct v4l2_loopback_device *dev) +static bool any_mapped_buffer(struct v4l2_loopback_device *dev) { u32 index; for (index = 0; index < dev->buffer_count; ++index) @@ -1594,6 +1596,18 @@ return false; } +static void get_buffer(struct v4l2l_buffer *buf) +{ + if (atomic_inc_return(&buf->use_count)) + buf->buffer.flags |= V4L2_BUF_FLAG_MAPPED; +} + +static void put_buffer(struct v4l2l_buffer *buf) +{ + if (atomic_dec_and_test(&buf->use_count)) + buf->buffer.flags &= ~V4L2_BUF_FLAG_MAPPED; +} + static void prepare_buffer_queue(struct v4l2_loopback_device *dev, int count) { struct v4l2l_buffer *bufd, *n; @@ -1651,6 +1665,9 @@ reqbuf->memory, req_count, dev->used_buffer_count, dev->buffer_count); + if (req_count > dev->buffer_count) + req_count = dev->buffer_count; + switch (reqbuf->memory) { case V4L2_MEMORY_MMAP: #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0) @@ -1719,7 +1736,7 @@ if (has_other_owners(opener, dev) && dev->used_buffer_count > 0) { /* allow 'allocation' of existing number of buffers */ req_count = dev->used_buffer_count; - } else if (any_buffers_mapped(dev)) { + } else if (any_mapped_buffer(dev)) { /* do not allow re-allocation if buffers are mapped */ result = -EBUSY; goto exit_reqbufs_unlock; @@ -1727,10 +1744,6 @@ MARK(); opener->buffer_count = 0; - - if (req_count > dev->buffer_count) - req_count = dev->buffer_count; - if (has_no_owners(dev)) { result = allocate_buffers(dev, &dev->pix_format); if (result < 0) @@ -1810,17 +1823,24 @@ timer_delete_sync(&dev->sustain_timer); timer_delete_sync(&dev->timeout_timer); - spin_lock_bh(&dev->list_lock); - list_move_tail(&buf->list_head, &dev->outbufs_list); - spin_unlock_bh(&dev->list_lock); + mutex_lock(&dev->image_mutex); + if (dev->used_buffer_count != 0) { + spin_lock_bh(&dev->list_lock); + list_move_tail(&buf->list_head, &dev->outbufs_list); + spin_unlock_bh(&dev->list_lock); - spin_lock_bh(&dev->lock); - dev->bufpos2index[v4l2l_mod64(dev->write_position, - dev->used_buffer_count)] = - buf->buffer.index; - ++dev->write_position; - dev->reread_count = 0; + spin_lock_bh(&dev->lock); + dev->bufpos2index[v4l2l_mod64(dev->write_position, + dev->used_buffer_count)] = + buf->buffer.index; + ++dev->write_position; + dev->reread_count = 0; + spin_unlock_bh(&dev->lock); + } + mutex_unlock(&dev->image_mutex); + + spin_lock_bh(&dev->lock); check_timers(dev); spin_unlock_bh(&dev->lock); } @@ -1934,6 +1954,11 @@ return -EAGAIN; wait_event_interruptible(dev->read_event, can_read(dev, opener)); + mutex_lock(&dev->image_mutex); + if (!dev->image || dev->used_buffer_count == 0) { + mutex_unlock(&dev->image_mutex); + return -EINVAL; + } spin_lock_bh(&dev->lock); if (dev->write_position == opener->read_position) { if (dev->reread_count > opener->reread_count + 2) @@ -1953,21 +1978,20 @@ } timeout_happened = dev->timeout_happened && (dev->timeout_jiffies > 0); dev->timeout_happened = 0; + index = dev->bufpos2index[pos]; + if (timeout_happened) + get_buffer(&dev->buffers[index]); + spin_unlock_bh(&dev->lock); + mutex_unlock(&dev->image_mutex); - index = dev->bufpos2index[pos]; if (timeout_happened) { - if (index >= dev->used_buffer_count) { - dprintkrw("get_capture_buffer() read position is at " - "an unallocated buffer [index=%u]\n", - index); - return -EFAULT; - } /* although allocated on-demand, timeout_image is freed only * in free_buffers(), so we don't need to worry about it being * deallocated suddenly */ memcpy(dev->image + dev->buffers[index].buffer.m.offset, dev->timeout_image, dev->buffer_size); + put_buffer(&dev->buffers[index]); } return (int)index; } @@ -2182,22 +2206,16 @@ /* file operations */ static void vm_open(struct vm_area_struct *vma) { - struct v4l2l_buffer *buf; + struct v4l2l_buffer *buf = vma->vm_private_data; MARK(); - - buf = vma->vm_private_data; - atomic_inc(&buf->use_count); - buf->buffer.flags |= V4L2_BUF_FLAG_MAPPED; + get_buffer(buf); } static void vm_close(struct vm_area_struct *vma) { - struct v4l2l_buffer *buf; + struct v4l2l_buffer *buf = vma->vm_private_data; MARK(); - - buf = vma->vm_private_data; - if (atomic_dec_and_test(&buf->use_count)) - buf->buffer.flags &= ~V4L2_BUF_FLAG_MAPPED; + put_buffer(buf); } static struct vm_operations_struct vm_ops = { @@ -2274,8 +2292,8 @@ vma->vm_ops = &vm_ops; vma->vm_private_data = buffer; + get_buffer(buffer); - vm_open(vma); exit_mmap_unlock: mutex_unlock(&dev->image_mutex); return result; @@ -2454,14 +2472,26 @@ index = get_capture_buffer(file); if (index < 0) return index; + + mutex_lock(&dev->image_mutex); + if (!dev->image) { + mutex_unlock(&dev->image_mutex); + return -EINVAL; + } + get_buffer(&dev->buffers[index]); + mutex_unlock(&dev->image_mutex); + b = &dev->buffers[index].buffer; if (count > b->bytesused) count = b->bytesused; + if (copy_to_user((void *)buf, (void *)(dev->image + b->m.offset), count)) { printk(KERN_ERR "v4l2-loopback read() failed copy_to_user()\n"); + put_buffer(&dev->buffers[index]); return -EFAULT; } + put_buffer(&dev->buffers[index]); return count; } @@ -2480,15 +2510,25 @@ if (count > dev->buffer_size) count = dev->buffer_size; + + mutex_lock(&dev->image_mutex); + if (!dev->image || dev->used_buffer_count == 0) { + mutex_unlock(&dev->image_mutex); + return -EINVAL; + } index = v4l2l_mod64(dev->write_position, dev->used_buffer_count); - b = &dev->buffers[index].buffer; + get_buffer(&dev->buffers[index]); + mutex_unlock(&dev->image_mutex); + b = &dev->buffers[index].buffer; if (copy_from_user((void *)(dev->image + b->m.offset), (void *)buf, count)) { printk(KERN_ERR "v4l2-loopback write() failed copy_from_user()\n"); + put_buffer(&dev->buffers[index]); return -EFAULT; } + put_buffer(&dev->buffers[index]); b->bytesused = count; v4l2l_get_timestamp(b); @@ -2508,7 +2548,7 @@ dprintk("free_buffers() with image@%p\n", dev->image); if (!dev->image) return; - if (!has_no_owners(dev) || any_buffers_mapped(dev)) + if (!has_no_owners(dev) || any_mapped_buffer(dev)) /* maybe an opener snuck in before image_mutex was acquired */ printk(KERN_WARNING "v4l2-loopback free_buffers() buffers of video device " @@ -2558,7 +2598,7 @@ image_size, buffer_size, dev->buffer_count); if (dev->image) { /* check that no buffers are expected in user-space */ - if (!has_no_owners(dev) || any_buffers_mapped(dev)) + if (!has_no_owners(dev) || any_mapped_buffer(dev)) return -EBUSY; dprintk("allocate_buffers() existing size=%lubytes\n", dev->image_size); @@ -2762,6 +2802,10 @@ int nr = -1; + /* Fix: Ensure buffer count does not exceed the statically allocated array size */ + if (_max_buffers > MAX_BUFFERS) + _max_buffers = MAX_BUFFERS; + if (conf) { const int output_nr = conf->output_nr; #ifdef SPLIT_DEVICES diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/v4l2loopback-0.15.3/v4l2loopback.h new/v4l2loopback-0.15.4/v4l2loopback.h --- old/v4l2loopback-0.15.3/v4l2loopback.h 2025-11-24 14:15:11.000000000 +0100 +++ new/v4l2loopback-0.15.4/v4l2loopback.h 2026-06-24 15:50:52.000000000 +0200 @@ -12,7 +12,7 @@ #define V4L2LOOPBACK_VERSION_MAJOR 0 #define V4L2LOOPBACK_VERSION_MINOR 15 -#define V4L2LOOPBACK_VERSION_BUGFIX 3 +#define V4L2LOOPBACK_VERSION_BUGFIX 4 /* /dev/v4l2loopback interface */
