aboutsummaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/md/md.c72
-rw-r--r--sys/sys/mdioctl.h1
2 files changed, 72 insertions, 1 deletions
diff --git a/sys/dev/md/md.c b/sys/dev/md/md.c
index 8ff52a9c883b..4d4c22c9765d 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)
diff --git a/sys/sys/mdioctl.h b/sys/sys/mdioctl.h
index 82ac397530f3..5efae7908003 100644
--- a/sys/sys/mdioctl.h
+++ b/sys/sys/mdioctl.h
@@ -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 */