mirror of
https://git.FreeBSD.org/src.git
synced 2025-01-17 15:27:36 +00:00
Fix a bug in the block number calculation for VN disks with a sector
size != 512 that are configured without a label. The bug should only have effected swap-backed VN mounts without a label. Add several major features to VN. In the kernel we add a swap pre-reservation capability, which can be used to guarentee seek consistency for swap-backed VN nodes. This also incidently allows a swap-backed VN filesystem to be recovered after a crash in some cases (if the same swap blocks happen to be reserved). We also add a number of new options to vnconfig which do the work of pre-zeroing or creating/truncating/extending a file which greatly simplifies using VN in a file-backed configuration. Add FreeBSD CVS label to sys/sys/vnioctl.h, as well as a new ioctl flag for the swap pre-reservation feature. Reviewed by: Alan Cox <alc@cs.rice.edu>, David Greenman <dg@root.com>
This commit is contained in:
parent
24579ca1d7
commit
447deba3da
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=51341
@ -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);
|
||||
|
@ -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_*/
|
||||
|
@ -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_*/
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
@ -293,6 +353,34 @@ config(vnp)
|
||||
} else if (verbose)
|
||||
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
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user