Module Name: src
Committed By: hannken
Date: Thu Nov 11 11:07:07 UTC 2010
Modified Files:
src/sys/dev: md.c
src/sys/kern: kern_subr.c
Log Message:
Change md(4) to:
- create md devices on first open and destroy on last close.
- add enough disk label support to make DIOCGDINFO and DIOCGPART work.
- add disk_busy()/disk_unbusy() instrumentation.
Ok: David Young <[email protected]>
To generate a diff of this commit:
cvs rdiff -u -r1.62 -r1.63 src/sys/dev/md.c
cvs rdiff -u -r1.207 -r1.208 src/sys/kern/kern_subr.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/dev/md.c
diff -u src/sys/dev/md.c:1.62 src/sys/dev/md.c:1.63
--- src/sys/dev/md.c:1.62 Thu Jan 21 02:14:42 2010
+++ src/sys/dev/md.c Thu Nov 11 11:07:06 2010
@@ -1,4 +1,4 @@
-/* $NetBSD: md.c,v 1.62 2010/01/21 02:14:42 dyoung Exp $ */
+/* $NetBSD: md.c,v 1.63 2010/11/11 11:07:06 hannken Exp $ */
/*
* Copyright (c) 1995 Gordon W. Ross, Leo Weppelman.
@@ -40,10 +40,9 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: md.c,v 1.62 2010/01/21 02:14:42 dyoung Exp $");
+__KERNEL_RCSID(0, "$NetBSD: md.c,v 1.63 2010/11/11 11:07:06 hannken Exp $");
#include "opt_md.h"
-#include "opt_tftproot.h"
#include <sys/param.h>
#include <sys/kernel.h>
@@ -78,6 +77,7 @@
/* autoconfig stuff... */
struct md_softc {
+ device_t sc_dev; /* Self. */
struct disk sc_dkdev; /* hook for generic disk handling */
struct md_conf sc_md;
struct bufq_state *sc_buflist;
@@ -115,43 +115,23 @@
CFATTACH_DECL3_NEW(md, sizeof(struct md_softc),
0, md_attach, md_detach, NULL, NULL, NULL, DVF_DETACH_SHUTDOWN);
+static kmutex_t md_device_lock; /* Protect unit creation / deletion. */
extern size_t md_root_size;
+static void md_set_disklabel(struct md_softc *);
+
/*
* This is called if we are configured as a pseudo-device
*/
void
mdattach(int n)
{
- int i;
- cfdata_t cf;
-#ifdef TFTPROOT
- /*
- * Attachement of md0 must be done after md_root_setconf(),
- * because the RAMdisk is not loaded yet.
- */
- if (md_root_size == 0)
- return;
-#endif
- if (config_cfattach_attach("md", &md_ca)) {
- printf("md: cfattach_attach failed\n");
+ mutex_init(&md_device_lock, MUTEX_DEFAULT, IPL_NONE);
+ if (config_cfattach_attach(md_cd.cd_name, &md_ca)) {
+ aprint_error("%s: cfattach_attach failed\n", md_cd.cd_name);
return;
}
-
- /* XXX: Are we supposed to provide a default? */
- if (n <= 1)
- n = 1;
-
- /* Attach as if by autoconfig. */
- for (i = 0; i < n; i++) {
- cf = malloc(sizeof(*cf), M_DEVBUF, M_WAITOK);
- cf->cf_name = "md";
- cf->cf_atname = "md";
- cf->cf_unit = i;
- cf->cf_fstate = FSTATE_NOTFOUND;
- (void)config_attach_pseudo(cf);
- }
}
static void
@@ -159,6 +139,7 @@
{
struct md_softc *sc = device_private(self);
+ sc->sc_dev = self;
bufq_alloc(&sc->sc_buflist, "fcfs", 0);
/* XXX - Could accept aux info here to set the config. */
@@ -177,6 +158,9 @@
disk_init(&sc->sc_dkdev, device_xname(self), &mddkdriver);
disk_attach(&sc->sc_dkdev);
+ if (sc->sc_type != MD_UNCONFIGURED)
+ md_set_disklabel(sc);
+
if (!pmf_device_register(self, NULL, NULL))
aprint_error_dev(self, "couldn't establish power handler\n");
}
@@ -240,13 +224,29 @@
int unit;
int part = DISKPART(dev);
int pmask = 1 << part;
+ cfdata_t cf;
struct md_softc *sc;
struct disk *dk;
+ mutex_enter(&md_device_lock);
unit = MD_UNIT(dev);
sc = device_lookup_private(&md_cd, unit);
- if (sc == NULL)
- return ENXIO;
+ if (sc == NULL) {
+ if (part != RAW_PART) {
+ mutex_exit(&md_device_lock);
+ return ENXIO;
+ }
+ cf = malloc(sizeof(*cf), M_DEVBUF, M_WAITOK);
+ cf->cf_name = md_cd.cd_name;
+ cf->cf_atname = md_cd.cd_name;
+ cf->cf_unit = unit;
+ cf->cf_fstate = FSTATE_STAR;
+ sc = device_private(config_attach_pseudo(cf));
+ if (sc == NULL) {
+ mutex_exit(&md_device_lock);
+ return ENOMEM;
+ }
+ }
dk = &sc->sc_dkdev;
@@ -265,8 +265,10 @@
* This is a normal, "slave" device, so
* enforce initialized.
*/
- if (sc->sc_type == MD_UNCONFIGURED)
+ if (sc->sc_type == MD_UNCONFIGURED) {
+ mutex_exit(&md_device_lock);
return ENXIO;
+ }
ok:
/* XXX duplicates code in dk_open(). Call dk_open(), instead? */
@@ -284,6 +286,7 @@
dk->dk_openmask = dk->dk_copenmask | dk->dk_bopenmask;
mutex_exit(&dk->dk_openlock);
+ mutex_exit(&md_device_lock);
return 0;
}
@@ -292,6 +295,8 @@
{
int part = DISKPART(dev);
int pmask = 1 << part;
+ int error;
+ cfdata_t cf;
struct md_softc *sc;
struct disk *dk;
@@ -314,7 +319,14 @@
dk->dk_openmask = dk->dk_copenmask | dk->dk_bopenmask;
mutex_exit(&dk->dk_openlock);
- return 0;
+
+ mutex_enter(&md_device_lock);
+ cf = device_cfdata(sc->sc_dev);
+ error = config_detach(sc->sc_dev, DETACH_QUIET);
+ if (! error)
+ free(cf, M_DEVBUF);
+ mutex_exit(&md_device_lock);
+ return error;
}
static int
@@ -353,6 +365,7 @@
struct md_softc *sc;
void * addr;
size_t off, xfer;
+ bool is_read;
sc = device_lookup_private(&md_cd, MD_UNIT(bp->b_dev));
@@ -375,10 +388,11 @@
case MD_KMEM_FIXED:
case MD_KMEM_ALLOCATED:
/* These are in kernel space. Access directly. */
+ is_read = ((bp->b_flags & B_READ) == B_READ);
bp->b_resid = bp->b_bcount;
off = (bp->b_blkno << DEV_BSHIFT);
if (off >= sc->sc_size) {
- if (bp->b_flags & B_READ)
+ if (is_read)
break; /* EOF */
goto set_eio;
}
@@ -386,10 +400,12 @@
if (xfer > (sc->sc_size - off))
xfer = (sc->sc_size - off);
addr = (char *)sc->sc_addr + off;
- if (bp->b_flags & B_READ)
+ disk_busy(&sc->sc_dkdev);
+ if (is_read)
memcpy(bp->b_data, addr, xfer);
else
memcpy(addr, bp->b_data, xfer);
+ disk_unbusy(&sc->sc_dkdev, xfer, is_read);
bp->b_resid -= xfer;
break;
@@ -408,10 +424,28 @@
{
struct md_softc *sc;
struct md_conf *umd;
+ struct disklabel *lp;
+ struct partinfo *pp;
if ((sc = device_lookup_private(&md_cd, MD_UNIT(dev))) == NULL)
return ENXIO;
+ if (sc->sc_type != MD_UNCONFIGURED) {
+ switch (cmd) {
+ case DIOCGDINFO:
+ lp = (struct disklabel *)data;
+ *lp = *sc->sc_dkdev.dk_label;
+ return 0;
+
+ case DIOCGPART:
+ pp = (struct partinfo *)data;
+ pp->disklab = sc->sc_dkdev.dk_label;
+ pp->part =
+ &sc->sc_dkdev.dk_label->d_partitions[DISKPART(dev)];
+ return 0;
+ }
+ }
+
/* If this is not the raw partition, punt! */
if (DISKPART(dev) != RAW_PART)
return ENOTTY;
@@ -441,6 +475,50 @@
return EINVAL;
}
+static void
+md_set_disklabel(struct md_softc *sc)
+{
+ struct disklabel *lp = sc->sc_dkdev.dk_label;
+ struct partition *pp;
+
+ memset(lp, 0, sizeof(*lp));
+
+ lp->d_secsize = DEV_BSIZE;
+ lp->d_secperunit = sc->sc_size / DEV_BSIZE;
+ if (lp->d_secperunit >= (32*64)) {
+ lp->d_nsectors = 32;
+ lp->d_ntracks = 64;
+ lp->d_ncylinders = lp->d_secperunit / (32*64);
+ } else {
+ lp->d_nsectors = 1;
+ lp->d_ntracks = 1;
+ lp->d_ncylinders = lp->d_secperunit;
+ }
+ lp->d_secpercyl = lp->d_ntracks*lp->d_nsectors;
+
+ strncpy(lp->d_typename, md_cd.cd_name, sizeof(lp->d_typename));
+ lp->d_type = DTYPE_UNKNOWN;
+ strncpy(lp->d_packname, "fictitious", sizeof(lp->d_packname));
+ lp->d_rpm = 3600;
+ lp->d_interleave = 1;
+ lp->d_flags = 0;
+
+ pp = &lp->d_partitions[0];
+ pp->p_offset = 0;
+ pp->p_size = lp->d_secperunit;
+ pp->p_fstype = FS_BSDFFS;
+
+ pp = &lp->d_partitions[RAW_PART];
+ pp->p_offset = 0;
+ pp->p_size = lp->d_secperunit;
+ pp->p_fstype = FS_UNUSED;
+
+ lp->d_npartitions = RAW_PART+1;
+ lp->d_magic = DISKMAGIC;
+ lp->d_magic2 = DISKMAGIC;
+ lp->d_checksum = dkcksum(lp);
+}
+
/*
* Handle ioctl MD_SETCONF for (sc_type == MD_KMEM_ALLOCATED)
* Just allocate some kernel memory and return.
@@ -462,6 +540,7 @@
sc->sc_addr = (void *)addr; /* kernel space */
sc->sc_size = (size_t)size;
sc->sc_type = MD_KMEM_ALLOCATED;
+ md_set_disklabel(sc);
return 0;
}
@@ -489,6 +568,7 @@
sc->sc_addr = umd->md_addr; /* user space */
sc->sc_size = umd->md_size;
sc->sc_type = MD_UMEM_SERVER;
+ md_set_disklabel(sc);
/* Become the server daemon */
error = md_server_loop(sc);
@@ -511,6 +591,7 @@
size_t off; /* offset into "device" */
size_t xfer; /* amount to transfer */
int error;
+ bool is_read;
for (;;) {
/* Wait for some work to arrive. */
@@ -522,10 +603,11 @@
/* Do the transfer to/from user space. */
error = 0;
+ is_read = ((bp->b_flags & B_READ) == B_READ);
bp->b_resid = bp->b_bcount;
off = (bp->b_blkno << DEV_BSHIFT);
if (off >= sc->sc_size) {
- if (bp->b_flags & B_READ)
+ if (is_read)
goto done; /* EOF (not an error) */
error = EIO;
goto done;
@@ -534,10 +616,12 @@
if (xfer > (sc->sc_size - off))
xfer = (sc->sc_size - off);
addr = (char *)sc->sc_addr + off;
- if (bp->b_flags & B_READ)
+ disk_busy(&sc->sc_dkdev);
+ if (is_read)
error = copyin(addr, bp->b_data, xfer);
else
error = copyout(bp->b_data, addr, xfer);
+ disk_unbusy(&sc->sc_dkdev, (error ? 0 : xfer), is_read);
if (!error)
bp->b_resid -= xfer;
Index: src/sys/kern/kern_subr.c
diff -u src/sys/kern/kern_subr.c:1.207 src/sys/kern/kern_subr.c:1.208
--- src/sys/kern/kern_subr.c:1.207 Wed Apr 14 14:46:59 2010
+++ src/sys/kern/kern_subr.c Thu Nov 11 11:07:07 2010
@@ -1,4 +1,4 @@
-/* $NetBSD: kern_subr.c,v 1.207 2010/04/14 14:46:59 pooka Exp $ */
+/* $NetBSD: kern_subr.c,v 1.208 2010/11/11 11:07:07 hannken Exp $ */
/*-
* Copyright (c) 1997, 1998, 1999, 2002, 2007, 2008 The NetBSD Foundation, Inc.
@@ -79,7 +79,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: kern_subr.c,v 1.207 2010/04/14 14:46:59 pooka Exp $");
+__KERNEL_RCSID(0, "$NetBSD: kern_subr.c,v 1.208 2010/11/11 11:07:07 hannken Exp $");
#include "opt_ddb.h"
#include "opt_md.h"
@@ -102,6 +102,7 @@
#include <sys/ptrace.h>
#include <sys/fcntl.h>
#include <sys/kauth.h>
+#include <sys/stat.h>
#include <sys/vnode.h>
#include <sys/module.h>
@@ -152,16 +153,11 @@
* Determine the root device and, if instructed to, the root file system.
*/
-#include "md.h"
-
-#if NMD > 0
-extern struct cfdriver md_cd;
#ifdef MEMORY_DISK_IS_ROOT
int md_is_root = 1;
#else
int md_is_root = 0;
#endif
-#endif
/*
* The device and wedge that we booted from. If booted_wedge is NULL,
@@ -201,16 +197,23 @@
boothowto |= RB_ASKNAME;
#endif
-#if NMD > 0
+ /*
+ * For root on md0 we have to force the attachment of md0.
+ */
if (md_is_root) {
- /*
- * XXX there should be "root on md0" in the config file,
- * but it isn't always
- */
- bootdv = md_cd.cd_devs[0];
- bootpartition = 0;
+ int md_major;
+ dev_t md_dev;
+
+ bootdv = NULL;
+ md_major = devsw_name2blk("md", NULL, 0);
+ if (md_major >= 0) {
+ md_dev = MAKEDISKDEV(md_major, 0, RAW_PART);
+ if (bdev_open(md_dev, FREAD, S_IFBLK, curlwp) == 0)
+ bootdv = device_find_by_xname("md0");
+ }
+ if (bootdv == NULL)
+ panic("Cannot open \"md0\" (root)");
}
-#endif
/*
* If NFS is specified as the file system, and we found