AMD64 - Fix many compile-time warnings. int/ptr type mismatches, %llx, etc.
[dragonfly.git] / sys / kern / subr_diskslice.c
CommitLineData
984263bc
MD
1/*-
2 * Copyright (c) 1994 Bruce D. Evans.
3 * All rights reserved.
4 *
5 * Copyright (c) 1990 The Regents of the University of California.
6 * All rights reserved.
7 *
8 * This code is derived from software contributed to Berkeley by
9 * William Jolitz.
10 *
11 * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
12 * All rights reserved.
13 *
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions
16 * are met:
17 * 1. Redistributions of source code must retain the above copyright
18 * notice, this list of conditions and the following disclaimer.
19 * 2. Redistributions in binary form must reproduce the above copyright
20 * notice, this list of conditions and the following disclaimer in the
21 * documentation and/or other materials provided with the distribution.
22 * 3. All advertising materials mentioning features or use of this software
23 * must display the following acknowledgement:
24 * This product includes software developed by the University of
25 * California, Berkeley and its contributors.
26 * 4. Neither the name of the University nor the names of its contributors
27 * may be used to endorse or promote products derived from this software
28 * without specific prior written permission.
29 *
30 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
31 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
32 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
34 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
35 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
36 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
37 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
38 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
39 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
40 * SUCH DAMAGE.
41 *
42 * from: @(#)wd.c 7.2 (Berkeley) 5/9/91
43 * from: wd.c,v 1.55 1994/10/22 01:57:12 phk Exp $
44 * from: @(#)ufs_disksubr.c 7.16 (Berkeley) 5/4/91
45 * from: ufs_disksubr.c,v 1.8 1994/06/07 01:21:39 phk Exp $
46 * $FreeBSD: src/sys/kern/subr_diskslice.c,v 1.82.2.6 2001/07/24 09:49:41 dd Exp $
a9bf1b8c 47 * $DragonFly: src/sys/kern/subr_diskslice.c,v 1.51 2008/08/29 20:08:36 dillon Exp $
984263bc
MD
48 */
49
50#include <sys/param.h>
51#include <sys/systm.h>
52#include <sys/buf.h>
53#include <sys/conf.h>
54#include <sys/disklabel.h>
2b961883 55#include <sys/disklabel32.h>
0ffe40b3 56#include <sys/disklabel64.h>
984263bc 57#include <sys/diskslice.h>
a688b15c 58#include <sys/disk.h>
dc62b251 59#include <sys/diskmbr.h>
984263bc
MD
60#include <sys/fcntl.h>
61#include <sys/malloc.h>
62#include <sys/stat.h>
63#include <sys/syslog.h>
fef8985e 64#include <sys/proc.h>
984263bc 65#include <sys/vnode.h>
335dda38 66#include <sys/device.h>
e43a034f 67#include <sys/thread2.h>
984263bc 68
50e58362
MD
69#include <vfs/ufs/dinode.h> /* XXX used only for fs.h */
70#include <vfs/ufs/fs.h> /* XXX used only to get BBSIZE/SBSIZE */
984263bc 71
5350e1e9
MD
72static int dsreadandsetlabel(cdev_t dev, u_int flags,
73 struct diskslices *ssp, struct diskslice *sp,
74 struct disk_info *info);
402ed7e1 75static void free_ds_label (struct diskslices *ssp, int slice);
0ffe40b3
MD
76static void set_ds_label (struct diskslices *ssp, int slice, disklabel_t lp,
77 disklabel_ops_t ops);
e1c7bccd 78static void set_ds_wlabel (struct diskslices *ssp, int slice, int wlabel);
984263bc
MD
79
80/*
984263bc
MD
81 * Determine the size of the transfer, and make sure it is
82 * within the boundaries of the partition. Adjust transfer
83 * if needed, and signal errors or early completion.
84 *
85 * XXX TODO:
86 * o Split buffers that are too big for the device.
87 * o Check for overflow.
88 * o Finish cleaning this up.
ea5f2871
HP
89 *
90 * This function returns 1 on success, 0 if transfer equates
91 * to EOF (end of disk) or -1 on failure. The appropriate
92 * 'errno' value is also set in bp->b_error and bp->b_flags
93 * is marked with B_ERROR.
984263bc 94 */
81b5c339 95struct bio *
b13267a5 96dscheck(cdev_t dev, struct bio *bio, struct diskslices *ssp)
984263bc 97{
81b5c339
MD
98 struct buf *bp = bio->bio_buf;
99 struct bio *nbio;
2b961883 100 disklabel_t lp;
0ffe40b3 101 disklabel_ops_t ops;
e1c7bccd 102 long nsec;
e0fc5693
MD
103 u_int64_t secno;
104 u_int64_t endsecno;
e0fc5693 105 u_int64_t slicerel_secno;
984263bc 106 struct diskslice *sp;
5350e1e9
MD
107 u_int32_t part;
108 u_int32_t slice;
54078292
MD
109 int shift;
110 int mask;
984263bc 111
5350e1e9
MD
112 slice = dkslice(dev);
113 part = dkpart(dev);
114
54078292 115 if (bio->bio_offset < 0) {
6ea70f76 116 kprintf("dscheck(%s): negative bio_offset %lld\n",
973c11b9 117 devtoname(dev), (long long)bio->bio_offset);
984263bc
MD
118 goto bad;
119 }
5350e1e9
MD
120 if (slice >= ssp->dss_nslices) {
121 kprintf("dscheck(%s): slice too large %d/%d\n",
122 devtoname(dev), slice, ssp->dss_nslices);
123 goto bad;
124 }
125 sp = &ssp->dss_slices[slice];
54078292 126
5350e1e9
MD
127 /*
128 * Calculate secno and nsec
129 */
984263bc 130 if (ssp->dss_secmult == 1) {
54078292
MD
131 shift = DEV_BSHIFT;
132 goto doshift;
984263bc 133 } else if (ssp->dss_secshift != -1) {
54078292
MD
134 shift = DEV_BSHIFT + ssp->dss_secshift;
135doshift:
136 mask = (1 << shift) - 1;
137 if ((int)bp->b_bcount & mask)
984263bc 138 goto bad_bcount;
54078292 139 if ((int)bio->bio_offset & mask)
984263bc 140 goto bad_blkno;
e0fc5693 141 secno = bio->bio_offset >> shift;
54078292 142 nsec = bp->b_bcount >> shift;
984263bc
MD
143 } else {
144 if (bp->b_bcount % ssp->dss_secsize)
145 goto bad_bcount;
54078292 146 if (bio->bio_offset % ssp->dss_secsize)
984263bc 147 goto bad_blkno;
e0fc5693 148 secno = bio->bio_offset / ssp->dss_secsize;
984263bc
MD
149 nsec = bp->b_bcount / ssp->dss_secsize;
150 }
5350e1e9
MD
151
152 /*
153 * Calculate slice-relative sector number end slice-relative
154 * limit.
155 */
8a88e0d0 156 if (slice == WHOLE_DISK_SLICE) {
5350e1e9
MD
157 /*
158 * Labels have not been allowed on whole-disks for a while.
2b961883 159 * This really puts the nail in the coffin.
8a88e0d0
MD
160 *
161 * Accesses to the WHOLE_DISK_SLICE do not use a disklabel
162 * and partition numbers are special-cased. Currently numbers
163 * less then 128 are not allowed. Partition numbers >= 128
164 * are encoded in the high 8 bits of the 64 bit buffer offset
165 * and are fed directly through to the device with no
166 * further interpretation. In particular, no sector
167 * translation interpretation should occur because the
168 * sector size for the special raw access may not be the
169 * same as the nominal sector size for the device.
170 */
2b961883 171 lp.opaque = NULL;
8a88e0d0
MD
172 if (part < 128) {
173 kprintf("dscheck(%s): illegal partition number (%d) "
174 "for WHOLE_DISK_SLICE access\n",
175 devtoname(dev), part);
176 goto bad;
177 } else if (part != WHOLE_SLICE_PART) {
178 nbio = push_bio(bio);
179 nbio->bio_offset = bio->bio_offset |
180 (u_int64_t)part << 56;
181 return(nbio);
182 }
183
184 /*
1c3c151b
MD
185 * sp->ds_size is for the whole disk in the WHOLE_DISK_SLICE,
186 * there are no reserved areas.
8a88e0d0 187 */
984263bc
MD
188 endsecno = sp->ds_size;
189 slicerel_secno = secno;
5350e1e9 190 } else if (part == WHOLE_SLICE_PART) {
5a8edc7a 191 /*
5a8edc7a 192 * NOTE! opens on a whole-slice partition will not attempt
1c3c151b
MD
193 * to read a disklabel in, so there may not be an in-core
194 * disklabel even if there is one on the disk.
5350e1e9 195 */
5350e1e9
MD
196 endsecno = sp->ds_size;
197 slicerel_secno = secno;
2b961883 198 } else if ((lp = sp->ds_label).opaque != NULL) {
5a8edc7a 199 /*
ba0cc1ab
MD
200 * A label is present, extract the partition. Snooping of
201 * the disklabel is not supported even if accessible. Of
202 * course, the reserved area is still write protected.
5a8edc7a 203 */
0ffe40b3
MD
204 ops = sp->ds_ops;
205 if (ops->op_getpartbounds(ssp, lp, part,
206 &slicerel_secno, &endsecno)) {
ba0cc1ab
MD
207 kprintf("dscheck(%s): partition %d out of bounds\n",
208 devtoname(dev), part);
209 goto bad;
210 }
211 slicerel_secno += secno;
984263bc 212 } else {
8a88e0d0 213 /*
5a8edc7a 214 * Attempt to access partition when no disklabel present
8a88e0d0 215 */
0ca0cd25 216 kprintf("dscheck(%s): attempt to access non-existent partition\n",
5a8edc7a
MD
217 devtoname(dev));
218 goto bad;
984263bc
MD
219 }
220
5a8edc7a 221 /*
1c3c151b 222 * Disallow writes to reserved areas unless ds_wlabel allows it.
5a8edc7a 223 */
1c3c151b 224 if (slicerel_secno < sp->ds_reserved && nsec &&
a9bf1b8c 225 bp->b_cmd == BUF_CMD_WRITE && sp->ds_wlabel == 0) {
984263bc 226 bp->b_error = EROFS;
4414f2c9 227 goto error;
984263bc
MD
228 }
229
8a88e0d0 230 /*
5a8edc7a
MD
231 * If we get here, bio_offset must be on a block boundary and
232 * the sector size must be a power of 2.
8a88e0d0
MD
233 */
234 if ((bio->bio_offset & (ssp->dss_secsize - 1)) ||
235 (ssp->dss_secsize ^ (ssp->dss_secsize - 1)) !=
236 ((ssp->dss_secsize << 1) - 1)) {
237 kprintf("%s: invalid BIO offset, not sector aligned or"
238 " invalid sector size (not power of 2) %08llx %d\n",
973c11b9
MD
239 devtoname(dev), (long long)bio->bio_offset,
240 ssp->dss_secsize);
8a88e0d0 241 goto bad;
984263bc 242 }
984263bc 243
4414f2c9
MD
244 /*
245 * EOF handling
246 */
984263bc 247 if (secno + nsec > endsecno) {
9a71d53f 248 /*
4414f2c9
MD
249 * Return an error if beyond the end of the disk, or
250 * if B_BNOCLIP is set. Tell the system that we do not
251 * need to keep the buffer around.
252 */
253 if (secno > endsecno || (bp->b_flags & B_BNOCLIP))
254 goto bad;
255
256 /*
257 * If exactly at end of disk, return an EOF. Throw away
258 * the buffer contents, if any, by setting B_INVAL.
9a71d53f 259 */
984263bc
MD
260 if (secno == endsecno) {
261 bp->b_resid = bp->b_bcount;
9a71d53f 262 bp->b_flags |= B_INVAL;
4414f2c9 263 goto done;
984263bc 264 }
4414f2c9
MD
265
266 /*
267 * Else truncate
268 */
984263bc 269 nsec = endsecno - secno;
984263bc
MD
270 bp->b_bcount = nsec * ssp->dss_secsize;
271 }
272
81b5c339 273 nbio = push_bio(bio);
4414f2c9
MD
274 nbio->bio_offset = (off_t)(sp->ds_offset + slicerel_secno) *
275 ssp->dss_secsize;
81b5c339 276 return (nbio);
984263bc
MD
277
278bad_bcount:
6ea70f76 279 kprintf(
54078292 280 "dscheck(%s): b_bcount %d is not on a sector boundary (ssize %d)\n",
81b5c339 281 devtoname(dev), bp->b_bcount, ssp->dss_secsize);
984263bc
MD
282 goto bad;
283
284bad_blkno:
6ea70f76 285 kprintf(
54078292 286 "dscheck(%s): bio_offset %lld is not on a sector boundary (ssize %d)\n",
973c11b9 287 devtoname(dev), (long long)bio->bio_offset, ssp->dss_secsize);
4414f2c9 288bad:
984263bc 289 bp->b_error = EINVAL;
9a71d53f 290 /* fall through */
4414f2c9 291error:
9a71d53f
MD
292 /*
293 * Terminate the I/O with a ranging error. Since the buffer is
294 * either illegal or beyond the file EOF, mark it B_INVAL as well.
295 */
984263bc 296 bp->b_resid = bp->b_bcount;
9a71d53f 297 bp->b_flags |= B_ERROR | B_INVAL;
4414f2c9
MD
298done:
299 /*
300 * Caller must biodone() the originally passed bio if NULL is
301 * returned.
302 */
81b5c339 303 return (NULL);
984263bc
MD
304}
305
306void
b13267a5 307dsclose(cdev_t dev, int mode, struct diskslices *ssp)
984263bc 308{
5350e1e9
MD
309 u_int32_t part;
310 u_int32_t slice;
984263bc
MD
311 struct diskslice *sp;
312
5350e1e9
MD
313 slice = dkslice(dev);
314 part = dkpart(dev);
315 if (slice < ssp->dss_nslices) {
316 sp = &ssp->dss_slices[slice];
41cf3502 317 dsclrmask(sp, part);
5350e1e9 318 }
984263bc
MD
319}
320
321void
e1c7bccd 322dsgone(struct diskslices **sspp)
984263bc 323{
e1c7bccd 324 int slice;
984263bc
MD
325 struct diskslice *sp;
326 struct diskslices *ssp;
327
328 for (slice = 0, ssp = *sspp; slice < ssp->dss_nslices; slice++) {
329 sp = &ssp->dss_slices[slice];
330 free_ds_label(ssp, slice);
331 }
efda3bd0 332 kfree(ssp, M_DEVBUF);
984263bc
MD
333 *sspp = NULL;
334}
335
336/*
337 * For the "write" commands (DIOCSDINFO and DIOCWDINFO), this
338 * is subject to the same restriction as dsopen().
339 */
340int
84f8b009
MD
341dsioctl(cdev_t dev, u_long cmd, caddr_t data, int flags,
342 struct diskslices **sspp, struct disk_info *info)
984263bc 343{
e1c7bccd 344 int error;
2b961883
MD
345 disklabel_t lp;
346 disklabel_t lptmp;
0ffe40b3 347 disklabel_ops_t ops;
e1c7bccd 348 int old_wlabel;
ae81fc47 349 u_int32_t openmask[DKMAXPARTITIONS/(sizeof(u_int32_t)*8)];
e1c7bccd
MD
350 int part;
351 int slice;
984263bc
MD
352 struct diskslice *sp;
353 struct diskslices *ssp;
984263bc
MD
354
355 slice = dkslice(dev);
5350e1e9 356 part = dkpart(dev);
984263bc 357 ssp = *sspp;
5350e1e9
MD
358 if (slice >= ssp->dss_nslices)
359 return (EINVAL);
984263bc
MD
360 sp = &ssp->dss_slices[slice];
361 lp = sp->ds_label;
0ffe40b3 362 ops = sp->ds_ops; /* may be NULL if no label */
984263bc 363
1c3c151b 364 switch (cmd) {
2b961883 365 case DIOCGDVIRGIN32:
0ffe40b3
MD
366 ops = &disklabel32_ops;
367 /* fall through */
368 case DIOCGDVIRGIN64:
369 if (cmd != DIOCGDVIRGIN32)
370 ops = &disklabel64_ops;
5350e1e9
MD
371 /*
372 * You can only retrieve a virgin disklabel on the whole
373 * disk slice or whole-slice partition.
374 */
375 if (slice != WHOLE_DISK_SLICE &&
376 part != WHOLE_SLICE_PART) {
377 return(EINVAL);
378 }
379
2b961883
MD
380 lp.opaque = data;
381 ops->op_makevirginlabel(lp, ssp, sp, info);
984263bc
MD
382 return (0);
383
2b961883 384 case DIOCGDINFO32:
0ffe40b3 385 case DIOCGDINFO64:
5350e1e9
MD
386 /*
387 * You can only retrieve a disklabel on the whole
388 * slice partition.
389 *
390 * We do not support labels directly on whole-disks
391 * any more (that is, disks without slices), unless the
392 * device driver has asked for a compatible label (e.g.
393 * for a CD) to allow booting off of storage that is
394 * otherwise unlabeled.
395 */
396 error = 0;
397 if (part != WHOLE_SLICE_PART)
398 return(EINVAL);
399 if (slice == WHOLE_DISK_SLICE &&
400 (info->d_dsflags & DSO_COMPATLABEL) == 0) {
401 return (ENODEV);
402 }
2b961883 403 if (sp->ds_label.opaque == NULL) {
5350e1e9
MD
404 error = dsreadandsetlabel(dev, info->d_dsflags,
405 ssp, sp, info);
0ffe40b3 406 ops = sp->ds_ops; /* may be NULL */
5350e1e9 407 }
0ffe40b3
MD
408
409 /*
410 * The type of label we found must match the type of
411 * label requested.
412 */
413 if (error == 0 && IOCPARM_LEN(cmd) != ops->labelsize)
414 error = ENOATTR;
5350e1e9 415 if (error == 0)
2b961883 416 bcopy(sp->ds_label.opaque, data, ops->labelsize);
5350e1e9 417 return (error);
984263bc
MD
418
419 case DIOCGPART:
2ec8fb79
MD
420 {
421 struct partinfo *dpart = (void *)data;
422
5a8edc7a 423 /*
1c3c151b
MD
424 * The disk management layer may not have read the
425 * disklabel yet because simply opening a slice no
426 * longer 'probes' the disk that way. Be sure we
427 * have tried.
5a8edc7a
MD
428 *
429 * We ignore any error.
430 */
2b961883
MD
431 if (sp->ds_label.opaque == NULL &&
432 part == WHOLE_SLICE_PART &&
5a8edc7a
MD
433 slice != WHOLE_DISK_SLICE) {
434 dsreadandsetlabel(dev, info->d_dsflags,
435 ssp, sp, info);
0ffe40b3 436 ops = sp->ds_ops; /* may be NULL */
5a8edc7a
MD
437 }
438
2ec8fb79
MD
439 bzero(dpart, sizeof(*dpart));
440 dpart->media_offset = (u_int64_t)sp->ds_offset *
441 info->d_media_blksize;
442 dpart->media_size = (u_int64_t)sp->ds_size *
443 info->d_media_blksize;
444 dpart->media_blocks = sp->ds_size;
445 dpart->media_blksize = info->d_media_blksize;
1c3c151b 446 dpart->reserved_blocks= sp->ds_reserved;
18cb7add
MD
447 dpart->fstype_uuid = sp->ds_type_uuid;
448 dpart->storage_uuid = sp->ds_stor_uuid;
5350e1e9
MD
449
450 if (slice != WHOLE_DISK_SLICE &&
451 part != WHOLE_SLICE_PART) {
ba0cc1ab
MD
452 u_int64_t start;
453 u_int64_t blocks;
2b961883 454 if (lp.opaque == NULL)
5350e1e9 455 return(EINVAL);
0ffe40b3
MD
456 if (ops->op_getpartbounds(ssp, lp, part,
457 &start, &blocks)) {
ba0cc1ab 458 return(EINVAL);
0ffe40b3 459 }
18cb7add 460 ops->op_loadpartinfo(lp, part, dpart);
ba0cc1ab 461 dpart->media_offset += start *
2ec8fb79 462 info->d_media_blksize;
ba0cc1ab 463 dpart->media_size = blocks *
2ec8fb79 464 info->d_media_blksize;
ba0cc1ab 465 dpart->media_blocks = blocks;
154b688d
MD
466
467 /*
468 * partition starting sector (p_offset)
469 * requires slice's reserved areas to be
470 * adjusted.
471 */
ba0cc1ab
MD
472 if (dpart->reserved_blocks > start)
473 dpart->reserved_blocks -= start;
154b688d 474 else
1c3c151b 475 dpart->reserved_blocks = 0;
2ec8fb79 476 }
291fc38f
MD
477
478 /*
479 * Load remaining fields from the info structure
480 */
481 dpart->d_nheads = info->d_nheads;
482 dpart->d_ncylinders = info->d_ncylinders;
483 dpart->d_secpertrack = info->d_secpertrack;
484 dpart->d_secpercyl = info->d_secpercyl;
2ec8fb79 485 }
984263bc
MD
486 return (0);
487
488 case DIOCGSLICEINFO:
489 bcopy(ssp, data, (char *)&ssp->dss_slices[ssp->dss_nslices] -
490 (char *)ssp);
491 return (0);
492
2b961883 493 case DIOCSDINFO32:
0ffe40b3
MD
494 ops = &disklabel32_ops;
495 /* fall through */
496 case DIOCSDINFO64:
497 if (cmd != DIOCSDINFO32)
498 ops = &disklabel64_ops;
5350e1e9
MD
499 /*
500 * You can write a disklabel on the whole disk slice or
501 * whole-slice partition.
502 */
503 if (slice != WHOLE_DISK_SLICE &&
504 part != WHOLE_SLICE_PART) {
505 return(EINVAL);
506 }
507
508 /*
509 * We no longer support writing disklabels directly to media
510 * without there being a slice. Keep this as a separate
511 * conditional.
512 */
984263bc
MD
513 if (slice == WHOLE_DISK_SLICE)
514 return (ENODEV);
515 if (!(flags & FWRITE))
516 return (EBADF);
0ffe40b3
MD
517
518 /*
519 * If an existing label is present it must be the same
520 * type as the label being passed by the ioctl.
521 */
522 if (sp->ds_label.opaque && sp->ds_ops != ops)
523 return (ENOATTR);
524
525 /*
526 * Create a temporary copy of the existing label
527 * (if present) so setdisklabel can compare it against
528 * the new label.
529 */
2b961883
MD
530 lp.opaque = kmalloc(ops->labelsize, M_DEVBUF, M_WAITOK);
531 if (sp->ds_label.opaque == NULL)
532 bzero(lp.opaque, ops->labelsize);
984263bc 533 else
2b961883
MD
534 bcopy(sp->ds_label.opaque, lp.opaque, ops->labelsize);
535 if (sp->ds_label.opaque == NULL) {
41cf3502 536 bzero(openmask, sizeof(openmask));
154b688d 537 } else {
41cf3502 538 bcopy(sp->ds_openmask, openmask, sizeof(openmask));
984263bc 539 }
2b961883 540 lptmp.opaque = data;
0ffe40b3 541 error = ops->op_setdisklabel(lp, lptmp, ssp, sp, openmask);
984263bc 542 if (error != 0) {
2b961883 543 kfree(lp.opaque, M_DEVBUF);
984263bc
MD
544 return (error);
545 }
546 free_ds_label(ssp, slice);
0ffe40b3 547 set_ds_label(ssp, slice, lp, ops);
984263bc
MD
548 return (0);
549
550 case DIOCSYNCSLICEINFO:
5350e1e9
MD
551 /*
552 * This ioctl can only be done on the whole disk
553 */
554 if (slice != WHOLE_DISK_SLICE || part != WHOLE_SLICE_PART)
984263bc 555 return (EINVAL);
5350e1e9 556
84f8b009 557 if (*(int *)data == 0) {
984263bc 558 for (slice = 0; slice < ssp->dss_nslices; slice++) {
41cf3502
MD
559 struct diskslice *ds = &ssp->dss_slices[slice];
560
561 switch(dscountmask(ds)) {
562 case 0:
563 break;
564 case 1:
565 if (slice != WHOLE_DISK_SLICE)
566 return (EBUSY);
567 if (!dschkmask(ds, RAW_PART))
568 return (EBUSY);
569 break;
570 default:
984263bc 571 return (EBUSY);
84f8b009 572 }
984263bc 573 }
84f8b009 574 }
984263bc
MD
575
576 /*
577 * Temporarily forget the current slices struct and read
578 * the current one.
84f8b009
MD
579 *
580 * NOTE:
581 *
984263bc
MD
582 * XXX should wait for current accesses on this disk to
583 * complete, then lock out future accesses and opens.
584 */
585 *sspp = NULL;
84f8b009 586 error = dsopen(dev, S_IFCHR, ssp->dss_oflags, sspp, info);
984263bc 587 if (error != 0) {
984263bc
MD
588 *sspp = ssp;
589 return (error);
590 }
591
592 /*
593 * Reopen everything. This is a no-op except in the "force"
594 * case and when the raw bdev and cdev are both open. Abort
595 * if anything fails.
596 */
597 for (slice = 0; slice < ssp->dss_nslices; slice++) {
41cf3502
MD
598 for (part = 0; part < DKMAXPARTITIONS; ++part) {
599 if (!dschkmask(&ssp->dss_slices[slice], part))
984263bc
MD
600 continue;
601 error = dsopen(dkmodslice(dkmodpart(dev, part),
602 slice),
603 S_IFCHR, ssp->dss_oflags, sspp,
84f8b009 604 info);
984263bc 605 if (error != 0) {
984263bc
MD
606 *sspp = ssp;
607 return (EBUSY);
608 }
609 }
610 }
611
984263bc
MD
612 dsgone(&ssp);
613 return (0);
614
2b961883 615 case DIOCWDINFO32:
0ffe40b3
MD
616 case DIOCWDINFO64:
617 error = dsioctl(dev, ((cmd == DIOCWDINFO32) ?
618 DIOCSDINFO32 : DIOCSDINFO64),
619 data, flags, &ssp, info);
620 if (error == 0 && sp->ds_label.opaque == NULL)
621 error = EINVAL;
984263bc
MD
622 if (error != 0)
623 return (error);
1c3c151b 624
984263bc 625 /*
0ffe40b3
MD
626 * Allow the reserved area to be written, reload ops
627 * because the DIOCSDINFO op above may have installed
628 * a new label type.
984263bc 629 */
0ffe40b3 630 ops = sp->ds_ops;
984263bc
MD
631 old_wlabel = sp->ds_wlabel;
632 set_ds_wlabel(ssp, slice, TRUE);
0ffe40b3 633 error = ops->op_writedisklabel(dev, ssp, sp, sp->ds_label);
984263bc 634 set_ds_wlabel(ssp, slice, old_wlabel);
1c3c151b 635 /* XXX should invalidate in-core label if write failed. */
984263bc
MD
636 return (error);
637
638 case DIOCWLABEL:
984263bc
MD
639 if (slice == WHOLE_DISK_SLICE)
640 return (ENODEV);
984263bc
MD
641 if (!(flags & FWRITE))
642 return (EBADF);
643 set_ds_wlabel(ssp, slice, *(int *)data != 0);
644 return (0);
645
646 default:
647 return (ENOIOCTL);
648 }
649}
650
984263bc 651int
e1c7bccd 652dsisopen(struct diskslices *ssp)
984263bc 653{
e1c7bccd 654 int slice;
984263bc
MD
655
656 if (ssp == NULL)
657 return (0);
e1c7bccd 658 for (slice = 0; slice < ssp->dss_nslices; slice++) {
41cf3502 659 if (dscountmask(&ssp->dss_slices[slice]))
984263bc 660 return (1);
e1c7bccd 661 }
984263bc
MD
662 return (0);
663}
664
665/*
666 * Allocate a slices "struct" and initialize it to contain only an empty
667 * compatibility slice (pointing to itself), a whole disk slice (covering
668 * the disk as described by the label), and (nslices - BASE_SLICES) empty
669 * slices beginning at BASE_SLICE.
1c3c151b
MD
670 *
671 * Note that the compatibility slice is no longer really a compatibility
672 * slice. It is slice 0 if a GPT label is present, and the dangerously
673 * dedicated slice if no slice table otherwise exists. Else it is 0-sized.
984263bc
MD
674 */
675struct diskslices *
84f8b009 676dsmakeslicestruct(int nslices, struct disk_info *info)
984263bc
MD
677{
678 struct diskslice *sp;
679 struct diskslices *ssp;
680
77652cad 681 ssp = kmalloc(offsetof(struct diskslices, dss_slices) +
984263bc
MD
682 nslices * sizeof *sp, M_DEVBUF, M_WAITOK);
683 ssp->dss_first_bsd_slice = COMPATIBILITY_SLICE;
684 ssp->dss_nslices = nslices;
685 ssp->dss_oflags = 0;
8a88e0d0
MD
686
687 /*
688 * Figure out if we can use shifts or whether we have to
689 * use mod/multply to translate byte offsets into sector numbers.
690 */
691 if ((info->d_media_blksize ^ (info->d_media_blksize - 1)) ==
692 (info->d_media_blksize << 1) - 1) {
693 ssp->dss_secmult = info->d_media_blksize / DEV_BSIZE;
694 if (ssp->dss_secmult & (ssp->dss_secmult - 1))
695 ssp->dss_secshift = -1;
696 else
697 ssp->dss_secshift = ffs(ssp->dss_secmult) - 1;
698 } else {
699 ssp->dss_secmult = 0;
984263bc 700 ssp->dss_secshift = -1;
8a88e0d0 701 }
84f8b009 702 ssp->dss_secsize = info->d_media_blksize;
984263bc
MD
703 sp = &ssp->dss_slices[0];
704 bzero(sp, nslices * sizeof *sp);
84f8b009 705 sp[WHOLE_DISK_SLICE].ds_size = info->d_media_blocks;
984263bc
MD
706 return (ssp);
707}
708
709char *
b13267a5 710dsname(cdev_t dev, int unit, int slice, int part, char *partname)
984263bc
MD
711{
712 static char name[32];
713 const char *dname;
5350e1e9 714 int used;
984263bc 715
335dda38 716 dname = dev_dname(dev);
984263bc
MD
717 if (strlen(dname) > 16)
718 dname = "nametoolong";
f8c7a42d 719 ksnprintf(name, sizeof(name), "%s%d", dname, unit);
984263bc 720 partname[0] = '\0';
5350e1e9
MD
721 used = strlen(name);
722
723 if (slice != WHOLE_DISK_SLICE) {
c6f49b01
MD
724 /*
725 * slice or slice + partition. BASE_SLICE is s1, but
726 * the compatibility slice (0) needs to be s0.
727 */
291fc38f 728 used += ksnprintf(name + used, sizeof(name) - used,
c6f49b01 729 "s%d", (slice ? slice - BASE_SLICE + 1 : 0));
5350e1e9
MD
730 if (part != WHOLE_SLICE_PART) {
731 used += ksnprintf(name + used, sizeof(name) - used,
732 "%c", 'a' + part);
733 partname[0] = 'a' + part;
734 partname[1] = 0;
e1c7bccd 735 }
c6f49b01
MD
736 } else if (part == WHOLE_SLICE_PART) {
737 /*
738 * whole-disk-device, raw access to disk
739 */
740 /* no string extension */
8a88e0d0
MD
741 } else if (part > 128) {
742 /*
c6f49b01
MD
743 * whole-disk-device, extended raw access partitions.
744 * (typically used to access CD audio tracks)
8a88e0d0
MD
745 */
746 used += ksnprintf(name + used, sizeof(name) - used,
747 "t%d", part - 128);
c6f49b01
MD
748 } else {
749 /*
750 * whole-disk-device, illegal partition number
751 */
752 used += ksnprintf(name + used, sizeof(name) - used,
753 "?%d", part);
984263bc
MD
754 }
755 return (name);
756}
757
758/*
759 * This should only be called when the unit is inactive and the strategy
760 * routine should not allow it to become active unless we call it. Our
761 * strategy routine must be special to allow activity.
762 */
763int
b13267a5 764dsopen(cdev_t dev, int mode, u_int flags,
84f8b009 765 struct diskslices **sspp, struct disk_info *info)
984263bc 766{
b13267a5 767 cdev_t dev1;
e1c7bccd 768 int error;
ba0cc1ab 769 int need_init;
984263bc
MD
770 struct diskslice *sp;
771 struct diskslices *ssp;
5350e1e9
MD
772 int slice;
773 int part;
984263bc 774
84f8b009 775 dev->si_bsize_phys = info->d_media_blksize;
984263bc 776
984263bc 777 /*
77dc851e 778 * Do not attempt to read the slice table or disk label when
5a8edc7a 779 * accessing the whole-disk slice or a while-slice partition.
77dc851e 780 */
5350e1e9 781 if (dkslice(dev) == WHOLE_DISK_SLICE)
77dc851e 782 flags |= DSO_ONESLICE | DSO_NOLABELS;
5350e1e9
MD
783 if (dkpart(dev) == WHOLE_SLICE_PART)
784 flags |= DSO_NOLABELS;
77dc851e
MD
785
786 /*
5a8edc7a
MD
787 * Reinitialize the slice table unless there is an open device
788 * on the unit.
789 *
790 * It would be nice if we didn't have to do this but when a
791 * user is slicing and partitioning up a disk it is a lot safer
792 * to not take any chances.
984263bc
MD
793 */
794 ssp = *sspp;
795 need_init = !dsisopen(ssp);
796 if (ssp != NULL && need_init)
797 dsgone(sspp);
798 if (need_init) {
799 /*
800 * Allocate a minimal slices "struct". This will become
801 * the final slices "struct" if we don't want real slices
802 * or if we can't find any real slices.
154b688d
MD
803 *
804 * Then scan the disk
984263bc 805 */
84f8b009 806 *sspp = dsmakeslicestruct(BASE_SLICE, info);
984263bc 807
5350e1e9 808 if ((flags & DSO_ONESLICE) == 0) {
84f8b009 809 error = mbrinit(dev, info, sspp);
984263bc
MD
810 if (error != 0) {
811 dsgone(sspp);
812 return (error);
813 }
814 }
815 ssp = *sspp;
816 ssp->dss_oflags = flags;
817
818 /*
819 * If there are no real slices, then make the compatiblity
820 * slice cover the whole disk.
821 */
84f8b009 822 if (ssp->dss_nslices == BASE_SLICE) {
7dc62e37
MD
823 sp = &ssp->dss_slices[COMPATIBILITY_SLICE];
824
825 sp->ds_size = info->d_media_blocks;
1c3c151b 826 sp->ds_reserved = 0;
84f8b009 827 }
984263bc 828
154b688d 829 /*
1c3c151b
MD
830 * Set dss_first_bsd_slice to point at the first BSD
831 * slice, if any.
154b688d 832 */
984263bc
MD
833 for (slice = BASE_SLICE; slice < ssp->dss_nslices; slice++) {
834 sp = &ssp->dss_slices[slice];
835 if (sp->ds_type == DOSPTYP_386BSD /* XXX */) {
1c3c151b 836#if 0
154b688d 837 struct diskslice *csp;
1c3c151b 838#endif
154b688d 839
984263bc 840 ssp->dss_first_bsd_slice = slice;
1c3c151b
MD
841#if 0
842 /*
843 * no longer supported, s0 is a real slice
844 * for GPT
845 */
846 csp = &ssp->dss_slices[COMPATIBILITY_SLICE];
154b688d
MD
847 csp->ds_offset = sp->ds_offset;
848 csp->ds_size = sp->ds_size;
849 csp->ds_type = sp->ds_type;
1c3c151b
MD
850 csp->ds_reserved = sp->ds_reserved;
851#endif
984263bc
MD
852 break;
853 }
854 }
154b688d
MD
855
856 /*
857 * By definition accesses via the whole-disk device do not
858 * specify any reserved areas. The whole disk may be read
859 * or written by the whole-disk device.
860 *
0ffe40b3 861 * The whole-disk slice does not ever have a label.
154b688d 862 */
84f8b009 863 sp = &ssp->dss_slices[WHOLE_DISK_SLICE];
84f8b009 864 sp->ds_wlabel = TRUE;
1c3c151b 865 sp->ds_reserved = 0;
984263bc
MD
866 }
867
868 /*
5a8edc7a
MD
869 * Load the disklabel for the slice being accessed unless it is
870 * a whole-disk-slice or a whole-slice-partition (as determined
871 * by DSO_NOLABELS).
84f8b009 872 *
5a8edc7a
MD
873 * We could scan all slices here and try to load up their
874 * disklabels, but that would cause us to access slices that
875 * the user may otherwise not intend us to access, or corrupted
876 * slices, etc.
877 *
878 * XXX if there are no opens on the slice we may want to re-read
879 * the disklabel anyway, even if we have one cached.
984263bc 880 */
5a8edc7a
MD
881 slice = dkslice(dev);
882 if (slice >= ssp->dss_nslices)
883 return (ENXIO);
884 sp = &ssp->dss_slices[slice];
885 part = dkpart(dev);
5350e1e9 886
2b961883 887 if ((flags & DSO_NOLABELS) == 0 && sp->ds_label.opaque == NULL) {
5350e1e9
MD
888 dev1 = dkmodslice(dkmodpart(dev, WHOLE_SLICE_PART), slice);
889
984263bc 890 /*
5a8edc7a
MD
891 * If opening a raw disk we do not try to
892 * read the disklabel now. No interpretation of raw disks
893 * (e.g. like 'da0') ever occurs. We will try to read the
894 * disklabel for a raw slice if asked to via DIOC* ioctls.
895 *
896 * Access to the label area is disallowed by default. Note
897 * however that accesses via WHOLE_DISK_SLICE, and accesses
898 * via WHOLE_SLICE_PART for slices without valid disklabels,
899 * will allow writes and ignore the flag.
984263bc 900 */
5a8edc7a
MD
901 set_ds_wlabel(ssp, slice, FALSE);
902 dsreadandsetlabel(dev1, flags, ssp, sp, info);
984263bc
MD
903 }
904
5350e1e9
MD
905 /*
906 * If opening a particular partition the disklabel must exist and
907 * the partition must be present in the label.
908 *
909 * If the partition is the special whole-disk-slice no partition
910 * table need exist.
911 */
912 if (part != WHOLE_SLICE_PART && slice != WHOLE_DISK_SLICE) {
2b961883 913 if (sp->ds_label.opaque == NULL ||
0ffe40b3 914 part >= sp->ds_ops->op_getnumparts(sp->ds_label)) {
5350e1e9 915 return (EINVAL);
2b961883 916 }
5350e1e9
MD
917 }
918
8a88e0d0
MD
919 /*
920 * Do not allow special raw-extension partitions to be opened
921 * if the device doesn't support them. Raw-extension partitions
922 * are typically used to handle CD tracks.
5350e1e9 923 */
5a8edc7a
MD
924 if (slice == WHOLE_DISK_SLICE && part >= 128 &&
925 part != WHOLE_SLICE_PART) {
8a88e0d0
MD
926 if ((info->d_dsflags & DSO_RAWEXTENSIONS) == 0)
927 return (EINVAL);
928 }
9d99f469
MD
929
930 /*
931 * Ok, we are open
932 */
933 dssetmask(sp, part);
984263bc
MD
934 return (0);
935}
936
5350e1e9
MD
937/*
938 * Attempt to read the disklabel. If successful, store it in sp->ds_label.
939 *
940 * If we cannot read the disklabel and DSO_COMPATLABEL is set, we construct
941 * a fake label covering the whole disk.
942 */
943static
944int
945dsreadandsetlabel(cdev_t dev, u_int flags,
946 struct diskslices *ssp, struct diskslice *sp,
947 struct disk_info *info)
948{
2b961883 949 disklabel_t lp;
0ffe40b3 950 disklabel_ops_t ops;
5350e1e9
MD
951 const char *msg;
952 const char *sname;
953 char partname[2];
954 int slice = dkslice(dev);
2b961883 955
0ffe40b3
MD
956 /*
957 * Probe the disklabel
958 */
2b961883 959 lp.opaque = NULL;
5350e1e9 960 sname = dsname(dev, dkunit(dev), slice, WHOLE_SLICE_PART, partname);
0ffe40b3 961 ops = &disklabel32_ops;
2b961883 962 msg = ops->op_readdisklabel(dev, sp, &lp, info);
0ffe40b3
MD
963 if (msg && strcmp(msg, "no disk label") == 0) {
964 ops = &disklabel64_ops;
965 msg = disklabel64_ops.op_readdisklabel(dev, sp, &lp, info);
966 }
5350e1e9 967
0ffe40b3
MD
968 /*
969 * If we failed and COMPATLABEL is set, create a dummy disklabel.
970 */
5350e1e9
MD
971 if (msg != NULL && (flags & DSO_COMPATLABEL)) {
972 msg = NULL;
0ffe40b3
MD
973 if (sp->ds_size >= 0x100000000ULL)
974 ops = &disklabel64_ops;
975 else
976 ops = &disklabel32_ops;
2b961883 977 lp = ops->op_clone_label(info, sp);
5350e1e9 978 }
5350e1e9
MD
979 if (msg != NULL) {
980 if (sp->ds_type == DOSPTYP_386BSD /* XXX */)
981 log(LOG_WARNING, "%s: cannot find label (%s)\n",
982 sname, msg);
2b961883
MD
983 if (lp.opaque)
984 kfree(lp.opaque, M_DEVBUF);
5350e1e9 985 } else {
0ffe40b3 986 set_ds_label(ssp, slice, lp, ops);
5350e1e9
MD
987 set_ds_wlabel(ssp, slice, FALSE);
988 }
989 return (msg ? EINVAL : 0);
990}
991
e0fc5693 992int64_t
b13267a5 993dssize(cdev_t dev, struct diskslices **sspp)
984263bc 994{
2b961883 995 disklabel_t lp;
0ffe40b3 996 disklabel_ops_t ops;
e1c7bccd
MD
997 int part;
998 int slice;
984263bc 999 struct diskslices *ssp;
ba0cc1ab
MD
1000 u_int64_t start;
1001 u_int64_t blocks;
984263bc
MD
1002
1003 slice = dkslice(dev);
1004 part = dkpart(dev);
1005 ssp = *sspp;
1006 if (ssp == NULL || slice >= ssp->dss_nslices
41cf3502 1007 || !dschkmask(&ssp->dss_slices[slice], part)) {
fef8985e 1008 if (dev_dopen(dev, FREAD, S_IFCHR, proc0.p_ucred) != 0)
984263bc 1009 return (-1);
fef8985e 1010 dev_dclose(dev, FREAD, S_IFCHR);
984263bc
MD
1011 ssp = *sspp;
1012 }
1013 lp = ssp->dss_slices[slice].ds_label;
2b961883 1014 if (lp.opaque == NULL)
984263bc 1015 return (-1);
0ffe40b3
MD
1016 ops = ssp->dss_slices[slice].ds_ops;
1017 if (ops->op_getpartbounds(ssp, lp, part, &start, &blocks))
ba0cc1ab
MD
1018 return (-1);
1019 return ((int64_t)blocks);
984263bc
MD
1020}
1021
1022static void
e1c7bccd 1023free_ds_label(struct diskslices *ssp, int slice)
984263bc 1024{
984263bc 1025 struct diskslice *sp;
2b961883 1026 disklabel_t lp;
984263bc
MD
1027
1028 sp = &ssp->dss_slices[slice];
1029 lp = sp->ds_label;
2b961883
MD
1030 if (lp.opaque != NULL) {
1031 kfree(lp.opaque, M_DEVBUF);
1032 lp.opaque = NULL;
0ffe40b3 1033 set_ds_label(ssp, slice, lp, NULL);
2b961883 1034 }
984263bc
MD
1035}
1036
984263bc 1037static void
0ffe40b3
MD
1038set_ds_label(struct diskslices *ssp, int slice,
1039 disklabel_t lp, disklabel_ops_t ops)
984263bc 1040{
ba0cc1ab 1041 struct diskslice *sp = &ssp->dss_slices[slice];
154b688d 1042
ba0cc1ab 1043 sp->ds_label = lp;
0ffe40b3
MD
1044 sp->ds_ops = ops;
1045 if (lp.opaque && slice != WHOLE_DISK_SLICE)
1046 ops->op_adjust_label_reserved(ssp, slice, sp);
1047 else
1048 sp->ds_reserved = 0;
984263bc
MD
1049}
1050
984263bc 1051static void
e1c7bccd 1052set_ds_wlabel(struct diskslices *ssp, int slice, int wlabel)
984263bc
MD
1053{
1054 ssp->dss_slices[slice].ds_wlabel = wlabel;
984263bc 1055}
ba0cc1ab 1056