Allow the sector size to be specified by the user when configuring a
authorjsing <jsing@openbsd.org>
Thu, 14 Aug 2008 17:10:29 +0000 (17:10 +0000)
committerjsing <jsing@openbsd.org>
Thu, 14 Aug 2008 17:10:29 +0000 (17:10 +0000)
vnd(4) device, via a new -s option to vnconfig/mount_vnd. This allows us
to create disklabels and file systems that are suitable for use on
devices that have a non-512 byte sector size (eg. CDROMs).

With help from krw@ and feedback from pedro@.

ok krw@, pedro@

sbin/mount_vnd/mount_vnd.8
sbin/mount_vnd/mount_vnd.c
sys/dev/vnd.c
sys/dev/vndioctl.h

index fe3a863..a44c76a 100644 (file)
@@ -1,4 +1,4 @@
-.\"    $OpenBSD: mount_vnd.8,v 1.13 2008/05/26 21:14:46 jmc Exp $
+.\"    $OpenBSD: mount_vnd.8,v 1.14 2008/08/14 17:10:29 jsing Exp $
 .\"
 .\" Copyright (c) 1993 University of Utah.
 .\" Copyright (c) 1980, 1989, 1991, 1993
@@ -49,7 +49,7 @@
 .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 .\"
-.Dd $Mdocdate: May 26 2008 $
+.Dd $Mdocdate: August 14 2008 $
 .Dt MOUNT_VND 8
 .Os
 .Sh NAME
@@ -63,6 +63,7 @@
 .Op Fl K Ar rounds
 .Op Fl o Ar options
 .Op Fl S Ar saltfile
+.Op Fl s Ar secsize
 .Ar image
 .Ar vnd_dev
 .Ek
@@ -71,6 +72,7 @@
 .Op Fl ckluv
 .Op Fl K Ar rounds
 .Op Fl S Ar saltfile
+.Op Fl s Ar secsize
 .Ar vnd_dev
 .Ar image
 .Ek
@@ -208,6 +210,12 @@ If the salt filename is not specified using
 .Fl S ,
 it defaults to
 .Ar image Ns .slt .
+.It Fl s Ar secsize
+Specify the sector size, in bytes, to be used by the device.
+The default sector size is 512 bytes.
+If specified
+.Ar secsize
+must be a multiple of 512 bytes and cannot exceed 65536 bytes.
 .It Fl u
 .Nm vnconfig
 only.
index 50fe655..70441e4 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: mount_vnd.c,v 1.5 2008/06/14 01:47:27 grunk Exp $     */
+/*     $OpenBSD: mount_vnd.c,v 1.6 2008/08/14 17:10:29 jsing Exp $     */
 /*
  * Copyright (c) 1993 University of Utah.
  * Copyright (c) 1990, 1993
@@ -67,7 +67,7 @@ int verbose = 0;
 int run_mount_vnd = 0;
 
 __dead void     usage(void);
-int             config(char *, char *, int, char *, size_t);
+int             config(char *, char *, int, size_t, char *, size_t);
 int             getinfo(const char *);
 char           *get_pkcs_key(char *, char *);
 
@@ -76,7 +76,8 @@ main(int argc, char **argv)
 {
        int      ch, rv, action, opt_c, opt_k, opt_K, opt_l, opt_u;
        char    *key, *mntopts, *rounds, *saltopt;
-       size_t   keylen = 0;
+       size_t   keylen = 0, secsize = 0;
+       const char *errstr;
        extern char *__progname;
 
        if (strcasecmp(__progname, "mount_vnd") == 0)
@@ -86,7 +87,7 @@ main(int argc, char **argv)
        key = mntopts = rounds = saltopt = NULL;
        action = VND_CONFIG;
 
-       while ((ch = getopt(argc, argv, "ckK:lo:S:uv")) != -1) {
+       while ((ch = getopt(argc, argv, "ckK:lo:s:S:uv")) != -1) {
                switch (ch) {
                case 'c':
                        opt_c = 1;
@@ -107,6 +108,11 @@ main(int argc, char **argv)
                case 'S':
                        saltopt = optarg;
                        break;
+               case 's':
+                       secsize = strtonum(optarg, 512, 65536, &errstr);
+                       if (errstr || (secsize & 0x1ff) != 0)
+                               errx(1, "invalid sector size: %s", optarg);
+                       break;
                case 'u':
                        opt_u = 1;
                        break;
@@ -156,9 +162,10 @@ main(int argc, char **argv)
                        ind_raw = 0;
                        ind_reg = 1;
                }
-               rv = config(argv[ind_raw], argv[ind_reg], action, key, keylen);
+               rv = config(argv[ind_raw], argv[ind_reg], action, secsize, key,
+                   keylen);
        } else if (action == VND_UNCONFIG && argc == 1)
-               rv = config(argv[0], NULL, action, NULL, 0);
+               rv = config(argv[0], NULL, action, 0, NULL, 0);
        else if (action == VND_GET)
                rv = getinfo(argc ? argv[0] : NULL);
        else
@@ -274,7 +281,8 @@ query:
 }
 
 int
-config(char *dev, char *file, int action, char *key, size_t keylen)
+config(char *dev, char *file, int action, size_t secsize, char *key,
+    size_t keylen)
 {
        struct vnd_ioctl vndio;
        FILE *f;
@@ -289,6 +297,7 @@ config(char *dev, char *file, int action, char *key, size_t keylen)
                goto out;
        }
        vndio.vnd_file = file;
+       vndio.vnd_secsize = secsize;
        vndio.vnd_key = (u_char *)key;
        vndio.vnd_keylen = keylen;
 
index 602f56f..fe4c9d3 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: vnd.c,v 1.88 2008/07/23 16:24:43 beck Exp $   */
+/*     $OpenBSD: vnd.c,v 1.89 2008/08/14 17:10:29 jsing Exp $  */
 /*     $NetBSD: vnd.c,v 1.26 1996/03/30 23:06:11 christos Exp $        */
 
 /*
@@ -128,7 +128,8 @@ struct vnd_softc {
 
        char             sc_file[VNDNLEN];      /* file we're covering */
        int              sc_flags;              /* flags */
