Submit #3276 ยป expand.patch
| sbin/gpt/expand.c | ||
|---|---|---|
|
#include "map.h"
|
||
|
#include "gpt.h"
|
||
|
static void expand(int fd);
|
||
|
static void expand(int fd, int expand_last);
|
||
|
static void
|
||
|
usage_expand(void)
|
||
|
{
|
||
|
fprintf(stderr, "usage: %s expand [-x] <device>...\n", getprogname());
|
||
|
exit(1);
|
||
|
}
|
||
|
int
|
||
|
cmd_expand(int argc, char *argv[])
|
||
|
{
|
||
|
int fd;
|
||
|
if (argc == optind) {
|
||
|
fprintf(stderr, "usage: gpt expand <device>...\n");
|
||
|
exit(1);
|
||
|
int ch;
|
||
|
int expand_last = 0;
|
||
|
while ((ch = getopt(argc, argv, "x")) != -1) {
|
||
|
switch(ch) {
|
||
|
case 'x':
|
||
|
expand_last = 1;
|
||
|
break;
|
||
|
default:
|
||
|
usage_expand();
|
||
|
}
|
||
|
}
|
||
|
if (argc == optind)
|
||
|
usage_expand();
|
||
|
while (optind < argc) {
|
||
|
fd = gpt_open(argv[optind++]);
|
||
|
if (fd == -1) {
|
||
| ... | ... | |
|
continue;
|
||
|
}
|
||
|
expand(fd);
|
||
|
expand(fd, expand_last);
|
||
|
gpt_close(fd);
|
||
|
}
|
||
| ... | ... | |
|
}
|
||
|
static void
|
||
|
expand(int fd __unused)
|
||
|
expand_last_to_fill(struct gpt_hdr *hdr, map_t *tbl, off_t last, off_t blocks)
|
||
|
{
|
||
|
struct gpt_ent *ent;
|
||
|
struct gpt_ent *lent = NULL;
|
||
|
u_int i;
|
||
|
u_int li;
|
||
|
off_t nblocks;
|
||
|
char *name = NULL;
|
||
|
li = 0;
|
||
|
for (i = 0; i < le32toh(hdr->hdr_entries); ++i) {
|
||
|
ent = (void *)((char *)tbl->map_data + i *
|
||
|
le32toh(hdr->hdr_entsz));
|
||
|
if (uuid_is_nil(&ent->ent_type, NULL))
|
||
|
continue;
|
||
|
lent = ent;
|
||
|
li = i;
|
||
|
}
|
||
|
if (lent) {
|
||
|
uuid_to_string(&ent->ent_type, &name, NULL);
|
||
|
nblocks = last - blocks - le64toh(lent->ent_lba_start);
|
||
|
nblocks = (nblocks * secsz / (1024 * 1024)) * 1024 * 1024 /
|
||
|
secsz;
|
||
|
if (le64toh(lent->ent_lba_end) ==
|
||
|
le64toh(lent->ent_lba_start) + nblocks - 1) {
|
||
|
printf("entry %d type=%s %ld,%ld unchanged\n",
|
||
|
li, name,
|
||
|
le64toh(lent->ent_lba_start),
|
||
|
le64toh(lent->ent_lba_end));
|
||
|
} else {
|
||
|
printf("expand entry %d type=%s %ld,%ld to %ld\n",
|
||
|
li, name,
|
||
|
le64toh(lent->ent_lba_start),
|
||
|
le64toh(lent->ent_lba_end),
|
||
|
le64toh(lent->ent_lba_start) + nblocks - 1);
|
||
|
lent->ent_lba_end = htole64(
|
||
|
le64toh(lent->ent_lba_start) +
|
||
|
nblocks - 1);
|
||
|
}
|
||
|
if (name != NULL) {
|
||
|
free(name);
|
||
|
name = NULL;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
static void
|
||
|
expand(int fd __unused, int expand_last)
|
||
|
{
|
||
|
map_t *pmbr;
|
||
|
map_t *gpt, *gpt2;
|
||
| ... | ... | |
|
off_t last;
|
||
|
off_t blocks;
|
||
|
off_t delta;
|
||
|
off_t nblocks;
|
||
|
struct gpt_hdr *hdr;
|
||
|
struct gpt_ent *ent;
|
||
|
struct gpt_ent *lent;
|
||
|
char *name = NULL;
|
||
|
u_int i;
|
||
|
u_int li;
|
||
|
pmbr = map_find(MAP_TYPE_PMBR);
|
||
|
if (pmbr == NULL) {
|
||
| ... | ... | |
|
hdr->hdr_lba_table = htole64(tbl2->map_start);
|
||
|
hdr->hdr_lba_alt = htole64(1);
|
||
|
lent = NULL;
|
||
|
li = 0;
|
||
|
for (i = 0; i < le32toh(hdr->hdr_entries); ++i) {
|
||
|
ent = (void *)((char *)tbl->map_data + i *
|
||
|
le32toh(hdr->hdr_entsz));
|
||
|
if (uuid_is_nil(&ent->ent_type, NULL))
|
||
|
continue;
|
||
|
lent = ent;
|
||
|
li = i;
|
||
|
}
|
||
|
hdr = gpt2->map_data;
|
||
|
if (lent) {
|
||
|
uuid_to_string(&ent->ent_type, &name, NULL);
|
||
|
nblocks = last - blocks - le64toh(lent->ent_lba_start);
|
||
|
nblocks = (nblocks * secsz / (1024 * 1024)) * 1024 * 1024 /
|
||
|
secsz;
|
||
|
if (le64toh(lent->ent_lba_end) ==
|
||
|
le64toh(lent->ent_lba_start) + nblocks - 1) {
|
||
|
printf("entry %d type=%s %ld,%ld unchanged\n",
|
||
|
li, name,
|
||
|
le64toh(lent->ent_lba_start),
|
||
|
le64toh(lent->ent_lba_end));
|
||
|
} else {
|
||
|
printf("expand entry %d type=%s %ld,%ld to %ld\n",
|
||
|
li, name,
|
||
|
le64toh(lent->ent_lba_start),
|
||
|
le64toh(lent->ent_lba_end),
|
||
|
le64toh(lent->ent_lba_start) + nblocks - 1);
|
||
|
lent->ent_lba_end = htole64(
|
||
|
le64toh(lent->ent_lba_start) +
|
||
|
nblocks - 1);
|
||
|
}
|
||
|
}
|
||
|
if (expand_last)
|
||
|
expand_last_to_fill(hdr, tbl, last, blocks);
|
||
|
/*
|
||
|
* Write out
|
||
| ... | ... | |
|
gpt_write(fd, gpt); /* primary partition table */
|
||
|
gpt_write(fd, tbl); /* primary header */
|
||
|
gpt_write(fd, pmbr); /* primary header */
|
||
|
if (name)
|
||
|
free(name);
|
||
|
}
|
||
| sbin/gpt/gpt.8 | ||
|---|---|---|
|
.Nm
|
||
|
to destroy the table in a way that it can be recovered.
|
||
|
.\" ==== expand ====
|
||
|
.It Nm Ic expand Ar device
|
||
|
.It Nm Ic expand Oo Fl x Oc Ar device
|
||
|
The
|
||
|
.Ic expand
|
||
|
command will expand an existing gpt label to cover a device which
|
||
|
has grown in size, and will also expand the size of the last GPT
|
||
|
partition to fit.
|
||
|
has grown in size.
|
||
|
.Pp
|
||
|
If the
|
||
|
.Fl x
|
||
|
option is specified, last GPT partition is expanded to fit.
|
||
|
This is typically the first step when expanding a hammer2 filesystem,
|
||
|
after which disklabel -x and hammer2 growfs are run.
|
||
|
.\" ==== init ====
|
||