diff options
author | Milan Broz <mbroz@redhat.com> | 2009-03-16 13:44:36 -0400 |
---|---|---|
committer | Alasdair G Kergon <agk@redhat.com> | 2009-03-16 13:44:36 -0400 |
commit | b35f8caa0890169000fec22902290d9a15274cbd (patch) | |
tree | a1a8ad3e5ba8b36da631d7125e0deb4ae743955a /drivers/md/dm-crypt.c | |
parent | b2174eebd1fadb76454dad09a1dacbc17081e6b0 (diff) |
dm crypt: wait for endio to complete before destruction
The following oops has been reported when dm-crypt runs over a loop device.
...
[ 70.381058] Process loop0 (pid: 4268, ti=cf3b2000 task=cf1cc1f0 task.ti=cf3b2000)
...
[ 70.381058] Call Trace:
[ 70.381058] [<d0d76601>] ? crypt_dec_pending+0x5e/0x62 [dm_crypt]
[ 70.381058] [<d0d767b8>] ? crypt_endio+0xa2/0xaa [dm_crypt]
[ 70.381058] [<d0d76716>] ? crypt_endio+0x0/0xaa [dm_crypt]
[ 70.381058] [<c01a2f24>] ? bio_endio+0x2b/0x2e
[ 70.381058] [<d0806530>] ? dec_pending+0x224/0x23b [dm_mod]
[ 70.381058] [<d08066e4>] ? clone_endio+0x79/0xa4 [dm_mod]
[ 70.381058] [<d080666b>] ? clone_endio+0x0/0xa4 [dm_mod]
[ 70.381058] [<c01a2f24>] ? bio_endio+0x2b/0x2e
[ 70.381058] [<c02bad86>] ? loop_thread+0x380/0x3b7
[ 70.381058] [<c02ba8a1>] ? do_lo_send_aops+0x0/0x165
[ 70.381058] [<c013754f>] ? autoremove_wake_function+0x0/0x33
[ 70.381058] [<c02baa06>] ? loop_thread+0x0/0x3b7
When a table is being replaced, it waits for I/O to complete
before destroying the mempool, but the endio function doesn't
call mempool_free() until after completing the bio.
Fix it by swapping the order of those two operations.
The same problem occurs in dm.c with md referenced after dec_pending.
Again, we swap the order.
Cc: stable@kernel.org
Signed-off-by: Milan Broz <mbroz@redhat.com>
Signed-off-by: Alasdair G Kergon <agk@redhat.com>
Diffstat (limited to 'drivers/md/dm-crypt.c')
-rw-r--r-- | drivers/md/dm-crypt.c | 17 |
1 files changed, 10 insertions, 7 deletions
diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c index ebab49f8cc1d..bfefd079a955 100644 --- a/drivers/md/dm-crypt.c +++ b/drivers/md/dm-crypt.c | |||
@@ -568,19 +568,22 @@ static void crypt_inc_pending(struct dm_crypt_io *io) | |||
568 | static void crypt_dec_pending(struct dm_crypt_io *io) | 568 | static void crypt_dec_pending(struct dm_crypt_io *io) |
569 | { | 569 | { |
570 | struct crypt_config *cc = io->target->private; | 570 | struct crypt_config *cc = io->target->private; |
571 | struct bio *base_bio = io->base_bio; | ||
572 | struct dm_crypt_io *base_io = io->base_io; | ||
573 | int error = io->error; | ||
571 | 574 | ||
572 | if (!atomic_dec_and_test(&io->pending)) | 575 | if (!atomic_dec_and_test(&io->pending)) |
573 | return; | 576 | return; |
574 | 577 | ||
575 | if (likely(!io->base_io)) | 578 | mempool_free(io, cc->io_pool); |
576 | bio_endio(io->base_bio, io->error); | 579 | |
580 | if (likely(!base_io)) | ||
581 | bio_endio(base_bio, error); | ||
577 | else { | 582 | else { |
578 | if (io->error && !io->base_io->error) | 583 | if (error && !base_io->error) |
579 | io->base_io->error = io->error; | 584 | base_io->error = error; |
580 | crypt_dec_pending(io->base_io); | 585 | crypt_dec_pending(base_io); |
581 | } | 586 | } |
582 | |||
583 | mempool_free(io, cc->io_pool); | ||
584 | } | 587 | } |
585 | 588 | ||
586 | /* | 589 | /* |