-       size_t           sc_size;               /* size of vnd in blocks */
+       size_t           sc_size;               /* size of vnd in sectors */
+       size_t           sc_secsize;            /* sector size in bytes */
        struct vnode    *sc_vp;                 /* vnode */
        struct ucred    *sc_cred;               /* credentials */
        struct buf       sc_tab;                /* transfer queue */
@@ -305,7 +306,7 @@ vndgetdisklabel(dev_t dev, struct vnd_softc *sc, struct disklabel *lp,
 
        bzero(lp, sizeof(struct disklabel));
 
-       lp->d_secsize = DEV_BSIZE;
+       lp->d_secsize = sc->sc_secsize;
        lp->d_ntracks = 1;
        lp->d_nsectors = 100;
        lp->d_ncylinders = sc->sc_size / 100;
@@ -407,6 +408,16 @@ vndstrategy(struct buf *bp)
                return;
        }
 
+       /* Ensure that the requested block is sector aligned. */
+       if (bp->b_blkno % DL_BLKSPERSEC(vnd->sc_dk.dk_label) != 0) {
+               bp->b_error = EINVAL;
+               bp->b_flags |= B_ERROR;
+               s = splbio();
+               biodone(bp);
+               splx(s);
+               return;
+       }
+
        bn = bp->b_blkno;
        bp->b_resid = bp->b_bcount;
 
@@ -434,15 +445,18 @@ vndstrategy(struct buf *bp)
                bp->b_resid = bp->b_bcount;
        }
 
