]> git.neil.brown.name Git - LaFS.git/commitdiff
Improve choice of superblock at mount.
authorNeilBrown <neilb@suse.de>
Sun, 25 Jul 2010 07:05:55 +0000 (17:05 +1000)
committerNeilBrown <neilb@suse.de>
Mon, 9 Aug 2010 01:58:12 +0000 (11:58 +1000)
Identify superblock by uuid, and ensure that it is unique
when mounting a new LaFS.

Signed-off-by: NeilBrown <neilb@suse.de>
roll.c
super.c

diff --git a/roll.c b/roll.c
index fbdf2fe120fb8ec97a99869e1c1f62d09345c806..e6f605b43bcfeac4ff6ed6f3c186740b25968421 100644 (file)
--- a/roll.c
+++ b/roll.c
@@ -552,13 +552,11 @@ lafs_mount(struct fs *fs)
        struct dentry *de;
        int err;
        int d;
-       struct sb_key *k = kmalloc(sizeof(*k), GFP_KERNEL);
+       struct sb_key *k = fs->prime_sb->s_fs_info;
 
        fs->rolled = 0;
        fs->ss[0].root = root = iget_locked(fs->prime_sb, 0);
        k->root = root;
-       k->fs = fs;
-       fs->prime_sb->s_fs_info = k;
 
        err = -ENOMEM;
        b = lafs_get_block(root, 0, NULL, GFP_KERNEL, MKREF(mount));
diff --git a/super.c b/super.c
index 1bdd737dee1f057031eb7ec2624654caab31aa73..7fb56e5747ff96212a2615368ff9d46fdca2431d 100644 (file)
--- a/super.c
+++ b/super.c
@@ -464,6 +464,26 @@ check_devs(struct options *op)
        return newstate;
 }
 
+/* we identify lafs superblocks by the filesystem uuid.  This means
+ * that block-level snapshots cannot be mounted.  You should use
+ * fs-level snapshots instead.
+ */
+static int sb_test(struct super_block *sb, void *data)
+{
+       struct sb_key *ptn = data;
+       struct sb_key *sk = sb->s_fs_info;
+       return memcmp(ptn->fs->state->uuid,
+                     sk->fs->state->uuid, 16) == 0;
+}
+
+static int sb_set(struct super_block *sb, void *data)
+{
+       struct sb_key *ptn = data;
+       sb->s_fs_info = ptn;
+       return set_anon_super(sb, NULL);
+}
+
+
 static int
 lafs_load(struct fs *fs, struct options *op, int newest)
 {
@@ -475,6 +495,7 @@ lafs_load(struct fs *fs, struct options *op, int newest)
        struct lafs_state *st;
        int i;
        int err;
+       struct sb_key *k;
 
        st = fs->state = op->devlist[newest].stateblock;
        op->devlist[newest].stateblock = NULL;
@@ -504,8 +525,11 @@ lafs_load(struct fs *fs, struct options *op, int newest)
        err = lafs_segtrack_init(fs->segtrack);
 
        fs->ss = kzalloc(sizeof(struct snapshot)*fs->maxsnapshot, GFP_KERNEL);
-       if (!fs->ss || !fs->scan.free_usages || err)
+       if (!fs->ss || !fs->scan.free_usages || err) {
+               if (!err)
+                       err = -ENOMEM;
                goto abort;
+       }
 
        fs->checkpointcluster = le64_to_cpu(st->checkpointcluster);
        for (i = 0; i < fs->maxsnapshot; i++) {
@@ -548,13 +572,27 @@ lafs_load(struct fs *fs, struct options *op, int newest)
                                   * guessed better
                                   */
 
+       err = -ENOMEM;
        fs->devs = kzalloc(sizeof(struct fs_dev)*fs->devices, GFP_KERNEL);
        if (!fs->devs)
                goto abort;
 
-       fs->prime_sb = sget(&lafs_fs_type, NULL, set_anon_super, NULL);
-       if (!fs->prime_sb)
+       k = kzalloc(sizeof(*k), GFP_KERNEL);
+       k->fs = fs;
+       fs->prime_sb = sget(&lafs_fs_type, sb_test, sb_set, k);
+       if (IS_ERR(fs->prime_sb)) {
+               kfree(k);
+               err = PTR_ERR(fs->prime_sb);
                goto abort;
+       }
+       if (fs->prime_sb->s_root) {
+               /* filesystem with this uuid already exists */
+               kfree(k);
+               deactivate_locked_super(fs->prime_sb);
+               fs->prime_sb = NULL;
+               err = -EBUSY;
+               goto abort;
+       }
        fs->prime_sb->s_blocksize = 1 << op->blockbits;
        fs->prime_sb->s_blocksize_bits = op->blockbits;
        fs->prime_sb->s_op = &lafs_sops;