]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - fs/nilfs2/dat.c
Merge branch 'master' into csb1725
[mv-sheeva.git] / fs / nilfs2 / dat.c
index 01314675568388635638759dfc4711d56d609b4b..59e5fe742f7bd7bcc6d6aa88dbdcf595e4c64019 100644 (file)
@@ -36,6 +36,7 @@
 struct nilfs_dat_info {
        struct nilfs_mdt_info mi;
        struct nilfs_palloc_cache palloc_cache;
+       struct nilfs_shadow_map shadow;
 };
 
 static inline struct nilfs_dat_info *NILFS_DAT_I(struct inode *dat)
@@ -102,7 +103,8 @@ void nilfs_dat_abort_alloc(struct inode *dat, struct nilfs_palloc_req *req)
        nilfs_palloc_abort_alloc_entry(dat, req);
 }
 
-void nilfs_dat_commit_free(struct inode *dat, struct nilfs_palloc_req *req)
+static void nilfs_dat_commit_free(struct inode *dat,
+                                 struct nilfs_palloc_req *req)
 {
        struct nilfs_dat_entry *entry;
        void *kaddr;
@@ -327,6 +329,23 @@ int nilfs_dat_move(struct inode *dat, __u64 vblocknr, sector_t blocknr)
        ret = nilfs_palloc_get_entry_block(dat, vblocknr, 0, &entry_bh);
        if (ret < 0)
                return ret;
+
+       /*
+        * The given disk block number (blocknr) is not yet written to
+        * the device at this point.
+        *
+        * To prevent nilfs_dat_translate() from returning the
+        * uncommitted block number, this makes a copy of the entry
+        * buffer and redirects nilfs_dat_translate() to the copy.
+        */
+       if (!buffer_nilfs_redirected(entry_bh)) {
+               ret = nilfs_mdt_freeze_buffer(dat, entry_bh);
+               if (ret) {
+                       brelse(entry_bh);
+                       return ret;
+               }
+       }
+
        kaddr = kmap_atomic(entry_bh->b_page, KM_USER0);
        entry = nilfs_palloc_block_get_entry(dat, vblocknr, entry_bh, kaddr);
        if (unlikely(entry->de_blocknr == cpu_to_le64(0))) {
@@ -371,7 +390,7 @@ int nilfs_dat_move(struct inode *dat, __u64 vblocknr, sector_t blocknr)
  */
 int nilfs_dat_translate(struct inode *dat, __u64 vblocknr, sector_t *blocknrp)
 {
-       struct buffer_head *entry_bh;
+       struct buffer_head *entry_bh, *bh;
        struct nilfs_dat_entry *entry;
        sector_t blocknr;
        void *kaddr;
@@ -381,6 +400,15 @@ int nilfs_dat_translate(struct inode *dat, __u64 vblocknr, sector_t *blocknrp)
        if (ret < 0)
                return ret;
 
+       if (!nilfs_doing_gc() && buffer_nilfs_redirected(entry_bh)) {
+               bh = nilfs_mdt_get_frozen_buffer(dat, entry_bh);
+               if (bh) {
+                       WARN_ON(!buffer_uptodate(bh));
+                       brelse(entry_bh);
+                       entry_bh = bh;
+               }
+       }
+
        kaddr = kmap_atomic(entry_bh->b_page, KM_USER0);
        entry = nilfs_palloc_block_get_entry(dat, vblocknr, entry_bh, kaddr);
        blocknr = le64_to_cpu(entry->de_blocknr);
@@ -436,38 +464,48 @@ ssize_t nilfs_dat_get_vinfo(struct inode *dat, void *buf, unsigned visz,
 }
 
 /**
- * nilfs_dat_read - read dat inode
- * @dat: dat inode
- * @raw_inode: on-disk dat inode
- */
-int nilfs_dat_read(struct inode *dat, struct nilfs_inode *raw_inode)
-{
-       return nilfs_read_inode_common(dat, raw_inode);
-}
-
-/**
- * nilfs_dat_new - create dat file
- * @nilfs: nilfs object
+ * nilfs_dat_read - read or get dat inode
+ * @sb: super block instance
  * @entry_size: size of a dat entry
+ * @raw_inode: on-disk dat inode
+ * @inodep: buffer to store the inode
  */
-struct inode *nilfs_dat_new(struct the_nilfs *nilfs, size_t entry_size)
+int nilfs_dat_read(struct super_block *sb, size_t entry_size,
+                  struct nilfs_inode *raw_inode, struct inode **inodep)
 {
        static struct lock_class_key dat_lock_key;
        struct inode *dat;
        struct nilfs_dat_info *di;
        int err;
 
-       dat = nilfs_mdt_new(nilfs, NULL, NILFS_DAT_INO, sizeof(*di));
-       if (dat) {
-               err = nilfs_palloc_init_blockgroup(dat, entry_size);
-               if (unlikely(err)) {
-                       nilfs_mdt_destroy(dat);
-                       return NULL;
-               }
+       dat = nilfs_iget_locked(sb, NULL, NILFS_DAT_INO);
+       if (unlikely(!dat))
+               return -ENOMEM;
+       if (!(dat->i_state & I_NEW))
+               goto out;
 
-               di = NILFS_DAT_I(dat);
-               lockdep_set_class(&di->mi.mi_sem, &dat_lock_key);
-               nilfs_palloc_setup_cache(dat, &di->palloc_cache);
-       }
-       return dat;
+       err = nilfs_mdt_init(dat, NILFS_MDT_GFP, sizeof(*di));
+       if (err)
+               goto failed;
+
+       err = nilfs_palloc_init_blockgroup(dat, entry_size);
+       if (err)
+               goto failed;
+
+       di = NILFS_DAT_I(dat);
+       lockdep_set_class(&di->mi.mi_sem, &dat_lock_key);
+       nilfs_palloc_setup_cache(dat, &di->palloc_cache);
+       nilfs_mdt_setup_shadow_map(dat, &di->shadow);
+
+       err = nilfs_read_inode_common(dat, raw_inode);
+       if (err)
+               goto failed;
+
+       unlock_new_inode(dat);
+ out:
+       *inodep = dat;
+       return 0;
+ failed:
+       iget_failed(dat);
+       return err;
 }