kern/95459: Rebooting the system while rebuilding RAID (Intel MatrixRAID) results in data loss

Hideki SAKAMOTO hsakamt at tsnr.com
Fri Sep 5 17:33:14 UTC 2008


Remko Lodder wrote:
> Hideki SAKAMOTO wrote:
> 
> The patch is unreadable. Can you please attach it inline, or make it 
> available online somewhere?
> 
> Thanks,
> remko
> 

Oh, sorry. I sent the mail to bug-followup at FreeBSD.org using "Submit Followup" 
link in GNATS website. I can read the patch at:
http://www.freebsd.org/cgi/query-pr.cgi?pr=kern/95459
(I don't know why but download link was broken.)

I attach the patch inline just in case.

Thanks,
---
   Hideki Sakamoto

===== ata-raid.h.patch: common file for 6_STABLE and 7_STABLE =====

*** ata-raid.h.orig	Sat Sep 30 23:51:49 2006
--- ata-raid.h	Thu Sep  4 18:35:15 2008
***************
*** 323,329 ****
       u_int64_t           total_sectors __packed;
       u_int32_t           state;
       u_int32_t           reserved;
!     u_int32_t           filler_0[20];
       u_int32_t           offset;
       u_int32_t           disk_sectors;
       u_int32_t           stripe_count;
--- 323,336 ----
       u_int64_t           total_sectors __packed;
       u_int32_t           state;
       u_int32_t           reserved;
!     u_int32_t           filler_0[12];
!     u_int32_t           rebuild_count;
!     u_int32_t           dummy;
!     u_int32_t           rebuild_flag;
! #define INTEL_RF_NORMAL         0x00000100
! #define INTEL_RF_REBUILDING     0x00000001
!
!     u_int32_t           filler_1[5];
       u_int32_t           offset;
       u_int32_t           disk_sectors;
       u_int32_t           stripe_count;
***************
*** 341,347 ****

       u_int8_t            total_disks;
       u_int8_t            magic[3];
!     u_int32_t           filler_1[7];
       u_int32_t           disk_idx[1];
   } __packed;

--- 348,354 ----

       u_int8_t            total_disks;
       u_int8_t            magic[3];
!     u_int32_t           filler_2[7];
       u_int32_t           disk_idx[1];
   } __packed;


========== ata-raid.c.patch6: for 6_STABLE ==========

*** ata-raid.c.orig	Thu Sep  4 18:40:36 2008
--- ata-raid.c	Fri Sep  5 10:52:01 2008
***************
*** 1286,1291 ****
--- 1286,1293 ----
   	if (count) {
   	    rdp->rebuild_lba = 0;
   	    rdp->status |= AR_S_REBUILDING;
+ 	    if (rdp->format == AR_F_INTEL_RAID)
+ 	        ata_raid_config_changed(rdp, 1);
   	    return 0;
   	}
   	return EIO;
***************
*** 2135,2140 ****
--- 2137,2153 ----
   		raid->status |= AR_S_DEGRADED;
   		break;
   	    case INTEL_S_DISABLED:
+ 		raid->status |= AR_S_READY;
+ 		/*
+ 		 * rollback to DEGRADED mode because /bin/dd cann't kick
+ 		 * like atacontrol(8) at this moment.
+ 		 *
+ 		 * I checked the code below by execute /bin/dd on shell.
+ 		 *
+ 		 * if ((map->rebuild_flag & INTEL_RF_REBUILDING) && map->magic[1] != 0xff)
+ 		 *    raid->status |= (AR_S_REBUILDING|AR_S_DEGRADED);
+ 		 */
+ 		break;
   	    case INTEL_S_FAILURE:
   		raid->status = 0;
   	    }
***************
*** 2164,2171 ****
   		raid->disks[disk].sectors =
   		    meta->disk[map->disk_idx[disk]].sectors;
   		raid->disks[disk].flags = 0;
