freebsd-dev/sys/kern/subr_disk.c
Julian Elischer b40ce4165d KSE Milestone 2
Note ALL MODULES MUST BE RECOMPILED
make the kernel aware that there are smaller units of scheduling than the
process. (but only allow one thread per process at this time).
This is functionally equivalent to teh previousl -current except
that there is a thread associated with each process.

Sorry john! (your next MFC will be a doosie!)

Reviewed by: peter@freebsd.org, dillon@freebsd.org

X-MFC after:    ha ha ha ha
2001-09-12 08:38:13 +00:00

372 lines
7.8 KiB
C

/*
* ----------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (Revision 42):
* <phk@FreeBSD.ORG> wrote this file. As long as you retain this notice you
* can do whatever you want with this stuff. If we meet some day, and you think
* this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
* ----------------------------------------------------------------------------
*
* $FreeBSD$
*
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/sysctl.h>
#include <sys/bio.h>
#include <sys/conf.h>
#include <sys/disk.h>
#include <sys/malloc.h>
#include <sys/sysctl.h>
#include <machine/md_var.h>
#include <sys/ctype.h>
static MALLOC_DEFINE(M_DISK, "disk", "disk data");
static d_strategy_t diskstrategy;
static d_open_t diskopen;
static d_close_t diskclose;
static d_ioctl_t diskioctl;
static d_psize_t diskpsize;
static LIST_HEAD(, disk) disklist = LIST_HEAD_INITIALIZER(&disklist);
static void
disk_clone(void *arg, char *name, int namelen, dev_t *dev)
{
struct disk *dp;
char const *d;
int i, u, s, p;
dev_t pdev;
if (*dev != NODEV)
return;
LIST_FOREACH(dp, &disklist, d_list) {
d = dp->d_devsw->d_name;
i = strlen(d);
if (bcmp(d, name, i) != 0)
continue;
u = 0;
if (!isdigit(name[i]))
continue;
while (isdigit(name[i])) {
u *= 10;
u += name[i++] - '0';
}
if (u > DKMAXUNIT)
continue;
p = RAW_PART;
s = WHOLE_DISK_SLICE;
pdev = makedev(dp->d_devsw->d_maj, dkmakeminor(u, s, p));
if (pdev->si_disk == NULL)
continue;
if (name[i] != '\0') {
if (name[i] == 's') {
s = 0;
i++;
if (!isdigit(name[i]))
continue;
while (isdigit(name[i])) {
s *= 10;
s += name[i++] - '0';
}
s += BASE_SLICE - 1;
} else {
s = COMPATIBILITY_SLICE;
}
if (name[i] == '\0')
;
else if (name[i] < 'a' || name[i] > 'h')
continue;
else
p = name[i] - 'a';
}
*dev = make_dev(pdev->si_devsw, dkmakeminor(u, s, p),
UID_ROOT, GID_OPERATOR, 0640, name);
dev_depends(pdev, *dev);
return;
}
}
static void
inherit_raw(dev_t pdev, dev_t dev)
{
dev->si_disk = pdev->si_disk;
dev->si_drv1 = pdev->si_drv1;
dev->si_drv2 = pdev->si_drv2;
dev->si_iosize_max = pdev->si_iosize_max;
dev->si_bsize_phys = pdev->si_bsize_phys;
dev->si_bsize_best = pdev->si_bsize_best;
}
dev_t
disk_create(int unit, struct disk *dp, int flags, struct cdevsw *cdevsw, struct cdevsw *proto)
{
static int once;
dev_t dev;
if (!once) {
EVENTHANDLER_REGISTER(dev_clone, disk_clone, 0, 1000);
once++;
}
bzero(dp, sizeof(*dp));
if (proto->d_open != diskopen) {
*proto = *cdevsw;
proto->d_open = diskopen;
proto->d_close = diskclose;
proto->d_ioctl = diskioctl;
proto->d_strategy = diskstrategy;
proto->d_psize = diskpsize;
cdevsw_add(proto);
}
if (bootverbose)
printf("Creating DISK %s%d\n", cdevsw->d_name, unit);
dev = make_dev(proto, dkmakeminor(unit, WHOLE_DISK_SLICE, RAW_PART),
UID_ROOT, GID_OPERATOR, 0640, "%s%d", cdevsw->d_name, unit);
dev->si_disk = dp;
dp->d_dev = dev;
dp->d_dsflags = flags;
dp->d_devsw = cdevsw;
LIST_INSERT_HEAD(&disklist, dp, d_list);
return (dev);
}
int
disk_dumpcheck(dev_t dev, u_int *count, u_int *blkno, u_int *secsize)
{
struct disk *dp;
struct disklabel *dl;
u_int boff;
dp = dev->si_disk;
if (!dp)
return (ENXIO);
if (!dp->d_slice)
return (ENXIO);
dl = dsgetlabel(dev, dp->d_slice);
if (!dl)
return (ENXIO);
*count = Maxmem * (PAGE_SIZE / dl->d_secsize);
if (dumplo <= LABELSECTOR ||
(dumplo + *count > dl->d_partitions[dkpart(dev)].p_size))
return (EINVAL);
boff = dl->d_partitions[dkpart(dev)].p_offset +
dp->d_slice->dss_slices[dkslice(dev)].ds_offset;
*blkno = boff + dumplo;
*secsize = dl->d_secsize;
return (0);
}
void
disk_invalidate (struct disk *disk)
{
if (disk->d_slice)
dsgone(&disk->d_slice);
}
void
disk_destroy(dev_t dev)
{
LIST_REMOVE(dev->si_disk, d_list);
bzero(dev->si_disk, sizeof(*dev->si_disk));
dev->si_disk = NULL;
destroy_dev(dev);
return;
}
struct disk *
disk_enumerate(struct disk *disk)
{
if (!disk)
return (LIST_FIRST(&disklist));
else
return (LIST_NEXT(disk, d_list));
}
static int
sysctl_disks(SYSCTL_HANDLER_ARGS)
{
struct disk *disk;
int error, first;
disk = NULL;
first = 1;
while ((disk = disk_enumerate(disk))) {
if (!first) {
error = SYSCTL_OUT(req, " ", 1);
if (error)
return error;
} else {
first = 0;
}
error = SYSCTL_OUT(req, disk->d_dev->si_name, strlen(disk->d_dev->si_name));
if (error)
return error;
}
error = SYSCTL_OUT(req, "", 1);
return error;
}
SYSCTL_PROC(_kern, OID_AUTO, disks, CTLTYPE_STRING | CTLFLAG_RD, 0, NULL,
sysctl_disks, "A", "names of available disks");
/*
* The cdevsw functions
*/
static int
diskopen(dev_t dev, int oflags, int devtype, struct thread *td)
{
dev_t pdev;
struct disk *dp;
int error;
error = 0;
pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART);
dp = pdev->si_disk;
if (!dp)
return (ENXIO);
while (dp->d_flags & DISKFLAG_LOCK) {
dp->d_flags |= DISKFLAG_WANTED;
error = tsleep(dp, PRIBIO | PCATCH, "diskopen", hz);
if (error)
return (error);
}
dp->d_flags |= DISKFLAG_LOCK;
if (!dsisopen(dp->d_slice)) {
if (!pdev->si_iosize_max)
pdev->si_iosize_max = dev->si_iosize_max;
error = dp->d_devsw->d_open(pdev, oflags, devtype, td);
}
/* Inherit properties from the whole/raw dev_t */
inherit_raw(pdev, dev);
if (error)
goto out;
error = dsopen(dev, devtype, dp->d_dsflags, &dp->d_slice, &dp->d_label);
if (!dsisopen(dp->d_slice))
dp->d_devsw->d_close(pdev, oflags, devtype, td);
out:
dp->d_flags &= ~DISKFLAG_LOCK;
if (dp->d_flags & DISKFLAG_WANTED) {
dp->d_flags &= ~DISKFLAG_WANTED;
wakeup(dp);
}
return(error);
}
static int
diskclose(dev_t dev, int fflag, int devtype, struct thread *td)
{
struct disk *dp;
int error;
dev_t pdev;
error = 0;
pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART);
dp = pdev->si_disk;
if (!dp)
return (ENXIO);
dsclose(dev, devtype, dp->d_slice);
if (!dsisopen(dp->d_slice))
error = dp->d_devsw->d_close(dp->d_dev, fflag, devtype, td);
return (error);
}
static void
diskstrategy(struct bio *bp)
{
dev_t pdev;
struct disk *dp;
pdev = dkmodpart(dkmodslice(bp->bio_dev, WHOLE_DISK_SLICE), RAW_PART);
dp = pdev->si_disk;
bp->bio_resid = bp->bio_bcount;
if (dp != bp->bio_dev->si_disk)
inherit_raw(pdev, bp->bio_dev);
if (!dp) {
biofinish(bp, NULL, ENXIO);
return;
}
if (dscheck(bp, dp->d_slice) <= 0) {
biodone(bp);
return;
}
if (bp->bio_bcount == 0) {
biodone(bp);
return;
}
KASSERT(dp->d_devsw != NULL, ("NULL devsw"));
KASSERT(dp->d_devsw->d_strategy != NULL, ("NULL d_strategy"));
dp->d_devsw->d_strategy(bp);
return;
}
static int
diskioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct thread *td)
{
struct disk *dp;
int error;
dev_t pdev;
pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART);
dp = pdev->si_disk;
if (!dp)
return (ENXIO);
error = dsioctl(dev, cmd, data, fflag, &dp->d_slice);
if (error == ENOIOCTL)
error = dp->d_devsw->d_ioctl(dev, cmd, data, fflag, td);
return (error);
}
static int
diskpsize(dev_t dev)
{
struct disk *dp;
dev_t pdev;
pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART);
dp = pdev->si_disk;
if (!dp)
return (-1);
if (dp != dev->si_disk) {
dev->si_drv1 = pdev->si_drv1;
dev->si_drv2 = pdev->si_drv2;
/* XXX: don't set bp->b_dev->si_disk (?) */
}
return (dssize(dev, &dp->d_slice));
}
SYSCTL_DECL(_debug_sizeof);
SYSCTL_INT(_debug_sizeof, OID_AUTO, disklabel, CTLFLAG_RD,
0, sizeof(struct disklabel), "sizeof(struct disklabel)");
SYSCTL_INT(_debug_sizeof, OID_AUTO, diskslices, CTLFLAG_RD,
0, sizeof(struct diskslices), "sizeof(struct diskslices)");
SYSCTL_INT(_debug_sizeof, OID_AUTO, disk, CTLFLAG_RD,
0, sizeof(struct disk), "sizeof(struct disk)");