--- /dev/null
+From 02a5d6925cd34c3b774bdb8eefb057c40a30e870 Mon Sep 17 00:00:00 2001
+From: Takashi Iwai <tiwai@suse.de>
+Date: Thu, 22 Mar 2018 18:10:14 +0100
+Subject: ALSA: pcm: Avoid potential races between OSS ioctls and read/write
+
+From: Takashi Iwai <tiwai@suse.de>
+
+commit 02a5d6925cd34c3b774bdb8eefb057c40a30e870 upstream.
+
+Although we apply the params_lock mutex to the whole read and write
+operations as well as snd_pcm_oss_change_params(), we may still face
+some races.
+
+First off, the params_lock is taken inside the read and write loop.
+This is intentional for avoiding the too long locking, but it allows
+the in-between parameter change, which might lead to invalid
+pointers. We check the readiness of the stream and set up via
+snd_pcm_oss_make_ready() at the beginning of read and write, but it's
+called only once, by assuming that it remains ready in the rest.
+
+Second, many ioctls that may change the actual parameters
+(i.e. setting runtime->oss.params=1) aren't protected, hence they can
+be processed in a half-baked state.
+
+This patch is an attempt to plug these holes. The stream readiness
+check is moved inside the read/write inner loop, so that the stream is
+always set up in a proper state before further processing. Also, each
+ioctl that may change the parameter is wrapped with the params_lock
+for avoiding the races.
+
+The issues were triggered by syzkaller in a few different scenarios,
+particularly the one below appearing as GPF in loopback_pos_update.
+
+Reported-by: syzbot+c4227aec125487ec3efa@syzkaller.appspotmail.com
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ sound/core/oss/pcm_oss.c | 134 +++++++++++++++++++++++++++++++++++++----------
+ 1 file changed, 106 insertions(+), 28 deletions(-)
+
+--- a/sound/core/oss/pcm_oss.c
++++ b/sound/core/oss/pcm_oss.c
+@@ -823,8 +823,8 @@ static int choose_rate(struct snd_pcm_su
+ return snd_pcm_hw_param_near(substream, params, SNDRV_PCM_HW_PARAM_RATE, best_rate, NULL);
+ }
+
+-static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream,
+- bool trylock)
++/* call with params_lock held */
++static int snd_pcm_oss_change_params_locked(struct snd_pcm_substream *substream)
+ {
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_pcm_hw_params *params, *sparams;
+@@ -838,11 +838,8 @@ static int snd_pcm_oss_change_params(str
+ const struct snd_mask *sformat_mask;
+ struct snd_mask mask;
+
+- if (trylock) {
+- if (!(mutex_trylock(&runtime->oss.params_lock)))
+- return -EAGAIN;
+- } else if (mutex_lock_interruptible(&runtime->oss.params_lock))
+- return -ERESTARTSYS;
++ if (!runtime->oss.params)
++ return 0;
+ sw_params = kzalloc(sizeof(*sw_params), GFP_KERNEL);
+ params = kmalloc(sizeof(*params), GFP_KERNEL);
+ sparams = kmalloc(sizeof(*sparams), GFP_KERNEL);
+@@ -1068,6 +1065,23 @@ failure:
+ kfree(sw_params);
+ kfree(params);
+ kfree(sparams);
++ return err;
++}
++
++/* this one takes the lock by itself */
++static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream,
++ bool trylock)
++{
++ struct snd_pcm_runtime *runtime = substream->runtime;
++ int err;
++
++ if (trylock) {
++ if (!(mutex_trylock(&runtime->oss.params_lock)))
++ return -EAGAIN;
++ } else if (mutex_lock_interruptible(&runtime->oss.params_lock))
++ return -ERESTARTSYS;
++
++ err = snd_pcm_oss_change_params_locked(substream);
+ mutex_unlock(&runtime->oss.params_lock);
+ return err;
+ }
+@@ -1096,11 +1110,14 @@ static int snd_pcm_oss_get_active_substr
+ return 0;
+ }
+
++/* call with params_lock held */
+ static int snd_pcm_oss_prepare(struct snd_pcm_substream *substream)
+ {
+ int err;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+
++ if (!runtime->oss.prepare)
++ return 0;
+ err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_PREPARE, NULL);
+ if (err < 0) {
+ pcm_dbg(substream->pcm,
+@@ -1120,8 +1137,6 @@ static int snd_pcm_oss_make_ready(struct
+ struct snd_pcm_runtime *runtime;
+ int err;
+
+- if (substream == NULL)
+- return 0;
+ runtime = substream->runtime;
+ if (runtime->oss.params) {
+ err = snd_pcm_oss_change_params(substream, false);
+@@ -1129,6 +1144,29 @@ static int snd_pcm_oss_make_ready(struct
+ return err;
+ }
+ if (runtime->oss.prepare) {
++ if (mutex_lock_interruptible(&runtime->oss.params_lock))
++ return -ERESTARTSYS;
++ err = snd_pcm_oss_prepare(substream);
++ mutex_unlock(&runtime->oss.params_lock);
++ if (err < 0)
++ return err;
++ }
++ return 0;
++}
++
++/* call with params_lock held */
++static int snd_pcm_oss_make_ready_locked(struct snd_pcm_substream *substream)
++{
++ struct snd_pcm_runtime *runtime;
++ int err;
++
++ runtime = substream->runtime;
++ if (runtime->oss.params) {
++ err = snd_pcm_oss_change_params_locked(substream);
++ if (err < 0)
++ return err;
++ }
++ if (runtime->oss.prepare) {
+ err = snd_pcm_oss_prepare(substream);
+ if (err < 0)
+ return err;
+@@ -1332,13 +1370,14 @@ static ssize_t snd_pcm_oss_write1(struct
+ if (atomic_read(&substream->mmap_count))
+ return -ENXIO;
+
+- if ((tmp = snd_pcm_oss_make_ready(substream)) < 0)
+- return tmp;
+ while (bytes > 0) {
+ if (mutex_lock_interruptible(&runtime->oss.params_lock)) {
+ tmp = -ERESTARTSYS;
+ break;
+ }
++ tmp = snd_pcm_oss_make_ready_locked(substream);
++ if (tmp < 0)
++ goto err;
+ if (bytes < runtime->oss.period_bytes || runtime->oss.buffer_used > 0) {
+ tmp = bytes;
+ if (tmp + runtime->oss.buffer_used > runtime->oss.period_bytes)
+@@ -1439,13 +1478,14 @@ static ssize_t snd_pcm_oss_read1(struct
+ if (atomic_read(&substream->mmap_count))
+ return -ENXIO;
+
+- if ((tmp = snd_pcm_oss_make_ready(substream)) < 0)
+- return tmp;
+ while (bytes > 0) {
+ if (mutex_lock_interruptible(&runtime->oss.params_lock)) {
+ tmp = -ERESTARTSYS;
+ break;
+ }
++ tmp = snd_pcm_oss_make_ready_locked(substream);
++ if (tmp < 0)
++ goto err;
+ if (bytes < runtime->oss.period_bytes || runtime->oss.buffer_used > 0) {
+ if (runtime->oss.buffer_used == 0) {
+ tmp = snd_pcm_oss_read2(substream, runtime->oss.buffer, runtime->oss.period_bytes, 1);
+@@ -1501,10 +1541,12 @@ static int snd_pcm_oss_reset(struct snd_
+ continue;
+ runtime = substream->runtime;
+ snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL);
++ mutex_lock(&runtime->oss.params_lock);
+ runtime->oss.prepare = 1;
+ runtime->oss.buffer_used = 0;
+ runtime->oss.prev_hw_ptr_period = 0;
+ runtime->oss.period_ptr = 0;
++ mutex_unlock(&runtime->oss.params_lock);
+ }
+ return 0;
+ }
+@@ -1590,9 +1632,10 @@ static int snd_pcm_oss_sync(struct snd_p
+ goto __direct;
+ if ((err = snd_pcm_oss_make_ready(substream)) < 0)
+ return err;
++ if (mutex_lock_interruptible(&runtime->oss.params_lock))
++ return -ERESTARTSYS;
+ format = snd_pcm_oss_format_from(runtime->oss.format);
+ width = snd_pcm_format_physical_width(format);
+- mutex_lock(&runtime->oss.params_lock);
+ if (runtime->oss.buffer_used > 0) {
+ #ifdef OSS_DEBUG
+ pcm_dbg(substream->pcm, "sync: buffer_used\n");
+@@ -1643,7 +1686,9 @@ static int snd_pcm_oss_sync(struct snd_p
+ substream->f_flags = saved_f_flags;
+ if (err < 0)
+ return err;
++ mutex_lock(&runtime->oss.params_lock);
+ runtime->oss.prepare = 1;
++ mutex_unlock(&runtime->oss.params_lock);
+ }
+
+ substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE];
+@@ -1654,8 +1699,10 @@ static int snd_pcm_oss_sync(struct snd_p
+ err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL);
+ if (err < 0)
+ return err;
++ mutex_lock(&runtime->oss.params_lock);
+ runtime->oss.buffer_used = 0;
+ runtime->oss.prepare = 1;
++ mutex_unlock(&runtime->oss.params_lock);
+ }
+ return 0;
+ }
+@@ -1674,10 +1721,13 @@ static int snd_pcm_oss_set_rate(struct s
+ rate = 1000;
+ else if (rate > 192000)
+ rate = 192000;
++ if (mutex_lock_interruptible(&runtime->oss.params_lock))
++ return -ERESTARTSYS;
+ if (runtime->oss.rate != rate) {
+ runtime->oss.params = 1;
+ runtime->oss.rate = rate;
+ }
++ mutex_unlock(&runtime->oss.params_lock);
+ }
+ return snd_pcm_oss_get_rate(pcm_oss_file);
+ }
+@@ -1705,10 +1755,13 @@ static int snd_pcm_oss_set_channels(stru
+ if (substream == NULL)
+ continue;
+ runtime = substream->runtime;
++ if (mutex_lock_interruptible(&runtime->oss.params_lock))
++ return -ERESTARTSYS;
+ if (runtime->oss.channels != channels) {
+ runtime->oss.params = 1;
+ runtime->oss.channels = channels;
+ }
++ mutex_unlock(&runtime->oss.params_lock);
+ }
+ return snd_pcm_oss_get_channels(pcm_oss_file);
+ }
+@@ -1794,10 +1847,13 @@ static int snd_pcm_oss_set_format(struct
+ if (substream == NULL)
+ continue;
+ runtime = substream->runtime;
++ if (mutex_lock_interruptible(&runtime->oss.params_lock))
++ return -ERESTARTSYS;
+ if (runtime->oss.format != format) {
+ runtime->oss.params = 1;
+ runtime->oss.format = format;
+ }
++ mutex_unlock(&runtime->oss.params_lock);
+ }
+ }
+ return snd_pcm_oss_get_format(pcm_oss_file);
+@@ -1817,8 +1873,6 @@ static int snd_pcm_oss_set_subdivide1(st
+ {
+ struct snd_pcm_runtime *runtime;
+
+- if (substream == NULL)
+- return 0;
+ runtime = substream->runtime;
+ if (subdivide == 0) {
+ subdivide = runtime->oss.subdivision;
+@@ -1842,9 +1896,16 @@ static int snd_pcm_oss_set_subdivide(str
+
+ for (idx = 1; idx >= 0; --idx) {
+ struct snd_pcm_substream *substream = pcm_oss_file->streams[idx];
++ struct snd_pcm_runtime *runtime;
++
+ if (substream == NULL)
+ continue;
+- if ((err = snd_pcm_oss_set_subdivide1(substream, subdivide)) < 0)
++ runtime = substream->runtime;
++ if (mutex_lock_interruptible(&runtime->oss.params_lock))
++ return -ERESTARTSYS;
++ err = snd_pcm_oss_set_subdivide1(substream, subdivide);
++ mutex_unlock(&runtime->oss.params_lock);
++ if (err < 0)
+ return err;
+ }
+ return err;
+@@ -1854,8 +1915,6 @@ static int snd_pcm_oss_set_fragment1(str
+ {
+ struct snd_pcm_runtime *runtime;
+
+- if (substream == NULL)
+- return 0;
+ runtime = substream->runtime;
+ if (runtime->oss.subdivision || runtime->oss.fragshift)
+ return -EINVAL;
+@@ -1875,9 +1934,16 @@ static int snd_pcm_oss_set_fragment(stru
+
+ for (idx = 1; idx >= 0; --idx) {
+ struct snd_pcm_substream *substream = pcm_oss_file->streams[idx];
++ struct snd_pcm_runtime *runtime;
++
+ if (substream == NULL)
+ continue;
+- if ((err = snd_pcm_oss_set_fragment1(substream, val)) < 0)
++ runtime = substream->runtime;
++ if (mutex_lock_interruptible(&runtime->oss.params_lock))
++ return -ERESTARTSYS;
++ err = snd_pcm_oss_set_fragment1(substream, val);
++ mutex_unlock(&runtime->oss.params_lock);
++ if (err < 0)
+ return err;
+ }
+ return err;
+@@ -1961,6 +2027,9 @@ static int snd_pcm_oss_set_trigger(struc
+ }
+ if (psubstream) {
+ runtime = psubstream->runtime;
++ cmd = 0;
++ if (mutex_lock_interruptible(&runtime->oss.params_lock))
++ return -ERESTARTSYS;
+ if (trigger & PCM_ENABLE_OUTPUT) {
+ if (runtime->oss.trigger)
+ goto _skip1;
+@@ -1978,13 +2047,19 @@ static int snd_pcm_oss_set_trigger(struc
+ cmd = SNDRV_PCM_IOCTL_DROP;
+ runtime->oss.prepare = 1;
+ }
+- err = snd_pcm_kernel_ioctl(psubstream, cmd, NULL);
+- if (err < 0)
+- return err;
+- }
+ _skip1:
++ mutex_unlock(&runtime->oss.params_lock);
++ if (cmd) {
++ err = snd_pcm_kernel_ioctl(psubstream, cmd, NULL);
++ if (err < 0)
++ return err;
++ }
++ }
+ if (csubstream) {
+ runtime = csubstream->runtime;
++ cmd = 0;
++ if (mutex_lock_interruptible(&runtime->oss.params_lock))
++ return -ERESTARTSYS;
+ if (trigger & PCM_ENABLE_INPUT) {
+ if (runtime->oss.trigger)
+ goto _skip2;
+@@ -1999,11 +2074,14 @@ static int snd_pcm_oss_set_trigger(struc
+ cmd = SNDRV_PCM_IOCTL_DROP;
+ runtime->oss.prepare = 1;
+ }
+- err = snd_pcm_kernel_ioctl(csubstream, cmd, NULL);
+- if (err < 0)
+- return err;
+- }
+ _skip2:
++ mutex_unlock(&runtime->oss.params_lock);
++ if (cmd) {
++ err = snd_pcm_kernel_ioctl(csubstream, cmd, NULL);
++ if (err < 0)
++ return err;
++ }
++ }
+ return 0;
+ }
+
--- /dev/null
+From e15dc99dbb9cf99f6432e8e3c0b3a8f7a3403a86 Mon Sep 17 00:00:00 2001
+From: Takashi Iwai <tiwai@suse.de>
+Date: Sat, 7 Apr 2018 11:48:58 +0200
+Subject: ALSA: pcm: Fix endless loop for XRUN recovery in OSS emulation
+
+From: Takashi Iwai <tiwai@suse.de>
+
+commit e15dc99dbb9cf99f6432e8e3c0b3a8f7a3403a86 upstream.
+
+The commit 02a5d6925cd3 ("ALSA: pcm: Avoid potential races between OSS
+ioctls and read/write") split the PCM preparation code to a locked
+version, and it added a sanity check of runtime->oss.prepare flag
+along with the change. This leaded to an endless loop when the stream
+gets XRUN: namely, snd_pcm_oss_write3() and co call
+snd_pcm_oss_prepare() without setting runtime->oss.prepare flag and
+the loop continues until the PCM state reaches to another one.
+
+As the function is supposed to execute the preparation
+unconditionally, drop the invalid state check there.
+
+The bug was triggered by syzkaller.
+
+Fixes: 02a5d6925cd3 ("ALSA: pcm: Avoid potential races between OSS ioctls and read/write")
+Reported-by: syzbot+150189c103427d31a053@syzkaller.appspotmail.com
+Reported-by: syzbot+7e3f31a52646f939c052@syzkaller.appspotmail.com
+Reported-by: syzbot+4f2016cf5185da7759dc@syzkaller.appspotmail.com
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ sound/core/oss/pcm_oss.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+--- a/sound/core/oss/pcm_oss.c
++++ b/sound/core/oss/pcm_oss.c
+@@ -1128,13 +1128,14 @@ static int snd_pcm_oss_get_active_substr
+ }
+
+ /* call with params_lock held */
++/* NOTE: this always call PREPARE unconditionally no matter whether
++ * runtime->oss.prepare is set or not
++ */
+ static int snd_pcm_oss_prepare(struct snd_pcm_substream *substream)
+ {
+ int err;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+
+- if (!runtime->oss.prepare)
+- return 0;
+ err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_PREPARE, NULL);
+ if (err < 0) {
+ pcm_dbg(substream->pcm,
--- /dev/null
+From f6d297df4dd47ef949540e4a201230d0c5308325 Mon Sep 17 00:00:00 2001
+From: Takashi Iwai <tiwai@suse.de>
+Date: Tue, 27 Mar 2018 14:32:23 +0200
+Subject: ALSA: pcm: Fix mutex unbalance in OSS emulation ioctls
+
+From: Takashi Iwai <tiwai@suse.de>
+
+commit f6d297df4dd47ef949540e4a201230d0c5308325 upstream.
+
+The previous fix 40cab6e88cb0 ("ALSA: pcm: Return -EBUSY for OSS
+ioctls changing busy streams") introduced some mutex unbalance; the
+check of runtime->oss.rw_ref was inserted in a wrong place after the
+mutex lock.
+
+This patch fixes the inconsistency by rewriting with the helper
+functions to lock/unlock parameters with the stream check.
+
+Fixes: 40cab6e88cb0 ("ALSA: pcm: Return -EBUSY for OSS ioctls changing busy streams")
+Reported-by: Dan Carpenter <dan.carpenter@oracle.com>
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ sound/core/oss/pcm_oss.c | 67 +++++++++++++++++++++++++++++------------------
+ 1 file changed, 42 insertions(+), 25 deletions(-)
+
+--- a/sound/core/oss/pcm_oss.c
++++ b/sound/core/oss/pcm_oss.c
+@@ -823,6 +823,23 @@ static int choose_rate(struct snd_pcm_su
+ return snd_pcm_hw_param_near(substream, params, SNDRV_PCM_HW_PARAM_RATE, best_rate, NULL);
+ }
+
++/* parameter locking: returns immediately if tried during streaming */
++static int lock_params(struct snd_pcm_runtime *runtime)
++{
++ if (mutex_lock_interruptible(&runtime->oss.params_lock))
++ return -ERESTARTSYS;
++ if (atomic_read(&runtime->oss.rw_ref)) {
++ mutex_unlock(&runtime->oss.params_lock);
++ return -EBUSY;
++ }
++ return 0;
++}
++
++static void unlock_params(struct snd_pcm_runtime *runtime)
++{
++ mutex_unlock(&runtime->oss.params_lock);
++}
++
+ /* call with params_lock held */
+ static int snd_pcm_oss_change_params_locked(struct snd_pcm_substream *substream)
+ {
+@@ -1721,6 +1738,8 @@ static int snd_pcm_oss_set_rate(struct s
+ for (idx = 1; idx >= 0; --idx) {
+ struct snd_pcm_substream *substream = pcm_oss_file->streams[idx];
+ struct snd_pcm_runtime *runtime;
++ int err;
++
+ if (substream == NULL)
+ continue;
+ runtime = substream->runtime;
+@@ -1728,15 +1747,14 @@ static int snd_pcm_oss_set_rate(struct s
+ rate = 1000;
+ else if (rate > 192000)
+ rate = 192000;
+- if (mutex_lock_interruptible(&runtime->oss.params_lock))
+- return -ERESTARTSYS;
+- if (atomic_read(&runtime->oss.rw_ref))
+- return -EBUSY;
++ err = lock_params(runtime);
++ if (err < 0)
++ return err;
+ if (runtime->oss.rate != rate) {
+ runtime->oss.params = 1;
+ runtime->oss.rate = rate;
+ }
+- mutex_unlock(&runtime->oss.params_lock);
++ unlock_params(runtime);
+ }
+ return snd_pcm_oss_get_rate(pcm_oss_file);
+ }
+@@ -1761,18 +1779,19 @@ static int snd_pcm_oss_set_channels(stru
+ for (idx = 1; idx >= 0; --idx) {
+ struct snd_pcm_substream *substream = pcm_oss_file->streams[idx];
+ struct snd_pcm_runtime *runtime;
++ int err;
++
+ if (substream == NULL)
+ continue;
+ runtime = substream->runtime;
+- if (mutex_lock_interruptible(&runtime->oss.params_lock))
+- return -ERESTARTSYS;
+- if (atomic_read(&runtime->oss.rw_ref))
+- return -EBUSY;
++ err = lock_params(runtime);
++ if (err < 0)
++ return err;
+ if (runtime->oss.channels != channels) {
+ runtime->oss.params = 1;
+ runtime->oss.channels = channels;
+ }
+- mutex_unlock(&runtime->oss.params_lock);
++ unlock_params(runtime);
+ }
+ return snd_pcm_oss_get_channels(pcm_oss_file);
+ }
+@@ -1845,6 +1864,7 @@ static int snd_pcm_oss_get_formats(struc
+ static int snd_pcm_oss_set_format(struct snd_pcm_oss_file *pcm_oss_file, int format)
+ {
+ int formats, idx;
++ int err;
+
+ if (format != AFMT_QUERY) {
+ formats = snd_pcm_oss_get_formats(pcm_oss_file);
+@@ -1858,15 +1878,14 @@ static int snd_pcm_oss_set_format(struct
+ if (substream == NULL)
+ continue;
+ runtime = substream->runtime;
+- if (atomic_read(&runtime->oss.rw_ref))
+- return -EBUSY;
+- if (mutex_lock_interruptible(&runtime->oss.params_lock))
+- return -ERESTARTSYS;
++ err = lock_params(runtime);
++ if (err < 0)
++ return err;
+ if (runtime->oss.format != format) {
+ runtime->oss.params = 1;
+ runtime->oss.format = format;
+ }
+- mutex_unlock(&runtime->oss.params_lock);
++ unlock_params(runtime);
+ }
+ }
+ return snd_pcm_oss_get_format(pcm_oss_file);
+@@ -1914,12 +1933,11 @@ static int snd_pcm_oss_set_subdivide(str
+ if (substream == NULL)
+ continue;
+ runtime = substream->runtime;
+- if (atomic_read(&runtime->oss.rw_ref))
+- return -EBUSY;
+- if (mutex_lock_interruptible(&runtime->oss.params_lock))
+- return -ERESTARTSYS;
++ err = lock_params(runtime);
++ if (err < 0)
++ return err;
+ err = snd_pcm_oss_set_subdivide1(substream, subdivide);
+- mutex_unlock(&runtime->oss.params_lock);
++ unlock_params(runtime);
+ if (err < 0)
+ return err;
+ }
+@@ -1954,12 +1972,11 @@ static int snd_pcm_oss_set_fragment(stru
+ if (substream == NULL)
+ continue;
+ runtime = substream->runtime;
+- if (atomic_read(&runtime->oss.rw_ref))
+- return -EBUSY;
+- if (mutex_lock_interruptible(&runtime->oss.params_lock))
+- return -ERESTARTSYS;
++ err = lock_params(runtime);
++ if (err < 0)
++ return err;
+ err = snd_pcm_oss_set_fragment1(substream, val);
+- mutex_unlock(&runtime->oss.params_lock);
++ unlock_params(runtime);
+ if (err < 0)
+ return err;
+ }
--- /dev/null
+From a820ccbe21e8ce8e86c39cd1d3bc8c7d1cbb949b Mon Sep 17 00:00:00 2001
+From: Takashi Iwai <tiwai@suse.de>
+Date: Mon, 2 Apr 2018 22:41:43 +0200
+Subject: ALSA: pcm: Fix UAF at PCM release via PCM timer access
+
+From: Takashi Iwai <tiwai@suse.de>
+
+commit a820ccbe21e8ce8e86c39cd1d3bc8c7d1cbb949b upstream.
+
+The PCM runtime object is created and freed dynamically at PCM stream
+open / close time. This is tracked via substream->runtime, and it's
+cleared at snd_pcm_detach_substream().
+
+The runtime object assignment is protected by PCM open_mutex, so for
+all PCM operations, it's safely handled. However, each PCM substream
+provides also an ALSA timer interface, and user-space can access to
+this while closing a PCM substream. This may eventually lead to a
+UAF, as snd_pcm_timer_resolution() tries to access the runtime while
+clearing it in other side.
+
+Fortunately, it's the only concurrent access from the PCM timer, and
+it merely reads runtime->timer_resolution field. So, we can avoid the
+race by reordering kfree() and wrapping the substream->runtime
+clearance with the corresponding timer lock.
+
+Reported-by: syzbot+8e62ff4e07aa2ce87826@syzkaller.appspotmail.com
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ sound/core/pcm.c | 8 +++++++-
+ 1 file changed, 7 insertions(+), 1 deletion(-)
+
+--- a/sound/core/pcm.c
++++ b/sound/core/pcm.c
+@@ -28,6 +28,7 @@
+ #include <sound/core.h>
+ #include <sound/minors.h>
+ #include <sound/pcm.h>
++#include <sound/timer.h>
+ #include <sound/control.h>
+ #include <sound/info.h>
+
+@@ -1054,8 +1055,13 @@ void snd_pcm_detach_substream(struct snd
+ snd_free_pages((void*)runtime->control,
+ PAGE_ALIGN(sizeof(struct snd_pcm_mmap_control)));
+ kfree(runtime->hw_constraints.rules);
+- kfree(runtime);
++ /* Avoid concurrent access to runtime via PCM timer interface */
++ if (substream->timer)
++ spin_lock_irq(&substream->timer->lock);
+ substream->runtime = NULL;
++ if (substream->timer)
++ spin_unlock_irq(&substream->timer->lock);
++ kfree(runtime);
+ put_pid(substream->pid);
+ substream->pid = NULL;
+ substream->pstr->substream_opened--;
--- /dev/null
+From 40cab6e88cb0b6c56d3f30b7491a20e803f948f6 Mon Sep 17 00:00:00 2001
+From: Takashi Iwai <tiwai@suse.de>
+Date: Fri, 23 Mar 2018 08:03:26 +0100
+Subject: ALSA: pcm: Return -EBUSY for OSS ioctls changing busy streams
+
+From: Takashi Iwai <tiwai@suse.de>
+
+commit 40cab6e88cb0b6c56d3f30b7491a20e803f948f6 upstream.
+
+OSS PCM stream management isn't modal but it allows ioctls issued at
+any time for changing the parameters. In the previous hardening
+patch ("ALSA: pcm: Avoid potential races between OSS ioctls and
+read/write"), we covered these races and prevent the corruption by
+protecting the concurrent accesses via params_lock mutex. However,
+this means that some ioctls that try to change the stream parameter
+(e.g. channels or format) would be blocked until the read/write
+finishes, and it may take really long.
+
+Basically changing the parameter while reading/writing is an invalid
+operation, hence it's even more user-friendly from the API POV if it
+returns -EBUSY in such a situation.
+
+This patch adds such checks in the relevant ioctls with the addition
+of read/write access refcount.
+
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ include/sound/pcm_oss.h | 1 +
+ sound/core/oss/pcm_oss.c | 36 +++++++++++++++++++++++++++---------
+ 2 files changed, 28 insertions(+), 9 deletions(-)
+
+--- a/include/sound/pcm_oss.h
++++ b/include/sound/pcm_oss.h
+@@ -57,6 +57,7 @@ struct snd_pcm_oss_runtime {
+ char *buffer; /* vmallocated period */
+ size_t buffer_used; /* used length from period buffer */
+ struct mutex params_lock;
++ atomic_t rw_ref; /* concurrent read/write accesses */
+ #ifdef CONFIG_SND_PCM_OSS_PLUGINS
+ struct snd_pcm_plugin *plugin_first;
+ struct snd_pcm_plugin *plugin_last;
+--- a/sound/core/oss/pcm_oss.c
++++ b/sound/core/oss/pcm_oss.c
+@@ -1370,6 +1370,7 @@ static ssize_t snd_pcm_oss_write1(struct
+ if (atomic_read(&substream->mmap_count))
+ return -ENXIO;
+
++ atomic_inc(&runtime->oss.rw_ref);
+ while (bytes > 0) {
+ if (mutex_lock_interruptible(&runtime->oss.params_lock)) {
+ tmp = -ERESTARTSYS;
+@@ -1433,6 +1434,7 @@ static ssize_t snd_pcm_oss_write1(struct
+ }
+ tmp = 0;
+ }
++ atomic_dec(&runtime->oss.rw_ref);
+ return xfer > 0 ? (snd_pcm_sframes_t)xfer : tmp;
+ }
+
+@@ -1478,6 +1480,7 @@ static ssize_t snd_pcm_oss_read1(struct
+ if (atomic_read(&substream->mmap_count))
+ return -ENXIO;
+
++ atomic_inc(&runtime->oss.rw_ref);
+ while (bytes > 0) {
+ if (mutex_lock_interruptible(&runtime->oss.params_lock)) {
+ tmp = -ERESTARTSYS;
+@@ -1526,6 +1529,7 @@ static ssize_t snd_pcm_oss_read1(struct
+ }
+ tmp = 0;
+ }
++ atomic_dec(&runtime->oss.rw_ref);
+ return xfer > 0 ? (snd_pcm_sframes_t)xfer : tmp;
+ }
+
+@@ -1632,8 +1636,11 @@ static int snd_pcm_oss_sync(struct snd_p
+ goto __direct;
+ if ((err = snd_pcm_oss_make_ready(substream)) < 0)
+ return err;
+- if (mutex_lock_interruptible(&runtime->oss.params_lock))
++ atomic_inc(&runtime->oss.rw_ref);
++ if (mutex_lock_interruptible(&runtime->oss.params_lock)) {
++ atomic_dec(&runtime->oss.rw_ref);
+ return -ERESTARTSYS;
++ }
+ format = snd_pcm_oss_format_from(runtime->oss.format);
+ width = snd_pcm_format_physical_width(format);
+ if (runtime->oss.buffer_used > 0) {
+@@ -1645,10 +1652,8 @@ static int snd_pcm_oss_sync(struct snd_p
+ runtime->oss.buffer + runtime->oss.buffer_used,
+ size);
+ err = snd_pcm_oss_sync1(substream, runtime->oss.period_bytes);
+- if (err < 0) {
+- mutex_unlock(&runtime->oss.params_lock);
+- return err;
+- }
++ if (err < 0)
++ goto unlock;
+ } else if (runtime->oss.period_ptr > 0) {
+ #ifdef OSS_DEBUG
+ pcm_dbg(substream->pcm, "sync: period_ptr\n");
+@@ -1658,10 +1663,8 @@ static int snd_pcm_oss_sync(struct snd_p
+ runtime->oss.buffer,
+ size * 8 / width);
+ err = snd_pcm_oss_sync1(substream, size);
+- if (err < 0) {
+- mutex_unlock(&runtime->oss.params_lock);
+- return err;
+- }
++ if (err < 0)
++ goto unlock;
+ }
+ /*
+ * The ALSA's period might be a bit large than OSS one.
+@@ -1675,7 +1678,11 @@ static int snd_pcm_oss_sync(struct snd_p
+ else if (runtime->access == SNDRV_PCM_ACCESS_RW_NONINTERLEAVED)
+ snd_pcm_lib_writev(substream, NULL, size);
+ }
++unlock:
+ mutex_unlock(&runtime->oss.params_lock);
++ atomic_dec(&runtime->oss.rw_ref);
++ if (err < 0)
++ return err;
+ /*
+ * finish sync: drain the buffer
+ */
+@@ -1723,6 +1730,8 @@ static int snd_pcm_oss_set_rate(struct s
+ rate = 192000;
+ if (mutex_lock_interruptible(&runtime->oss.params_lock))
+ return -ERESTARTSYS;
++ if (atomic_read(&runtime->oss.rw_ref))
++ return -EBUSY;
+ if (runtime->oss.rate != rate) {
+ runtime->oss.params = 1;
+ runtime->oss.rate = rate;
+@@ -1757,6 +1766,8 @@ static int snd_pcm_oss_set_channels(stru
+ runtime = substream->runtime;
+ if (mutex_lock_interruptible(&runtime->oss.params_lock))
+ return -ERESTARTSYS;
++ if (atomic_read(&runtime->oss.rw_ref))
++ return -EBUSY;
+ if (runtime->oss.channels != channels) {
+ runtime->oss.params = 1;
+ runtime->oss.channels = channels;
+@@ -1847,6 +1858,8 @@ static int snd_pcm_oss_set_format(struct
+ if (substream == NULL)
+ continue;
+ runtime = substream->runtime;
++ if (atomic_read(&runtime->oss.rw_ref))
++ return -EBUSY;
+ if (mutex_lock_interruptible(&runtime->oss.params_lock))
+ return -ERESTARTSYS;
+ if (runtime->oss.format != format) {
+@@ -1901,6 +1914,8 @@ static int snd_pcm_oss_set_subdivide(str
+ if (substream == NULL)
+ continue;
+ runtime = substream->runtime;
++ if (atomic_read(&runtime->oss.rw_ref))
++ return -EBUSY;
+ if (mutex_lock_interruptible(&runtime->oss.params_lock))
+ return -ERESTARTSYS;
+ err = snd_pcm_oss_set_subdivide1(substream, subdivide);
+@@ -1939,6 +1954,8 @@ static int snd_pcm_oss_set_fragment(stru
+ if (substream == NULL)
+ continue;
+ runtime = substream->runtime;
++ if (atomic_read(&runtime->oss.rw_ref))
++ return -EBUSY;
+ if (mutex_lock_interruptible(&runtime->oss.params_lock))
+ return -ERESTARTSYS;
+ err = snd_pcm_oss_set_fragment1(substream, val);
+@@ -2333,6 +2350,7 @@ static void snd_pcm_oss_init_substream(s
+ runtime->oss.maxfrags = 0;
+ runtime->oss.subdivision = 0;
+ substream->pcm_release = snd_pcm_oss_release_substream;
++ atomic_set(&runtime->oss.rw_ref, 0);
+ }
+
+ static int snd_pcm_oss_release_file(struct snd_pcm_oss_file *pcm_oss_file)
--- /dev/null
+From ad7b4e8022b9864c075fe71e1328b1d25cad82f6 Mon Sep 17 00:00:00 2001
+From: Frederic Barrat <fbarrat@linux.vnet.ibm.com>
+Date: Tue, 3 Apr 2018 15:54:02 +0200
+Subject: cxl: Fix possible deadlock when processing page faults from cxllib
+
+From: Frederic Barrat <fbarrat@linux.vnet.ibm.com>
+
+commit ad7b4e8022b9864c075fe71e1328b1d25cad82f6 upstream.
+
+cxllib_handle_fault() is called by an external driver when it needs to
+have the host resolve page faults for a buffer. The buffer can cover
+several pages and VMAs. The function iterates over all the pages used
+by the buffer, based on the page size of the VMA.
+
+To ensure some stability while processing the faults, the thread T1
+grabs the mm->mmap_sem semaphore with read access (R1). However, when
+processing a page fault for a single page, one of the underlying
+functions, copro_handle_mm_fault(), also grabs the same semaphore with
+read access (R2). So the thread T1 takes the semaphore twice.
+
+If another thread T2 tries to access the semaphore in write mode W1
+(say, because it wants to allocate memory and calls 'brk'), then that
+thread T2 will have to wait because there's a reader (R1). If the
+thread T1 is processing a new page at that time, it won't get an
+automatic grant at R2, because there's now a writer thread
+waiting (T2). And we have a deadlock.
+
+The timeline is:
+1. thread T1 owns the semaphore with read access R1
+2. thread T2 requests write access W1 and waits
+3. thread T1 requests read access R2 and waits
+
+The fix is for the thread T1 to release the semaphore R1 once it got
+the information it needs from the current VMA. The address space/VMAs
+could evolve while T1 iterates over the full buffer, but in the
+unlikely case where T1 misses a page, the external driver will raise a
+new page fault when retrying the memory access.
+
+Fixes: 3ced8d730063 ("cxl: Export library to support IBM XSL")
+Cc: stable@vger.kernel.org # 4.13+
+Signed-off-by: Frederic Barrat <fbarrat@linux.vnet.ibm.com>
+Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/misc/cxl/cxllib.c | 83 +++++++++++++++++++++++++++++-----------------
+ 1 file changed, 54 insertions(+), 29 deletions(-)
+
+--- a/drivers/misc/cxl/cxllib.c
++++ b/drivers/misc/cxl/cxllib.c
+@@ -208,49 +208,74 @@ int cxllib_get_PE_attributes(struct task
+ }
+ EXPORT_SYMBOL_GPL(cxllib_get_PE_attributes);
+
+-int cxllib_handle_fault(struct mm_struct *mm, u64 addr, u64 size, u64 flags)
++static int get_vma_info(struct mm_struct *mm, u64 addr,
++ u64 *vma_start, u64 *vma_end,
++ unsigned long *page_size)
+ {
+- int rc;
+- u64 dar;
+ struct vm_area_struct *vma = NULL;
+- unsigned long page_size;
+-
+- if (mm == NULL)
+- return -EFAULT;
++ int rc = 0;
+
+ down_read(&mm->mmap_sem);
+
+ vma = find_vma(mm, addr);
+ if (!vma) {
+- pr_err("Can't find vma for addr %016llx\n", addr);
+ rc = -EFAULT;
+ goto out;
+ }
+- /* get the size of the pages allocated */
+- page_size = vma_kernel_pagesize(vma);
++ *page_size = vma_kernel_pagesize(vma);
++ *vma_start = vma->vm_start;
++ *vma_end = vma->vm_end;
++out:
++ up_read(&mm->mmap_sem);
++ return rc;
++}
++
++int cxllib_handle_fault(struct mm_struct *mm, u64 addr, u64 size, u64 flags)
++{
++ int rc;
++ u64 dar, vma_start, vma_end;
++ unsigned long page_size;
+
+- for (dar = (addr & ~(page_size - 1)); dar < (addr + size); dar += page_size) {
+- if (dar < vma->vm_start || dar >= vma->vm_end) {
+- vma = find_vma(mm, addr);
+- if (!vma) {
+- pr_err("Can't find vma for addr %016llx\n", addr);
+- rc = -EFAULT;
+- goto out;
+- }
+- /* get the size of the pages allocated */
+- page_size = vma_kernel_pagesize(vma);
++ if (mm == NULL)
++ return -EFAULT;
++
++ /*
++ * The buffer we have to process can extend over several pages
++ * and may also cover several VMAs.
++ * We iterate over all the pages. The page size could vary
++ * between VMAs.
++ */
++ rc = get_vma_info(mm, addr, &vma_start, &vma_end, &page_size);
++ if (rc)
++ return rc;
++
++ for (dar = (addr & ~(page_size - 1)); dar < (addr + size);
++ dar += page_size) {
++ if (dar < vma_start || dar >= vma_end) {
++ /*
++ * We don't hold the mm->mmap_sem semaphore
++ * while iterating, since the semaphore is
++ * required by one of the lower-level page
++ * fault processing functions and it could
++ * create a deadlock.
++ *
++ * It means the VMAs can be altered between 2
++ * loop iterations and we could theoretically
++ * miss a page (however unlikely). But that's
++ * not really a problem, as the driver will
++ * retry access, get another page fault on the
++ * missing page and call us again.
++ */
++ rc = get_vma_info(mm, dar, &vma_start, &vma_end,
++ &page_size);
++ if (rc)
++ return rc;
+ }
+
+ rc = cxl_handle_mm_fault(mm, flags, dar);
+- if (rc) {
+- pr_err("cxl_handle_mm_fault failed %d", rc);
+- rc = -EFAULT;
+- goto out;
+- }
++ if (rc)
++ return -EFAULT;
+ }
+- rc = 0;
+-out:
+- up_read(&mm->mmap_sem);
+- return rc;
++ return 0;
+ }
+ EXPORT_SYMBOL_GPL(cxllib_handle_fault);
--- /dev/null
+From 0519c71e8d461ac3ef9a555bb7339243c9128d37 Mon Sep 17 00:00:00 2001
+From: Mike Snitzer <snitzer@redhat.com>
+Date: Mon, 26 Mar 2018 11:49:16 -0400
+Subject: dm: backfill abnormal IO support to non-splitting IO submission
+
+From: Mike Snitzer <snitzer@redhat.com>
+
+commit 0519c71e8d461ac3ef9a555bb7339243c9128d37 upstream.
+
+Otherwise, these abnormal IOs would be sent to the DM target
+regardless of whether the target advertised support for them.
+
+Factor out __process_abnormal_io() from __split_and_process_non_flush()
+so that discards, write same, etc may be conditionally processed.
+
+Fixes: 978e51ba3 ("dm: optimize bio-based NVMe IO submission")
+Cc: stable@vger.kernel.org # 4.16
+Signed-off-by: Mike Snitzer <snitzer@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/md/dm.c | 30 +++++++++++++++++++++++-------
+ 1 file changed, 23 insertions(+), 7 deletions(-)
+
+--- a/drivers/md/dm.c
++++ b/drivers/md/dm.c
+@@ -1477,6 +1477,23 @@ static int __send_write_zeroes(struct cl
+ return __send_changing_extent_only(ci, ti, get_num_write_zeroes_bios, NULL);
+ }
+
++static bool __process_abnormal_io(struct clone_info *ci, struct dm_target *ti,
++ int *result)
++{
++ struct bio *bio = ci->bio;
++
++ if (bio_op(bio) == REQ_OP_DISCARD)
++ *result = __send_discard(ci, ti);
++ else if (bio_op(bio) == REQ_OP_WRITE_SAME)
++ *result = __send_write_same(ci, ti);
++ else if (bio_op(bio) == REQ_OP_WRITE_ZEROES)
++ *result = __send_write_zeroes(ci, ti);
++ else
++ return false;
++
++ return true;
++}
++
+ /*
+ * Select the correct strategy for processing a non-flush bio.
+ */
+@@ -1491,12 +1508,8 @@ static int __split_and_process_non_flush
+ if (!dm_target_is_valid(ti))
+ return -EIO;
+
+- if (unlikely(bio_op(bio) == REQ_OP_DISCARD))
+- return __send_discard(ci, ti);
+- else if (unlikely(bio_op(bio) == REQ_OP_WRITE_SAME))
+- return __send_write_same(ci, ti);
+- else if (unlikely(bio_op(bio) == REQ_OP_WRITE_ZEROES))
+- return __send_write_zeroes(ci, ti);
++ if (unlikely(__process_abnormal_io(ci, ti, &r)))
++ return r;
+
+ if (bio_op(bio) == REQ_OP_ZONE_REPORT)
+ len = ci->sector_count;
+@@ -1617,9 +1630,12 @@ static blk_qc_t __process_bio(struct map
+ goto out;
+ }
+
+- tio = alloc_tio(&ci, ti, 0, GFP_NOIO);
+ ci.bio = bio;
+ ci.sector_count = bio_sectors(bio);
++ if (unlikely(__process_abnormal_io(&ci, ti, &error)))
++ goto out;
++
++ tio = alloc_tio(&ci, ti, 0, GFP_NOIO);
+ ret = __clone_and_map_simple_bio(&ci, tio, NULL);
+ }
+ out:
--- /dev/null
+From 5059353df86e2573ccd9d43fd9d9396dcec47ca2 Mon Sep 17 00:00:00 2001
+From: Mikulas Patocka <mpatocka@redhat.com>
+Date: Sun, 13 Aug 2017 22:45:08 -0400
+Subject: dm crypt: limit the number of allocated pages
+
+From: Mikulas Patocka <mpatocka@redhat.com>
+
+commit 5059353df86e2573ccd9d43fd9d9396dcec47ca2 upstream.
+
+dm-crypt consumes an excessive amount memory when the user attempts to
+zero a dm-crypt device with "blkdiscard -z". The command "blkdiscard -z"
+calls the BLKZEROOUT ioctl, it goes to the function __blkdev_issue_zeroout,
+__blkdev_issue_zeroout sends a large amount of write bios that contain
+the zero page as their payload.
+
+For each incoming page, dm-crypt allocates another page that holds the
+encrypted data, so when processing "blkdiscard -z", dm-crypt tries to
+allocate the amount of memory that is equal to the size of the device.
+This can trigger OOM killer or cause system crash.
+
+Fix this by limiting the amount of memory that dm-crypt allocates to 2%
+of total system memory. This limit is system-wide and is divided by the
+number of active dm-crypt devices and each device receives an equal
+share.
+
+Cc: stable@vger.kernel.org
+Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
+Signed-off-by: Mike Snitzer <snitzer@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/md/dm-crypt.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 65 insertions(+), 1 deletion(-)
+
+--- a/drivers/md/dm-crypt.c
++++ b/drivers/md/dm-crypt.c
+@@ -148,6 +148,8 @@ struct crypt_config {
+ mempool_t *tag_pool;
+ unsigned tag_pool_max_sectors;
+
++ struct percpu_counter n_allocated_pages;
++
+ struct bio_set *bs;
+ struct mutex bio_alloc_lock;
+
+@@ -219,6 +221,12 @@ struct crypt_config {
+ #define MAX_TAG_SIZE 480
+ #define POOL_ENTRY_SIZE 512
+
++static DEFINE_SPINLOCK(dm_crypt_clients_lock);
++static unsigned dm_crypt_clients_n = 0;
++static volatile unsigned long dm_crypt_pages_per_client;
++#define DM_CRYPT_MEMORY_PERCENT 2
++#define DM_CRYPT_MIN_PAGES_PER_CLIENT (BIO_MAX_PAGES * 16)
++
+ static void clone_init(struct dm_crypt_io *, struct bio *);
+ static void kcryptd_queue_crypt(struct dm_crypt_io *io);
+ static struct scatterlist *crypt_get_sg_data(struct crypt_config *cc,
+@@ -2155,6 +2163,43 @@ static int crypt_wipe_key(struct crypt_c
+ return r;
+ }
+
++static void crypt_calculate_pages_per_client(void)
++{
++ unsigned long pages = (totalram_pages - totalhigh_pages) * DM_CRYPT_MEMORY_PERCENT / 100;
++
++ if (!dm_crypt_clients_n)
++ return;
++
++ pages /= dm_crypt_clients_n;
++ if (pages < DM_CRYPT_MIN_PAGES_PER_CLIENT)
++ pages = DM_CRYPT_MIN_PAGES_PER_CLIENT;
++ dm_crypt_pages_per_client = pages;
++}
++
++static void *crypt_page_alloc(gfp_t gfp_mask, void *pool_data)
++{
++ struct crypt_config *cc = pool_data;
++ struct page *page;
++
++ if (unlikely(percpu_counter_compare(&cc->n_allocated_pages, dm_crypt_pages_per_client) >= 0) &&
++ likely(gfp_mask & __GFP_NORETRY))
++ return NULL;
++
++ page = alloc_page(gfp_mask);
++ if (likely(page != NULL))
++ percpu_counter_add(&cc->n_allocated_pages, 1);
++
++ return page;
++}
++
++static void crypt_page_free(void *page, void *pool_data)
++{
++ struct crypt_config *cc = pool_data;
++
++ __free_page(page);
++ percpu_counter_sub(&cc->n_allocated_pages, 1);
++}
++
+ static void crypt_dtr(struct dm_target *ti)
+ {
+ struct crypt_config *cc = ti->private;
+@@ -2181,6 +2226,10 @@ static void crypt_dtr(struct dm_target *
+ mempool_destroy(cc->req_pool);
+ mempool_destroy(cc->tag_pool);
+
++ if (cc->page_pool)
++ WARN_ON(percpu_counter_sum(&cc->n_allocated_pages) != 0);
++ percpu_counter_destroy(&cc->n_allocated_pages);
++
+ if (cc->iv_gen_ops && cc->iv_gen_ops->dtr)
+ cc->iv_gen_ops->dtr(cc);
+
+@@ -2197,6 +2246,12 @@ static void crypt_dtr(struct dm_target *
+
+ /* Must zero key material before freeing */
+ kzfree(cc);
++
++ spin_lock(&dm_crypt_clients_lock);
++ WARN_ON(!dm_crypt_clients_n);
++ dm_crypt_clients_n--;
++ crypt_calculate_pages_per_client();
++ spin_unlock(&dm_crypt_clients_lock);
+ }
+
+ static int crypt_ctr_ivmode(struct dm_target *ti, const char *ivmode)
+@@ -2644,6 +2699,15 @@ static int crypt_ctr(struct dm_target *t
+
+ ti->private = cc;
+
++ spin_lock(&dm_crypt_clients_lock);
++ dm_crypt_clients_n++;
++ crypt_calculate_pages_per_client();
++ spin_unlock(&dm_crypt_clients_lock);
++
++ ret = percpu_counter_init(&cc->n_allocated_pages, 0, GFP_KERNEL);
++ if (ret < 0)
++ goto bad;
++
+ /* Optional parameters need to be read before cipher constructor */
+ if (argc > 5) {
+ ret = crypt_ctr_optional(ti, argc - 5, &argv[5]);
+@@ -2698,7 +2762,7 @@ static int crypt_ctr(struct dm_target *t
+ ALIGN(sizeof(struct dm_crypt_io) + cc->dmreq_start + additional_req_size,
+ ARCH_KMALLOC_MINALIGN);
+
+- cc->page_pool = mempool_create_page_pool(BIO_MAX_PAGES, 0);
++ cc->page_pool = mempool_create(BIO_MAX_PAGES, crypt_page_alloc, crypt_page_free, cc);
+ if (!cc->page_pool) {
+ ti->error = "Cannot allocate page mempool";
+ goto bad;
--- /dev/null
+From 880bcce0dcc3172fe865352b492c41d85290cb8d Mon Sep 17 00:00:00 2001
+From: Heinz Mauelshagen <heinzm@redhat.com>
+Date: Fri, 16 Mar 2018 23:01:59 +0100
+Subject: dm raid: fix nosync status
+
+From: Heinz Mauelshagen <heinzm@redhat.com>
+
+commit 880bcce0dcc3172fe865352b492c41d85290cb8d upstream.
+
+Fix a race for "nosync" activations providing "aa.." device health
+characters and "0/N" sync ratio rather than "AA..." and "N/N". Occurs
+when status for the raid set is retrieved during resume before the MD
+sync thread starts and clears the MD_RECOVERY_NEEDED flag.
+
+Cc: stable@vger.kernel.org # 4.16+
+Signed-off-by: Heinz Mauelshagen <heinzm@redhat.com>
+Signed-off-by: Mike Snitzer <snitzer@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/md/dm-raid.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/md/dm-raid.c
++++ b/drivers/md/dm-raid.c
+@@ -3408,7 +3408,8 @@ static sector_t rs_get_progress(struct r
+ set_bit(RT_FLAG_RS_IN_SYNC, &rs->runtime_flags);
+
+ } else {
+- if (!test_bit(MD_RECOVERY_INTR, &recovery) &&
++ if (!test_bit(__CTR_FLAG_NOSYNC, &rs->ctr_flags) &&
++ !test_bit(MD_RECOVERY_INTR, &recovery) &&
+ (test_bit(MD_RECOVERY_NEEDED, &recovery) ||
+ test_bit(MD_RECOVERY_RESHAPE, &recovery) ||
+ test_bit(MD_RECOVERY_RUNNING, &recovery)))
--- /dev/null
+From c5637476bbf9bb86c7f0413b8f4822a73d8d2d07 Mon Sep 17 00:00:00 2001
+From: Maxime Jayat <maxime.jayat@mobile-devices.fr>
+Date: Thu, 22 Feb 2018 12:39:55 +0100
+Subject: dmaengine: at_xdmac: fix rare residue corruption
+
+From: Maxime Jayat <maxime.jayat@mobile-devices.fr>
+
+commit c5637476bbf9bb86c7f0413b8f4822a73d8d2d07 upstream.
+
+Despite the efforts made to correctly read the NDA and CUBC registers,
+the order in which the registers are read could sometimes lead to an
+inconsistent state.
+
+Re-using the timeline from the comments, this following timing of
+registers reads could lead to reading NDA with value "@desc2" and
+CUBC with value "MAX desc1":
+
+ INITD -------- ------------
+ |____________________|
+ _______________________ _______________
+ NDA @desc2 \/ @desc3
+ _______________________/\_______________
+ __________ ___________ _______________
+ CUBC 0 \/ MAX desc1 \/ MAX desc2
+ __________/\___________/\_______________
+ | | | |
+Events:(1)(2) (3)(4)
+
+(1) check_nda = @desc2
+(2) initd = 1
+(3) cur_ubc = MAX desc1
+(4) cur_nda = @desc2
+
+This is allowed by the condition ((check_nda == cur_nda) && initd),
+despite cur_ubc and cur_nda being in the precise state we don't want.
+
+This error leads to incorrect residue computation.
+
+Fix it by inversing the order in which CUBC and INITD are read. This
+makes sure that NDA and CUBC are always read together either _before_
+INITD goes to 0 or _after_ it is back at 1.
+The case where NDA is read before INITD is at 0 and CUBC is read after
+INITD is back at 1 will be rejected by check_nda and cur_nda being
+different.
+
+Fixes: 53398f488821 ("dmaengine: at_xdmac: fix residue corruption")
+Cc: stable@vger.kernel.org
+Signed-off-by: Maxime Jayat <maxime.jayat@mobile-devices.fr>
+Acked-by: Ludovic Desroches <ludovic.desroches@microchip.com>
+Signed-off-by: Vinod Koul <vinod.koul@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/dma/at_xdmac.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/dma/at_xdmac.c
++++ b/drivers/dma/at_xdmac.c
+@@ -1471,10 +1471,10 @@ at_xdmac_tx_status(struct dma_chan *chan
+ for (retry = 0; retry < AT_XDMAC_RESIDUE_MAX_RETRIES; retry++) {
+ check_nda = at_xdmac_chan_read(atchan, AT_XDMAC_CNDA) & 0xfffffffc;
+ rmb();
+- initd = !!(at_xdmac_chan_read(atchan, AT_XDMAC_CC) & AT_XDMAC_CC_INITD);
+- rmb();
+ cur_ubc = at_xdmac_chan_read(atchan, AT_XDMAC_CUBC);
+ rmb();
++ initd = !!(at_xdmac_chan_read(atchan, AT_XDMAC_CC) & AT_XDMAC_CC_INITD);
++ rmb();
+ cur_nda = at_xdmac_chan_read(atchan, AT_XDMAC_CNDA) & 0xfffffffc;
+ rmb();
+
--- /dev/null
+From 6ee687735e745eafae9e6b93d1ea70bc52e7ad07 Mon Sep 17 00:00:00 2001
+From: Andrew Morton <akpm@linux-foundation.org>
+Date: Tue, 13 Mar 2018 14:51:57 -0700
+Subject: drivers/infiniband/core/verbs.c: fix build with gcc-4.4.4
+
+From: Andrew Morton <akpm@linux-foundation.org>
+
+commit 6ee687735e745eafae9e6b93d1ea70bc52e7ad07 upstream.
+
+gcc-4.4.4 has issues with initialization of anonymous unions.
+
+drivers/infiniband/core/verbs.c: In function '__ib_drain_sq':
+drivers/infiniband/core/verbs.c:2204: error: unknown field 'wr_cqe' specified in initializer
+drivers/infiniband/core/verbs.c:2204: warning: initialization makes integer from pointer without a cast
+
+Work around this.
+
+Fixes: a1ae7d0345edd5 ("RDMA/core: Avoid that ib_drain_qp() triggers an out-of-bounds stack access")
+Cc: Bart Van Assche <bart.vanassche@wdc.com>
+Cc: Steve Wise <swise@opengridcomputing.com>
+Cc: Sagi Grimberg <sagi@grimberg.me>
+Cc: Jason Gunthorpe <jgg@mellanox.com>
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Doug Ledford <dledford@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/infiniband/core/verbs.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/infiniband/core/verbs.c
++++ b/drivers/infiniband/core/verbs.c
+@@ -2197,8 +2197,9 @@ static void __ib_drain_sq(struct ib_qp *
+ struct ib_send_wr *bad_swr;
+ struct ib_rdma_wr swr = {
+ .wr = {
++ .next = NULL,
++ { .wr_cqe = &sdrain.cqe, },
+ .opcode = IB_WR_RDMA_WRITE,
+- .wr_cqe = &sdrain.cqe,
+ },
+ };
+ int ret;
--- /dev/null
+From 06892cc190550807d332c95a0114c7e175584012 Mon Sep 17 00:00:00 2001
+From: Andrew Morton <akpm@linux-foundation.org>
+Date: Tue, 13 Mar 2018 15:06:45 -0700
+Subject: drivers/infiniband/ulp/srpt/ib_srpt.c: fix build with gcc-4.4.4
+
+From: Andrew Morton <akpm@linux-foundation.org>
+
+commit 06892cc190550807d332c95a0114c7e175584012 upstream.
+
+gcc-4.4.4 has issues with initialization of anonymous unions:
+
+drivers/infiniband/ulp/srpt/ib_srpt.c: In function 'srpt_zerolength_write':
+drivers/infiniband/ulp/srpt/ib_srpt.c:854: error: unknown field 'wr_cqe' specified in initializer
+drivers/infiniband/ulp/srpt/ib_srpt.c:854: warning: initialization makes integer from pointer without a cast
+
+Work aound this.
+
+Fixes: 2a78cb4db487 ("IB/srpt: Fix an out-of-bounds stack access in srpt_zerolength_write()")
+Cc: Bart Van Assche <bart.vanassche@wdc.com>
+Cc: Christoph Hellwig <hch@lst.de>
+Cc: Jason Gunthorpe <jgg@mellanox.com>
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Doug Ledford <dledford@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/infiniband/ulp/srpt/ib_srpt.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/infiniband/ulp/srpt/ib_srpt.c
++++ b/drivers/infiniband/ulp/srpt/ib_srpt.c
+@@ -841,8 +841,9 @@ static int srpt_zerolength_write(struct
+ struct ib_send_wr *bad_wr;
+ struct ib_rdma_wr wr = {
+ .wr = {
++ .next = NULL,
++ { .wr_cqe = &ch->zw_cqe, },
+ .opcode = IB_WR_RDMA_WRITE,
+- .wr_cqe = &ch->zw_cqe,
+ .send_flags = IB_SEND_SIGNALED,
+ }
+ };
--- /dev/null
+From 3a148896b24adf8688dc0c59af54531931677a40 Mon Sep 17 00:00:00 2001
+From: Bart Van Assche <bart.vanassche@wdc.com>
+Date: Mon, 12 Feb 2018 09:50:25 -0800
+Subject: IB/srp: Fix completion vector assignment algorithm
+
+From: Bart Van Assche <bart.vanassche@wdc.com>
+
+commit 3a148896b24adf8688dc0c59af54531931677a40 upstream.
+
+Ensure that cv_end is equal to ibdev->num_comp_vectors for the
+NUMA node with the highest index. This patch improves spreading
+of RDMA channels over completion vectors and thereby improves
+performance, especially on systems with only a single NUMA node.
+This patch drops support for the comp_vector login parameter by
+ignoring the value of that parameter since I have not found a
+good way to combine support for that parameter and automatic
+spreading of RDMA channels over completion vectors.
+
+Fixes: d92c0da71a35 ("IB/srp: Add multichannel support")
+Reported-by: Alexander Schmid <alex@modula-shop-systems.de>
+Signed-off-by: Bart Van Assche <bart.vanassche@wdc.com>
+Cc: Alexander Schmid <alex@modula-shop-systems.de>
+Cc: stable@vger.kernel.org
+Signed-off-by: Jason Gunthorpe <jgg@mellanox.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/infiniband/ulp/srp/ib_srp.c | 10 ++++------
+ 1 file changed, 4 insertions(+), 6 deletions(-)
+
+--- a/drivers/infiniband/ulp/srp/ib_srp.c
++++ b/drivers/infiniband/ulp/srp/ib_srp.c
+@@ -3873,12 +3873,10 @@ static ssize_t srp_create_target(struct
+ num_online_nodes());
+ const int ch_end = ((node_idx + 1) * target->ch_count /
+ num_online_nodes());
+- const int cv_start = (node_idx * ibdev->num_comp_vectors /
+- num_online_nodes() + target->comp_vector)
+- % ibdev->num_comp_vectors;
+- const int cv_end = ((node_idx + 1) * ibdev->num_comp_vectors /
+- num_online_nodes() + target->comp_vector)
+- % ibdev->num_comp_vectors;
++ const int cv_start = node_idx * ibdev->num_comp_vectors /
++ num_online_nodes();
++ const int cv_end = (node_idx + 1) * ibdev->num_comp_vectors /
++ num_online_nodes();
+ int cpu_idx = 0;
+
+ for_each_online_cpu(cpu) {
--- /dev/null
+From e68088e78d82920632eba112b968e49d588d02a2 Mon Sep 17 00:00:00 2001
+From: Bart Van Assche <bart.vanassche@wdc.com>
+Date: Fri, 23 Feb 2018 14:09:24 -0800
+Subject: IB/srp: Fix srp_abort()
+
+From: Bart Van Assche <bart.vanassche@wdc.com>
+
+commit e68088e78d82920632eba112b968e49d588d02a2 upstream.
+
+Before commit e494f6a72839 ("[SCSI] improved eh timeout handler") it
+did not really matter whether or not abort handlers like srp_abort()
+called .scsi_done() when returning another value than SUCCESS. Since
+that commit however this matters. Hence only call .scsi_done() when
+returning SUCCESS.
+
+Signed-off-by: Bart Van Assche <bart.vanassche@wdc.com>
+Cc: stable@vger.kernel.org
+Signed-off-by: Jason Gunthorpe <jgg@mellanox.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/infiniband/ulp/srp/ib_srp.c | 8 +++++---
+ 1 file changed, 5 insertions(+), 3 deletions(-)
+
+--- a/drivers/infiniband/ulp/srp/ib_srp.c
++++ b/drivers/infiniband/ulp/srp/ib_srp.c
+@@ -2974,9 +2974,11 @@ static int srp_abort(struct scsi_cmnd *s
+ ret = FAST_IO_FAIL;
+ else
+ ret = FAILED;
+- srp_free_req(ch, req, scmnd, 0);
+- scmnd->result = DID_ABORT << 16;
+- scmnd->scsi_done(scmnd);
++ if (ret == SUCCESS) {
++ srp_free_req(ch, req, scmnd, 0);
++ scmnd->result = DID_ABORT << 16;
++ scmnd->scsi_done(scmnd);
++ }
+
+ return ret;
+ }
--- /dev/null
+From 2a78cb4db487372152bed2055c038f9634d595e8 Mon Sep 17 00:00:00 2001
+From: Bart Van Assche <bart.vanassche@wdc.com>
+Date: Thu, 1 Mar 2018 14:00:30 -0800
+Subject: IB/srpt: Fix an out-of-bounds stack access in srpt_zerolength_write()
+
+From: Bart Van Assche <bart.vanassche@wdc.com>
+
+commit 2a78cb4db487372152bed2055c038f9634d595e8 upstream.
+
+Avoid triggering an out-of-bounds stack access by changing the type
+of 'wr' from ib_send_wr into ib_rdma_wr.
+
+This patch fixes the following KASAN bug report:
+
+BUG: KASAN: stack-out-of-bounds in rxe_post_send+0x7a9/0x9a0 [rdma_rxe]
+Read of size 8 at addr ffff880068197a48 by task kworker/2:1/44
+
+Workqueue: ib_cm cm_work_handler [ib_cm]
+Call Trace:
+ dump_stack+0x8e/0xcd
+ print_address_description+0x6f/0x280
+ kasan_report+0x25a/0x380
+ __asan_load8+0x54/0x90
+ rxe_post_send+0x7a9/0x9a0 [rdma_rxe]
+ srpt_zerolength_write+0xf0/0x180 [ib_srpt]
+ srpt_cm_rtu_recv+0x68/0x110 [ib_srpt]
+ srpt_rdma_cm_handler+0xbb/0x15b [ib_srpt]
+ cma_ib_handler+0x1aa/0x4a0 [rdma_cm]
+ cm_process_work+0x30/0x100 [ib_cm]
+ cm_work_handler+0xa86/0x351b [ib_cm]
+ process_one_work+0x475/0x9f0
+ worker_thread+0x69/0x690
+ kthread+0x1ad/0x1d0
+ ret_from_fork+0x3a/0x50
+
+Fixes: aaf45bd83eba ("IB/srpt: Detect session shutdown reliably")
+Signed-off-by: Bart Van Assche <bart.vanassche@wdc.com>
+Cc: Christoph Hellwig <hch@lst.de>
+Cc: stable@vger.kernel.org
+Signed-off-by: Jason Gunthorpe <jgg@mellanox.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/infiniband/ulp/srpt/ib_srpt.c | 15 +++++++++------
+ 1 file changed, 9 insertions(+), 6 deletions(-)
+
+--- a/drivers/infiniband/ulp/srpt/ib_srpt.c
++++ b/drivers/infiniband/ulp/srpt/ib_srpt.c
+@@ -838,16 +838,19 @@ static int srpt_post_recv(struct srpt_de
+ */
+ static int srpt_zerolength_write(struct srpt_rdma_ch *ch)
+ {
+- struct ib_send_wr wr, *bad_wr;
++ struct ib_send_wr *bad_wr;
++ struct ib_rdma_wr wr = {
++ .wr = {
++ .opcode = IB_WR_RDMA_WRITE,
++ .wr_cqe = &ch->zw_cqe,
++ .send_flags = IB_SEND_SIGNALED,
++ }
++ };
+
+ pr_debug("%s-%d: queued zerolength write\n", ch->sess_name,
+ ch->qp->qp_num);
+
+- memset(&wr, 0, sizeof(wr));
+- wr.opcode = IB_WR_RDMA_WRITE;
+- wr.wr_cqe = &ch->zw_cqe;
+- wr.send_flags = IB_SEND_SIGNALED;
+- return ib_post_send(ch->qp, &wr, &bad_wr);
++ return ib_post_send(ch->qp, &wr.wr, &bad_wr);
+ }
+
+ static void srpt_zerolength_write_done(struct ib_cq *cq, struct ib_wc *wc)
--- /dev/null
+From c31898c8c711f2bbbcaebe802a55827e288d875a Mon Sep 17 00:00:00 2001
+From: Dan Williams <dan.j.williams@intel.com>
+Date: Fri, 6 Apr 2018 11:25:38 -0700
+Subject: libnvdimm, dimm: fix dpa reservation vs uninitialized label area
+
+From: Dan Williams <dan.j.williams@intel.com>
+
+commit c31898c8c711f2bbbcaebe802a55827e288d875a upstream.
+
+At initialization time the 'dimm' driver caches a copy of the memory
+device's label area and reserves address space for each of the
+namespaces defined.
+
+However, as can be seen below, the reservation occurs even when the
+index blocks are invalid:
+
+ nvdimm nmem0: nvdimm_init_config_data: len: 131072 rc: 0
+ nvdimm nmem0: config data size: 131072
+ nvdimm nmem0: __nd_label_validate: nsindex0 labelsize 1 invalid
+ nvdimm nmem0: __nd_label_validate: nsindex1 labelsize 1 invalid
+ nvdimm nmem0: : pmem-6025e505: 0x1000000000 @ 0xf50000000 reserve <-- bad
+
+Gate dpa reservation on the presence of valid index blocks.
+
+Cc: <stable@vger.kernel.org>
+Fixes: 4a826c83db4e ("libnvdimm: namespace indices: read and validate")
+Reported-by: Krzysztof Rusocki <krzysztof.rusocki@intel.com>
+Signed-off-by: Dan Williams <dan.j.williams@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/nvdimm/dimm.c | 8 +++++---
+ 1 file changed, 5 insertions(+), 3 deletions(-)
+
+--- a/drivers/nvdimm/dimm.c
++++ b/drivers/nvdimm/dimm.c
+@@ -67,9 +67,11 @@ static int nvdimm_probe(struct device *d
+ ndd->ns_next = nd_label_next_nsindex(ndd->ns_current);
+ nd_label_copy(ndd, to_next_namespace_index(ndd),
+ to_current_namespace_index(ndd));
+- rc = nd_label_reserve_dpa(ndd);
+- if (ndd->ns_current >= 0)
+- nvdimm_set_aliasing(dev);
++ if (ndd->ns_current >= 0) {
++ rc = nd_label_reserve_dpa(ndd);
++ if (rc == 0)
++ nvdimm_set_aliasing(dev);
++ }
+ nvdimm_clear_locked(dev);
+ nvdimm_bus_unlock(dev);
+
--- /dev/null
+From 4f8672201b7e7ed4f5f6c3cf6dcd080648580582 Mon Sep 17 00:00:00 2001
+From: Dan Williams <dan.j.williams@intel.com>
+Date: Fri, 6 Apr 2018 16:37:21 -0700
+Subject: libnvdimm, namespace: use a safe lookup for dimm device name
+
+From: Dan Williams <dan.j.williams@intel.com>
+
+commit 4f8672201b7e7ed4f5f6c3cf6dcd080648580582 upstream.
+
+The following NULL dereference results from incorrectly assuming that
+ndd is valid in this print:
+
+ struct nvdimm_drvdata *ndd = to_ndd(&nd_region->mapping[i]);
+
+ /*
+ * Give up if we don't find an instance of a uuid at each
+ * position (from 0 to nd_region->ndr_mappings - 1), or if we
+ * find a dimm with two instances of the same uuid.
+ */
+ dev_err(&nd_region->dev, "%s missing label for %pUb\n",
+ dev_name(ndd->dev), nd_label->uuid);
+
+ BUG: unable to handle kernel NULL pointer dereference at 0000000000000000
+ IP: nd_region_register_namespaces+0xd67/0x13c0 [libnvdimm]
+ PGD 0 P4D 0
+ Oops: 0000 [#1] SMP PTI
+ CPU: 43 PID: 673 Comm: kworker/u609:10 Not tainted 4.16.0-rc4+ #1
+ [..]
+ RIP: 0010:nd_region_register_namespaces+0xd67/0x13c0 [libnvdimm]
+ [..]
+ Call Trace:
+ ? devres_add+0x2f/0x40
+ ? devm_kmalloc+0x52/0x60
+ ? nd_region_activate+0x9c/0x320 [libnvdimm]
+ nd_region_probe+0x94/0x260 [libnvdimm]
+ ? kernfs_add_one+0xe4/0x130
+ nvdimm_bus_probe+0x63/0x100 [libnvdimm]
+
+Switch to using the nvdimm device directly.
+
+Fixes: 0e3b0d123c8f ("libnvdimm, namespace: allow multiple pmem...")
+Cc: <stable@vger.kernel.org>
+Reported-by: Dave Jiang <dave.jiang@intel.com>
+Signed-off-by: Dan Williams <dan.j.williams@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/nvdimm/namespace_devs.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/nvdimm/namespace_devs.c
++++ b/drivers/nvdimm/namespace_devs.c
+@@ -1926,7 +1926,7 @@ static struct device *create_namespace_p
+ }
+
+ if (i < nd_region->ndr_mappings) {
+- struct nvdimm_drvdata *ndd = to_ndd(&nd_region->mapping[i]);
++ struct nvdimm *nvdimm = nd_region->mapping[i].nvdimm;
+
+ /*
+ * Give up if we don't find an instance of a uuid at each
+@@ -1934,7 +1934,7 @@ static struct device *create_namespace_p
+ * find a dimm with two instances of the same uuid.
+ */
+ dev_err(&nd_region->dev, "%s missing label for %pUb\n",
+- dev_name(ndd->dev), nd_label->uuid);
++ nvdimm_name(nvdimm), nd_label->uuid);
+ rc = -EINVAL;
+ goto err;
+ }
--- /dev/null
+From a1ae7d0345edd593d6725d3218434d903a0af95d Mon Sep 17 00:00:00 2001
+From: Bart Van Assche <bart.vanassche@wdc.com>
+Date: Thu, 1 Mar 2018 14:00:28 -0800
+Subject: RDMA/core: Avoid that ib_drain_qp() triggers an out-of-bounds stack access
+
+From: Bart Van Assche <bart.vanassche@wdc.com>
+
+commit a1ae7d0345edd593d6725d3218434d903a0af95d upstream.
+
+This patch fixes the following KASAN complaint:
+
+==================================================================
+BUG: KASAN: stack-out-of-bounds in rxe_post_send+0x77d/0x9b0 [rdma_rxe]
+Read of size 8 at addr ffff880061aef860 by task 01/1080
+
+CPU: 2 PID: 1080 Comm: 01 Not tainted 4.16.0-rc3-dbg+ #2
+Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.0.0-prebuilt.qemu-project.org 04/01/2014
+Call Trace:
+dump_stack+0x85/0xc7
+print_address_description+0x65/0x270
+kasan_report+0x231/0x350
+rxe_post_send+0x77d/0x9b0 [rdma_rxe]
+__ib_drain_sq+0x1ad/0x250 [ib_core]
+ib_drain_qp+0x9/0x30 [ib_core]
+srp_destroy_qp+0x51/0x70 [ib_srp]
+srp_free_ch_ib+0xfc/0x380 [ib_srp]
+srp_create_target+0x1071/0x19e0 [ib_srp]
+kernfs_fop_write+0x180/0x210
+__vfs_write+0xb1/0x2e0
+vfs_write+0xf6/0x250
+SyS_write+0x99/0x110
+do_syscall_64+0xee/0x2b0
+entry_SYSCALL_64_after_hwframe+0x42/0xb7
+
+The buggy address belongs to the page:
+page:ffffea000186bbc0 count:0 mapcount:0 mapping:0000000000000000 index:0x0
+flags: 0x4000000000000000()
+raw: 4000000000000000 0000000000000000 0000000000000000 00000000ffffffff
+raw: 0000000000000000 ffffea000186bbe0 0000000000000000 0000000000000000
+page dumped because: kasan: bad access detected
+
+Memory state around the buggy address:
+ffff880061aef700: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ffff880061aef780: 00 00 00 00 00 00 00 00 00 00 00 f1 f1 f1 f1 00
+>ffff880061aef800: f2 f2 f2 f2 f2 f2 f2 00 00 00 00 00 f2 f2 f2 f2
+ ^
+ffff880061aef880: f2 f2 f2 00 00 00 00 00 00 00 00 00 00 00 f2 f2
+ffff880061aef900: f2 f2 f2 00 00 00 00 00 00 00 00 00 00 00 00 00
+==================================================================
+
+Fixes: 765d67748bcf ("IB: new common API for draining queues")
+Signed-off-by: Bart Van Assche <bart.vanassche@wdc.com>
+Cc: Steve Wise <swise@opengridcomputing.com>
+Cc: Sagi Grimberg <sagi@grimberg.me>
+Cc: stable@vger.kernel.org
+Signed-off-by: Jason Gunthorpe <jgg@mellanox.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/infiniband/core/verbs.c | 11 ++++++++---
+ 1 file changed, 8 insertions(+), 3 deletions(-)
+
+--- a/drivers/infiniband/core/verbs.c
++++ b/drivers/infiniband/core/verbs.c
+@@ -2194,7 +2194,13 @@ static void __ib_drain_sq(struct ib_qp *
+ struct ib_cq *cq = qp->send_cq;
+ struct ib_qp_attr attr = { .qp_state = IB_QPS_ERR };
+ struct ib_drain_cqe sdrain;
+- struct ib_send_wr swr = {}, *bad_swr;
++ struct ib_send_wr *bad_swr;
++ struct ib_rdma_wr swr = {
++ .wr = {
++ .opcode = IB_WR_RDMA_WRITE,
++ .wr_cqe = &sdrain.cqe,
++ },
++ };
+ int ret;
+
+ ret = ib_modify_qp(qp, &attr, IB_QP_STATE);
+@@ -2203,11 +2209,10 @@ static void __ib_drain_sq(struct ib_qp *
+ return;
+ }
+
+- swr.wr_cqe = &sdrain.cqe;
+ sdrain.cqe.done = ib_drain_qp_done;
+ init_completion(&sdrain.done);
+
+- ret = ib_post_send(qp, &swr, &bad_swr);
++ ret = ib_post_send(qp, &swr.wr, &bad_swr);
+ if (ret) {
+ WARN_ONCE(ret, "failed to drain send queue: %d\n", ret);
+ return;
--- /dev/null
+From 4289861d88d6c7b5e4c8cc7fe2ad6cdf0cdfc366 Mon Sep 17 00:00:00 2001
+From: Leon Romanovsky <leonro@mellanox.com>
+Date: Tue, 13 Mar 2018 15:29:24 +0200
+Subject: RDMA/mlx5: Protect from NULL pointer derefence
+
+From: Leon Romanovsky <leonro@mellanox.com>
+
+commit 4289861d88d6c7b5e4c8cc7fe2ad6cdf0cdfc366 upstream.
+
+The mlx5_ib_alloc_implicit_mr() can fail to acquire pages
+and the returned mr pointer won't be valid. Ensure that it
+is not error prior to access.
+
+Cc: <stable@vger.kernel.org> # 4.10
+Fixes: 81713d3788d2 ("IB/mlx5: Add implicit MR support")
+Reported-by: Noa Osherovich <noaos@mellanox.com>
+Signed-off-by: Leon Romanovsky <leonro@mellanox.com>
+Signed-off-by: Doug Ledford <dledford@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/infiniband/hw/mlx5/mr.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/drivers/infiniband/hw/mlx5/mr.c
++++ b/drivers/infiniband/hw/mlx5/mr.c
+@@ -1223,6 +1223,8 @@ struct ib_mr *mlx5_ib_reg_user_mr(struct
+ return ERR_PTR(-EINVAL);
+
+ mr = mlx5_ib_alloc_implicit_mr(to_mpd(pd), access_flags);
++ if (IS_ERR(mr))
++ return ERR_CAST(mr);
+ return &mr->ibmr;
+ }
+ #endif
--- /dev/null
+From a6544a624c3ff92a64e4aca3931fa064607bd3da Mon Sep 17 00:00:00 2001
+From: Bart Van Assche <bart.vanassche@wdc.com>
+Date: Thu, 1 Mar 2018 14:00:29 -0800
+Subject: RDMA/rxe: Fix an out-of-bounds read
+
+From: Bart Van Assche <bart.vanassche@wdc.com>
+
+commit a6544a624c3ff92a64e4aca3931fa064607bd3da upstream.
+
+This patch avoids that KASAN reports the following when the SRP initiator
+calls srp_post_send():
+
+==================================================================
+BUG: KASAN: stack-out-of-bounds in rxe_post_send+0x5c4/0x980 [rdma_rxe]
+Read of size 8 at addr ffff880066606e30 by task 02-mq/1074
+
+CPU: 2 PID: 1074 Comm: 02-mq Not tainted 4.16.0-rc3-dbg+ #1
+Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.0.0-prebuilt.qemu-project.org 04/01/2014
+Call Trace:
+dump_stack+0x85/0xc7
+print_address_description+0x65/0x270
+kasan_report+0x231/0x350
+rxe_post_send+0x5c4/0x980 [rdma_rxe]
+srp_post_send.isra.16+0x149/0x190 [ib_srp]
+srp_queuecommand+0x94d/0x1670 [ib_srp]
+scsi_dispatch_cmd+0x1c2/0x550 [scsi_mod]
+scsi_queue_rq+0x843/0xa70 [scsi_mod]
+blk_mq_dispatch_rq_list+0x143/0xac0
+blk_mq_do_dispatch_ctx+0x1c5/0x260
+blk_mq_sched_dispatch_requests+0x2bf/0x2f0
+__blk_mq_run_hw_queue+0xdb/0x160
+__blk_mq_delay_run_hw_queue+0xba/0x100
+blk_mq_run_hw_queue+0xf2/0x190
+blk_mq_sched_insert_request+0x163/0x2f0
+blk_execute_rq+0xb0/0x130
+scsi_execute+0x14e/0x260 [scsi_mod]
+scsi_probe_and_add_lun+0x366/0x13d0 [scsi_mod]
+__scsi_scan_target+0x18a/0x810 [scsi_mod]
+scsi_scan_target+0x11e/0x130 [scsi_mod]
+srp_create_target+0x1522/0x19e0 [ib_srp]
+kernfs_fop_write+0x180/0x210
+__vfs_write+0xb1/0x2e0
+vfs_write+0xf6/0x250
+SyS_write+0x99/0x110
+do_syscall_64+0xee/0x2b0
+entry_SYSCALL_64_after_hwframe+0x42/0xb7
+
+The buggy address belongs to the page:
+page:ffffea0001998180 count:0 mapcount:0 mapping:0000000000000000 index:0x0
+flags: 0x4000000000000000()
+raw: 4000000000000000 0000000000000000 0000000000000000 00000000ffffffff
+raw: dead000000000100 dead000000000200 0000000000000000 0000000000000000
+page dumped because: kasan: bad access detected
+
+Memory state around the buggy address:
+ffff880066606d00: 00 00 00 00 00 00 00 00 00 00 00 00 00 f1 f1 f1
+ffff880066606d80: f1 00 f2 f2 f2 f2 f2 f2 f2 00 00 f2 f2 f2 f2 f2
+>ffff880066606e00: f2 00 00 00 00 00 f2 f2 f2 f3 f3 f3 f3 00 00 00
+ ^
+ffff880066606e80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ffff880066606f00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+==================================================================
+
+Fixes: 8700e3e7c485 ("Soft RoCE driver")
+Signed-off-by: Bart Van Assche <bart.vanassche@wdc.com>
+Cc: Moni Shoua <monis@mellanox.com>
+Cc: stable@vger.kernel.org
+Signed-off-by: Jason Gunthorpe <jgg@mellanox.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/infiniband/sw/rxe/rxe_verbs.c | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+--- a/drivers/infiniband/sw/rxe/rxe_verbs.c
++++ b/drivers/infiniband/sw/rxe/rxe_verbs.c
+@@ -711,9 +711,8 @@ static int init_send_wqe(struct rxe_qp *
+ memcpy(wqe->dma.sge, ibwr->sg_list,
+ num_sge * sizeof(struct ib_sge));
+
+- wqe->iova = (mask & WR_ATOMIC_MASK) ?
+- atomic_wr(ibwr)->remote_addr :
+- rdma_wr(ibwr)->remote_addr;
++ wqe->iova = mask & WR_ATOMIC_MASK ? atomic_wr(ibwr)->remote_addr :
++ mask & WR_READ_OR_WRITE_MASK ? rdma_wr(ibwr)->remote_addr : 0;
+ wqe->mask = mask;
+ wqe->dma.length = length;
+ wqe->dma.resid = length;
--- /dev/null
+From 8435168d50e66fa5eae01852769d20a36f9e5e83 Mon Sep 17 00:00:00 2001
+From: Roland Dreier <roland@purestorage.com>
+Date: Tue, 3 Apr 2018 15:33:01 -0700
+Subject: RDMA/ucma: Don't allow setting RDMA_OPTION_IB_PATH without an RDMA device
+
+From: Roland Dreier <roland@purestorage.com>
+
+commit 8435168d50e66fa5eae01852769d20a36f9e5e83 upstream.
+
+Check to make sure that ctx->cm_id->device is set before we use it.
+Otherwise userspace can trigger a NULL dereference by doing
+RDMA_USER_CM_CMD_SET_OPTION on an ID that is not bound to a device.
+
+Cc: <stable@vger.kernel.org>
+Reported-by: <syzbot+a67bc93e14682d92fc2f@syzkaller.appspotmail.com>
+Signed-off-by: Roland Dreier <roland@purestorage.com>
+Signed-off-by: Jason Gunthorpe <jgg@mellanox.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/infiniband/core/ucma.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/drivers/infiniband/core/ucma.c
++++ b/drivers/infiniband/core/ucma.c
+@@ -1241,6 +1241,9 @@ static int ucma_set_ib_path(struct ucma_
+ if (!optlen)
+ return -EINVAL;
+
++ if (!ctx->cm_id->device)
++ return -EINVAL;
++
+ memset(&sa_path, 0, sizeof(sa_path));
+
+ sa_path.rec_type = SA_PATH_REC_TYPE_IB;
ext4-add-bounds-checking-to-ext4_xattr_find_entry.patch
ext4-add-extra-checks-to-ext4_xattr_block_get.patch
ext4-force-revalidation-of-directory-pointer-after-seekdir-2.patch
+dm-backfill-abnormal-io-support-to-non-splitting-io-submission.patch
+dm-crypt-limit-the-number-of-allocated-pages.patch
+rdma-ucma-don-t-allow-setting-rdma_option_ib_path-without-an-rdma-device.patch
+rdma-mlx5-protect-from-null-pointer-derefence.patch
+rdma-rxe-fix-an-out-of-bounds-read.patch
+rdma-core-avoid-that-ib_drain_qp-triggers-an-out-of-bounds-stack-access.patch
+xprtrdma-fix-latency-regression-on-numa-nfs-rdma-clients.patch
+xprtrdma-fix-corner-cases-when-handling-device-removal.patch
+alsa-pcm-avoid-potential-races-between-oss-ioctls-and-read-write.patch
+alsa-pcm-return-ebusy-for-oss-ioctls-changing-busy-streams.patch
+alsa-pcm-fix-mutex-unbalance-in-oss-emulation-ioctls.patch
+alsa-pcm-fix-uaf-at-pcm-release-via-pcm-timer-access.patch
+alsa-pcm-fix-endless-loop-for-xrun-recovery-in-oss-emulation.patch
+ib-srp-fix-srp_abort.patch
+ib-srp-fix-completion-vector-assignment-algorithm.patch
+ib-srpt-fix-an-out-of-bounds-stack-access-in-srpt_zerolength_write.patch
+drivers-infiniband-core-verbs.c-fix-build-with-gcc-4.4.4.patch
+drivers-infiniband-ulp-srpt-ib_srpt.c-fix-build-with-gcc-4.4.4.patch
+dm-raid-fix-nosync-status.patch
+dmaengine-at_xdmac-fix-rare-residue-corruption.patch
+cxl-fix-possible-deadlock-when-processing-page-faults-from-cxllib.patch
+tpm-self-test-failure-should-not-cause-suspend-to-fail.patch
+libnvdimm-dimm-fix-dpa-reservation-vs-uninitialized-label-area.patch
+libnvdimm-namespace-use-a-safe-lookup-for-dimm-device-name.patch
+vsprintf-do-not-preprocess-non-dereferenced-pointers-for-bprintf-px-and-pk.patch
--- /dev/null
+From 0803d7befa15cab5717d667a97a66214d2a4c083 Mon Sep 17 00:00:00 2001
+From: Chris Chiu <chiu@endlessm.com>
+Date: Tue, 20 Mar 2018 15:36:40 +0800
+Subject: tpm: self test failure should not cause suspend to fail
+
+From: Chris Chiu <chiu@endlessm.com>
+
+commit 0803d7befa15cab5717d667a97a66214d2a4c083 upstream.
+
+The Acer Acer Veriton X4110G has a TPM device detected as:
+ tpm_tis 00:0b: 1.2 TPM (device-id 0xFE, rev-id 71)
+
+After the first S3 suspend, the following error appears during resume:
+ tpm tpm0: A TPM error(38) occurred continue selftest
+
+Any following S3 suspend attempts will now fail with this error:
+ tpm tpm0: Error (38) sending savestate before suspend
+ PM: Device 00:0b failed to suspend: error 38
+
+Error 38 is TPM_ERR_INVALID_POSTINIT which means the TPM is
+not in the correct state. This indicates that the platform BIOS
+is not sending the usual TPM_Startup command during S3 resume.
+>From this point onwards, all TPM commands will fail.
+
+The same issue was previously reported on Foxconn 6150BK8MC and
+Sony Vaio TX3.
+
+The platform behaviour seems broken here, but we should not break
+suspend/resume because of this.
+
+When the unexpected TPM state is encountered, set a flag to skip the
+affected TPM_SaveState command on later suspends.
+
+Cc: stable@vger.kernel.org
+Signed-off-by: Chris Chiu <chiu@endlessm.com>
+Signed-off-by: Daniel Drake <drake@endlessm.com>
+Link: http://lkml.kernel.org/r/CAB4CAwfSCvj1cudi+MWaB5g2Z67d9DwY1o475YOZD64ma23UiQ@mail.gmail.com
+Link: https://lkml.org/lkml/2011/3/28/192
+Link: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=591031
+Reviewed-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
+Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/char/tpm/tpm-interface.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/drivers/char/tpm/tpm-interface.c
++++ b/drivers/char/tpm/tpm-interface.c
+@@ -969,6 +969,10 @@ int tpm_do_selftest(struct tpm_chip *chi
+ loops = jiffies_to_msecs(duration) / delay_msec;
+
+ rc = tpm_continue_selftest(chip);
++ if (rc == TPM_ERR_INVALID_POSTINIT) {
++ chip->flags |= TPM_CHIP_FLAG_ALWAYS_POWERED;
++ dev_info(&chip->dev, "TPM not ready (%d)\n", rc);
++ }
+ /* This may fail if there was no TPM driver during a suspend/resume
+ * cycle; some may return 10 (BAD_ORDINAL), others 28 (FAILEDSELFTEST)
+ */
--- /dev/null
+From 1e6338cfb50e244c445ad7d891b35385bd0ee757 Mon Sep 17 00:00:00 2001
+From: "Steven Rostedt (VMware)" <rostedt@goodmis.org>
+Date: Tue, 3 Apr 2018 14:38:53 -0400
+Subject: vsprintf: Do not preprocess non-dereferenced pointers for bprintf (%px and %pK)
+
+From: Steven Rostedt (VMware) <rostedt@goodmis.org>
+
+commit 1e6338cfb50e244c445ad7d891b35385bd0ee757 upstream.
+
+Commit 841a915d20c7b2 ("printf: Do not have bprintf dereference pointers")
+would preprocess various pointers that are dereferenced in the bprintf()
+because the recording and printing are done at two different times. Some
+pointers stayed dereferenced in the ring buffer because user space could
+handle them (namely "%pS" and friends). Pointers that are not dereferenced
+should not be processed immediately but instead just saved directly.
+
+Cc: stable@vger.kernel.org
+Fixes: 841a915d20c7b2 ("printf: Do not have bprintf dereference pointers")
+Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ lib/vsprintf.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/lib/vsprintf.c
++++ b/lib/vsprintf.c
+@@ -2591,6 +2591,8 @@ int vbin_printf(u32 *bin_buf, size_t siz
+ case 's':
+ case 'F':
+ case 'f':
++ case 'x':
++ case 'K':
+ save_arg(void *);
+ break;
+ default:
+@@ -2765,6 +2767,8 @@ int bstr_printf(char *buf, size_t size,
+ case 's':
+ case 'F':
+ case 'f':
++ case 'x':
++ case 'K':
+ process = true;
+ break;
+ default:
--- /dev/null
+From 25524288631fc5b7d33259fca1e0dc38146be5d6 Mon Sep 17 00:00:00 2001
+From: Chuck Lever <chuck.lever@oracle.com>
+Date: Mon, 19 Mar 2018 14:23:16 -0400
+Subject: xprtrdma: Fix corner cases when handling device removal
+
+From: Chuck Lever <chuck.lever@oracle.com>
+
+commit 25524288631fc5b7d33259fca1e0dc38146be5d6 upstream.
+
+Michal Kalderon has found some corner cases around device unload
+with active NFS mounts that I didn't have the imagination to test
+when xprtrdma device removal was added last year.
+
+- The ULP device removal handler is responsible for deallocating
+ the PD. That wasn't clear to me initially, and my own testing
+ suggested it was not necessary, but that is incorrect.
+
+- The transport destruction path can no longer assume that there
+ is a valid ID.
+
+- When destroying a transport, ensure that ib_free_cq() is not
+ invoked on a CQ that was already released.
+
+Reported-by: Michal Kalderon <Michal.Kalderon@cavium.com>
+Fixes: bebd031866ca ("xprtrdma: Support unplugging an HCA from ...")
+Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
+Cc: stable@vger.kernel.org # v4.12+
+Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ net/sunrpc/xprtrdma/verbs.c | 13 +++++++++----
+ 1 file changed, 9 insertions(+), 4 deletions(-)
+
+--- a/net/sunrpc/xprtrdma/verbs.c
++++ b/net/sunrpc/xprtrdma/verbs.c
+@@ -250,7 +250,6 @@ rpcrdma_conn_upcall(struct rdma_cm_id *i
+ wait_for_completion(&ia->ri_remove_done);
+
+ ia->ri_id = NULL;
+- ia->ri_pd = NULL;
+ ia->ri_device = NULL;
+ /* Return 1 to ensure the core destroys the id. */
+ return 1;
+@@ -445,7 +444,9 @@ rpcrdma_ia_remove(struct rpcrdma_ia *ia)
+ ia->ri_id->qp = NULL;
+ }
+ ib_free_cq(ep->rep_attr.recv_cq);
++ ep->rep_attr.recv_cq = NULL;
+ ib_free_cq(ep->rep_attr.send_cq);
++ ep->rep_attr.send_cq = NULL;
+
+ /* The ULP is responsible for ensuring all DMA
+ * mappings and MRs are gone.
+@@ -458,6 +459,8 @@ rpcrdma_ia_remove(struct rpcrdma_ia *ia)
+ rpcrdma_dma_unmap_regbuf(req->rl_recvbuf);
+ }
+ rpcrdma_mrs_destroy(buf);
++ ib_dealloc_pd(ia->ri_pd);
++ ia->ri_pd = NULL;
+
+ /* Allow waiters to continue */
+ complete(&ia->ri_remove_done);
+@@ -628,14 +631,16 @@ rpcrdma_ep_destroy(struct rpcrdma_ep *ep
+ {
+ cancel_delayed_work_sync(&ep->rep_connect_worker);
+
+- if (ia->ri_id->qp) {
++ if (ia->ri_id && ia->ri_id->qp) {
+ rpcrdma_ep_disconnect(ep, ia);
+ rdma_destroy_qp(ia->ri_id);
+ ia->ri_id->qp = NULL;
+ }
+
+- ib_free_cq(ep->rep_attr.recv_cq);
+- ib_free_cq(ep->rep_attr.send_cq);
++ if (ep->rep_attr.recv_cq)
++ ib_free_cq(ep->rep_attr.recv_cq);
++ if (ep->rep_attr.send_cq)
++ ib_free_cq(ep->rep_attr.send_cq);
+ }
+
+ /* Re-establish a connection after a device removal event.
--- /dev/null
+From 6720a89933739cb8dec748cd253f7c8df2c0ae4d Mon Sep 17 00:00:00 2001
+From: Chuck Lever <chuck.lever@oracle.com>
+Date: Wed, 28 Feb 2018 15:30:27 -0500
+Subject: xprtrdma: Fix latency regression on NUMA NFS/RDMA clients
+
+From: Chuck Lever <chuck.lever@oracle.com>
+
+commit 6720a89933739cb8dec748cd253f7c8df2c0ae4d upstream.
+
+With v4.15, on one of my NFS/RDMA clients I measured a nearly
+doubling in the latency of small read and write system calls. There
+was no change in server round trip time. The extra latency appears
+in the whole RPC execution path.
+
+"git bisect" settled on commit ccede7598588 ("xprtrdma: Spread reply
+processing over more CPUs") .
+
+After some experimentation, I found that leaving the WQ bound and
+allowing the scheduler to pick the dispatch CPU seems to eliminate
+the long latencies, and it does not introduce any new regressions.
+
+The fix is implemented by reverting only the part of
+commit ccede7598588 ("xprtrdma: Spread reply processing over more
+CPUs") that dispatches RPC replies specifically on the CPU where the
+matching RPC call was made.
+
+Interestingly, saving the CPU number and later queuing reply
+processing there was effective _only_ for a NFS READ and WRITE
+request. On my NUMA client, in-kernel RPC reply processing for
+asynchronous RPCs was dispatched on the same CPU where the RPC call
+was made, as expected. However synchronous RPCs seem to get their
+reply dispatched on some other CPU than where the call was placed,
+every time.
+
+Fixes: ccede7598588 ("xprtrdma: Spread reply processing over ... ")
+Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
+Cc: stable@vger.kernel.org # v4.15+
+Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ net/sunrpc/xprtrdma/rpc_rdma.c | 2 +-
+ net/sunrpc/xprtrdma/transport.c | 2 --
+ net/sunrpc/xprtrdma/xprt_rdma.h | 1 -
+ 3 files changed, 1 insertion(+), 4 deletions(-)
+
+--- a/net/sunrpc/xprtrdma/rpc_rdma.c
++++ b/net/sunrpc/xprtrdma/rpc_rdma.c
+@@ -1366,7 +1366,7 @@ void rpcrdma_reply_handler(struct rpcrdm
+
+ trace_xprtrdma_reply(rqst->rq_task, rep, req, credits);
+
+- queue_work_on(req->rl_cpu, rpcrdma_receive_wq, &rep->rr_work);
++ queue_work(rpcrdma_receive_wq, &rep->rr_work);
+ return;
+
+ out_badstatus:
+--- a/net/sunrpc/xprtrdma/transport.c
++++ b/net/sunrpc/xprtrdma/transport.c
+@@ -52,7 +52,6 @@
+ #include <linux/slab.h>
+ #include <linux/seq_file.h>
+ #include <linux/sunrpc/addr.h>
+-#include <linux/smp.h>
+
+ #include "xprt_rdma.h"
+
+@@ -651,7 +650,6 @@ xprt_rdma_allocate(struct rpc_task *task
+ if (!rpcrdma_get_recvbuf(r_xprt, req, rqst->rq_rcvsize, flags))
+ goto out_fail;
+
+- req->rl_cpu = smp_processor_id();
+ req->rl_connect_cookie = 0; /* our reserved value */
+ rpcrdma_set_xprtdata(rqst, req);
+ rqst->rq_buffer = req->rl_sendbuf->rg_base;
+--- a/net/sunrpc/xprtrdma/xprt_rdma.h
++++ b/net/sunrpc/xprtrdma/xprt_rdma.h
+@@ -334,7 +334,6 @@ enum {
+ struct rpcrdma_buffer;
+ struct rpcrdma_req {
+ struct list_head rl_list;
+- int rl_cpu;
+ unsigned int rl_connect_cookie;
+ struct rpcrdma_buffer *rl_buffer;
+ struct rpcrdma_rep *rl_reply;