]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
Fixes for 4.4
authorSasha Levin <sashal@kernel.org>
Fri, 22 May 2020 00:42:56 +0000 (20:42 -0400)
committerSasha Levin <sashal@kernel.org>
Fri, 22 May 2020 00:42:56 +0000 (20:42 -0400)
Signed-off-by: Sasha Levin <sashal@kernel.org>
18 files changed:
queue-4.4/drivers-media-media-devnode-clear-private_data-befor.patch [new file with mode: 0644]
queue-4.4/i2c-dev-don-t-get-i2c-adapter-via-i2c_dev.patch [new file with mode: 0644]
queue-4.4/i2c-dev-don-t-start-function-name-with-return.patch [new file with mode: 0644]
queue-4.4/i2c-dev-fix-the-race-between-the-release-of-i2c_dev-.patch [new file with mode: 0644]
queue-4.4/i2c-dev-switch-from-register_chrdev-to-cdev-api.patch [new file with mode: 0644]
queue-4.4/i2c-dev-use-after-free-in-detach.patch [new file with mode: 0644]
queue-4.4/media-device-dynamically-allocate-struct-media_devno.patch [new file with mode: 0644]
queue-4.4/media-devnode-add-missing-mutex-lock-in-error-handle.patch [new file with mode: 0644]
queue-4.4/media-devnode-fix-namespace-mess.patch [new file with mode: 0644]
queue-4.4/media-fix-media-devnode-ioctl-syscall-and-unregister.patch [new file with mode: 0644]
queue-4.4/media-fix-media_open-to-clear-filp-private_data-in-e.patch [new file with mode: 0644]
queue-4.4/media-fix-use-after-free-in-cdev_put-when-app-exits-.patch [new file with mode: 0644]
queue-4.4/padata-initialize-pd-cpu-with-effective-cpumask.patch [new file with mode: 0644]
queue-4.4/padata-purge-get_cpu-and-reorder_via_wq-from-padata_.patch [new file with mode: 0644]
queue-4.4/padata-replace-delayed-timer-with-immediate-workqueu.patch [new file with mode: 0644]
queue-4.4/padata-set-cpu_index-of-unused-cpus-to-1.patch [new file with mode: 0644]
queue-4.4/sched-fair-cpumask-export-for_each_cpu_wrap.patch [new file with mode: 0644]
queue-4.4/series

