Skip to content

Commit

Permalink
[PATCH] dm: fix rh_dec()/rh_inc() race in dm-raid1.c
Browse files Browse the repository at this point in the history
Fix another bug in dm-raid1.c that the dirty region may stay in or be moved
to clean list and freed while in use.

It happens as follows:

   CPU0                                   CPU1
   ------------------------------------------------------------------------------
   rh_dec()
     if (atomic_dec_and_test(pending))
        <the region is still marked dirty>
                                          rh_inc()
                                            if the region is clean
                                               mark the region dirty
                                               and remove from clean list
        mark the region clean
        and move to clean list
                                                  atomic_inc(pending)

At this stage, the region is in clean list and will be mistakenly reclaimed
by rh_update_states() later.

Signed-off-by: Jun'ichi Nomura <j-nomura@ce.jp.nec.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
  • Loading branch information
Jun'ichi Nomura authored and Linus Torvalds committed Sep 9, 2005
1 parent e5dcdd8 commit 844e8d9
Showing 1 changed file with 9 additions and 3 deletions.
12 changes: 9 additions & 3 deletions drivers/md/dm-raid1.c
Original file line number Diff line number Diff line change
Expand Up @@ -375,16 +375,18 @@ static void rh_inc(struct region_hash *rh, region_t region)

read_lock(&rh->hash_lock);
reg = __rh_find(rh, region);

atomic_inc(&reg->pending);

spin_lock_irq(&rh->region_lock);
if (reg->state == RH_CLEAN) {
rh->log->type->mark_region(rh->log, reg->key);

spin_lock_irq(&rh->region_lock);
reg->state = RH_DIRTY;
list_del_init(&reg->list); /* take off the clean list */
spin_unlock_irq(&rh->region_lock);
}
spin_unlock_irq(&rh->region_lock);

atomic_inc(&reg->pending);
read_unlock(&rh->hash_lock);
}

Expand All @@ -408,6 +410,10 @@ static void rh_dec(struct region_hash *rh, region_t region)

if (atomic_dec_and_test(&reg->pending)) {
spin_lock_irqsave(&rh->region_lock, flags);
if (atomic_read(&reg->pending)) { /* check race */
spin_unlock_irqrestore(&rh->region_lock, flags);
return;
}
if (reg->state == RH_RECOVERING) {
list_add_tail(&reg->list, &rh->quiesced_regions);
} else {
Expand Down

0 comments on commit 844e8d9

Please sign in to comment.