From 1a306361bc545e63e6960a8e25af7c0532448b6c Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 5 Mar 2014 10:53:41 -0800 Subject: [PATCH] 3.4-stable patches added patches: block-don-t-access-request-after-it-might-be-freed.patch ext4-return-enomem-if-sb_getblk-fails.patch nbd-correct-disconnect-behavior.patch --- ...cess-request-after-it-might-be-freed.patch | 60 +++++ ...xt4-return-enomem-if-sb_getblk-fails.patch | 251 ++++++++++++++++++ .../nbd-correct-disconnect-behavior.patch | 76 ++++++ queue-3.4/series | 3 + 4 files changed, 390 insertions(+) create mode 100644 queue-3.4/block-don-t-access-request-after-it-might-be-freed.patch create mode 100644 queue-3.4/ext4-return-enomem-if-sb_getblk-fails.patch create mode 100644 queue-3.4/nbd-correct-disconnect-behavior.patch diff --git a/queue-3.4/block-don-t-access-request-after-it-might-be-freed.patch b/queue-3.4/block-don-t-access-request-after-it-might-be-freed.patch new file mode 100644 index 00000000000..24ac48d39b6 --- /dev/null +++ b/queue-3.4/block-don-t-access-request-after-it-might-be-freed.patch @@ -0,0 +1,60 @@ +From 893d290f1d7496db97c9471bc352ad4a11dc8a25 Mon Sep 17 00:00:00 2001 +From: Roland Dreier +Date: Thu, 22 Nov 2012 02:00:11 -0800 +Subject: block: Don't access request after it might be freed + +From: Roland Dreier + +commit 893d290f1d7496db97c9471bc352ad4a11dc8a25 upstream. + +After we've done __elv_add_request() and __blk_run_queue() in +blk_execute_rq_nowait(), the request might finish and be freed +immediately. Therefore checking if the type is REQ_TYPE_PM_RESUME +isn't safe afterwards, because if it isn't, rq might be gone. +Instead, check beforehand and stash the result in a temporary. + +This fixes crashes in blk_execute_rq_nowait() I get occasionally when +running with lots of memory debugging options enabled -- I think this +race is usually harmless because the window for rq to be reallocated +is so small. + +Signed-off-by: Roland Dreier +Signed-off-by: Jens Axboe +[xr: Backported to 3.4: adjust context] +Signed-off-by: Rui Xiang +Signed-off-by: Greg Kroah-Hartman + +--- + block/blk-exec.c | 12 +++++++++++- + 1 file changed, 11 insertions(+), 1 deletion(-) + +--- a/block/blk-exec.c ++++ b/block/blk-exec.c +@@ -49,8 +49,18 @@ void blk_execute_rq_nowait(struct reques + rq_end_io_fn *done) + { + int where = at_head ? ELEVATOR_INSERT_FRONT : ELEVATOR_INSERT_BACK; ++ bool is_pm_resume; + + WARN_ON(irqs_disabled()); ++ ++ rq->rq_disk = bd_disk; ++ rq->end_io = done; ++ /* ++ * need to check this before __blk_run_queue(), because rq can ++ * be freed before that returns. ++ */ ++ is_pm_resume = rq->cmd_type == REQ_TYPE_PM_RESUME; ++ + spin_lock_irq(q->queue_lock); + + if (unlikely(blk_queue_dead(q))) { +@@ -66,7 +76,7 @@ void blk_execute_rq_nowait(struct reques + __elv_add_request(q, rq, where); + __blk_run_queue(q); + /* the queue is stopped so it won't be run */ +- if (rq->cmd_type == REQ_TYPE_PM_RESUME) ++ if (is_pm_resume) + q->request_fn(q); + spin_unlock_irq(q->queue_lock); + } diff --git a/queue-3.4/ext4-return-enomem-if-sb_getblk-fails.patch b/queue-3.4/ext4-return-enomem-if-sb_getblk-fails.patch new file mode 100644 index 00000000000..7893debc081 --- /dev/null +++ b/queue-3.4/ext4-return-enomem-if-sb_getblk-fails.patch @@ -0,0 +1,251 @@ +From 860d21e2c585f7ee8a4ecc06f474fdc33c9474f4 Mon Sep 17 00:00:00 2001 +From: Theodore Ts'o +Date: Sat, 12 Jan 2013 16:19:36 -0500 +Subject: ext4: return ENOMEM if sb_getblk() fails + +From: Theodore Ts'o + +commit 860d21e2c585f7ee8a4ecc06f474fdc33c9474f4 upstream. + +The only reason for sb_getblk() failing is if it can't allocate the +buffer_head. So ENOMEM is more appropriate than EIO. In addition, +make sure that the file system is marked as being inconsistent if +sb_getblk() fails. + +Signed-off-by: "Theodore Ts'o" +[xr: Backported to 3.4: + - Drop change to inline.c + - Call to ext4_ext_check() from ext4_ext_find_extent() is conditional] +Signed-off-by: Rui Xiang +Signed-off-by: Greg Kroah-Hartman + +--- + fs/ext4/extents.c | 25 ++++++++++++++----------- + fs/ext4/indirect.c | 9 ++++++--- + fs/ext4/inode.c | 9 +++------ + fs/ext4/mmp.c | 2 ++ + fs/ext4/resize.c | 8 ++++---- + fs/ext4/xattr.c | 3 ++- + 6 files changed, 31 insertions(+), 25 deletions(-) + +--- a/fs/ext4/extents.c ++++ b/fs/ext4/extents.c +@@ -670,6 +670,7 @@ ext4_ext_find_extent(struct inode *inode + struct ext4_extent_header *eh; + struct buffer_head *bh; + short int depth, i, ppos = 0, alloc = 0; ++ int ret; + + eh = ext_inode_hdr(inode); + depth = ext_depth(inode); +@@ -699,12 +700,15 @@ ext4_ext_find_extent(struct inode *inode + path[ppos].p_ext = NULL; + + bh = sb_getblk(inode->i_sb, path[ppos].p_block); +- if (unlikely(!bh)) ++ if (unlikely(!bh)) { ++ ret = -ENOMEM; + goto err; ++ } + if (!bh_uptodate_or_lock(bh)) { + trace_ext4_ext_load_extent(inode, block, + path[ppos].p_block); +- if (bh_submit_read(bh) < 0) { ++ ret = bh_submit_read(bh); ++ if (ret < 0) { + put_bh(bh); + goto err; + } +@@ -717,13 +721,15 @@ ext4_ext_find_extent(struct inode *inode + put_bh(bh); + EXT4_ERROR_INODE(inode, + "ppos %d > depth %d", ppos, depth); ++ ret = -EIO; + goto err; + } + path[ppos].p_bh = bh; + path[ppos].p_hdr = eh; + i--; + +- if (need_to_validate && ext4_ext_check(inode, eh, i)) ++ ret = need_to_validate ? ext4_ext_check(inode, eh, i) : 0; ++ if (ret < 0) + goto err; + } + +@@ -745,7 +751,7 @@ err: + ext4_ext_drop_refs(path); + if (alloc) + kfree(path); +- return ERR_PTR(-EIO); ++ return ERR_PTR(ret); + } + + /* +@@ -900,7 +906,7 @@ static int ext4_ext_split(handle_t *hand + } + bh = sb_getblk(inode->i_sb, newblock); + if (!bh) { +- err = -EIO; ++ err = -ENOMEM; + goto cleanup; + } + lock_buffer(bh); +@@ -972,7 +978,7 @@ static int ext4_ext_split(handle_t *hand + newblock = ablocks[--a]; + bh = sb_getblk(inode->i_sb, newblock); + if (!bh) { +- err = -EIO; ++ err = -ENOMEM; + goto cleanup; + } + lock_buffer(bh); +@@ -1083,11 +1089,8 @@ static int ext4_ext_grow_indepth(handle_ + return err; + + bh = sb_getblk(inode->i_sb, newblock); +- if (!bh) { +- err = -EIO; +- ext4_std_error(inode->i_sb, err); +- return err; +- } ++ if (!bh) ++ return -ENOMEM; + lock_buffer(bh); + + err = ext4_journal_get_create_access(handle, bh); +--- a/fs/ext4/indirect.c ++++ b/fs/ext4/indirect.c +@@ -145,6 +145,7 @@ static Indirect *ext4_get_branch(struct + struct super_block *sb = inode->i_sb; + Indirect *p = chain; + struct buffer_head *bh; ++ int ret = -EIO; + + *err = 0; + /* i_data is not going away, no lock needed */ +@@ -153,8 +154,10 @@ static Indirect *ext4_get_branch(struct + goto no_block; + while (--depth) { + bh = sb_getblk(sb, le32_to_cpu(p->key)); +- if (unlikely(!bh)) ++ if (unlikely(!bh)) { ++ ret = -ENOMEM; + goto failure; ++ } + + if (!bh_uptodate_or_lock(bh)) { + if (bh_submit_read(bh) < 0) { +@@ -176,7 +179,7 @@ static Indirect *ext4_get_branch(struct + return NULL; + + failure: +- *err = -EIO; ++ *err = ret; + no_block: + return p; + } +@@ -470,7 +473,7 @@ static int ext4_alloc_branch(handle_t *h + */ + bh = sb_getblk(inode->i_sb, new_blocks[n-1]); + if (unlikely(!bh)) { +- err = -EIO; ++ err = -ENOMEM; + goto failed; + } + +--- a/fs/ext4/inode.c ++++ b/fs/ext4/inode.c +@@ -663,7 +663,7 @@ struct buffer_head *ext4_getblk(handle_t + + bh = sb_getblk(inode->i_sb, map.m_pblk); + if (!bh) { +- *errp = -EIO; ++ *errp = -ENOMEM; + return NULL; + } + if (map.m_flags & EXT4_MAP_NEW) { +@@ -3461,11 +3461,8 @@ static int __ext4_get_inode_loc(struct i + iloc->offset = (inode_offset % inodes_per_block) * EXT4_INODE_SIZE(sb); + + bh = sb_getblk(sb, block); +- if (!bh) { +- EXT4_ERROR_INODE_BLOCK(inode, block, +- "unable to read itable block"); +- return -EIO; +- } ++ if (!bh) ++ return -ENOMEM; + if (!buffer_uptodate(bh)) { + lock_buffer(bh); + +--- a/fs/ext4/mmp.c ++++ b/fs/ext4/mmp.c +@@ -41,6 +41,8 @@ static int read_mmp_block(struct super_b + * is not blocked in the elevator. */ + if (!*bh) + *bh = sb_getblk(sb, mmp_block); ++ if (!*bh) ++ return -ENOMEM; + if (*bh) { + get_bh(*bh); + lock_buffer(*bh); +--- a/fs/ext4/resize.c ++++ b/fs/ext4/resize.c +@@ -315,7 +315,7 @@ static struct buffer_head *bclean(handle + + bh = sb_getblk(sb, blk); + if (!bh) +- return ERR_PTR(-EIO); ++ return ERR_PTR(-ENOMEM); + if ((err = ext4_journal_get_write_access(handle, bh))) { + brelse(bh); + bh = ERR_PTR(err); +@@ -392,7 +392,7 @@ static int set_flexbg_block_bitmap(struc + + bh = sb_getblk(sb, flex_gd->groups[group].block_bitmap); + if (!bh) +- return -EIO; ++ return -ENOMEM; + + err = ext4_journal_get_write_access(handle, bh); + if (err) +@@ -470,7 +470,7 @@ static int setup_new_flex_group_blocks(s + + gdb = sb_getblk(sb, block); + if (!gdb) { +- err = -EIO; ++ err = -ENOMEM; + goto out; + } + +@@ -991,7 +991,7 @@ static void update_backups(struct super_ + + bh = sb_getblk(sb, group * bpg + blk_off); + if (!bh) { +- err = -EIO; ++ err = -ENOMEM; + break; + } + ext4_debug("update metadata backup %#04lx\n", +--- a/fs/ext4/xattr.c ++++ b/fs/ext4/xattr.c +@@ -840,16 +840,17 @@ inserted: + + new_bh = sb_getblk(sb, block); + if (!new_bh) { ++ error = -ENOMEM; + getblk_failed: + ext4_free_blocks(handle, inode, NULL, block, 1, + EXT4_FREE_BLOCKS_METADATA); +- error = -EIO; + goto cleanup; + } + lock_buffer(new_bh); + error = ext4_journal_get_create_access(handle, new_bh); + if (error) { + unlock_buffer(new_bh); ++ error = -EIO; + goto getblk_failed; + } + memcpy(new_bh->b_data, s->base, new_bh->b_size); diff --git a/queue-3.4/nbd-correct-disconnect-behavior.patch b/queue-3.4/nbd-correct-disconnect-behavior.patch new file mode 100644 index 00000000000..f8edc4c25e5 --- /dev/null +++ b/queue-3.4/nbd-correct-disconnect-behavior.patch @@ -0,0 +1,76 @@ +From c378f70adbc1bbecd9e6db145019f14b2f688c7c Mon Sep 17 00:00:00 2001 +From: Paul Clements +Date: Wed, 3 Jul 2013 15:09:04 -0700 +Subject: nbd: correct disconnect behavior + +From: Paul Clements + +commit c378f70adbc1bbecd9e6db145019f14b2f688c7c upstream. + +Currently, when a disconnect is requested by the user (via NBD_DISCONNECT +ioctl) the return from NBD_DO_IT is undefined (it is usually one of +several error codes). This means that nbd-client does not know if a +manual disconnect was performed or whether a network error occurred. +Because of this, nbd-client's persist mode (which tries to reconnect after +error, but not after manual disconnect) does not always work correctly. + +This change fixes this by causing NBD_DO_IT to always return 0 if a user +requests a disconnect. This means that nbd-client can correctly either +persist the connection (if an error occurred) or disconnect (if the user +requested it). + +Signed-off-by: Paul Clements +Acked-by: Rob Landley +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +[xr: Backported to 3.4: adjust context] +Signed-off-by: Rui Xiang +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/block/nbd.c | 8 +++++++- + include/linux/nbd.h | 1 + + 2 files changed, 8 insertions(+), 1 deletion(-) + +--- a/drivers/block/nbd.c ++++ b/drivers/block/nbd.c +@@ -590,8 +590,11 @@ static int __nbd_ioctl(struct block_devi + nbd_cmd(&sreq) = NBD_CMD_DISC; + if (!nbd->sock) + return -EINVAL; ++ ++ nbd->disconnect = 1; ++ + nbd_send_req(nbd, &sreq); +- return 0; ++ return 0; + } + + case NBD_CLEAR_SOCK: { +@@ -620,6 +623,7 @@ static int __nbd_ioctl(struct block_devi + nbd->sock = SOCKET_I(inode); + if (max_part > 0) + bdev->bd_invalidated = 1; ++ nbd->disconnect = 0; /* we're connected now */ + return 0; + } else { + fput(file); +@@ -691,6 +695,8 @@ static int __nbd_ioctl(struct block_devi + set_capacity(nbd->disk, 0); + if (max_part > 0) + ioctl_by_bdev(bdev, BLKRRPART, 0); ++ if (nbd->disconnect) /* user requested, ignore socket errors */ ++ return 0; + return nbd->harderror; + } + +--- a/include/linux/nbd.h ++++ b/include/linux/nbd.h +@@ -68,6 +68,7 @@ struct nbd_device { + u64 bytesize; + pid_t pid; /* pid of nbd-client, if attached */ + int xmit_timeout; ++ int disconnect; /* a disconnect has been requested by user */ + }; + + #endif diff --git a/queue-3.4/series b/queue-3.4/series index 261f2f05c2e..c7c7e70cc94 100644 --- a/queue-3.4/series +++ b/queue-3.4/series @@ -61,3 +61,6 @@ ext4-jbd2-don-t-wait-forever-for-stale-tid-caused-by-wraparound.patch ubifs-fix-double-free-of-ubifs_orphan-objects.patch ext4-fix-possible-use-after-free-with-aio.patch cifs-adjust-sequence-number-downward-after-signing-nt_cancel-request.patch +nbd-correct-disconnect-behavior.patch +block-don-t-access-request-after-it-might-be-freed.patch +ext4-return-enomem-if-sb_getblk-fails.patch -- 2.47.3