diff --git a/queue-4.4/drivers-media-media-devnode-clear-private_data-befor.patch b/queue-4.4/drivers-media-media-devnode-clear-private_data-befor.patch
new file mode 100644 (file)
index 0000000..df0ba5f
--- /dev/null
@@ -0,0 +1,40 @@
+From 5d135c6a3e6cfb279e3fde493f856173d484d5e7 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 21 Mar 2016 10:30:28 -0300
+Subject: drivers/media/media-devnode: clear private_data before put_device()
+
+From: Max Kellermann <max@duempel.org>
+
+commit bf244f665d76d20312c80524689b32a752888838 upstream.
+
+Callbacks invoked from put_device() may free the struct media_devnode
+pointer, so any cleanup needs to be done before put_device().
+
+Signed-off-by: Max Kellermann <max@duempel.org>
+Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/media/media-devnode.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/media/media-devnode.c b/drivers/media/media-devnode.c
+index a8cb52dc8c4f..6c56aebd8db0 100644
+--- a/drivers/media/media-devnode.c
++++ b/drivers/media/media-devnode.c
+@@ -197,10 +197,11 @@ static int media_release(struct inode *inode, struct file *filp)
+       if (mdev->fops->release)
+               mdev->fops->release(filp);
++      filp->private_data = NULL;
++
+       /* decrease the refcount unconditionally since the release()
+          return value is ignored. */
+       put_device(&mdev->dev);
+-      filp->private_data = NULL;
+       return 0;
+ }
+-- 
+2.25.1
+
diff --git a/queue-4.4/i2c-dev-don-t-get-i2c-adapter-via-i2c_dev.patch b/queue-4.4/i2c-dev-don-t-get-i2c-adapter-via-i2c_dev.patch
new file mode 100644 (file)
index 0000000..50f4378
--- /dev/null
@@ -0,0 +1,47 @@
+From 940eeed2adac118127c453aff2000fd6f02c021e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 5 Jul 2016 19:57:06 -0700
+Subject: i2c-dev: don't get i2c adapter via i2c_dev
+
+From: viresh kumar <viresh.kumar@linaro.org>
+
+commit 5136ed4fcb05cd4981cc6034a11e66370ed84789 upstream.
+
+There is no code protecting i2c_dev to be freed after it is returned
+from i2c_dev_get_by_minor() and using it to access the value which we
+already have (minor) isn't safe really.
+
+Avoid using it and get the adapter directly from 'minor'.
+
+Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
+Reviewed-by: Jean Delvare <jdelvare@suse.de>
+Tested-by: Jean Delvare <jdelvare@suse.de>
+Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/i2c/i2c-dev.c | 7 +------
+ 1 file changed, 1 insertion(+), 6 deletions(-)
+
+diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c
+index e5cd307ebfc9..5543b49e2e05 100644
+--- a/drivers/i2c/i2c-dev.c
++++ b/drivers/i2c/i2c-dev.c
+@@ -492,13 +492,8 @@ static int i2cdev_open(struct inode *inode, struct file *file)
+       unsigned int minor = iminor(inode);
+       struct i2c_client *client;
+       struct i2c_adapter *adap;
+-      struct i2c_dev *i2c_dev;
+-
+-      i2c_dev = i2c_dev_get_by_minor(minor);
+-      if (!i2c_dev)
+-              return -ENODEV;
+-      adap = i2c_get_adapter(i2c_dev->adap->nr);
++      adap = i2c_get_adapter(minor);
+       if (!adap)
+               return -ENODEV;
+-- 
+2.25.1
+
diff --git a/queue-4.4/i2c-dev-don-t-start-function-name-with-return.patch b/queue-4.4/i2c-dev-don-t-start-function-name-with-return.patch
new file mode 100644 (file)
index 0000000..723f86f
--- /dev/null
@@ -0,0 +1,54 @@
+From 108a1d68bee0b317808828d0f0d3354e45a411ad Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 27 May 2016 13:13:01 +0200
+Subject: i2c: dev: don't start function name with 'return'
+
+From: Wolfram Sang <wsa@the-dreams.de>
+
+commit 72a71f869c95dc11b73f09fe18c593d4a0618c3f upstream.
+
+I stumbled multiple times over 'return_i2c_dev', especially before the
+actual 'return res'. It makes the code hard to read, so reanme the
+function to 'put_i2c_dev' which also better matches 'get_free_i2c_dev'.
+
+Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/i2c/i2c-dev.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c
+index 5fecc1d9e0a1..382c66d5a470 100644
+--- a/drivers/i2c/i2c-dev.c
++++ b/drivers/i2c/i2c-dev.c
+@@ -91,7 +91,7 @@ static struct i2c_dev *get_free_i2c_dev(struct i2c_adapter *adap)
+       return i2c_dev;
+ }
+-static void return_i2c_dev(struct i2c_dev *i2c_dev)
++static void put_i2c_dev(struct i2c_dev *i2c_dev)
+ {
+       spin_lock(&i2c_dev_list_lock);
+       list_del(&i2c_dev->list);
+@@ -582,7 +582,7 @@ static int i2cdev_attach_adapter(struct device *dev, void *dummy)
+ error:
+       cdev_del(&i2c_dev->cdev);
+ error_cdev:
+-      return_i2c_dev(i2c_dev);
++      put_i2c_dev(i2c_dev);
+       return res;
+ }
+@@ -599,7 +599,7 @@ static int i2cdev_detach_adapter(struct device *dev, void *dummy)
+       if (!i2c_dev) /* attach_adapter must have failed */
+               return 0;
+-      return_i2c_dev(i2c_dev);
++      put_i2c_dev(i2c_dev);
+       device_destroy(i2c_dev_class, MKDEV(I2C_MAJOR, adap->nr));
+       cdev_del(&i2c_dev->cdev);
+-- 
+2.25.1
+
diff --git a/queue-4.4/i2c-dev-fix-the-race-between-the-release-of-i2c_dev-.patch b/queue-4.4/i2c-dev-fix-the-race-between-the-release-of-i2c_dev-.patch
new file mode 100644 (file)
index 0000000..c026157
--- /dev/null
@@ -0,0 +1,188 @@
+From 1329cc3082b4fe3e34bbb839a4c8bfb22084729e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 11 Oct 2019 23:00:14 +0800
+Subject: i2c: dev: Fix the race between the release of i2c_dev and cdev
+
+From: Kevin Hao <haokexin@gmail.com>
+
+commit 1413ef638abae4ab5621901cf4d8ef08a4a48ba6 upstream.
+
+The struct cdev is embedded in the struct i2c_dev. In the current code,
+we would free the i2c_dev struct directly in put_i2c_dev(), but the
+cdev is manged by a kobject, and the release of it is not predictable.
+So it is very possible that the i2c_dev is freed before the cdev is
+entirely released. We can easily get the following call trace with
+CONFIG_DEBUG_KOBJECT_RELEASE and CONFIG_DEBUG_OBJECTS_TIMERS enabled.
+  ODEBUG: free active (active state 0) object type: timer_list hint: delayed_work_timer_fn+0x0/0x38
+  WARNING: CPU: 19 PID: 1 at lib/debugobjects.c:325 debug_print_object+0xb0/0xf0
+  Modules linked in:
+  CPU: 19 PID: 1 Comm: swapper/0 Tainted: G        W         5.2.20-yocto-standard+ #120
+  Hardware name: Marvell OcteonTX CN96XX board (DT)
+  pstate: 80c00089 (Nzcv daIf +PAN +UAO)
+  pc : debug_print_object+0xb0/0xf0
+  lr : debug_print_object+0xb0/0xf0
+  sp : ffff00001292f7d0
+  x29: ffff00001292f7d0 x28: ffff800b82151788
+  x27: 0000000000000001 x26: ffff800b892c0000
+  x25: ffff0000124a2558 x24: 0000000000000000
+  x23: ffff00001107a1d8 x22: ffff0000116b5088
+  x21: ffff800bdc6afca8 x20: ffff000012471ae8
+  x19: ffff00001168f2c8 x18: 0000000000000010
+  x17: 00000000fd6f304b x16: 00000000ee79de43
+  x15: ffff800bc0e80568 x14: 79616c6564203a74
+  x13: 6e6968207473696c x12: 5f72656d6974203a
+  x11: ffff0000113f0018 x10: 0000000000000000
+  x9 : 000000000000001f x8 : 0000000000000000
+  x7 : ffff0000101294cc x6 : 0000000000000000
+  x5 : 0000000000000000 x4 : 0000000000000001
+  x3 : 00000000ffffffff x2 : 0000000000000000
+  x1 : 387fc15c8ec0f200 x0 : 0000000000000000
+  Call trace:
+   debug_print_object+0xb0/0xf0
+   __debug_check_no_obj_freed+0x19c/0x228
+   debug_check_no_obj_freed+0x1c/0x28
+   kfree+0x250/0x440
+   put_i2c_dev+0x68/0x78
+   i2cdev_detach_adapter+0x60/0xc8
+   i2cdev_notifier_call+0x3c/0x70
+   notifier_call_chain+0x8c/0xe8
+   blocking_notifier_call_chain+0x64/0x88
+   device_del+0x74/0x380
+   device_unregister+0x54/0x78
+   i2c_del_adapter+0x278/0x2d0
+   unittest_i2c_bus_remove+0x3c/0x80
+   platform_drv_remove+0x30/0x50
+   device_release_driver_internal+0xf4/0x1c0
+   driver_detach+0x58/0xa0
+   bus_remove_driver+0x84/0xd8
+   driver_unregister+0x34/0x60
+   platform_driver_unregister+0x20/0x30
+   of_unittest_overlay+0x8d4/0xbe0
+   of_unittest+0xae8/0xb3c
+   do_one_initcall+0xac/0x450
+   do_initcall_level+0x208/0x224
+   kernel_init_freeable+0x2d8/0x36c
+   kernel_init+0x18/0x108
+   ret_from_fork+0x10/0x1c
+  irq event stamp: 3934661
+  hardirqs last  enabled at (3934661): [<ffff00001009fa04>] debug_exception_exit+0x4c/0x58
+  hardirqs last disabled at (3934660): [<ffff00001009fb14>] debug_exception_enter+0xa4/0xe0
+  softirqs last  enabled at (3934654): [<ffff000010081d94>] __do_softirq+0x46c/0x628
+  softirqs last disabled at (3934649): [<ffff0000100b4a1c>] irq_exit+0x104/0x118
+
+This is a common issue when using cdev embedded in a struct.
+Fortunately, we already have a mechanism to solve this kind of issue.
+Please see commit 233ed09d7fda ("chardev: add helper function to
+register char devs with a struct device") for more detail.
+
+In this patch, we choose to embed the struct device into the i2c_dev,
+and use the API provided by the commit 233ed09d7fda to make sure that
+the release of i2c_dev and cdev are in sequence.
+
+Signed-off-by: Kevin Hao <haokexin@gmail.com>
+Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/i2c/i2c-dev.c | 48 +++++++++++++++++++++++--------------------
+ 1 file changed, 26 insertions(+), 22 deletions(-)
+
+diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c
+index 5543b49e2e05..7584f292e2fd 100644
+--- a/drivers/i2c/i2c-dev.c
++++ b/drivers/i2c/i2c-dev.c
+@@ -47,7 +47,7 @@
+ struct i2c_dev {
+       struct list_head list;
+       struct i2c_adapter *adap;
+-      struct device *dev;
++      struct device dev;
+       struct cdev cdev;
+ };
+@@ -91,12 +91,14 @@ static struct i2c_dev *get_free_i2c_dev(struct i2c_adapter *adap)
+       return i2c_dev;
+ }
+-static void put_i2c_dev(struct i2c_dev *i2c_dev)
++static void put_i2c_dev(struct i2c_dev *i2c_dev, bool del_cdev)
+ {
+       spin_lock(&i2c_dev_list_lock);
+       list_del(&i2c_dev->list);
+       spin_unlock(&i2c_dev_list_lock);
+-      kfree(i2c_dev);
++      if (del_cdev)
++              cdev_device_del(&i2c_dev->cdev, &i2c_dev->dev);
++      put_device(&i2c_dev->dev);
+ }
+ static ssize_t name_show(struct device *dev,
+@@ -542,6 +544,14 @@ static const struct file_operations i2cdev_fops = {
+ static struct class *i2c_dev_class;
++static void i2cdev_dev_release(struct device *dev)
++{
++      struct i2c_dev *i2c_dev;
++
++      i2c_dev = container_of(dev, struct i2c_dev, dev);
++      kfree(i2c_dev);
++}
++
+ static int i2cdev_attach_adapter(struct device *dev, void *dummy)
+ {
+       struct i2c_adapter *adap;
+@@ -558,27 +568,23 @@ static int i2cdev_attach_adapter(struct device *dev, void *dummy)
+       cdev_init(&i2c_dev->cdev, &i2cdev_fops);
+       i2c_dev->cdev.owner = THIS_MODULE;
+-      res = cdev_add(&i2c_dev->cdev, MKDEV(I2C_MAJOR, adap->nr), 1);
+-      if (res)
+-              goto error_cdev;
+-
+-      /* register this i2c device with the driver core */
+-      i2c_dev->dev = device_create(i2c_dev_class, &adap->dev,
+-                                   MKDEV(I2C_MAJOR, adap->nr), NULL,
+-                                   "i2c-%d", adap->nr);
+-      if (IS_ERR(i2c_dev->dev)) {
+-              res = PTR_ERR(i2c_dev->dev);
+-              goto error;
++
++      device_initialize(&i2c_dev->dev);
++      i2c_dev->dev.devt = MKDEV(I2C_MAJOR, adap->nr);
++      i2c_dev->dev.class = i2c_dev_class;
++      i2c_dev->dev.parent = &adap->dev;
++      i2c_dev->dev.release = i2cdev_dev_release;
++      dev_set_name(&i2c_dev->dev, "i2c-%d", adap->nr);
++
++      res = cdev_device_add(&i2c_dev->cdev, &i2c_dev->dev);
++      if (res) {
++              put_i2c_dev(i2c_dev, false);
++              return res;
+       }
+       pr_debug("i2c-dev: adapter [%s] registered as minor %d\n",
+                adap->name, adap->nr);
+       return 0;
+-error:
+-      cdev_del(&i2c_dev->cdev);
+-error_cdev:
+-      put_i2c_dev(i2c_dev);
+-      return res;
+ }
+ static int i2cdev_detach_adapter(struct device *dev, void *dummy)
+@@ -594,9 +600,7 @@ static int i2cdev_detach_adapter(struct device *dev, void *dummy)
+       if (!i2c_dev) /* attach_adapter must have failed */
+               return 0;
+-      cdev_del(&i2c_dev->cdev);
+-      put_i2c_dev(i2c_dev);
+-      device_destroy(i2c_dev_class, MKDEV(I2C_MAJOR, adap->nr));
++      put_i2c_dev(i2c_dev, true);
+       pr_debug("i2c-dev: adapter [%s] unregistered\n", adap->name);
+       return 0;
+-- 
+2.25.1
+
diff --git a/queue-4.4/i2c-dev-switch-from-register_chrdev-to-cdev-api.patch b/queue-4.4/i2c-dev-switch-from-register_chrdev-to-cdev-api.patch
new file mode 100644 (file)
index 0000000..5f304b3
--- /dev/null
@@ -0,0 +1,124 @@
+From 528303832f25e979851e632cb34b24577b8d43b3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 3 May 2016 15:45:43 -0300
+Subject: i2c: dev: switch from register_chrdev to cdev API
+
+From: Erico Nunes <erico.nunes@datacom.ind.br>
+
+commit d6760b14d4a1243f918d983bba1e35c5a5cd5a6d upstream.
+
+i2c-dev had never moved away from the older register_chrdev interface to
+implement its char device registration. The register_chrdev API has the
+limitation of enabling only up to 256 i2c-dev busses to exist.
+
+Large platforms with lots of i2c devices (i.e. pluggable transceivers)
+with dedicated busses may have to exceed that limit.
+In particular, there are also platforms making use of the i2c bus
+multiplexing API, which instantiates a virtual bus for each possible
+multiplexed selection.
+
+This patch removes the register_chrdev usage and replaces it with the
+less old cdev API, which takes away the 256 i2c-dev bus limitation.
+It should not have any other impact for i2c bus drivers or user space.
+
+This patch has been tested on qemu x86 and qemu powerpc platforms with
+the aid of a module which adds and removes 5000 virtual i2c busses, as
+well as validated on an existing powerpc hardware platform which makes
+use of the i2c bus multiplexing API.
+i2c-dev busses with device minor numbers larger than 256 have also been
+validated to work with the existing i2c-tools.
+
+Signed-off-by: Erico Nunes <erico.nunes@datacom.ind.br>
+[wsa: kept includes sorted]
+Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
+[bwh: Backported to 4.4: adjust context]
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/i2c/i2c-dev.c | 19 +++++++++++++++----
+ 1 file changed, 15 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c
+index e56b774e7cf9..5fecc1d9e0a1 100644
+--- a/drivers/i2c/i2c-dev.c
++++ b/drivers/i2c/i2c-dev.c
+@@ -22,6 +22,7 @@
+ /* The I2C_RDWR ioctl code is written by Kolja Waschk <waschk@telos.de> */
++#include <linux/cdev.h>
+ #include <linux/kernel.h>
+ #include <linux/module.h>
+ #include <linux/device.h>
+@@ -47,9 +48,10 @@ struct i2c_dev {
+       struct list_head list;
+       struct i2c_adapter *adap;
+       struct device *dev;
++      struct cdev cdev;
+ };
+-#define I2C_MINORS    256
++#define I2C_MINORS    MINORMASK
+ static LIST_HEAD(i2c_dev_list);
+ static DEFINE_SPINLOCK(i2c_dev_list_lock);
+@@ -559,6 +561,12 @@ static int i2cdev_attach_adapter(struct device *dev, void *dummy)
+       if (IS_ERR(i2c_dev))
+               return PTR_ERR(i2c_dev);
++      cdev_init(&i2c_dev->cdev, &i2cdev_fops);
++      i2c_dev->cdev.owner = THIS_MODULE;
++      res = cdev_add(&i2c_dev->cdev, MKDEV(I2C_MAJOR, adap->nr), 1);
++      if (res)
++              goto error_cdev;
++
+       /* register this i2c device with the driver core */
+       i2c_dev->dev = device_create(i2c_dev_class, &adap->dev,
+                                    MKDEV(I2C_MAJOR, adap->nr), NULL,
+@@ -572,6 +580,8 @@ static int i2cdev_attach_adapter(struct device *dev, void *dummy)
+                adap->name, adap->nr);
+       return 0;
+ error:
++      cdev_del(&i2c_dev->cdev);
++error_cdev:
+       return_i2c_dev(i2c_dev);
+       return res;
+ }
+@@ -591,6 +601,7 @@ static int i2cdev_detach_adapter(struct device *dev, void *dummy)
+       return_i2c_dev(i2c_dev);
+       device_destroy(i2c_dev_class, MKDEV(I2C_MAJOR, adap->nr));
++      cdev_del(&i2c_dev->cdev);
+       pr_debug("i2c-dev: adapter [%s] unregistered\n", adap->name);
+       return 0;
+@@ -627,7 +638,7 @@ static int __init i2c_dev_init(void)
+       printk(KERN_INFO "i2c /dev entries driver\n");
+-      res = register_chrdev(I2C_MAJOR, "i2c", &i2cdev_fops);
++      res = register_chrdev_region(MKDEV(I2C_MAJOR, 0), I2C_MINORS, "i2c");
+       if (res)
+               goto out;
+@@ -651,7 +662,7 @@ static int __init i2c_dev_init(void)
+ out_unreg_class:
+       class_destroy(i2c_dev_class);
+ out_unreg_chrdev:
+-      unregister_chrdev(I2C_MAJOR, "i2c");
++      unregister_chrdev_region(MKDEV(I2C_MAJOR, 0), I2C_MINORS);
+ out:
+       printk(KERN_ERR "%s: Driver Initialisation failed\n", __FILE__);
+       return res;
+@@ -662,7 +673,7 @@ static void __exit i2c_dev_exit(void)
+       bus_unregister_notifier(&i2c_bus_type, &i2cdev_notifier);
+       i2c_for_each_dev(NULL, i2cdev_detach_adapter);
+       class_destroy(i2c_dev_class);
+-      unregister_chrdev(I2C_MAJOR, "i2c");
++      unregister_chrdev_region(MKDEV(I2C_MAJOR, 0), I2C_MINORS);
+ }
+ MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl> and "
+-- 
+2.25.1
+
diff --git a/queue-4.4/i2c-dev-use-after-free-in-detach.patch b/queue-4.4/i2c-dev-use-after-free-in-detach.patch
new file mode 100644 (file)
index 0000000..b6d498b
--- /dev/null
@@ -0,0 +1,39 @@
+From 7d36e754a433001e08a1339949e5192be29d966f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 28 May 2016 08:01:46 +0300
+Subject: i2c: dev: use after free in detach
+
+From: Dan Carpenter <dan.carpenter@oracle.com>
+
+commit e6be18f6d62c1d3b331ae020b76a29c2ccf6b0bf upstream.
+
+The call to put_i2c_dev() frees "i2c_dev" so there is a use after
+free when we call cdev_del(&i2c_dev->cdev).
+
+Fixes: d6760b14d4a1 ('i2c: dev: switch from register_chrdev to cdev API')
+Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
+Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/i2c/i2c-dev.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c
+index 382c66d5a470..e5cd307ebfc9 100644
+--- a/drivers/i2c/i2c-dev.c
++++ b/drivers/i2c/i2c-dev.c
+@@ -599,9 +599,9 @@ static int i2cdev_detach_adapter(struct device *dev, void *dummy)
+       if (!i2c_dev) /* attach_adapter must have failed */
+               return 0;
++      cdev_del(&i2c_dev->cdev);
+       put_i2c_dev(i2c_dev);
+       device_destroy(i2c_dev_class, MKDEV(I2C_MAJOR, adap->nr));
+-      cdev_del(&i2c_dev->cdev);
+       pr_debug("i2c-dev: adapter [%s] unregistered\n", adap->name);
+       return 0;
+-- 
+2.25.1
+
diff --git a/queue-4.4/media-device-dynamically-allocate-struct-media_devno.patch b/queue-4.4/media-device-dynamically-allocate-struct-media_devno.patch
new file mode 100644 (file)
index 0000000..a8068dc
--- /dev/null
@@ -0,0 +1,265 @@
+From 82b2a743620ff7f9f16ee889a400753dd2ea74e5 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 27 Apr 2016 19:28:26 -0300
+Subject: media-device: dynamically allocate struct media_devnode
+
+From: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
+
+commit a087ce704b802becbb4b0f2a20f2cb3f6911802e upstream.
+
+struct media_devnode is currently embedded at struct media_device.
+
+While this works fine during normal usage, it leads to a race
+condition during devnode unregister. the problem is that drivers
+assume that, after calling media_device_unregister(), the struct
+that contains media_device can be freed. This is not true, as it
+can't be freed until userspace closes all opened /dev/media devnodes.
+
+In other words, if the media devnode is still open, and media_device
+gets freed, any call to an ioctl will make the core to try to access
+struct media_device, with will cause an use-after-free and even GPF.
+
+Fix this by dynamically allocating the struct media_devnode and only
+freeing it when it is safe.
+
+Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
+Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
+[bwh: Backported to 4.4:
+ - Drop change in au0828
+ - Include <linux/slab.h> in media-device.c
+ - Adjust context]
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/media/media-device.c       | 40 +++++++++++++++++++++---------
+ drivers/media/media-devnode.c      |  8 +++++-
+ drivers/media/usb/uvc/uvc_driver.c |  2 +-
+ include/media/media-device.h       |  5 +---
+ include/media/media-devnode.h      | 10 +++++++-
+ 5 files changed, 46 insertions(+), 19 deletions(-)
+
+diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c
+index 7b39440192d6..fb018fe1a8f7 100644
+--- a/drivers/media/media-device.c
++++ b/drivers/media/media-device.c
+@@ -24,6 +24,7 @@
+ #include <linux/export.h>
+ #include <linux/ioctl.h>
+ #include <linux/media.h>
++#include <linux/slab.h>
+ #include <linux/types.h>
+ #include <media/media-device.h>
+@@ -234,7 +235,7 @@ 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);
++      struct media_device *dev = devnode->media_dev;
+       long ret;
+       switch (cmd) {
+@@ -303,7 +304,7 @@ static long media_device_compat_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);
++      struct media_device *dev = devnode->media_dev;
+       long ret;
+       switch (cmd) {
+@@ -344,7 +345,8 @@ static const struct media_file_operations media_device_fops = {
+ static ssize_t show_model(struct device *cd,
+                         struct device_attribute *attr, char *buf)
+ {
+-      struct media_device *mdev = to_media_device(to_media_devnode(cd));
++      struct media_devnode *devnode = to_media_devnode(cd);
++      struct media_device *mdev = devnode->media_dev;
+       return sprintf(buf, "%.*s\n", (int)sizeof(mdev->model), mdev->model);
+ }
+@@ -372,6 +374,7 @@ static void media_device_release(struct media_devnode *mdev)
+ int __must_check __media_device_register(struct media_device *mdev,
+                                        struct module *owner)
+ {
++      struct media_devnode *devnode;
+       int ret;
+       if (WARN_ON(mdev->dev == NULL || mdev->model[0] == 0))
+@@ -382,17 +385,27 @@ int __must_check __media_device_register(struct media_device *mdev,
+       spin_lock_init(&mdev->lock);
+       mutex_init(&mdev->graph_mutex);
++      devnode = kzalloc(sizeof(*devnode), GFP_KERNEL);
++      if (!devnode)
++              return -ENOMEM;
++
+       /* Register the device node. */
+-      mdev->devnode.fops = &media_device_fops;
+-      mdev->devnode.parent = mdev->dev;
+-      mdev->devnode.release = media_device_release;
+-      ret = media_devnode_register(&mdev->devnode, owner);
+-      if (ret < 0)
++      mdev->devnode = devnode;
++      devnode->fops = &media_device_fops;
++      devnode->parent = mdev->dev;
++      devnode->release = media_device_release;
++      ret = media_devnode_register(mdev, devnode, owner);
++      if (ret < 0) {
++              mdev->devnode = NULL;
++              kfree(devnode);
+               return ret;
++      }
+-      ret = device_create_file(&mdev->devnode.dev, &dev_attr_model);
++      ret = device_create_file(&devnode->dev, &dev_attr_model);
+       if (ret < 0) {
+-              media_devnode_unregister(&mdev->devnode);
++              mdev->devnode = NULL;
++              media_devnode_unregister(devnode);
++              kfree(devnode);
+               return ret;
+       }
+@@ -413,8 +426,11 @@ void media_device_unregister(struct media_device *mdev)
+       list_for_each_entry_safe(entity, next, &mdev->entities, list)
+               media_device_unregister_entity(entity);
+-      device_remove_file(&mdev->devnode.dev, &dev_attr_model);
+-      media_devnode_unregister(&mdev->devnode);
++      /* Check if mdev devnode was registered */
++      if (media_devnode_is_registered(mdev->devnode)) {
++              device_remove_file(&mdev->devnode->dev, &dev_attr_model);
++              media_devnode_unregister(mdev->devnode);
++      }
+ }
+ EXPORT_SYMBOL_GPL(media_device_unregister);
+diff --git a/drivers/media/media-devnode.c b/drivers/media/media-devnode.c
+index 98211c570e11..000efb17b95b 100644
+--- a/drivers/media/media-devnode.c
++++ b/drivers/media/media-devnode.c
+@@ -44,6 +44,7 @@
+ #include <linux/uaccess.h>
+ #include <media/media-devnode.h>
++#include <media/media-device.h>
+ #define MEDIA_NUM_DEVICES     256
+ #define MEDIA_NAME            "media"
+@@ -74,6 +75,8 @@ static void media_devnode_release(struct device *cd)
+       /* Release media_devnode and perform other cleanups as needed. */
+       if (devnode->release)
+               devnode->release(devnode);
++
++      kfree(devnode);
+ }
+ static struct bus_type media_bus_type = {
+@@ -221,6 +224,7 @@ static const struct file_operations media_devnode_fops = {
+ /**
+  * media_devnode_register - register a media device node
++ * @media_dev: struct media_device we want to register a device node
+  * @devnode: media device node structure we want to register
+  *
+  * The registration code assigns minor numbers and registers the new device node
+@@ -233,7 +237,8 @@ static const struct file_operations media_devnode_fops = {
+  * the media_devnode structure is *not* called, so the caller is responsible for
+  * freeing any data.
+  */
+-int __must_check media_devnode_register(struct media_devnode *devnode,
++int __must_check media_devnode_register(struct media_device *mdev,
++                                      struct media_devnode *devnode,
+                                       struct module *owner)
+ {
+       int minor;
+@@ -252,6 +257,7 @@ int __must_check media_devnode_register(struct media_devnode *devnode,
+       mutex_unlock(&media_devnode_lock);
+       devnode->minor = minor;
++      devnode->media_dev = mdev;
+       /* Part 2: Initialize and register the character device */
+       cdev_init(&devnode->cdev, &media_devnode_fops);
+diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c
+index 9cd0268b2767..f353ab569b8e 100644
+--- a/drivers/media/usb/uvc/uvc_driver.c
++++ b/drivers/media/usb/uvc/uvc_driver.c
+@@ -1800,7 +1800,7 @@ static void uvc_delete(struct uvc_device *dev)
+       if (dev->vdev.dev)
+               v4l2_device_unregister(&dev->vdev);
+ #ifdef CONFIG_MEDIA_CONTROLLER
+-      if (media_devnode_is_registered(&dev->mdev.devnode))
++      if (media_devnode_is_registered(dev->mdev.devnode))
+               media_device_unregister(&dev->mdev);
+ #endif
+diff --git a/include/media/media-device.h b/include/media/media-device.h
+index 6e6db78f1ee2..00bbd679864a 100644
+--- a/include/media/media-device.h
++++ b/include/media/media-device.h
+@@ -60,7 +60,7 @@ struct device;
+ struct media_device {
+       /* dev->driver_data points to this struct. */
+       struct device *dev;
+-      struct media_devnode devnode;
++      struct media_devnode *devnode;
+       char model[32];
+       char serial[40];
+@@ -84,9 +84,6 @@ struct media_device {
+ #define MEDIA_DEV_NOTIFY_PRE_LINK_CH  0
+ #define MEDIA_DEV_NOTIFY_POST_LINK_CH 1
+-/* media_devnode to media_device */
+-#define to_media_device(node) container_of(node, struct media_device, devnode)
+-
+ int __must_check __media_device_register(struct media_device *mdev,
+                                        struct module *owner);
+ #define media_device_register(mdev) __media_device_register(mdev, THIS_MODULE)
+diff --git a/include/media/media-devnode.h b/include/media/media-devnode.h
+index 79f702d26d1f..8b854c044032 100644
+--- a/include/media/media-devnode.h
++++ b/include/media/media-devnode.h
+@@ -33,6 +33,8 @@
+ #include <linux/device.h>
+ #include <linux/cdev.h>
++struct media_device;
++
+ /*
+  * Flag to mark the media_devnode struct as registered. Drivers must not touch
+  * this flag directly, it will be set and cleared by media_devnode_register and
+@@ -67,6 +69,8 @@ struct media_file_operations {
+  * before registering the node.
+  */
+ struct media_devnode {
++      struct media_device *media_dev;
++
+       /* device ops */
+       const struct media_file_operations *fops;
+@@ -86,7 +90,8 @@ struct media_devnode {
+ /* dev to media_devnode */
+ #define to_media_devnode(cd) container_of(cd, struct media_devnode, dev)
+-int __must_check media_devnode_register(struct media_devnode *devnode,
++int __must_check media_devnode_register(struct media_device *mdev,
++                                      struct media_devnode *devnode,
+                                       struct module *owner);
+ void media_devnode_unregister(struct media_devnode *devnode);
+@@ -97,6 +102,9 @@ static inline struct media_devnode *media_devnode_data(struct file *filp)
+ static inline int media_devnode_is_registered(struct media_devnode *devnode)
+ {
++      if (!devnode)
++              return false;
++
+       return test_bit(MEDIA_FLAG_REGISTERED, &devnode->flags);
+ }
+-- 
+2.25.1
+
diff --git a/queue-4.4/media-devnode-add-missing-mutex-lock-in-error-handle.patch b/queue-4.4/media-devnode-add-missing-mutex-lock-in-error-handle.patch
new file mode 100644 (file)
index 0000000..6678f87
--- /dev/null
@@ -0,0 +1,39 @@
+From 677ab4f9d477410d1a3216d4d51287d075c64195 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 21 Mar 2016 04:33:12 -0700
+Subject: media-devnode: add missing mutex lock in error handler
+
+From: Max Kellermann <max@duempel.org>
+
+commit 88336e174645948da269e1812f138f727cd2896b upstream.
+
+We should protect the device unregister patch too, at the error
+condition.
+
+Signed-off-by: Max Kellermann <max@duempel.org>
+Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/media/media-devnode.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/drivers/media/media-devnode.c b/drivers/media/media-devnode.c
+index 6c56aebd8db0..86c7c3732c84 100644
+--- a/drivers/media/media-devnode.c
++++ b/drivers/media/media-devnode.c
+@@ -282,8 +282,11 @@ int __must_check media_devnode_register(struct media_devnode *mdev,
+       return 0;
+ error:
++      mutex_lock(&media_devnode_lock);
+       cdev_del(&mdev->cdev);
+       clear_bit(mdev->minor, media_devnode_nums);
++      mutex_unlock(&media_devnode_lock);
++
+       return ret;
+ }
+-- 
+2.25.1
+
diff --git a/queue-4.4/media-devnode-fix-namespace-mess.patch b/queue-4.4/media-devnode-fix-namespace-mess.patch
new file mode 100644 (file)
index 0000000..279b6e7
--- /dev/null
@@ -0,0 +1,355 @@
+From 2657e725986ccd5cdae49ec62d204042f6df2f44 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 23 Mar 2016 11:22:57 -0300
+Subject: media-devnode: fix namespace mess
+
+From: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
+
+commit 163f1e93e995048b894c5fc86a6034d16beed740 upstream.
+
+Along all media controller code, "mdev" is used to represent
+a pointer to struct media_device, and "devnode" for a pointer
+to struct media_devnode.
+
+However, inside media-devnode.[ch], "mdev" is used to represent
+a pointer to struct media_devnode.
+
+This is very confusing and may lead to development errors.
+
+So, let's change all occurrences at media-devnode.[ch] to
+also use "devnode" for such pointers.
+
+This patch doesn't make any functional changes.
+
+Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
+Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
+[bwh: Backported to 4.4: adjust filename, context]
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/media/media-devnode.c | 114 +++++++++++++++++-----------------
+ include/media/media-devnode.h |  10 +--
+ 2 files changed, 62 insertions(+), 62 deletions(-)
+
+diff --git a/drivers/media/media-devnode.c b/drivers/media/media-devnode.c
+index 86c7c3732c84..98211c570e11 100644
+--- a/drivers/media/media-devnode.c
++++ b/drivers/media/media-devnode.c
+@@ -59,21 +59,21 @@ static DECLARE_BITMAP(media_devnode_nums, MEDIA_NUM_DEVICES);
+ /* Called when the last user of the media device exits. */
+ static void media_devnode_release(struct device *cd)
+ {
+-      struct media_devnode *mdev = to_media_devnode(cd);
++      struct media_devnode *devnode = to_media_devnode(cd);
+       mutex_lock(&media_devnode_lock);
+       /* Delete the cdev on this minor as well */
+-      cdev_del(&mdev->cdev);
++      cdev_del(&devnode->cdev);
+       /* Mark device node number as free */
+-      clear_bit(mdev->minor, media_devnode_nums);
++      clear_bit(devnode->minor, media_devnode_nums);
+       mutex_unlock(&media_devnode_lock);
+       /* Release media_devnode and perform other cleanups as needed. */
+-      if (mdev->release)
+-              mdev->release(mdev);
++      if (devnode->release)
++              devnode->release(devnode);
+ }
+ static struct bus_type media_bus_type = {
+@@ -83,37 +83,37 @@ static struct bus_type media_bus_type = {
+ static ssize_t media_read(struct file *filp, char __user *buf,
+               size_t sz, loff_t *off)
+ {
+-      struct media_devnode *mdev = media_devnode_data(filp);
++      struct media_devnode *devnode = media_devnode_data(filp);
+-      if (!mdev->fops->read)
++      if (!devnode->fops->read)
+               return -EINVAL;
+-      if (!media_devnode_is_registered(mdev))
++      if (!media_devnode_is_registered(devnode))
+               return -EIO;
+-      return mdev->fops->read(filp, buf, sz, off);
++      return devnode->fops->read(filp, buf, sz, off);
+ }
+ static ssize_t media_write(struct file *filp, const char __user *buf,
+               size_t sz, loff_t *off)
+ {
+-      struct media_devnode *mdev = media_devnode_data(filp);
++      struct media_devnode *devnode = media_devnode_data(filp);
+-      if (!mdev->fops->write)
++      if (!devnode->fops->write)
+               return -EINVAL;
+-      if (!media_devnode_is_registered(mdev))
++      if (!media_devnode_is_registered(devnode))
+               return -EIO;
+-      return mdev->fops->write(filp, buf, sz, off);
++      return devnode->fops->write(filp, buf, sz, off);
+ }
+ static unsigned int media_poll(struct file *filp,
+                              struct poll_table_struct *poll)
+ {
+-      struct media_devnode *mdev = media_devnode_data(filp);
++      struct media_devnode *devnode = media_devnode_data(filp);
+-      if (!media_devnode_is_registered(mdev))
++      if (!media_devnode_is_registered(devnode))
+               return POLLERR | POLLHUP;
+-      if (!mdev->fops->poll)
++      if (!devnode->fops->poll)
+               return DEFAULT_POLLMASK;
+-      return mdev->fops->poll(filp, poll);
++      return devnode->fops->poll(filp, poll);
+ }
+ static long
+@@ -121,12 +121,12 @@ __media_ioctl(struct file *filp, unsigned int cmd, unsigned long arg,
+             long (*ioctl_func)(struct file *filp, unsigned int cmd,
+                                unsigned long arg))
+ {
+-      struct media_devnode *mdev = media_devnode_data(filp);
++      struct media_devnode *devnode = media_devnode_data(filp);
+       if (!ioctl_func)
+               return -ENOTTY;
+-      if (!media_devnode_is_registered(mdev))
++      if (!media_devnode_is_registered(devnode))
+               return -EIO;
+       return ioctl_func(filp, cmd, arg);
+@@ -134,9 +134,9 @@ __media_ioctl(struct file *filp, unsigned int cmd, unsigned long arg,
+ static long media_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+ {
+-      struct media_devnode *mdev = media_devnode_data(filp);
++      struct media_devnode *devnode = media_devnode_data(filp);
+-      return __media_ioctl(filp, cmd, arg, mdev->fops->ioctl);
++      return __media_ioctl(filp, cmd, arg, devnode->fops->ioctl);
+ }
+ #ifdef CONFIG_COMPAT
+@@ -144,9 +144,9 @@ static long media_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+ static long media_compat_ioctl(struct file *filp, unsigned int cmd,
+                              unsigned long arg)
+ {
+-      struct media_devnode *mdev = media_devnode_data(filp);
++      struct media_devnode *devnode = media_devnode_data(filp);
+-      return __media_ioctl(filp, cmd, arg, mdev->fops->compat_ioctl);
++      return __media_ioctl(filp, cmd, arg, devnode->fops->compat_ioctl);
+ }
+ #endif /* CONFIG_COMPAT */
+@@ -154,7 +154,7 @@ static long media_compat_ioctl(struct file *filp, unsigned int cmd,
+ /* Override for the open function */
+ static int media_open(struct inode *inode, struct file *filp)
+ {
+-      struct media_devnode *mdev;
++      struct media_devnode *devnode;
+       int ret;
+       /* Check if the media device is available. This needs to be done with
+@@ -164,23 +164,23 @@ static int media_open(struct inode *inode, struct file *filp)
+        * a crash.
+        */
+       mutex_lock(&media_devnode_lock);
+-      mdev = container_of(inode->i_cdev, struct media_devnode, cdev);
++      devnode = container_of(inode->i_cdev, struct media_devnode, cdev);
+       /* return ENXIO if the media device has been removed
+          already or if it is not registered anymore. */
+-      if (!media_devnode_is_registered(mdev)) {
++      if (!media_devnode_is_registered(devnode)) {
+               mutex_unlock(&media_devnode_lock);
+               return -ENXIO;
+       }
+       /* and increase the device refcount */
+-      get_device(&mdev->dev);
++      get_device(&devnode->dev);
+       mutex_unlock(&media_devnode_lock);
+-      filp->private_data = mdev;
++      filp->private_data = devnode;
+-      if (mdev->fops->open) {
+-              ret = mdev->fops->open(filp);
++      if (devnode->fops->open) {
++              ret = devnode->fops->open(filp);
+               if (ret) {
+-                      put_device(&mdev->dev);
++                      put_device(&devnode->dev);
+                       filp->private_data = NULL;
+                       return ret;
+               }
+@@ -192,16 +192,16 @@ static int media_open(struct inode *inode, struct file *filp)
+ /* Override for the release function */
+ static int media_release(struct inode *inode, struct file *filp)
+ {
+-      struct media_devnode *mdev = media_devnode_data(filp);
++      struct media_devnode *devnode = media_devnode_data(filp);
+-      if (mdev->fops->release)
+-              mdev->fops->release(filp);
++      if (devnode->fops->release)
++              devnode->fops->release(filp);
+       filp->private_data = NULL;
+       /* decrease the refcount unconditionally since the release()
+          return value is ignored. */
+-      put_device(&mdev->dev);
++      put_device(&devnode->dev);
+       return 0;
+ }
+@@ -221,7 +221,7 @@ static const struct file_operations media_devnode_fops = {
+ /**
+  * media_devnode_register - register a media device node
+- * @mdev: media device node structure we want to register
++ * @devnode: media device node structure we want to register
+  *
+  * The registration code assigns minor numbers and registers the new device node
+  * with the kernel. An error is returned if no free minor number can be found,
+@@ -233,7 +233,7 @@ static const struct file_operations media_devnode_fops = {
+  * the media_devnode structure is *not* called, so the caller is responsible for
+  * freeing any data.
+  */
+-int __must_check media_devnode_register(struct media_devnode *mdev,
++int __must_check media_devnode_register(struct media_devnode *devnode,
+                                       struct module *owner)
+ {
+       int minor;
+@@ -251,40 +251,40 @@ int __must_check media_devnode_register(struct media_devnode *mdev,
+       set_bit(minor, media_devnode_nums);
+       mutex_unlock(&media_devnode_lock);
+-      mdev->minor = minor;
++      devnode->minor = minor;
+       /* Part 2: Initialize and register the character device */
+-      cdev_init(&mdev->cdev, &media_devnode_fops);
+-      mdev->cdev.owner = owner;
++      cdev_init(&devnode->cdev, &media_devnode_fops);
++      devnode->cdev.owner = owner;
+-      ret = cdev_add(&mdev->cdev, MKDEV(MAJOR(media_dev_t), mdev->minor), 1);
++      ret = cdev_add(&devnode->cdev, MKDEV(MAJOR(media_dev_t), devnode->minor), 1);
+       if (ret < 0) {
+               pr_err("%s: cdev_add failed\n", __func__);
+               goto error;
+       }
+       /* Part 3: Register the media device */
+-      mdev->dev.bus = &media_bus_type;
+-      mdev->dev.devt = MKDEV(MAJOR(media_dev_t), mdev->minor);
+-      mdev->dev.release = media_devnode_release;
+-      if (mdev->parent)
+-              mdev->dev.parent = mdev->parent;
+-      dev_set_name(&mdev->dev, "media%d", mdev->minor);
+-      ret = device_register(&mdev->dev);
++      devnode->dev.bus = &media_bus_type;
++      devnode->dev.devt = MKDEV(MAJOR(media_dev_t), devnode->minor);
++      devnode->dev.release = media_devnode_release;
++      if (devnode->parent)
++              devnode->dev.parent = devnode->parent;
++      dev_set_name(&devnode->dev, "media%d", devnode->minor);
++      ret = device_register(&devnode->dev);
+       if (ret < 0) {
+               pr_err("%s: device_register failed\n", __func__);
+               goto error;
+       }
+       /* Part 4: Activate this minor. The char device can now be used. */
+-      set_bit(MEDIA_FLAG_REGISTERED, &mdev->flags);
++      set_bit(MEDIA_FLAG_REGISTERED, &devnode->flags);
+       return 0;
+ error:
+       mutex_lock(&media_devnode_lock);
+-      cdev_del(&mdev->cdev);
+-      clear_bit(mdev->minor, media_devnode_nums);
++      cdev_del(&devnode->cdev);
++      clear_bit(devnode->minor, media_devnode_nums);
+       mutex_unlock(&media_devnode_lock);
+       return ret;
+@@ -292,7 +292,7 @@ int __must_check media_devnode_register(struct media_devnode *mdev,
+ /**
+  * media_devnode_unregister - unregister a media device node
+- * @mdev: the device node to unregister
++ * @devnode: the device node to unregister
+  *
+  * This unregisters the passed device. Future open calls will be met with
+  * errors.
+@@ -300,16 +300,16 @@ int __must_check media_devnode_register(struct media_devnode *mdev,
+  * This function can safely be called if the device node has never been
+  * registered or has already been unregistered.
+  */
+-void media_devnode_unregister(struct media_devnode *mdev)
++void media_devnode_unregister(struct media_devnode *devnode)
+ {
+-      /* Check if mdev was ever registered at all */
+-      if (!media_devnode_is_registered(mdev))
++      /* Check if devnode was ever registered at all */
++      if (!media_devnode_is_registered(devnode))
+               return;
+       mutex_lock(&media_devnode_lock);
+-      clear_bit(MEDIA_FLAG_REGISTERED, &mdev->flags);
++      clear_bit(MEDIA_FLAG_REGISTERED, &devnode->flags);
+       mutex_unlock(&media_devnode_lock);
+-      device_unregister(&mdev->dev);
++      device_unregister(&devnode->dev);
+ }
+ /*
+diff --git a/include/media/media-devnode.h b/include/media/media-devnode.h
+index 17ddae32060d..79f702d26d1f 100644
+--- a/include/media/media-devnode.h
++++ b/include/media/media-devnode.h
+@@ -80,24 +80,24 @@ struct media_devnode {
+       unsigned long flags;            /* Use bitops to access flags */
+       /* callbacks */
+-      void (*release)(struct media_devnode *mdev);
++      void (*release)(struct media_devnode *devnode);
+ };
+ /* dev to media_devnode */
+ #define to_media_devnode(cd) container_of(cd, struct media_devnode, dev)
+-int __must_check media_devnode_register(struct media_devnode *mdev,
++int __must_check media_devnode_register(struct media_devnode *devnode,
+                                       struct module *owner);
+-void media_devnode_unregister(struct media_devnode *mdev);
++void media_devnode_unregister(struct media_devnode *devnode);
+ static inline struct media_devnode *media_devnode_data(struct file *filp)
+ {
+       return filp->private_data;
+ }
+-static inline int media_devnode_is_registered(struct media_devnode *mdev)
++static inline int media_devnode_is_registered(struct media_devnode *devnode)
+ {
+-      return test_bit(MEDIA_FLAG_REGISTERED, &mdev->flags);
++      return test_bit(MEDIA_FLAG_REGISTERED, &devnode->flags);
+ }
+ #endif /* _MEDIA_DEVNODE_H */
+-- 
+2.25.1
+
diff --git a/queue-4.4/media-fix-media-devnode-ioctl-syscall-and-unregister.patch b/queue-4.4/media-fix-media-devnode-ioctl-syscall-and-unregister.patch
new file mode 100644 (file)
index 0000000..cc8e22b
--- /dev/null
@@ -0,0 +1,186 @@
+From 653727fd92f2a8d2db75dcf55ba5c2cbad1cfdd4 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 10 Jun 2016 14:37:23 -0300
+Subject: media: fix media devnode ioctl/syscall and unregister race
+
+From: Shuah Khan <shuahkh@osg.samsung.com>
+
+commit 6f0dd24a084a17f9984dd49dffbf7055bf123993 upstream.
+
+Media devnode open/ioctl could be in progress when media device unregister
+is initiated. System calls and ioctls check media device registered status
+at the beginning, however, there is a window where unregister could be in
+progress without changing the media devnode status to unregistered.
+
+process 1                              process 2
+fd = open(/dev/media0)
+media_devnode_is_registered()
+       (returns true here)
+
+                                       media_device_unregister()
+                                               (unregister is in progress
+                                               and devnode isn't
+                                               unregistered yet)
+                                       ...
+ioctl(fd, ...)
+__media_ioctl()
+media_devnode_is_registered()
+       (returns true here)
+                                       ...
+                                       media_devnode_unregister()
+                                       ...
+                                       (driver releases the media device
+                                       memory)
+
+media_device_ioctl()
+       (By this point
+       devnode->media_dev does not
+       point to allocated memory.
+       use-after free in in mutex_lock_nested)
+
+BUG: KASAN: use-after-free in mutex_lock_nested+0x79c/0x800 at addr
+ffff8801ebe914f0
+
+Fix it by clearing register bit when unregister starts to avoid the race.
+
+process 1                               process 2
+fd = open(/dev/media0)
+media_devnode_is_registered()
+        (could return true here)
+
+                                        media_device_unregister()
+                                                (clear the register bit,
+                                                then start unregister.)
+                                        ...
+ioctl(fd, ...)
+__media_ioctl()
+media_devnode_is_registered()
+        (return false here, ioctl
+        returns I/O error, and
+        will not access media
+        device memory)
+                                        ...
+                                        media_devnode_unregister()
+                                        ...
+                                        (driver releases the media device
+                                        memory)
+
+Signed-off-by: Shuah Khan <shuahkh@osg.samsung.com>
+Suggested-by: Sakari Ailus <sakari.ailus@linux.intel.com>
+Reported-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
+Tested-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
+Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
+[bwh: Backported to 4.4: adjut filename, context]
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/media/media-device.c  | 15 ++++++++-------
+ drivers/media/media-devnode.c | 19 ++++++++++++-------
+ include/media/media-devnode.h | 14 ++++++++++++++
+ 3 files changed, 34 insertions(+), 14 deletions(-)
+
+diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c
+index 5d79cd481730..0ca9506f4654 100644
+--- a/drivers/media/media-device.c
++++ b/drivers/media/media-device.c
+@@ -405,6 +405,7 @@ int __must_check __media_device_register(struct media_device *mdev,
+       if (ret < 0) {
+               /* devnode free is handled in media_devnode_*() */
+               mdev->devnode = NULL;
++              media_devnode_unregister_prepare(devnode);
+               media_devnode_unregister(devnode);
+               return ret;
+       }
+@@ -423,16 +424,16 @@ void media_device_unregister(struct media_device *mdev)
+       struct media_entity *entity;
+       struct media_entity *next;
++      /* Clear the devnode register bit to avoid races with media dev open */
++      media_devnode_unregister_prepare(mdev->devnode);
++
+       list_for_each_entry_safe(entity, next, &mdev->entities, list)
+               media_device_unregister_entity(entity);
+-      /* Check if mdev devnode was registered */
+-      if (media_devnode_is_registered(mdev->devnode)) {
+-              device_remove_file(&mdev->devnode->dev, &dev_attr_model);
+-              media_devnode_unregister(mdev->devnode);
+-              /* devnode free is handled in media_devnode_*() */
+-              mdev->devnode = NULL;
+-      }
++      device_remove_file(&mdev->devnode->dev, &dev_attr_model);
++      media_devnode_unregister(mdev->devnode);
++      /* devnode free is handled in media_devnode_*() */
++      mdev->devnode = NULL;
+ }
+ EXPORT_SYMBOL_GPL(media_device_unregister);
+diff --git a/drivers/media/media-devnode.c b/drivers/media/media-devnode.c
+index 45bb70d27224..e887120d19aa 100644
+--- a/drivers/media/media-devnode.c
++++ b/drivers/media/media-devnode.c
+@@ -302,6 +302,17 @@ int __must_check media_devnode_register(struct media_device *mdev,
+       return ret;
+ }
++void media_devnode_unregister_prepare(struct media_devnode *devnode)
++{
++      /* Check if devnode was ever registered at all */
++      if (!media_devnode_is_registered(devnode))
++              return;
++
++      mutex_lock(&media_devnode_lock);
++      clear_bit(MEDIA_FLAG_REGISTERED, &devnode->flags);
++      mutex_unlock(&media_devnode_lock);
++}
++
+ /**
+  * media_devnode_unregister - unregister a media device node
+  * @devnode: the device node to unregister
+@@ -309,17 +320,11 @@ int __must_check media_devnode_register(struct media_device *mdev,
+  * This unregisters the passed device. Future open calls will be met with
+  * errors.
+  *
+- * This function can safely be called if the device node has never been
+- * registered or has already been unregistered.
++ * Should be called after media_devnode_unregister_prepare()
+  */
+ void media_devnode_unregister(struct media_devnode *devnode)
+ {
+-      /* Check if devnode was ever registered at all */
+-      if (!media_devnode_is_registered(devnode))
+-              return;
+-
+       mutex_lock(&media_devnode_lock);
+-      clear_bit(MEDIA_FLAG_REGISTERED, &devnode->flags);
+       /* Delete the cdev on this minor as well */
+       cdev_del(&devnode->cdev);
+       mutex_unlock(&media_devnode_lock);
+diff --git a/include/media/media-devnode.h b/include/media/media-devnode.h
+index 8b854c044032..d5ff95bf2d4b 100644
+--- a/include/media/media-devnode.h
++++ b/include/media/media-devnode.h
+@@ -93,6 +93,20 @@ struct media_devnode {
+ int __must_check media_devnode_register(struct media_device *mdev,
+                                       struct media_devnode *devnode,
+                                       struct module *owner);
++
++/**
++ * media_devnode_unregister_prepare - clear the media device node register bit
++ * @devnode: the device node to prepare for unregister
++ *
++ * This clears the passed device register bit. Future open calls will be met
++ * with errors. Should be called before media_devnode_unregister() to avoid
++ * races with unregister and device file open calls.
++ *
++ * This function can safely be called if the device node has never been
++ * registered or has already been unregistered.
++ */
++void media_devnode_unregister_prepare(struct media_devnode *devnode);
++
+ void media_devnode_unregister(struct media_devnode *devnode);
+ static inline struct media_devnode *media_devnode_data(struct file *filp)
+-- 
+2.25.1
+
diff --git a/queue-4.4/media-fix-media_open-to-clear-filp-private_data-in-e.patch b/queue-4.4/media-fix-media_open-to-clear-filp-private_data-in-e.patch
new file mode 100644 (file)
index 0000000..8b5ca3c
--- /dev/null
@@ -0,0 +1,36 @@
+From b977a5248a55f01ce98e002d5398f38b9f4c991e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 27 Jan 2016 21:49:33 -0200
+Subject: media: Fix media_open() to clear filp->private_data in error leg
+
+From: Shuah Khan <shuahkh@osg.samsung.com>
+
+commit d40ec6fdb0b03b7be4c7923a3da0e46bf943740a upstream.
+
+Fix media_open() to clear filp->private_data when file open
+fails.
+
+Signed-off-by: Shuah Khan <shuahkh@osg.samsung.com>
+Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
+Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/media/media-devnode.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/drivers/media/media-devnode.c b/drivers/media/media-devnode.c
+index ebf9626e5ae5..a8cb52dc8c4f 100644
+--- a/drivers/media/media-devnode.c
++++ b/drivers/media/media-devnode.c
+@@ -181,6 +181,7 @@ static int media_open(struct inode *inode, struct file *filp)
+               ret = mdev->fops->open(filp);
+               if (ret) {
+                       put_device(&mdev->dev);
++                      filp->private_data = NULL;
+                       return ret;
+               }
+       }
+-- 
+2.25.1
+
diff --git a/queue-4.4/media-fix-use-after-free-in-cdev_put-when-app-exits-.patch b/queue-4.4/media-fix-use-after-free-in-cdev_put-when-app-exits-.patch
new file mode 100644 (file)
index 0000000..41f0ac5
--- /dev/null
@@ -0,0 +1,217 @@
+From 3725671d2b4f9d4d74c307c446691e9078ae0d24 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 4 May 2016 16:48:28 -0300
+Subject: media: fix use-after-free in cdev_put() when app exits after driver
+ unbind
+
+From: Shuah Khan <shuahkh@osg.samsung.com>
+
+commit 5b28dde51d0ccc54cee70756e1800d70bed7114a upstream.
+
+When driver unbinds while media_ioctl is in progress, cdev_put() fails with
+when app exits after driver unbinds.
+
+Add devnode struct device kobj as the cdev parent kobject. cdev_add() gets
+a reference to it and releases it in cdev_del() ensuring that the devnode
+is not deallocated as long as the application has the device file open.
+
+media_devnode_register() initializes the struct device kobj before calling
+cdev_add(). media_devnode_unregister() does cdev_del() and then deletes the
+device. devnode is released when the last reference to the struct device is
+gone.
+
+This problem is found on uvcvideo, em28xx, and au0828 drivers and fix has
+been tested on all three.
+
+kernel: [  193.599736] BUG: KASAN: use-after-free in cdev_put+0x4e/0x50
+kernel: [  193.599745] Read of size 8 by task media_device_te/1851
+kernel: [  193.599792] INFO: Allocated in __media_device_register+0x54
+kernel: [  193.599951] INFO: Freed in media_devnode_release+0xa4/0xc0
+
+kernel: [  193.601083] Call Trace:
+kernel: [  193.601093]  [<ffffffff81aecac3>] dump_stack+0x67/0x94
+kernel: [  193.601102]  [<ffffffff815359b2>] print_trailer+0x112/0x1a0
+kernel: [  193.601111]  [<ffffffff8153b5e4>] object_err+0x34/0x40
+kernel: [  193.601119]  [<ffffffff8153d9d4>] kasan_report_error+0x224/0x530
+kernel: [  193.601128]  [<ffffffff814a2c3d>] ? kzfree+0x2d/0x40
+kernel: [  193.601137]  [<ffffffff81539d72>] ? kfree+0x1d2/0x1f0
+kernel: [  193.601154]  [<ffffffff8157ca7e>] ? cdev_put+0x4e/0x50
+kernel: [  193.601162]  [<ffffffff8157ca7e>] cdev_put+0x4e/0x50
+kernel: [  193.601170]  [<ffffffff815767eb>] __fput+0x52b/0x6c0
+kernel: [  193.601179]  [<ffffffff8117743a>] ? switch_task_namespaces+0x2a
+kernel: [  193.601188]  [<ffffffff815769ee>] ____fput+0xe/0x10
+kernel: [  193.601196]  [<ffffffff81170023>] task_work_run+0x133/0x1f0
+kernel: [  193.601204]  [<ffffffff8117746e>] ? switch_task_namespaces+0x5e
+kernel: [  193.601213]  [<ffffffff8111b50c>] do_exit+0x72c/0x2c20
+kernel: [  193.601224]  [<ffffffff8111ade0>] ? release_task+0x1250/0x1250
+-
+-
+-
+kernel: [  193.601360]  [<ffffffff81003587>] ? exit_to_usermode_loop+0xe7
+kernel: [  193.601368]  [<ffffffff810035c0>] exit_to_usermode_loop+0x120
+kernel: [  193.601376]  [<ffffffff810061da>] syscall_return_slowpath+0x16a
+kernel: [  193.601386]  [<ffffffff82848b33>] entry_SYSCALL_64_fastpath+0xa6
+
+Signed-off-by: Shuah Khan <shuahkh@osg.samsung.com>
+Tested-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
+Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/media/media-device.c  |  6 +++--
+ drivers/media/media-devnode.c | 48 +++++++++++++++++++++--------------
+ 2 files changed, 33 insertions(+), 21 deletions(-)
+
+diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c
+index fb018fe1a8f7..5d79cd481730 100644
+--- a/drivers/media/media-device.c
++++ b/drivers/media/media-device.c
+@@ -396,16 +396,16 @@ int __must_check __media_device_register(struct media_device *mdev,
+       devnode->release = media_device_release;
+       ret = media_devnode_register(mdev, devnode, owner);
+       if (ret < 0) {
++              /* devnode free is handled in media_devnode_*() */
+               mdev->devnode = NULL;
+-              kfree(devnode);
+               return ret;
+       }
+       ret = device_create_file(&devnode->dev, &dev_attr_model);
+       if (ret < 0) {
++              /* devnode free is handled in media_devnode_*() */
+               mdev->devnode = NULL;
+               media_devnode_unregister(devnode);
+-              kfree(devnode);
+               return ret;
+       }
+@@ -430,6 +430,8 @@ void media_device_unregister(struct media_device *mdev)
+       if (media_devnode_is_registered(mdev->devnode)) {
+               device_remove_file(&mdev->devnode->dev, &dev_attr_model);
+               media_devnode_unregister(mdev->devnode);
++              /* devnode free is handled in media_devnode_*() */
++              mdev->devnode = NULL;
+       }
+ }
+ EXPORT_SYMBOL_GPL(media_device_unregister);
+diff --git a/drivers/media/media-devnode.c b/drivers/media/media-devnode.c
+index 000efb17b95b..45bb70d27224 100644
+--- a/drivers/media/media-devnode.c
++++ b/drivers/media/media-devnode.c
+@@ -63,13 +63,8 @@ static void media_devnode_release(struct device *cd)
+       struct media_devnode *devnode = to_media_devnode(cd);
+       mutex_lock(&media_devnode_lock);
+-
+-      /* Delete the cdev on this minor as well */
+-      cdev_del(&devnode->cdev);
+-
+       /* Mark device node number as free */
+       clear_bit(devnode->minor, media_devnode_nums);
+-
+       mutex_unlock(&media_devnode_lock);
+       /* Release media_devnode and perform other cleanups as needed. */
+@@ -77,6 +72,7 @@ static void media_devnode_release(struct device *cd)
+               devnode->release(devnode);
+       kfree(devnode);
++      pr_debug("%s: Media Devnode Deallocated\n", __func__);
+ }
+ static struct bus_type media_bus_type = {
+@@ -205,6 +201,8 @@ static int media_release(struct inode *inode, struct file *filp)
+       /* decrease the refcount unconditionally since the release()
+          return value is ignored. */
+       put_device(&devnode->dev);
++
++      pr_debug("%s: Media Release\n", __func__);
+       return 0;
+ }
+@@ -250,6 +248,7 @@ int __must_check media_devnode_register(struct media_device *mdev,
+       if (minor == MEDIA_NUM_DEVICES) {
+               mutex_unlock(&media_devnode_lock);
+               pr_err("could not get a free minor\n");
++              kfree(devnode);
+               return -ENFILE;
+       }
+@@ -259,27 +258,31 @@ int __must_check media_devnode_register(struct media_device *mdev,
+       devnode->minor = minor;
+       devnode->media_dev = mdev;
++      /* Part 1: Initialize dev now to use dev.kobj for cdev.kobj.parent */
++      devnode->dev.bus = &media_bus_type;
++      devnode->dev.devt = MKDEV(MAJOR(media_dev_t), devnode->minor);
++      devnode->dev.release = media_devnode_release;
++      if (devnode->parent)
++              devnode->dev.parent = devnode->parent;
++      dev_set_name(&devnode->dev, "media%d", devnode->minor);
++      device_initialize(&devnode->dev);
++
+       /* Part 2: Initialize and register the character device */
+       cdev_init(&devnode->cdev, &media_devnode_fops);
+       devnode->cdev.owner = owner;
++      devnode->cdev.kobj.parent = &devnode->dev.kobj;
+       ret = cdev_add(&devnode->cdev, MKDEV(MAJOR(media_dev_t), devnode->minor), 1);
+       if (ret < 0) {
+               pr_err("%s: cdev_add failed\n", __func__);
+-              goto error;
++              goto cdev_add_error;
+       }
+-      /* Part 3: Register the media device */
+-      devnode->dev.bus = &media_bus_type;
+-      devnode->dev.devt = MKDEV(MAJOR(media_dev_t), devnode->minor);
+-      devnode->dev.release = media_devnode_release;
+-      if (devnode->parent)
+-              devnode->dev.parent = devnode->parent;
+-      dev_set_name(&devnode->dev, "media%d", devnode->minor);
+-      ret = device_register(&devnode->dev);
++      /* Part 3: Add the media device */
++      ret = device_add(&devnode->dev);
+       if (ret < 0) {
+-              pr_err("%s: device_register failed\n", __func__);
+-              goto error;
++              pr_err("%s: device_add failed\n", __func__);
++              goto device_add_error;
+       }
+       /* Part 4: Activate this minor. The char device can now be used. */
+@@ -287,12 +290,15 @@ int __must_check media_devnode_register(struct media_device *mdev,
+       return 0;
+-error:
+-      mutex_lock(&media_devnode_lock);
++device_add_error:
+       cdev_del(&devnode->cdev);
++cdev_add_error:
++      mutex_lock(&media_devnode_lock);
+       clear_bit(devnode->minor, media_devnode_nums);
++      devnode->media_dev = NULL;
+       mutex_unlock(&media_devnode_lock);
++      put_device(&devnode->dev);
+       return ret;
+ }
+@@ -314,8 +320,12 @@ void media_devnode_unregister(struct media_devnode *devnode)
+       mutex_lock(&media_devnode_lock);
+       clear_bit(MEDIA_FLAG_REGISTERED, &devnode->flags);
++      /* Delete the cdev on this minor as well */
++      cdev_del(&devnode->cdev);
+       mutex_unlock(&media_devnode_lock);
+-      device_unregister(&devnode->dev);
++      device_del(&devnode->dev);
++      devnode->media_dev = NULL;
++      put_device(&devnode->dev);
+ }
+ /*
+-- 
+2.25.1
+
diff --git a/queue-4.4/padata-initialize-pd-cpu-with-effective-cpumask.patch b/queue-4.4/padata-initialize-pd-cpu-with-effective-cpumask.patch
new file mode 100644 (file)
index 0000000..2293691
--- /dev/null
@@ -0,0 +1,76 @@
+From 0f5c19f725997d7b5a5bd056a0128ff323cf0d86 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 21 May 2020 16:51:44 -0400
+Subject: padata: initialize pd->cpu with effective cpumask
+
+From: Daniel Jordan <daniel.m.jordan@oracle.com>
+
+[ Upstream commit ec9c7d19336ee98ecba8de80128aa405c45feebb ]
+
+Exercising CPU hotplug on a 5.2 kernel with recent padata fixes from
+cryptodev-2.6.git in an 8-CPU kvm guest...
+
+    # modprobe tcrypt alg="pcrypt(rfc4106(gcm(aes)))" type=3
+    # echo 0 > /sys/devices/system/cpu/cpu1/online
+    # echo c > /sys/kernel/pcrypt/pencrypt/parallel_cpumask
+    # modprobe tcrypt mode=215
+
+...caused the following crash:
+
+    BUG: kernel NULL pointer dereference, address: 0000000000000000
+    #PF: supervisor read access in kernel mode
+    #PF: error_code(0x0000) - not-present page
+    PGD 0 P4D 0
+    Oops: 0000 [#1] SMP PTI
+    CPU: 2 PID: 134 Comm: kworker/2:2 Not tainted 5.2.0-padata-base+ #7
+    Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.12.0-<snip>
+    Workqueue: pencrypt padata_parallel_worker
+    RIP: 0010:padata_reorder+0xcb/0x180
+    ...
+    Call Trace:
+     padata_do_serial+0x57/0x60
+     pcrypt_aead_enc+0x3a/0x50 [pcrypt]
+     padata_parallel_worker+0x9b/0xe0
+     process_one_work+0x1b5/0x3f0
+     worker_thread+0x4a/0x3c0
+     ...
+
+In padata_alloc_pd, pd->cpu is set using the user-supplied cpumask
+instead of the effective cpumask, and in this case cpumask_first picked
+an offline CPU.
+
+The offline CPU's reorder->list.next is NULL in padata_reorder because
+the list wasn't initialized in padata_init_pqueues, which only operates
+on CPUs in the effective mask.
+
+Fix by using the effective mask in padata_alloc_pd.
+
+Fixes: 6fc4dbcf0276 ("padata: Replace delayed timer with immediate workqueue in padata_reorder")
+Signed-off-by: Daniel Jordan <daniel.m.jordan@oracle.com>
+Cc: Herbert Xu <herbert@gondor.apana.org.au>
+Cc: Steffen Klassert <steffen.klassert@secunet.com>
+Cc: linux-crypto@vger.kernel.org
+Cc: linux-kernel@vger.kernel.org
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Daniel Jordan <daniel.m.jordan@oracle.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/padata.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/kernel/padata.c b/kernel/padata.c
+index e5966eedfa36..43b72f5dfe07 100644
+--- a/kernel/padata.c
++++ b/kernel/padata.c
+@@ -449,7 +449,7 @@ static struct parallel_data *padata_alloc_pd(struct padata_instance *pinst,
+       atomic_set(&pd->refcnt, 1);
+       pd->pinst = pinst;
+       spin_lock_init(&pd->lock);
+-      pd->cpu = cpumask_first(pcpumask);
++      pd->cpu = cpumask_first(pd->cpumask.pcpu);
+       INIT_WORK(&pd->reorder_work, invoke_padata_reorder);
+       return pd;
+-- 
+2.25.1
+
diff --git a/queue-4.4/padata-purge-get_cpu-and-reorder_via_wq-from-padata_.patch b/queue-4.4/padata-purge-get_cpu-and-reorder_via_wq-from-padata_.patch
new file mode 100644 (file)
index 0000000..70e6151
--- /dev/null
@@ -0,0 +1,68 @@
+From 05539e0e77745aac87da493d8452295cb67fc7a8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 21 May 2020 16:51:45 -0400
+Subject: padata: purge get_cpu and reorder_via_wq from padata_do_serial
+
+From: Daniel Jordan <daniel.m.jordan@oracle.com>
+
+[ Upstream commit 065cf577135a4977931c7a1e1edf442bfd9773dd]
+
+With the removal of the padata timer, padata_do_serial no longer
+needs special CPU handling, so remove it.
+
+Signed-off-by: Daniel Jordan <daniel.m.jordan@oracle.com>
+Cc: Herbert Xu <herbert@gondor.apana.org.au>
+Cc: Steffen Klassert <steffen.klassert@secunet.com>
+Cc: linux-crypto@vger.kernel.org
+Cc: linux-kernel@vger.kernel.org
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Daniel Jordan <daniel.m.jordan@oracle.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/padata.c | 23 +++--------------------
+ 1 file changed, 3 insertions(+), 20 deletions(-)
+
+diff --git a/kernel/padata.c b/kernel/padata.c
+index 43b72f5dfe07..c50975f43b34 100644
+--- a/kernel/padata.c
++++ b/kernel/padata.c
+@@ -322,24 +322,9 @@ static void padata_serial_worker(struct work_struct *serial_work)
+  */
+ void padata_do_serial(struct padata_priv *padata)
+ {
+-      int cpu;
+-      struct padata_parallel_queue *pqueue;
+-      struct parallel_data *pd;
+-      int reorder_via_wq = 0;
+-
+-      pd = padata->pd;
+-
+-      cpu = get_cpu();
+-
+-      /* We need to enqueue the padata object into the correct
+-       * per-cpu queue.
+-       */
+-      if (cpu != padata->cpu) {
+-              reorder_via_wq = 1;
+-              cpu = padata->cpu;
+-      }
+-
+-      pqueue = per_cpu_ptr(pd->pqueue, cpu);
++      struct parallel_data *pd = padata->pd;
++      struct padata_parallel_queue *pqueue = per_cpu_ptr(pd->pqueue,
++                                                         padata->cpu);
+       spin_lock(&pqueue->reorder.lock);
+       list_add_tail(&padata->list, &pqueue->reorder.list);
+@@ -353,8 +338,6 @@ void padata_do_serial(struct padata_priv *padata)
+        */
+       smp_mb__after_atomic();
+-      put_cpu();
+-
+       padata_reorder(pd);
+ }
+ EXPORT_SYMBOL(padata_do_serial);
+-- 
+2.25.1
+
diff --git a/queue-4.4/padata-replace-delayed-timer-with-immediate-workqueu.patch b/queue-4.4/padata-replace-delayed-timer-with-immediate-workqueu.patch
new file mode 100644 (file)
index 0000000..2a04213
--- /dev/null
@@ -0,0 +1,308 @@
+From 4c099d6cdd80618907639cb023ce9a879eb83f6c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 21 May 2020 16:51:43 -0400
+Subject: padata: Replace delayed timer with immediate workqueue in
+ padata_reorder
+
+From: Herbert Xu <herbert@gondor.apana.org.au>
+
+[ Upstream commit 6fc4dbcf0276279d488c5fbbfabe94734134f4fa ]
+
+The function padata_reorder will use a timer when it cannot progress
+while completed jobs are outstanding (pd->reorder_objects > 0).  This
+is suboptimal as if we do end up using the timer then it would have
+introduced a gratuitous delay of one second.
+
+In fact we can easily distinguish between whether completed jobs
+are outstanding and whether we can make progress.  All we have to
+do is look at the next pqueue list.
+
+This patch does that by replacing pd->processed with pd->cpu so
+that the next pqueue is more accessible.
+
+A work queue is used instead of the original try_again to avoid
+hogging the CPU.
+
+Note that we don't bother removing the work queue in
+padata_flush_queues because the whole premise is broken.  You
+cannot flush async crypto requests so it makes no sense to even
+try.  A subsequent patch will fix it by replacing it with a ref
+counting scheme.
+
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+[dj: - adjust context
+     - corrected setup_timer -> timer_setup to delete hunk
+     - skip padata_flush_queues() hunk, function already removed
+       in 4.4]
+Signed-off-by: Daniel Jordan <daniel.m.jordan@oracle.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/linux/padata.h | 13 ++----
+ kernel/padata.c        | 95 ++++++++----------------------------------
+ 2 files changed, 22 insertions(+), 86 deletions(-)
+
+diff --git a/include/linux/padata.h b/include/linux/padata.h
+index e74d61fa50fe..547a8d1e4a3b 100644
+--- a/include/linux/padata.h
++++ b/include/linux/padata.h
+@@ -24,7 +24,6 @@
+ #include <linux/workqueue.h>
+ #include <linux/spinlock.h>
+ #include <linux/list.h>
+-#include <linux/timer.h>
+ #include <linux/notifier.h>
+ #include <linux/kobject.h>
+@@ -85,18 +84,14 @@ struct padata_serial_queue {
+  * @serial: List to wait for serialization after reordering.
+  * @pwork: work struct for parallelization.
+  * @swork: work struct for serialization.
+- * @pd: Backpointer to the internal control structure.
+  * @work: work struct for parallelization.
+- * @reorder_work: work struct for reordering.
+  * @num_obj: Number of objects that are processed by this cpu.
+  * @cpu_index: Index of the cpu.
+  */
+ struct padata_parallel_queue {
+        struct padata_list    parallel;
+        struct padata_list    reorder;
+-       struct parallel_data *pd;
+        struct work_struct    work;
+-       struct work_struct    reorder_work;
+        atomic_t              num_obj;
+        int                   cpu_index;
+ };
+@@ -122,10 +117,10 @@ struct padata_cpumask {
+  * @reorder_objects: Number of objects waiting in the reorder queues.
+  * @refcnt: Number of objects holding a reference on this parallel_data.
+  * @max_seq_nr:  Maximal used sequence number.
++ * @cpu: Next CPU to be processed.
+  * @cpumask: The cpumasks in use for parallel and serial workers.
++ * @reorder_work: work struct for reordering.
+  * @lock: Reorder lock.
+- * @processed: Number of already processed objects.
+- * @timer: Reorder timer.
+  */
+ struct parallel_data {
+       struct padata_instance          *pinst;
+@@ -134,10 +129,10 @@ struct parallel_data {
+       atomic_t                        reorder_objects;
+       atomic_t                        refcnt;
+       atomic_t                        seq_nr;
++      int                             cpu;
+       struct padata_cpumask           cpumask;
++      struct work_struct              reorder_work;
+       spinlock_t                      lock ____cacheline_aligned;
+-      unsigned int                    processed;
+-      struct timer_list               timer;
+ };
+ /**
+diff --git a/kernel/padata.c b/kernel/padata.c
+index 4f860043a8e5..e5966eedfa36 100644
+--- a/kernel/padata.c
++++ b/kernel/padata.c
+@@ -165,23 +165,12 @@ EXPORT_SYMBOL(padata_do_parallel);
+  */
+ static struct padata_priv *padata_get_next(struct parallel_data *pd)
+ {
+-      int cpu, num_cpus;
+-      unsigned int next_nr, next_index;
+       struct padata_parallel_queue *next_queue;
+       struct padata_priv *padata;
+       struct padata_list *reorder;
++      int cpu = pd->cpu;
+-      num_cpus = cpumask_weight(pd->cpumask.pcpu);
+-
+-      /*
+-       * Calculate the percpu reorder queue and the sequence
+-       * number of the next object.
+-       */
+-      next_nr = pd->processed;
+-      next_index = next_nr % num_cpus;
+-      cpu = padata_index_to_cpu(pd, next_index);
+       next_queue = per_cpu_ptr(pd->pqueue, cpu);
+-
+       reorder = &next_queue->reorder;
+       spin_lock(&reorder->lock);
+@@ -192,7 +181,8 @@ static struct padata_priv *padata_get_next(struct parallel_data *pd)
+               list_del_init(&padata->list);
+               atomic_dec(&pd->reorder_objects);
+-              pd->processed++;
++              pd->cpu = cpumask_next_wrap(cpu, pd->cpumask.pcpu, -1,
++                                          false);
+               spin_unlock(&reorder->lock);
+               goto out;
+@@ -215,6 +205,7 @@ static void padata_reorder(struct parallel_data *pd)
+       struct padata_priv *padata;
+       struct padata_serial_queue *squeue;
+       struct padata_instance *pinst = pd->pinst;
++      struct padata_parallel_queue *next_queue;
+       /*
+        * We need to ensure that only one cpu can work on dequeueing of
+@@ -246,7 +237,6 @@ static void padata_reorder(struct parallel_data *pd)
+                * so exit immediately.
+                */
+               if (PTR_ERR(padata) == -ENODATA) {
+-                      del_timer(&pd->timer);
+                       spin_unlock_bh(&pd->lock);
+                       return;
+               }
+@@ -265,70 +255,29 @@ static void padata_reorder(struct parallel_data *pd)
+       /*
+        * The next object that needs serialization might have arrived to
+-       * the reorder queues in the meantime, we will be called again
+-       * from the timer function if no one else cares for it.
++       * the reorder queues in the meantime.
+        *
+-       * Ensure reorder_objects is read after pd->lock is dropped so we see
+-       * an increment from another task in padata_do_serial.  Pairs with
++       * Ensure reorder queue is read after pd->lock is dropped so we see
++       * new objects from another task in padata_do_serial.  Pairs with
+        * smp_mb__after_atomic in padata_do_serial.
+        */
+       smp_mb();
+-      if (atomic_read(&pd->reorder_objects)
+-                      && !(pinst->flags & PADATA_RESET))
+-              mod_timer(&pd->timer, jiffies + HZ);
+-      else
+-              del_timer(&pd->timer);
+-      return;
++      next_queue = per_cpu_ptr(pd->pqueue, pd->cpu);
++      if (!list_empty(&next_queue->reorder.list))
++              queue_work(pinst->wq, &pd->reorder_work);
+ }
+ static void invoke_padata_reorder(struct work_struct *work)
+ {
+-      struct padata_parallel_queue *pqueue;
+       struct parallel_data *pd;
+       local_bh_disable();
+-      pqueue = container_of(work, struct padata_parallel_queue, reorder_work);
+-      pd = pqueue->pd;
++      pd = container_of(work, struct parallel_data, reorder_work);
+       padata_reorder(pd);
+       local_bh_enable();
+ }
+-static void padata_reorder_timer(unsigned long arg)
+-{
+-      struct parallel_data *pd = (struct parallel_data *)arg;
+-      unsigned int weight;
+-      int target_cpu, cpu;
+-
+-      cpu = get_cpu();
+-
+-      /* We don't lock pd here to not interfere with parallel processing
+-       * padata_reorder() calls on other CPUs. We just need any CPU out of
+-       * the cpumask.pcpu set. It would be nice if it's the right one but
+-       * it doesn't matter if we're off to the next one by using an outdated
+-       * pd->processed value.
+-       */
+-      weight = cpumask_weight(pd->cpumask.pcpu);
+-      target_cpu = padata_index_to_cpu(pd, pd->processed % weight);
+-
+-      /* ensure to call the reorder callback on the correct CPU */
+-      if (cpu != target_cpu) {
+-              struct padata_parallel_queue *pqueue;
+-              struct padata_instance *pinst;
+-
+-              /* The timer function is serialized wrt itself -- no locking
+-               * needed.
+-               */
+-              pinst = pd->pinst;
+-              pqueue = per_cpu_ptr(pd->pqueue, target_cpu);
+-              queue_work_on(target_cpu, pinst->wq, &pqueue->reorder_work);
+-      } else {
+-              padata_reorder(pd);
+-      }
+-
+-      put_cpu();
+-}
+-
+ static void padata_serial_worker(struct work_struct *serial_work)
+ {
+       struct padata_serial_queue *squeue;
+@@ -382,9 +331,8 @@ void padata_do_serial(struct padata_priv *padata)
+       cpu = get_cpu();
+-      /* We need to run on the same CPU padata_do_parallel(.., padata, ..)
+-       * was called on -- or, at least, enqueue the padata object into the
+-       * correct per-cpu queue.
++      /* We need to enqueue the padata object into the correct
++       * per-cpu queue.
+        */
+       if (cpu != padata->cpu) {
+               reorder_via_wq = 1;
+@@ -394,12 +342,12 @@ void padata_do_serial(struct padata_priv *padata)
+       pqueue = per_cpu_ptr(pd->pqueue, cpu);
+       spin_lock(&pqueue->reorder.lock);
+-      atomic_inc(&pd->reorder_objects);
+       list_add_tail(&padata->list, &pqueue->reorder.list);
++      atomic_inc(&pd->reorder_objects);
+       spin_unlock(&pqueue->reorder.lock);
+       /*
+-       * Ensure the atomic_inc of reorder_objects above is ordered correctly
++       * Ensure the addition to the reorder list is ordered correctly
+        * with the trylock of pd->lock in padata_reorder.  Pairs with smp_mb
+        * in padata_reorder.
+        */
+@@ -407,13 +355,7 @@ void padata_do_serial(struct padata_priv *padata)
+       put_cpu();
+-      /* If we're running on the wrong CPU, call padata_reorder() via a
+-       * kernel worker.
+-       */
+-      if (reorder_via_wq)
+-              queue_work_on(cpu, pd->pinst->wq, &pqueue->reorder_work);
+-      else
+-              padata_reorder(pd);
++      padata_reorder(pd);
+ }
+ EXPORT_SYMBOL(padata_do_serial);
+@@ -469,14 +411,12 @@ static void padata_init_pqueues(struct parallel_data *pd)
+                       continue;
+               }
+-              pqueue->pd = pd;
+               pqueue->cpu_index = cpu_index;
+               cpu_index++;
+               __padata_list_init(&pqueue->reorder);
+               __padata_list_init(&pqueue->parallel);
+               INIT_WORK(&pqueue->work, padata_parallel_worker);
+-              INIT_WORK(&pqueue->reorder_work, invoke_padata_reorder);
+               atomic_set(&pqueue->num_obj, 0);
+       }
+ }
+@@ -504,12 +444,13 @@ static struct parallel_data *padata_alloc_pd(struct padata_instance *pinst,
+       padata_init_pqueues(pd);
+       padata_init_squeues(pd);
+-      setup_timer(&pd->timer, padata_reorder_timer, (unsigned long)pd);
+       atomic_set(&pd->seq_nr, -1);
+       atomic_set(&pd->reorder_objects, 0);
+       atomic_set(&pd->refcnt, 1);
+       pd->pinst = pinst;
+       spin_lock_init(&pd->lock);
++      pd->cpu = cpumask_first(pcpumask);
++      INIT_WORK(&pd->reorder_work, invoke_padata_reorder);
+       return pd;
+-- 
+2.25.1
+
diff --git a/queue-4.4/padata-set-cpu_index-of-unused-cpus-to-1.patch b/queue-4.4/padata-set-cpu_index-of-unused-cpus-to-1.patch
new file mode 100644 (file)
index 0000000..a46cdfa
--- /dev/null
@@ -0,0 +1,50 @@
+From 0f46a45bb313a0489b467856ebeb3c168f76bbf3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 21 May 2020 16:51:41 -0400
+Subject: padata: set cpu_index of unused CPUs to -1
+
+From: Mathias Krause <minipli@googlemail.com>
+
+[ Upstream commit 1bd845bcb41d5b7f83745e0cb99273eb376f2ec5 ]
+
+The parallel queue per-cpu data structure gets initialized only for CPUs
+in the 'pcpu' CPU mask set. This is not sufficient as the reorder timer
+may run on a different CPU and might wrongly decide it's the target CPU
+for the next reorder item as per-cpu memory gets memset(0) and we might
+be waiting for the first CPU in cpumask.pcpu, i.e. cpu_index 0.
+
+Make the '__this_cpu_read(pd->pqueue->cpu_index) == next_queue->cpu_index'
+compare in padata_get_next() fail in this case by initializing the
+cpu_index member of all per-cpu parallel queues. Use -1 for unused ones.
+
+Signed-off-by: Mathias Krause <minipli@googlemail.com>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Daniel Jordan <daniel.m.jordan@oracle.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/padata.c | 8 +++++++-
+ 1 file changed, 7 insertions(+), 1 deletion(-)
+
+diff --git a/kernel/padata.c b/kernel/padata.c
+index 8aef48c3267b..4f860043a8e5 100644
+--- a/kernel/padata.c
++++ b/kernel/padata.c
+@@ -461,8 +461,14 @@ static void padata_init_pqueues(struct parallel_data *pd)
+       struct padata_parallel_queue *pqueue;
+       cpu_index = 0;
+-      for_each_cpu(cpu, pd->cpumask.pcpu) {
++      for_each_possible_cpu(cpu) {
+               pqueue = per_cpu_ptr(pd->pqueue, cpu);
++
++              if (!cpumask_test_cpu(cpu, pd->cpumask.pcpu)) {
++                      pqueue->cpu_index = -1;
++                      continue;
++              }
++
+               pqueue->pd = pd;
+               pqueue->cpu_index = cpu_index;
+               cpu_index++;
+-- 
+2.25.1
+
diff --git a/queue-4.4/sched-fair-cpumask-export-for_each_cpu_wrap.patch b/queue-4.4/sched-fair-cpumask-export-for_each_cpu_wrap.patch
new file mode 100644 (file)
index 0000000..8145194
--- /dev/null
@@ -0,0 +1,107 @@
+From 6ab43c8f5881b8385e74fee50517c67847f77565 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 21 May 2020 16:51:42 -0400
+Subject: sched/fair, cpumask: Export for_each_cpu_wrap()
+
+From: Peter Zijlstra <peterz@infradead.org>
+
+[ Upstream commit c743f0a5c50f2fcbc628526279cfa24f3dabe182 ]
+
+More users for for_each_cpu_wrap() have appeared. Promote the construct
+to generic cpumask interface.
+
+The implementation is slightly modified to reduce arguments.
+
+Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
+Cc: Lauro Ramos Venancio <lvenanci@redhat.com>
+Cc: Linus Torvalds <torvalds@linux-foundation.org>
+Cc: Mike Galbraith <efault@gmx.de>
+Cc: Peter Zijlstra <peterz@infradead.org>
+Cc: Rik van Riel <riel@redhat.com>
+Cc: Thomas Gleixner <tglx@linutronix.de>
+Cc: lwang@redhat.com
+Link: http://lkml.kernel.org/r/20170414122005.o35me2h5nowqkxbv@hirez.programming.kicks-ass.net
+Signed-off-by: Ingo Molnar <mingo@kernel.org>
+[dj: include only what's added to the cpumask interface, 4.4 doesn't
+     have them in the scheduler]
+Signed-off-by: Daniel Jordan <daniel.m.jordan@oracle.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/linux/cpumask.h | 17 +++++++++++++++++
+ lib/cpumask.c           | 32 ++++++++++++++++++++++++++++++++
+ 2 files changed, 49 insertions(+)
+
+diff --git a/include/linux/cpumask.h b/include/linux/cpumask.h
+index bb3a4bb35183..1322883e7b46 100644
+--- a/include/linux/cpumask.h
++++ b/include/linux/cpumask.h
+@@ -232,6 +232,23 @@ unsigned int cpumask_local_spread(unsigned int i, int node);
+               (cpu) = cpumask_next_zero((cpu), (mask)),       \
+               (cpu) < nr_cpu_ids;)
++extern int cpumask_next_wrap(int n, const struct cpumask *mask, int start, bool wrap);
++
++/**
++ * for_each_cpu_wrap - iterate over every cpu in a mask, starting at a specified location
++ * @cpu: the (optionally unsigned) integer iterator
++ * @mask: the cpumask poiter
++ * @start: the start location
++ *
++ * The implementation does not assume any bit in @mask is set (including @start).
++ *
++ * After the loop, cpu is >= nr_cpu_ids.
++ */
++#define for_each_cpu_wrap(cpu, mask, start)                                   \
++      for ((cpu) = cpumask_next_wrap((start)-1, (mask), (start), false);      \
++           (cpu) < nr_cpumask_bits;                                           \
++           (cpu) = cpumask_next_wrap((cpu), (mask), (start), true))
++
+ /**
+  * for_each_cpu_and - iterate over every cpu in both masks
+  * @cpu: the (optionally unsigned) integer iterator
+diff --git a/lib/cpumask.c b/lib/cpumask.c
+index 5a70f6196f57..24f06e7abf92 100644
+--- a/lib/cpumask.c
++++ b/lib/cpumask.c
+@@ -42,6 +42,38 @@ int cpumask_any_but(const struct cpumask *mask, unsigned int cpu)
+       return i;
+ }
++/**
++ * cpumask_next_wrap - helper to implement for_each_cpu_wrap
++ * @n: the cpu prior to the place to search
++ * @mask: the cpumask pointer
++ * @start: the start point of the iteration
++ * @wrap: assume @n crossing @start terminates the iteration
++ *
++ * Returns >= nr_cpu_ids on completion
++ *
++ * Note: the @wrap argument is required for the start condition when
++ * we cannot assume @start is set in @mask.
++ */
++int cpumask_next_wrap(int n, const struct cpumask *mask, int start, bool wrap)
++{
++      int next;
++
++again:
++      next = cpumask_next(n, mask);
++
++      if (wrap && n < start && next >= start) {
++              return nr_cpumask_bits;
++
++      } else if (next >= nr_cpumask_bits) {
++              wrap = true;
++              n = -1;
++              goto again;
++      }
++
++      return next;
++}
++EXPORT_SYMBOL(cpumask_next_wrap);
++
+ /* These are not inline because of header tangles. */
+ #ifdef CONFIG_CPUMASK_OFFSTACK
+ /**
+-- 
+2.25.1
+
index aedf85126e3d20e0436732f872ec11f113446faf..b6d61579a7437da67e01f4df8f2eb449ae2dbd8a 100644 (file)
@@ -10,3 +10,20 @@ ceph-fix-double-unlock-in-handle_cap_export.patch
 usb-core-fix-misleading-driver-bug-report.patch
 platform-x86-asus-nb-wmi-do-not-load-on-asus-t100ta-.patch
 arm-futex-address-build-warning.patch
+media-fix-media_open-to-clear-filp-private_data-in-e.patch
+drivers-media-media-devnode-clear-private_data-befor.patch
+media-devnode-add-missing-mutex-lock-in-error-handle.patch
+media-devnode-fix-namespace-mess.patch
+media-device-dynamically-allocate-struct-media_devno.patch
+media-fix-use-after-free-in-cdev_put-when-app-exits-.patch
+media-fix-media-devnode-ioctl-syscall-and-unregister.patch
+i2c-dev-switch-from-register_chrdev-to-cdev-api.patch
+i2c-dev-don-t-start-function-name-with-return.patch
+i2c-dev-use-after-free-in-detach.patch
+i2c-dev-don-t-get-i2c-adapter-via-i2c_dev.patch
+i2c-dev-fix-the-race-between-the-release-of-i2c_dev-.patch
+padata-set-cpu_index-of-unused-cpus-to-1.patch
+sched-fair-cpumask-export-for_each_cpu_wrap.patch
+padata-replace-delayed-timer-with-immediate-workqueu.patch
+padata-initialize-pd-cpu-with-effective-cpumask.patch
+padata-purge-get_cpu-and-reorder_via_wq-from-padata_.patch