]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
3.16-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 12 Sep 2014 21:46:16 +0000 (14:46 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 12 Sep 2014 21:46:16 +0000 (14:46 -0700)
added patches:
media-au0828-only-alt-setting-logic-when-needed.patch
media-xc4000-fix-get_frequency.patch
media-xc5000-fix-get_frequency.patch
reiserfs-fix-corruption-introduced-by-balance_leaf-refactor.patch
reiserfs-fix-use-after-free-in-journal-teardown.patch

queue-3.16/media-au0828-only-alt-setting-logic-when-needed.patch [new file with mode: 0644]
queue-3.16/media-xc4000-fix-get_frequency.patch [new file with mode: 0644]
queue-3.16/media-xc5000-fix-get_frequency.patch [new file with mode: 0644]
queue-3.16/reiserfs-fix-corruption-introduced-by-balance_leaf-refactor.patch [new file with mode: 0644]
queue-3.16/reiserfs-fix-use-after-free-in-journal-teardown.patch [new file with mode: 0644]

diff --git a/queue-3.16/media-au0828-only-alt-setting-logic-when-needed.patch b/queue-3.16/media-au0828-only-alt-setting-logic-when-needed.patch
new file mode 100644 (file)
index 0000000..0ada51e
--- /dev/null
@@ -0,0 +1,91 @@
+From 64ea37bbd8a5815522706f0099ad3f11c7537e15 Mon Sep 17 00:00:00 2001
+From: Mauro Carvalho Chehab <m.chehab@samsung.com>
+Date: Sun, 8 Jun 2014 13:54:57 -0300
+Subject: media: au0828: Only alt setting logic when needed
+
+From: Mauro Carvalho Chehab <m.chehab@samsung.com>
+
+commit 64ea37bbd8a5815522706f0099ad3f11c7537e15 upstream.
+
+It seems that there's a bug at au0828 hardware/firmware
+related to alternate setting: when the device is already at
+alt 5, a further call causes the URBs to receive -ESHUTDOWN.
+
+I found two different encarnations of this issue:
+
+1) at qv4l2, it fails the second time we try to open the
+video screen;
+2) at xawtv, when audio underrun occurs, with is very
+frequent, at least on my test machine.
+
+The fix is simple: just check if alt=5 before calling
+set_usb_interface().
+
+Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/media/usb/au0828/au0828-video.c |   34 ++++++++++++++++----------------
+ 1 file changed, 17 insertions(+), 17 deletions(-)
+
+--- a/drivers/media/usb/au0828/au0828-video.c
++++ b/drivers/media/usb/au0828/au0828-video.c
+@@ -787,11 +787,27 @@ static int au0828_i2s_init(struct au0828
+ /*
+  * Auvitek au0828 analog stream enable
+- * Please set interface0 to AS5 before enable the stream
+  */
+ static int au0828_analog_stream_enable(struct au0828_dev *d)
+ {
++      struct usb_interface *iface;
++      int ret;
++
+       dprintk(1, "au0828_analog_stream_enable called\n");
++
++      iface = usb_ifnum_to_if(d->usbdev, 0);
++      if (iface && iface->cur_altsetting->desc.bAlternateSetting != 5) {
++              dprintk(1, "Changing intf#0 to alt 5\n");
++              /* set au0828 interface0 to AS5 here again */
++              ret = usb_set_interface(d->usbdev, 0, 5);
++              if (ret < 0) {
++                      printk(KERN_INFO "Au0828 can't set alt setting to 5!\n");
++                      return -EBUSY;
++              }
++      }
++
++      /* FIXME: size should be calculated using d->width, d->height */
++
+       au0828_writereg(d, AU0828_SENSORCTRL_VBI_103, 0x00);
+       au0828_writereg(d, 0x106, 0x00);
+       /* set x position */
+@@ -1002,15 +1018,6 @@ static int au0828_v4l2_open(struct file
+               return -ERESTARTSYS;
+       }
+       if (dev->users == 0) {
+-              /* set au0828 interface0 to AS5 here again */
+-              ret = usb_set_interface(dev->usbdev, 0, 5);
+-              if (ret < 0) {
+-                      mutex_unlock(&dev->lock);
+-                      printk(KERN_INFO "Au0828 can't set alternate to 5!\n");
+-                      kfree(fh);
+-                      return -EBUSY;
+-              }
+-
+               au0828_analog_stream_enable(dev);
+               au0828_analog_stream_reset(dev);
+@@ -1252,13 +1259,6 @@ static int au0828_set_format(struct au08
+               }
+       }
+-      /* set au0828 interface0 to AS5 here again */
+-      ret = usb_set_interface(dev->usbdev, 0, 5);
+-      if (ret < 0) {
+-              printk(KERN_INFO "Au0828 can't set alt setting to 5!\n");
+-              return -EBUSY;
+-      }
+-
+       au0828_analog_stream_enable(dev);
+       return 0;
diff --git a/queue-3.16/media-xc4000-fix-get_frequency.patch b/queue-3.16/media-xc4000-fix-get_frequency.patch
new file mode 100644 (file)
index 0000000..48d45b6
--- /dev/null
@@ -0,0 +1,105 @@
+From 4c07e32884ab69574cfd9eb4de3334233c938071 Mon Sep 17 00:00:00 2001
+From: Mauro Carvalho Chehab <m.chehab@samsung.com>
+Date: Mon, 21 Jul 2014 13:28:15 -0300
+Subject: media: xc4000: Fix get_frequency()
+
+From: Mauro Carvalho Chehab <m.chehab@samsung.com>
+
+commit 4c07e32884ab69574cfd9eb4de3334233c938071 upstream.
+
+The programmed frequency on xc4000 is not the middle
+frequency, but the initial frequency on the bandwidth range.
+However, the DVB API works with the middle frequency.
+
+This works fine on set_frontend, as the device calculates
+the needed offset. However, at get_frequency(), the returned
+value is the initial frequency. That's generally not a big
+problem on most drivers, however, starting with changeset
+6fe1099c7aec, the frequency drift is taken into account at
+dib7000p driver.
+
+This broke support for PCTV 340e, with uses dib7000p demod and
+xc4000 tuner.
+
+Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/media/tuners/xc4000.c |   20 +++++++++++---------
+ 1 file changed, 11 insertions(+), 9 deletions(-)
+
+--- a/drivers/media/tuners/xc4000.c
++++ b/drivers/media/tuners/xc4000.c
+@@ -93,7 +93,7 @@ struct xc4000_priv {
+       struct firmware_description *firm;
+       int     firm_size;
+       u32     if_khz;
+-      u32     freq_hz;
++      u32     freq_hz, freq_offset;
+       u32     bandwidth;
+       u8      video_standard;
+       u8      rf_mode;
+@@ -1157,14 +1157,14 @@ static int xc4000_set_params(struct dvb_
+       case SYS_ATSC:
+               dprintk(1, "%s() VSB modulation\n", __func__);
+               priv->rf_mode = XC_RF_MODE_AIR;
+-              priv->freq_hz = c->frequency - 1750000;
++              priv->freq_offset = 1750000;
+               priv->video_standard = XC4000_DTV6;
+               type = DTV6;
+               break;
+       case SYS_DVBC_ANNEX_B:
+               dprintk(1, "%s() QAM modulation\n", __func__);
+               priv->rf_mode = XC_RF_MODE_CABLE;
+-              priv->freq_hz = c->frequency - 1750000;
++              priv->freq_offset = 1750000;
+               priv->video_standard = XC4000_DTV6;
+               type = DTV6;
+               break;
+@@ -1173,23 +1173,23 @@ static int xc4000_set_params(struct dvb_
+               dprintk(1, "%s() OFDM\n", __func__);
+               if (bw == 0) {
+                       if (c->frequency < 400000000) {
+-                              priv->freq_hz = c->frequency - 2250000;
++                              priv->freq_offset = 2250000;
+                       } else {
+-                              priv->freq_hz = c->frequency - 2750000;
++                              priv->freq_offset = 2750000;
+                       }
+                       priv->video_standard = XC4000_DTV7_8;
+                       type = DTV78;
+               } else if (bw <= 6000000) {
+                       priv->video_standard = XC4000_DTV6;
+-                      priv->freq_hz = c->frequency - 1750000;
++                      priv->freq_offset = 1750000;
+                       type = DTV6;
+               } else if (bw <= 7000000) {
+                       priv->video_standard = XC4000_DTV7;
+-                      priv->freq_hz = c->frequency - 2250000;
++                      priv->freq_offset = 2250000;
+                       type = DTV7;
+               } else {
+                       priv->video_standard = XC4000_DTV8;
+-                      priv->freq_hz = c->frequency - 2750000;
++                      priv->freq_offset = 2750000;
+                       type = DTV8;
+               }
+               priv->rf_mode = XC_RF_MODE_AIR;
+@@ -1200,6 +1200,8 @@ static int xc4000_set_params(struct dvb_
+               goto fail;
+       }
++      priv->freq_hz = c->frequency - priv->freq_offset;
++
+       dprintk(1, "%s() frequency=%d (compensated)\n",
+               __func__, priv->freq_hz);
+@@ -1520,7 +1522,7 @@ static int xc4000_get_frequency(struct d
+ {
+       struct xc4000_priv *priv = fe->tuner_priv;
+-      *freq = priv->freq_hz;
++      *freq = priv->freq_hz + priv->freq_offset;
+       if (debug) {
+               mutex_lock(&priv->lock);
diff --git a/queue-3.16/media-xc5000-fix-get_frequency.patch b/queue-3.16/media-xc5000-fix-get_frequency.patch
new file mode 100644 (file)
index 0000000..7d35f36
--- /dev/null
@@ -0,0 +1,103 @@
+From a3eec916cbc17dc1aaa3ddf120836cd5200eb4ef Mon Sep 17 00:00:00 2001
+From: Mauro Carvalho Chehab <m.chehab@samsung.com>
+Date: Mon, 21 Jul 2014 14:21:18 -0300
+Subject: media: xc5000: Fix get_frequency()
+
+From: Mauro Carvalho Chehab <m.chehab@samsung.com>
+
+commit a3eec916cbc17dc1aaa3ddf120836cd5200eb4ef upstream.
+
+The programmed frequency on xc5000 is not the middle
+frequency, but the initial frequency on the bandwidth range.
+However, the DVB API works with the middle frequency.
+
+Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/media/tuners/xc5000.c |   22 ++++++++++++----------
+ 1 file changed, 12 insertions(+), 10 deletions(-)
+
+--- a/drivers/media/tuners/xc5000.c
++++ b/drivers/media/tuners/xc5000.c
+@@ -56,7 +56,7 @@ struct xc5000_priv {
+       u32 if_khz;
+       u16 xtal_khz;
+-      u32 freq_hz;
++      u32 freq_hz, freq_offset;
+       u32 bandwidth;
+       u8  video_standard;
+       u8  rf_mode;
+@@ -749,13 +749,13 @@ static int xc5000_set_params(struct dvb_
+       case SYS_ATSC:
+               dprintk(1, "%s() VSB modulation\n", __func__);
+               priv->rf_mode = XC_RF_MODE_AIR;
+-              priv->freq_hz = freq - 1750000;
++              priv->freq_offset = 1750000;
+               priv->video_standard = DTV6;
+               break;
+       case SYS_DVBC_ANNEX_B:
+               dprintk(1, "%s() QAM modulation\n", __func__);
+               priv->rf_mode = XC_RF_MODE_CABLE;
+-              priv->freq_hz = freq - 1750000;
++              priv->freq_offset = 1750000;
+               priv->video_standard = DTV6;
+               break;
+       case SYS_ISDBT:
+@@ -770,15 +770,15 @@ static int xc5000_set_params(struct dvb_
+               switch (bw) {
+               case 6000000:
+                       priv->video_standard = DTV6;
+-                      priv->freq_hz = freq - 1750000;
++                      priv->freq_offset = 1750000;
+                       break;
+               case 7000000:
+                       priv->video_standard = DTV7;
+-                      priv->freq_hz = freq - 2250000;
++                      priv->freq_offset = 2250000;
+                       break;
+               case 8000000:
+                       priv->video_standard = DTV8;
+-                      priv->freq_hz = freq - 2750000;
++                      priv->freq_offset = 2750000;
+                       break;
+               default:
+                       printk(KERN_ERR "xc5000 bandwidth not set!\n");
+@@ -792,15 +792,15 @@ static int xc5000_set_params(struct dvb_
+               priv->rf_mode = XC_RF_MODE_CABLE;
+               if (bw <= 6000000) {
+                       priv->video_standard = DTV6;
+-                      priv->freq_hz = freq - 1750000;
++                      priv->freq_offset = 1750000;
+                       b = 6;
+               } else if (bw <= 7000000) {
+                       priv->video_standard = DTV7;
+-                      priv->freq_hz = freq - 2250000;
++                      priv->freq_offset = 2250000;
+                       b = 7;
+               } else {
+                       priv->video_standard = DTV7_8;
+-                      priv->freq_hz = freq - 2750000;
++                      priv->freq_offset = 2750000;
+                       b = 8;
+               }
+               dprintk(1, "%s() Bandwidth %dMHz (%d)\n", __func__,
+@@ -811,6 +811,8 @@ static int xc5000_set_params(struct dvb_
+               return -EINVAL;
+       }
++      priv->freq_hz = freq - priv->freq_offset;
++
+       dprintk(1, "%s() frequency=%d (compensated to %d)\n",
+               __func__, freq, priv->freq_hz);
+@@ -1061,7 +1063,7 @@ static int xc5000_get_frequency(struct d
+ {
+       struct xc5000_priv *priv = fe->tuner_priv;
+       dprintk(1, "%s()\n", __func__);
+-      *freq = priv->freq_hz;
++      *freq = priv->freq_hz + priv->freq_offset;
+       return 0;
+ }
diff --git a/queue-3.16/reiserfs-fix-corruption-introduced-by-balance_leaf-refactor.patch b/queue-3.16/reiserfs-fix-corruption-introduced-by-balance_leaf-refactor.patch
new file mode 100644 (file)
index 0000000..38846f2
--- /dev/null
@@ -0,0 +1,382 @@
+From 27d0e5bc85f3341b9ba66f0c23627cf9d7538c9d Mon Sep 17 00:00:00 2001
+From: Jeff Mahoney <jeffm@suse.com>
+Date: Mon, 4 Aug 2014 19:51:47 -0400
+Subject: reiserfs: fix corruption introduced by balance_leaf refactor
+
+From: Jeff Mahoney <jeffm@suse.com>
+
+commit 27d0e5bc85f3341b9ba66f0c23627cf9d7538c9d upstream.
+
+Commits f1f007c308e (reiserfs: balance_leaf refactor, pull out
+balance_leaf_insert_left) and cf22df182bf (reiserfs: balance_leaf
+refactor, pull out balance_leaf_paste_left) missed that the `body'
+pointer was getting repositioned. Subsequent users of the pointer
+would expect it to be repositioned, and as a result, parts of the
+tree would get overwritten. The most common observed corruption
+is indirect block pointers being overwritten.
+
+Since the body value isn't actually used anymore in the called routines,
+we can pass back the offset it should be shifted. We constify the body
+and ih pointers in the balance_leaf as a mostly-free preventative measure.
+
+Reported-and-tested-by: Jeff Chua <jeff.chua.linux@gmail.com>
+Signed-off-by: Jeff Mahoney <jeffm@suse.com>
+Signed-off-by: Jan Kara <jack@suse.cz>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/reiserfs/do_balan.c |  111 +++++++++++++++++++++++++++----------------------
+ fs/reiserfs/lbalance.c |    5 +-
+ fs/reiserfs/reiserfs.h |    9 ++-
+ 3 files changed, 71 insertions(+), 54 deletions(-)
+
+--- a/fs/reiserfs/do_balan.c
++++ b/fs/reiserfs/do_balan.c
+@@ -286,12 +286,14 @@ static int balance_leaf_when_delete(stru
+       return 0;
+ }
+-static void balance_leaf_insert_left(struct tree_balance *tb,
+-                                   struct item_head *ih, const char *body)
++static unsigned int balance_leaf_insert_left(struct tree_balance *tb,
++                                           struct item_head *const ih,
++                                           const char * const body)
+ {
+       int ret;
+       struct buffer_info bi;
+       int n = B_NR_ITEMS(tb->L[0]);
++      unsigned body_shift_bytes = 0;
+       if (tb->item_pos == tb->lnum[0] - 1 && tb->lbytes != -1) {
+               /* part of new item falls into L[0] */
+@@ -329,7 +331,7 @@ static void balance_leaf_insert_left(str
+               put_ih_item_len(ih, new_item_len);
+               if (tb->lbytes > tb->zeroes_num) {
+-                      body += (tb->lbytes - tb->zeroes_num);
++                      body_shift_bytes = tb->lbytes - tb->zeroes_num;
+                       tb->zeroes_num = 0;
+               } else
+                       tb->zeroes_num -= tb->lbytes;
+@@ -349,11 +351,12 @@ static void balance_leaf_insert_left(str
+               tb->insert_size[0] = 0;
+               tb->zeroes_num = 0;
+       }
++      return body_shift_bytes;
+ }
+ static void balance_leaf_paste_left_shift_dirent(struct tree_balance *tb,
+-                                               struct item_head *ih,
+-                                               const char *body)
++                                               struct item_head * const ih,
++                                               const char * const body)
+ {
+       int n = B_NR_ITEMS(tb->L[0]);
+       struct buffer_info bi;
+@@ -413,17 +416,18 @@ static void balance_leaf_paste_left_shif
+       tb->pos_in_item -= tb->lbytes;
+ }
+-static void balance_leaf_paste_left_shift(struct tree_balance *tb,
+-                                        struct item_head *ih,
+-                                        const char *body)
++static unsigned int balance_leaf_paste_left_shift(struct tree_balance *tb,
++                                                struct item_head * const ih,
++                                                const char * const body)
+ {
+       struct buffer_head *tbS0 = PATH_PLAST_BUFFER(tb->tb_path);
+       int n = B_NR_ITEMS(tb->L[0]);
+       struct buffer_info bi;
++      int body_shift_bytes = 0;
+       if (is_direntry_le_ih(item_head(tbS0, tb->item_pos))) {
+               balance_leaf_paste_left_shift_dirent(tb, ih, body);
+-              return;
++              return 0;
+       }
+       RFALSE(tb->lbytes <= 0,
+@@ -497,7 +501,7 @@ static void balance_leaf_paste_left_shif
+                * insert_size[0]
+                */
+               if (l_n > tb->zeroes_num) {
+-                      body += (l_n - tb->zeroes_num);
++                      body_shift_bytes = l_n - tb->zeroes_num;
+                       tb->zeroes_num = 0;
+               } else
+                       tb->zeroes_num -= l_n;
+@@ -526,13 +530,14 @@ static void balance_leaf_paste_left_shif
+                */
+               leaf_shift_left(tb, tb->lnum[0], tb->lbytes);
+       }
++      return body_shift_bytes;
+ }
+ /* appended item will be in L[0] in whole */
+ static void balance_leaf_paste_left_whole(struct tree_balance *tb,
+-                                        struct item_head *ih,
+-                                        const char *body)
++                                        struct item_head * const ih,
++                                        const char * const body)
+ {
+       struct buffer_head *tbS0 = PATH_PLAST_BUFFER(tb->tb_path);
+       int n = B_NR_ITEMS(tb->L[0]);
+@@ -584,39 +589,44 @@ static void balance_leaf_paste_left_whol
+       tb->zeroes_num = 0;
+ }
+-static void balance_leaf_paste_left(struct tree_balance *tb,
+-                                  struct item_head *ih, const char *body)
++static unsigned int balance_leaf_paste_left(struct tree_balance *tb,
++                                          struct item_head * const ih,
++                                          const char * const body)
+ {
+       /* we must shift the part of the appended item */
+       if (tb->item_pos == tb->lnum[0] - 1 && tb->lbytes != -1)
+-              balance_leaf_paste_left_shift(tb, ih, body);
++              return balance_leaf_paste_left_shift(tb, ih, body);
+       else
+               balance_leaf_paste_left_whole(tb, ih, body);
++      return 0;
+ }
+ /* Shift lnum[0] items from S[0] to the left neighbor L[0] */
+-static void balance_leaf_left(struct tree_balance *tb, struct item_head *ih,
+-                            const char *body, int flag)
++static unsigned int balance_leaf_left(struct tree_balance *tb,
++                                    struct item_head * const ih,
++                                    const char * const body, int flag)
+ {
+       if (tb->lnum[0] <= 0)
+-              return;
++              return 0;
+       /* new item or it part falls to L[0], shift it too */
+       if (tb->item_pos < tb->lnum[0]) {
+               BUG_ON(flag != M_INSERT && flag != M_PASTE);
+               if (flag == M_INSERT)
+-                      balance_leaf_insert_left(tb, ih, body);
++                      return balance_leaf_insert_left(tb, ih, body);
+               else /* M_PASTE */
+-                      balance_leaf_paste_left(tb, ih, body);
++                      return balance_leaf_paste_left(tb, ih, body);
+       } else
+               /* new item doesn't fall into L[0] */
+               leaf_shift_left(tb, tb->lnum[0], tb->lbytes);
++      return 0;
+ }
+ static void balance_leaf_insert_right(struct tree_balance *tb,
+-                                    struct item_head *ih, const char *body)
++                                    struct item_head * const ih,
++                                    const char * const body)
+ {
+       struct buffer_head *tbS0 = PATH_PLAST_BUFFER(tb->tb_path);
+@@ -704,7 +714,8 @@ static void balance_leaf_insert_right(st
+ static void balance_leaf_paste_right_shift_dirent(struct tree_balance *tb,
+-                                   struct item_head *ih, const char *body)
++                                   struct item_head * const ih,
++                                   const char * const body)
+ {
+       struct buffer_head *tbS0 = PATH_PLAST_BUFFER(tb->tb_path);
+       struct buffer_info bi;
+@@ -754,7 +765,8 @@ static void balance_leaf_paste_right_shi
+ }
+ static void balance_leaf_paste_right_shift(struct tree_balance *tb,
+-                                   struct item_head *ih, const char *body)
++                                   struct item_head * const ih,
++                                   const char * const body)
+ {
+       struct buffer_head *tbS0 = PATH_PLAST_BUFFER(tb->tb_path);
+       int n_shift, n_rem, r_zeroes_number, version;
+@@ -831,7 +843,8 @@ static void balance_leaf_paste_right_shi
+ }
+ static void balance_leaf_paste_right_whole(struct tree_balance *tb,
+-                                   struct item_head *ih, const char *body)
++                                   struct item_head * const ih,
++                                   const char * const body)
+ {
+       struct buffer_head *tbS0 = PATH_PLAST_BUFFER(tb->tb_path);
+       int n = B_NR_ITEMS(tbS0);
+@@ -874,7 +887,8 @@ static void balance_leaf_paste_right_who
+ }
+ static void balance_leaf_paste_right(struct tree_balance *tb,
+-                                   struct item_head *ih, const char *body)
++                                   struct item_head * const ih,
++                                   const char * const body)
+ {
+       struct buffer_head *tbS0 = PATH_PLAST_BUFFER(tb->tb_path);
+       int n = B_NR_ITEMS(tbS0);
+@@ -896,8 +910,9 @@ static void balance_leaf_paste_right(str
+ }
+ /* shift rnum[0] items from S[0] to the right neighbor R[0] */
+-static void balance_leaf_right(struct tree_balance *tb, struct item_head *ih,
+-                             const char *body, int flag)
++static void balance_leaf_right(struct tree_balance *tb,
++                             struct item_head * const ih,
++                             const char * const body, int flag)
+ {
+       if (tb->rnum[0] <= 0)
+               return;
+@@ -911,8 +926,8 @@ static void balance_leaf_right(struct tr
+ }
+ static void balance_leaf_new_nodes_insert(struct tree_balance *tb,
+-                                        struct item_head *ih,
+-                                        const char *body,
++                                        struct item_head * const ih,
++                                        const char * const body,
+                                         struct item_head *insert_key,
+                                         struct buffer_head **insert_ptr,
+                                         int i)
+@@ -1003,8 +1018,8 @@ static void balance_leaf_new_nodes_inser
+ /* we append to directory item */
+ static void balance_leaf_new_nodes_paste_dirent(struct tree_balance *tb,
+-                                       struct item_head *ih,
+-                                       const char *body,
++                                       struct item_head * const ih,
++                                       const char * const body,
+                                        struct item_head *insert_key,
+                                        struct buffer_head **insert_ptr,
+                                        int i)
+@@ -1058,8 +1073,8 @@ static void balance_leaf_new_nodes_paste
+ }
+ static void balance_leaf_new_nodes_paste_shift(struct tree_balance *tb,
+-                                       struct item_head *ih,
+-                                       const char *body,
++                                       struct item_head * const ih,
++                                       const char * const body,
+                                        struct item_head *insert_key,
+                                        struct buffer_head **insert_ptr,
+                                        int i)
+@@ -1131,8 +1146,8 @@ static void balance_leaf_new_nodes_paste
+ }
+ static void balance_leaf_new_nodes_paste_whole(struct tree_balance *tb,
+-                                             struct item_head *ih,
+-                                             const char *body,
++                                             struct item_head * const ih,
++                                             const char * const body,
+                                              struct item_head *insert_key,
+                                              struct buffer_head **insert_ptr,
+                                              int i)
+@@ -1184,8 +1199,8 @@ static void balance_leaf_new_nodes_paste
+ }
+ static void balance_leaf_new_nodes_paste(struct tree_balance *tb,
+-                                       struct item_head *ih,
+-                                       const char *body,
++                                       struct item_head * const ih,
++                                       const char * const body,
+                                        struct item_head *insert_key,
+                                        struct buffer_head **insert_ptr,
+                                        int i)
+@@ -1214,8 +1229,8 @@ static void balance_leaf_new_nodes_paste
+ /* Fill new nodes that appear in place of S[0] */
+ static void balance_leaf_new_nodes(struct tree_balance *tb,
+-                                 struct item_head *ih,
+-                                 const char *body,
++                                 struct item_head * const ih,
++                                 const char * const body,
+                                  struct item_head *insert_key,
+                                  struct buffer_head **insert_ptr,
+                                  int flag)
+@@ -1254,8 +1269,8 @@ static void balance_leaf_new_nodes(struc
+ }
+ static void balance_leaf_finish_node_insert(struct tree_balance *tb,
+-                                          struct item_head *ih,
+-                                          const char *body)
++                                          struct item_head * const ih,
++                                          const char * const body)
+ {
+       struct buffer_head *tbS0 = PATH_PLAST_BUFFER(tb->tb_path);
+       struct buffer_info bi;
+@@ -1271,8 +1286,8 @@ static void balance_leaf_finish_node_ins
+ }
+ static void balance_leaf_finish_node_paste_dirent(struct tree_balance *tb,
+-                                                struct item_head *ih,
+-                                                const char *body)
++                                                struct item_head * const ih,
++                                                const char * const body)
+ {
+       struct buffer_head *tbS0 = PATH_PLAST_BUFFER(tb->tb_path);
+       struct item_head *pasted = item_head(tbS0, tb->item_pos);
+@@ -1305,8 +1320,8 @@ static void balance_leaf_finish_node_pas
+ }
+ static void balance_leaf_finish_node_paste(struct tree_balance *tb,
+-                                         struct item_head *ih,
+-                                         const char *body)
++                                         struct item_head * const ih,
++                                         const char * const body)
+ {
+       struct buffer_head *tbS0 = PATH_PLAST_BUFFER(tb->tb_path);
+       struct buffer_info bi;
+@@ -1349,8 +1364,8 @@ static void balance_leaf_finish_node_pas
+  * of the affected item which remains in S
+  */
+ static void balance_leaf_finish_node(struct tree_balance *tb,
+-                                    struct item_head *ih,
+-                                    const char *body, int flag)
++                                    struct item_head * const ih,
++                                    const char * const body, int flag)
+ {
+       /* if we must insert or append into buffer S[0] */
+       if (0 <= tb->item_pos && tb->item_pos < tb->s0num) {
+@@ -1402,7 +1417,7 @@ static int balance_leaf(struct tree_bala
+           && is_indirect_le_ih(item_head(tbS0, tb->item_pos)))
+               tb->pos_in_item *= UNFM_P_SIZE;
+-      balance_leaf_left(tb, ih, body, flag);
++      body += balance_leaf_left(tb, ih, body, flag);
+       /* tb->lnum[0] > 0 */
+       /* Calculate new item position */
+--- a/fs/reiserfs/lbalance.c
++++ b/fs/reiserfs/lbalance.c
+@@ -899,8 +899,9 @@ void leaf_delete_items(struct buffer_inf
+ /* insert item into the leaf node in position before */
+ void leaf_insert_into_buf(struct buffer_info *bi, int before,
+-                        struct item_head *inserted_item_ih,
+-                        const char *inserted_item_body, int zeros_number)
++                        struct item_head * const inserted_item_ih,
++                        const char * const inserted_item_body,
++                        int zeros_number)
+ {
+       struct buffer_head *bh = bi->bi_bh;
+       int nr, free_space;
+--- a/fs/reiserfs/reiserfs.h
++++ b/fs/reiserfs/reiserfs.h
+@@ -3216,11 +3216,12 @@ int leaf_shift_right(struct tree_balance
+ void leaf_delete_items(struct buffer_info *cur_bi, int last_first, int first,
+                      int del_num, int del_bytes);
+ void leaf_insert_into_buf(struct buffer_info *bi, int before,
+-                        struct item_head *inserted_item_ih,
+-                        const char *inserted_item_body, int zeros_number);
+-void leaf_paste_in_buffer(struct buffer_info *bi, int pasted_item_num,
+-                        int pos_in_item, int paste_size, const char *body,
++                        struct item_head * const inserted_item_ih,
++                        const char * const inserted_item_body,
+                         int zeros_number);
++void leaf_paste_in_buffer(struct buffer_info *bi, int pasted_item_num,
++                        int pos_in_item, int paste_size,
++                        const char * const body, int zeros_number);
+ void leaf_cut_from_buffer(struct buffer_info *bi, int cut_item_num,
+                         int pos_in_item, int cut_size);
+ void leaf_paste_entries(struct buffer_info *bi, int item_num, int before,
diff --git a/queue-3.16/reiserfs-fix-use-after-free-in-journal-teardown.patch b/queue-3.16/reiserfs-fix-use-after-free-in-journal-teardown.patch
new file mode 100644 (file)
index 0000000..0fe944b
--- /dev/null
@@ -0,0 +1,87 @@
+From 01777836c87081e4f68c4a43c9abe6114805f91e Mon Sep 17 00:00:00 2001
+From: Jan Kara <jack@suse.cz>
+Date: Wed, 6 Aug 2014 19:43:56 +0200
+Subject: reiserfs: Fix use after free in journal teardown
+
+From: Jan Kara <jack@suse.cz>
+
+commit 01777836c87081e4f68c4a43c9abe6114805f91e upstream.
+
+If do_journal_release() races with do_journal_end() which requeues
+delayed works for transaction flushing, we can leave work items for
+flushing outstanding transactions queued while freeing them. That
+results in use after free and possible crash in run_timers_softirq().
+
+Fix the problem by not requeueing works if superblock is being shut down
+(MS_ACTIVE not set) and using cancel_delayed_work_sync() in
+do_journal_release().
+
+Signed-off-by: Jan Kara <jack@suse.cz>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/reiserfs/journal.c |   22 ++++++++++++++++------
+ fs/reiserfs/super.c   |    6 +++++-
+ 2 files changed, 21 insertions(+), 7 deletions(-)
+
+--- a/fs/reiserfs/journal.c
++++ b/fs/reiserfs/journal.c
+@@ -1947,8 +1947,6 @@ static int do_journal_release(struct rei
+               }
+       }
+-      /* wait for all commits to finish */
+-      cancel_delayed_work(&SB_JOURNAL(sb)->j_work);
+       /*
+        * We must release the write lock here because
+@@ -1956,8 +1954,14 @@ static int do_journal_release(struct rei
+        */
+       reiserfs_write_unlock(sb);
++      /*
++       * Cancel flushing of old commits. Note that neither of these works
++       * will be requeued because superblock is being shutdown and doesn't
++       * have MS_ACTIVE set.
++       */
+       cancel_delayed_work_sync(&REISERFS_SB(sb)->old_work);
+-      flush_workqueue(REISERFS_SB(sb)->commit_wq);
++      /* wait for all commits to finish */
++      cancel_delayed_work_sync(&SB_JOURNAL(sb)->j_work);
+       free_journal_ram(sb);
+@@ -4292,9 +4296,15 @@ static int do_journal_end(struct reiserf
+       if (flush) {
+               flush_commit_list(sb, jl, 1);
+               flush_journal_list(sb, jl, 1);
+-      } else if (!(jl->j_state & LIST_COMMIT_PENDING))
+-              queue_delayed_work(REISERFS_SB(sb)->commit_wq,
+-                                 &journal->j_work, HZ / 10);
++      } else if (!(jl->j_state & LIST_COMMIT_PENDING)) {
++              /*
++               * Avoid queueing work when sb is being shut down. Transaction
++               * will be flushed on journal shutdown.
++               */
++              if (sb->s_flags & MS_ACTIVE)
++                      queue_delayed_work(REISERFS_SB(sb)->commit_wq,
++                                         &journal->j_work, HZ / 10);
++      }
+       /*
+        * if the next transaction has any chance of wrapping, flush
+--- a/fs/reiserfs/super.c
++++ b/fs/reiserfs/super.c
+@@ -100,7 +100,11 @@ void reiserfs_schedule_old_flush(struct
+       struct reiserfs_sb_info *sbi = REISERFS_SB(s);
+       unsigned long delay;
+-      if (s->s_flags & MS_RDONLY)
++      /*
++       * Avoid scheduling flush when sb is being shut down. It can race
++       * with journal shutdown and free still queued delayed work.
++       */
++      if (s->s_flags & MS_RDONLY || !(s->s_flags & MS_ACTIVE))
+               return;
+       spin_lock(&sbi->old_work_lock);