Add gpt pseudo-metadata
[thirdparty/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
77         free_gpt(st);
78
79         if (st->subarray[0])
80                 return 1;
81
82         if (posix_memalign((void**)&super, 512, 32*512) != 0) {
83                 fprintf(stderr, Name ": %s could not allocate superblock\n",
84                         __func__);
85                 return 1;
86         }
87
88         ioctl(fd, BLKFLSBUF, 0); /* make sure we read current data */
89
90         lseek(fd, 0, 0);
91         if (read(fd, super, sizeof(*super)) != sizeof(*super)) {
92         no_read:
93                 if (devname)
94                         fprintf(stderr, Name ": 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                         fprintf(stderr, Name ": No partition table found on %s\n",
105                                 devname);
106                 free(super);
107                 return 1;
108         }
109         /* Seem to have GPT, load the header */
110         gpt_head = (struct GPT*)(super+1);
111         if (read(fd, gpt_head, sizeof(*gpt_head)) != sizeof(*gpt_head))
112                 goto no_read;
113         if (gpt_head->magic != GPT_SIGNATURE_MAGIC)
114                 goto not_found;
115         if (__le32_to_cpu(gpt_head->part_cnt) >= 128)
116                 goto not_found;
117
118         to_read = __le32_to_cpu(gpt_head->part_cnt) * sizeof(struct GPT_part_entry);
119         to_read =  ((to_read+511)/512) * 512;
120         if (read(fd, gpt_head+1, to_read) != to_read)
121                 goto no_read;
122
123         st->sb = super;
124
125         if (st->ss == NULL) {
126                 st->ss = &gpt;
127                 st->minor_version = 0;
128                 st->max_devs = 1;
129                 st->info = NULL;
130         }
131         return 0;
132 }
133
134 static int store_gpt(struct supertype *st, int fd)
135 {
136         /* FIXME should I save the boot loader */
137         /* need to write two copies! */
138         /* FIXME allow for blocks != 512 bytes
139          *etc
140          */
141         struct MBR *super = st->sb;
142         struct GPT *gpt;
143         int to_write;
144
145         gpt = (struct GPT*)(super+1);
146
147         to_write = __le32_to_cpu(gpt->part_cnt) * sizeof(struct GPT_part_entry);
148         to_write =  ((to_write+511)/512) * 512;
149
150         lseek(fd, 0, 0);
151         if (write(fd, st->sb, to_write) != to_write)
152                 return 4;
153
154         fsync(fd);
155         ioctl(fd, BLKRRPART, 0);
156         return 0;
157 }
158
159 static void getinfo_gpt(struct supertype *st, struct mdinfo *info)
160 {
161         struct GPT *gpt = st->sb + 512;
162         struct GPT_part_entry *gpe = st->sb + 1024;
163         unsigned int i;
164
165         memset(&info->array, 0, sizeof(info->array));
166         memset(&info->disk, 0, sizeof(info->disk));
167         strcpy(info->text_version, "gpt");
168         strcpy(info->name, "gpt");
169         info->component_size = 0;
170
171         for (i = 0; i < __le32_to_cpu(gpt->part_cnt); i++) {
172                 unsigned long long last =
173                         (unsigned long long)__le64_to_cpu(gpe[i].ending_lba);
174                 if (last > info->component_size)
175                         info->component_size = last;
176         }
177 }
178
179 static struct supertype *match_metadata_desc(char *arg)
180 {
181         struct supertype *st = malloc(sizeof(*st));
182
183         if (!st)
184                 return st;
185         if (strcmp(arg, "gpt") != 0)
186                 return NULL;
187
188         st->ss = &gpt;
189         st->info = NULL;
190         st->minor_version = 0;
191         st->max_devs = 1;
192         st->sb = NULL;
193         return st;
194 }
195
196 #ifndef MDASSEMBLE
197 static int validate_geometry(struct supertype *st, int level,
198                              int layout, int raiddisks,
199                              int chunk, unsigned long long size,
200                              char *subdev, unsigned long long *freesize,
201                              int verbose)
202 {
203         fprintf(stderr, Name ": gpt metadata cannot be used this way\n");
204         return 0;
205 }
206 #endif
207
208 struct superswitch gpt = {
209 #ifndef MDASSEMBLE
210         .examine_super = examine_gpt,
211 #endif
212         .validate_geometry = validate_geometry,
213         .match_metadata_desc = match_metadata_desc,
214         .load_super = load_gpt,
215         .store_super = store_gpt,
216         .getinfo_super = getinfo_gpt,
217         .free_super = free_gpt,
218         .name = "gpt",
219 };