Make it possible to resize md(4) devices.

Reviewed by:	kib
Sponsored by:	FreeBSD Foundation
This commit is contained in:
Edward Tomasz Napierala 2012-07-07 20:32:21 +00:00
parent fcc144ad4e
commit dc604f0cf6
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=238215
4 changed files with 118 additions and 17 deletions

View File

@ -64,6 +64,11 @@
.Fl u Ar unit
.Op Fl o Oo Cm no Oc Ns Ar force
.Nm
.Fl r
.Fl u Ar unit
.Fl s Ar size
.Op Fl o Oo Cm no Oc Ns Ar force
.Nm
.Fl l
.Op Fl n
.Op Fl v
@ -85,6 +90,8 @@ This will configure and attach a memory disk with the
parameters specified and attach it to the system.
.It Fl d
Detach a memory disk from the system and release all resources.
.It Fl r
Resize a memory disk.
.It Fl t Ar type
Select the type of the memory disk.
.Bl -tag -width "malloc"

View File

@ -54,7 +54,7 @@
#include <unistd.h>
static struct md_ioctl mdio;
static enum {UNSET, ATTACH, DETACH, LIST} action = UNSET;
static enum {UNSET, ATTACH, DETACH, RESIZE, LIST} action = UNSET;
static int nflag;
static void usage(void);
@ -81,6 +81,7 @@ usage(void)
" [-s size] [-S sectorsize] [-u unit]\n"
" [-x sectors/track] [-y heads/cylinder]\n"
" mdconfig -d -u unit [-o [no]force]\n"
" mdconfig -r -u unit -s size [-o [no]force]\n"
" mdconfig -l [-v] [-n] [-u unit]\n"
" mdconfig file\n");
fprintf(stderr, "\t\ttype = {malloc, preload, vnode, swap}\n");
@ -96,7 +97,7 @@ main(int argc, char **argv)
{
int ch, fd, i, vflag;
char *p;
char *fflag = NULL, *tflag = NULL, *uflag = NULL;
char *fflag = NULL, *sflag = NULL, *tflag = NULL, *uflag = NULL;
bzero(&mdio, sizeof(mdio));
mdio.md_file = malloc(PATH_MAX);
@ -108,25 +109,32 @@ main(int argc, char **argv)
if (argc == 1)
usage();
while ((ch = getopt(argc, argv, "ab:df:lno:s:S:t:u:vx:y:")) != -1) {
while ((ch = getopt(argc, argv, "ab:df:lno:rs:S:t:u:vx:y:")) != -1) {
switch (ch) {
case 'a':
if (action != UNSET && action != ATTACH)
errx(1,
"-a is mutually exclusive with -d and -l");
errx(1, "-a is mutually exclusive "
"with -d, -r, and -l");
action = ATTACH;
break;
case 'd':
if (action != UNSET && action != DETACH)
errx(1,
"-d is mutually exclusive with -a and -l");
errx(1, "-d is mutually exclusive "
"with -a, -r, and -l");
action = DETACH;
mdio.md_options |= MD_AUTOUNIT;
break;
case 'r':
if (action != UNSET && action != RESIZE)
errx(1, "-r is mutually exclusive "
"with -a, -d, and -l");
action = RESIZE;
mdio.md_options |= MD_AUTOUNIT;
break;
case 'l':
if (action != UNSET && action != LIST)
errx(1,
"-l is mutually exclusive with -a and -d");
errx(1, "-l is mutually exclusive "
"with -a, -r, and -d");
action = LIST;
mdio.md_options |= MD_AUTOUNIT;
break;
@ -188,6 +196,9 @@ main(int argc, char **argv)
mdio.md_sectorsize = strtoul(optarg, &p, 0);
break;
case 's':
if (sflag != NULL)
errx(1, "-s can be passed only once");
sflag = optarg;
mdio.md_mediasize = (off_t)strtoumax(optarg, &p, 0);
if (p == NULL || *p == '\0')
mdio.md_mediasize *= DEV_BSIZE;
@ -242,7 +253,7 @@ main(int argc, char **argv)
mdio.md_type = MD_VNODE;
mdio.md_options |= MD_CLUSTER | MD_AUTOUNIT |
MD_COMPRESS;
} else if (mdio.md_mediasize != 0) {
} else if (sflag != NULL) {
/* Imply ``-t swap'' */
mdio.md_type = MD_SWAP;
mdio.md_options |= MD_CLUSTER | MD_AUTOUNIT |
@ -276,15 +287,15 @@ main(int argc, char **argv)
}
if ((mdio.md_type == MD_MALLOC || mdio.md_type == MD_SWAP) &&
mdio.md_mediasize == 0)
sflag == NULL)
errx(1, "must specify -s for -t malloc or -t swap");
if (mdio.md_type == MD_VNODE && mdio.md_file[0] == '\0')
errx(1, "must specify -f for -t vnode");
} else {
if (mdio.md_sectorsize != 0)
errx(1, "-S can only be used with -a");
if (mdio.md_mediasize != 0)
errx(1, "-s can only be used with -a");
if (action != RESIZE && sflag != NULL)
errx(1, "-s can only be used with -a and -r");
if (mdio.md_fwsectors != 0)
errx(1, "-x can only be used with -a");
if (mdio.md_fwheads != 0)
@ -295,13 +306,20 @@ main(int argc, char **argv)
errx(1, "-t can only be used with -a");
if (argc > 0)
errx(1, "file can only be used with -a");
if (action != DETACH && (mdio.md_options & ~MD_AUTOUNIT) != 0)
errx(1, "-o can only be used with -a and -d");
if ((action != DETACH && action != RESIZE) &&
(mdio.md_options & ~MD_AUTOUNIT) != 0)
errx(1, "-o can only be used with -a, -d, and -r");
if (action == DETACH &&
(mdio.md_options & ~(MD_FORCE | MD_AUTOUNIT)) != 0)
errx(1, "only -o [no]force can be used with -d");
if (action == RESIZE &&
(mdio.md_options & ~(MD_FORCE | MD_RESERVE | MD_AUTOUNIT)) != 0)
errx(1, "only -o [no]force and -o [no]reserve can be used with -r");
}
if (action == RESIZE && sflag == NULL)
errx(1, "must specify -s for -r");
if (action != LIST && vflag == OPT_VERBOSE)
errx(1, "-v can only be used with -l");
@ -333,6 +351,12 @@ main(int argc, char **argv)
i = ioctl(fd, MDIOCDETACH, &mdio);
if (i < 0)
err(1, "ioctl(/dev/%s)", MDCTL_NAME);
} else if (action == RESIZE) {
if (mdio.md_options & MD_AUTOUNIT)
errx(1, "-r requires -u");
i = ioctl(fd, MDIOCRESIZE, &mdio);
if (i < 0)
err(1, "ioctl(/dev/%s)", MDCTL_NAME);
} else if (action == LIST) {
if (mdio.md_options & MD_AUTOUNIT) {
/*
@ -342,7 +366,6 @@ main(int argc, char **argv)
md_list(NULL, OPT_LIST | vflag);
} else
return (md_query(uflag));
} else
usage();
close(fd);

View File

@ -1080,6 +1080,64 @@ mddestroy(struct md_s *sc, struct thread *td)
return (0);
}
static int
mdresize(struct md_s *sc, struct md_ioctl *mdio)
{
int error, res;
vm_pindex_t oldpages, newpages;
switch (sc->type) {
case MD_VNODE:
break;
case MD_SWAP:
if (mdio->md_mediasize == 0 ||
(mdio->md_mediasize % PAGE_SIZE) != 0)
return (EDOM);
oldpages = OFF_TO_IDX(round_page(sc->mediasize));
newpages = OFF_TO_IDX(round_page(mdio->md_mediasize));
if (newpages < oldpages) {
VM_OBJECT_LOCK(sc->object);
vm_object_page_remove(sc->object, newpages, 0, 0);
swap_pager_freespace(sc->object, newpages,
oldpages - newpages);
swap_release_by_cred(IDX_TO_OFF(oldpages -
newpages), sc->cred);
sc->object->charge = IDX_TO_OFF(newpages);
sc->object->size = newpages;
VM_OBJECT_UNLOCK(sc->object);
} else if (newpages > oldpages) {
res = swap_reserve_by_cred(IDX_TO_OFF(newpages -
oldpages), sc->cred);
if (!res)
return (ENOMEM);
if ((mdio->md_options & MD_RESERVE) ||
(sc->flags & MD_RESERVE)) {
error = swap_pager_reserve(sc->object,
oldpages, newpages - oldpages);
if (error < 0) {
swap_release_by_cred(
IDX_TO_OFF(newpages - oldpages),
sc->cred);
return (EDOM);
}
}
VM_OBJECT_LOCK(sc->object);
sc->object->charge = IDX_TO_OFF(newpages);
sc->object->size = newpages;
VM_OBJECT_UNLOCK(sc->object);
}
break;
default:
return (EOPNOTSUPP);
}
sc->mediasize = mdio->md_mediasize;
g_topology_lock();
g_resize_provider(sc->pp, sc->mediasize);
g_topology_unlock();
return (0);
}
static int
mdcreate_swap(struct md_s *sc, struct md_ioctl *mdio, struct thread *td)
{
@ -1108,7 +1166,7 @@ mdcreate_swap(struct md_s *sc, struct md_ioctl *mdio, struct thread *td)
VM_PROT_DEFAULT, 0, td->td_ucred);
if (sc->object == NULL)
return (ENOMEM);
sc->flags = mdio->md_options & MD_FORCE;
sc->flags = mdio->md_options & (MD_FORCE | MD_RESERVE);
if (mdio->md_options & MD_RESERVE) {
if (swap_pager_reserve(sc->object, 0, npage) < 0) {
error = EDOM;
@ -1217,6 +1275,18 @@ xmdctlioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread
!(mdio->md_options & MD_FORCE))
return (EBUSY);
return (mddestroy(sc, td));
case MDIOCRESIZE:
if ((mdio->md_options & ~(MD_FORCE | MD_RESERVE)) != 0)
return (EINVAL);
sc = mdfind(mdio->md_unit);
if (sc == NULL)
return (ENOENT);
if (mdio->md_mediasize < sc->mediasize &&
!(sc->flags & MD_FORCE) &&
!(mdio->md_options & MD_FORCE))
return (EBUSY);
return (mdresize(sc, mdio));
case MDIOCQUERY:
sc = mdfind(mdio->md_unit);
if (sc == NULL)

View File

@ -79,6 +79,7 @@ struct md_ioctl {
#define MDIOCDETACH _IOWR('m', 1, struct md_ioctl) /* detach disk */
#define MDIOCQUERY _IOWR('m', 2, struct md_ioctl) /* query status */
#define MDIOCLIST _IOWR('m', 3, struct md_ioctl) /* query status */
#define MDIOCRESIZE _IOWR('m', 4, struct md_ioctl) /* resize disk */
#define MD_CLUSTER 0x01 /* Don't cluster */
#define MD_RESERVE 0x02 /* Pre-reserve swap */