Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 17 Jan 2002 18:07:26 +1100 (EST)
From:      Bruce Evans <bde@zeta.org.au>
To:        Michael Reifenberger <root@nihil.plaut.de>
Cc:        FreeBSD-Current <current@FreeBSD.ORG>
Subject:   Re: panic during fdisk'ing a md(4) device
Message-ID:  <20020117175846.H491-100000@gamplex.bde.org>
In-Reply-To: <20020114152940.W429-200000@nihil>

next in thread | previous in thread | raw e-mail | index | archive | help
On Mon, 14 Jan 2002, Michael Reifenberger wrote:

> On Tue, 15 Jan 2002, Bruce Evans wrote:
> ...
> > Try this version.  Only disklabel.h has many changes.  The code for
> > avoiding creation of bogus 'c' partitions didn't work at all.
>
> This works during startup but the following commands cases a panic
> while executing newfs (BT is attached):
>
> mdconfig -a -t swap -s 128M -o reserve -u 10
> disklabel -r -w md10 auto
>   (When looking into /dev now I see two! md10c devices!)
> newfs -f 4096 /dev/md10c
> tunefs -n enable /dev/md10c
> mount /dev/md10c /tmp

Oops.  There should be no alias for md10c.  Try this version.  It fixes
the "may want an alias case" in dkmodminor() and moves all the dk inlines
to subr_diskslice.c.

%%%
Index: kern/subr_disk.c
===================================================================
RCS file: /home/ncvs/src/sys/kern/subr_disk.c,v
retrieving revision 1.50
diff -u -2 -r1.50 subr_disk.c
--- kern/subr_disk.c	4 Nov 2001 11:56:22 -0000	1.50
+++ kern/subr_disk.c	14 Jan 2002 11:42:38 -0000
@@ -301,5 +301,5 @@

 	error = 0;
-	pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART);
+	pdev = dkmodslice(dkmodpart(dev, -RAW_PART), WHOLE_DISK_SLICE);

 	dp = pdev->si_disk;
@@ -349,5 +349,5 @@

 	error = 0;
-	pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART);
+	pdev = dkmodslice(dkmodpart(dev, -RAW_PART), WHOLE_DISK_SLICE);
 	dp = pdev->si_disk;
 	if (!dp)
@@ -365,5 +365,5 @@
 	struct disk *dp;

-	pdev = dkmodpart(dkmodslice(bp->bio_dev, WHOLE_DISK_SLICE), RAW_PART);
+	pdev = dkmodslice(dkmodpart(bp->bio_dev, -RAW_PART), WHOLE_DISK_SLICE);
 	dp = pdev->si_disk;
 	bp->bio_resid = bp->bio_bcount;
@@ -400,5 +400,5 @@
 	dev_t pdev;

-	pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART);
+	pdev = dkmodslice(dkmodpart(dev, -RAW_PART), WHOLE_DISK_SLICE);
 	dp = pdev->si_disk;
 	if (!dp)
@@ -416,5 +416,5 @@
 	dev_t pdev;

-	pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART);
+	pdev = dkmodslice(dkmodpart(dev, -RAW_PART), WHOLE_DISK_SLICE);
 	dp = pdev->si_disk;
 	if (!dp)
Index: kern/subr_diskmbr.c
===================================================================
RCS file: /home/ncvs/src/sys/kern/subr_diskmbr.c,v
retrieving revision 1.54
diff -u -2 -r1.54 subr_diskmbr.c
--- kern/subr_diskmbr.c	11 Dec 2001 05:35:43 -0000	1.54
+++ kern/subr_diskmbr.c	9 Jan 2002 10:34:30 -0000
@@ -209,5 +209,5 @@
 	/* Read master boot record. */
 	bp = geteblk((int)lp->d_secsize);
-	bp->b_dev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART);
+	bp->b_dev = dkmodslice(dkmodpart(dev, -RAW_PART), WHOLE_DISK_SLICE);
 	bp->b_blkno = mbr_offset;
 	bp->b_bcount = lp->d_secsize;
Index: kern/subr_diskslice.c
===================================================================
RCS file: /home/ncvs/src/sys/kern/subr_diskslice.c,v
retrieving revision 1.96
diff -u -2 -r1.96 subr_diskslice.c
--- kern/subr_diskslice.c	12 Sep 2001 08:37:45 -0000	1.96
+++ kern/subr_diskslice.c	17 Jan 2002 04:19:10 -0000
@@ -68,4 +68,5 @@

 static struct disklabel *clone_label __P((struct disklabel *lp));
+static dev_t dkmodminor __P((dev_t dev, int mynor, int slicehint));
 static void dsiodone __P((struct bio *bp));
 static char *fixlabel __P((char *sname, struct diskslice *sp,
@@ -77,4 +78,5 @@
 			      struct disklabel *lp));
 static void set_ds_labeldevs __P((dev_t dev, struct diskslices *ssp));
+static void set_ds_labeldevs_unaliased __P((dev_t dev, struct diskslices *ssp));
 static void set_ds_wlabel __P((struct diskslices *ssp, int slice,
 			       int wlabel));
