Extract common code from i386, xen, and sparc64, creating

config_handle_wedges() and read_disk_sectors().  On x86, handle_wedges()
is a thin wrapper for config_handle_wedges().  Share opendisk()
across architectures.

Add kernel code in support of specifying a root partition by wedge
name.  E.g., root specifications "wedge:wd0a", "wedge:David's Root
Volume" are possible.  (Patches for config(1) coming soon.)

In support of moving disks between architectures (esp. i386 <->
evbmips), I've written a routine convertdisklabel() that ensures
that the raw partition is at RAW_DISK by following these steps:

        0 If we have read a disklabel that has a RAW_PART with
          p_offset == 0 and p_size != 0, then use that raw partition.

        1 If we have read a disklabel that has both partitions 'c'
          and 'd', and RAW_PART has p_offset != 0 or p_size == 0,
          but the other partition is suitable for a raw partition
          (p_offset == 0, p_size != 0), then swap the two partitions
          and use the new raw partition.

        2 If the architecture's raw partition is 'd', and if there
          is no partition 'd', but there is a partition 'c' that
          is suitable for a raw partition, then copy partition 'c'
          to partition 'd'.

        3 Determine the drive's last sector, using either the
          d_secperunit the drive reported, or by guessing (0x1fffffff).
          If we cannot read the drive's last sector, then fail.

        4 If we have read a disklabel that has no partition slot
          RAW_PART, then create a partition RAW_PART.  Make it span
          the whole drive.

        5 If there are fewer than MAXPARTITIONS partitions,
          then "slide" the unsuitable raw partition RAW_PART, and
          subsequent partitions, into partition slots RAW_PART+1
          and subsequent slots.  Create a raw partition at RAW_PART.
          Make it span the whole drive.

The convertdisklabel() procedure can probably stand to be simplified,
but it ought to deal with all but an extraordinarily broken disklabel,
now.

