From: Greg Kroah-Hartman Date: Fri, 12 Sep 2014 21:46:16 +0000 (-0700) Subject: 3.16-stable patches X-Git-Tag: v3.10.55~44 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=78089f6ce3e5bcecbf383072ad2460ee81e3b608;p=thirdparty%2Fkernel%2Fstable-queue.git 3.16-stable patches 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 --- 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 index 00000000000..0ada51e4184 --- /dev/null +++ b/queue-3.16/media-au0828-only-alt-setting-logic-when-needed.patch @@ -0,0 +1,91 @@ +From 64ea37bbd8a5815522706f0099ad3f11c7537e15 Mon Sep 17 00:00:00 2001 +From: Mauro Carvalho Chehab +Date: Sun, 8 Jun 2014 13:54:57 -0300 +Subject: media: au0828: Only alt setting logic when needed + +From: Mauro Carvalho Chehab + +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 +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..48d45b6b915 --- /dev/null +++ b/queue-3.16/media-xc4000-fix-get_frequency.patch @@ -0,0 +1,105 @@ +From 4c07e32884ab69574cfd9eb4de3334233c938071 Mon Sep 17 00:00:00 2001 +From: Mauro Carvalho Chehab +Date: Mon, 21 Jul 2014 13:28:15 -0300 +Subject: media: xc4000: Fix get_frequency() + +From: Mauro Carvalho Chehab + +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 +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..7d35f36f99d --- /dev/null +++ b/queue-3.16/media-xc5000-fix-get_frequency.patch @@ -0,0 +1,103 @@ +From a3eec916cbc17dc1aaa3ddf120836cd5200eb4ef Mon Sep 17 00:00:00 2001 +From: Mauro Carvalho Chehab +Date: Mon, 21 Jul 2014 14:21:18 -0300 +Subject: media: xc5000: Fix get_frequency() + +From: Mauro Carvalho Chehab + +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 +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..38846f2140e --- /dev/null +++ b/queue-3.16/reiserfs-fix-corruption-introduced-by-balance_leaf-refactor.patch @@ -0,0 +1,382 @@ +From 27d0e5bc85f3341b9ba66f0c23627cf9d7538c9d Mon Sep 17 00:00:00 2001 +From: Jeff Mahoney +Date: Mon, 4 Aug 2014 19:51:47 -0400 +Subject: reiserfs: fix corruption introduced by balance_leaf refactor + +From: Jeff Mahoney + +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 +Signed-off-by: Jeff Mahoney +Signed-off-by: Jan Kara +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..0fe944b086e --- /dev/null +++ b/queue-3.16/reiserfs-fix-use-after-free-in-journal-teardown.patch @@ -0,0 +1,87 @@ +From 01777836c87081e4f68c4a43c9abe6114805f91e Mon Sep 17 00:00:00 2001 +From: Jan Kara +Date: Wed, 6 Aug 2014 19:43:56 +0200 +Subject: reiserfs: Fix use after free in journal teardown + +From: Jan Kara + +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 +Signed-off-by: Greg Kroah-Hartman + +--- + 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);