summaryrefslogtreecommitdiffstats
path: root/sys/dev/md
diff options
context:
space:
mode:
authortrasz <trasz@FreeBSD.org>2012-07-07 20:32:21 +0000
committertrasz <trasz@FreeBSD.org>2012-07-07 20:32:21 +0000
commit1a80449f25e6980accddd15147c01f7c51e59731 (patch)
tree43f177b6e61b4e88e7b97088b0b3392ef38588c2 /sys/dev/md
parentb5336ab352c11dcd18cdec71746a53518ab2f96f (diff)
downloadFreeBSD-src-1a80449f25e6980accddd15147c01f7c51e59731.zip
FreeBSD-src-1a80449f25e6980accddd15147c01f7c51e59731.tar.gz
Make it possible to resize md(4) devices.
Reviewed by: kib Sponsored by: FreeBSD Foundation
Diffstat (limited to 'sys/dev/md')
-rw-r--r--sys/dev/md/md.c72
1 files changed, 71 insertions, 1 deletions
diff --git a/sys/dev/md/md.c b/sys/dev/md/md.c
index 8ff52a9..4d4c22c 100644
--- a/sys/dev/md/md.c
+++ b/sys/dev/md/md.c
@@ -1081,6 +1081,64 @@ mddestroy(struct md_s *sc, struct thread *td)
}
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)
{
vm_ooffset_t npage;
@@ -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)
OpenPOWER on IntegriCloud