Linus,

 The following patch addresses a small number of bugs in raid1.c in
 2.4.0-test10.

 1/ A number of routines that are called from interrupt context used
     spin_lock_irq / spin_unlock_irq
   instead of the more appropriate
     spin_lock_irqsave( ,flags)   /  spin_unlock_irqrestore( ,flags)

   This can, and did, lead to deadlocks on an SMP system.

 2/ b_rsector and b_rdev are used in a couple of cases *after*
    generic_make_request has been called.  If the underlying devices
    was, for example, RAID0, these fields would no longer have the
    assumed values.  I have changed these cases to use b_blocknr
    (scales) and b_dev. 

    This bug could affect correctness if raid1 is used over raid0 or
    raid-linear or LVM.

 3/ In two cases, b_blocknr is calculated by *multiplying* b_rsector
    by the sector-per-block count instead of *dividing* it.

    This bug could affect correctness when restarted a read request
    after a drive failure.

NeilBrown

--- ./drivers/md/raid1.c        2000/11/07 02:14:25     1.1
+++ ./drivers/md/raid1.c        2000/11/07 02:15:21     1.2
@@ -91,7 +91,8 @@
 
 static inline void raid1_free_bh(raid1_conf_t *conf, struct buffer_head *bh)
 {
-       md_spin_lock_irq(&conf->device_lock);
+       unsigned long flags;
+       spin_lock_irqsave(&conf->device_lock, flags);
        while (bh) {
                struct buffer_head *t = bh;
                bh=bh->b_next;
@@ -103,7 +104,7 @@
                        conf->freebh_cnt++;
                }
        }
-       md_spin_unlock_irq(&conf->device_lock);
+       spin_unlock_irqrestore(&conf->device_lock, flags);
        wake_up(&conf->wait_buffer);
 }
 
@@ -182,10 +183,11 @@
        r1_bh->mirror_bh_list = NULL;
 
        if (test_bit(R1BH_PreAlloc, &r1_bh->state)) {
-               md_spin_lock_irq(&conf->device_lock);
+               unsigned long flags;
+               spin_lock_irqsave(&conf->device_lock, flags);
                r1_bh->next_r1 = conf->freer1;
                conf->freer1 = r1_bh;
-               md_spin_unlock_irq(&conf->device_lock);
+               spin_unlock_irqrestore(&conf->device_lock, flags);
        } else {
                kfree(r1_bh);
        }
@@ -229,14 +231,15 @@
 
 static inline void raid1_free_buf(struct raid1_bh *r1_bh)
 {
+       unsigned long flags;
        struct buffer_head *bh = r1_bh->mirror_bh_list;
        raid1_conf_t *conf = mddev_to_conf(r1_bh->mddev);
        r1_bh->mirror_bh_list = NULL;
        
-       md_spin_lock_irq(&conf->device_lock);
+       spin_lock_irqsave(&conf->device_lock, flags);
        r1_bh->next_r1 = conf->freebuf;
        conf->freebuf = r1_bh;
-       md_spin_unlock_irq(&conf->device_lock);
+       spin_unlock_irqrestore(&conf->device_lock, flags);
        raid1_free_bh(conf, bh);
 }
 
@@ -371,7 +374,7 @@
 {
        struct buffer_head *bh = r1_bh->master_bh;
 
-       io_request_done(bh->b_rsector, mddev_to_conf(r1_bh->mddev),
+       io_request_done(bh->b_blocknr*(bh->b_size>>9), mddev_to_conf(r1_bh->mddev),
                        test_bit(R1BH_SyncPhase, &r1_bh->state));
 
        bh->b_end_io(bh, uptodate);
@@ -599,7 +602,7 @@
 
                bh_req = &r1_bh->bh_req;
                memcpy(bh_req, bh, sizeof(*bh));
-               bh_req->b_blocknr = bh->b_rsector * sectors;
+               bh_req->b_blocknr = bh->b_rsector / sectors;
                bh_req->b_dev = mirror->dev;
                bh_req->b_rdev = mirror->dev;
        /*      bh_req->b_rsector = bh->n_rsector; */
@@ -643,7 +646,7 @@
        /*
         * prepare mirrored mbh (fields ordered for max mem throughput):
         */
-               mbh->b_blocknr    = bh->b_rsector * sectors;
+               mbh->b_blocknr    = bh->b_rsector / sectors;
                mbh->b_dev        = conf->mirrors[i].dev;
                mbh->b_rdev       = conf->mirrors[i].dev;
                mbh->b_rsector    = bh->b_rsector;
@@ -1181,7 +1184,7 @@
                                        struct buffer_head *bh1 = mbh;
                                        mbh = mbh->b_next;
                                        generic_make_request(WRITE, bh1);
-                                       md_sync_acct(bh1->b_rdev, bh1->b_size/512);
+                                       md_sync_acct(bh1->b_dev, bh1->b_size/512);
                                }
                        } else {
                                dev = bh->b_dev;
@@ -1406,7 +1409,7 @@
        init_waitqueue_head(&bh->b_wait);
 
        generic_make_request(READ, bh);
-       md_sync_acct(bh->b_rdev, bh->b_size/512);
+       md_sync_acct(bh->b_dev, bh->b_size/512);
 
        return (bsize >> 10);
 
-
To unsubscribe from this list: send the line "unsubscribe linux-raid" in
the body of a message to [EMAIL PROTECTED]

Reply via email to