nilfs2: make snapshots in checkpoint tree exportable
[pandora-kernel.git] / fs / nilfs2 / super.c
index 9f4913f..adbf582 100644 (file)
 #include <linux/vfs.h>
 #include <linux/writeback.h>
 #include <linux/kobject.h>
-#include <linux/exportfs.h>
 #include <linux/seq_file.h>
 #include <linux/mount.h>
 #include "nilfs.h"
+#include "export.h"
 #include "mdt.h"
 #include "alloc.h"
 #include "btree.h"
@@ -155,6 +155,7 @@ struct inode *nilfs_alloc_inode_common(struct the_nilfs *nilfs)
                return NULL;
        ii->i_bh = NULL;
        ii->i_state = 0;
+       ii->i_cno = 0;
        ii->vfs_inode.i_version = 1;
        nilfs_btnode_cache_init(&ii->i_btnode_cache, nilfs->ns_bdi);
        return &ii->vfs_inode;
@@ -167,6 +168,12 @@ struct inode *nilfs_alloc_inode(struct super_block *sb)
 
 void nilfs_destroy_inode(struct inode *inode)
 {
+       struct nilfs_mdt_info *mdi = NILFS_MDT(inode);
+
+       if (mdi) {
+               kfree(mdi->mi_bgl); /* kfree(NULL) is safe */
+               kfree(mdi);
+       }
        kmem_cache_free(nilfs_inode_cachep, NILFS_I(inode));
 }
 
@@ -384,18 +391,24 @@ static int nilfs_sync_fs(struct super_block *sb, int wait)
        return err;
 }
 
-int nilfs_attach_checkpoint(struct nilfs_sb_info *sbi, __u64 cno)
+int nilfs_attach_checkpoint(struct nilfs_sb_info *sbi, __u64 cno, int curr_mnt,
+                           struct nilfs_root **rootp)
 {
        struct the_nilfs *nilfs = sbi->s_nilfs;
+       struct nilfs_root *root;
        struct nilfs_checkpoint *raw_cp;
        struct buffer_head *bh_cp;
-       int err;
+       int err = -ENOMEM;
+
+       root = nilfs_find_or_create_root(
+               nilfs, curr_mnt ? NILFS_CPTREE_CURRENT_CNO : cno);
+       if (!root)
+               return err;
 
        down_write(&nilfs->ns_super_sem);
        list_add(&sbi->s_list, &nilfs->ns_supers);
        up_write(&nilfs->ns_super_sem);
 
-       err = -ENOMEM;
        sbi->s_ifile = nilfs_ifile_new(sbi, nilfs->ns_inode_size);
        if (!sbi->s_ifile)
                goto delist;
@@ -421,6 +434,8 @@ int nilfs_attach_checkpoint(struct nilfs_sb_info *sbi, __u64 cno)
        atomic_set(&sbi->s_blocks_count, le64_to_cpu(raw_cp->cp_blocks_count));
 
        nilfs_cpfile_put_checkpoint(nilfs->ns_cpfile, cno, bh_cp);
+
+       *rootp = root;
        return 0;
 
  failed_bh:
@@ -433,6 +448,7 @@ int nilfs_attach_checkpoint(struct nilfs_sb_info *sbi, __u64 cno)
        down_write(&nilfs->ns_super_sem);
        list_del_init(&sbi->s_list);
        up_write(&nilfs->ns_super_sem);
+       nilfs_put_root(root);
 
        return err;
 }
@@ -540,48 +556,6 @@ static const struct super_operations nilfs_sops = {
        .show_options = nilfs_show_options
 };
 
-static struct inode *
-nilfs_nfs_get_inode(struct super_block *sb, u64 ino, u32 generation)
-{
-       struct inode *inode;
-
-       if (ino < NILFS_FIRST_INO(sb) && ino != NILFS_ROOT_INO &&
-           ino != NILFS_SKETCH_INO)
-               return ERR_PTR(-ESTALE);
-
-       inode = nilfs_iget(sb, ino);
-       if (IS_ERR(inode))
-               return ERR_CAST(inode);
-       if (generation && inode->i_generation != generation) {
-               iput(inode);
-               return ERR_PTR(-ESTALE);
-       }
-
-       return inode;
-}
-
-static struct dentry *
-nilfs_fh_to_dentry(struct super_block *sb, struct fid *fid, int fh_len,
-                  int fh_type)
-{
-       return generic_fh_to_dentry(sb, fid, fh_len, fh_type,
-                                   nilfs_nfs_get_inode);
-}
-
-static struct dentry *
-nilfs_fh_to_parent(struct super_block *sb, struct fid *fid, int fh_len,
-                  int fh_type)
-{
-       return generic_fh_to_parent(sb, fid, fh_len, fh_type,
-                                   nilfs_nfs_get_inode);
-}
-
-static const struct export_operations nilfs_export_ops = {
-       .fh_to_dentry = nilfs_fh_to_dentry,
-       .fh_to_parent = nilfs_fh_to_parent,
-       .get_parent = nilfs_get_parent,
-};
-
 enum {
        Opt_err_cont, Opt_err_panic, Opt_err_ro,
        Opt_barrier, Opt_nobarrier, Opt_snapshot, Opt_order, Opt_norecovery,
@@ -808,9 +782,10 @@ nilfs_fill_super(struct super_block *sb, void *data, int silent,
                 struct the_nilfs *nilfs)
 {
        struct nilfs_sb_info *sbi;
+       struct nilfs_root *fsroot;
        struct inode *root;
        __u64 cno;
-       int err;
+       int err, curr_mnt;
 
        sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
        if (!sbi)
@@ -852,6 +827,7 @@ nilfs_fill_super(struct super_block *sb, void *data, int silent,
                goto failed_sbi;
 
        cno = nilfs_last_cno(nilfs);
+       curr_mnt = true;
 
        if (sb->s_flags & MS_RDONLY) {
                if (nilfs_test_opt(sbi, SNAPSHOT)) {
@@ -874,10 +850,11 @@ nilfs_fill_super(struct super_block *sb, void *data, int silent,
                                goto failed_sbi;
                        }
                        cno = sbi->s_snapshot_cno;
+                       curr_mnt = false;
                }
        }
 
-       err = nilfs_attach_checkpoint(sbi, cno);
+       err = nilfs_attach_checkpoint(sbi, cno, curr_mnt, &fsroot);
        if (err) {
                printk(KERN_ERR "NILFS: error loading a checkpoint"
                       " (checkpoint number=%llu).\n", (unsigned long long)cno);
@@ -890,7 +867,7 @@ nilfs_fill_super(struct super_block *sb, void *data, int silent,
                        goto failed_checkpoint;
        }
 
-       root = nilfs_iget(sb, NILFS_ROOT_INO);
+       root = nilfs_iget(sb, fsroot, NILFS_ROOT_INO);
        if (IS_ERR(root)) {
                printk(KERN_ERR "NILFS: get root inode failed\n");
                err = PTR_ERR(root);
@@ -910,6 +887,8 @@ nilfs_fill_super(struct super_block *sb, void *data, int silent,
                goto failed_segctor;
        }
 
+       nilfs_put_root(fsroot);
+
        if (!(sb->s_flags & MS_RDONLY)) {
                down_write(&nilfs->ns_sem);
                nilfs_setup_super(sbi);
@@ -928,6 +907,7 @@ nilfs_fill_super(struct super_block *sb, void *data, int silent,
 
  failed_checkpoint:
        nilfs_detach_checkpoint(sbi);
+       nilfs_put_root(fsroot);
 
  failed_sbi:
        put_nilfs(nilfs);