Allow configuration of the sector size advertised to the guest.

The default behavior is to infer the logical and physical sector sizes from
the block device backend. However older versions of Windows only work with
specific logical/physical combinations:
- Vista and Windows 7:	512/512
- Windows 7 SP1:	512/512 or 512/4096

For this reason allow the sector size to be specified using the following
block device option: sectorsize=logical[/physical]

Reported by:	Leon Dang (ldang@nahannisys.com)
Reviewed by:	grehan
MFC after:	2 weeks
This commit is contained in:
Neel Natu 2015-05-12 00:30:39 +00:00
parent be59bc7ae9
commit 4e43c1e8b5
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=282788
2 changed files with 69 additions and 26 deletions

View File

@ -193,8 +193,13 @@ format.
.Pp
Block storage devices:
.Bl -tag -width 10n
.It Pa /filename Ns Oo , Ns Li nocache Oc Ns Oo , Ns Li direct Oc Ns Oo , Ns Li ro Oc
.It Pa /dev/xxx Ns Oo , Ns Ar nocache Oc Ns Oo , Ns Ar direct Oc Ns Oo , Ns Ar ro Oc
.It Pa /filename Ns Oo , Ns Ar block-device-options Oc
.It Pa /dev/xxx Ns Oo , Ns Ar block-device-options Oc
.El
.Pp
The
.Ar block-device-options
are:
.Bl -tag -width 8n
.It Li nocache
Open the file with
@ -204,14 +209,10 @@ Open the file using
.Dv O_SYNC .
.It Li ro
Force the file to be opened read-only.
.El
.Pp
The
.Li nocache ,
.Li direct ,
and
.Li ro
options are not available for virtio block devices.
.It Li sectorsize= Ns Ar logical Ns Oo / Ns Ar physical Oc
Specify the logical and physical sector sizes of the emulated disk.
The physical sector size is optional and is equal to the logical sector size
if not explicitly specified.
.El
.Pp
TTY devices:

View File

@ -392,16 +392,18 @@ blockif_open(const char *optstr, const char *ident)
{
char tname[MAXCOMLEN + 1];
char name[MAXPATHLEN];
char *nopt, *xopts;
char *nopt, *xopts, *cp;
struct blockif_ctxt *bc;
struct stat sbuf;
struct diocgattr_arg arg;
off_t size, psectsz, psectoff;
int extra, fd, i, sectsz;
int nocache, sync, ro, candelete, geom;
int nocache, sync, ro, candelete, geom, ssopt, pssopt;
pthread_once(&blockif_once, blockif_init);
fd = -1;
ssopt = 0;
nocache = 0;
sync = 0;
ro = 0;
@ -410,16 +412,25 @@ blockif_open(const char *optstr, const char *ident)
* The first element in the optstring is always a pathname.
* Optional elements follow
*/
nopt = strdup(optstr);
for (xopts = strtok(nopt, ",");
xopts != NULL;
xopts = strtok(NULL, ",")) {
if (!strcmp(xopts, "nocache"))
nopt = xopts = strdup(optstr);
while (xopts != NULL) {
cp = strsep(&xopts, ",");
if (cp == nopt) /* file or device pathname */
continue;
else if (!strcmp(cp, "nocache"))
nocache = 1;
else if (!strcmp(xopts, "sync"))
else if (!strcmp(cp, "sync") || !strcmp(cp, "direct"))
sync = 1;
else if (!strcmp(xopts, "ro"))
else if (!strcmp(cp, "ro"))
ro = 1;
else if (sscanf(cp, "sectorsize=%d/%d", &ssopt, &pssopt) == 2)
;
else if (sscanf(cp, "sectorsize=%d", &ssopt) == 1)
pssopt = ssopt;
else {
fprintf(stderr, "Invalid device option \"%s\"\n", cp);
goto err;
}
}
extra = 0;
@ -437,13 +448,12 @@ blockif_open(const char *optstr, const char *ident)
if (fd < 0) {
perror("Could not open backing file");
return (NULL);
goto err;
}
if (fstat(fd, &sbuf) < 0) {
perror("Could not stat backing file");
close(fd);
return (NULL);
goto err;
}
/*
@ -457,8 +467,7 @@ blockif_open(const char *optstr, const char *ident)
if (ioctl(fd, DIOCGMEDIASIZE, &size) < 0 ||
ioctl(fd, DIOCGSECTORSIZE, &sectsz)) {
perror("Could not fetch dev blk/sector size");
close(fd);
return (NULL);
goto err;
}
assert(size != 0);
assert(sectsz != 0);
@ -473,10 +482,39 @@ blockif_open(const char *optstr, const char *ident)
} else
psectsz = sbuf.st_blksize;
if (ssopt != 0) {
if (!powerof2(ssopt) || !powerof2(pssopt) || ssopt < 512 ||
ssopt > pssopt) {
fprintf(stderr, "Invalid sector size %d/%d\n",
ssopt, pssopt);
goto err;
}
/*
* Some backend drivers (e.g. cd0, ada0) require that the I/O
* size be a multiple of the device's sector size.
*
* Validate that the emulated sector size complies with this
* requirement.
*/
if (S_ISCHR(sbuf.st_mode)) {
if (ssopt < sectsz || (ssopt % sectsz) != 0) {
fprintf(stderr, "Sector size %d incompatible "
"with underlying device sector size %d\n",
ssopt, sectsz);
goto err;
}
}
sectsz = ssopt;
psectsz = pssopt;
psectoff = 0;
}
bc = calloc(1, sizeof(struct blockif_ctxt));
if (bc == NULL) {
close(fd);
return (NULL);
perror("calloc");
goto err;
}
bc->bc_magic = BLOCKIF_SIG;
@ -506,6 +544,10 @@ blockif_open(const char *optstr, const char *ident)
}
return (bc);
err:
if (fd >= 0)
close(fd);
return (NULL);
}
static int