This is the first snapshot of the new all-singing-and-dancing md(4).
Using the mdconfig(8) program you can now configure memory disks on malloc(9), swap or a file/vnode. preloaded md disks also work as usual.
This commit is contained in:
parent
284f963cf5
commit
8f8def9e2c
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=70541
@ -27,8 +27,9 @@ enum {UNSET, ATTACH, DETACH} action = UNSET;
|
|||||||
void
|
void
|
||||||
usage()
|
usage()
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Usage:\n\t");
|
fprintf(stderr, "Usage:\n");
|
||||||
fprintf(stderr, "mdconfig {-a|-d} -t type [-o [no]option]... [ -f file] [-s size] [-u unit]\n");
|
fprintf(stderr, "\tmdconfig -a -t type [-o [no]option]... [ -f file] [-s size] [-u unit]\n");
|
||||||
|
fprintf(stderr, "\tmdconfig -d -u unit\n");
|
||||||
fprintf(stderr, "\t\ttype = {malloc, preload, vnode, swap}\n");
|
fprintf(stderr, "\t\ttype = {malloc, preload, vnode, swap}\n");
|
||||||
fprintf(stderr, "\t\toption = {cluster, compress, reserve, autounit}\n");
|
fprintf(stderr, "\t\toption = {cluster, compress, reserve, autounit}\n");
|
||||||
fprintf(stderr, "\t\tsize = %%d (512 byte blocks), %%dk (kB), %%dm (MB) or %%dg (GB)\n");
|
fprintf(stderr, "\t\tsize = %%d (512 byte blocks), %%dk (kB), %%dm (MB) or %%dg (GB)\n");
|
||||||
@ -57,7 +58,8 @@ main(int argc, char **argv)
|
|||||||
if (cmdline != 0)
|
if (cmdline != 0)
|
||||||
usage();
|
usage();
|
||||||
action = DETACH;
|
action = DETACH;
|
||||||
cmdline = 1;
|
mdio.md_options = MD_AUTOUNIT;
|
||||||
|
cmdline = 3;
|
||||||
break;
|
break;
|
||||||
case 't':
|
case 't':
|
||||||
if (cmdline != 1)
|
if (cmdline != 1)
|
||||||
@ -122,7 +124,7 @@ main(int argc, char **argv)
|
|||||||
errx(1, "Unknown suffix on -s argument");
|
errx(1, "Unknown suffix on -s argument");
|
||||||
break;
|
break;
|
||||||
case 'u':
|
case 'u':
|
||||||
if (cmdline != 2)
|
if (cmdline != 2 && cmdline != 3)
|
||||||
usage();
|
usage();
|
||||||
mdio.md_unit = strtoul(optarg, NULL, 0);
|
mdio.md_unit = strtoul(optarg, NULL, 0);
|
||||||
mdio.md_options &= ~MD_AUTOUNIT;
|
mdio.md_options &= ~MD_AUTOUNIT;
|
||||||
@ -135,12 +137,17 @@ main(int argc, char **argv)
|
|||||||
fd = open("/dev/mdctl", O_RDWR, 0);
|
fd = open("/dev/mdctl", O_RDWR, 0);
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
err(1, "open(/dev/mdctl)");
|
err(1, "open(/dev/mdctl)");
|
||||||
if (action == ATTACH)
|
if (action == ATTACH) {
|
||||||
i = ioctl(fd, MDIOCATTACH, &mdio);
|
i = ioctl(fd, MDIOCATTACH, &mdio);
|
||||||
else
|
} else {
|
||||||
|
if (mdio.md_options & MD_AUTOUNIT)
|
||||||
|
usage();
|
||||||
i = ioctl(fd, MDIOCDETACH, &mdio);
|
i = ioctl(fd, MDIOCDETACH, &mdio);
|
||||||
|
}
|
||||||
if (i < 0)
|
if (i < 0)
|
||||||
err(1, "ioctl(/dev/mdctl)");
|
err(1, "ioctl(/dev/mdctl)");
|
||||||
|
if (mdio.md_options & MD_AUTOUNIT)
|
||||||
|
printf("md%d\n", mdio.md_unit);
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
642
sys/dev/md/md.c
642
sys/dev/md/md.c
@ -24,6 +24,19 @@
|
|||||||
#include <sys/sysctl.h>
|
#include <sys/sysctl.h>
|
||||||
#include <sys/linker.h>
|
#include <sys/linker.h>
|
||||||
#include <sys/queue.h>
|
#include <sys/queue.h>
|
||||||
|
#include <sys/mdioctl.h>
|
||||||
|
#include <sys/vnode.h>
|
||||||
|
#include <sys/namei.h>
|
||||||
|
#include <sys/fcntl.h>
|
||||||
|
#include <sys/proc.h>
|
||||||
|
#include <machine/atomic.h>
|
||||||
|
|
||||||
|
#include <vm/vm.h>
|
||||||
|
#include <vm/vm_object.h>
|
||||||
|
#include <vm/vm_page.h>
|
||||||
|
#include <vm/vm_pager.h>
|
||||||
|
#include <vm/vm_zone.h>
|
||||||
|
#include <vm/swap_pager.h>
|
||||||
|
|
||||||
#ifndef MD_NSECT
|
#ifndef MD_NSECT
|
||||||
#define MD_NSECT (10000 * 2)
|
#define MD_NSECT (10000 * 2)
|
||||||
@ -52,17 +65,13 @@ static u_char end_mfs_root[] __unused = "MFS Filesystem had better STOP here";
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int mdrootready;
|
static int mdrootready;
|
||||||
|
static int mdunits;
|
||||||
static void mdcreate_malloc(int unit);
|
|
||||||
|
|
||||||
#define CDEV_MAJOR 95
|
#define CDEV_MAJOR 95
|
||||||
#define BDEV_MAJOR 22
|
|
||||||
|
|
||||||
static d_strategy_t mdstrategy;
|
static d_strategy_t mdstrategy;
|
||||||
static d_strategy_t mdstrategy_preload;
|
|
||||||
static d_strategy_t mdstrategy_malloc;
|
|
||||||
static d_open_t mdopen;
|
static d_open_t mdopen;
|
||||||
static d_ioctl_t mdioctl;
|
static d_ioctl_t mdioctl, mdctlioctl;
|
||||||
|
|
||||||
static struct cdevsw md_cdevsw = {
|
static struct cdevsw md_cdevsw = {
|
||||||
/* open */ mdopen,
|
/* open */ mdopen,
|
||||||
@ -78,7 +87,19 @@ static struct cdevsw md_cdevsw = {
|
|||||||
/* dump */ nodump,
|
/* dump */ nodump,
|
||||||
/* psize */ nopsize,
|
/* psize */ nopsize,
|
||||||
/* flags */ D_DISK | D_CANFREE | D_MEMDISK,
|
/* flags */ D_DISK | D_CANFREE | D_MEMDISK,
|
||||||
/* bmaj */ BDEV_MAJOR
|
};
|
||||||
|
|
||||||
|
static struct cdevsw mdctl_cdevsw = {
|
||||||
|
/* open */ nullopen,
|
||||||
|
/* close */ nullclose,
|
||||||
|
/* read */ noread,
|
||||||
|
/* write */ nowrite,
|
||||||
|
/* ioctl */ mdctlioctl,
|
||||||
|
/* poll */ nopoll,
|
||||||
|
/* mmap */ nommap,
|
||||||
|
/* strategy */ nostrategy,
|
||||||
|
/* name */ "md",
|
||||||
|
/* maj */ CDEV_MAJOR
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct cdevsw mddisk_cdevsw;
|
static struct cdevsw mddisk_cdevsw;
|
||||||
@ -93,8 +114,10 @@ struct md_s {
|
|||||||
struct disk disk;
|
struct disk disk;
|
||||||
dev_t dev;
|
dev_t dev;
|
||||||
int busy;
|
int busy;
|
||||||
enum {MD_MALLOC, MD_PRELOAD} type;
|
enum md_types type;
|
||||||
unsigned nsect;
|
unsigned nsect;
|
||||||
|
unsigned secsize;
|
||||||
|
unsigned flags;
|
||||||
|
|
||||||
/* MD_MALLOC related fields */
|
/* MD_MALLOC related fields */
|
||||||
unsigned nsecp;
|
unsigned nsecp;
|
||||||
@ -103,9 +126,14 @@ struct md_s {
|
|||||||
/* MD_PRELOAD related fields */
|
/* MD_PRELOAD related fields */
|
||||||
u_char *pl_ptr;
|
u_char *pl_ptr;
|
||||||
unsigned pl_len;
|
unsigned pl_len;
|
||||||
};
|
|
||||||
|
|
||||||
static int mdunits;
|
/* MD_VNODE related fields */
|
||||||
|
struct vnode *vnode;
|
||||||
|
struct ucred *cred;
|
||||||
|
|
||||||
|
/* MD_OBJET related fields */
|
||||||
|
vm_object_t object;
|
||||||
|
};
|
||||||
|
|
||||||
static int
|
static int
|
||||||
mdopen(dev_t dev, int flag, int fmt, struct proc *p)
|
mdopen(dev_t dev, int flag, int fmt, struct proc *p)
|
||||||
@ -118,13 +146,12 @@ mdopen(dev_t dev, int flag, int fmt, struct proc *p)
|
|||||||
devtoname(dev), flag, fmt, p);
|
devtoname(dev), flag, fmt, p);
|
||||||
|
|
||||||
sc = dev->si_drv1;
|
sc = dev->si_drv1;
|
||||||
if ((!devfs_present) && sc->unit + 1 == mdunits)
|
|
||||||
mdcreate_malloc(-1);
|
|
||||||
|
|
||||||
dl = &sc->disk.d_label;
|
dl = &sc->disk.d_label;
|
||||||
bzero(dl, sizeof(*dl));
|
bzero(dl, sizeof(*dl));
|
||||||
dl->d_secsize = DEV_BSIZE;
|
dl->d_secsize = sc->secsize;
|
||||||
dl->d_nsectors = 1024;
|
if (sc->nsect > 1024)
|
||||||
|
dl->d_nsectors = sc->nsect > 1024 ? 1024 : sc->nsect;
|
||||||
dl->d_ntracks = 1;
|
dl->d_ntracks = 1;
|
||||||
dl->d_secpercyl = dl->d_nsectors * dl->d_ntracks;
|
dl->d_secpercyl = dl->d_nsectors * dl->d_ntracks;
|
||||||
dl->d_secperunit = sc->nsect;
|
dl->d_secperunit = sc->nsect;
|
||||||
@ -144,57 +171,20 @@ mdioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
mdstrategy(struct bio *bp)
|
mdstart_malloc(struct md_s *sc)
|
||||||
{
|
{
|
||||||
struct md_s *sc;
|
int i;
|
||||||
|
struct bio *bp;
|
||||||
if (md_debug > 1)
|
|
||||||
printf("mdstrategy(%p) %s %x, %d, %ld, %p)\n",
|
|
||||||
bp, devtoname(bp->bio_dev), bp->bio_flags, bp->bio_blkno,
|
|
||||||
bp->bio_bcount / DEV_BSIZE, bp->bio_data);
|
|
||||||
|
|
||||||
sc = bp->bio_dev->si_drv1;
|
|
||||||
if (sc->type == MD_MALLOC) {
|
|
||||||
mdstrategy_malloc(bp);
|
|
||||||
} else {
|
|
||||||
mdstrategy_preload(bp);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
|
||||||
mdstrategy_malloc(struct bio *bp)
|
|
||||||
{
|
|
||||||
int s, i;
|
|
||||||
struct md_s *sc;
|
|
||||||
devstat_trans_flags dop;
|
devstat_trans_flags dop;
|
||||||
u_char *secp, **secpp, *dst;
|
u_char *secp, **secpp, *dst;
|
||||||
unsigned secno, nsec, secval, uc;
|
unsigned secno, nsec, secval, uc;
|
||||||
|
|
||||||
if (md_debug > 1)
|
for (;;) {
|
||||||
printf("mdstrategy_malloc(%p) %s %x, %d, %ld, %p)\n",
|
/* XXX: LOCK(unique unit numbers) */
|
||||||
bp, devtoname(bp->bio_dev), bp->bio_flags, bp->bio_blkno,
|
|
||||||
bp->bio_bcount / DEV_BSIZE, bp->bio_data);
|
|
||||||
|
|
||||||
sc = bp->bio_dev->si_drv1;
|
|
||||||
|
|
||||||
s = splbio();
|
|
||||||
|
|
||||||
bioqdisksort(&sc->bio_queue, bp);
|
|
||||||
|
|
||||||
if (sc->busy) {
|
|
||||||
splx(s);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
sc->busy++;
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
bp = bioq_first(&sc->bio_queue);
|
bp = bioq_first(&sc->bio_queue);
|
||||||
if (bp)
|
if (bp)
|
||||||
bioq_remove(&sc->bio_queue, bp);
|
bioq_remove(&sc->bio_queue, bp);
|
||||||
splx(s);
|
/* XXX: UNLOCK(unique unit numbers) */
|
||||||
if (!bp)
|
if (!bp)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -211,7 +201,6 @@ mdstrategy_malloc(struct bio *bp)
|
|||||||
secno = bp->bio_pblkno;
|
secno = bp->bio_pblkno;
|
||||||
dst = bp->bio_data;
|
dst = bp->bio_data;
|
||||||
while (nsec--) {
|
while (nsec--) {
|
||||||
|
|
||||||
if (secno < sc->nsecp) {
|
if (secno < sc->nsecp) {
|
||||||
secpp = &sc->secp[secno];
|
secpp = &sc->secp[secno];
|
||||||
if ((uintptr_t)*secpp > 255) {
|
if ((uintptr_t)*secpp > 255) {
|
||||||
@ -231,7 +220,7 @@ mdstrategy_malloc(struct bio *bp)
|
|||||||
bp->bio_flags, secpp, secp, secval);
|
bp->bio_flags, secpp, secp, secval);
|
||||||
|
|
||||||
if (bp->bio_cmd == BIO_DELETE) {
|
if (bp->bio_cmd == BIO_DELETE) {
|
||||||
if (secpp) {
|
if (secpp && !(sc->flags & MD_RESERVE)) {
|
||||||
if (secp)
|
if (secp)
|
||||||
FREE(secp, M_MDSECT);
|
FREE(secp, M_MDSECT);
|
||||||
*secpp = 0;
|
*secpp = 0;
|
||||||
@ -246,10 +235,15 @@ mdstrategy_malloc(struct bio *bp)
|
|||||||
bzero(dst, DEV_BSIZE);
|
bzero(dst, DEV_BSIZE);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
uc = dst[0];
|
if (sc->flags & MD_COMPRESS) {
|
||||||
for (i = 1; i < DEV_BSIZE; i++)
|
uc = dst[0];
|
||||||
if (dst[i] != uc)
|
for (i = 1; i < DEV_BSIZE; i++)
|
||||||
break;
|
if (dst[i] != uc)
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
i = 0;
|
||||||
|
uc = 0;
|
||||||
|
}
|
||||||
if (i == DEV_BSIZE && !uc) {
|
if (i == DEV_BSIZE && !uc) {
|
||||||
if (secp)
|
if (secp)
|
||||||
FREE(secp, M_MDSECT);
|
FREE(secp, M_MDSECT);
|
||||||
@ -272,7 +266,6 @@ mdstrategy_malloc(struct bio *bp)
|
|||||||
if (!secp)
|
if (!secp)
|
||||||
MALLOC(secp, u_char *, DEV_BSIZE, M_MDSECT, M_WAITOK);
|
MALLOC(secp, u_char *, DEV_BSIZE, M_MDSECT, M_WAITOK);
|
||||||
bcopy(dst, secp, DEV_BSIZE);
|
bcopy(dst, secp, DEV_BSIZE);
|
||||||
|
|
||||||
*secpp = secp;
|
*secpp = secp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -283,43 +276,23 @@ mdstrategy_malloc(struct bio *bp)
|
|||||||
bp->bio_resid = 0;
|
bp->bio_resid = 0;
|
||||||
devstat_end_transaction_bio(&sc->stats, bp);
|
devstat_end_transaction_bio(&sc->stats, bp);
|
||||||
biodone(bp);
|
biodone(bp);
|
||||||
s = splbio();
|
|
||||||
}
|
}
|
||||||
sc->busy = 0;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
mdstrategy_preload(struct bio *bp)
|
mdstart_preload(struct md_s *sc)
|
||||||
{
|
{
|
||||||
int s;
|
struct bio *bp;
|
||||||
struct md_s *sc;
|
|
||||||
devstat_trans_flags dop;
|
devstat_trans_flags dop;
|
||||||
|
|
||||||
if (md_debug > 1)
|
for (;;) {
|
||||||
printf("mdstrategy_preload(%p) %s %x, %d, %ld, %p)\n",
|
/* XXX: LOCK(unique unit numbers) */
|
||||||
bp, devtoname(bp->bio_dev), bp->bio_flags, bp->bio_blkno,
|
|
||||||
bp->bio_bcount / DEV_BSIZE, bp->bio_data);
|
|
||||||
|
|
||||||
sc = bp->bio_dev->si_drv1;
|
|
||||||
|
|
||||||
s = splbio();
|
|
||||||
|
|
||||||
bioqdisksort(&sc->bio_queue, bp);
|
|
||||||
|
|
||||||
if (sc->busy) {
|
|
||||||
splx(s);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
sc->busy++;
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
bp = bioq_first(&sc->bio_queue);
|
bp = bioq_first(&sc->bio_queue);
|
||||||
if (bp)
|
if (bp)
|
||||||
bioq_remove(&sc->bio_queue, bp);
|
bioq_remove(&sc->bio_queue, bp);
|
||||||
splx(s);
|
/* XXX: UNLOCK(unique unit numbers) */
|
||||||
if (!bp)
|
if (!bp)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -337,27 +310,199 @@ mdstrategy_preload(struct bio *bp)
|
|||||||
bp->bio_resid = 0;
|
bp->bio_resid = 0;
|
||||||
devstat_end_transaction_bio(&sc->stats, bp);
|
devstat_end_transaction_bio(&sc->stats, bp);
|
||||||
biodone(bp);
|
biodone(bp);
|
||||||
s = splbio();
|
|
||||||
}
|
}
|
||||||
sc->busy = 0;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct md_s *
|
static void
|
||||||
mdcreate(int unit)
|
mdstart_vnode(struct md_s *sc)
|
||||||
|
{
|
||||||
|
int error;
|
||||||
|
struct bio *bp;
|
||||||
|
struct uio auio;
|
||||||
|
struct iovec aiov;
|
||||||
|
struct mount *mp;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* VNODE I/O
|
||||||
|
*
|
||||||
|
* If an error occurs, we set BIO_ERROR but we do not set
|
||||||
|
* B_INVAL because (for a write anyway), the buffer is
|
||||||
|
* still valid.
|
||||||
|
*/
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
/* XXX: LOCK(unique unit numbers) */
|
||||||
|
bp = bioq_first(&sc->bio_queue);
|
||||||
|
if (bp)
|
||||||
|
bioq_remove(&sc->bio_queue, bp);
|
||||||
|
/* XXX: UNLOCK(unique unit numbers) */
|
||||||
|
if (!bp)
|
||||||
|
break;
|
||||||
|
|
||||||
|
devstat_start_transaction(&sc->stats);
|
||||||
|
|
||||||
|
bzero(&auio, sizeof(auio));
|
||||||
|
|
||||||
|
aiov.iov_base = bp->bio_data;
|
||||||
|
aiov.iov_len = bp->bio_bcount;
|
||||||
|
auio.uio_iov = &aiov;
|
||||||
|
auio.uio_iovcnt = 1;
|
||||||
|
auio.uio_offset = (vm_ooffset_t)bp->bio_pblkno * sc->secsize;
|
||||||
|
auio.uio_segflg = UIO_SYSSPACE;
|
||||||
|
if(bp->bio_cmd == BIO_READ)
|
||||||
|
auio.uio_rw = UIO_READ;
|
||||||
|
else
|
||||||
|
auio.uio_rw = UIO_WRITE;
|
||||||
|
auio.uio_resid = bp->bio_bcount;
|
||||||
|
auio.uio_procp = curproc;
|
||||||
|
if (VOP_ISLOCKED(sc->vnode, NULL))
|
||||||
|
vprint("unexpected vn driver lock", sc->vnode);
|
||||||
|
if (bp->bio_cmd == BIO_READ) {
|
||||||
|
vn_lock(sc->vnode, LK_EXCLUSIVE | LK_RETRY, curproc);
|
||||||
|
error = VOP_READ(sc->vnode, &auio, 0, sc->cred);
|
||||||
|
} else {
|
||||||
|
(void) vn_start_write(sc->vnode, &mp, V_WAIT);
|
||||||
|
vn_lock(sc->vnode, LK_EXCLUSIVE | LK_RETRY, curproc);
|
||||||
|
error = VOP_WRITE(sc->vnode, &auio, 0, sc->cred);
|
||||||
|
vn_finished_write(mp);
|
||||||
|
}
|
||||||
|
VOP_UNLOCK(sc->vnode, 0, curproc);
|
||||||
|
bp->bio_resid = auio.uio_resid;
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
bp->bio_error = error;
|
||||||
|
bp->bio_flags |= BIO_ERROR;
|
||||||
|
}
|
||||||
|
devstat_end_transaction_bio(&sc->stats, bp);
|
||||||
|
biodone(bp);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
mdstart_swap(struct md_s *sc)
|
||||||
|
{
|
||||||
|
struct bio *bp;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
/* XXX: LOCK(unique unit numbers) */
|
||||||
|
bp = bioq_first(&sc->bio_queue);
|
||||||
|
if (bp)
|
||||||
|
bioq_remove(&sc->bio_queue, bp);
|
||||||
|
/* XXX: UNLOCK(unique unit numbers) */
|
||||||
|
if (!bp)
|
||||||
|
break;
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
devstat_start_transaction(&sc->stats);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if ((bp->bio_cmd == BIO_DELETE) && (sc->flags & MD_RESERVE))
|
||||||
|
biodone(bp);
|
||||||
|
else
|
||||||
|
vm_pager_strategy(sc->object, bp);
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
devstat_end_transaction_bio(&sc->stats, bp);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
mdstrategy(struct bio *bp)
|
||||||
{
|
{
|
||||||
struct md_s *sc;
|
struct md_s *sc;
|
||||||
|
|
||||||
if (unit == -1)
|
if (md_debug > 1)
|
||||||
unit = mdunits++;
|
printf("mdstrategy(%p) %s %x, %d, %ld, %p)\n",
|
||||||
/* Make sure this unit isn't already in action */
|
bp, devtoname(bp->bio_dev), bp->bio_flags, bp->bio_blkno,
|
||||||
|
bp->bio_bcount / DEV_BSIZE, bp->bio_data);
|
||||||
|
|
||||||
|
sc = bp->bio_dev->si_drv1;
|
||||||
|
|
||||||
|
/* XXX: LOCK(sc->lock) */
|
||||||
|
bioqdisksort(&sc->bio_queue, bp);
|
||||||
|
/* XXX: UNLOCK(sc->lock) */
|
||||||
|
|
||||||
|
if (atomic_cmpset_int(&sc->busy, 0, 1) == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
switch (sc->type) {
|
||||||
|
case MD_MALLOC:
|
||||||
|
mdstart_malloc(sc);
|
||||||
|
break;
|
||||||
|
case MD_PRELOAD:
|
||||||
|
mdstart_preload(sc);
|
||||||
|
break;
|
||||||
|
case MD_VNODE:
|
||||||
|
mdstart_vnode(sc);
|
||||||
|
break;
|
||||||
|
case MD_SWAP:
|
||||||
|
mdstart_swap(sc);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
panic("Impossible md(type)");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
sc->busy = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct md_s *
|
||||||
|
mdfind(int unit)
|
||||||
|
{
|
||||||
|
struct md_s *sc;
|
||||||
|
|
||||||
|
/* XXX: LOCK(unique unit numbers) */
|
||||||
LIST_FOREACH(sc, &md_softc_list, list) {
|
LIST_FOREACH(sc, &md_softc_list, list) {
|
||||||
if (sc->unit == unit)
|
if (sc->unit == unit)
|
||||||
return (NULL);
|
break;
|
||||||
}
|
}
|
||||||
|
/* XXX: UNLOCK(unique unit numbers) */
|
||||||
|
return (sc);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct md_s *
|
||||||
|
mdnew(int unit)
|
||||||
|
{
|
||||||
|
struct md_s *sc;
|
||||||
|
int max = -1;
|
||||||
|
|
||||||
|
/* XXX: LOCK(unique unit numbers) */
|
||||||
|
LIST_FOREACH(sc, &md_softc_list, list) {
|
||||||
|
if (sc->unit == unit) {
|
||||||
|
/* XXX: UNLOCK(unique unit numbers) */
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
if (sc->unit > max)
|
||||||
|
max = sc->unit;
|
||||||
|
}
|
||||||
|
if (unit == -1)
|
||||||
|
unit = max + 1;
|
||||||
|
if (unit > DKMAXUNIT)
|
||||||
|
return (NULL);
|
||||||
MALLOC(sc, struct md_s *,sizeof(*sc), M_MD, M_WAITOK | M_ZERO);
|
MALLOC(sc, struct md_s *,sizeof(*sc), M_MD, M_WAITOK | M_ZERO);
|
||||||
LIST_INSERT_HEAD(&md_softc_list, sc, list);
|
|
||||||
sc->unit = unit;
|
sc->unit = unit;
|
||||||
|
LIST_INSERT_HEAD(&md_softc_list, sc, list);
|
||||||
|
/* XXX: UNLOCK(unique unit numbers) */
|
||||||
|
return (sc);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
mddelete(struct md_s *sc)
|
||||||
|
{
|
||||||
|
|
||||||
|
/* XXX: LOCK(unique unit numbers) */
|
||||||
|
LIST_REMOVE(sc, list);
|
||||||
|
/* XXX: UNLOCK(unique unit numbers) */
|
||||||
|
FREE(sc, M_MD);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
mdinit(struct md_s *sc)
|
||||||
|
{
|
||||||
|
|
||||||
bioq_init(&sc->bio_queue);
|
bioq_init(&sc->bio_queue);
|
||||||
devstat_add_entry(&sc->stats, "md", sc->unit, DEV_BSIZE,
|
devstat_add_entry(&sc->stats, "md", sc->unit, DEV_BSIZE,
|
||||||
DEVSTAT_NO_ORDERED_TAGS,
|
DEVSTAT_NO_ORDERED_TAGS,
|
||||||
@ -365,7 +510,6 @@ mdcreate(int unit)
|
|||||||
DEVSTAT_PRIORITY_OTHER);
|
DEVSTAT_PRIORITY_OTHER);
|
||||||
sc->dev = disk_create(sc->unit, &sc->disk, 0, &md_cdevsw, &mddisk_cdevsw);
|
sc->dev = disk_create(sc->unit, &sc->disk, 0, &md_cdevsw, &mddisk_cdevsw);
|
||||||
sc->dev->si_drv1 = sc;
|
sc->dev->si_drv1 = sc;
|
||||||
return (sc);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -373,53 +517,291 @@ mdcreate_preload(u_char *image, unsigned length)
|
|||||||
{
|
{
|
||||||
struct md_s *sc;
|
struct md_s *sc;
|
||||||
|
|
||||||
sc = mdcreate(-1);
|
sc = mdnew(-1);
|
||||||
|
if (sc == NULL)
|
||||||
|
return;
|
||||||
sc->type = MD_PRELOAD;
|
sc->type = MD_PRELOAD;
|
||||||
|
sc->secsize = DEV_BSIZE;
|
||||||
sc->nsect = length / DEV_BSIZE;
|
sc->nsect = length / DEV_BSIZE;
|
||||||
sc->pl_ptr = image;
|
sc->pl_ptr = image;
|
||||||
sc->pl_len = length;
|
sc->pl_len = length;
|
||||||
|
|
||||||
if (sc->unit == 0)
|
if (sc->unit == 0)
|
||||||
mdrootready = 1;
|
mdrootready = 1;
|
||||||
|
mdinit(sc);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static int
|
||||||
mdcreate_malloc(int unit)
|
mdcreate_malloc(struct md_ioctl *mdio)
|
||||||
{
|
{
|
||||||
struct md_s *sc;
|
struct md_s *sc;
|
||||||
|
unsigned u;
|
||||||
|
|
||||||
sc = mdcreate(unit);
|
if (mdio->md_size == 0)
|
||||||
if (sc == NULL)
|
return(EINVAL);
|
||||||
return;
|
if (mdio->md_options & ~(MD_AUTOUNIT | MD_COMPRESS | MD_RESERVE))
|
||||||
|
return(EINVAL);
|
||||||
|
/* Compression doesn't make sense if we have reserved space */
|
||||||
|
if (mdio->md_options & MD_RESERVE)
|
||||||
|
mdio->md_options &= ~MD_COMPRESS;
|
||||||
|
if (mdio->md_options & MD_AUTOUNIT) {
|
||||||
|
sc = mdnew(-1);
|
||||||
|
if (sc == NULL)
|
||||||
|
return (ENOMEM);
|
||||||
|
mdio->md_unit = sc->unit;
|
||||||
|
} else {
|
||||||
|
sc = mdnew(mdio->md_unit);
|
||||||
|
if (sc == NULL)
|
||||||
|
return (EBUSY);
|
||||||
|
}
|
||||||
sc->type = MD_MALLOC;
|
sc->type = MD_MALLOC;
|
||||||
|
sc->secsize = DEV_BSIZE;
|
||||||
sc->nsect = MD_NSECT; /* for now */
|
sc->nsect = mdio->md_size;
|
||||||
MALLOC(sc->secp, u_char **, sizeof(u_char *), M_MD, M_WAITOK | M_ZERO);
|
sc->flags = mdio->md_options & MD_COMPRESS;
|
||||||
sc->nsecp = 1;
|
if (!(mdio->md_options & MD_RESERVE)) {
|
||||||
|
MALLOC(sc->secp, u_char **, sizeof(u_char *), M_MD, M_WAITOK | M_ZERO);
|
||||||
|
sc->nsecp = 1;
|
||||||
|
} else {
|
||||||
|
MALLOC(sc->secp, u_char **, sc->nsect * sizeof(u_char *), M_MD, M_WAITOK | M_ZERO);
|
||||||
|
sc->nsecp = sc->nsect;
|
||||||
|
for (u = 0; u < sc->nsect; u++)
|
||||||
|
MALLOC(sc->secp[u], u_char *, DEV_BSIZE, M_MDSECT, M_WAITOK | M_ZERO);
|
||||||
|
}
|
||||||
printf("md%d: Malloc disk\n", sc->unit);
|
printf("md%d: Malloc disk\n", sc->unit);
|
||||||
|
mdinit(sc);
|
||||||
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
md_clone (void *arg, char *name, int namelen, dev_t *dev)
|
|
||||||
{
|
|
||||||
int i, u;
|
|
||||||
|
|
||||||
if (*dev != NODEV)
|
static int
|
||||||
return;
|
mdsetcred(struct md_s *sc, struct ucred *cred)
|
||||||
i = dev_stdclone(name, NULL, "md", &u);
|
{
|
||||||
if (i == 0)
|
char *tmpbuf;
|
||||||
return;
|
int error = 0;
|
||||||
if (u > DKMAXUNIT)
|
|
||||||
return;
|
|
||||||
/* XXX: should check that next char is [\0sa-h] */
|
|
||||||
/*
|
/*
|
||||||
* Now we cheat: We just create the disk, but don't match.
|
* Set credits in our softc
|
||||||
* Since we run before it, subr_disk.c::disk_clone() will
|
|
||||||
* find our disk and match the sought for device.
|
|
||||||
*/
|
*/
|
||||||
mdcreate_malloc(u);
|
|
||||||
return;
|
if (sc->cred)
|
||||||
|
crfree(sc->cred);
|
||||||
|
sc->cred = crdup(cred);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Horrible kludge to establish credentials for NFS XXX.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (sc->vnode) {
|
||||||
|
struct uio auio;
|
||||||
|
struct iovec aiov;
|
||||||
|
|
||||||
|
tmpbuf = malloc(sc->secsize, M_TEMP, M_WAITOK);
|
||||||
|
bzero(&auio, sizeof(auio));
|
||||||
|
|
||||||
|
aiov.iov_base = tmpbuf;
|
||||||
|
aiov.iov_len = sc->secsize;
|
||||||
|
auio.uio_iov = &aiov;
|
||||||
|
auio.uio_iovcnt = 1;
|
||||||
|
auio.uio_offset = 0;
|
||||||
|
auio.uio_rw = UIO_READ;
|
||||||
|
auio.uio_segflg = UIO_SYSSPACE;
|
||||||
|
auio.uio_resid = aiov.iov_len;
|
||||||
|
vn_lock(sc->vnode, LK_EXCLUSIVE | LK_RETRY, curproc);
|
||||||
|
error = VOP_READ(sc->vnode, &auio, 0, sc->cred);
|
||||||
|
VOP_UNLOCK(sc->vnode, 0, curproc);
|
||||||
|
free(tmpbuf, M_TEMP);
|
||||||
|
}
|
||||||
|
return (error);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
mdcreate_vnode(struct md_ioctl *mdio, struct proc *p)
|
||||||
|
{
|
||||||
|
struct md_s *sc;
|
||||||
|
struct vattr vattr;
|
||||||
|
struct nameidata nd;
|
||||||
|
int error, flags;
|
||||||
|
|
||||||
|
if (mdio->md_options & MD_AUTOUNIT) {
|
||||||
|
sc = mdnew(-1);
|
||||||
|
mdio->md_unit = sc->unit;
|
||||||
|
} else {
|
||||||
|
sc = mdnew(mdio->md_unit);
|
||||||
|
}
|
||||||
|
if (sc == NULL)
|
||||||
|
return (EBUSY);
|
||||||
|
|
||||||
|
sc->type = MD_VNODE;
|
||||||
|
|
||||||
|
flags = FREAD|FWRITE;
|
||||||
|
NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, mdio->md_file, p);
|
||||||
|
error = vn_open(&nd, &flags, 0);
|
||||||
|
if (error) {
|
||||||
|
if (error != EACCES && error != EPERM && error != EROFS)
|
||||||
|
return (error);
|
||||||
|
flags &= ~FWRITE;
|
||||||
|
sc->flags |= MD_READONLY;
|
||||||
|
NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, mdio->md_file, p);
|
||||||
|
error = vn_open(&nd, &flags, 0);
|
||||||
|
if (error)
|
||||||
|
return (error);
|
||||||
|
}
|
||||||
|
NDFREE(&nd, NDF_ONLY_PNBUF);
|
||||||
|
if (nd.ni_vp->v_type != VREG ||
|
||||||
|
(error = VOP_GETATTR(nd.ni_vp, &vattr, p->p_ucred, p))) {
|
||||||
|
VOP_UNLOCK(nd.ni_vp, 0, p);
|
||||||
|
(void) vn_close(nd.ni_vp, flags, p->p_ucred, p);
|
||||||
|
return (error ? error : EINVAL);
|
||||||
|
}
|
||||||
|
VOP_UNLOCK(nd.ni_vp, 0, p);
|
||||||
|
sc->secsize = DEV_BSIZE;
|
||||||
|
sc->vnode = nd.ni_vp;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the size is specified, override the file attributes.
|
||||||
|
*/
|
||||||
|
if (mdio->md_size)
|
||||||
|
sc->nsect = mdio->md_size;
|
||||||
|
else
|
||||||
|
sc->nsect = vattr.va_size / sc->secsize; /* XXX: round up ? */
|
||||||
|
error = mdsetcred(sc, p->p_ucred);
|
||||||
|
if (error) {
|
||||||
|
(void) vn_close(nd.ni_vp, flags, p->p_ucred, p);
|
||||||
|
return(error);
|
||||||
|
}
|
||||||
|
mdinit(sc);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
mddestroy(struct md_s *sc, struct md_ioctl *mdio, struct proc *p)
|
||||||
|
{
|
||||||
|
unsigned u;
|
||||||
|
|
||||||
|
if (sc->dev != NULL)
|
||||||
|
disk_destroy(sc->dev);
|
||||||
|
if (sc->vnode != NULL)
|
||||||
|
(void)vn_close(sc->vnode, sc->flags & MD_READONLY ? FREAD : (FREAD|FWRITE), sc->cred, p);
|
||||||
|
if (sc->cred != NULL)
|
||||||
|
crfree(sc->cred);
|
||||||
|
if (sc->object != NULL)
|
||||||
|
vm_pager_deallocate(sc->object);
|
||||||
|
if (sc->secp != NULL) {
|
||||||
|
for (u = 0; u < sc->nsecp; u++)
|
||||||
|
if ((uintptr_t)sc->secp[u] > 255)
|
||||||
|
FREE(sc->secp[u], M_MDSECT);
|
||||||
|
FREE(sc->secp, M_MD);
|
||||||
|
}
|
||||||
|
mddelete(sc);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
mdcreate_swap(struct md_ioctl *mdio, struct proc *p)
|
||||||
|
{
|
||||||
|
int error;
|
||||||
|
struct md_s *sc;
|
||||||
|
|
||||||
|
if (mdio->md_options & MD_AUTOUNIT) {
|
||||||
|
sc = mdnew(-1);
|
||||||
|
mdio->md_unit = sc->unit;
|
||||||
|
} else {
|
||||||
|
sc = mdnew(mdio->md_unit);
|
||||||
|
}
|
||||||
|
if (sc == NULL)
|
||||||
|
return (EBUSY);
|
||||||
|
|
||||||
|
sc->type = MD_SWAP;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Range check. Disallow negative sizes or any size less then the
|
||||||
|
* size of a page. Then round to a page.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (mdio->md_size == 0)
|
||||||
|
return(EDOM);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Allocate an OBJT_SWAP object.
|
||||||
|
*
|
||||||
|
* sc_secsize is PAGE_SIZE'd
|
||||||
|
*
|
||||||
|
* mdio->size is in DEV_BSIZE'd chunks.
|
||||||
|
* Note the truncation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
sc->secsize = PAGE_SIZE;
|
||||||
|
sc->nsect = mdio->md_size / (PAGE_SIZE / DEV_BSIZE);
|
||||||
|
sc->object = vm_pager_allocate(OBJT_SWAP, NULL, sc->secsize * (vm_offset_t)sc->nsect, VM_PROT_DEFAULT, 0);
|
||||||
|
if (mdio->md_options & MD_RESERVE) {
|
||||||
|
if (swap_pager_reserve(sc->object, 0, sc->nsect) < 0) {
|
||||||
|
vm_pager_deallocate(sc->object);
|
||||||
|
sc->object = NULL;
|
||||||
|
return(EDOM);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
error = mdsetcred(sc, p->p_ucred);
|
||||||
|
if (error)
|
||||||
|
mddestroy(sc, mdio, p);
|
||||||
|
else
|
||||||
|
mdinit(sc);
|
||||||
|
return(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
mdctlioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
|
||||||
|
{
|
||||||
|
struct md_ioctl *mdio;
|
||||||
|
struct md_s *sc;
|
||||||
|
|
||||||
|
if (md_debug)
|
||||||
|
printf("mdctlioctl(%s %lx %p %x %p)\n",
|
||||||
|
devtoname(dev), cmd, addr, flags, p);
|
||||||
|
|
||||||
|
mdio = (struct md_ioctl *)addr;
|
||||||
|
if (mdio->md_type != MD_VNODE)
|
||||||
|
mdio->md_file[0] = '\0';
|
||||||
|
switch (cmd) {
|
||||||
|
case MDIOCATTACH:
|
||||||
|
printf("A: u %u t %d n %s s %u o %u\n", mdio->md_unit,
|
||||||
|
mdio->md_type, mdio->md_file, mdio->md_size,
|
||||||
|
mdio->md_options);
|
||||||
|
switch (mdio->md_type) {
|
||||||
|
case MD_MALLOC:
|
||||||
|
return(mdcreate_malloc(mdio));
|
||||||
|
case MD_PRELOAD:
|
||||||
|
return (EINVAL);
|
||||||
|
case MD_VNODE:
|
||||||
|
return(mdcreate_vnode(mdio, p));
|
||||||
|
case MD_SWAP:
|
||||||
|
return(mdcreate_swap(mdio, p));
|
||||||
|
default:
|
||||||
|
return (EINVAL);
|
||||||
|
}
|
||||||
|
case MDIOCDETACH:
|
||||||
|
printf("D: u %u t %d n %s s %u o %u\n", mdio->md_unit,
|
||||||
|
mdio->md_type, mdio->md_file, mdio->md_size,
|
||||||
|
mdio->md_options);
|
||||||
|
if (*mdio->md_file != '\0')
|
||||||
|
return(EINVAL);
|
||||||
|
if (mdio->md_size != 0)
|
||||||
|
return(EINVAL);
|
||||||
|
if (mdio->md_options != 0)
|
||||||
|
return(EINVAL);
|
||||||
|
sc = mdfind(mdio->md_unit);
|
||||||
|
if (sc == NULL)
|
||||||
|
return (ENOENT);
|
||||||
|
switch(sc->type) {
|
||||||
|
case MD_VNODE:
|
||||||
|
case MD_SWAP:
|
||||||
|
case MD_MALLOC:
|
||||||
|
return(mddestroy(sc, mdio, p));
|
||||||
|
default:
|
||||||
|
return (EOPNOTSUPP);
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return (ENOIOCTL);
|
||||||
|
};
|
||||||
|
return (ENOIOCTL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -452,9 +834,7 @@ md_drvinit(void *unused)
|
|||||||
mdunits, name, len, ptr);
|
mdunits, name, len, ptr);
|
||||||
mdcreate_preload(ptr, len);
|
mdcreate_preload(ptr, len);
|
||||||
}
|
}
|
||||||
EVENTHANDLER_REGISTER(dev_clone, md_clone, 0, 999);
|
make_dev(&mdctl_cdevsw, 0xffff00ff, UID_ROOT, GID_WHEEL, 0600, "mdctl");
|
||||||
if (!devfs_present)
|
|
||||||
mdcreate_malloc(-1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SYSINIT(mddev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR, md_drvinit,NULL)
|
SYSINIT(mddev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR, md_drvinit,NULL)
|
||||||
|
Loading…
Reference in New Issue
Block a user