linux/drivers/block
Ilya Dryomov ba00942e3b rbd: fix copyup completion race
[ Upstream commit 2761713d35 ]

For write/discard obj_requests that involved a copyup method call, the
opcode of the first op is CEPH_OSD_OP_CALL and the ->callback is
rbd_img_obj_copyup_callback().  The latter frees copyup pages, sets
->xferred and delegates to rbd_img_obj_callback(), the "normal" image
object callback, for reporting to block layer and putting refs.

rbd_osd_req_callback() however treats CEPH_OSD_OP_CALL as a trivial op,
which means obj_request is marked done in rbd_osd_trivial_callback(),
*before* ->callback is invoked and rbd_img_obj_copyup_callback() has
a chance to run.  Marking obj_request done essentially means giving
rbd_img_obj_callback() a license to end it at any moment, so if another
obj_request from the same img_request is being completed concurrently,
rbd_img_obj_end_request() may very well be called on such prematurally
marked done request:

<obj_request-1/2 reply>
handle_reply()
  rbd_osd_req_callback()
    rbd_osd_trivial_callback()
    rbd_obj_request_complete()
    rbd_img_obj_copyup_callback()
    rbd_img_obj_callback()
                                    <obj_request-2/2 reply>
                                    handle_reply()
                                      rbd_osd_req_callback()
                                        rbd_osd_trivial_callback()
      for_each_obj_request(obj_request->img_request) {
        rbd_img_obj_end_request(obj_request-1/2)
        rbd_img_obj_end_request(obj_request-2/2) <--
      }

Calling rbd_img_obj_end_request() on such a request leads to trouble,
in particular because its ->xfferred is 0.  We report 0 to the block
layer with blk_update_request(), get back 1 for "this request has more
data in flight" and then trip on

    rbd_assert(more ^ (which == img_request->obj_request_count));

with rhs (which == ...) being 1 because rbd_img_obj_end_request() has
been called for both requests and lhs (more) being 1 because we haven't
got a chance to set ->xfferred in rbd_img_obj_copyup_callback() yet.

To fix this, leverage that rbd wants to call class methods in only two
cases: one is a generic method call wrapper (obj_request is standalone)
and the other is a copyup (obj_request is part of an img_request).  So
make a dedicated handler for CEPH_OSD_OP_CALL and directly invoke
rbd_img_obj_copyup_callback() from it if obj_request is part of an
img_request, similar to how CEPH_OSD_OP_READ handler invokes
rbd_img_obj_request_read_callback().

Since rbd_img_obj_copyup_callback() is now being called from the OSD
request callback (only), it is renamed to rbd_osd_copyup_callback().

