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]
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
27 * This file contains functions to implement the partition menu commands.
30 #include "partition.h"
31 #include "menu_partition.h"
32 #include "menu_command.h"
33 #include "modify_partition.h"
37 #include "auto_sense.h"
44 /* Function prototypes for ANSI C Compilers */
46 static void adj_cyl_offset(struct dk_map32
*map
);
47 static int check_map(struct dk_map32
*map
);
48 static void get_user_map(struct dk_map32
*map
, int float_part
);
49 static void get_user_map_efi(struct dk_gpt
*map
, int float_part
);
53 /* Function prototypes for non-ANSI C Compilers */
55 static void adj_cyl_offset();
56 static int check_map();
57 static void get_user_map();
58 static void get_user_map_efi();
62 static char *partn_list
[] = { "0", "1", "2", "3", "4", "5", "6", "7", NULL
};
64 static char *sel_list
[] = { "0", "1", "2", "3", NULL
};
66 #define MBYTE (1024*1024)
70 * Modify/Create a predefined partition table.
75 struct partition_info tmp_pinfo
[1];
76 struct dk_map32
*map
= tmp_pinfo
->pinfo_map
;
86 * There must be a current disk type (and therefore a current disk).
88 if (cur_dtype
== NULL
) {
89 err_print("Current Disk Type is not set.\n");
94 * check if there exists a partition table for the disk.
96 if (cur_parts
== NULL
) {
97 err_print("Current Disk has no partition table.\n");
103 * If the disk has mounted partitions, cannot modify
105 if (checkmount((diskaddr_t
)-1, (diskaddr_t
)-1)) {
107 "Cannot modify disk partitions while it has mounted partitions.\n\n");
112 * If the disk has partitions currently being used for
113 * swapping, cannot modify
115 if (checkswap((diskaddr_t
)-1, (diskaddr_t
)-1)) {
117 "Cannot modify disk partitions while it is \
118 currently being used for swapping.\n");
123 * Check to see if any partitions used for svm, vxvm, ZFS zpool
124 * or live upgrade are on the disk.
126 if (checkdevinuse(cur_disk
->disk_name
, (diskaddr_t
)-1,
127 (diskaddr_t
)-1, 0, 0)) {
128 err_print("Cannot modify disk partition when "
129 "partitions are in use as described.\n");
134 * prompt user for a partition table base
136 if (cur_parts
->pinfo_name
!= NULL
) {
137 (void) snprintf(tmpstr
, sizeof (tmpstr
),
138 "\t0. Current partition table (%s)",
139 cur_parts
->pinfo_name
);
141 (void) sprintf(tmpstr
,
142 "\t0. Current partition table (unnamed)");
145 (void) snprintf(tmpstr2
, sizeof (tmpstr2
),
146 "Select partitioning base:\n%s\n"
147 "\t1. All Free Hog\n"
148 "Choose base (enter number) ",
151 ioparam
.io_charlist
= sel_list
;
152 sel_type
= input(FIO_MSTR
, tmpstr2
, '?', &ioparam
,
153 &sel_type
, DATA_INPUT
);
159 * Check for invalid parameters but do
160 * not modify the table.
162 if (check_map(cur_parts
->pinfo_map
)) {
164 Warning: Fix, or select a different partition table.\n");
168 * Create partition map from existing map
170 tmp_pinfo
->vtoc
= cur_parts
->vtoc
;
171 for (i
= 0; i
< NDKMAP
; i
++) {
172 map
[i
].dkl_nblk
= cur_parts
->pinfo_map
[i
].dkl_nblk
;
173 map
[i
].dkl_cylno
= cur_parts
->pinfo_map
[i
].dkl_cylno
;
177 * Make an empty partition map, with all the space
178 * in the c partition.
180 set_vtoc_defaults(tmp_pinfo
);
181 for (i
= 0; i
< NDKMAP
; i
++) {
183 map
[i
].dkl_cylno
= 0;
185 map
[C_PARTITION
].dkl_nblk
= ncyl
* spc();
189 * Adjust for the boot and possibly alternates partitions
191 map
[I_PARTITION
].dkl_nblk
= spc();
192 map
[I_PARTITION
].dkl_cylno
= 0;
193 if (cur_ctype
->ctype_ctype
!= DKC_SCSI_CCS
) {
194 map
[J_PARTITION
].dkl_nblk
= 2 * spc();
195 map
[J_PARTITION
].dkl_cylno
= spc() / spc();
197 #endif /* defined(i386) */
202 for (i
= 0; i
< cur_parts
->etoc
->efi_nparts
; i
++) {
203 cur_parts
->etoc
->efi_parts
[i
].p_start
= 0;
204 cur_parts
->etoc
->efi_parts
[i
].p_size
= 0;
211 if (cur_label
== L_TYPE_SOLARIS
) {
212 print_map(tmp_pinfo
);
214 print_map(cur_parts
);
217 ioparam
.io_charlist
= confirm_list
;
219 "Do you wish to continue creating a new partition\ntable based on above table",
220 '?', &ioparam
, &inpt_dflt
, DATA_INPUT
)) {
225 * get Free Hog partition
228 while ((free_hog
< 0) && (cur_label
== L_TYPE_SOLARIS
)) {
229 free_hog
= G_PARTITION
; /* default to g partition */
230 ioparam
.io_charlist
= partn_list
;
231 free_hog
= input(FIO_MSTR
, "Free Hog partition", '?',
232 &ioparam
, &free_hog
, DATA_INPUT
);
233 /* disallow c partition */
234 if (free_hog
== C_PARTITION
) {
235 fmt_print("'%c' cannot be the 'Free Hog' partition.\n",
236 C_PARTITION
+ PARTITION_BASE
);
241 * If user selected all float set the
242 * float to be the whole disk.
245 map
[free_hog
].dkl_nblk
= map
[C_PARTITION
].dkl_nblk
;
247 map
[free_hog
].dkl_nblk
-= map
[I_PARTITION
].dkl_nblk
;
248 if (cur_ctype
->ctype_ctype
!= DKC_SCSI_CCS
) {
249 map
[free_hog
].dkl_nblk
-=
250 map
[J_PARTITION
].dkl_nblk
;
252 #endif /* defined(i386) */
256 * Warn the user if there is no free space in
257 * the float partition.
259 if (map
[free_hog
].dkl_nblk
== 0) {
261 Warning: No space available from Free Hog partition.\n");
262 ioparam
.io_charlist
= confirm_list
;
263 if (input(FIO_MSTR
, "Continue", '?',
264 &ioparam
, &inpt_dflt
, DATA_INPUT
)) {
271 if (cur_label
== L_TYPE_EFI
) {
272 free_hog
= G_PARTITION
; /* default to g partition */
273 ioparam
.io_charlist
= partn_list
;
274 free_hog
= input(FIO_MSTR
, "Free Hog partition", '?',
275 &ioparam
, &free_hog
, DATA_INPUT
);
276 /* disallow c partition */
277 if (free_hog
== C_PARTITION
) {
278 fmt_print("'%c' cannot be the 'Free Hog' partition.\n",
279 C_PARTITION
+ PARTITION_BASE
);
282 get_user_map_efi(cur_parts
->etoc
, free_hog
);
283 print_map(cur_parts
);
284 if (check("Ready to label disk, continue")) {
289 err_print("Writing label failed\n");
295 * get user modified partition table
297 get_user_map(map
, free_hog
);
300 * Update cylno offsets
305 print_map(tmp_pinfo
);
307 ioparam
.io_charlist
= confirm_list
;
308 if (input(FIO_MSTR
, "\
309 Okay to make this the current partition table", '?',
310 &ioparam
, &inpt_dflt
, DATA_INPUT
)) {
315 * Update new partition map
317 for (i
= 0; i
< NDKMAP
; i
++) {
318 cur_parts
->pinfo_map
[i
].dkl_nblk
= map
[i
].dkl_nblk
;
319 cur_parts
->pinfo_map
[i
].dkl_cylno
= map
[i
].dkl_cylno
;
321 cur_parts
->vtoc
.v_part
[i
].p_start
=
322 map
[i
].dkl_cylno
* nhead
* nsect
;
323 cur_parts
->vtoc
.v_part
[i
].p_size
=
332 if (check("Ready to label disk, continue")) {
337 err_print("Writing label failed\n");
347 * Adjust cylinder offsets
351 struct dk_map32
*map
;
358 * Update cylno offsets
361 #if defined(_SUNOS_VTOC_16)
363 * Correct cylinder allocation for having the boot and alternates
364 * slice in the beginning of the disk
366 for (i
= NDKMAP
/2; i
< NDKMAP
; i
++) {
367 if (i
!= C_PARTITION
&& map
[i
].dkl_nblk
) {
368 map
[i
].dkl_cylno
= cyloffset
;
369 cyloffset
+= (map
[i
].dkl_nblk
+ (spc()-1))/spc();
370 } else if (map
[i
].dkl_nblk
== 0) {
371 map
[i
].dkl_cylno
= 0;
374 for (i
= 0; i
< NDKMAP
/2; i
++) {
376 #else /* !defined(_SUNOS_VTOC_16) */
377 for (i
= 0; i
< NDKMAP
; i
++) {
378 #endif /* defined(_SUNOS_VTOC_16) */
380 if (i
!= C_PARTITION
&& map
[i
].dkl_nblk
) {
381 map
[i
].dkl_cylno
= cyloffset
;
382 cyloffset
+= (map
[i
].dkl_nblk
+ (spc()-1))/spc();
383 } else if (map
[i
].dkl_nblk
== 0) {
384 map
[i
].dkl_cylno
= 0;
391 * Check partition table
395 struct dk_map32
*map
;
399 blkaddr32_t tot_blks
= 0;
403 * On x86, we must account for the boot and alternates
405 cyloffset
= map
[0].dkl_cylno
;
406 tot_blks
= map
[0].dkl_nblk
;
410 * Do some checks for invalid parameters but do
411 * not modify the table.
413 for (i
= 0; i
< NDKMAP
; i
++) {
414 if (map
[i
].dkl_cylno
> (blkaddr32_t
)ncyl
-1) {
416 Warning: Partition %c starting cylinder %d is out of range.\n",
417 (PARTITION_BASE
+i
), map
[i
].dkl_cylno
);
420 if (map
[i
].dkl_nblk
>
421 (blkaddr32_t
)(ncyl
- map
[i
].dkl_cylno
) * spc()) {
423 Warning: Partition %c, specified # of blocks, %u, is out of range.\n",
424 (PARTITION_BASE
+i
), map
[i
].dkl_nblk
);
427 if (i
!= C_PARTITION
&& map
[i
].dkl_nblk
) {
429 if (i
== I_PARTITION
|| i
== J_PARTITION
)
432 if (map
[i
].dkl_cylno
< cyloffset
) {
434 "Warning: Overlapping partition (%c) in table.\n", PARTITION_BASE
+i
);
436 } else if (map
[i
].dkl_cylno
> cyloffset
) {
438 "Warning: Non-contiguous partition (%c) in table.\n", PARTITION_BASE
+i
);
440 cyloffset
+= (map
[i
].dkl_nblk
+ (spc()-1))/spc();
441 tot_blks
= map
[i
].dkl_nblk
;
444 if (tot_blks
> map
[C_PARTITION
].dkl_nblk
) {
446 Warning: Total blocks used is greater than number of blocks in '%c'\n\
447 \tpartition.\n", C_PARTITION
+ PARTITION_BASE
);
456 * get user defined partitions
459 get_user_map(map
, float_part
)
460 struct dk_map32
*map
;
470 * Get partition sizes
472 for (i
= 0; i
< NDKMAP
; i
++) {
473 if (partn_list
[i
] == NULL
)
475 if ((i
== C_PARTITION
) || (i
== float_part
))
478 ioparam
.io_bounds
.lower
= 0;
479 ioparam
.io_bounds
.upper
= map
[i
].dkl_nblk
+
480 map
[float_part
].dkl_nblk
;
481 deflt
= map
[i
].dkl_nblk
;
482 if (ioparam
.io_bounds
.upper
== 0) {
484 Warning: no space available for '%s' from Free Hog partition\n",
488 (void) snprintf(tmpstr
, sizeof (tmpstr
),
489 "Enter size of partition '%s' ",
491 newsize
= (blkaddr32_t
)input(FIO_CYL
, tmpstr
, ':',
492 &ioparam
, (int *)&deflt
, DATA_INPUT
);
493 map
[float_part
].dkl_nblk
-= (newsize
- map
[i
].dkl_nblk
);
494 map
[i
].dkl_nblk
= newsize
;
499 static struct partition_info
*
500 build_partition(tptr
)
501 struct disk_type
*tptr
;
503 struct partition_info
*part
;
504 struct dk_label
*label
;
508 fmt_print("Creating Default Partition for the disk \n");
511 * construct a label and pass it on to
512 * build_default_partition() which builds the
513 * default partition list.
515 label
= zalloc(sizeof (struct dk_label
));
516 label
->dkl_pcyl
= tptr
->dtype_pcyl
;
517 label
->dkl_ncyl
= tptr
->dtype_ncyl
;
518 label
->dkl_acyl
= tptr
->dtype_acyl
;
519 label
->dkl_nhead
= tptr
->dtype_nhead
;
520 label
->dkl_nsect
= tptr
->dtype_nsect
;
521 label
->dkl_apc
= apc
;
522 label
->dkl_intrlv
= 1;
523 label
->dkl_rpm
= tptr
->dtype_rpm
;
525 if (!build_default_partition(label
, cur_ctype
->ctype_ctype
))
528 part
= (struct partition_info
*)
529 zalloc(sizeof (struct partition_info
));
530 part
->pinfo_name
= alloc_string(tptr
->dtype_asciilabel
);
532 * Fill in the partition info from the label
534 for (i
= 0; i
< NDKMAP
; i
++) {
535 #if defined(_SUNOS_VTOC_8)
536 part
->pinfo_map
[i
] = label
->dkl_map
[i
];
538 part
->pinfo_map
[i
].dkl_cylno
=
539 label
->dkl_vtoc
.v_part
[i
].p_start
/
540 (blkaddr32_t
)(tptr
->dtype_nhead
* tptr
->dtype_nsect
- apc
);
541 part
->pinfo_map
[i
].dkl_nblk
=
542 label
->dkl_vtoc
.v_part
[i
].p_size
;
543 #endif /* ifdefined(_SUNOS_VTOC_8) */
545 part
->vtoc
= label
->dkl_vtoc
;
550 * build new partition table for given disk type
553 get_user_map_efi(map
, float_part
)
559 efi_deflt_t efi_deflt
;
563 uint64_t start_lba
= 34;
565 for (i
= 0; i
< map
->efi_nparts
- 1; i
++) {
569 ioparam
.io_bounds
.lower
= start_lba
;
570 ioparam
.io_bounds
.upper
= map
->efi_last_u_lba
;
571 efi_deflt
.start_sector
= ioparam
.io_bounds
.lower
;
572 efi_deflt
.end_sector
= map
->efi_parts
[i
].p_size
;
573 (void) sprintf(tmpstr
,
574 "Enter size of partition %d ", i
);
575 i64
= input(FIO_EFI
, tmpstr
, ':',
576 &ioparam
, (int *)&efi_deflt
, DATA_INPUT
);
578 map
->efi_parts
[i
].p_tag
= V_UNASSIGNED
;
579 } else if ((i64
!= 0) && (map
->efi_parts
[i
].p_tag
==
581 map
->efi_parts
[i
].p_tag
= V_USR
;
584 map
->efi_parts
[i
].p_start
= 0;
586 map
->efi_parts
[i
].p_start
= start_lba
;
588 map
->efi_parts
[i
].p_size
= i64
;
592 map
->efi_parts
[float_part
].p_start
= start_lba
;
593 map
->efi_parts
[float_part
].p_size
= map
->efi_last_u_lba
-
594 start_lba
- (1024 * 16);
595 map
->efi_parts
[float_part
].p_tag
= V_USR
;
596 if (map
->efi_parts
[float_part
].p_size
== UINT_MAX64
) {
597 map
->efi_parts
[float_part
].p_size
= 0;
598 map
->efi_parts
[float_part
].p_start
= 0;
599 map
->efi_parts
[float_part
].p_tag
= V_UNASSIGNED
;
600 fmt_print("Warning: No space left for HOG\n");
603 for (i
= 0; i
< map
->efi_nparts
; i
++) {
604 if (map
->efi_parts
[i
].p_tag
== V_RESERVED
) {
605 map
->efi_parts
[i
].p_start
= map
->efi_last_u_lba
-
607 map
->efi_parts
[i
].p_size
= (1024 * 16);
615 new_partitiontable(tptr
, oldtptr
)
616 struct disk_type
*tptr
, *oldtptr
;
618 struct partition_info
*part
;
621 * check if disk geometry has changed , if so add new
622 * partition table else copy the old partition table.(best guess).
624 if ((oldtptr
!= NULL
) &&
625 (tptr
->dtype_ncyl
== oldtptr
->dtype_ncyl
) &&
626 (tptr
->dtype_nhead
== oldtptr
->dtype_nhead
) &&
627 (tptr
->dtype_nsect
== oldtptr
->dtype_nsect
)) {
629 part
= (struct partition_info
*)
630 zalloc(sizeof (struct partition_info
));
631 bcopy((char *)cur_parts
, (char *)part
,
632 sizeof (struct partition_info
));
633 part
->pinfo_next
= tptr
->dtype_plist
;
634 tptr
->dtype_plist
= part
;
638 if (cur_parts
!= NULL
) {
639 fmt_print("Warning: Partition Table is set");
640 fmt_print("to default partition table. \n");
643 if (tptr
->dtype_plist
== NULL
) {
644 part
= (struct partition_info
*)build_partition(tptr
);
646 part
->pinfo_next
= tptr
->dtype_plist
;
647 tptr
->dtype_plist
= part
;