1 /*
2 * Copyright (c) 1982, 1986, 1988, 1993
3 * The Regents of the University of California. All rights reserved.
4 * (c) UNIX System Laboratories, Inc.
5 * All or some portions of this file are derived from material licensed
6 * to the University of California by American Telephone and Telegraph
7 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
8 * the permission of UNIX System Laboratories, Inc.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the University of
21 * California, Berkeley and its contributors.
22 * 4. Neither the name of the University nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
37 *
38 * @(#)ufs_disksubr.c 8.5 (Berkeley) 1/21/94
39 * $FreeBSD: releng/5.0/sys/kern/subr_disklabel.c 103714 2002-09-20 19:36:05Z phk $
40 */
41
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/stdint.h>
45 #include <sys/bio.h>
46 #include <sys/buf.h>
47 #include <sys/conf.h>
48 #include <sys/kernel.h>
49 #include <sys/disk.h>
50 #include <sys/disklabel.h>
51 #include <sys/syslog.h>
52
53 /*
54 * Attempt to read a disk label from a device using the indicated strategy
55 * routine. The label must be partly set up before this: secpercyl, secsize
56 * and anything required in the strategy routine (e.g., dummy bounds for the
57 * partition containing the label) must be filled in before calling us.
58 * Returns NULL on success and an error string on failure.
59 */
60 char *
61 readdisklabel(dev, lp)
62 dev_t dev;
63 register struct disklabel *lp;
64 {
65 register struct buf *bp;
66 struct disklabel *dlp;
67 char *msg = NULL;
68
69 bp = geteblk((int)lp->d_secsize);
70 bp->b_dev = dev;
71 bp->b_blkno = LABELSECTOR * ((int)lp->d_secsize/DEV_BSIZE);
72 bp->b_bcount = lp->d_secsize;
73 bp->b_flags &= ~B_INVAL;
74 bp->b_iocmd = BIO_READ;
75 DEV_STRATEGY(bp, 1);
76 if (bufwait(bp))
77 msg = "I/O error";
78 else if (bp->b_resid != 0)
79 msg = "disk too small for a label";
80 else for (dlp = (struct disklabel *)bp->b_data;
81 dlp <= (struct disklabel *)((char *)bp->b_data +
82 lp->d_secsize - sizeof(*dlp));
83 dlp = (struct disklabel *)((char *)dlp + sizeof(long))) {
84 if (dlp->d_magic != DISKMAGIC || dlp->d_magic2 != DISKMAGIC) {
85 if (msg == NULL)
86 msg = "no disk label";
87 } else if (dlp->d_npartitions > MAXPARTITIONS ||
88 dkcksum(dlp) != 0)
89 msg = "disk label corrupted";
90 else {
91 *lp = *dlp;
92 msg = NULL;
93 break;
94 }
95 }
96 bp->b_flags |= B_INVAL | B_AGE;
97 brelse(bp);
98 return (msg);
99 }
100
101 /*
102 * Check new disk label for sensibility before setting it.
103 */
104 int
105 setdisklabel(olp, nlp, openmask)
106 register struct disklabel *olp, *nlp;
107 u_long openmask;
108 {
109 register int i;
110 register struct partition *opp, *npp;
111
112 /*
113 * Check it is actually a disklabel we are looking at.
114 */
115 if (nlp->d_magic != DISKMAGIC || nlp->d_magic2 != DISKMAGIC ||
116 dkcksum(nlp) != 0)
117 return (EINVAL);
118 /*
119 * For each partition that we think is open,
120 */
121 while ((i = ffs((long)openmask)) != 0) {
122 i--;
123 /*
124 * Check it is not changing....
125 */
126 openmask &= ~(1 << i);
127 if (nlp->d_npartitions <= i)
128 return (EBUSY);
129 opp = &olp->d_partitions[i];
130 npp = &nlp->d_partitions[i];
131 if (npp->p_offset != opp->p_offset || npp->p_size < opp->p_size)
132 return (EBUSY);
133 /*
134 * Copy internally-set partition information
135 * if new label doesn't include it. XXX
136 * (If we are using it then we had better stay the same type)
137 * This is possibly dubious, as someone else noted (XXX)
138 */
139 if (npp->p_fstype == FS_UNUSED && opp->p_fstype != FS_UNUSED) {
140 npp->p_fstype = opp->p_fstype;
141 npp->p_fsize = opp->p_fsize;
142 npp->p_frag = opp->p_frag;
143 npp->p_cpg = opp->p_cpg;
144 }
145 }
146 nlp->d_checksum = 0;
147 nlp->d_checksum = dkcksum(nlp);
148 *olp = *nlp;
149 return (0);
150 }
151
152 /*
153 * Write disk label back to device after modification.
154 */
155 int
156 writedisklabel(dev, lp)
157 dev_t dev;
158 register struct disklabel *lp;
159 {
160 struct buf *bp;
161 struct disklabel *dlp;
162 int error = 0;
163
164 if (lp->d_partitions[RAW_PART].p_offset != 0)
165 return (EXDEV); /* not quite right */
166 bp = geteblk((int)lp->d_secsize);
167 bp->b_dev = dkmodpart(dev, RAW_PART);
168 bp->b_blkno = LABELSECTOR * ((int)lp->d_secsize/DEV_BSIZE);
169 bp->b_bcount = lp->d_secsize;
170 #if 1
171 /*
172 * We read the label first to see if it's there,
173 * in which case we will put ours at the same offset into the block..
174 * (I think this is stupid [Julian])
175 * Note that you can't write a label out over a corrupted label!
176 * (also stupid.. how do you write the first one? by raw writes?)
177 */
178 bp->b_flags &= ~B_INVAL;
179 bp->b_iocmd = BIO_READ;
180 DEV_STRATEGY(bp, 1);
181 error = bufwait(bp);
182 if (error)
183 goto done;
184 if (bp->b_resid != 0) {
185 error = ENOSPC;
186 goto done;
187 }
188 for (dlp = (struct disklabel *)bp->b_data;
189 dlp <= (struct disklabel *)
190 ((char *)bp->b_data + lp->d_secsize - sizeof(*dlp));
191 dlp = (struct disklabel *)((char *)dlp + sizeof(long))) {
192 if (dlp->d_magic == DISKMAGIC && dlp->d_magic2 == DISKMAGIC &&
193 dkcksum(dlp) == 0) {
194 *dlp = *lp;
195 bp->b_flags &= ~B_DONE;
196 bp->b_iocmd = BIO_WRITE;
197 #ifdef __alpha__
198 alpha_fix_srm_checksum(bp);
199 #endif
200 DEV_STRATEGY(bp, 1);
201 error = bufwait(bp);
202 goto done;
203 }
204 }
205 error = ESRCH;
206 done:
207 #else
208 bzero(bp->b_data, lp->d_secsize);
209 dlp = (struct disklabel *)bp->b_data;
210 *dlp = *lp;
211 bp->b_flags &= ~B_INVAL;
212 bp->b_iocmd = BIO_WRITE;
213 DEV_STRATEGY(bp, 1);
214 error = bufwait(bp);
215 #endif
216 bp->b_flags |= B_INVAL | B_AGE;
217 brelse(bp);
218 return (error);
219 }
220
221 /*
222 * Determine the size of the transfer, and make sure it is
223 * within the boundaries of the partition. Adjust transfer
224 * if needed, and signal errors or early completion.
225 */
226 int
227 bounds_check_with_label(struct bio *bp, struct disklabel *lp, int wlabel)
228 {
229 struct partition *p = lp->d_partitions + dkpart(bp->bio_dev);
230 int labelsect = lp->d_partitions[0].p_offset;
231 int maxsz = p->p_size,
232 sz = (bp->bio_bcount + DEV_BSIZE - 1) >> DEV_BSHIFT;
233
234 /* overwriting disk label ? */
235 /* XXX should also protect bootstrap in first 8K */
236 if (bp->bio_blkno + p->p_offset <= LABELSECTOR + labelsect &&
237 #if LABELSECTOR != 0
238 bp->bio_blkno + p->p_offset + sz > LABELSECTOR + labelsect &&
239 #endif
240 (bp->bio_cmd == BIO_WRITE) && wlabel == 0) {
241 bp->bio_error = EROFS;
242 goto bad;
243 }
244
245 #if defined(DOSBBSECTOR) && defined(notyet)
246 /* overwriting master boot record? */
247 if (bp->bio_blkno + p->p_offset <= DOSBBSECTOR &&
248 (bp->bio_cmd == BIO_WRITE) && wlabel == 0) {
249 bp->bio_error = EROFS;
250 goto bad;
251 }
252 #endif
253
254 /* beyond partition? */
255 if (bp->bio_blkno < 0 || bp->bio_blkno + sz > maxsz) {
256 /* if exactly at end of disk, return an EOF */
257 if (bp->bio_blkno == maxsz) {
258 bp->bio_resid = bp->bio_bcount;
259 return(0);
260 }
261 /* or truncate if part of it fits */
262 sz = maxsz - bp->bio_blkno;
263 if (sz <= 0) {
264 bp->bio_error = EINVAL;
265 goto bad;
266 }
267 bp->bio_bcount = sz << DEV_BSHIFT;
268 }
269
270 bp->bio_pblkno = bp->bio_blkno + p->p_offset;
271 return(1);
272
273 bad:
274 bp->bio_flags |= BIO_ERROR;
275 return(-1);
276 }
277
Cache object: 6a438804dbc4a951ba3c8cae86e89a03
|