! 		if (meta->disk[map->disk_idx[disk]].flags & INTEL_F_ONLINE)
! 		    raid->disks[disk].flags |= AR_DF_ONLINE;
   		if (meta->disk[map->disk_idx[disk]].flags & INTEL_F_ASSIGNED)
   		    raid->disks[disk].flags |= AR_DF_ASSIGNED;
   		if (meta->disk[map->disk_idx[disk]].flags & INTEL_F_SPARE) {
--- 2177,2190 ----
   		raid->disks[disk].sectors =
   		    meta->disk[map->disk_idx[disk]].sectors;
   		raid->disks[disk].flags = 0;
! 		if (meta->disk[map->disk_idx[disk]].flags & INTEL_F_ONLINE) {
! 		    if ((map->rebuild_flag & INTEL_RF_REBUILDING) && disk == map->magic[1]) {
! 		        raid->disks[disk].flags |= AR_DF_SPARE;
! 			// raid->rebuild_lba = map->rebuild_count ...;
! 		    } else {
! 		        raid->disks[disk].flags |= AR_DF_ONLINE;
! 		    }
! 		}
   		if (meta->disk[map->disk_idx[disk]].flags & INTEL_F_ASSIGNED)
   		    raid->disks[disk].flags |= AR_DF_ASSIGNED;
   		if (meta->disk[map->disk_idx[disk]].flags & INTEL_F_SPARE) {
***************
*** 2183,2189 ****
   		if (!strncmp(raid->disks[disk].serial, atadev->param.serial,
   		    sizeof(raid->disks[disk].serial))) {
   		    raid->disks[disk].dev = parent;
! 		    raid->disks[disk].flags |= (AR_DF_PRESENT | AR_DF_ONLINE);
   		    ars->raid[raid->volume] = raid;
   		    ars->disk_number[raid->volume] = disk;
   		    retval = 1;
--- 2202,2208 ----
   		if (!strncmp(raid->disks[disk].serial, atadev->param.serial,
   		    sizeof(raid->disks[disk].serial))) {
   		    raid->disks[disk].dev = parent;
! 		    raid->disks[disk].flags |= AR_DF_PRESENT;
   		    ars->raid[raid->volume] = raid;
   		    ars->disk_number[raid->volume] = disk;
   		    retval = 1;
***************
*** 2222,2229 ****
       struct intel_raid_conf *meta;
       struct intel_raid_mapping *map;
       struct timeval timestamp;
!     u_int32_t checksum, *ptr;
       int count, disk, error = 0;
       char *tmp;

       if (!(meta = (struct intel_raid_conf *)
--- 2241,2249 ----
       struct intel_raid_conf *meta;
       struct intel_raid_mapping *map;
       struct timeval timestamp;
!     u_int32_t checksum, *ptr, rebuild_flag = INTEL_RF_NORMAL;
       int count, disk, error = 0;
+     u_int8_t rebuild_target = 0xff;
       char *tmp;

       if (!(meta = (struct intel_raid_conf *)
***************
*** 2253,2282 ****
   	    meta->disk[disk].sectors = rdp->disks[disk].sectors;
   	    meta->disk[disk].id = (ch->unit << 16) | ATA_DEV(atadev->unit);
   	}
! 	else
   	    meta->disk[disk].sectors = rdp->total_sectors / rdp->width;
   	meta->disk[disk].flags = 0;
! 	if (rdp->disks[disk].flags & AR_DF_SPARE)
   	    meta->disk[disk].flags  |= INTEL_F_SPARE;
! 	else {
! 	    if (rdp->disks[disk].flags & AR_DF_ONLINE)
   		meta->disk[disk].flags |= INTEL_F_ONLINE;
   	    else
   		meta->disk[disk].flags |= INTEL_F_DOWN;
   	    if (rdp->disks[disk].flags & AR_DF_ASSIGNED)
   		meta->disk[disk].flags  |= INTEL_F_ASSIGNED;
   	}
       }
       map = (struct intel_raid_mapping *)&meta->disk[meta->total_disks];

       bcopy(rdp->name, map->name, sizeof(rdp->name));
       map->total_sectors = rdp->total_sectors;
!     map->state = 12;                                            /* XXX SOS */
       map->offset = rdp->offset_sectors;
       map->stripe_count = rdp->total_sectors / (rdp->interleave*rdp->total_disks);
       map->stripe_sectors =  rdp->interleave;
       map->disk_sectors = rdp->total_sectors / rdp->width;
!     map->status = INTEL_S_READY;                                /* XXX SOS */
       switch (rdp->type) {
       case AR_T_RAID0:
   	map->type = INTEL_T_RAID0;
--- 2273,2330 ----
   	    meta->disk[disk].sectors = rdp->disks[disk].sectors;
   	    meta->disk[disk].id = (ch->unit << 16) | ATA_DEV(atadev->unit);
   	}
! 	else {
   	    meta->disk[disk].sectors = rdp->total_sectors / rdp->width;
+ 	    meta->disk[disk].id = 0xffffffff;
+ 	}
   	meta->disk[disk].flags = 0;
! 	/*
! 	 * Rebuilding status:
! 	 *   driver:
! 	 *     - AR_DF_ONLINE is NOT set on mirror drive.
! 	 *     - AR_S_REBUILDING is set.
! 	 *     - AR_DF_SPARE is set on mirror drive.
! 	 *   BIOS:
! 	 *     - INTEL_F_ONLINE is set on both master and mirror drive.
! 	 *     - INTEL_RF_REBUILDING is set.
! 	 *     - mirror's drive number is in magic[1].
! 	 */
! 	if ((rdp->disks[disk].flags & AR_DF_SPARE) &&
! 	      (!(rdp->status & AR_S_REBUILDING) || (rebuild_target != 0xff))) {
   	    meta->disk[disk].flags  |= INTEL_F_SPARE;
! 	} else {
! 	    if ((rdp->disks[disk].flags & (AR_DF_ONLINE|AR_DF_SPARE)))
   		meta->disk[disk].flags |= INTEL_F_ONLINE;
   	    else
   		meta->disk[disk].flags |= INTEL_F_DOWN;
   	    if (rdp->disks[disk].flags & AR_DF_ASSIGNED)
   		meta->disk[disk].flags  |= INTEL_F_ASSIGNED;
+ 	    if (rdp->disks[disk].flags & AR_DF_SPARE) {
+ 		rebuild_target = (u_int8_t)disk;
+ 		rebuild_flag |= INTEL_RF_REBUILDING;
+ 	    }
   	}
       }
       map = (struct intel_raid_mapping *)&meta->disk[meta->total_disks];

       bcopy(rdp->name, map->name, sizeof(rdp->name));
       map->total_sectors = rdp->total_sectors;
!     map->state = 268;                                           /* XXX */
       map->offset = rdp->offset_sectors;
       map->stripe_count = rdp->total_sectors / (rdp->interleave*rdp->total_disks);
       map->stripe_sectors =  rdp->interleave;
       map->disk_sectors = rdp->total_sectors / rdp->width;
!     map->rebuild_count = map->stripe_count / 2;                /* XXX */
!     map->rebuild_flag = rebuild_flag;
!     if (rdp->status & AR_S_REBUILDING) {           /* keep this order */
!     	map->status = INTEL_S_DISABLED;
!     } else if (rdp->status & AR_S_READY) {
!     	map->status = INTEL_S_READY;
!     } else if (rdp->status & AR_S_DEGRADED) {
! 	map->status = INTEL_S_DEGRADED;
!     } else {
! 	map->status = INTEL_S_FAILURE;
!     }
       switch (rdp->type) {
       case AR_T_RAID0:
   	map->type = INTEL_T_RAID0;
***************
*** 2296,2302 ****
       }
       map->total_disks = rdp->total_disks;
       map->magic[0] = 0x02;
!     map->magic[1] = 0xff;
       map->magic[2] = 0x01;
       for (disk = 0; disk < rdp->total_disks; disk++)
   	map->disk_idx[disk] = disk;
--- 2344,2350 ----
       }
       map->total_disks = rdp->total_disks;
       map->magic[0] = 0x02;
!     map->magic[1] = rebuild_target;
       map->magic[2] = 0x01;
       for (disk = 0; disk < rdp->total_disks; disk++)
   	map->disk_idx[disk] = disk;
***************
*** 4530,4535 ****
--- 4578,4585 ----
   	printf("total_sectors       %ju\n", map->total_sectors);
   	printf("state               %u\n", map->state);
   	printf("reserved            %u\n", map->reserved);
+ 	printf("rebuild_count       %u\n", map->rebuild_count);
+ 	printf("rebuild_flag        0x%08x\n", map->rebuild_flag);
   	printf("offset              %u\n", map->offset);
   	printf("disk_sectors        %u\n", map->disk_sectors);
   	printf("stripe_count        %u\n", map->stripe_count);

========== ata-raid.c.patch7: for 7_STABLE ==========

*** ata-raid.c.orig	Tue Aug 14 03:46:31 2007
--- ata-raid.c	Fri Sep  5 01:21:26 2008
***************
*** 1325,1330 ****
--- 1325,1332 ----
   	if (count) {
   	    rdp->rebuild_lba = 0;
   	    rdp->status |= AR_S_REBUILDING;
+ 	    if (rdp->format == AR_F_INTEL_RAID)
+ 		ata_raid_config_changed(rdp, 1);
   	    return 0;
   	}
   	return EIO;
***************
*** 2174,2179 ****
--- 2176,2191 ----
   		raid->status |= AR_S_DEGRADED;
   		break;
   	    case INTEL_S_DISABLED:
+ 		raid->status = AR_S_READY;
+ 		/*
+ 		 * rollback to DEGRADED mode because /bin/dd cann't kick
+                  * like atacontrol(8) at this moment.
+ 		 *
+ 		 * I checked the code below by execute /bin/dd on shell.
+ 		 * if (map->rebuild_flag & INTEL_RF_REBUILDING && map->magic[1] != 0xff)
+ 		 *    raid->status |= (AR_S_REBUILDING|AR_S_DEGRADED);
+                  */
+ 		break;
   	    case INTEL_S_FAILURE:
   		raid->status = 0;
   	    }
***************
*** 2203,2210 ****
   		raid->disks[disk].sectors =
   		    meta->disk[map->disk_idx[disk]].sectors;
   		raid->disks[disk].flags = 0;
! 		if (meta->disk[map->disk_idx[disk]].flags & INTEL_F_ONLINE)
! 		    raid->disks[disk].flags |= AR_DF_ONLINE;
   		if (meta->disk[map->disk_idx[disk]].flags & INTEL_F_ASSIGNED)
   		    raid->disks[disk].flags |= AR_DF_ASSIGNED;
   		if (meta->disk[map->disk_idx[disk]].flags & INTEL_F_SPARE) {
--- 2215,2228 ----
   		raid->disks[disk].sectors =
   		    meta->disk[map->disk_idx[disk]].sectors;
   		raid->disks[disk].flags = 0;
! 		if (meta->disk[map->disk_idx[disk]].flags & INTEL_F_ONLINE) {
! 		    if ((map->rebuild_flag & INTEL_RF_REBUILDING) && disk == map->magic[1]) {
! 			raid->disks[disk].flags |= AR_DF_SPARE;
! 			// raid->rebuild_lba = map->rebuild_count ...;
! 		    } else {
! 			raid->disks[disk].flags |= AR_DF_ONLINE;
! 		    }
! 		}
   		if (meta->disk[map->disk_idx[disk]].flags & INTEL_F_ASSIGNED)
   		    raid->disks[disk].flags |= AR_DF_ASSIGNED;
   		if (meta->disk[map->disk_idx[disk]].flags & INTEL_F_SPARE) {
***************
*** 2222,2228 ****
   		if (!strncmp(raid->disks[disk].serial, atadev->param.serial,
   		    sizeof(raid->disks[disk].serial))) {
   		    raid->disks[disk].dev = parent;
! 		    raid->disks[disk].flags |= (AR_DF_PRESENT | AR_DF_ONLINE);
   		    ars->raid[raid->volume] = raid;
   		    ars->disk_number[raid->volume] = disk;
   		    retval = 1;
--- 2240,2246 ----
   		if (!strncmp(raid->disks[disk].serial, atadev->param.serial,
   		    sizeof(raid->disks[disk].serial))) {
   		    raid->disks[disk].dev = parent;
! 		    raid->disks[disk].flags |= AR_DF_PRESENT;
   		    ars->raid[raid->volume] = raid;
   		    ars->disk_number[raid->volume] = disk;
   		    retval = 1;
***************
*** 2261,2268 ****
       struct intel_raid_conf *meta;
       struct intel_raid_mapping *map;
       struct timeval timestamp;
!     u_int32_t checksum, *ptr;
       int count, disk, error = 0;
       char *tmp;

       if (!(meta = (struct intel_raid_conf *)
--- 2279,2287 ----
       struct intel_raid_conf *meta;
       struct intel_raid_mapping *map;
       struct timeval timestamp;
!     u_int32_t checksum, *ptr, rebuild_flag = INTEL_RF_NORMAL;
       int count, disk, error = 0;
+     u_int8_t rebuild_target = 0xff;
       char *tmp;

       if (!(meta = (struct intel_raid_conf *)
***************
*** 2292,2321 ****
   	    meta->disk[disk].sectors = rdp->disks[disk].sectors;
   	    meta->disk[disk].id = (ch->unit << 16) | ATA_DEV(atadev->unit);
   	}
! 	else
   	    meta->disk[disk].sectors = rdp->total_sectors / rdp->width;
   	meta->disk[disk].flags = 0;
! 	if (rdp->disks[disk].flags & AR_DF_SPARE)
   	    meta->disk[disk].flags  |= INTEL_F_SPARE;
! 	else {
! 	    if (rdp->disks[disk].flags & AR_DF_ONLINE)
   		meta->disk[disk].flags |= INTEL_F_ONLINE;
   	    else
   		meta->disk[disk].flags |= INTEL_F_DOWN;
   	    if (rdp->disks[disk].flags & AR_DF_ASSIGNED)
   		meta->disk[disk].flags  |= INTEL_F_ASSIGNED;
   	}
       }
       map = (struct intel_raid_mapping *)&meta->disk[meta->total_disks];

       bcopy(rdp->name, map->name, sizeof(rdp->name));
       map->total_sectors = rdp->total_sectors;
!     map->state = 12;                                            /* XXX SOS */
       map->offset = rdp->offset_sectors;
       map->stripe_count = rdp->total_sectors / (rdp->interleave*rdp->total_disks);
       map->stripe_sectors =  rdp->interleave;
       map->disk_sectors = rdp->total_sectors / rdp->width;
!     map->status = INTEL_S_READY;                                /* XXX SOS */
       switch (rdp->type) {
       case AR_T_RAID0:
   	map->type = INTEL_T_RAID0;
--- 2311,2368 ----
   	    meta->disk[disk].sectors = rdp->disks[disk].sectors;
   	    meta->disk[disk].id = (ch->unit << 16) | ATA_DEV(atadev->unit);
   	}
! 	else {
   	    meta->disk[disk].sectors = rdp->total_sectors / rdp->width;
+ 	    meta->disk[disk].id = 0xffffffff;
+ 	}
   	meta->disk[disk].flags = 0;
! 	/*
! 	 * Rebuilding status:
! 	 *   driver:
! 	 *     - AR_DF_ONLINE is NOT set on mirror drive.
! 	 *     - AR_S_REBUILDING is set.
! 	 *     - AR_DF_SPARE is set on mirror drive.
! 	 *   BIOS:
! 	 *     - INTEL_F_ONLINE is set on both master and mirror drive.
! 	 *     - INTEL_RF_REBUILDING is set.
! 	 *     - mirror's drive number is in magic[1].
! 	 */
! 	if ((rdp->disks[disk].flags & AR_DF_SPARE) &&
! 	    (!(rdp->status & AR_S_REBUILDING) || (rebuild_target != 0xff))) {
   	    meta->disk[disk].flags  |= INTEL_F_SPARE;
! 	} else {
! 	    if (rdp->disks[disk].flags & (AR_DF_ONLINE|AR_DF_SPARE))
   		meta->disk[disk].flags |= INTEL_F_ONLINE;
   	    else
   		meta->disk[disk].flags |= INTEL_F_DOWN;
   	    if (rdp->disks[disk].flags & AR_DF_ASSIGNED)
   		meta->disk[disk].flags  |= INTEL_F_ASSIGNED;
+ 	    if (rdp->disks[disk].flags & AR_DF_SPARE) {
+ 		rebuild_target = (u_int8_t)disk;
+ 		rebuild_flag = INTEL_RF_REBUILDING;
+ 	    }
   	}
       }
       map = (struct intel_raid_mapping *)&meta->disk[meta->total_disks];

       bcopy(rdp->name, map->name, sizeof(rdp->name));
       map->total_sectors = rdp->total_sectors;
!     map->state = 268;                                            /* XXX */
       map->offset = rdp->offset_sectors;
       map->stripe_count = rdp->total_sectors / (rdp->interleave*rdp->total_disks);
       map->stripe_sectors =  rdp->interleave;
       map->disk_sectors = rdp->total_sectors / rdp->width;
!     map->rebuild_count = map->stripe_count / 2;                  /* XXX */
!     map->rebuild_flag = rebuild_flag;
!     if (rdp->status & AR_S_REBUILDING) {             /* keep this order */
! 	map->status = INTEL_S_DISABLED;
!     } else if (rdp->status & AR_S_READY) {
! 	map->status = INTEL_S_READY;
!     } else if (rdp->status & AR_S_DEGRADED) {
! 	map->status = INTEL_S_DEGRADED;
!     } else {
! 	map->status = INTEL_S_FAILURE;
!     }
       switch (rdp->type) {
       case AR_T_RAID0:
   	map->type = INTEL_T_RAID0;
***************
*** 2335,2341 ****
       }
       map->total_disks = rdp->total_disks;
       map->magic[0] = 0x02;
!     map->magic[1] = 0xff;
       map->magic[2] = 0x01;
       for (disk = 0; disk < rdp->total_disks; disk++)
   	map->disk_idx[disk] = disk;
--- 2382,2388 ----
       }
       map->total_disks = rdp->total_disks;
       map->magic[0] = 0x02;
!     map->magic[1] = rebuild_target;
       map->magic[2] = 0x01;
       for (disk = 0; disk < rdp->total_disks; disk++)
   	map->disk_idx[disk] = disk;
***************
*** 4572,4577 ****
--- 4619,4626 ----
   	printf("total_sectors       %ju\n", map->total_sectors);
   	printf("state               %u\n", map->state);
   	printf("reserved            %u\n", map->reserved);
+ 	printf("rebuild_count       %u\n", map->rebuild_count);
+ 	printf("rebuild_flag        0x%08x\n", map->rebuild_flag);
   	printf("offset              %u\n", map->offset);
   	printf("disk_sectors        %u\n", map->disk_sectors);
   	printf("stripe_count        %u\n", map->stripe_count);




More information about the freebsd-bugs mailing list