]> git.neil.brown.name Git - LaFS.git/commitdiff
Define filesystem type for sub-fileset filesystems
authorNeil Brown <neilb@nbeee.brown>
Mon, 19 Jul 2010 08:07:27 +0000 (18:07 +1000)
committerNeilBrown <neilb@suse.de>
Mon, 9 Aug 2010 01:58:12 +0000 (11:58 +1000)
This also allows a sub-fileset to be created by
mounting an empty perm==0 directory as though it were
a sub-fileset already.

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

diff --git a/state.h b/state.h
index f0099aa4cf5366432885a21658460645c781262a..66e903e83800af440e7eb2b9597c0351a47aedaa 100644 (file)
--- a/state.h
+++ b/state.h
@@ -551,13 +551,16 @@ struct lafs_inode {
        loff_t          trunc_next; /* next block to truncate from */
        union {
                struct fs_md {
-                       int     usagetable;
+                       int     usagetable;   /* 0 and unused for subsets,
+                                              * 1 for main fs, >1 for snapshots
+                                              */
                        u64     update_time;
                        u64     cblocks_used; /* blocks commited */
                        u64     pblocks_used; /* extra blocks in next phase */
                        u64     ablocks_used; /* extra blocks allocated */
                        u64     blocks_allowed;
-                       u64     blocks_unalloc;
+                       u64     blocks_unalloc; /* FIXME what is this for ?? */
+
                        u64     creation_age;
                        u32     inodes_used;
                        u32     quota_inums[3];
diff --git a/super.c b/super.c
index 7fb56e5747ff96212a2615368ff9d46fdca2431d..e5036c6430e08468147ae6f4280cd041dadb3966 100644 (file)
--- a/super.c
+++ b/super.c
@@ -912,6 +912,150 @@ out:
        return err;
 }
 
+static int test_subset(struct super_block *sb, void *data)
+{
+       struct sb_key *ptn = data;
+       struct sb_key *k = sb->s_fs_info;
+
+       return ptn->fs == k->fs && ptn->root == k->root;
+}
+
+static int set_subset(struct super_block *sb, void *data)
+{
+       sb->s_fs_info = data;
+       return 0;
+}
+
+static int
+lafs_get_subset(struct file_system_type *fs_type,
+               int flags, const char *dev_name, void *data,
+               struct vfsmount *mnt)
+{
+       /* mount, possibly creating, a sub-fileset.
+        * dev_name must be an absolute path that leads
+        * to an object in a lafs file-system (or snapshot).
+        * The object must be either an InodeFile or
+        * an empty directory in the main file-system
+        * with mode 0 (though that rule might change).
+        * In the latter case we change the object to an
+        * InodeFile
+        * FIXME must require readonly for snapshots, and readwrite
+        * to create.
+        */
+
+       struct nameidata nd;
+       int err;
+       struct super_block *sb;
+       struct inode *ino;
+       struct fs *fs;
+       struct sb_key *k;
+
+       err = path_lookup(dev_name, LOOKUP_FOLLOW, &nd);
+       if (err)
+               goto out_noput;
+       sb = nd.path.dentry->d_sb;
+       err = -EINVAL;
+       if (sb->s_type != &lafs_fs_type &&
+           sb->s_type != &lafs_snap_fs_type)
+               goto out;
+       ino = nd.path.dentry->d_inode;
+       if (LAFSI(ino)->type != TypeInodeFile &&
+           LAFSI(ino)->type != TypeDir)
+               goto out;
+       fs = fs_from_sb(sb);
+       if (LAFSI(ino)->type == TypeDir) {
+               struct datablock *inodb;
+               /* maybe convert this to TypeInodeFile */
+               if (sb->s_type != &lafs_fs_type)
+                       goto out;
+               mutex_lock(&ino->i_mutex);
+               if (ino->i_size)
+                       /* FIXME maybe I should run orphans */
+                       goto out_unlock;
+               if ((ino->i_mode & 07777) != 0)
+                       goto out_unlock;
+               inodb = lafs_inode_dblock(ino, SYNC, MKREF(make_subset));
+               err = PTR_ERR(inodb);
+               if (IS_ERR(inodb))
+                       goto out_unlock;
+               lafs_iolock_block(&inodb->b);
+               set_bit(B_PinPending, &inodb->b.flags);
+               lafs_iounlock_block(&inodb->b);
+               lafs_checkpoint_lock(fs);
+               err = lafs_pin_dblock(inodb, ReleaseSpace);
+               if (!err) {
+                       struct fs_md *md;
+                       /* OK, we are good to go making this filesystem */
+                       LAFSI(ino)->type = TypeDir;
+                       md = &LAFSI(ino)->md.fs;
+                       md->usagetable = 0;
+                       md->update_time = CURRENT_TIME.tv_sec;
+                       md->cblocks_used = 0;
+                       md->pblocks_used = 0;
+                       md->ablocks_used = 0;
+                       md->blocks_allowed = 10000; /* FIXME */
+                       md->blocks_unalloc = 0;
+                       md->creation_age = fs->youth_next;
+                       md->inodes_used = 0;
+                       md->quota_inums[0] = 0;
+                       md->quota_inums[1] = 0;
+                       md->quota_inums[2] = 0;
+                       md->quota_inodes[0] = NULL;
+                       md->quota_inodes[1] = NULL;
+                       md->quota_inodes[2] = NULL;
+                       md->name[0] = '\0';
+                       lafs_dirty_inode(ino);
+                       /* We use a checkpoint to commit this change,
+                        * it is too unusual to bother logging
+                        */
+                       lafs_checkpoint_start(fs);
+                       lafs_checkpoint_unlock_wait(fs);
+               } else {
+                       lafs_checkpoint_unlock(fs);
+               }
+               putdref(inodb, MKREF(make_subset));
+               if (err)
+                       goto out_unlock;
+       }
+       /* We have a TypeInodeFile so we can make a superblock */
+       k = kmalloc(sizeof(*k), GFP_KERNEL);
+       k->fs = fs;
+       k->root = ino;
+       sb = sget(fs_type, test_subset, set_subset, k);
+       if (IS_ERR(sb)) {
+               kfree(k);
+               err = PTR_ERR(sb);
+       } else if (sb->s_root) {
+               /* already allocated */
+               kfree(k);
+       } else {
+               struct inode *rootdir;
+               err = 0;
+               sb->s_blocksize = fs->blocksize;
+               sb->s_blocksize_bits = fs->blocksize_bits;
+               sb->s_op = &lafs_sops;
+               sb->s_export_op = &lafs_export_ops;
+               sb->s_time_gran = 2;
+               rootdir = lafs_iget(sb, 2, SYNC);
+               sb->s_root = d_alloc_root(rootdir);
+               sb->s_op = fs->prime_sb->s_op;
+               sb->s_flags |= MS_ACTIVE;
+       }
+       if (!err)
+               simple_set_mnt(mnt, sb);
+out_unlock:
+       mutex_unlock(&ino->i_mutex);
+out:
+       path_put(&nd.path);
+out_noput:
+       return err;
+}
+
+static void lafs_kill_subset(struct super_block *sb)
+{
+       kill_anon_super(sb);
+}
+
 struct file_system_type lafs_fs_type = {
        .owner          = THIS_MODULE,
        .name           = "lafs",
@@ -920,6 +1064,13 @@ struct file_system_type lafs_fs_type = {
        .fs_flags       = FS_REQUIRES_DEV,
 };
 
+struct file_system_type lafs_subset_fs_type = {
+       .owner          = THIS_MODULE,
+       .name           = "lafs_subset",
+       .get_sb         = lafs_get_subset,
+       .kill_sb        = lafs_kill_subset,
+};
+
 static int __init lafs_init(void)
 {
        int err;
@@ -927,19 +1078,17 @@ static int __init lafs_init(void)
        BUILD_BUG_ON(B_NUM_FLAGS > 32);
 
        err = lafs_ihash_init();
+       err = err ?: register_filesystem(&lafs_fs_type);
+       err = err ?: register_filesystem(&lafs_snap_fs_type);
+       err = err ?: register_filesystem(&lafs_subset_fs_type);
        if (err)
                goto out;
-       err = register_filesystem(&lafs_fs_type);
-       if (err)
-               goto out;
-       err = register_filesystem(&lafs_snap_fs_type);
-       if (err) {
-               unregister_filesystem(&lafs_fs_type);
-               goto out;
-       }
        return 0;
 
 out:
+       unregister_filesystem(&lafs_fs_type);
+       unregister_filesystem(&lafs_snap_fs_type);
+       unregister_filesystem(&lafs_subset_fs_type);
        lafs_ihash_free();
        return err;
 }
@@ -948,6 +1097,7 @@ static void __exit lafs_exit(void)
 {
        unregister_filesystem(&lafs_fs_type);
        unregister_filesystem(&lafs_snap_fs_type);
+       unregister_filesystem(&lafs_subset_fs_type);
        lafs_ihash_free();
 }