Cc: Alex Elder <elder@linaro.org>
Cc: stable@vger.kernel.org # 3.10+, needs backporting for < 3.18
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
Reviewed-by: Alex Elder <elder@linaro.org>
Signed-off-by: Sasha Levin <sasha.levin@oracle.com>
History 2015-08-27 13:25:27 -04:00
..
aoe mm: close PageTail race 2014-03-04 07:55:47 -08:00
drbd drbd: Fix state change in case of connection timeout 2015-01-16 06:59:52 -08:00
mtip32xx Merge branch 'for-3.18/drivers' of git://git.kernel.dk/linux-block 2014-10-18 12:12:45 -07:00
paride Merge branch 'for-3.18/core' of git://git.kernel.dk/linux-block 2014-10-18 11:53:51 -07:00
rsxx Merge branch 'for-3.18/drivers' of git://git.kernel.dk/linux-block 2014-10-18 12:12:45 -07:00
xen-blkback Merge branch 'for-3.18/drivers' of git://git.kernel.dk/linux-block 2014-10-18 12:12:45 -07:00
zram zram: avoid kunmap_atomic() of a NULL pointer 2014-11-13 16:17:05 -08:00
amiflop.c block: remove struct request buffer member 2014-04-15 14:03:02 -06:00
ataflop.c Merge branch 'for-3.16/core' of git://git.kernel.dk/linux-block into next 2014-06-02 09:29:34 -07:00
brd.c brd: add ram disk visibility option 2014-08-21 20:42:01 -05:00
cciss.c block: use pci_zalloc_consistent 2014-08-08 15:57:28 -07:00
cciss.h cciss: Adds simple mode functionality 2011-08-08 11:40:15 +02:00
cciss_cmd.h cciss: use new doorbell-bit-5 reset method 2011-05-06 08:23:55 -06:00
cciss_scsi.c cciss: switch to ->show_info() 2013-04-09 14:13:19 -04:00
cciss_scsi.h cciss: add cciss_tape_cmds module paramter 2011-05-06 08:23:59 -06:00
cpqarray.c cpqarray: fix info leak in ida_locked_ioctl() 2013-09-24 17:00:26 -07:00
cpqarray.h Linux-2.6.12-rc2 2005-04-16 15:20:36 -07:00
cryptoloop.c move linux/loop.h to drivers/block 2013-06-29 12:46:45 +04:00
DAC960.c block: use pci_zalloc_consistent 2014-08-08 15:57:28 -07:00
DAC960.h Fix DAC960 driver on machines which don't support 64-bit DMA 2007-09-11 17:21:19 -07:00
floppy.c Merge branch 'for-jens' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/linux-block into for-linus 2014-06-18 10:30:22 -07:00
hd.c block: hd: remove deprecated IRQF_DISABLED 2014-10-01 08:16:07 -06:00
ida_cmd.h Linux-2.6.12-rc2 2005-04-16 15:20:36 -07:00
ida_ioctl.h Linux-2.6.12-rc2 2005-04-16 15:20:36 -07:00
Kconfig zram: promote zram from staging 2014-01-30 16:56:55 -08:00
loop.c Merge branch 'sched/urgent' into sched/core, to avoid conflicts 2014-05-07 13:15:46 +02:00
loop.h move linux/loop.h to drivers/block 2013-06-29 12:46:45 +04:00
Makefile zram: promote zram from staging 2014-01-30 16:56:55 -08:00
mg_disk.c block: remove struct request buffer member 2014-04-15 14:03:02 -06:00
nbd.c nbd: fix possible memory leak 2015-04-23 14:58:28 -04:00
null_blk.c null_blk: Cleanup error recovery in null_add_dev() 2014-10-22 07:59:25 -06:00
nvme-core.c block: disable entropy contributions for nonrot devices 2014-10-04 10:55:32 -06:00
nvme-scsi.c NVMe: Fix START_STOP_UNIT Scsi->NVMe translation. 2014-06-13 13:11:00 -04:00
osdblk.c block: replace strict_strtoul() with kstrtoul() 2013-09-11 15:56:56 -07:00
pktcdvd.c block,scsi: fixup blk_get_request dead queue scenarios 2014-08-28 10:03:46 -06:00
ps3disk.c block: Kill bio_segments()/bi_vcnt usage 2013-11-23 22:33:51 -08:00
ps3vram.c block: Convert bio_for_each_segment() to bvec_iter 2013-11-23 22:33:49 -08:00
rbd.c rbd: fix copyup completion race 2015-08-27 13:25:27 -04:00
rbd_types.h rbd: get rid of RBD_MAX_SEG_NAME_LEN 2012-12-17 08:37:29 -06:00
skd_main.c block: disable entropy contributions for nonrot devices 2014-10-04 10:55:32 -06:00
skd_s1120.h skd: fix formatting in skd_s1120.h 2013-11-08 09:10:30 -07:00
smart1,2.h fix typos 'comamnd' -> 'command' in comments 2011-02-02 11:31:21 +01:00
sunvdc.c sunvdc: don't call VD_OP_GET_VTOC 2014-10-31 15:49:45 -04:00
swim.c block: remove struct request buffer member 2014-04-15 14:03:02 -06:00
swim3.c block: remove struct request buffer member 2014-04-15 14:03:02 -06:00
swim_asm.S m68k: mac - Add SWIM floppy support 2009-03-26 21:15:27 +01:00
sx8.c block,scsi: fixup blk_get_request dead queue scenarios 2014-08-28 10:03:46 -06:00
umem.c block: Convert drivers to immutable biovecs 2013-11-23 22:33:51 -08:00
umem.h drivers/block/umem: trim trailing whitespace 2007-10-10 09:25:59 +02:00
virtio_blk.c Merge branch 'for-3.18/core' of git://git.kernel.dk/linux-block 2014-10-18 11:53:51 -07:00
xen-blkfront.c Merge branch 'for-3.18/drivers' of git://git.kernel.dk/linux-block 2014-10-18 12:12:45 -07:00
xsysace.c block: systemace: Remove .owner field for driver 2014-08-21 20:37:54 -05:00
z2ram.c block: remove struct request buffer member 2014-04-15 14:03:02 -06:00