@@ -123,4 +125,106 @@

 /*
+ * XXX should be able to share more code between disk_dev_synth(),
+ * disk_clone() and here.
+ * XXX using dsname() only slightly insulates us from complications.
+ */
+static dev_t
+dkmodminor(dev_t dev, int mynor, int slicehint)
+{
+	dev_t newdev, newdev_alias;
+	const char *sname;
+	char partname[2];
+
+	newdev = makedev(major(dev), mynor);
+	if ((dev->si_flags & SI_NAMED) == 0)
+		return (newdev);	/* XXX should panic. */
+ 	if (newdev->si_flags & SI_NAMED) {
+		/* We have found a device, but may want an alias. */
+		if (dkslice(newdev) == WHOLE_DISK_SLICE ||
+		    dkslice(newdev) == COMPATIBILITY_SLICE ||
+		    dkpart(newdev) != RAW_PART || slicehint)
+			return (newdev);
+
+		/* We do want an alias.  There can be only one.  XXX. */
+		newdev_alias = LIST_FIRST(&newdev->si_children);
+		if (newdev_alias != NULL)
+			return (newdev_alias);
+		sname = dsname(dev, dkunit(newdev), dkslice(newdev),
+		    dkpart(newdev), partname);
+		return (make_dev_alias(newdev, "%s%s", sname, partname));
+	}
+	sname = dsname(dev, dkunit(newdev), dkslice(newdev), dkpart(newdev),
+	    partname);
+	if (dkslice(newdev) == WHOLE_DISK_SLICE && dkpart(newdev) != RAW_PART) {
+		printf("bad disk name, sname = '%s', partname = '%s'\n",
+		    sname, partname);
+		Debugger("dkmod");
+	}
+	if (dkslice(newdev) == COMPATIBILITY_SLICE ||
+	    dkpart(newdev) != RAW_PART)
+		return (make_dev(dev->si_devsw, mynor, dev->si_uid,
+		    dev->si_gid, dev->si_mode, "%s%s", sname, partname));
+	newdev = make_dev(dev->si_devsw, mynor, dev->si_uid,
+	    dev->si_gid, dev->si_mode, "%s", sname);
+	if (dkslice(newdev) == WHOLE_DISK_SLICE)
+		return (newdev);
+#if 0
+	newdev_alias = make_dev_alias(newdev, "%s%s", sname, partname);
+#else
+	/*
+	 * Don't blindly create the alias. since it is bogus if the slice
+	 * is unlabeled.  Passing another hint to tell use when to do this
+	 * would be too messy even for this prototype version.  Now there
+	 * are problems getting the alias created if the label is discovered
+	 * later (these are fixed here but not in subr_disk.c).
+	 */
+	if (slicehint)
+		newdev_alias = NULL;
+	else
+		newdev_alias = make_dev_alias(newdev, "%s%s", sname, partname);
+#endif
+	return (slicehint ? newdev : newdev_alias);
+}
+
+dev_t
+dkmodpart(dev_t dev, int part)
+{
+	int slicehint;
+
+	/*
+	 * XXX temporary hack: callers pass part == -RAW_PART instead of
+	 * part == RAW_PART as a hint that they want a device whose name
+	 * doesn't contain the partition letter for RAW_PART, if possible.
+	 * This is possible unless the slice is COMPATIBILITY_SLICE.  This
+	 * is non-optional if the slice is WHOLE_DISK_SLICE.
+	 */
+	if (part == -RAW_PART) {
+		slicehint = 1;
+		part = RAW_PART;
+	} else
+		slicehint = 0;
+	return (dkmodminor(dev, (minor(dev) & ~7) | part, slicehint));
+}
+
+dev_t
+dkmodslice(dev_t dev, int slice)
+{
+	/*
+	 * Here we hint that we don't want a partition letter unless we
+	 * don't already have one, our partition is RAW_PART, and our slice
+	 * is not COMPATIBILITY_SLICE.  These cases are distinguished by
+	 * SI_ALIAS being set.  The hint is not used in other cases.
+	 */
+	return (dkmodminor(dev, (minor(dev) & ~0x1f0000) | (slice << 16),
+	    (dev->si_flags & SI_ALIAS) == 0));
+}
+
+u_int
+dkunit(dev_t dev)
+{
+	return (((minor(dev) >> 16) & 0x1e0) | ((minor(dev) >> 3) & 0x1f));
+}
+
+/*
  * Determine the size of the transfer, and make sure it is
  * within the boundaries of the partition. Adjust transfer
@@ -649,4 +753,5 @@
 	char	*msg;
 	u_char	mask;
+	char	*oldsname;
 	int	part;
 	char	partname[2];
@@ -728,11 +833,29 @@
 		    )
 			continue;
-		dev1 = dkmodslice(dkmodpart(dev, RAW_PART), slice);
-#if 0
-		sname = dsname(dev, unit, slice, RAW_PART, partname);
-#else
-		*partname='\0';
-		sname = dev1->si_name;
-#endif
+		dev1 = dkmodslice(dkmodpart(dev, -RAW_PART), slice);
+		if (dev1->si_devsw == NULL) {
+			Debugger("dsopen: no devsw (can't happen)");
+			dev1->si_devsw = dev->si_devsw;
+		}
+		/*
+		 * XXX we want a device name without any partition letter
+		 * in it for use in error messages.  dev1->si_name doesn't
+		 * give this for the compatibility slice since there is no
+		 * alias for the raw partiton on that slice.
+		 *
+		 * XXX dsname() is only used for the regression check;
+		 * partname is only used to throw away the partition name
+		 * in the regression check.
+		 */
+		if (slice == COMPATIBILITY_SLICE)
+			sname = dkmodslice(dkmodpart(dev, -RAW_PART),
+			    WHOLE_DISK_SLICE)->si_name;
+		else
+			sname = dev1->si_name;
+		oldsname = dsname(dev, unit, slice, RAW_PART, partname);
+		if (strcmp(sname, oldsname) != 0)
+			printf(
+		"dsopen: dsname = '%s', partname = '%s', sname = '%s'\n",
+			    oldsname, partname, sname);
 		/*
 		 * XXX this should probably only be done for the need_init
@@ -969,6 +1092,55 @@
 	struct diskslices *ssp;
 {
+	int	slice;
+
+	set_ds_labeldevs_unaliased(dev, ssp);
+	if (ssp->dss_first_bsd_slice == COMPATIBILITY_SLICE)
+		return;
+	slice = dkslice(dev);
+	if (slice == COMPATIBILITY_SLICE)
+		set_ds_labeldevs_unaliased(
+		    dkmodslice(dev, ssp->dss_first_bsd_slice), ssp);
+	else if (slice == ssp->dss_first_bsd_slice)
+		set_ds_labeldevs_unaliased(
+		    dkmodslice(dev, COMPATIBILITY_SLICE), ssp);
 }

+static void
+set_ds_labeldevs_unaliased(dev, ssp)
+	dev_t	dev;
+	struct diskslices *ssp;
+{
+	struct disklabel *lp;
+	int	part;
+	struct partition *pp;
+	int	slice;
+	struct diskslice *sp;
+
+	slice = dkslice(dev);
+	sp = &ssp->dss_slices[slice];
+	if (sp->ds_size == 0)
+		return;
+	lp = sp->ds_label;
+	for (part = 0; part < lp->d_npartitions; part++) {
+		pp = &lp->d_partitions[part];
+		if (pp->p_size == 0)
+			continue;
+		/*
+		 * Just dkmod'ing to a partition creates all the necessary
+		 * device entries for it.  This is a bit weird, but it
+		 * corresponds to userland stat'ing of nonexistent devfs
+		 * directory entries creating them, and at least we avoid
+		 * creating entries for nonexistent empty devices here.
+		 *
+		 * XXX userland can even exploit bugs to create invalid
+		 * devices, e.g., ones with slice numbers larger than the
+		 * max.  Such slice numbers leak into the unit number
+		 * or so-called "spare" bitfields.
+		 */
+		if (dev->si_flags & SI_ALIAS)
+			Debugger("unexpeced dk alias");
+		(void)dkmodpart(dev, part);
+	}
+}

 static void
