From: NeilBrown Date: Sat, 19 Mar 2011 07:51:40 +0000 (+1100) Subject: add mount command X-Git-Url: http://git.neil.brown.name/?a=commitdiff_plain;h=f88171465f3bf8ef350a7f6cd6730fbcd8a5997b;p=lafs-utils.git add mount command new command for 'lafs' and lafs_mount in library. Doesn't load the root inode yet, just locates it. Signed-off-by: NeilBrown --- diff --git a/include/lafs/lafs.h b/include/lafs/lafs.h index b43a44e..eab5482 100644 --- a/include/lafs/lafs.h +++ b/include/lafs/lafs.h @@ -67,6 +67,7 @@ void lafs_segment_count(struct lafs *fs, loff_t addr, int diff); void lafs_print_device(struct lafs_device *dev); void lafs_print_devblock(struct lafs_dev *dev); +char *lafs_mount(struct lafs *fs, int force); static inline struct lafs_dblk *dblk(struct lafs_blk *b) { diff --git a/lib/lafs_mount.c b/lib/lafs_mount.c new file mode 100644 index 0000000..71c2e24 --- /dev/null +++ b/lib/lafs_mount.c @@ -0,0 +1,112 @@ +#define _GNU_SOURCE +#define _FILE_OFFSET_BITS 64 + +#include +#include +#include +#include +#include +#include "internal.h" + +static int csum_ok(struct lafs_state *st, int size) +{ + u32 crc, crc2; + crc = st->checksum; + st->checksum = 0; + crc2 = crc32(0, (uint32_t*)st, size); + st->checksum = crc; + return crc == crc2; +} + +char *lafs_mount(struct lafs *fs, int force) +{ + char *err = NULL; + struct lafs_device *dv; + struct lafs_state *st; + struct lafs_snapshot **ssp; + int s; + + if (fs->blocksize == 0) + return strdup("mount: no devices loaded"); + + if (fs->loaded_devs != fs->devices) { + asprintf(&err, + "need %d devices, only %d loaded", + fs->devices, fs->loaded_devs); + return err; + } + /* - check that the loaded devices don't overlap. + * - Choose and load a state block + * - fill in data in 'lafs': e..g ss, max_segment, checkpoint_cluster, + * youth + */ + + if (fs->ss.root || fs->ss.root_addr) { + asprintf(&err, "LaFS is already mounted"); + return err; + } + + /* FIXME check seq number is OK. */ + for (dv = fs->devs; dv; dv = dv->next) { + struct lafs_device *dv2; + for (dv2 = dv->next; dv2; dv2= dv->next) { + if (dv->start < dv2->start + dv2->size && + dv->start + dv->size <= dv2->start) + continue; + if (dv2->start < dv->start + dv->size && + dv2->start + dv2->size <= dv->start) + continue; + asprintf(&err, "devices %s and %s overlap", + dv->name, dv2->name); + return err; + } + } + st = malloc(fs->statesize); + for (dv = fs->devs; dv; dv = dv->next) + if (lseek64(dv->fd, dv->stateaddr[dv->recent_state], 0) + == dv->stateaddr[dv->recent_state] + && read(dv->fd, st, fs->statesize) == fs->statesize) + break; + if (!dv) { + asprintf(&err, "Couldn't load a state block from any device"); + free(st); + return err; + } + /* The state block has already been checked by lafs_load, but just + * to be sure... + */ + if (memcmp(st->idtag, "LaFS-State-Block", 16) != 0 || + memcmp(st->uuid, fs->uuid, 16) != 0 || + !csum_ok(st, fs->statesize)) { + asprintf(&err, "state block nolonger looks correct"); + free(st); + return err; + } + /* OK, let-her-rip. */ + fs->seq = __le32_to_cpu(st->seq); +// fs->levels = __le32_to_cpu(st->levels); + fs->checkpoint_cluster = __le64_to_cpu(st->checkpointcluster); + fs->youth_next = __le16_to_cpu(st->nextyouth); + fs->ss.root_addr = __le64_to_cpu(st->root_inodes[0]); + fs->ss.next = NULL; + + ssp = &fs->ss.next; + for (s = 1; s < __le32_to_cpu(st->maxsnapshot); s++) { + struct lafs_snapshot *ss = talloc(fs, struct lafs_snapshot); + ss->next = NULL; + ss->root_addr = __le64_to_cpu(st->root_inodes[s]); + ss->root = NULL; + ss->rootdir = NULL; + *ssp = ss; + ssp = &ss->next; + } + + fs->max_segment = 0; + for (dv = fs->devs ; dv; dv=dv->next) + if (fs->max_segment < dv->segment_size) + fs->max_segment = dv->segment_size; + + fs->checkpointing = 0; + free(st); + return NULL; +} diff --git a/tools/lafs.c b/tools/lafs.c index bb942c9..32e5de7 100644 --- a/tools/lafs.c +++ b/tools/lafs.c @@ -1094,6 +1094,57 @@ static void c_load_dev(struct state *st, void **args) } } +/****** MOUNT ******/ +static char help_mount[] = "Coalesce loaded devices into a filesystem"; +static struct args args_mount[] = { + { "DEVNAME", external, -1, {NULL}, "Device to load and mount"}, + { "-file", external, 0, {NULL}, "File to load and mount"}, + { "-force", flag, -1, {NULL}, "Try to mount even if there are problems"}, + TERMINAL_ARG +}; +static void c_mount(struct state *st, void **args) +{ + char *err; + if (args[1]) { + /* Load the device first, then mount */ + char *devname = args[1]; + long long device_bytes = 0; + int fd; + struct lafs_device *dev; + if (st->lafs->blocksize) { + printf("mount: lafs already initialised - cannot load %s\n", + devname); + return; + } + fd = open_device(devname, &device_bytes, args[2] != NULL, &err); + if (fd < 0) { + printf("mount: %s\n", err); + free(err); + return; + } + dev = lafs_load(fd, device_bytes, &err); + if (err) { + printf("mount: Cannot load %s: %s\n", devname, err); + if (dev) + talloc_free(dev); + close(fd); + return; + } + dev->name = talloc_strdup(dev, devname); + if (lafs_include_dev(st->lafs, dev, &err) != 0) { + printf("mount: Cannot use %s: %s\n", devname, err); + talloc_free(dev); + return; + } + printf("loaded device %s\n", devname); + } + err = lafs_mount(st->lafs, args[3] != NULL); + if (err) { + printf("mount: cannot mount filesystem: %s\n", err); + free(err); + } +} + /****** SHOW *****/ static struct cmd show_cmds[]; @@ -1231,6 +1282,7 @@ static struct cmd lafs_cmds[] = { CMD(exit), CMD(help), CMD(load_dev), + CMD(mount), CMD(newfs), CMD(quit), CMD(reset),