summaryrefslogtreecommitdiffstats
path: root/sys/kern
diff options
context:
space:
mode:
authorbde <bde@FreeBSD.org>1995-02-18 22:10:44 +0000
committerbde <bde@FreeBSD.org>1995-02-18 22:10:44 +0000
commited02ff46e431b6f804926dcf2b9582f65b150dbf (patch)
tree6014ed9bc5467f4e71a6907d6e9254d596c3965a /sys/kern
parent476ac66c48a43ef9a3cbffbe75b6c07a5f978321 (diff)
downloadFreeBSD-src-ed02ff46e431b6f804926dcf2b9582f65b150dbf.zip
FreeBSD-src-ed02ff46e431b6f804926dcf2b9582f65b150dbf.tar.gz
Keep absolute offsets in on-disk labels for backwards compatibility. This
requires complications to adjust the offsets to relative when a block containing the label is read and back to absolute when such a block is written. The adjustment is not made on the whole disk slice. Don't allow setting the offset of partition C to nonzero in in-core labels. This will cause some (nonstandard) disktab entries to fail. They will need to be changed to have relative offsets (and no partitions outside of the slice). Don't write protect the (nonexistent) label on the whole disk slice. Writing labels and bootstraps should work right now (except if there is no DOSpartition table).
Diffstat (limited to 'sys/kern')
-rw-r--r--sys/kern/subr_diskslice.c123
1 files changed, 106 insertions, 17 deletions
diff --git a/sys/kern/subr_diskslice.c b/sys/kern/subr_diskslice.c
index 7dde87c..50a7923 100644
--- a/sys/kern/subr_diskslice.c
+++ b/sys/kern/subr_diskslice.c
@@ -43,7 +43,7 @@
* from: wd.c,v 1.55 1994/10/22 01:57:12 phk Exp $
* from: @(#)ufs_disksubr.c 7.16 (Berkeley) 5/4/91
* from: ufs_disksubr.c,v 1.8 1994/06/07 01:21:39 phk Exp $
- * $Id: subr_diskslice.c,v 1.3 1995/01/31 04:33:41 phk Exp $
+ * $Id: subr_diskslice.c,v 1.4 1995/02/16 15:19:00 bde Exp $
*/
#include <sys/param.h>
@@ -62,8 +62,11 @@
#define FALSE 0
#define TRUE 1
+
typedef u_char bool_t;
+static void adjust_label __P((struct disklabel *lp, u_long offset));
+static void dsiodone __P((struct buf *bp));
static char *fixlabel __P((char *dname, int unit, int slice,
struct diskslice *sp, struct disklabel *lp));
static void partition_info __P((char *dname, int unit, int slice,
@@ -77,6 +80,20 @@ static void set_ds_label __P((struct diskslices *ssp, int slice,
static void set_ds_wlabel __P((struct diskslices *ssp, int slice,
int wlabel));
+static void
+adjust_label(lp, offset)
+ struct disklabel *lp;
+ u_long offset;
+{
+ int part;
+ struct partition *pp;
+
+ pp = &lp->d_partitions[0];
+ for (part = 0; part < lp->d_npartitions; part++, pp++)
+ if (pp->p_offset != 0 || pp->p_size != 0)
+ pp->p_offset += offset;
+}
+
/*
* Determine the size of the transfer, and make sure it is
* within the boundaries of the partition. Adjust transfer
@@ -162,11 +179,48 @@ if (labelsect != 0) Debugger("labelsect != 0 in dscheck()");
/* calculate cylinder for disksort to order transfers with */
bp->b_pblkno = blkno + sp->ds_offset;
-
if (lp == NULL)
bp->b_cylinder = 0; /* XXX always 0 would be better */
else
bp->b_cylinder = bp->b_pblkno / lp->d_secpercyl;
+
+ /*
+ * Snoop on label accesses if the slice offset is nonzero. Fudge
+ * offsets in the label to keep the in-core label coherent with
+ * the on-disk one.
+ */
+ if (blkno <= LABELSECTOR + labelsect
+#if LABELSECTOR != 0
+ && bp->b_blkno + sz > LABELSECTOR + labelsect
+#endif
+ && sp->ds_offset != 0) {
+ struct iodone_chain *ic;
+
+ ic = malloc(sizeof *ic , M_DEVBUF, M_WAITOK);
+ ic->ic_prev_flags = bp->b_flags;
+ ic->ic_prev_iodone = bp->b_iodone;
+ ic->ic_prev_iodone_chain = bp->b_iodone_chain;
+ ic->ic_args[0].ia_long = (LABELSECTOR + labelsect - blkno)
+ << DEV_BSHIFT;
+ ic->ic_args[1].ia_long = sp->ds_offset;
+ bp->b_flags |= B_CALL;
+ bp->b_iodone = dsiodone;
+ bp->b_iodone_chain = ic;
+ if (!(bp->b_flags & B_READ)) {
+ /*
+ * XXX even disklabel(8) writes directly so we need
+ * to adjust writes. Perhaps we should drop support
+ * for DIOCWLABEL (always write protect labels) and
+ * require the use of DIOCWDINFO.
+ *
+ * XXX probably need to copy the data to avoid even
+ * temporarily corrupting the in-core copy.
+ */
+ adjust_label((struct disklabel *)
+ (bp->b_data + ic->ic_args[0].ia_long),
+ sp->ds_offset);
+ }
+ }
return (1);
bad:
@@ -287,6 +341,9 @@ dsioctl(dev, cmd, data, flags, ssp, strat, setgeom)
error = setdisklabel(lp, (struct disklabel *)data,
sp->ds_label != NULL
? sp->ds_openmask : (u_long)0);
+ /* XXX why doesn't setdisklabel() check this? */
+ if (error == 0 && lp->d_partitions[RAW_PART].p_offset != 0)
+ error = EINVAL;
#if 0 /* XXX */
if (error != 0 && setgeom != NULL)
error = setgeom(lp);
@@ -311,7 +368,17 @@ dsioctl(dev, cmd, data, flags, ssp, strat, setgeom)
*/
old_wlabel = sp->ds_wlabel;
set_ds_wlabel(ssp, slice, TRUE);
- error = correct_writedisklabel(dev, strat, sp->ds_label);
+ /*
+ * XXX convert on-disk label offsets to absolute sectors for
+ * backwards compatibility.
+ */
+ lp = malloc(sizeof *lp, M_DEVBUF, M_WAITOK);
+ *lp = *sp->ds_label;
+ adjust_label(lp, sp->ds_offset);
+
+ error = correct_writedisklabel(dev, strat, lp);
+ /* XXX should restore old label if writedisklabel() failed. */
+ free(lp, M_DEVBUF);
set_ds_wlabel(ssp, slice, old_wlabel);
return (error);
@@ -328,6 +395,27 @@ dsioctl(dev, cmd, data, flags, ssp, strat, setgeom)
}
}
+static void
+dsiodone(bp)
+ struct buf *bp;
+{
+ struct iodone_chain *ic;
+ struct disklabel *lp;
+
+ ic = bp->b_iodone_chain;
+ bp->b_flags = (ic->ic_prev_flags & B_CALL)
+ | (bp->b_flags & ~(B_CALL | B_DONE));
+ bp->b_iodone = ic->ic_prev_iodone;
+ bp->b_iodone_chain = ic->ic_prev_iodone_chain;
+ free(ic, M_DEVBUF);
+ lp = (struct disklabel *)(bp->b_data + ic->ic_args[0].ia_long);
+ if (!(bp->b_flags & B_READ))
+ adjust_label(lp, ic->ic_args[1].ia_long);
+ else if (!(bp->b_flags & B_ERROR) && bp->b_error == 0)
+ adjust_label(lp, -lp->d_partitions[RAW_PART].p_offset);
+ biodone(bp);
+}
+
int
dsisopen(ssp)
struct diskslices *ssp;
@@ -403,8 +491,11 @@ dsopen(dname, dev, mode, sspp, lp, strat, setgeom)
lp1 = malloc(sizeof *lp1, M_DEVBUF, M_WAITOK);
*lp1 = *lp;
lp = lp1;
- if (slice == WHOLE_DISK_SLICE)
- goto set;
+ if (slice == WHOLE_DISK_SLICE) {
+ sp->ds_label = lp;
+ sp->ds_wlabel = TRUE;
+ goto out;
+ }
printf("readdisklabel\n");
msg = correct_readdisklabel(dkmodpart(dev, RAW_PART), strat, lp);
#if 0 /* XXX */
@@ -446,9 +537,7 @@ dsopen(dname, dev, mode, sspp, lp, strat, setgeom)
return (EINVAL); /* XXX needs translation */
}
}
-set:
set_ds_label(ssp, slice, lp);
- set_ds_wlabel(ssp, slice, FALSE);
}
if (part != RAW_PART
&& (sp->ds_label == NULL || part >= sp->ds_label->d_npartitions))
@@ -476,7 +565,7 @@ fixlabel(dname, unit, slice, sp, lp)
struct disklabel *lp;
{
bool_t adjust;
- int bsdpart;
+ int part;
struct partition *pp;
bool_t warned;
@@ -511,7 +600,7 @@ fixlabel(dname, unit, slice, sp, lp)
warned = TRUE;
}
pp -= LABEL_PART;
- for (bsdpart = 0; bsdpart < lp->d_npartitions; bsdpart++, pp++) {
+ for (part = 0; part < lp->d_npartitions; part++, pp++) {
if (adjust && (pp->p_offset != 0 || pp->p_size != 0))
pp->p_offset -= sp->ds_offset;
if (pp->p_offset + pp->p_size > sp->ds_size
@@ -525,7 +614,7 @@ fixlabel(dname, unit, slice, sp, lp)
}
if (adjust)
pp->p_offset += sp->ds_offset;
- partition_info(dname, unit, slice, bsdpart, pp);
+ partition_info(dname, unit, slice, part, pp);
bzero(pp, sizeof *pp);
}
}
@@ -548,13 +637,6 @@ partition_info(dname, unit, slice, part, pp)
pp->p_offset, pp->p_offset + pp->p_size - 1, pp->p_size);
}
-/*
- * Most changes to ds_bad, ds_label and ds_wlabel are made using the
- * following functions to ensure coherency of the compatibility slice
- * with the first BSD slice. The openmask fields are _not_ shared and
- * the other fields (ds_offset and ds_size) aren't changed after they
- * are initialized.
- */
static void
slice_info(dname, unit, slice, sp)
char *dname;
@@ -567,6 +649,13 @@ slice_info(dname, unit, slice, sp)
sp->ds_offset, sp->ds_offset + sp->ds_size - 1, sp->ds_size);
}
+/*
+ * Most changes to ds_bad, ds_label and ds_wlabel are made using the
+ * following functions to ensure coherency of the compatibility slice
+ * with the first BSD slice. The openmask fields are _not_ shared and
+ * the other fields (ds_offset and ds_size) aren't changed after they
+ * are initialized.
+ */
static void
set_ds_bad(ssp, slice, btp)
struct diskslices *ssp;
OpenPOWER on IntegriCloud