]> git.neil.brown.name Git - lafs-utils.git/blob - lib/lafs_mount.c
bce49efa312b91e4992a8b3b61007e43f03ba79c
[lafs-utils.git] / lib / lafs_mount.c
1 #define _GNU_SOURCE
2 #define _FILE_OFFSET_BITS 64
3
4 #include <unistd.h>
5 #include <stdio.h>
6 #include <string.h>
7 #include <talloc.h>
8 #include <lafs/lafs.h>
9 #include "internal.h"
10
11 static int csum_ok(struct lafs_state *st, int size)
12 {
13         u32 crc, crc2;
14         crc = st->checksum;
15         st->checksum = 0;
16         crc2 = crc32(0, (uint32_t*)st, size);
17         st->checksum = crc;
18         return crc == crc2;
19 }
20
21 char *lafs_mount(struct lafs *fs, int force)
22 {
23         char *err = NULL;
24         struct lafs_device *dv;
25         struct lafs_state *st;
26         struct lafs_snapshot **ssp;
27         int s;
28
29         if (fs->blocksize == 0)
30                 return strdup("mount: no devices loaded");
31
32         if (fs->loaded_devs != fs->devices) {
33                 asprintf(&err, 
34                          "need %d devices, only %d loaded",
35                          fs->devices, fs->loaded_devs);
36                 return err;
37         }
38         /* - check that the loaded devices don't overlap.
39          * - Choose and load a state block
40          * - fill in data in 'lafs': e..g ss, max_segment, checkpoint_cluster,
41          *   youth
42          */
43
44         if (fs->ss.root || fs->ss.root_addr) {
45                 asprintf(&err, "LaFS is already mounted");
46                 return err;
47         }
48
49         /* FIXME check seq number is OK. */
50         for (dv = fs->devs; dv; dv = dv->next) {
51                 struct lafs_device *dv2;
52                 for (dv2 = dv->next; dv2; dv2= dv->next) {
53                         if (dv->start < dv2->start + dv2->size &&
54                             dv->start + dv->size <= dv2->start)
55                                 continue;
56                         if (dv2->start < dv->start + dv->size &&
57                             dv2->start + dv2->size <= dv->start)
58                                 continue;
59                         asprintf(&err, "devices %s and %s overlap",
60                                  dv->name, dv2->name);
61                         return err;
62                 }
63         }
64         st = malloc(fs->statesize);
65         for (dv = fs->devs; dv; dv = dv->next)
66                 if (lseek64(dv->fd, dv->stateaddr[dv->recent_state], 0)
67                     == dv->stateaddr[dv->recent_state]
68                     && read(dv->fd, st, fs->statesize) == fs->statesize)
69                         break;
70         if (!dv) {
71                 asprintf(&err, "Couldn't load a state block from any device");
72                 free(st);
73                 return err;
74         }
75         /* The state block has already been checked by lafs_load, but just
76          * to be sure...
77          */
78         if (memcmp(st->idtag, "LaFS-State-Block", 16) != 0 ||
79             memcmp(st->uuid, fs->uuid, 16) != 0 ||
80             !csum_ok(st, fs->statesize)) {
81                 asprintf(&err, "state block nolonger looks correct");
82                 free(st);
83                 return err;
84         }
85         /* OK, let-her-rip. */
86         fs->seq = __le32_to_cpu(st->seq);
87 //      fs->levels = __le32_to_cpu(st->levels);
88         fs->checkpoint_cluster = __le64_to_cpu(st->checkpointcluster);
89         fs->youth_next = __le16_to_cpu(st->nextyouth);
90         fs->ss.root_addr = __le64_to_cpu(st->root_inodes[0]);
91         fs->ss.next = NULL;
92
93         ssp = &fs->ss.next;
94         for (s = 1; s < __le32_to_cpu(st->maxsnapshot); s++) {
95                 struct lafs_snapshot *ss;
96                 if (st->root_inodes[s] == 0)
97                         continue;
98                 ss = talloc(fs, struct lafs_snapshot);
99                 ss->next = NULL;
100                 ss->root_addr = __le64_to_cpu(st->root_inodes[s]);
101                 ss->root = NULL;
102                 ss->rootdir = NULL;
103                 *ssp = ss;
104                 ssp = &ss->next;
105         }
106         lafs_get_itable(fs);
107
108         fs->max_segment = 0;
109         for (dv = fs->devs ; dv; dv=dv->next)
110                 if (fs->max_segment < dv->segment_size)
111                         fs->max_segment = dv->segment_size;
112
113         fs->checkpointing = 0;
114         free(st);
115         return NULL;
116 }