Index: sys/disklabel.h
===================================================================
RCS file: /home/ncvs/src/sys/sys/disklabel.h,v
retrieving revision 1.63
diff -u -2 -r1.63 disklabel.h
--- sys/disklabel.h	4 Nov 2001 09:01:02 -0000	1.63
+++ sys/disklabel.h	17 Jan 2002 03:26:30 -0000
@@ -438,26 +438,8 @@
 				(((slice) << 16) | (((unit) & 0x1e0) << 16) | \
 				(((unit) & 0x1f) << 3) | (part))
-static __inline dev_t
-dkmodpart(dev_t dev, int part)
-{
-	return (makedev(major(dev), (minor(dev) & ~7) | part));
-}
-
-static __inline dev_t
-dkmodslice(dev_t dev, int slice)
-{
-	return (makedev(major(dev), (minor(dev) & ~0x1f0000) | (slice << 16)));
-}
-
 #define	dkpart(dev)		(minor(dev) & 7)
 #define	dkslice(dev)		((minor(dev) >> 16) & 0x1f)
 #define	dksparebits(dev)       	((minor(dev) >> 25) & 0x7f)

-static __inline u_int
-dkunit(dev_t dev)
-{
-	return (((minor(dev) >> 16) & 0x1e0) | ((minor(dev) >> 3) & 0x1f));
-}
-
 struct	bio;
 struct	buf;
@@ -470,4 +452,7 @@
 		     struct disklabel *lp));
 void	disksort __P((struct buf *ap, struct buf *bp));
+dev_t	dkmodpart __P((dev_t dev, int part));
+dev_t	dkmodslice __P((dev_t dev, int slice));
+u_int	dkunit __P((dev_t dev));
 char	*readdisklabel __P((dev_t dev, struct disklabel *lp));
 void	bioqdisksort __P((struct bio_queue_head *ap, struct bio *bp));
%%%

Bruce


To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-current" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20020117175846.H491-100000>