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",
.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;
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;
}
{
unregister_filesystem(&lafs_fs_type);
unregister_filesystem(&lafs_snap_fs_type);
+ unregister_filesystem(&lafs_subset_fs_type);
lafs_ihash_free();
}