1 /*
2 * Copyright (C) 2009 by Bastian Friedrich <bastian.friedrich@collax.com>
3 *
4 * This file may be redistributed under the terms of the
5 * GNU Lesser General Public License.
6 *
7 * defines, structs taken from drbd source; file names represent drbd source
8 * files.
9 */
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <unistd.h>
13 #include <string.h>
14 #include <errno.h>
15 #include <ctype.h>
16 #include <inttypes.h>
17 #include <stddef.h>
18
19 #include "superblocks.h"
20
21 /*
22 * drbd/linux/drbd.h
23 */
24 #define DRBD_MAGIC 0x83740267
25
26 /*
27 * user/drbdmeta.c
28 * We support v08 and v09
29 */
30 #define DRBD_MD_MAGIC_08 (DRBD_MAGIC+4)
31 #define DRBD_MD_MAGIC_84_UNCLEAN (DRBD_MAGIC+5)
32 #define DRBD_MD_MAGIC_09 (DRBD_MAGIC+6)
33 /* there is no DRBD_MD_MAGIC_09_UNCLEAN */
34
35 /*
36 * drbd/linux/drbd.h
37 */
38 enum drbd_uuid_index {
39 UI_CURRENT,
40 UI_BITMAP,
41 UI_HISTORY_START,
42 UI_HISTORY_END,
43 UI_SIZE, /* nl-packet: number of dirty bits */
44 UI_FLAGS, /* nl-packet: flags */
45 UI_EXTENDED_SIZE /* Everything. */
46 };
47
48
49 /*
50 * Used by libblkid to avoid unnecessary padding at the end of the structs and
51 * too large unused structs in memory.
52 */
53 #define DRBD_MD_OFFSET 4096
54
55 /*
56 * user/shared/drbdmeta.c
57 * Minor modifications wrt. types
58 */
59 struct md_on_disk_08 {
60 uint64_t la_sect; /* last agreed size. */
61 uint64_t uuid[UI_SIZE]; /* UUIDs */
62 uint64_t device_uuid;
63 uint64_t reserved_u64_1;
64 uint32_t flags;
65 uint32_t magic;
66 uint32_t md_size_sect;
67 int32_t al_offset; /* signed sector offset to this block */
68 uint32_t al_nr_extents; /* important for restoring the AL */
69 int32_t bm_offset; /* signed sector offset to the bitmap, from here */
70 uint32_t bm_bytes_per_bit;
71 uint32_t reserved_u32[4];
72
73 /* Unnecessary for libblkid **
74 * char reserved[8 * 512 - (8*(UI_SIZE+3)+4*11)];
75 */
76 };
77
78 /*
79 * linux/drbd.h, v9 only
80 */
81 #define DRBD_PEERS_MAX 32
82 #define HISTORY_UUIDS DRBD_PEERS_MAX
83
84 /*
85 * drbd-headers/drbd_meta_data.h
86 * Minor modifications wrt. types
87 */
88 struct peer_dev_md_on_disk_9 {
89 uint64_t bitmap_uuid;
90 uint64_t bitmap_dagtag;
91 uint32_t flags;
92 int32_t bitmap_index;
93 uint32_t reserved_u32[2];
94 } __attribute__((packed));
95
96 struct meta_data_on_disk_9 {
97 uint64_t effective_size; /* last agreed size */
98 uint64_t current_uuid;
99 uint64_t reserved_u64[4]; /* to have the magic at the same position as in v07, and v08 */
100 uint64_t device_uuid;
101 uint32_t flags; /* MDF */
102 uint32_t magic;
103 uint32_t md_size_sect;
104 uint32_t al_offset; /* offset to this block */
105 uint32_t al_nr_extents; /* important for restoring the AL */
106 uint32_t bm_offset; /* offset to the bitmap, from here */
107 uint32_t bm_bytes_per_bit; /* BM_BLOCK_SIZE */
108 uint32_t la_peer_max_bio_size; /* last peer max_bio_size */
109 uint32_t bm_max_peers;
110 int32_t node_id;
111
112 /* see al_tr_number_to_on_disk_sector() */
113 uint32_t al_stripes;
114 uint32_t al_stripe_size_4k;
115
116 uint32_t reserved_u32[2];
117
118 struct peer_dev_md_on_disk_9 peers[DRBD_PEERS_MAX];
119 uint64_t history_uuids[HISTORY_UUIDS];
120
121 /* Unnecessary for libblkid **
122 * char padding[0] __attribute__((aligned(4096)));
123 */
124 } __attribute__((packed));
125
126
127 static int probe_drbd_84(blkid_probe pr)
128 {
129 struct md_on_disk_08 *md;
130 off_t off;
131
132 off = pr->size - DRBD_MD_OFFSET;
133
134 /* Small devices cannot be drbd (?) */
135 if (pr->size < 0x10000)
136 return 1;
137
138 md = (struct md_on_disk_08 *)
139 blkid_probe_get_buffer(pr,
140 off,
141 sizeof(struct md_on_disk_08));
142 if (!md)
143 return errno ? -errno : 1;
144
145 if (be32_to_cpu(md->magic) != DRBD_MD_MAGIC_08 &&
146 be32_to_cpu(md->magic) != DRBD_MD_MAGIC_84_UNCLEAN)
147 return 1;
148
149 /*
150 * DRBD does not have "real" uuids; the following resembles DRBD's
151 * notion of uuids (64 bit, see struct above)
152 */
153 blkid_probe_sprintf_uuid(pr,
154 (unsigned char *) &md->device_uuid, sizeof(md->device_uuid),
155 "%" PRIx64, be64_to_cpu(md->device_uuid));
156
157 blkid_probe_set_version(pr, "v08");
158
159 if (blkid_probe_set_magic(pr,
160 off + offsetof(struct md_on_disk_08, magic),
161 sizeof(md->magic),
162 (unsigned char *) &md->magic))
163 return 1;
164
165 return 0;
166 }
167
168 static int probe_drbd_90(blkid_probe pr)
169 {
170 struct meta_data_on_disk_9 *md;
171 off_t off;
172
173 off = pr->size - DRBD_MD_OFFSET;
174
175 /*
176 * Smaller ones are certainly not DRBD9 devices.
177 * Recent utils even refuse to generate larger ones,
178 * keep this as a sufficient lower bound.
179 */
180 if (pr->size < 0x10000)
181 return 1;
182
183 md = (struct meta_data_on_disk_9 *)
184 blkid_probe_get_buffer(pr,
185 off,
186 sizeof(struct meta_data_on_disk_9));
187 if (!md)
188 return errno ? -errno : 1;
189
190 if (be32_to_cpu(md->magic) != DRBD_MD_MAGIC_09)
191 return 1;
192
193 /*
194 * DRBD does not have "real" uuids; the following resembles DRBD's
195 * notion of uuids (64 bit, see struct above)
196 */
197 blkid_probe_sprintf_uuid(pr,
198 (unsigned char *) &md->device_uuid, sizeof(md->device_uuid),
199 "%" PRIx64, be64_to_cpu(md->device_uuid));
200
201 blkid_probe_set_version(pr, "v09");
202
203 if (blkid_probe_set_magic(pr,
204 off + offsetof(struct meta_data_on_disk_9, magic),
205 sizeof(md->magic),
206 (unsigned char *) &md->magic))
207 return 1;
208
209 return 0;
210 }
211
212 static int probe_drbd(blkid_probe pr,
213 const struct blkid_idmag *mag __attribute__((__unused__)))
214 {
215 int ret;
216
217 ret = probe_drbd_84(pr);
218 if (ret <= 0) /* success or fatal (-errno) */
219 return ret;
220
221 return probe_drbd_90(pr);
222 }
223
224 const struct blkid_idinfo drbd_idinfo =
225 {
226 .name = "drbd",
227 .usage = BLKID_USAGE_RAID,
228 .probefunc = probe_drbd,
229 .magics = BLKID_NONE_MAGIC
230 };
231