From owner-freebsd-current Wed Jan 16 23: 7:28 2002 Delivered-To: freebsd-current@freebsd.org Received: from mailman.zeta.org.au (mailman.zeta.org.au [203.26.10.16]) by hub.freebsd.org (Postfix) with ESMTP id 1CC6637B405 for ; Wed, 16 Jan 2002 23:07:16 -0800 (PST) Received: from bde.zeta.org.au (bde.zeta.org.au [203.2.228.102]) by mailman.zeta.org.au (8.9.3/8.8.7) with ESMTP id SAA21809; Thu, 17 Jan 2002 18:06:11 +1100 Date: Thu, 17 Jan 2002 18:07:26 +1100 (EST) From: Bruce Evans X-X-Sender: To: Michael Reifenberger Cc: FreeBSD-Current Subject: Re: panic during fdisk'ing a md(4) device In-Reply-To: <20020114152940.W429-200000@nihil> Message-ID: <20020117175846.H491-100000@gamplex.bde.org> MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII Sender: owner-freebsd-current@FreeBSD.ORG Precedence: bulk List-ID: List-Archive: (Web Archive) List-Help: (List Instructions) List-Subscribe: List-Unsubscribe: X-Loop: FreeBSD.ORG 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