--- linux-2.4.18-orig/drivers/md/md.c Mon Nov 18 14:13:29 2002 +++ linux-2.4.18/drivers/md/md.c Tue Dec 17 11:14:59 2002 @@ -506,20 +506,21 @@ if (rdev->sb) MD_BUG(); - rdev->sb = (mdp_super_t *) __get_free_page(GFP_KERNEL); - if (!rdev->sb) { - EPRINTK(OUT_OF_MEM); + rdev->sb_page = alloc_page(GFP_KERNEL); + if (!rdev->sb_page) { + printk(OUT_OF_MEM); return -EINVAL; } - md_clear_page(rdev->sb); + rdev->sb = (mdp_super_t *) page_address(rdev->sb_page); return 0; } static void free_disk_sb(mdk_rdev_t * rdev) { - if (rdev->sb) { - free_page((unsigned long) rdev->sb); + if (rdev->sb_page) { + page_cache_release(rdev->sb_page); + rdev->sb_page = NULL; rdev->sb = NULL; rdev->sb_offset = 0; rdev->size = 0; @@ -529,12 +530,42 @@ } } +static void bh_complete(struct buffer_head *bh, int uptodate) +{ + + if (uptodate) + set_bit(BH_Uptodate, &bh->b_state); + + complete((struct completion*)bh->b_private); +} + +static int sync_page_io(kdev_t dev, unsigned long sector, int size, + struct page *page, int rw) +{ + struct buffer_head bh; + struct completion event; + + init_completion(&event); + init_buffer(&bh, bh_complete, &event); + bh.b_rdev = dev; + bh.b_rsector = sector; + bh.b_state = (1 << BH_Req) | (1 << BH_Mapped); + bh.b_size = size; + bh.b_page = page; + bh.b_reqnext = NULL; + bh.b_data = page_address(page); + generic_make_request(rw, &bh); + + run_task_queue(&tq_disk); + wait_for_completion(&event); + + return test_bit(BH_Uptodate, &bh.b_state); +} + static int read_disk_sb(mdk_rdev_t * rdev) { int ret = -EINVAL; - struct buffer_head *bh = NULL; kdev_t dev = rdev->dev; - mdp_super_t *sb; unsigned long sb_offset; if (!rdev->sb) { @@ -548,22 +579,15 @@ */ sb_offset = calc_dev_sboffset(rdev->dev, rdev->mddev, 1); rdev->sb_offset = sb_offset; - fsync_dev(dev); - set_blocksize (dev, MD_SB_BYTES); - bh = bread (dev, sb_offset / MD_SB_BLOCKS, MD_SB_BYTES); - - if (bh) { - sb = (mdp_super_t *) bh->b_data; - memcpy (rdev->sb, sb, MD_SB_BYTES); - } else { - EPRINTK(NO_SB,partition_name(rdev->dev)); - goto abort; + + if (!sync_page_io(dev, sb_offset<<1, MD_SB_BYTES, rdev->sb_page, READ)) + { + printk(NO_SB,partition_name(dev)); + return -EINVAL; } EPRINTK(KERN_INFO " [events: %08lx]\n", (unsigned long)rdev->sb->events_lo); ret = 0; abort: - if (bh) - brelse (bh); return ret; } @@ -951,10 +975,8 @@ static int write_disk_sb(mdk_rdev_t * rdev) { - struct buffer_head *bh; kdev_t dev; unsigned long sb_offset, size; - mdp_super_t *sb; if (!rdev->sb) { MD_BUG(); @@ -993,23 +1015,10 @@ } EPRINTK(KERN_INFO "(write) %s's sb offset: %ld\n", partition_name(dev), sb_offset); - fsync_dev(dev); - set_blocksize(dev, MD_SB_BYTES); - bh = getblk(dev, sb_offset / MD_SB_BLOCKS, MD_SB_BYTES); - if (!bh) { - EPRINTK(GETBLK_FAILED, partition_name(dev)); + if (!sync_page_io(dev, sb_offset<<1, MD_SB_BYTES, rdev->sb_page, WRITE)) { + printk("md: write_disk_sb failed for device %s\n", partition_name(dev)); return 1; } - memset(bh->b_data,0,bh->b_size); - sb = (mdp_super_t *) bh->b_data; - memcpy(sb, rdev->sb, MD_SB_BYTES); - - mark_buffer_uptodate(bh, 1); - mark_buffer_dirty(bh); - ll_rw_block(WRITE, 1, &bh); - wait_on_buffer(bh); - brelse(bh); - fsync_dev(dev); skip: return 0; } @@ -1111,6 +1120,11 @@ if (rdev->alias_device) printk("(skipping alias "); + if (disk_faulty(&rdev->sb->this_disk)) { + printk("(skipping new-faulty %s )\n", + partition_name(rdev->dev)); + continue; + } printk("%s ", partition_name(rdev->dev)); /* check for rdev->sb NULL here also. ARC*/ if (!rdev->faulty && !rdev->alias_device && rdev->sb) { @@ -1143,7 +1157,6 @@ * - the device is nonexistent (zero size) * - the device has no valid superblock * - * a faulty rdev _never_ has rdev->sb set. */ static int md_import_device(kdev_t newdev, int on_disk) { @@ -1215,14 +1228,13 @@ md_list_add(&rdev->all, &all_raid_disks); MD_INIT_LIST_HEAD(&rdev->pending); - if (rdev->faulty && rdev->sb) - free_disk_sb(rdev); +// if (rdev->faulty && rdev->sb) +// free_disk_sb(rdev); return 0; abort_free: if (rdev->sb) { - if (rdev->bdev) - unlock_rdev(rdev); + if (rdev->bdev) unlock_rdev(rdev); free_disk_sb(rdev); } kfree(rdev); @@ -3136,7 +3148,7 @@ return 0; if (!mddev->pers->error_handler || mddev->pers->error_handler(mddev,rdev) <= 0) { - free_disk_sb(rrdev); + // free_disk_sb(rrdev); rrdev->faulty = 1; } else return 1; --- linux-2.4.18-orig/include/linux/raid/md_k.h Mon Nov 26 08:29:17 2001 +++ linux-2.4.18/include/linux/raid/md_k.h Tue Dec 17 11:03:14 2002 @@ -171,6 +171,7 @@ struct block_device *bdev; /* block device handle */ mdp_super_t *sb; + struct page *sb_page; unsigned long sb_offset; int alias_device; /* device alias to the same disk */