Subject: standalone and kernel driver bugs with unlabeled disks (#269) Index: pdpuba,pdpstand/ra.c,rl.c,label.c 2.11BSD Description: The standalone disklabel program (for MSCP and RL disks) can refuse to open a disk if a corrupt label is present. This prevents placing a correct label on the disk. In the kernel a similar problem was encountered. If a label is missing or corrupt the drivers would not permit the open to take place, preventing a label from being written to the device. Repeat-By: Corrupt the label on a drive by dd'ing over top of sector 1. Or have a disk present which has never been labeled before. Attempt to use either the standalone disklabel program or disklabel(8) and observe the "bad partition number or size = 0" error message. Fix: The patch below will fix the problem of labeling MSCP (RA) or RL disks. Drivers converted in the future will incorporate the logic implemented below. The problem in the standalone disklabel program was that unlabeled disks (or if the label is corrupt) should not have the partition number validated if the program being run is 'disklabel'. The check of the partition number was moved from the individual drivers to the common label handling module where the check is only performed if the program is not 'disklabel'. In the kernel the problem was slightly different. If a missing or corrupt label is detected by the kernel drivers the correct action is to use a "fake label" suitable for writing the label sector. This involved creating a "default label" routine in each driver which is called once before attempting to read the label and again if there is no valid label present. For MSCP and RL devices the geometry is either completely known (RL) or irrelevant, it is thus possible for these device types to create a label with the 'a' partition spanning the entire drive. Serious thought is being given to whether this is the right thing to do (there is a risk of damaging data on other partitions if the 'a' partition is actually used for anything except writing a label). To install this patch: 1) Cut where indicated and save to a file (/tmp/269) 2) patch -p0 < /tmp/269 3) cd /sys/pdpstand make clean make cp boot /boot Then create a bootable tape/floppy containing the new boot and disklabel programs! Next the kernel needs to be recompiled if you use MSCP or RL disks: 4) cd /sys/{YOUR_KERNEL_DIRECTORY} make make install reboot ======================cut here============== *** /usr/src/sys/pdpuba/ra.c.old Mon Jul 3 21:12:59 1995 --- /usr/src/sys/pdpuba/ra.c Tue Aug 1 22:21:45 1995 *************** *** 3,9 **** * All rights reserved. The Berkeley software License Agreement * specifies the terms and conditions for redistribution. * ! * @(#)ra.c 2.9 (2.11BSD GTE) 1995/07/03 */ /*********************************************************************** --- 3,9 ---- * All rights reserved. The Berkeley software License Agreement * specifies the terms and conditions for redistribution. * ! * @(#)ra.c 3.0 (2.11BSD GTE) 1995/08/01 */ /*********************************************************************** *************** *** 14,19 **** --- 14,24 ---- /* * ra.c - MSCP Driver + * Date: August 1, 1995 + * Fix a bug which prohibited labeling previously disks which were unlabeled + * or had a corrupted label. The default ('a' partition spanning the volume) + * must be left in place to allow the write of the label. + * * Date: July 3, 1995 * Fix a couple bugs and simplify the close protocol. * *************** *** 226,232 **** extern int wakeup(); extern ubadr_t _iomap(); extern size_t physmem; /* used by the crash dump routine */ ! void ragetinfo(); struct mscp *ragetcp(); #define b_qsize b_resid /* queue size per drive, in rqdtab */ --- 231,237 ---- extern int wakeup(); extern ubadr_t _iomap(); extern size_t physmem; /* used by the crash dump routine */ ! void ragetinfo(), radfltlbl(); struct mscp *ragetcp(); #define b_qsize b_resid /* queue size per drive, in rqdtab */ *************** *** 501,506 **** --- 506,542 ---- } /* + * This code was moved from ragetinfo() because it is fairly large and used + * twice - once to initialize for reading the label and a second time if + * there is no valid label present on the drive and the default one must be + * used. + */ + + void + radfltlbl(disk, lp) + ra_infoT *disk; + register struct disklabel *lp; + { + register struct partition *pi = &lp->d_partitions[0]; + + bzero(lp, sizeof (*lp)); + lp->d_type = DTYPE_MSCP; + lp->d_secsize = 512; /* XXX */ + lp->d_nsectors = 32; + lp->d_ntracks = 1; + lp->d_secpercyl = 20 * 32; + lp->d_npartitions = 1; /* 'a' */ + pi->p_size = disk->ra_nblks; /* entire volume */ + pi->p_fstype = FS_V71K; + pi->p_frag = 1; + pi->p_fsize = 1024; + /* + * Put where rastrategy() will look. + */ + bcopy(pi, disk->ra_parts, sizeof (lp->d_partitions)); + } + + /* * Read disklabel. It is tempting to generalize this routine so that * all disk drivers could share it. However by the time all of the * necessary parameters are setup and passed the savings vanish. Also, *************** *** 523,561 **** struct disklabel locallabel; char *msg; register struct disklabel *lp = &locallabel; - int part = dkpart(dev); /* * NOTE: partition 0 ('a') is used to read the label. Therefore 'a' must * start at the beginning of the disk! If there is no label or the label * is corrupted then 'a' will span the entire disk */ - register struct partition *pi = lp->d_partitions; - struct partition *kpi = disk->ra_parts; ! bzero(lp, sizeof (*lp)); ! lp->d_type = DTYPE_MSCP; ! lp->d_secsize = 512; /* XXX */ ! lp->d_nsectors = 32; ! lp->d_ntracks = 1; ! lp->d_secpercyl = 20 * 32; ! lp->d_npartitions = 1; /* 'a' */ ! pi[0].p_offset = 0; ! pi[0].p_size = LABELSECTOR + 1; ! pi[0].p_fstype = FS_V71K; ! kpi[0].p_offset = 0; /* put where rastrategy will look */ ! kpi[0].p_size = LABELSECTOR + 1; ! kpi[0].p_fstype = FS_V71K; msg = readdisklabel((dev & ~7) | 0, rastrategy, lp); /* 'a' */ ! if (msg == 0) { ! mapseg5(disk->ra_label, LABELDESC); ! bcopy(lp, (struct disklabel *)SEG5, sizeof (struct disklabel)); ! normalseg5(); ! bcopy(pi, kpi, sizeof (lp->d_partitions)); ! return; } ! log(LOG_NOTICE, "ra%da is entire disk: '%s'\n", dkunit(dev), msg); ! kpi[0].p_size = disk->ra_nblks; return; } --- 559,581 ---- struct disklabel locallabel; char *msg; register struct disklabel *lp = &locallabel; /* * NOTE: partition 0 ('a') is used to read the label. Therefore 'a' must * start at the beginning of the disk! If there is no label or the label * is corrupted then 'a' will span the entire disk */ ! radfltlbl(disk, lp); /* set up default/fake label */ msg = readdisklabel((dev & ~7) | 0, rastrategy, lp); /* 'a' */ ! if (msg != 0) { ! log(LOG_NOTICE, "ra%da is entire disk: %s\n", dkunit(dev), msg); ! radfltlbl(disk, lp); } ! mapseg5(disk->ra_label, LABELDESC); ! bcopy(lp, (struct disklabel *)SEG5, sizeof (struct disklabel)); ! normalseg5(); ! bcopy(lp->d_partitions, disk->ra_parts, sizeof (lp->d_partitions)); return; } *** /usr/src/sys/pdpuba/rl.c.old Wed Jun 28 19:59:31 1995 --- /usr/src/sys/pdpuba/rl.c Tue Aug 1 20:43:32 1995 *************** *** 3,13 **** * All rights reserved. The Berkeley software License Agreement * specifies the terms and conditions for redistribution. * ! * @(#)rl.c 1.5 (2.11BSD GTE) 1995/06/28 */ /* * RL01/RL02 disk driver * * Date: June 15, 1995. * Modified to handle disklabels. This provides the ability to partition --- 3,17 ---- * All rights reserved. The Berkeley software License Agreement * specifies the terms and conditions for redistribution. * ! * @(#)rl.c 1.6 (2.11BSD GTE) 1995/08/01 */ /* * RL01/RL02 disk driver + * Date: August 1, 1995 + * Fix bug which prevented labeling disks with no label or a corrupted label. + * Correct typographical error, the raclose() routine was being called by + * mistake in the rlsize() routine. * * Date: June 15, 1995. * Modified to handle disklabels. This provides the ability to partition *************** *** 52,57 **** --- 56,63 ---- daddr_t rlsize(); int rlstrategy(); + void rldfltlbl(); + struct buf rlutab[NRL]; /* Seek structure for each device */ struct buf rltab; *************** *** 212,217 **** --- 218,255 ---- } /* + * This code was moved from rlgetinfo() because it is fairly large and used + * twice - once to initialize for reading the label and a second time if + * there is no valid label present on the drive and the default one must be + * used. + */ + + void + rldfltlbl(disk, lp, dev) + struct dkdevice *disk; + register struct disklabel *lp; + dev_t dev; + { + register struct partition *pi = &lp->d_partitions[0]; + + bzero(lp, sizeof (*lp)); + lp->d_type = DTYPE_DEC; + lp->d_secsize = 512; /* XXX */ + lp->d_nsectors = 20; + lp->d_ntracks = 2; + lp->d_secpercyl = 2 * 20; + lp->d_npartitions = 1; /* 'a' */ + pi->p_size = rl.nblks[dkunit(dev)]; /* entire volume */ + pi->p_fstype = FS_V71K; + pi->p_frag = 1; + pi->p_fsize = 1024; + /* + * Put where rlstrategy() will look. + */ + bcopy(pi, disk->dk_parts, sizeof (lp->d_partitions)); + } + + /* * Read disklabel. It is tempting to generalize this routine so that * all disk drivers could share it. However by the time all of the * necessary parameters are setup and passed the savings vanish. Also, *************** *** 234,272 **** struct disklabel locallabel; char *msg; register struct disklabel *lp = &locallabel; - int part = dkpart(dev); /* * NOTE: partition 0 ('a') is used to read the label. Therefore 'a' must * start at the beginning of the disk! If there is no label or the label * is corrupted then 'a' will span the entire disk */ - register struct partition *pi = lp->d_partitions; - struct partition *kpi = disk->dk_parts; ! bzero(lp, sizeof (*lp)); ! lp->d_type = DTYPE_DEC; ! lp->d_secsize = 512; /* XXX */ ! lp->d_nsectors = 20; ! lp->d_ntracks = 2; ! lp->d_secpercyl = 2 * 20; ! lp->d_npartitions = 1; /* 'a' */ ! pi[0].p_offset = 0; ! pi[0].p_size = LABELSECTOR + 1; ! pi[0].p_fstype = FS_V71K; ! kpi[0].p_offset = 0; /* put where rlstrategy will look */ ! kpi[0].p_size = LABELSECTOR + 1; ! kpi[0].p_fstype = FS_V71K; msg = readdisklabel((dev & ~7) | 0, rlstrategy, lp); /* 'a' */ ! if (msg == 0) { ! mapseg5(disk->dk_label, LABELDESC) ! bcopy(lp, (struct disklabel *)SEG5, sizeof (struct disklabel)); ! normalseg5(); ! bcopy(pi, kpi, sizeof (lp->d_partitions)); ! return; } ! log(LOG_NOTICE, "rl%da is entire disk: '%s'\n", dkunit(dev), msg); ! kpi[0].p_size = rl.nblks[dkunit(dev)]; return; } --- 272,294 ---- struct disklabel locallabel; char *msg; register struct disklabel *lp = &locallabel; /* * NOTE: partition 0 ('a') is used to read the label. Therefore 'a' must * start at the beginning of the disk! If there is no label or the label * is corrupted then 'a' will span the entire disk */ ! rldfltlbl(disk, lp, dev); msg = readdisklabel((dev & ~7) | 0, rlstrategy, lp); /* 'a' */ ! if (msg != 0) { ! log(LOG_NOTICE, "rl%da is entire disk: %s\n", dkunit(dev), msg); ! rldfltlbl(disk, lp, dev); } ! mapseg5(disk->dk_label, LABELDESC) ! bcopy(lp, (struct disklabel *)SEG5, sizeof (struct disklabel)); ! normalseg5(); ! bcopy(lp->d_partitions, disk->dk_parts, sizeof (lp->d_partitions)); return; } *************** *** 593,598 **** --- 615,622 ---- register struct ubmap *ubp; unit = RLUNIT(dev); + if (unit >= NRL) + return(EINVAL); partition = dkpart(dev); disk = &rl_dk[unit]; pi = &disk->dk_parts[partition]; *************** *** 693,699 **** } psize = disk->dk_parts[dkpart(dev)].p_size; if (didopen) ! raclose(dev, FREAD|FWRITE, S_IFBLK); return(psize); } --- 717,723 ---- } psize = disk->dk_parts[dkpart(dev)].p_size; if (didopen) ! rlclose(dev, FREAD|FWRITE, S_IFBLK); return(psize); } *** /usr/src/sys/pdpstand/label.c.old Mon Jul 10 22:26:39 1995 --- /usr/src/sys/pdpstand/label.c Tue Aug 1 22:53:43 1995 *************** *** 1,7 **** /*- * Public domain, May 1995 * ! * @(#)label.c 1.0 (2.11BSD GTE) 1995/06/08 */ #include "../h/param.h" --- 1,14 ---- /*- * Public domain, May 1995 * ! * @(#)label.c 1.1 (2.11BSD GTE) 1995/08/01 ! * ! * Date: 1995/08/01 ! * Move the check for a partition number being out of bounds to the ! * readlabel routine. This is necessary in order to permit unlabeled disks ! * (or disks whose label is corrupt) to be open'd. This check can't be done ! * in the open routine because a corrupt or missing label could have garbage ! * for the number of partitions. */ #include "../h/param.h" *************** *** 45,50 **** --- 52,64 ---- { printf("%s%d,%d disklabel missing or corrupt\n", name, io->i_ctlr, io->i_unit); + return(-1); + } + if (io->i_part >= lp->d_npartitions || + lp->d_partitions[io->i_part].p_size == 0) + { + printf("%s%d,%d%c bad partition # or size = 0\n", + name, io->i_ctlr, io->i_unit, 'a' + io->i_part); return(-1); } return(0); *** /usr/src/sys/pdpstand/ra.c.old Tue Jul 11 20:06:43 1995 --- /usr/src/sys/pdpstand/ra.c Tue Aug 1 22:50:48 1995 *************** *** 3,9 **** * All rights reserved. The Berkeley software License Agreement * specifies the terms and conditions for redistribution. * ! * @(#)ra.c 2.5 (2.11BSD GTE) 1995/07/10 */ /* --- 3,9 ---- * All rights reserved. The Berkeley software License Agreement * specifies the terms and conditions for redistribution. * ! * @(#)ra.c 2.6 (2.11BSD GTE) 1995/08/01 */ /* *************** *** 105,117 **** return(-1); if (devlabel(io, READLABEL) == -1) return(-1); - if (io->i_part >= lp->d_npartitions || - lp->d_partitions[io->i_part].p_size == 0) - { - printf("ra%d,%d%c bad partition # or size = 0\n", - ctlr, unit, 'a' + io->i_part); - return(-1); - } io->i_boff = lp->d_partitions[io->i_part].p_offset; return(0); } --- 105,110 ---- *** /usr/src/sys/pdpstand/rl.c.old Thu Jun 15 20:53:15 1995 --- /usr/src/sys/pdpstand/rl.c Tue Aug 1 22:50:24 1995 *************** *** 3,9 **** * All rights reserved. The Berkeley software License Agreement * specifies the terms and conditions for redistribution. * ! * @(#)rl.c 2.3 (2.11BSD) 1995/06/15 */ /* --- 3,9 ---- * All rights reserved. The Berkeley software License Agreement * specifies the terms and conditions for redistribution. * ! * @(#)rl.c 2.4 (2.11BSD) 1995/08/01 */ /* *************** *** 140,152 **** rlgsts(io); /* get status and head position */ if (devlabel(io, READLABEL) < 0) return(-1); - if (part >= lp->d_npartitions || - lp->d_partitions[part].p_size == 0) - { - printf("rl%d,%d%c bad partition # or size = 0\n", - io->i_ctlr, io->i_unit, 'a' + part); - return(-1); - } io->i_boff = lp->d_partitions[part].p_offset; return(0); } --- 140,145 ---- *** /VERSION.old Sat Jul 15 21:47:15 1995 --- /VERSION Mon Jul 24 20:28:31 1995 *************** *** 1,4 **** ! Current Patch Level: 268 2.11 BSD ============ --- 1,4 ---- ! Current Patch Level: 269 2.11 BSD ============