-       sz = howmany(bp->b_bcount, DEV_BSIZE);
+       if (vnd->sc_flags & VNF_HAVELABEL)
+               sz = howmany(bp->b_bcount, vnd->sc_dk.dk_label->d_secsize);
+       else
+               sz = howmany(bp->b_bcount, DEV_BSIZE);
 
        /* No bypassing of buffer cache?  */
        if (vndsimple(bp->b_dev)) {
                /* Loop until all queued requests are handled.  */
                for (;;) {
                        int part = DISKPART(bp->b_dev);
-                       daddr64_t off = DL_GETPOFFSET(&vnd->sc_dk.dk_label->d_partitions[part]);
-
+                       daddr64_t off = DL_SECTOBLK(vnd->sc_dk.dk_label,
+                           DL_GETPOFFSET(&vnd->sc_dk.dk_label->d_partitions[part]));
                        aiov.iov_base = bp->b_data;
                        auio.uio_resid = aiov.iov_len = bp->b_bcount;
                        auio.uio_iov = &aiov;
@@ -509,7 +523,8 @@ vndstrategy(struct buf *bp)
        }
 
        /* The old-style buffercache bypassing method.  */
-       bn += DL_GETPOFFSET(&vnd->sc_dk.dk_label->d_partitions[DISKPART(bp->b_dev)]);
+       bn += DL_SECTOBLK(vnd->sc_dk.dk_label,
+           DL_GETPOFFSET(&vnd->sc_dk.dk_label->d_partitions[DISKPART(bp->b_dev)]));
        bn = dbtob(bn);
        bsize = vnd->sc_vp->v_mount->mnt_stat.f_iosize;
        addr = bp->b_data;
@@ -714,7 +729,6 @@ vndbdevsize(struct vnode *vp, struct proc *p)
 {
        struct partinfo pi;
        struct bdevsw *bsw;
-       long sscale;
        dev_t dev;
 
        dev = vp->v_rdev;
@@ -723,10 +737,9 @@ vndbdevsize(struct vnode *vp, struct proc *p)
                return (0);
        if (bsw->d_ioctl(dev, DIOCGPART, (caddr_t)&pi, FREAD, p))
                return (0);
-       sscale = pi.disklab->d_secsize / DEV_BSIZE;
-       DNPRINTF(VDB_INIT, "vndbdevsize: size %li secsize %li sscale %li\n",
-           (long)pi.part->p_size,(long)pi.disklab->d_secsize,sscale);
-       return (pi.part->p_size * sscale);
+       DNPRINTF(VDB_INIT, "vndbdevsize: size %li secsize %li\n",
+           (long)pi.part->p_size,(long)pi.disklab->d_secsize);
+       return (pi.part->p_size);
 }
 
 /* ARGSUSED */
@@ -777,6 +790,14 @@ vndioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
                        return(ENXIO);
                }
 
+               /* Set sector size for device, if specified. */
+               if (vio->vnd_secsize == 0)
+                       vnd->sc_secsize = DEV_BSIZE;
+               else if (vio->vnd_secsize % DEV_BSIZE == 0)
+                       vnd->sc_secsize = vio->vnd_secsize;
+               else
+                       return (EINVAL);
+
                /*
                 * Open for read and write first. This lets vn_open() weed out
                 * directories, sockets, etc. so we don't have to worry about
@@ -811,7 +832,7 @@ vndioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
                                vndunlock(vnd);
                                return (error);
                        }
-                       vnd->sc_size = btodb(vattr.va_size); /* note truncation */
+                       vnd->sc_size = vattr.va_size / vnd->sc_secsize;
                }
                VOP_UNLOCK(nd.ni_vp, 0, p);
                vnd->sc_vp = nd.ni_vp;
@@ -842,7 +863,7 @@ vndioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
                } else
                        vnd->sc_keyctx = NULL;
 
-               vio->vnd_size = dbtob((off_t)vnd->sc_size);
+               vio->vnd_size = vnd->sc_size * vnd->sc_secsize;
                vnd->sc_flags |= VNF_INITED;
 
                DNPRINTF(VDB_INIT, "vndioctl: SET vp %p size %llx\n",
@@ -1004,7 +1025,7 @@ vndsetcred(struct vnd_softc *vnd, struct ucred *cred)
 
        /* XXX: Horrible kludge to establish credentials for NFS */
        aiov.iov_base = tmpbuf;
-       aiov.iov_len = MIN(DEV_BSIZE, dbtob((off_t)vnd->sc_size));
+       aiov.iov_len = MIN(DEV_BSIZE, vnd->sc_size * vnd->sc_secsize);
        auio.uio_iov = &aiov;
        auio.uio_iovcnt = 1;
        auio.uio_offset = 0;
@@ -1055,7 +1076,7 @@ vndsize(dev_t dev)
 
        if (unit >= numvnd || (vnd->sc_flags & VNF_INITED) == 0)
                return (-1);
-       return (vnd->sc_size);
+       return (vnd->sc_size * (vnd->sc_secsize / DEV_BSIZE));
 }
 
 int
index 2227952..6995d80 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: vndioctl.h,v 1.6 2004/06/20 18:03:03 pedro Exp $      */
+/*     $OpenBSD: vndioctl.h,v 1.7 2008/08/14 17:10:29 jsing Exp $      */
 /*     $NetBSD: vndioctl.h,v 1.5 1995/01/25 04:46:30 cgd Exp $ */
 
 /*
@@ -49,6 +49,7 @@
  */
 struct vnd_ioctl {
        char    *vnd_file;      /* pathname of file to mount */
+       size_t  vnd_secsize;    /* sector size in bytes */
        off_t   vnd_size;       /* (returned) size of disk */
        u_char  *vnd_key;
        int     vnd_keylen;