nilfs_cpfile_get_blkoff(cpfile, cno));
 }
 
+/**
+ * nilfs_cpfile_read_checkpoint - read a checkpoint entry in cpfile
+ * @cpfile: checkpoint file inode
+ * @cno:    number of checkpoint entry to read
+ * @root:   nilfs root object
+ * @ifile:  ifile's inode to read and attach to @root
+ *
+ * This function imports checkpoint information from the checkpoint file and
+ * stores it to the inode file given by @ifile and the nilfs root object
+ * given by @root.
+ *
+ * Return: 0 on success, or the following negative error code on failure.
+ * * %-EINVAL  - Invalid checkpoint.
+ * * %-ENOMEM  - Insufficient memory available.
+ * * %-EIO     - I/O error (including metadata corruption).
+ */
+int nilfs_cpfile_read_checkpoint(struct inode *cpfile, __u64 cno,
+                                struct nilfs_root *root, struct inode *ifile)
+{
+       struct buffer_head *cp_bh;
+       struct nilfs_checkpoint *cp;
+       void *kaddr;
+       int ret;
+
+       if (cno < 1 || cno > nilfs_mdt_cno(cpfile))
+               return -EINVAL;
+
+       down_read(&NILFS_MDT(cpfile)->mi_sem);
+       ret = nilfs_cpfile_get_checkpoint_block(cpfile, cno, 0, &cp_bh);
+       if (unlikely(ret < 0)) {
+               if (ret == -ENOENT)
+                       ret = -EINVAL;
+               goto out_sem;
+       }
+
+       kaddr = kmap_local_page(cp_bh->b_page);
+       cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, cp_bh, kaddr);
+       if (nilfs_checkpoint_invalid(cp)) {
+               ret = -EINVAL;
+               goto put_cp;
+       }
+
+       ret = nilfs_read_inode_common(ifile, &cp->cp_ifile_inode);
+       if (unlikely(ret)) {
+               /*
+                * Since this inode is on a checkpoint entry, treat errors
+                * as metadata corruption.
+                */
+               nilfs_err(cpfile->i_sb,
+                         "ifile inode (checkpoint number=%llu) corrupted",
+                         (unsigned long long)cno);
+               ret = -EIO;
+               goto put_cp;
+       }
+
+       /* Configure the nilfs root object */
+       atomic64_set(&root->inodes_count, le64_to_cpu(cp->cp_inodes_count));
+       atomic64_set(&root->blocks_count, le64_to_cpu(cp->cp_blocks_count));
+       root->ifile = ifile;
+
+put_cp:
+       kunmap_local(kaddr);
+       brelse(cp_bh);
+out_sem:
+       up_read(&NILFS_MDT(cpfile)->mi_sem);
+       return ret;
+}
+
 /**
  * nilfs_cpfile_get_checkpoint - get a checkpoint
  * @cpfile: inode of checkpoint file
 
 int nilfs_cpfile_get_checkpoint(struct inode *, __u64, int,
                                struct nilfs_checkpoint **,
                                struct buffer_head **);
+int nilfs_cpfile_read_checkpoint(struct inode *cpfile, __u64 cno,
+                                struct nilfs_root *root, struct inode *ifile);
 int nilfs_cpfile_create_checkpoint(struct inode *cpfile, __u64 cno);
 void nilfs_cpfile_put_checkpoint(struct inode *, __u64, struct buffer_head *);
 int nilfs_cpfile_finalize_checkpoint(struct inode *cpfile, __u64 cno,
 
 #include "mdt.h"
 #include "alloc.h"
 #include "ifile.h"
+#include "cpfile.h"
 
 /**
  * struct nilfs_ifile_info - on-memory private data of ifile
  * nilfs_ifile_read - read or get ifile inode
  * @sb: super block instance
  * @root: root object
+ * @cno: number of checkpoint entry to read
  * @inode_size: size of an inode
- * @raw_inode: on-disk ifile inode
- * @inodep: buffer to store the inode
+ *
+ * Return: 0 on success, or the following negative error code on failure.
+ * * %-EINVAL  - Invalid checkpoint.
+ * * %-ENOMEM  - Insufficient memory available.
+ * * %-EIO     - I/O error (including metadata corruption).
  */
 int nilfs_ifile_read(struct super_block *sb, struct nilfs_root *root,
-                    size_t inode_size, struct nilfs_inode *raw_inode,
-                    struct inode **inodep)
+                    __u64 cno, size_t inode_size)
 {
+       struct the_nilfs *nilfs;
        struct inode *ifile;
        int err;
 
 
        nilfs_palloc_setup_cache(ifile, &NILFS_IFILE_I(ifile)->palloc_cache);
 
-       err = nilfs_read_inode_common(ifile, raw_inode);
+       nilfs = sb->s_fs_info;
+       err = nilfs_cpfile_read_checkpoint(nilfs->ns_cpfile, cno, root, ifile);
        if (err)
                goto failed;
 
        unlock_new_inode(ifile);
  out:
-       *inodep = ifile;
        return 0;
  failed:
        iget_failed(ifile);
 
 int nilfs_ifile_count_free_inodes(struct inode *, u64 *, u64 *);
 
 int nilfs_ifile_read(struct super_block *sb, struct nilfs_root *root,
-                    size_t inode_size, struct nilfs_inode *raw_inode,
-                    struct inode **inodep);
+                    __u64 cno, size_t inode_size);
 
 #endif /* _NILFS_IFILE_H */
 
 {
        struct the_nilfs *nilfs = sb->s_fs_info;
        struct nilfs_root *root;
-       struct nilfs_checkpoint *raw_cp;
-       struct buffer_head *bh_cp;
        int err = -ENOMEM;
 
        root = nilfs_find_or_create_root(
                goto reuse; /* already attached checkpoint */
 
        down_read(&nilfs->ns_segctor_sem);
-       err = nilfs_cpfile_get_checkpoint(nilfs->ns_cpfile, cno, 0, &raw_cp,
-                                         &bh_cp);
+       err = nilfs_ifile_read(sb, root, cno, nilfs->ns_inode_size);
        up_read(&nilfs->ns_segctor_sem);
-       if (unlikely(err)) {
-               if (err == -ENOENT || err == -EINVAL) {
-                       nilfs_err(sb,
-                                 "Invalid checkpoint (checkpoint number=%llu)",
-                                 (unsigned long long)cno);
-                       err = -EINVAL;
-               }
+       if (unlikely(err))
                goto failed;
-       }
-
-       err = nilfs_ifile_read(sb, root, nilfs->ns_inode_size,
-                              &raw_cp->cp_ifile_inode, &root->ifile);
-       if (err)
-               goto failed_bh;
-
-       atomic64_set(&root->inodes_count,
-                       le64_to_cpu(raw_cp->cp_inodes_count));
-       atomic64_set(&root->blocks_count,
-                       le64_to_cpu(raw_cp->cp_blocks_count));
-
-       nilfs_cpfile_put_checkpoint(nilfs->ns_cpfile, cno, bh_cp);
 
  reuse:
        *rootp = root;
        return 0;
 
- failed_bh:
-       nilfs_cpfile_put_checkpoint(nilfs->ns_cpfile, cno, bh_cp);
  failed:
+       if (err == -EINVAL)
+               nilfs_err(sb, "Invalid checkpoint (checkpoint number=%llu)",
+                         (unsigned long long)cno);
        nilfs_put_root(root);
 
        return err;