]> git.neil.brown.name Git - mdadm.git/blob - super-gpt.c
Release mdadm-4.0
[mdadm.git] / super-gpt.c
1 /*
2  * mdadm - manage Linux "md" devices aka RAID arrays.
3  *
4  * Copyright (C) 2010 Neil Brown <neilb@suse.de>
5  *
6  *
7  *    This program is free software; you can redistribute it and/or modify
8  *    it under the terms of the GNU General Public License as published by
9  *    the Free Software Foundation; either version 2 of the License, or
10  *    (at your option) any later version.
11  *
12  *    This program is distributed in the hope that it will be useful,
13  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *    GNU General Public License for more details.
16  *
17  *    You should have received a copy of the GNU General Public License
18  *    along with this program; if not, write to the Free Software
19  *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  *
21  *    Author: Neil Brown
22  *    Email: <neil@brown.name>
23  *
24  */
25
26 /*
27  * 'gpt' is a pseudo metadata type for devices which have a
28  * GPT partition table.
29  *
30  * Obviously arrays cannot be created or assembled for this type.
31  * It is used to allow a new bare device to have an partition table
32  * added so the member partitions can then be included in other
33  * arrays as relevant.
34  *
35  * The meaning operations are:
36  * examine_super, but not brief_examine_super or export_examine
37  * load_super
38  * store_super
39  */
40
41 #include "mdadm.h"
42 #include "part.h"
43
44 static void free_gpt(struct supertype *st)
45 {
46         free(st->sb);
47         st->sb = NULL;
48 }
49
50 #ifndef MDASSEMBLE
51 static void examine_gpt(struct supertype *st, char *homehost)
52 {
53         struct GPT *gpt = st->sb + 512;
54         struct GPT_part_entry *gpe = st->sb + 1024;
55         unsigned int i;
56
57         printf("    GPT Magic : %llx\n", (unsigned long long)__le64_to_cpu(gpt->magic));
58         printf(" GPT Revision : %ld\n", (long)__le32_to_cpu(gpt->revision));
59         for (i = 0; i < __le32_to_cpu(gpt->part_cnt); i++) {
60                 printf("  Partition[%02d] : %12llu sectors at %12llu\n",
61                        i,
62                        (unsigned long long)__le64_to_cpu(gpe[i].starting_lba),
63                        (unsigned long long)__le64_to_cpu(gpe[i].ending_lba)-
64                        (unsigned long long)__le64_to_cpu(gpe[i].starting_lba)
65                        +1
66                         );
67         }
68 }
69 #endif /* MDASSEMBLE */
70
71 static int load_gpt(struct supertype *st, int fd, char *devname)
72 {
73         struct MBR *super;
74         struct GPT *gpt_head;
75         int to_read;
76         unsigned int sector_size;
77
78         free_gpt(st);
79
80         if (posix_memalign((void**)&super, 4096, 32*512) != 0) {
81                 pr_err("could not allocate superblock\n");
82                 return 1;
83         }
84
85         if (!get_dev_sector_size(fd, devname, &sector_size)) {
86                 free(super);
87                 return 1;
88         }
89
90         lseek(fd, 0, 0);
91         if (read(fd, super, sizeof(*super)) != sizeof(*super)) {
92         no_read:
93                 if (devname)
94                         pr_err("Cannot read partition table on %s\n",
95                                 devname);
96                 free(super);
97                 return 1;
98         }
99
100         if (super->magic != MBR_SIGNATURE_MAGIC ||
101             super->parts[0].part_type != MBR_GPT_PARTITION_TYPE) {
102         not_found:
103                 if (devname)
104                         pr_err("No partition table found on %s\n",
105                                 devname);
106                 free(super);
107                 return 1;
108         }
109         /* Set offset to second block (GPT header) */
110         lseek(fd, sector_size, SEEK_SET);
111         /* Seem to have GPT, load the header */
112         gpt_head = (struct GPT*)(super+1);
113         if (read(fd, gpt_head, sizeof(*gpt_head)) != sizeof(*gpt_head))
114                 goto no_read;
115         if (gpt_head->magic != GPT_SIGNATURE_MAGIC)
116                 goto not_found;
117         if (__le32_to_cpu(gpt_head->part_cnt) >= 128)
118                 goto not_found;
119
120         to_read = __le32_to_cpu(gpt_head->part_cnt) * sizeof(struct GPT_part_entry);
121         to_read =  ((to_read+511)/512) * 512;
122         /* Set offset to third block (GPT entries) */
123         lseek(fd, sector_size*2, SEEK_SET);
124         if (read(fd, gpt_head+1, to_read) != to_read)
125                 goto no_read;
126
127         st->sb = super;
128
129         if (st->ss == NULL) {
130                 st->ss = &gpt;
131                 st->minor_version = 0;
132                 st->max_devs = 1;
133                 st->info = NULL;
134         }
135         return 0;
136 }
137
138 static int store_gpt(struct supertype *st, int fd)
139 {
140         /* FIXME should I save the boot loader */
141         /* need to write two copies! */
142         /* FIXME allow for blocks != 512 bytes
143          *etc
144          */
145         struct MBR *super = st->sb;
146         struct GPT *gpt;
147         int to_write;
148
149         gpt = (struct GPT*)(super+1);
150
151         to_write = __le32_to_cpu(gpt->part_cnt) * sizeof(struct GPT_part_entry);
152         to_write =  ((to_write+511)/512) * 512;
153
154         lseek(fd, 0, 0);
155         if (write(fd, st->sb, to_write) != to_write)
156                 return 4;
157
158         fsync(fd);
159         ioctl(fd, BLKRRPART, 0);
160         return 0;
161 }
162
163 static void getinfo_gpt(struct supertype *st, struct mdinfo *info, char *map)
164 {
165         struct GPT *gpt = st->sb + 512;
166         struct GPT_part_entry *gpe = st->sb + 1024;
167         unsigned int i;
168
169         memset(&info->array, 0, sizeof(info->array));
170         memset(&info->disk, 0, sizeof(info->disk));
171         strcpy(info->text_version, "gpt");
172         strcpy(info->name, "gpt");
173         info->component_size = 0;
174
175         for (i = 0; i < __le32_to_cpu(gpt->part_cnt); i++) {
176                 unsigned long long last =
177                         (unsigned long long)__le64_to_cpu(gpe[i].ending_lba);
178                 if (last > info->component_size)
179                         info->component_size = last;
180         }
181 }
182
183 static struct supertype *match_metadata_desc(char *arg)
184 {
185         struct supertype *st = xmalloc(sizeof(*st));
186
187         if (!st)
188                 return st;
189         if (strcmp(arg, "gpt") != 0) {
190                 free(st);
191                 return NULL;
192         }
193
194         st->ss = &gpt;
195         st->info = NULL;
196         st->minor_version = 0;
197         st->max_devs = 1;
198         st->sb = NULL;
199         return st;
200 }
201
202 #ifndef MDASSEMBLE
203 static int validate_geometry(struct supertype *st, int level,
204                              int layout, int raiddisks,
205                              int *chunk, unsigned long long size,
206                              unsigned long long data_offset,
207                              char *subdev, unsigned long long *freesize,
208                              int verbose)
209 {
210         pr_err("gpt metadata cannot be used this way\n");
211         return 0;
212 }
213 #endif
214
215 struct superswitch gpt = {
216 #ifndef MDASSEMBLE
217         .examine_super = examine_gpt,
218         .validate_geometry = validate_geometry,
219 #endif
220         .match_metadata_desc = match_metadata_desc,
221         .load_super = load_gpt,
222         .store_super = store_gpt,
223         .getinfo_super = getinfo_gpt,
224         .free_super = free_gpt,
225         .name = "gpt",
226 };