Re: PROBLEM: kernel crashes on RAID1 drive error

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Lars,

On Nov 16, 2004, at 9:51 AM, Lars Marowsky-Bree wrote:

On 2004-11-04T12:56:01, Mark Rustad <mrustad@xxxxxxx> wrote:

I came up with a patch that seems to fix the kernel crashing on a RAID1
device failure problem. I do not have confidence that it really is the
correct fix, but I'm pretty sure that it is touching the right area.
I'm sure someone more familiar with this area of the kernel will
recognize from this what the correct fix is, if this is not it.
Submitted for your consideration:

Hi Mark, checking back whether any better fix has since been proposed?

My earlier attempt was clearly broken, though it did cure the kernel crashes. Below is the patch I am currently applying against ll_rw_blk.c in SuSE kernel 2.6.5-7.111. The last two hunks of the patch are relevant to this problem (the remainder of the patch should look familiar).


It looks to me like this problem was introduced in 2.6.2 by what was thought to be a simple rearrangement of code. I believe that that change did not take into account all of the ways that the loop could exit.

Unfortunately, the drive I had that would power up and work for 20 minutes and then return media errors has now totally died, so I am not currently able to convince myself that this fix is really right. I am continuing to try to reproduce a similar event.

My current patch is below:

--- a/drivers/block/ll_rw_blk.c 2004-11-15 08:35:19.000000000 -0600
+++ a/drivers/block/ll_rw_blk.c 2004-11-15 08:41:37.000000000 -0600
@@ -2654,19 +2654,40 @@

 void blk_recalc_rq_segments(struct request *rq)
 {
-       struct bio *bio;
+       struct bio *bio, *prevbio = NULL;
        int nr_phys_segs, nr_hw_segs;
+       unsigned int phys_size, hw_size;
+       request_queue_t *q = rq->q;

        if (!rq->bio)
                return;

-       nr_phys_segs = nr_hw_segs = 0;
+       phys_size = hw_size = nr_phys_segs = nr_hw_segs = 0;
        rq_for_each_bio(bio, rq) {
                /* Force bio hw/phys segs to be recalculated. */
                bio->bi_flags &= ~(1 << BIO_SEG_VALID);

- nr_phys_segs += bio_phys_segments(rq->q, bio);
- nr_hw_segs += bio_hw_segments(rq->q, bio);
+ nr_phys_segs += bio_phys_segments(q, bio);
+ nr_hw_segs += bio_hw_segments(q, bio);
+ if (prevbio) {
+ int pseg = phys_size + prevbio->bi_size + bio->bi_size;
+ int hseg = hw_size + prevbio->bi_size + bio->bi_size;
+
+ if (blk_phys_contig_segment(q, prevbio, bio) &&
+ pseg <= q->max_segment_size) {
+ nr_phys_segs--;
+ phys_size += prevbio->bi_size + bio->bi_size;
+ } else
+ phys_size = 0;
+
+ if (blk_hw_contig_segment(q, prevbio, bio) &&
+ hseg <= q->max_segment_size) {
+ nr_hw_segs--;
+ hw_size += prevbio->bi_size + bio->bi_size;
+ } else
+ hw_size = 0;
+ }
+ prevbio = bio;
}


rq->nr_phys_segments = nr_phys_segs;
@@ -2762,6 +2783,8 @@
* not a complete bvec done
*/
if (unlikely(nbytes > nr_bytes)) {
+ bio_iovec_idx(bio, idx)->bv_offset += nr_bytes;
+ bio_iovec_idx(bio, idx)->bv_len -= nr_bytes;
bio_nbytes += nr_bytes;
total_bytes += nr_bytes;
break;
@@ -2798,8 +2821,6 @@
if (bio_nbytes) {
bio_endio(bio, bio_nbytes, error);
bio->bi_idx += next_idx;
- bio_iovec(bio)->bv_offset += nr_bytes;
- bio_iovec(bio)->bv_len -= nr_bytes;
}


        blk_recalc_rq_sectors(req, total_bytes >> 9);

--
Mark Rustad, MRustad@xxxxxxx

-
To unsubscribe from this list: send the line "unsubscribe linux-raid" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux RAID Wiki]     [ATA RAID]     [Linux SCSI Target Infrastructure]     [Linux Block]     [Linux IDE]     [Linux SCSI]     [Linux Hams]     [Device Mapper]     [Device Mapper Cryptographics]     [Kernel]     [Linux Admin]     [Linux Net]     [GFS]     [RPM]     [git]     [Yosemite Forum]


  Powered by Linux