Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 72ac7330 authored by shli@kernel.org's avatar shli@kernel.org Committed by NeilBrown
Browse files

raid5: handle io error of batch list



If io error happens in any stripe of a batch list, the batch list will be
split, then normal process will run for the stripes in the list.

Signed-off-by: default avatarShaohua Li <shli@fusionio.com>
Signed-off-by: default avatarNeilBrown <neilb@suse.de>
parent 59fc630b
Loading
Loading
Loading
Loading
+48 −0
Original line number Original line Diff line number Diff line
@@ -1070,6 +1070,9 @@ again:
			pr_debug("skip op %ld on disc %d for sector %llu\n",
			pr_debug("skip op %ld on disc %d for sector %llu\n",
				bi->bi_rw, i, (unsigned long long)sh->sector);
				bi->bi_rw, i, (unsigned long long)sh->sector);
			clear_bit(R5_LOCKED, &sh->dev[i].flags);
			clear_bit(R5_LOCKED, &sh->dev[i].flags);
			if (sh->batch_head)
				set_bit(STRIPE_BATCH_ERR,
					&sh->batch_head->state);
			set_bit(STRIPE_HANDLE, &sh->state);
			set_bit(STRIPE_HANDLE, &sh->state);
		}
		}


@@ -2380,6 +2383,9 @@ static void raid5_end_write_request(struct bio *bi, int error)
	}
	}
	rdev_dec_pending(rdev, conf->mddev);
	rdev_dec_pending(rdev, conf->mddev);


	if (sh->batch_head && !uptodate)
		set_bit(STRIPE_BATCH_ERR, &sh->batch_head->state);

	if (!test_and_clear_bit(R5_DOUBLE_LOCKED, &sh->dev[i].flags))
	if (!test_and_clear_bit(R5_DOUBLE_LOCKED, &sh->dev[i].flags))
		clear_bit(R5_LOCKED, &sh->dev[i].flags);
		clear_bit(R5_LOCKED, &sh->dev[i].flags);
	set_bit(STRIPE_HANDLE, &sh->state);
	set_bit(STRIPE_HANDLE, &sh->state);
@@ -4124,6 +4130,46 @@ static int clear_batch_ready(struct stripe_head *sh)
	return 0;
	return 0;
}
}


static void check_break_stripe_batch_list(struct stripe_head *sh)
{
	struct stripe_head *head_sh, *next;
	int i;

	if (!test_and_clear_bit(STRIPE_BATCH_ERR, &sh->state))
		return;

	head_sh = sh;
	do {
		sh = list_first_entry(&sh->batch_list,
				      struct stripe_head, batch_list);
		BUG_ON(sh == head_sh);
	} while (!test_bit(STRIPE_DEGRADED, &sh->state));

	while (sh != head_sh) {
		next = list_first_entry(&sh->batch_list,
					struct stripe_head, batch_list);
		list_del_init(&sh->batch_list);

		sh->state = head_sh->state & ~((1 << STRIPE_ACTIVE) |
					       (1 << STRIPE_PREREAD_ACTIVE) |
					       (1 << STRIPE_DEGRADED));
		sh->check_state = head_sh->check_state;
		sh->reconstruct_state = head_sh->reconstruct_state;
		for (i = 0; i < sh->disks; i++)
			sh->dev[i].flags = head_sh->dev[i].flags &
				(~((1 << R5_WriteError) | (1 << R5_Overlap)));

		spin_lock_irq(&sh->stripe_lock);
		sh->batch_head = NULL;
		spin_unlock_irq(&sh->stripe_lock);

		set_bit(STRIPE_HANDLE, &sh->state);
		release_stripe(sh);

		sh = next;
	}
}

static void handle_stripe(struct stripe_head *sh)
static void handle_stripe(struct stripe_head *sh)
{
{
	struct stripe_head_state s;
	struct stripe_head_state s;
@@ -4146,6 +4192,8 @@ static void handle_stripe(struct stripe_head *sh)
		return;
		return;
	}
	}


	check_break_stripe_batch_list(sh);

	if (test_bit(STRIPE_SYNC_REQUESTED, &sh->state)) {
	if (test_bit(STRIPE_SYNC_REQUESTED, &sh->state)) {
		spin_lock(&sh->stripe_lock);
		spin_lock(&sh->stripe_lock);
		/* Cannot process 'sync' concurrently with 'discard' */
		/* Cannot process 'sync' concurrently with 'discard' */
+1 −0
Original line number Original line Diff line number Diff line
@@ -336,6 +336,7 @@ enum {
	STRIPE_DISCARD,
	STRIPE_DISCARD,
	STRIPE_ON_RELEASE_LIST,
	STRIPE_ON_RELEASE_LIST,
	STRIPE_BATCH_READY,
	STRIPE_BATCH_READY,
	STRIPE_BATCH_ERR,
};
};


/*
/*