We should not allow disklabel to 'hint' that an ffs filesystem can
have a fragment size less than the disk's sector size.

amd64 should write the disklabel at the same spot that readdoslabel()
reads it no matter what the sector size is.

amd64/i386 installboot should provide the correct shift value to
convert filessystem block addresses (which are expressed in fs_fsize
units) to disk sector addresses for the BIOS to use.

With these changes 512-byte devices continue to work and I can also
create, newfs, fsck and installboot to 2048 and 4096 byte sector
devices.

Note: this *may* enable booting from some devices but I haven't got
any devices that my machines recognize as bootable devices.

Previosly sent out without the installboot fsbtodb correction.

ok?

.... Ken

Index: sbin/disklabel/editor.c
===================================================================
RCS file: /cvs/src/sbin/disklabel/editor.c,v
retrieving revision 1.256
diff -u -p -r1.256 editor.c
--- sbin/disklabel/editor.c     24 May 2011 15:27:56 -0000      1.256
+++ sbin/disklabel/editor.c     1 Jul 2011 20:53:04 -0000
@@ -667,7 +667,8 @@ cylinderalign:
                /* Everything seems ok so configure the partition. */
                DL_SETPSIZE(pp, secs);
                DL_SETPOFFSET(pp, chunkstart);
-               fragsize = 2048;
+               fragsize = (lp->d_secsize == DEV_BSIZE) ? 2048 :
+                   lp->d_secsize;
                if (secs * lp->d_secsize > 128ULL * 1024 * 1024 * 1024)
                        fragsize *= 2;
                if (secs * lp->d_secsize > 512ULL * 1024 * 1024 * 1024)
