aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/dev/vn/vn.c58
-rw-r--r--sys/sys/mdioctl.h3
-rw-r--r--sys/sys/vnioctl.h3
-rw-r--r--usr.sbin/vnconfig/vnconfig.826
-rw-r--r--usr.sbin/vnconfig/vnconfig.c104
5 files changed, 173 insertions, 21 deletions
diff --git a/sys/dev/vn/vn.c b/sys/dev/vn/vn.c
index 199c8046d460..54914b24f795 100644
--- a/sys/dev/vn/vn.c
+++ b/sys/dev/vn/vn.c
@@ -157,6 +157,7 @@ static SLIST_HEAD(, vn_softc) vn_list;
static u_long vn_options;
#define IFOPT(vn,opt) if (((vn)->sc_options|vn_options) & (opt))
+#define TESTOPT(vn,opt) (((vn)->sc_options|vn_options) & (opt))
static int vnsetcred (struct vn_softc *vn, struct ucred *cred);
static void vnclear (struct vn_softc *vn);
@@ -208,14 +209,23 @@ vnfindvn(dev_t dev)
static int
vnopen(dev_t dev, int flags, int mode, struct proc *p)
{
- int unit;
struct vn_softc *vn;
- unit = dkunit(dev);
- vn = dev->si_drv1;
- if (!vn)
+ /*
+ * Locate preexisting device
+ */
+
+ if ((vn = dev->si_drv1) == NULL)
vn = vnfindvn(dev);
+ /*
+ * Update si_bsize fields for device. This data will be overriden by
+ * the slice/parition code for vn accesses through partitions, and
+ * used directly if you open the 'whole disk' device.
+ */
+ dev->si_bsize_phys = vn->sc_secsize;
+ dev->si_bsize_best = vn->sc_secsize;
+
if (flags & FWRITE && vn->sc_flags & VNF_READONLY)
return (EACCES);
@@ -223,6 +233,10 @@ vnopen(dev_t dev, int flags, int mode, struct proc *p)
printf("vnopen(%s, 0x%x, 0x%x, %p)\n",
devtoname(dev), flags, mode, (void *)p);
+ /*
+ * Initialize label
+ */
+
IFOPT(vn, VN_LABELS) {
if (vn->sc_flags & VNF_INITED) {
struct disklabel label;
@@ -241,8 +255,9 @@ vnopen(dev_t dev, int flags, int mode, struct proc *p)
}
if (dkslice(dev) != WHOLE_DISK_SLICE ||
dkpart(dev) != RAW_PART ||
- mode != S_IFCHR)
+ mode != S_IFCHR) {
return (ENXIO);
+ }
}
return(0);
}
@@ -295,9 +310,9 @@ vnstrategy(struct buf *bp)
return;
}
} else {
- int pbn;
+ int pbn; /* in sc_secsize chunks */
- pbn = bp->b_blkno * (vn->sc_secsize / DEV_BSIZE);
+ pbn = bp->b_blkno / (vn->sc_secsize / DEV_BSIZE);
sz = howmany(bp->b_bcount, vn->sc_secsize);
if (pbn < 0 || pbn + sz > vn->sc_size) {
@@ -356,8 +371,17 @@ vnstrategy(struct buf *bp)
* OBJT_SWAP I/O
*
* ( handles read, write, freebuf )
+ *
+ * Note: if we pre-reserved swap, B_FREEBUF is disabled
*/
- vm_pager_strategy(vn->sc_object, bp);
+ KASSERT((bp->b_bufsize & (vn->sc_secsize - 1)) == 0,
+ ("vnstrategy: buffer %p to small for physio", bp));
+
+ if ((bp->b_flags & B_FREEBUF) && TESTOPT(vn, VN_RESERVE)) {
+ biodone(bp);
+ } else {
+ vm_pager_strategy(vn->sc_object, bp);
+ }
} else {
bp->b_flags |= B_ERROR;
bp->b_error = EINVAL;
@@ -504,13 +528,20 @@ vniocattach_file(vn, vio, dev, flag, p)
VOP_UNLOCK(nd.ni_vp, 0, p);
vn->sc_secsize = DEV_BSIZE;
vn->sc_vp = nd.ni_vp;
- vn->sc_size = vattr.va_size / vn->sc_secsize; /* note truncation */
+
+ /*
+ * If the size is specified, override the file attributes. Note that
+ * the vn_size argument is in PAGE_SIZE sized blocks.
+ */
+ if (vio->vn_size)
+ vn->sc_size = (quad_t)vio->vn_size * PAGE_SIZE / vn->sc_secsize;
+ else
+ vn->sc_size = vattr.va_size / vn->sc_secsize;
error = vnsetcred(vn, p->p_ucred);
if (error) {
(void) vn_close(nd.ni_vp, flags, p->p_ucred, p);
return(error);
}
- dev->si_bsize_phys = vn->sc_secsize;
vn->sc_flags |= VNF_INITED;
if (flags == FREAD)
vn->sc_flags |= VNF_READONLY;
@@ -571,6 +602,13 @@ vniocattach_swap(vn, vio, dev, flag, p)
vn->sc_size = vio->vn_size;
vn->sc_object =
vm_pager_allocate(OBJT_SWAP, NULL, vn->sc_secsize * (vm_ooffset_t)vio->vn_size, VM_PROT_DEFAULT, 0);
+ IFOPT(vn, VN_RESERVE) {
+ if (swap_pager_reserve(vn->sc_object, 0, vn->sc_size) < 0) {
+ vm_pager_deallocate(vn->sc_object);
+ vn->sc_object = NULL;
+ return(EDOM);
+ }
+ }
vn->sc_flags |= VNF_INITED;
error = vnsetcred(vn, p->p_ucred);
diff --git a/sys/sys/mdioctl.h b/sys/sys/mdioctl.h
index 4f2e9371ce96..b28374182821 100644
--- a/sys/sys/mdioctl.h
+++ b/sys/sys/mdioctl.h
@@ -38,6 +38,8 @@
* from: Utah $Hdr: fdioctl.h 1.1 90/07/09$
*
* @(#)vnioctl.h 8.1 (Berkeley) 6/10/93
+ *
+ * $FreeBSD$
*/
#ifndef _SYS_VNIOCTL_H_
@@ -72,5 +74,6 @@ struct vn_ioctl {
#define VN_DEBUG 0x4 /* Debug data in vn driver */
#define VN_IO 0x8 /* Debug I/O in vn driver */
#define VN_DONTCLUSTER 0x10 /* Don't cluster */
+#define VN_RESERVE 0x20 /* Pre-reserve swap */
#endif /* _SYS_VNIOCTL_H_*/
diff --git a/sys/sys/vnioctl.h b/sys/sys/vnioctl.h
index 4f2e9371ce96..b28374182821 100644
--- a/sys/sys/vnioctl.h
+++ b/sys/sys/vnioctl.h
@@ -38,6 +38,8 @@
* from: Utah $Hdr: fdioctl.h 1.1 90/07/09$
*
* @(#)vnioctl.h 8.1 (Berkeley) 6/10/93
+ *
+ * $FreeBSD$
*/
#ifndef _SYS_VNIOCTL_H_
@@ -72,5 +74,6 @@ struct vn_ioctl {
#define VN_DEBUG 0x4 /* Debug data in vn driver */
#define VN_IO 0x8 /* Debug I/O in vn driver */
#define VN_DONTCLUSTER 0x10 /* Don't cluster */
+#define VN_RESERVE 0x20 /* Pre-reserve swap */
#endif /* _SYS_VNIOCTL_H_*/
diff --git a/usr.sbin/vnconfig/vnconfig.8 b/usr.sbin/vnconfig/vnconfig.8
index 85ced187e917..7cfe517026c4 100644
--- a/usr.sbin/vnconfig/vnconfig.8
+++ b/usr.sbin/vnconfig/vnconfig.8
@@ -46,8 +46,8 @@
.Sh SYNOPSIS
.Nm vnconfig
.Op Fl cdeguv
-.Op Fl s Ar option
-.Op Fl r Ar option
+.Op Fl s Ar option[,option...]
+.Op Fl r Ar option[,option...]
.Op Fl S Ar value
.Ar special_file Ar [regular_file]
.Op Ar feature
@@ -106,6 +106,15 @@ The list of allowed flags and their meanings are:
.Bl -tag -width "follow"
.It Ar labels
use disk/slice labels.
+.It Ar reserve
+Pre-reserve the blocks underlying the file or swap backing store. Currently only
+works for swap backing store. This option also disables on-the-fly freeing of
+the underlying backing store (for example, when you remove a large file).
+Use this option if you wish to avoid long-term fragmentation of the backing
+store. Also note that when this option is used, the initial contents of the
+backing store may contain garbage rather then zeros. It may even be possible to
+recover the prior contents of a swap-backed VN across a reboot if the VN device
+is configured before any swap is allocated by the system.
.It Ar follow
debug flow in the
.Xr vn 4
@@ -133,7 +142,18 @@ option.
If no regular file is specified, VN will use swap for backing store.
This option specifies the size of the device. For example, '23m' for
23 megabytes. The VN device will round the size up to a machine page boundry.
-Filesystems up to 7.9 terrabytes are supported.
+Filesystems up to 7.9 terrabytes are supported. When specified along with
+a regular file, this option overrides the regular file's size insofar as
+VN is concerned.
+.It Fl T
+When a regular file is specified, VN will ftruncate() the file to 0 first.
+Normally you should also specify the -S option to set the size of the file.
+This option also creates the file if it did not previously exist.
+This option is only meaningful if the -S option has been specified.
+.It Fl Z
+When a regular file is specified, VN will zero the contents of the file to
+ensure that all blocks have been allocated by the filesystem. This option is
+only meaningful if the -S option has been specified.
.It Fl u
Disable and ``unconfigure'' the device.
.It Fl v
diff --git a/usr.sbin/vnconfig/vnconfig.c b/usr.sbin/vnconfig/vnconfig.c
index ce1f7eaae3de..c9f6e5e976df 100644
--- a/usr.sbin/vnconfig/vnconfig.c
+++ b/usr.sbin/vnconfig/vnconfig.c
@@ -51,6 +51,7 @@ static const char rcsid[] =
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
+#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <sys/param.h>
@@ -64,6 +65,7 @@ static const char rcsid[] =
#define MAXVNDISK 16
#define LINESIZE 1024
+#define ZBUFSIZE 32768
struct vndisk {
char *dev;
@@ -84,6 +86,8 @@ struct vndisk {
#define VN_IGNORE 0x80
#define VN_SET 0x100
#define VN_RESET 0x200
+#define VN_TRUNCATE 0x400
+#define VN_ZERO 0x800
int nvndisks;
@@ -111,9 +115,10 @@ main(argc, argv)
int flags = 0;
int size = 0;
char *autolabel = NULL;
+ char *s;
configfile = _PATH_VNTAB;
- while ((i = getopt(argc, argv, "acdef:gr:s:S:L:uv")) != -1)
+ while ((i = getopt(argc, argv, "acdef:gr:s:S:TZL:uv")) != -1)
switch (i) {
/* all -- use config file */
@@ -151,15 +156,19 @@ main(argc, argv)
/* reset options */
case 'r':
- if (what_opt(optarg,&resetopt))
- errx(1, "invalid options '%s'", optarg);
+ for (s = strtok(optarg, ","); s; s = strtok(NULL, ",")) {
+ if (what_opt(s, &resetopt))
+ errx(1, "invalid options '%s'", s);
+ }
flags |= VN_RESET;
break;
/* set options */
case 's':
- if (what_opt(optarg,&setopt))
- errx(1, "invalid options '%s'", optarg);
+ for (s = strtok(optarg, ","); s; s = strtok(NULL, ",")) {
+ if (what_opt(s, &setopt))
+ errx(1, "invalid options '%s'", s);
+ }
flags |= VN_SET;
break;
@@ -178,6 +187,14 @@ main(argc, argv)
size = getsize(optarg);
break;
+ case 'T':
+ flags |= VN_TRUNCATE;
+ break;
+
+ case 'Z':
+ flags |= VN_ZERO;
+ break;
+
case 'L':
autolabel = optarg;
break;
@@ -192,13 +209,13 @@ main(argc, argv)
if (flags == 0)
flags = VN_CONFIG;
- if (all)
+ if (all) {
readconfig(flags);
- else {
+ } else {
if (argc < optind + 1)
usage();
vndisks[0].dev = argv[optind++];
- vndisks[0].file = argv[optind++];
+ vndisks[0].file = argv[optind++]; /* may be NULL */
vndisks[0].flags = flags;
vndisks[0].size = size;
vndisks[0].autolabel = autolabel;
@@ -217,6 +234,7 @@ what_opt(str,p)
char *str;
u_long *p;
{
+ if (!strcmp(str,"reserve")) { *p |= VN_RESERVE; return 0; }
if (!strcmp(str,"labels")) { *p |= VN_LABELS; return 0; }
if (!strcmp(str,"follow")) { *p |= VN_FOLLOW; return 0; }
if (!strcmp(str,"debug")) { *p |= VN_DEBUG; return 0; }
@@ -237,6 +255,7 @@ config(vnp)
char *rdev;
FILE *f;
u_long l;
+ int pgsize = getpagesize();
rv = 0;
@@ -254,6 +273,47 @@ config(vnp)
if (flags & VN_IGNORE)
return(0);
+ /*
+ * When a regular file has been specified, do any requested setup
+ * of the file. Truncation (also creates the file if necessary),
+ * sizing, and zeroing.
+ */
+
+ if (file && vnp->size != 0 && (flags & VN_CONFIG)) {
+ int fd;
+ struct stat st;
+
+ if (flags & VN_TRUNCATE)
+ fd = open(file, O_RDWR|O_CREAT|O_TRUNC);
+ else
+ fd = open(file, O_RDWR);
+ if (fd >= 0 && fstat(fd, &st) == 0 && S_ISREG(st.st_mode)) {
+ if (st.st_size < (off_t)vnp->size * pgsize)
+ ftruncate(fd, (off_t)vnp->size * pgsize);
+ if (vnp->size != 0)
+ st.st_size = (off_t)vnp->size * pgsize;
+
+ if (flags & VN_ZERO) {
+ char *buf = malloc(ZBUFSIZE);
+ bzero(buf, ZBUFSIZE);
+ while (st.st_size > 0) {
+ int n = (st.st_size > ZBUFSIZE) ?
+ ZBUFSIZE : (int)st.st_size;
+ if (write(fd, buf, n) != n) {
+ ftruncate(fd, 0);
+ printf("Unable to ZERO file %s\n", file);
+ return(0);
+ }
+ st.st_size -= (off_t)n;
+ }
+ }
+ close(fd);
+ } else {
+ printf("Unable to open file %s\n", file);
+ return(0);
+ }
+ }
+
rdev = rawdevice(dev);
f = fopen(rdev, "rw");
if (f == NULL) {
@@ -294,6 +354,34 @@ config(vnp)
printf("%s: cleared\n", dev);
}
/*
+ * Set specified options
+ */
+ if (flags & VN_SET) {
+ l = setopt;
+ if (global)
+ rv = ioctl(fileno(f), VNIOCGSET, &l);
+ else
+ rv = ioctl(fileno(f), VNIOCUSET, &l);
+ if (rv) {
+ warn("VNIO[GU]SET");
+ } else if (verbose)
+ printf("%s: flags now=%08x\n",dev,l);
+ }
+ /*
+ * Reset specified options
+ */
+ if (flags & VN_RESET) {
+ l = resetopt;
+ if (global)
+ rv = ioctl(fileno(f), VNIOCGCLEAR, &l);
+ else
+ rv = ioctl(fileno(f), VNIOCUCLEAR, &l);
+ if (rv) {
+ warn("VNIO[GU]CLEAR");
+ } else if (verbose)
+ printf("%s: flags now=%08x\n",dev,l);
+ }
+ /*
* Configure the device
*/
if (flags & VN_CONFIG) {