]> git.neil.brown.name Git - lafs-utils.git/blob - lib/lafs_load.c
a4ef56e22053b32caf92143a49b480257634e7b8
[lafs-utils.git] / lib / lafs_load.c
1 #define _GNU_SOURCE
2 #define _FILE_OFFSET_BITS 64
3
4 #include <unistd.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include <talloc.h>
8 #include <lafs/lafs.h>
9 #include "internal.h"
10
11 /* read the device blocks and state blocks from this device.
12  * If valid, return a 'lafs_dev' suitably filled in.
13  * The most recent state block is found and index is recorded in lafs_dev
14  *
15  * device block should be near the start and near the end.
16  * Should probably determine block size, but for not just iterate
17  * over sectors.
18  */
19
20 static int valid_devblock(struct lafs_dev *db, unsigned long long addr,
21                           unsigned long long device_bytes)
22 {
23         /* check that this devblock is valid, given that
24          * it was found at sector 'addr'
25          */
26         u32 crc, crc2;
27         u64 byteaddr;
28         unsigned long long segsize;
29         int i;
30
31         if (strncmp(db->idtag, "LaFS-DeviceBlock", 16) != 0)
32                 return 0;
33         if (strncmp(db->version, "AlphaDevel      ", 16) != 0)
34                 return 0;
35         /* uuid can be anything */
36         crc = db->checksum;
37         db->checksum = 0;
38         crc2 = crc32(0, (uint32_t*)db, LAFS_DEVBLK_SIZE);
39         db->checksum = crc;
40         if (crc2 != crc)
41                 return 0;
42
43         byteaddr = addr << 9; /* convert to byte */
44         if (__le64_to_cpu(db->devaddr[0]) != byteaddr &&
45             __le64_to_cpu(db->devaddr[1]) != byteaddr)
46                 return 0;
47
48         if (db->statebits < 10 || db->statebits > 16)
49                 return 0;
50         if (db->blockbits < 9 || db->blockbits > 20)
51                 return 0;
52         if (__le16_to_cpu(db->width) < 1 || __le16_to_cpu(db->width) >= 512)
53                 return 0;
54         if (__le32_to_cpu(db->stride) < 1)
55                 return 0;
56         /* devaddr[0] must be early, [1] must be late */
57         if (__le64_to_cpu(db->devaddr[0]) >=
58             __le64_to_cpu(db->segment_offset))
59                 return 0;
60
61         if (__le64_to_cpu(db->devaddr[1]) <
62             __le64_to_cpu(db->segment_offset) +
63             ((((unsigned long long)__le32_to_cpu(db->segment_count)
64                * __le32_to_cpu(db->segment_size)))
65              << db->blockbits))
66                 return 0;
67
68         /* 2 is an absolute minimum segment size, a few hundred is more
69          * likely. We'll put a lower limit of 8, and an upper of 800000
70          */
71         if (__le32_to_cpu(db->segment_size) < 8 ||
72             __le32_to_cpu(db->segment_size) > 800000)
73                 return 0;
74
75         if (__le32_to_cpu(db->segment_offset) >
76             (__le32_to_cpu(db->segment_size)<<db->blockbits) * 10)
77                 return 0;
78
79         /* The 4 state blocks live before the first or after the last segment.
80          * The distance from start of first to end of last is either:
81          * - segment_count * segment_size  if width*stride <= segment_size
82          * - (width-1) * stride + segment_size / width * segment_count
83          *                if width * stride > segment_size
84          */
85         segsize = __le32_to_cpu(db->segment_size);
86         segsize *= __le32_to_cpu(db->segment_count);
87         if (__le16_to_cpu(db->width) *  __le32_to_cpu(db->stride)
88             > __le32_to_cpu(db->segment_size)) {
89                 int stride = __le32_to_cpu(db->stride);
90                 int width = __le16_to_cpu(db->width);
91
92                 segsize /= width;
93                 segsize += (width - 1) * stride;
94         }
95         segsize <<= db->blockbits;
96         for (i = 0; i < 4; i++) {
97                 unsigned long long addr = __le64_to_cpu(db->stateaddr[i]);
98                 int offset = __le32_to_cpu(db->segment_offset);
99                 if (addr + (1<<db->statebits) > offset &&
100                     addr < offset + segsize)
101                         return 0;
102                 if (addr + (1<<db->statebits) > device_bytes)
103                         return 0;
104         }
105
106         /* Check all segments fit within device */
107         if (__le32_to_cpu(db->segment_offset) + segsize > device_bytes)
108                 return 0;
109
110         if (__le32_to_cpu(db->level) > 10)
111                 return 0;
112
113         /* I guess it look sane enough... */
114         return 1;
115 }
116
117 static int compare_dev(struct lafs_dev *curr, struct lafs_dev *new)
118 {
119         if (memcmp(curr->uuid, new->uuid, 16) != 0)
120                 /* there are different */
121                 return -1;
122         if (memcmp(curr->version, new->version, 16) != 0)
123                 return -1;
124
125         if (__le32_to_cpu(curr->seq) >= __le32_to_cpu(new->seq))
126                 return 0; /*current is best */
127         return 1;
128 }
129
130 static int check_state(struct lafs_device *dev, int which)
131 {
132         /* Load this state block, perform basic check and update
133          * dev->state_seq if seq number is new
134          */
135         struct lafs_state *sb = malloc(dev->statesize);
136         u32 crc, crc2;
137         int rv = 0;
138
139         lseek64(dev->fd, dev->stateaddr[which], 0);
140         if (read(dev->fd, sb, dev->statesize) != dev->statesize)
141                 goto out;
142         if (memcmp(sb->idtag, "LaFS-State-Block", 16) != 0)
143                 goto out;
144         if (memcmp(sb->uuid, dev->uuid, 16) != 0)
145                 goto out;
146         crc = sb->checksum;
147         sb->checksum = 0;
148         crc2 = crc32(0, (uint32_t*)sb, dev->statesize);
149         if (crc != crc2)
150                 goto out;
151
152         if (__le32_to_cpu(sb->seq) > dev->state_seq) {
153                 dev->recent_state = which;
154                 dev->state_seq = __le32_to_cpu(sb->seq);
155                 dev->devices = __le32_to_cpu(sb->devices);
156         }
157         rv = 1;
158         
159 out:
160         free(sb);
161         return rv;
162 }
163
164 static int destroy(struct lafs_device *dev)
165 {
166         if (dev->fd >= 0)
167                 close(dev->fd);
168         return 0;
169 }
170
171
172 struct lafs_device *lafs_load(int fd, long long device_bytes, char **err)
173 {
174         char buf[LAFS_DEVBLK_SIZE];
175         struct lafs_dev *d = (void*)buf;
176         struct lafs_dev best;
177         int have_best = 0;
178         unsigned long long addr, best_addr;
179         struct lafs_device *dev;
180         int i;
181         int found;
182
183         err = NULL;
184
185         for (addr = 0; addr < device_bytes; addr += 512) {
186                 if (addr == 32*512 && device_bytes > 64*512)
187                         addr = device_bytes - 32*512;
188
189                 lseek64(fd, addr, 0);
190                 if (read(fd, buf, LAFS_DEVBLK_SIZE) != LAFS_DEVBLK_SIZE)
191                         continue;
192                 if (!valid_devblock(d, addr, device_bytes))
193                         continue;
194                 if (!have_best) {
195                         best = *d;
196                         best_addr = addr;
197                         have_best = 1;
198                         continue;
199                 }
200                 switch(compare_dev(&best, d)) {
201                 case 0: /* best is still best */
202                         continue;
203                 case 1: /* d is better */
204                         best = *d;
205                         best_addr = addr;
206                         continue;
207                 default: /* incompatible */
208                         *err = "inconsistent device information blocks found";
209                         return NULL;
210                 }
211         }
212         if (!have_best) {
213                 *err = "no valid device block found";
214                 return NULL;
215         }
216
217         /* talloc device, fill in details, record where loaded from */
218         dev = talloc(NULL, struct lafs_device);
219         talloc_set_destructor(dev, destroy);
220         memset(dev, 0, sizeof(*dev));
221         dev->fd = fd;
222         dev->seq = __le32_to_cpu(best.seq);
223         dev->start = __le64_to_cpu(best.start);
224         dev->size = __le64_to_cpu(best.size);
225         for (i=0 ; i<2; i++) {
226                 dev->devaddr[i] = __le64_to_cpu(best.devaddr[i]);
227                 if (dev->devaddr[i] == best_addr)
228                         dev->recent_super = i;
229         }
230         for (i=0; i<4; i++)
231                 dev->stateaddr[i] = __le64_to_cpu(best.stateaddr[i]);
232
233         lafs_decode_timeval(&dev->ctime, best.ctime);
234         dev->width = __le16_to_cpu(best.width);
235         dev->stride = __le32_to_cpu(best.stride);
236         dev->segment_size   = __le32_to_cpu(best.segment_size);
237         dev->segment_offset = __le32_to_cpu(best.segment_offset);
238         dev->segment_count  = __le32_to_cpu(best.segment_count);
239         dev->usage_inum = __le32_to_cpu(best.usage_inum);
240
241         memcpy(dev->version, best.version, 16);
242         memcpy(dev->uuid, best.uuid, 16);
243         dev->blockbits = best.blockbits;
244         dev->statesize = 1 << best.statebits;
245
246         found = 0;
247         for (i=0; i<4; i++)
248                 found += check_state(dev, i);
249         
250         if (!found)
251                 *err = "No valid state block found on device";
252
253         return dev;
254 }
255
256