/*
* Mounting a snapshot is very different from mounting a new
* filesystem.
- * The 'dev' passed is really a patch to the mountpoint of the
+ * The 'dev' passed is really a path to the mountpoint of the
* original - or atleast a file within the original.
* We find that filesystem, make sure it is a LaFS, find the
* named snapshot, and mount it read_only
*/
-static int match_one(struct super_block *sb, void *target)
-{
- return sb == target;
-}
-
-static int discard_one(struct super_block *sb, void *data)
-{
- return -ENOENT;
-}
struct options {
char *snapshot;
return 0;
}
+/* s_fs_info for snapshots contains the snapshot number as well */
+struct snap_key {
+ struct sb_key k;
+ int ssnum;
+};
+
+static int snap_test(struct super_block *sb, void *data)
+{
+ struct snap_key *ptn = data;
+ struct snap_key *sk = container_of(sb->s_fs_info, struct snap_key, k);
+ return sk->k.fs == ptn->k.fs && sk->ssnum == ptn->ssnum;
+}
+
+static int snap_set(struct super_block *sb, void *data)
+{
+ struct snap_key *sk = data;
+ sb->s_fs_info = &sk->k;
+ return set_anon_super(sb, NULL);
+}
+
static int
lafs_snap_get_sb(struct file_system_type *fstype,
int flags, const char *dev_name, void *data,
char *cdata = data;
struct nameidata nd;
int err;
- struct super_block *sb, *sb2;
+ struct super_block *sb;
struct fs *fs;
int s;
struct la_inode *lai;
struct page *p;
struct options op;
+ struct snap_key *sk;
err = parse_opts(&op, dev_name, cdata);
if (err)
fs = fs_from_sb(sb);
for (s = 1; s < fs->maxsnapshot; s++) {
- struct datablock *b;
- struct inode *rootdir;
- struct sb_key *k;
if (fs->ss[s].root_addr == 0)
continue;
if (fs->ss[s].root) {
struct lafs_inode *li = LAFSI(fs->ss[s].root);
- if (strcmp(li->md.fs.name, op.snapshot) == 0) {
- /* Already mounted... what to do? FIXME */
- return -EBUSY;
- }
+ if (strcmp(li->md.fs.name, op.snapshot) == 0)
+ /* found it */
+ break;
}
err = lafs_load_page(fs, p, fs->ss[s].root_addr, 1);
if (err)
if (strncmp(lai->metadata[0].fs.name, op.snapshot, 64) != 0)
continue;
/* FIXME more checks? */
-
- /* Ok, we have the right snapshot... now we need a superblock */
- sb = sget(&lafs_snap_fs_type, NULL, set_anon_super, NULL);
- if (IS_ERR(sb))
- return PTR_ERR(sb);
+ /* Found it */
+ break;
+ }
+ if (s == fs->maxsnapshot) {
+ err = -ENOENT;
+ goto fail;
+ }
+ /* Ok, we have the right snapshot... now we need a superblock */
+ sk = kzalloc(sizeof(*sk), GFP_KERNEL);
+ if (!sk) {
+ err = -ENOMEM;
+ goto fail;
+ }
+ /* FIXME Inc refcount here?? */
+ sk->k.fs = fs;
+ sk->ssnum = s;
+
+ sb = sget(&lafs_snap_fs_type, snap_test, snap_set, NULL);
+ if (IS_ERR(sb)) {
+ kfree(sk);
+ err = PTR_ERR(sb);
+ goto fail;
+ }
+ if (sb->s_root) {
+ /* already existed */
+ kfree(sk);
+ } else {
+ struct inode *rootdir;
+ struct datablock *b;
sb->s_flags = flags | MS_RDONLY;
- fs->ss[s].root = iget_locked(sb, 1);
- k = kmalloc(sizeof(*k), GFP_KERNEL);
- /* FIXME Inc refcount here?? */
- k->fs = fs;
- k->root = fs->ss[s].root;
- sb->s_fs_info = k;
+
+ fs->ss[s].root = sk->k.root = iget_locked(sb, 0);
b = lafs_get_block(fs->ss[s].root, 0, NULL, GFP_KERNEL,
MKREF(snap));
b->b.physaddr = fs->ss[s].root_addr;
if (!err)
err = lafs_import_inode(fs->ss[s].root, b);
putdref(b, MKREF(snap));
+ unlock_new_inode(fs->ss[s].root);
if (err) {
- /* FIXME what to do with a locked inode? */
- deactivate_super(sb);
+ deactivate_locked_super(sb);
goto fail;
}
- unlock_new_inode(fs->ss[s].root);
rootdir = lafs_iget(sb, 2, SYNC);
sb->s_root = d_alloc_root(rootdir);
sb->s_op = fs->prime_sb->s_op;
- sb2 = sget(&lafs_fs_type, match_one, discard_one, fs->prime_sb);
- if (sb2 != fs->prime_sb) {
- /* must be racing with umount */
- deactivate_super(sb2);
- deactivate_super(sb);
- err = -EBUSY;
- goto fail;
- }
- up_write(&fs->prime_sb->s_umount);
- path_put(&nd.path);
- put_page(p);
- simple_set_mnt(mnt, sb);
- return 0;
+ sb->s_flags |= MS_ACTIVE;
}
- err = -ENOENT;
+ up_write(&sb->s_umount);
+ path_put(&nd.path);
+ put_page(p);
+ simple_set_mnt(mnt, sb);
+ return 0;
fail:
put_page(p);
struct fs *fs = fs_from_sb(sb);
printk("Generic_shutdown_super being called....\n");
- generic_shutdown_super(sb);
+ kill_anon_super(sb);
kfree(sb->s_fs_info);
printk("Generic_shutdown_super called\n");
- deactivate_super(fs->prime_sb);
}
struct file_system_type lafs_snap_fs_type = {