4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright (c) 1991, 2010, Oracle and/or its affiliates. All rights reserved.
27 * This file contains functions to implement the partition menu commands.
32 #include "partition.h"
33 #include "menu_partition.h"
34 #include "menu_command.h"
35 #include "modify_partition.h"
39 #include "auto_sense.h"
43 /* Function prototypes for ANSI C Compilers */
45 static void adj_cyl_offset(struct dk_map32
*map
);
46 static int check_map(struct dk_map32
*map
);
47 static void get_user_map(struct dk_map32
*map
, int float_part
);
48 static void get_user_map_efi(struct dk_gpt
*map
, int float_part
);
52 /* Function prototypes for non-ANSI C Compilers */
54 static void adj_cyl_offset();
55 static int check_map();
56 static void get_user_map();
57 static void get_user_map_efi();
61 static char *partn_list
[] = { "0", "1", "2", "3", "4", "5", "6", "7", NULL
};
63 static char *sel_list
[] = { "0", "1", "2", "3", NULL
};
65 #define MBYTE (1024*1024)
69 * Modify/Create a predefined partition table.
74 struct partition_info tmp_pinfo
[1];
75 struct dk_map32
*map
= tmp_pinfo
->pinfo_map
;
85 * There must be a current disk type (and therefore a current disk).
87 if (cur_dtype
== NULL
) {
88 err_print("Current Disk Type is not set.\n");
93 * check if there exists a partition table for the disk.
95 if (cur_parts
== NULL
) {
96 err_print("Current Disk has no partition table.\n");
102 * If the disk has mounted partitions, cannot modify
104 if (checkmount((diskaddr_t
)-1, (diskaddr_t
)-1)) {
106 "Cannot modify disk partitions while it has mounted partitions.\n\n");
111 * If the disk has partitions currently being used for
112 * swapping, cannot modify
114 if (checkswap((diskaddr_t
)-1, (diskaddr_t
)-1)) {
116 "Cannot modify disk partitions while it is \
117 currently being used for swapping.\n");
122 * Check to see if any partitions used for svm, vxvm, ZFS zpool
123 * or live upgrade are on the disk.
125 if (checkdevinuse(cur_disk
->disk_name
, (diskaddr_t
)-1,
126 (diskaddr_t
)-1, 0, 0)) {
127 err_print("Cannot modify disk partition when "
128 "partitions are in use as described.\n");
133 * prompt user for a partition table base
135 if (cur_parts
->pinfo_name
!= NULL
) {
136 (void) snprintf(tmpstr
, sizeof (tmpstr
),
137 "\t0. Current partition table (%s)",
138 cur_parts
->pinfo_name
);
140 (void) sprintf(tmpstr
,
141 "\t0. Current partition table (unnamed)");
144 (void) snprintf(tmpstr2
, sizeof (tmpstr2
),
145 "Select partitioning base:\n%s\n"
146 "\t1. All Free Hog\n"
147 "Choose base (enter number) ",
150 ioparam
.io_charlist
= sel_list
;
151 sel_type
= input(FIO_MSTR
, tmpstr2
, '?', &ioparam
,
152 &sel_type
, DATA_INPUT
);
158 * Check for invalid parameters but do
159 * not modify the table.
161 if (check_map(cur_parts
->pinfo_map
)) {
163 Warning: Fix, or select a different partition table.\n");
167 * Create partition map from existing map
169 tmp_pinfo
->vtoc
= cur_parts
->vtoc
;
170 for (i
= 0; i
< NDKMAP
; i
++) {
171 map
[i
].dkl_nblk
= cur_parts
->pinfo_map
[i
].dkl_nblk
;
172 map
[i
].dkl_cylno
= cur_parts
->pinfo_map
[i
].dkl_cylno
;
176 * Make an empty partition map, with all the space
177 * in the c partition.
179 set_vtoc_defaults(tmp_pinfo
);
180 for (i
= 0; i
< NDKMAP
; i
++) {
182 map
[i
].dkl_cylno
= 0;
184 map
[C_PARTITION
].dkl_nblk
= ncyl
* spc();
188 * Adjust for the boot and possibly alternates partitions
190 map
[I_PARTITION
].dkl_nblk
= spc();
191 map
[I_PARTITION
].dkl_cylno
= 0;
192 if (cur_ctype
->ctype_ctype
!= DKC_SCSI_CCS
) {
193 map
[J_PARTITION
].dkl_nblk
= 2 * spc();
194 map
[J_PARTITION
].dkl_cylno
= spc() / spc();
196 #endif /* defined(i386) */
201 for (i
= 0; i
< cur_parts
->etoc
->efi_nparts
; i
++) {
202 cur_parts
->etoc
->efi_parts
[i
].p_start
= 0;
203 cur_parts
->etoc
->efi_parts
[i
].p_size
= 0;
210 if (cur_label
== L_TYPE_SOLARIS
) {
211 print_map(tmp_pinfo
);
213 print_map(cur_parts
);
216 ioparam
.io_charlist
= confirm_list
;
218 "Do you wish to continue creating a new partition\ntable based on above table",
219 '?', &ioparam
, &inpt_dflt
, DATA_INPUT
)) {
224 * get Free Hog partition
227 while ((free_hog
< 0) && (cur_label
== L_TYPE_SOLARIS
)) {
228 free_hog
= G_PARTITION
; /* default to g partition */
229 ioparam
.io_charlist
= partn_list
;
230 free_hog
= input(FIO_MSTR
, "Free Hog partition", '?',
231 &ioparam
, &free_hog
, DATA_INPUT
);
232 /* disallow c partition */
233 if (free_hog
== C_PARTITION
) {
234 fmt_print("'%c' cannot be the 'Free Hog' partition.\n",
235 C_PARTITION
+ PARTITION_BASE
);
240 * If user selected all float set the
241 * float to be the whole disk.
244 map
[free_hog
].dkl_nblk
= map
[C_PARTITION
].dkl_nblk
;
246 map
[free_hog
].dkl_nblk
-= map
[I_PARTITION
].dkl_nblk
;
247 if (cur_ctype
->ctype_ctype
!= DKC_SCSI_CCS
) {
248 map
[free_hog
].dkl_nblk
-=
249 map
[J_PARTITION
].dkl_nblk
;
251 #endif /* defined(i386) */
255 * Warn the user if there is no free space in
256 * the float partition.
258 if (map
[free_hog
].dkl_nblk
== 0) {
260 Warning: No space available from Free Hog partition.\n");
261 ioparam
.io_charlist
= confirm_list
;
262 if (input(FIO_MSTR
, "Continue", '?',
263 &ioparam
, &inpt_dflt
, DATA_INPUT
)) {
270 if (cur_label
== L_TYPE_EFI
) {
271 free_hog
= G_PARTITION
; /* default to g partition */
272 ioparam
.io_charlist
= partn_list
;
273 free_hog
= input(FIO_MSTR
, "Free Hog partition", '?',
274 &ioparam
, &free_hog
, DATA_INPUT
);
275 /* disallow c partition */
276 if (free_hog
== C_PARTITION
) {
277 fmt_print("'%c' cannot be the 'Free Hog' partition.\n",
278 C_PARTITION
+ PARTITION_BASE
);
281 get_user_map_efi(cur_parts
->etoc
, free_hog
);
282 print_map(cur_parts
);
283 if (check("Ready to label disk, continue")) {
288 err_print("Writing label failed\n");
294 * get user modified partition table
296 get_user_map(map
, free_hog
);
299 * Update cylno offsets
304 print_map(tmp_pinfo
);
306 ioparam
.io_charlist
= confirm_list
;
307 if (input(FIO_MSTR
, "\
308 Okay to make this the current partition table", '?',
309 &ioparam
, &inpt_dflt
, DATA_INPUT
)) {
314 * Update new partition map
316 for (i
= 0; i
< NDKMAP
; i
++) {
317 cur_parts
->pinfo_map
[i
].dkl_nblk
= map
[i
].dkl_nblk
;
318 cur_parts
->pinfo_map
[i
].dkl_cylno
= map
[i
].dkl_cylno
;
320 cur_parts
->vtoc
.v_part
[i
].p_start
=
321 map
[i
].dkl_cylno
* nhead
* nsect
;
322 cur_parts
->vtoc
.v_part
[i
].p_size
=
331 if (check("Ready to label disk, continue")) {
336 err_print("Writing label failed\n");
346 * Adjust cylinder offsets
350 struct dk_map32
*map
;
357 * Update cylno offsets
360 #if defined(_SUNOS_VTOC_16)
362 * Correct cylinder allocation for having the boot and alternates
363 * slice in the beginning of the disk
365 for (i
= NDKMAP
/2; i
< NDKMAP
; i
++) {
366 if (i
!= C_PARTITION
&& map
[i
].dkl_nblk
) {
367 map
[i
].dkl_cylno
= cyloffset
;
368 cyloffset
+= (map
[i
].dkl_nblk
+ (spc()-1))/spc();
369 } else if (map
[i
].dkl_nblk
== 0) {
370 map
[i
].dkl_cylno
= 0;
373 for (i
= 0; i
< NDKMAP
/2; i
++) {
375 #else /* !defined(_SUNOS_VTOC_16) */
376 for (i
= 0; i
< NDKMAP
; i
++) {
377 #endif /* defined(_SUNOS_VTOC_16) */
379 if (i
!= C_PARTITION
&& map
[i
].dkl_nblk
) {
380 map
[i
].dkl_cylno
= cyloffset
;
381 cyloffset
+= (map
[i
].dkl_nblk
+ (spc()-1))/spc();
382 } else if (map
[i
].dkl_nblk
== 0) {
383 map
[i
].dkl_cylno
= 0;
390 * Check partition table
394 struct dk_map32
*map
;
398 blkaddr32_t tot_blks
= 0;
402 * On x86, we must account for the boot and alternates
404 cyloffset
= map
[0].dkl_cylno
;
405 tot_blks
= map
[0].dkl_nblk
;
409 * Do some checks for invalid parameters but do
410 * not modify the table.
412 for (i
= 0; i
< NDKMAP
; i
++) {
413 if (map
[i
].dkl_cylno
> (blkaddr32_t
)ncyl
-1) {
415 Warning: Partition %c starting cylinder %d is out of range.\n",
416 (PARTITION_BASE
+i
), map
[i
].dkl_cylno
);
419 if (map
[i
].dkl_nblk
>
420 (blkaddr32_t
)(ncyl
- map
[i
].dkl_cylno
) * spc()) {
422 Warning: Partition %c, specified # of blocks, %u, is out of range.\n",
423 (PARTITION_BASE
+i
), map
[i
].dkl_nblk
);
426 if (i
!= C_PARTITION
&& map
[i
].dkl_nblk
) {
428 if (i
== I_PARTITION
|| i
== J_PARTITION
)
431 if (map
[i
].dkl_cylno
< cyloffset
) {
433 "Warning: Overlapping partition (%c) in table.\n", PARTITION_BASE
+i
);
435 } else if (map
[i
].dkl_cylno
> cyloffset
) {
437 "Warning: Non-contiguous partition (%c) in table.\n", PARTITION_BASE
+i
);
439 cyloffset
+= (map
[i
].dkl_nblk
+ (spc()-1))/spc();
440 tot_blks
= map
[i
].dkl_nblk
;
443 if (tot_blks
> map
[C_PARTITION
].dkl_nblk
) {
445 Warning: Total blocks used is greater than number of blocks in '%c'\n\
446 \tpartition.\n", C_PARTITION
+ PARTITION_BASE
);
455 * get user defined partitions
458 get_user_map(map
, float_part
)
459 struct dk_map32
*map
;
469 * Get partition sizes
471 for (i
= 0; i
< NDKMAP
; i
++) {
472 if (partn_list
[i
] == NULL
)
474 if ((i
== C_PARTITION
) || (i
== float_part
))
477 ioparam
.io_bounds
.lower
= 0;
478 ioparam
.io_bounds
.upper
= map
[i
].dkl_nblk
+
479 map
[float_part
].dkl_nblk
;
480 deflt
= map
[i
].dkl_nblk
;
481 if (ioparam
.io_bounds
.upper
== 0) {
483 Warning: no space available for '%s' from Free Hog partition\n",
487 (void) snprintf(tmpstr
, sizeof (tmpstr
),
488 "Enter size of partition '%s' ",
490 newsize
= (blkaddr32_t
)input(FIO_CYL
, tmpstr
, ':',
491 &ioparam
, (int *)&deflt
, DATA_INPUT
);
492 map
[float_part
].dkl_nblk
-= (newsize
- map
[i
].dkl_nblk
);
493 map
[i
].dkl_nblk
= newsize
;
498 static struct partition_info
*
499 build_partition(tptr
)
500 struct disk_type
*tptr
;
502 struct partition_info
*part
;
503 struct dk_label
*label
;
507 fmt_print("Creating Default Partition for the disk \n");
510 * construct a label and pass it on to
511 * build_default_partition() which builds the
512 * default partition list.
514 label
= zalloc(sizeof (struct dk_label
));
515 label
->dkl_pcyl
= tptr
->dtype_pcyl
;
516 label
->dkl_ncyl
= tptr
->dtype_ncyl
;
517 label
->dkl_acyl
= tptr
->dtype_acyl
;
518 label
->dkl_nhead
= tptr
->dtype_nhead
;
519 label
->dkl_nsect
= tptr
->dtype_nsect
;
520 label
->dkl_apc
= apc
;
521 label
->dkl_intrlv
= 1;
522 label
->dkl_rpm
= tptr
->dtype_rpm
;
524 if (!build_default_partition(label
, cur_ctype
->ctype_ctype
))
527 part
= (struct partition_info
*)
528 zalloc(sizeof (struct partition_info
));
529 part
->pinfo_name
= alloc_string(tptr
->dtype_asciilabel
);
531 * Fill in the partition info from the label
533 for (i
= 0; i
< NDKMAP
; i
++) {
534 #if defined(_SUNOS_VTOC_8)
535 part
->pinfo_map
[i
] = label
->dkl_map
[i
];
537 part
->pinfo_map
[i
].dkl_cylno
=
538 label
->dkl_vtoc
.v_part
[i
].p_start
/
539 (blkaddr32_t
)(tptr
->dtype_nhead
* tptr
->dtype_nsect
- apc
);
540 part
->pinfo_map
[i
].dkl_nblk
=
541 label
->dkl_vtoc
.v_part
[i
].p_size
;
542 #endif /* ifdefined(_SUNOS_VTOC_8) */
544 part
->vtoc
= label
->dkl_vtoc
;
549 * build new partition table for given disk type
552 get_user_map_efi(map
, float_part
)
558 efi_deflt_t efi_deflt
;
562 uint64_t start_lba
= 34;
564 for (i
= 0; i
< map
->efi_nparts
- 1; i
++) {
568 ioparam
.io_bounds
.lower
= start_lba
;
569 ioparam
.io_bounds
.upper
= map
->efi_last_u_lba
;
570 efi_deflt
.start_sector
= ioparam
.io_bounds
.lower
;
571 efi_deflt
.end_sector
= map
->efi_parts
[i
].p_size
;
572 (void) sprintf(tmpstr
,
573 "Enter size of partition %d ", i
);
574 i64
= input(FIO_EFI
, tmpstr
, ':',
575 &ioparam
, (int *)&efi_deflt
, DATA_INPUT
);
577 map
->efi_parts
[i
].p_tag
= V_UNASSIGNED
;
578 } else if ((i64
!= 0) && (map
->efi_parts
[i
].p_tag
==
580 map
->efi_parts
[i
].p_tag
= V_USR
;
583 map
->efi_parts
[i
].p_start
= 0;
585 map
->efi_parts
[i
].p_start
= start_lba
;
587 map
->efi_parts
[i
].p_size
= i64
;
591 map
->efi_parts
[float_part
].p_start
= start_lba
;
592 map
->efi_parts
[float_part
].p_size
= map
->efi_last_u_lba
-
593 start_lba
- (1024 * 16);
594 map
->efi_parts
[float_part
].p_tag
= V_USR
;
595 if (map
->efi_parts
[float_part
].p_size
== UINT_MAX64
) {
596 map
->efi_parts
[float_part
].p_size
= 0;
597 map
->efi_parts
[float_part
].p_start
= 0;
598 map
->efi_parts
[float_part
].p_tag
= V_UNASSIGNED
;
599 fmt_print("Warning: No space left for HOG\n");
602 for (i
= 0; i
< map
->efi_nparts
; i
++) {
603 if (map
->efi_parts
[i
].p_tag
== V_RESERVED
) {
604 map
->efi_parts
[i
].p_start
= map
->efi_last_u_lba
-
606 map
->efi_parts
[i
].p_size
= (1024 * 16);
614 new_partitiontable(tptr
, oldtptr
)
615 struct disk_type
*tptr
, *oldtptr
;
617 struct partition_info
*part
;
620 * check if disk geometry has changed , if so add new
621 * partition table else copy the old partition table.(best guess).
623 if ((oldtptr
!= NULL
) &&
624 (tptr
->dtype_ncyl
== oldtptr
->dtype_ncyl
) &&
625 (tptr
->dtype_nhead
== oldtptr
->dtype_nhead
) &&
626 (tptr
->dtype_nsect
== oldtptr
->dtype_nsect
)) {
628 part
= (struct partition_info
*)
629 zalloc(sizeof (struct partition_info
));
630 bcopy((char *)cur_parts
, (char *)part
,
631 sizeof (struct partition_info
));
632 part
->pinfo_next
= tptr
->dtype_plist
;
633 tptr
->dtype_plist
= part
;
637 if (cur_parts
!= NULL
) {
638 fmt_print("Warning: Partition Table is set");
639 fmt_print("to default partition table. \n");
642 if (tptr
->dtype_plist
== NULL
) {
643 part
= (struct partition_info
*)build_partition(tptr
);
645 part
->pinfo_next
= tptr
->dtype_plist
;
646 tptr
->dtype_plist
= part
;