Index: sys/arch/amd64/amd64/disksubr.c
===================================================================
RCS file: /cvs/src/sys/arch/amd64/amd64/disksubr.c,v
retrieving revision 1.61
diff -u -p -r1.61 disksubr.c
--- sys/arch/amd64/amd64/disksubr.c     16 Apr 2011 03:21:15 -0000      1.61
+++ sys/arch/amd64/amd64/disksubr.c     1 Jul 2011 20:53:04 -0000
@@ -122,6 +122,7 @@ int
 writedisklabel(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp)
 {
        int error = EIO, partoff = -1;
+       int offset;
        struct disklabel *dlp;
        struct buf *bp = NULL;
 
@@ -133,15 +134,15 @@ writedisklabel(dev_t dev, void (*strat)(
                goto done;
 
        /* Read it in, slap the new label in, and write it back out */
-       bp->b_blkno = partoff + LABELSECTOR;
-       bp->b_bcount = lp->d_secsize;
+       bp->b_blkno = DL_BLKTOSEC(lp, partoff+LABELSECTOR) * DL_BLKSPERSEC(lp);
+       offset = DL_BLKOFFSET(lp, partoff + LABELSECTOR) + LABELOFFSET;
        CLR(bp->b_flags, B_READ | B_WRITE | B_DONE);
        SET(bp->b_flags, B_BUSY | B_READ | B_RAW);
        (*strat)(bp);
        if ((error = biowait(bp)) != 0)
                goto done;
 
-       dlp = (struct disklabel *)(bp->b_data + LABELOFFSET);
+       dlp = (struct disklabel *)(bp->b_data + offset);
        *dlp = *lp;
        CLR(bp->b_flags, B_READ | B_WRITE | B_DONE);
        SET(bp->b_flags, B_BUSY | B_WRITE | B_RAW);
Index: sys/arch/amd64/stand/biosboot/biosboot.S
===================================================================
RCS file: /cvs/src/sys/arch/amd64/stand/biosboot/biosboot.S,v
retrieving revision 1.6
diff -u -p -r1.6 biosboot.S
--- sys/arch/amd64/stand/biosboot/biosboot.S    9 Jul 2010 17:36:38 -0000       
1.6
+++ sys/arch/amd64/stand/biosboot/biosboot.S    4 Jul 2011 18:59:26 -0000
@@ -91,8 +91,8 @@
  *                     where we load the block to.)
  * fs_bsize_p  uint16  the filesystem block size _in paragraphs_
  *                     (i.e. fs_bsize / 16)
- * fs_bsize_s  uint16  the number of 512-byte sectors in a filesystem
- *                     block (i.e. fs_bsize / 512).  Directly written
+ * fs_bsize_s  uint16  the number of disk sectors in a filesystem
+ *                     block (i.e. fs_bsize / d_secsize). Directly written
  *                     into the LBA command block, at lba_count.
  *                     XXX LIMITED TO 127 BY PHOENIX EDD SPEC.
  * fsbtodb     uint8   shift count to convert filesystem blocks to
Index: sys/arch/amd64/stand/installboot/installboot.c
===================================================================
RCS file: /cvs/src/sys/arch/amd64/stand/installboot/installboot.c,v
retrieving revision 1.20
diff -u -p -r1.20 installboot.c
--- sys/arch/amd64/stand/installboot/installboot.c      3 Jul 2011 19:21:48 
-0000       1.20
+++ sys/arch/amd64/stand/installboot/installboot.c      4 Jul 2011 20:58:00 
-0000
@@ -215,6 +215,7 @@ void
 write_bootblocks(int devfd, struct disklabel *dl)
 {
        struct stat     sb;
+       u_int8_t        *secbuf;
        u_int           start = 0;
 
        /* Write patched proto bootblock(s) into the superblock. */
@@ -240,7 +241,7 @@ write_bootblocks(int devfd, struct diskl
                        errx(1, "no OpenBSD partition");
        }
 
-       if (start + (protosize / DEV_BSIZE) > BOOTBIOS_MAXSEC)
+       if (start + (protosize / dl->d_secsize) > BOOTBIOS_MAXSEC)
                errx(1, "invalid location: all of /boot must be < sector %u.",
                    BOOTBIOS_MAXSEC);
 
@@ -248,9 +249,13 @@ write_bootblocks(int devfd, struct diskl
                fprintf(stderr, "/boot will be written at sector %u\n", start);
 
        if (!nowrite) {
-               if (lseek(devfd, (off_t)start * dl->d_secsize, SEEK_SET) < 0 ||
-                   write(devfd, protostore, protosize) != protosize)
+               if (lseek(devfd, (off_t)start * dl->d_secsize, SEEK_SET) < 0)
+                       err(1, "seek bootstrap");
+               secbuf = calloc(1, dl->d_secsize);
+               bcopy(protostore, secbuf, protosize);
+               if (write(devfd, secbuf, dl->d_secsize) != dl->d_secsize)
                        err(1, "write bootstrap");
+               free(secbuf);
        }
 }
 
@@ -261,6 +266,7 @@ findopenbsd(int devfd, struct disklabel 
        u_int           mbroff = DOSBBSECTOR;
        u_int           mbr_eoff = DOSBBSECTOR; /* Offset of extended part. */
        struct          dos_partition *dp;
+       u_int8_t        *secbuf;
        int             i, maxebr = DOS_MAXEBR, nextebr;
 
 again:
@@ -277,9 +283,12 @@ again:
                    (mbroff == DOSBBSECTOR) ? "master" : "extended",
                    (mbroff == DOSBBSECTOR) ? 'M' : 'E', mbroff);
 
+       secbuf = malloc(dl->d_secsize); 
        if (lseek(devfd, (off_t)mbroff * dl->d_secsize, SEEK_SET) < 0 ||
-           read(devfd, &mbr, sizeof(mbr)) != sizeof(mbr))
+           read(devfd, secbuf, dl->d_secsize) < sizeof(mbr))
                err(4, "can't read boot record");
+       bcopy(secbuf, &mbr, sizeof(mbr));
+       free(secbuf);
 
        if (mbr.dmbr_sign != DOSMBR_SIGNATURE)
                errx(1, "invalid boot record signature (0x%04X) @ sector %u",
@@ -477,7 +486,8 @@ getbootparams(char *boot, int devfd, str
        close(fd);
 
        /* Read superblock. */
-       devread(devfd, sblock, pp->p_offset + SBLOCK, SBSIZE, "superblock");
+       devread(devfd, sblock, DL_SECTOBLK(dl, pp->p_offset) + SBLOCK,
+           SBSIZE, "superblock");
        fs = (struct fs *)sblock;
 
        /* Sanity-check super-block. */
@@ -492,7 +502,8 @@ getbootparams(char *boot, int devfd, str
 
        blk = fsbtodb(fs, ino_to_fsba(fs, statbuf.st_ino));
 
-       devread(devfd, buf, pp->p_offset + blk, fs->fs_bsize, "inode");
+       devread(devfd, buf, DL_SECTOBLK(dl, pp->p_offset) + blk,
+           fs->fs_bsize, "inode");
        ip = (struct ufs1_dinode *)(buf) + ino_to_fsbo(fs, statbuf.st_ino);
 
        /*
@@ -508,8 +519,21 @@ getbootparams(char *boot, int devfd, str
         * (the partition boot record, a.k.a. the PBR).
         */
        sym_set_value(pbr_symbols, "_fs_bsize_p", (fs->fs_bsize / 16));
-       sym_set_value(pbr_symbols, "_fs_bsize_s", (fs->fs_bsize / 512));
-       sym_set_value(pbr_symbols, "_fsbtodb", fs->fs_fsbtodb);
+       sym_set_value(pbr_symbols, "_fs_bsize_s", (fs->fs_bsize / 
+           dl->d_secsize));
+
+       /*
+        * fs_fsbtodb is the shift to convert fs_fsize to DEV_BSIZE. The
+        * ino_to_fsba() return value is the number of fs_fsize units.
+        * Calculate the shift to convert fs_fsize into physical sectors,
+        * which are added to p_offset to get the sector address BIOS
+        * will use.
+        *
+        * N.B.: ASSUMES fs_fsize is a power of 2 of d_secsize.
+        */
+       sym_set_value(pbr_symbols, "_fsbtodb",
+           ffs(fs->fs_fsize / dl->d_secsize) - 1);
+
        sym_set_value(pbr_symbols, "_p_offset", pp->p_offset);
        sym_set_value(pbr_symbols, "_inodeblk",
            ino_to_fsba(fs, statbuf.st_ino));
@@ -523,7 +547,8 @@ getbootparams(char *boot, int devfd, str
                    boot, ndb, fs->fs_bsize);
                fprintf(stderr, "fs block shift %u; part offset %u; "
                    "inode block %lld, offset %u\n",
-                   fs->fs_fsbtodb, pp->p_offset,
+                   ffs(fs->fs_fsize / dl->d_secsize) - 1,
+                   pp->p_offset,
                    ino_to_fsba(fs, statbuf.st_ino),
                    (unsigned int)((((char *)ap) - buf) + INODEOFF));
        }
Index: sys/arch/i386/stand/biosboot/biosboot.S
===================================================================
RCS file: /cvs/src/sys/arch/i386/stand/biosboot/biosboot.S,v
retrieving revision 1.40
diff -u -p -r1.40 biosboot.S
--- sys/arch/i386/stand/biosboot/biosboot.S     30 Sep 2009 19:03:17 -0000      
1.40
+++ sys/arch/i386/stand/biosboot/biosboot.S     4 Jul 2011 19:41:12 -0000
@@ -91,8 +91,8 @@
  *                     where we load the block to.)
  * fs_bsize_p  uint16  the filesystem block size _in paragraphs_
  *                     (i.e. fs_bsize / 16)
- * fs_bsize_s  uint16  the number of 512-byte sectors in a filesystem
- *                     block (i.e. fs_bsize / 512).  Directly written
+ * fs_bsize_s  uint16  the number of disk sectors in a filesystem
+ *                     block (i.e. fs_bsize / d_secsize). Directly written
  *                     into the LBA command block, at lba_count.
  *                     XXX LIMITED TO 127 BY PHOENIX EDD SPEC.
  * fsbtodb     uint8   shift count to convert filesystem blocks to
Index: sys/arch/i386/stand/installboot/installboot.c
===================================================================
RCS file: /cvs/src/sys/arch/i386/stand/installboot/installboot.c,v
retrieving revision 1.63
diff -u -p -r1.63 installboot.c
--- sys/arch/i386/stand/installboot/installboot.c       3 Jul 2011 19:21:48 
-0000       1.63
+++ sys/arch/i386/stand/installboot/installboot.c       4 Jul 2011 21:02:17 
-0000
@@ -211,6 +211,7 @@ void
 write_bootblocks(int devfd, struct disklabel *dl)
 {
        struct stat     sb;
+       u_int8_t        *secbuf;
        u_int           start = 0;
 
        /* Write patched proto bootblock(s) into the superblock. */
@@ -236,7 +237,7 @@ write_bootblocks(int devfd, struct diskl
                        errx(1, "no OpenBSD partition");
        }
 
-       if (start + (protosize / DEV_BSIZE) > BOOTBIOS_MAXSEC)
+       if (start + (protosize / dl->d_secsize) > BOOTBIOS_MAXSEC)
                errx(1, "invalid location: all of /boot must be < sector %u.",
                    BOOTBIOS_MAXSEC);
 
@@ -244,9 +245,13 @@ write_bootblocks(int devfd, struct diskl
                fprintf(stderr, "/boot will be written at sector %u\n", start);
 
        if (!nowrite) {
-               if (lseek(devfd, (off_t)start * dl->d_secsize, SEEK_SET) < 0 ||
-                   write(devfd, protostore, protosize) != protosize)
+               if (lseek(devfd, (off_t)start * dl->d_secsize, SEEK_SET) < 0)
+                       err(1, "seek bootstrap");
+               secbuf = calloc(1, dl->d_secsize);
+               bcopy(protostore, secbuf, protosize);
+               if (write(devfd, secbuf, dl->d_secsize) != dl->d_secsize)
                        err(1, "write bootstrap");
+               free(secbuf);
        }
 }
 
@@ -257,6 +262,7 @@ findopenbsd(int devfd, struct disklabel 
        u_int           mbroff = DOSBBSECTOR;
        u_int           mbr_eoff = DOSBBSECTOR; /* Offset of extended part. */
        struct          dos_partition *dp;
+       u_int8_t        *secbuf;
        int             i, maxebr = DOS_MAXEBR, nextebr;
 
 again:
@@ -273,9 +279,12 @@ again:
                    (mbroff == DOSBBSECTOR) ? "master" : "extended",
                    (mbroff == DOSBBSECTOR) ? 'M' : 'E', mbroff);
 
+       secbuf = malloc(dl->d_secsize); 
        if (lseek(devfd, (off_t)mbroff * dl->d_secsize, SEEK_SET) < 0 ||
-           read(devfd, &mbr, sizeof(mbr)) != sizeof(mbr))
+           read(devfd, secbuf, dl->d_secsize) < sizeof(mbr))
                err(4, "can't read boot record");
+       bcopy(secbuf, &mbr, sizeof(mbr));
+       free(secbuf);
 
        if (mbr.dmbr_sign != DOSMBR_SIGNATURE)
                errx(1, "invalid boot record signature (0x%04X) @ sector %u",
@@ -473,7 +482,8 @@ getbootparams(char *boot, int devfd, str
        close(fd);
 
        /* Read superblock. */
-       devread(devfd, sblock, pp->p_offset + SBLOCK, SBSIZE, "superblock");
+       devread(devfd, sblock, DL_SECTOBLK(dl, pp->p_offset) + SBLOCK,
+           SBSIZE, "superblock");
        fs = (struct fs *)sblock;
 
        /* Sanity-check super-block. */
@@ -488,7 +498,8 @@ getbootparams(char *boot, int devfd, str
 
        blk = fsbtodb(fs, ino_to_fsba(fs, statbuf.st_ino));
 
-       devread(devfd, buf, pp->p_offset + blk, fs->fs_bsize, "inode");
+       devread(devfd, buf, DL_SECTOBLK(dl, pp->p_offset) + blk,
+           fs->fs_bsize, "inode");
        ip = (struct ufs1_dinode *)(buf) + ino_to_fsbo(fs, statbuf.st_ino);
 
        /*
@@ -504,8 +515,21 @@ getbootparams(char *boot, int devfd, str
         * (the partition boot record, a.k.a. the PBR).
         */
        sym_set_value(pbr_symbols, "_fs_bsize_p", (fs->fs_bsize / 16));
-       sym_set_value(pbr_symbols, "_fs_bsize_s", (fs->fs_bsize / 512));
-       sym_set_value(pbr_symbols, "_fsbtodb", fs->fs_fsbtodb);
+       sym_set_value(pbr_symbols, "_fs_bsize_s", (fs->fs_bsize / 
+           dl->d_secsize));
+
+       /*
+        * fs_fsbtodb is the shift to convert fs_fsize to DEV_BSIZE. The
+        * ino_to_fsba() return value is the number of fs_fsize units.
+        * Calculate the shift to convert fs_fsize into physical sectors,
+        * which are added to p_offset to get the sector address BIOS
+        * will use.
+        *
+        * N.B.: ASSUMES fs_fsize is a power of 2 of d_secsize.
+        */
+       sym_set_value(pbr_symbols, "_fsbtodb",
+           ffs(fs->fs_fsize / dl->d_secsize) - 1);
+
        sym_set_value(pbr_symbols, "_p_offset", pp->p_offset);
        sym_set_value(pbr_symbols, "_inodeblk",
            ino_to_fsba(fs, statbuf.st_ino));
@@ -518,10 +542,11 @@ getbootparams(char *boot, int devfd, str
                fprintf(stderr, "%s is %d blocks x %d bytes\n",
                    boot, ndb, fs->fs_bsize);
                fprintf(stderr, "fs block shift %u; part offset %u; "
-                   "inode block %lld, offset %ld\n",
-                   fs->fs_fsbtodb, pp->p_offset,
+                   "inode block %lld, offset %u\n",
+                   ffs(fs->fs_fsize / dl->d_secsize) - 1,
+                   pp->p_offset,
                    ino_to_fsba(fs, statbuf.st_ino),
-                   ((((char *)ap) - buf) + INODEOFF));
+                   (unsigned int)((((char *)ap) - buf) + INODEOFF));
        }
 
        return 0;

Reply via email to