i386: compiled and tested, sparc64: compiled, evbmips: compiled.
This commit is contained in:
dyoung 2007-06-24 01:43:34 +00:00
parent 82cc8fc351
commit 1ee8f4a418
12 changed files with 333 additions and 329 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: disksubr.c,v 1.12 2007/03/06 00:48:08 simonb Exp $ */
/* $NetBSD: disksubr.c,v 1.13 2007/06/24 01:43:34 dyoung Exp $ */
/*
* Copyright (c) 1982, 1986, 1988 Regents of the University of California.
@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: disksubr.c,v 1.12 2007/03/06 00:48:08 simonb Exp $");
__KERNEL_RCSID(0, "$NetBSD: disksubr.c,v 1.13 2007/06/24 01:43:34 dyoung Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -54,6 +54,7 @@ readdisklabel(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp,
struct disklabel *dlp;
struct dkbad *bdp;
const char *msg = NULL;
uint32_t secperunit;
int i;
/* minimal requirements for archtypal disk label */
@ -66,19 +67,16 @@ readdisklabel(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp,
lp->d_partitions[RAW_PART].p_size = lp->d_secperunit;
lp->d_partitions[RAW_PART].p_offset = 0;
secperunit = lp->d_secperunit;
/* obtain buffer to probe drive with */
bp = geteblk((int)lp->d_secsize);
/* next, dig out disk label */
bp->b_dev = dev;
bp->b_blkno = LABELSECTOR;
bp->b_cylinder = 0;
bp->b_bcount = lp->d_secsize;
bp->b_flags |= B_READ;
(*strat)(bp);
/* if successful, locate disk label within block and validate */
if (biowait(bp)) {
/* Next, dig out disk label. If successful, locate disk
* label within block and validate.
*/
if (disk_read_sectors(strat, lp, bp, LABELSECTOR, 1) != 0) {
msg = "disk label read error";
goto done;
}
@ -103,6 +101,9 @@ readdisklabel(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp,
if (msg)
goto done;
if ((msg = convertdisklabel(lp, strat, bp, secperunit)) != NULL)
goto done;
/* obtain bad sector table if requested and present */
if (clp && (bdp = &clp->bad) != NULL && (lp->d_flags & D_BADSECT)) {
struct dkbad *db;

View File

@ -1,4 +1,4 @@
/* $NetBSD: autoconf.c,v 1.137 2007/03/04 06:00:50 christos Exp $ */
/* $NetBSD: autoconf.c,v 1.138 2007/06/24 01:43:34 dyoung Exp $ */
/*
* Copyright (c) 1996
@ -48,7 +48,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: autoconf.c,v 1.137 2007/03/04 06:00:50 christos Exp $");
__KERNEL_RCSID(0, "$NetBSD: autoconf.c,v 1.138 2007/06/24 01:43:34 dyoung Exp $");
#include "opt_ddb.h"
#include "opt_kgdb.h"
@ -430,58 +430,9 @@ cpu_configure(void)
(void)spl0();
}
static struct vnode *
opendisk(struct device *dv)
{
int bmajor, bminor;
struct vnode *tmpvn;
int error;
dev_t dev;
/*
* Lookup major number for disk block device.
*/
bmajor = devsw_name2blk(device_xname(dv), NULL, 0);
if (bmajor == -1)
return NULL;
bminor = minor(device_unit(dv));
/*
* Fake a temporary vnode for the disk, open it, and read
* and hash the sectors.
*/
dev = device_is_a(dv, "dk") ? makedev(bmajor, bminor) :
MAKEDISKDEV(bmajor, bminor, RAW_PART);
if (bdevvp(dev, &tmpvn))
panic("%s: can't alloc vnode for %s", __func__,
device_xname(dv));
error = VOP_OPEN(tmpvn, FREAD, NOCRED, 0);
if (error) {
#ifndef DEBUG
/*
* Ignore errors caused by missing device, partition,
* or medium.
*/
if (error != ENXIO && error != ENODEV)
#endif
printf("%s: can't open dev %s (%d)\n",
__func__, device_xname(dv), error);
vput(tmpvn);
return NULL;
}
return tmpvn;
}
void
cpu_rootconf(void)
{
struct dkwedge_list wl;
struct dkwedge_info *wi;
struct vnode *vn;
char diskname[16];
int i, error;
if (booted_device == NULL) {
printf("FATAL: boot device not found, check your firmware "
"settings!\n");
@ -489,37 +440,10 @@ cpu_rootconf(void)
return;
}
if ((vn = opendisk(booted_device)) == NULL)
goto nowedge;
wl.dkwl_bufsize = sizeof(*wi) * 16;
wl.dkwl_buf = wi = malloc(wl.dkwl_bufsize, M_TEMP, M_WAITOK);
error = VOP_IOCTL(vn, DIOCLWEDGES, &wl, FREAD, NOCRED, 0);
VOP_CLOSE(vn, FREAD, NOCRED, 0);
vput(vn);
if (error)
goto nowedge2;
snprintf(diskname, sizeof(diskname), "%s%c",
device_xname(booted_device),
booted_partition + 'a');
for (i = 0; i < wl.dkwl_ncopied; i++) {
if (strcmp(wi[i].dkw_wname, diskname) == 0)
break;
}
if (i == wl.dkwl_ncopied)
goto nowedge2;
dkwedge_set_bootwedge(booted_device, wi[i].dkw_offset, wi[i].dkw_size);
free(wi, M_TEMP);
setroot(booted_wedge, 0);
return;
nowedge2:
free(wi, M_TEMP);
nowedge:
setroot(booted_device, booted_partition);
if (config_handle_wedges(booted_device, booted_partition) == 0)
setroot(booted_wedge, 0);
else
setroot(booted_device, booted_partition);
}
char *

View File

@ -1,4 +1,4 @@
/* $NetBSD: x86_autoconf.c,v 1.25 2007/03/04 06:01:09 christos Exp $ */
/* $NetBSD: x86_autoconf.c,v 1.26 2007/06/24 01:43:34 dyoung Exp $ */
/*-
* Copyright (c) 1990 The Regents of the University of California.
@ -65,114 +65,15 @@ __KERNEL_RCSID(0, "$NetBSD");
struct disklist *x86_alldisks;
int x86_ndisks;
static struct vnode *
opendisk(struct device *dv)
{
int bmajor, bminor;
struct vnode *tmpvn;
int error;
dev_t dev;
/*
* Lookup major number for disk block device.
*/
bmajor = devsw_name2blk(dv->dv_xname, NULL, 0);
if (bmajor == -1)
return NULL;
bminor = minor(device_unit(dv));
/*
* Fake a temporary vnode for the disk, open it, and read
* and hash the sectors.
*/
dev = device_is_a(dv, "dk") ? makedev(bmajor, bminor) :
MAKEDISKDEV(bmajor, bminor, RAW_PART);
if (bdevvp(dev, &tmpvn))
panic("%s: can't alloc vnode for %s", __func__, dv->dv_xname);
error = VOP_OPEN(tmpvn, FREAD, NOCRED, 0);
if (error) {
#ifndef DEBUG
/*
* Ignore errors caused by missing device, partition,
* or medium.
*/
if (error != ENXIO && error != ENODEV)
#endif
printf("%s: can't open dev %s (%d)\n",
__func__, dv->dv_xname, error);
vput(tmpvn);
return NULL;
}
return tmpvn;
}
static void
handle_wedges(struct device *dv, int par)
{
struct dkwedge_list wl;
struct dkwedge_info *wi;
struct vnode *vn;
char diskname[16];
int i, error;
if ((vn = opendisk(dv)) == NULL)
goto out;
wl.dkwl_bufsize = sizeof(*wi) * 16;
wl.dkwl_buf = wi = malloc(wl.dkwl_bufsize, M_TEMP, M_WAITOK);
error = VOP_IOCTL(vn, DIOCLWEDGES, &wl, FREAD, NOCRED, 0);
VOP_CLOSE(vn, FREAD, NOCRED, 0);
vput(vn);
if (error) {
#ifdef DEBUG_WEDGE
printf("%s: List wedges returned %d\n", dv->dv_xname, error);
#endif
free(wi, M_TEMP);
goto out;
}
#ifdef DEBUG_WEDGE
printf("%s: Returned %u(%u) wedges\n", dv->dv_xname,
wl.dkwl_nwedges, wl.dkwl_ncopied);
#endif
snprintf(diskname, sizeof(diskname), "%s%c", dv->dv_xname,
par + 'a');
for (i = 0; i < wl.dkwl_ncopied; i++) {
#ifdef DEBUG_WEDGE
printf("%s: Looking for %s in %s\n",
dv->dv_xname, diskname, wi[i].dkw_wname);
#endif
if (strcmp(wi[i].dkw_wname, diskname) == 0)
break;
}
if (i == wl.dkwl_ncopied) {
#ifdef DEBUG_WEDGE
printf("%s: Cannot find wedge with parent %s\n",
dv->dv_xname, diskname);
#endif
free(wi, M_TEMP);
goto out;
}
#ifdef DEBUG_WEDGE
printf("%s: Setting boot wedge %s (%s) at %llu %llu\n",
dv->dv_xname, wi[i].dkw_devname, wi[i].dkw_wname,
(unsigned long long)wi[i].dkw_offset,
(unsigned long long)wi[i].dkw_size);
#endif
dkwedge_set_bootwedge(dv, wi[i].dkw_offset, wi[i].dkw_size);
free(wi, M_TEMP);
return;
out:
if (config_handle_wedges(dv, par) == 0)
return;
booted_device = dv;
booted_partition = par;
}
static int
is_valid_disk(struct device *dv)
{

View File

@ -1,4 +1,4 @@
/* $NetBSD: autoconf.c,v 1.23 2007/05/17 14:51:35 yamt Exp $ */
/* $NetBSD: autoconf.c,v 1.24 2007/06/24 01:43:34 dyoung Exp $ */
/* NetBSD: autoconf.c,v 1.75 2003/12/30 12:33:22 pk Exp */
/*-
@ -45,7 +45,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: autoconf.c,v 1.23 2007/05/17 14:51:35 yamt Exp $");
__KERNEL_RCSID(0, "$NetBSD: autoconf.c,v 1.24 2007/06/24 01:43:34 dyoung Exp $");
#include "opt_xen.h"
#include "opt_compat_oldboot.h"
@ -94,7 +94,6 @@ static int match_harddisk(struct device *, struct btinfo_bootdisk *);
static void matchbiosdisks(void);
static void findroot(void);
static int is_valid_disk(struct device *);
static struct vnode *opendisk(struct device *);
static void handle_wedges(struct device *, int);
struct disklist *x86_alldisks;
@ -568,104 +567,11 @@ found:
booted_device = dev;
}
static struct vnode *
opendisk(struct device *dv)
{
int bmajor;
struct vnode *tmpvn;
int error;
/*
* Lookup major number for disk block device.
*/
bmajor = devsw_name2blk(dv->dv_xname, NULL, 0);
if (bmajor == -1)
return NULL;
/*
* Fake a temporary vnode for the disk, open it, and read
* and hash the sectors.
*/
if (bdevvp(MAKEDISKDEV(bmajor, device_unit(dv), RAW_PART), &tmpvn))
panic("%s: can't alloc vnode for %s", __func__, dv->dv_xname);
error = VOP_OPEN(tmpvn, FREAD, NOCRED, 0);
if (error) {
#ifndef DEBUG
/*
* Ignore errors caused by missing device, partition,
* or medium.
*/
if (error != ENXIO && error != ENODEV)
#endif
printf("%s: can't open dev %s (%d)\n",
__func__, dv->dv_xname, error);
vput(tmpvn);
return NULL;
}
return tmpvn;
}
static void
handle_wedges(struct device *dv, int par)
{
struct dkwedge_list wl;
struct dkwedge_info *wi;
struct vnode *vn;
char diskname[16];
int i, error;
if ((vn = opendisk(dv)) == NULL)
goto out;
wl.dkwl_bufsize = sizeof(*wi) * 16;
wl.dkwl_buf = wi = malloc(wl.dkwl_bufsize, M_TEMP, M_WAITOK);
error = VOP_IOCTL(vn, DIOCLWEDGES, &wl, FREAD, NOCRED, 0);
vput(vn);
if (error) {
#ifdef DEBUG_WEDGE
printf("%s: List wedges returned %d\n", dv->dv_xname, error);
#endif
free(wi, M_TEMP);
goto out;
}
#ifdef DEBUG_WEDGE
printf("%s: Returned %u(%u) wedges\n", dv->dv_xname,
wl.dkwl_nwedges, wl.dkwl_ncopied);
#endif
snprintf(diskname, sizeof(diskname), "%s%c", dv->dv_xname,
par + 'a');
for (i = 0; i < wl.dkwl_ncopied; i++) {
#ifdef DEBUG_WEDGE
printf("%s: Looking for %s in %s\n",
dv->dv_xname, diskname, wi[i].dkw_wname);
#endif
if (strcmp(wi[i].dkw_wname, diskname) == 0)
break;
}
if (i == wl.dkwl_ncopied) {
#ifdef DEBUG_WEDGE
printf("%s: Cannot find wedge with parent %s\n",
dv->dv_xname, diskname);
#endif
free(wi, M_TEMP);
goto out;
}
#ifdef DEBUG_WEDGE
printf("%s: Setting boot wedge %s (%s) at %llu %llu\n",
dv->dv_xname, wi[i].dkw_devname, wi[i].dkw_wname,
(unsigned long long)wi[i].dkw_offset,
(unsigned long long)wi[i].dkw_size);
#endif
dkwedge_set_bootwedge(dv, wi[i].dkw_offset, wi[i].dkw_size);
free(wi, M_TEMP);
return;
out:
if (config_handle_wedges(dv, par) == 0)
return;
booted_device = dv;
booted_partition = par;
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: dk.c,v 1.24 2007/06/16 18:11:33 christos Exp $ */
/* $NetBSD: dk.c,v 1.25 2007/06/24 01:43:34 dyoung Exp $ */
/*-
* Copyright (c) 2004 The NetBSD Foundation, Inc.
@ -37,7 +37,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: dk.c,v 1.24 2007/06/16 18:11:33 christos Exp $");
__KERNEL_RCSID(0, "$NetBSD: dk.c,v 1.25 2007/06/24 01:43:34 dyoung Exp $");
#include "opt_dkwedge.h"
@ -642,6 +642,47 @@ dkwedge_list(struct disk *pdk, struct dkwedge_list *dkwl, struct lwp *l)
return (error);
}
device_t
dkwedge_find_by_wname(const char *wname)
{
device_t dv = NULL;
struct dkwedge_softc *sc;
int i;
(void) lockmgr(&dkwedges_lock, LK_EXCLUSIVE, NULL);
for (i = 0; i < ndkwedges; i++) {
if ((sc = dkwedges[i]) == NULL)
continue;
if (strcmp(sc->sc_wname, wname) == 0) {
if (dv != NULL) {
printf(
"WARNING: double match for wedge name %s "
"(%s, %s)\n", wname, device_xname(dv),
device_xname(sc->sc_dev));
continue;
}
dv = sc->sc_dev;
}
}
(void) lockmgr(&dkwedges_lock, LK_RELEASE, NULL);
return dv;
}
void
dkwedge_print_wnames(void)
{
struct dkwedge_softc *sc;
int i;
(void) lockmgr(&dkwedges_lock, LK_EXCLUSIVE, NULL);
for (i = 0; i < ndkwedges; i++) {
if ((sc = dkwedges[i]) == NULL)
continue;
printf(" wedge:%s", sc->sc_wname);
}
(void) lockmgr(&dkwedges_lock, LK_RELEASE, NULL);
}
/*
* dkwedge_set_bootwedge
*

View File

@ -1,4 +1,4 @@
/* $NetBSD: kern_subr.c,v 1.158 2007/06/03 07:47:50 dsl Exp $ */
/* $NetBSD: kern_subr.c,v 1.159 2007/06/24 01:43:34 dyoung Exp $ */
/*-
* Copyright (c) 1997, 1998, 1999, 2002 The NetBSD Foundation, Inc.
@ -86,7 +86,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: kern_subr.c,v 1.158 2007/06/03 07:47:50 dsl Exp $");
__KERNEL_RCSID(0, "$NetBSD: kern_subr.c,v 1.159 2007/06/24 01:43:34 dyoung Exp $");
#include "opt_ddb.h"
#include "opt_md.h"
@ -105,6 +105,7 @@ __KERNEL_RCSID(0, "$NetBSD: kern_subr.c,v 1.158 2007/06/03 07:47:50 dsl Exp $");
#include <sys/device.h>
#include <sys/reboot.h>
#include <sys/conf.h>
#include <sys/disk.h>
#include <sys/disklabel.h>
#include <sys/queue.h>
#include <sys/systrace.h>
@ -122,6 +123,7 @@ __KERNEL_RCSID(0, "$NetBSD: kern_subr.c,v 1.158 2007/06/03 07:47:50 dsl Exp $");
static struct device *finddevice(const char *);
static struct device *getdisk(char *, int, int, dev_t *, int);
static struct device *parsedisk(char *, int, int, dev_t *);
static const char *getwedgename(const char *, int);
/*
* A generic linear hook.
@ -811,7 +813,7 @@ void
setroot(struct device *bootdv, int bootpartition)
{
struct device *dv;
int len;
int len, majdev;
#ifdef MEMORY_DISK_HOOKS
int i;
#endif
@ -1011,8 +1013,6 @@ setroot(struct device *bootdv, int bootpartition)
}
} else if (rootspec == NULL) {
int majdev;
/*
* Wildcarded root; use the boot device.
*/
@ -1047,6 +1047,11 @@ setroot(struct device *bootdv, int bootpartition)
goto haveroot;
}
if (rootdev == NODEV &&
device_class(dv) == DV_DISK && device_is_a(dv, "dk") &&
(majdev = devsw_name2blk(dv->dv_xname, NULL, 0)) >= 0)
rootdev = makedev(majdev, device_unit(dv));
rootdevname = devsw_blk2name(major(rootdev));
if (rootdevname == NULL) {
printf("unknown device major 0x%x\n", rootdev);
@ -1152,25 +1157,27 @@ setroot(struct device *bootdv, int bootpartition)
static struct device *
finddevice(const char *name)
{
const char *wname;
struct device *dv;
#if defined(BOOT_FROM_MEMORY_HOOKS)
int j;
#endif /* BOOT_FROM_MEMORY_HOOKS */
if ((wname = getwedgename(name, strlen(name))) != NULL)
return dkwedge_find_by_wname(wname);
#ifdef BOOT_FROM_MEMORY_HOOKS
for (j = 0; j < NMD; j++) {
if (strcmp(name, fakemdrootdev[j].dv_xname) == 0) {
dv = &fakemdrootdev[j];
return (dv);
}
if (strcmp(name, fakemdrootdev[j].dv_xname) == 0)
return &fakemdrootdev[j];
}
#endif /* BOOT_FROM_MEMORY_HOOKS */
for (dv = TAILQ_FIRST(&alldevs); dv != NULL;
dv = TAILQ_NEXT(dv, dv_list))
TAILQ_FOREACH(dv, &alldevs, dv_list) {
if (strcmp(dv->dv_xname, name) == 0)
break;
return (dv);
}
return dv;
}
static struct device *
@ -1198,6 +1205,7 @@ getdisk(char *str, int len, int defpart, dev_t *devp, int isdump)
if (isdump == 0 && device_class(dv) == DV_IFNET)
printf(" %s", dv->dv_xname);
}
dkwedge_print_wnames();
if (isdump)
printf(" none");
#if defined(DDB)
@ -1205,13 +1213,26 @@ getdisk(char *str, int len, int defpart, dev_t *devp, int isdump)
#endif
printf(" halt reboot\n");
}
return (dv);
return dv;
}
static const char *
getwedgename(const char *name, int namelen)
{
const char *wpfx = "wedge:";
const int wpfxlen = strlen(wpfx);
if (namelen < wpfxlen || strncmp(name, wpfx, wpfxlen) != 0)
return NULL;
return name + wpfxlen;
}
static struct device *
parsedisk(char *str, int len, int defpart, dev_t *devp)
{
struct device *dv;
const char *wname;
char *cp, c;
int majdev, part;
#ifdef MEMORY_DISK_HOOKS
@ -1231,7 +1252,13 @@ parsedisk(char *str, int len, int defpart, dev_t *devp)
cp = str + len - 1;
c = *cp;
if (c >= 'a' && c <= ('a' + MAXPARTITIONS - 1)) {
if ((wname = getwedgename(str, len)) != NULL) {
if ((dv = dkwedge_find_by_wname(wname)) == NULL)
return NULL;
part = defpart;
goto gotdisk;
} else if (c >= 'a' && c <= ('a' + MAXPARTITIONS - 1)) {
part = c - 'a';
*cp = '\0';
} else
@ -1248,9 +1275,7 @@ parsedisk(char *str, int len, int defpart, dev_t *devp)
dv = finddevice(str);
if (dv != NULL) {
if (device_class(dv) == DV_DISK) {
#ifdef MEMORY_DISK_HOOKS
gotdisk:
#endif
majdev = devsw_name2blk(dv->dv_xname, NULL, 0);
if (majdev < 0)
panic("parsedisk");

View File

@ -1,4 +1,4 @@
/* $NetBSD: subr_autoconf.c,v 1.117 2007/03/05 20:32:45 drochner Exp $ */
/* $NetBSD: subr_autoconf.c,v 1.118 2007/06/24 01:43:35 dyoung Exp $ */
/*
* Copyright (c) 1996, 2000 Christopher G. Demetriou
@ -77,18 +77,34 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: subr_autoconf.c,v 1.117 2007/03/05 20:32:45 drochner Exp $");
__KERNEL_RCSID(0, "$NetBSD: subr_autoconf.c,v 1.118 2007/06/24 01:43:35 dyoung Exp $");
#include "opt_ddb.h"
#include <sys/param.h>
#include <sys/device.h>
#include <sys/disklabel.h>
#include <sys/conf.h>
#include <sys/kauth.h>
#include <sys/malloc.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/errno.h>
#include <sys/proc.h>
#include <sys/reboot.h>
#include <sys/buf.h>
#include <sys/dirent.h>
#include <sys/lock.h>
#include <sys/vnode.h>
#include <sys/mount.h>
#include <sys/namei.h>
#include <sys/unistd.h>
#include <sys/fcntl.h>
#include <sys/lockf.h>
#include <sys/disk.h>
#include <machine/limits.h>
#include "opt_userconf.h"
@ -187,6 +203,112 @@ static int config_initialized; /* config_init() has been called. */
static int config_do_twiddle;
struct vnode *
opendisk(struct device *dv)
{
int bmajor, bminor;
struct vnode *tmpvn;
int error;
dev_t dev;
/*
* Lookup major number for disk block device.
*/
bmajor = devsw_name2blk(device_xname(dv), NULL, 0);
if (bmajor == -1)
return NULL;
bminor = minor(device_unit(dv));
/*
* Fake a temporary vnode for the disk, open it, and read
* and hash the sectors.
*/
dev = device_is_a(dv, "dk") ? makedev(bmajor, bminor) :
MAKEDISKDEV(bmajor, bminor, RAW_PART);
if (bdevvp(dev, &tmpvn))
panic("%s: can't alloc vnode for %s", __func__,
device_xname(dv));
error = VOP_OPEN(tmpvn, FREAD, NOCRED, 0);
if (error) {
#ifndef DEBUG
/*
* Ignore errors caused by missing device, partition,
* or medium.
*/
if (error != ENXIO && error != ENODEV)
#endif
printf("%s: can't open dev %s (%d)\n",
__func__, device_xname(dv), error);
vput(tmpvn);
return NULL;
}
return tmpvn;
}
int
config_handle_wedges(struct device *dv, int par)
{
struct dkwedge_list wl;
struct dkwedge_info *wi;
struct vnode *vn;
char diskname[16];
int i, error;
if ((vn = opendisk(dv)) == NULL)
return -1;
wl.dkwl_bufsize = sizeof(*wi) * 16;
wl.dkwl_buf = wi = malloc(wl.dkwl_bufsize, M_TEMP, M_WAITOK);
error = VOP_IOCTL(vn, DIOCLWEDGES, &wl, FREAD, NOCRED, 0);
VOP_CLOSE(vn, FREAD, NOCRED, 0);
vput(vn);
if (error) {
#ifdef DEBUG_WEDGE
printf("%s: List wedges returned %d\n",
device_xname(dv), error);
#endif
free(wi, M_TEMP);
return -1;
}
#ifdef DEBUG_WEDGE
printf("%s: Returned %u(%u) wedges\n", device_xname(dv),
wl.dkwl_nwedges, wl.dkwl_ncopied);
#endif
snprintf(diskname, sizeof(diskname), "%s%c", device_xname(dv),
par + 'a');
for (i = 0; i < wl.dkwl_ncopied; i++) {
#ifdef DEBUG_WEDGE
printf("%s: Looking for %s in %s\n",
device_xname(dv), diskname, wi[i].dkw_wname);
#endif
if (strcmp(wi[i].dkw_wname, diskname) == 0)
break;
}
if (i == wl.dkwl_ncopied) {
#ifdef DEBUG_WEDGE
printf("%s: Cannot find wedge with parent %s\n",
device_xname(dv), diskname);
#endif
free(wi, M_TEMP);
return -1;
}
#ifdef DEBUG_WEDGE
printf("%s: Setting boot wedge %s (%s) at %llu %llu\n",
device_xname(dv), wi[i].dkw_devname, wi[i].dkw_wname,
(unsigned long long)wi[i].dkw_offset,
(unsigned long long)wi[i].dkw_size);
#endif
dkwedge_set_bootwedge(dv, wi[i].dkw_offset, wi[i].dkw_size);
free(wi, M_TEMP);
return 0;
}
/*
* Initialize the autoconfiguration data structures. Normally this
* is done by configure(), but some platforms need to do this very

View File

@ -1,4 +1,4 @@
/* $NetBSD: subr_disk.c,v 1.85 2007/03/04 06:03:07 christos Exp $ */
/* $NetBSD: subr_disk.c,v 1.86 2007/06/24 01:43:35 dyoung Exp $ */
/*-
* Copyright (c) 1996, 1997, 1999, 2000 The NetBSD Foundation, Inc.
@ -74,7 +74,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: subr_disk.c,v 1.85 2007/03/04 06:03:07 christos Exp $");
__KERNEL_RCSID(0, "$NetBSD: subr_disk.c,v 1.86 2007/06/24 01:43:35 dyoung Exp $");
#include <sys/param.h>
#include <sys/kernel.h>
@ -266,6 +266,7 @@ disk_detach(struct disk *diskp)
{
(void) lockmgr(&diskp->dk_openlock, LK_DRAIN, NULL);
(void) lockmgr(&diskp->dk_rawlock, LK_DRAIN, NULL);
disk_detach0(diskp);
}
@ -430,6 +431,81 @@ bad:
return (-1);
}
int
disk_read_sectors(void (*strat)(struct buf *), const struct disklabel *lp,
struct buf *bp, unsigned int sector, int count)
{
bp->b_blkno = sector;
bp->b_bcount = count * lp->d_secsize;
bp->b_flags = (bp->b_flags & ~(B_WRITE | B_DONE)) | B_READ;
bp->b_cylinder = sector / lp->d_secpercyl;
(*strat)(bp);
return biowait(bp);
}
const char *
convertdisklabel(struct disklabel *lp, void (*strat)(struct buf *),
struct buf *bp, uint32_t secperunit)
{
struct partition rp, *altp, *p;
int geom_ok;
memset(&rp, 0, sizeof(rp));
rp.p_size = secperunit;
rp.p_fstype = FS_UNUSED;
/* If we can seek to d_secperunit - 1, believe the disk geometry. */
if (secperunit != 0 &&
disk_read_sectors(strat, lp, bp, secperunit - 1, 1) == 0)
geom_ok = 1;
else
geom_ok = 0;
#if 0
printf("%s: secperunit (%" PRIu32 ") %s\n", __func__,
secperunit, geom_ok ? "ok" : "not ok");
#endif
p = &lp->d_partitions[RAW_PART];
if (RAW_PART == 'c' - 'a')
altp = &lp->d_partitions['d' - 'a'];
else
altp = &lp->d_partitions['c' - 'a'];
if (lp->d_npartitions > RAW_PART && p->p_offset == 0 && p->p_size != 0)
; /* already a raw partition */
else if (lp->d_npartitions > MAX('c', 'd') - 'a' &&
altp->p_offset == 0 && altp->p_size != 0) {
/* alternate partition ('c' or 'd') is suitable for raw slot,
* swap with 'd' or 'c'.
*/
rp = *p;
*p = *altp;
*altp = rp;
} else if (lp->d_npartitions <= RAW_PART &&
lp->d_npartitions > 'c' - 'a') {
/* No raw partition is present, but the alternate is present.
* Copy alternate to raw partition.
*/
lp->d_npartitions = RAW_PART + 1;
*p = *altp;
} else if (!geom_ok)
return "no raw partition and disk reports bad geometry";
else if (lp->d_npartitions <= RAW_PART) {
memset(&lp->d_partitions[lp->d_npartitions], 0,
sizeof(struct partition) * (RAW_PART - lp->d_npartitions));
*p = rp;
lp->d_npartitions = RAW_PART + 1;
} else if (lp->d_npartitions < MAXPARTITIONS) {
memmove(p + 1, p,
sizeof(struct partition) * (lp->d_npartitions - RAW_PART));
*p = rp;
lp->d_npartitions++;
} else
return "no raw partition and partition table is full";
return NULL;
}
/*
* disk_ioctl --
* Generic disk ioctl handling.

View File

@ -1,4 +1,4 @@
/* $NetBSD: subr_disk_mbr.c,v 1.27 2007/06/14 17:18:40 dyoung Exp $ */
/* $NetBSD: subr_disk_mbr.c,v 1.28 2007/06/24 01:43:35 dyoung Exp $ */
/*
* Copyright (c) 1982, 1986, 1988 Regents of the University of California.
@ -54,7 +54,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: subr_disk_mbr.c,v 1.27 2007/06/14 17:18:40 dyoung Exp $");
__KERNEL_RCSID(0, "$NetBSD: subr_disk_mbr.c,v 1.28 2007/06/24 01:43:35 dyoung Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -93,6 +93,7 @@ typedef struct mbr_args {
int found_mbr; /* set if disk has a valid mbr */
uint label_sector; /* where we found the label */
int action;
uint32_t secperunit;
#define READ_LABEL 1
#define UPDATE_LABEL 2
#define WRITE_LABEL 3
@ -105,15 +106,9 @@ static int write_netbsd_label(mbr_args_t *, mbr_partition_t *, int, uint);
static int
read_sector(mbr_args_t *a, uint sector, int count)
{
struct buf *bp = a->bp;
int error;
bp->b_blkno = sector;
bp->b_bcount = count * a->lp->d_secsize;
bp->b_flags = (bp->b_flags & ~(B_WRITE | B_DONE)) | B_READ;
bp->b_cylinder = sector / a->lp->d_secpercyl;
(*a->strat)(bp);
error = biowait(bp);
error = disk_read_sectors(a->strat, a->lp, a->bp, sector, count);
if (error != 0)
a->error = error;
return error;
@ -265,6 +260,7 @@ readdisklabel(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp,
lp->d_secsize = DEV_BSIZE;
if (lp->d_secperunit == 0)
lp->d_secperunit = 0x1fffffff;
a.secperunit = lp->d_secperunit;
lp->d_npartitions = RAW_PART + 1;
for (i = 0; i < RAW_PART; i++) {
lp->d_partitions[i].p_size = 0;
@ -459,6 +455,9 @@ validate_label(mbr_args_t *a, uint label_sector)
switch (a->action) {
case READ_LABEL:
*a->lp = *dlp;
if ((a->msg = convertdisklabel(a->lp, a->strat, a->bp,
a->secperunit)) != NULL)
return SCAN_ERROR;
a->label_sector = label_sector;
return SCAN_FOUND;
case UPDATE_LABEL:

View File

@ -1,4 +1,4 @@
/* $NetBSD: device.h,v 1.94 2007/03/05 20:32:43 drochner Exp $ */
/* $NetBSD: device.h,v 1.95 2007/06/24 01:43:35 dyoung Exp $ */
/*
* Copyright (c) 1996, 2000 Christopher G. Demetriou
@ -307,6 +307,9 @@ extern int booted_partition; /* or the partition on that device */
extern volatile int config_pending; /* semaphore for mountroot */
struct vnode *opendisk(struct device *);
int config_handle_wedges(struct device *, int);
void config_init(void);
void configure(void);

View File

@ -1,4 +1,4 @@
/* $NetBSD: disk.h,v 1.43 2007/03/04 06:03:40 christos Exp $ */
/* $NetBSD: disk.h,v 1.44 2007/06/24 01:43:35 dyoung Exp $ */
/*-
* Copyright (c) 1996, 1997, 2004 The NetBSD Foundation, Inc.
@ -86,6 +86,7 @@
* Disk device structures.
*/
#include <sys/device.h>
#include <sys/dkio.h>
#include <sys/time.h>
#include <sys/queue.h>
@ -496,7 +497,6 @@ struct disk_strategy {
#ifdef _KERNEL
extern int disk_count; /* number of disks in global disklist */
struct device;
struct proc;
void disk_attach(struct disk *);
@ -515,8 +515,10 @@ int dkwedge_del(struct dkwedge_info *);
void dkwedge_delall(struct disk *);
int dkwedge_list(struct disk *, struct dkwedge_list *, struct lwp *);
void dkwedge_discover(struct disk *);
void dkwedge_set_bootwedge(struct device *, daddr_t, uint64_t);
void dkwedge_set_bootwedge(device_t, daddr_t, uint64_t);
int dkwedge_read(struct disk *, struct vnode *, daddr_t, void *, size_t);
device_t dkwedge_find_by_wname(const char *);
void dkwedge_print_wnames(void);
#endif
#endif /* _SYS_DISK_H_ */

View File

@ -1,4 +1,4 @@
/* $NetBSD: disklabel.h,v 1.99 2007/03/10 16:42:04 dsl Exp $ */
/* $NetBSD: disklabel.h,v 1.100 2007/06/24 01:43:35 dyoung Exp $ */
/*
* Copyright (c) 1987, 1988, 1993
@ -433,6 +433,8 @@ struct partinfo {
struct disk;
int disk_read_sectors(void (*)(struct buf *), const struct disklabel *,
struct buf *, unsigned int, int);
void diskerr(const struct buf *, const char *, const char *, int,
int, const struct disklabel *);
u_int dkcksum(struct disklabel *);
@ -443,6 +445,8 @@ const char *readdisklabel(dev_t, void (*)(struct buf *),
struct disklabel *, struct cpu_disklabel *);
int writedisklabel(dev_t, void (*)(struct buf *), struct disklabel *,
struct cpu_disklabel *);
const char *convertdisklabel(struct disklabel *, void (*)(struct buf *),
struct buf *, uint32_t);
int bounds_check_with_label(struct disk *, struct buf *, int);
int bounds_check_with_mediasize(struct buf *, int, uint64_t);
#endif