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
  ============
