These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / fs / f2fs / recovery.c
index 8d8ea99..cbf74f4 100644 (file)
@@ -83,6 +83,11 @@ static int recover_dentry(struct inode *inode, struct page *ipage)
                goto out;
        }
 
+       if (file_enc_name(inode)) {
+               iput(dir);
+               return 0;
+       }
+
        name.len = le32_to_cpu(raw_inode->i_namelen);
        name.name = raw_inode->i_name;
 
@@ -143,6 +148,7 @@ out:
 static void recover_inode(struct inode *inode, struct page *page)
 {
        struct f2fs_inode *raw = F2FS_INODE(page);
+       char *name;
 
        inode->i_mode = le16_to_cpu(raw->i_mode);
        i_size_write(inode, le64_to_cpu(raw->i_size));
@@ -153,8 +159,13 @@ static void recover_inode(struct inode *inode, struct page *page)
        inode->i_ctime.tv_nsec = le32_to_cpu(raw->i_ctime_nsec);
        inode->i_mtime.tv_nsec = le32_to_cpu(raw->i_mtime_nsec);
 
+       if (file_enc_name(inode))
+               name = "<encrypted>";
+       else
+               name = F2FS_INODE(page)->i_name;
+
        f2fs_msg(inode->i_sb, KERN_NOTICE, "recover_inode: ino = %x, name = %s",
-                       ino_of_node(page), F2FS_INODE(page)->i_name);
+                       ino_of_node(page), name);
 }
 
 static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head)
@@ -169,15 +180,15 @@ static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head)
        curseg = CURSEG_I(sbi, CURSEG_WARM_NODE);
        blkaddr = NEXT_FREE_BLKADDR(sbi, curseg);
 
-       ra_meta_pages(sbi, blkaddr, 1, META_POR);
+       ra_meta_pages(sbi, blkaddr, 1, META_POR, true);
 
        while (1) {
                struct fsync_inode_entry *entry;
 
-               if (blkaddr < MAIN_BLKADDR(sbi) || blkaddr >= MAX_BLKADDR(sbi))
+               if (!is_valid_blkaddr(sbi, blkaddr, META_POR))
                        return 0;
 
-               page = get_meta_page(sbi, blkaddr);
+               page = get_tmp_page(sbi, blkaddr);
 
                if (cp_ver != cpver_of_node(page))
                        break;
@@ -349,7 +360,6 @@ static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode,
        struct f2fs_inode_info *fi = F2FS_I(inode);
        unsigned int start, end;
        struct dnode_of_data dn;
-       struct f2fs_summary sum;
        struct node_info ni;
        int err = 0, recovered = 0;
 
@@ -373,15 +383,11 @@ static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode,
        start = start_bidx_of_node(ofs_of_node(page), fi);
        end = start + ADDRS_PER_PAGE(page, fi);
 
-       f2fs_lock_op(sbi);
-
        set_new_dnode(&dn, inode, NULL, NULL, 0);
 
        err = get_dnode_of_data(&dn, start, ALLOC_NODE);
-       if (err) {
-               f2fs_unlock_op(sbi);
+       if (err)
                goto out;
-       }
 
        f2fs_wait_on_page_writeback(dn.node_page, NODE);
 
@@ -389,14 +395,35 @@ static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode,
        f2fs_bug_on(sbi, ni.ino != ino_of_node(page));
        f2fs_bug_on(sbi, ofs_of_node(dn.node_page) != ofs_of_node(page));
 
-       for (; start < end; start++) {
+       for (; start < end; start++, dn.ofs_in_node++) {
                block_t src, dest;
 
                src = datablock_addr(dn.node_page, dn.ofs_in_node);
                dest = datablock_addr(page, dn.ofs_in_node);
 
-               if (src != dest && dest != NEW_ADDR && dest != NULL_ADDR &&
-                       dest >= MAIN_BLKADDR(sbi) && dest < MAX_BLKADDR(sbi)) {
+               /* skip recovering if dest is the same as src */
+               if (src == dest)
+                       continue;
+
+               /* dest is invalid, just invalidate src block */
+               if (dest == NULL_ADDR) {
+                       truncate_data_blocks_range(&dn, 1);
+                       continue;
+               }
+
+               /*
+                * dest is reserved block, invalidate src block
+                * and then reserve one new block in dnode page.
+                */
+               if (dest == NEW_ADDR) {
+                       truncate_data_blocks_range(&dn, 1);
+                       err = reserve_new_block(&dn);
+                       f2fs_bug_on(sbi, err);
+                       continue;
+               }
+
+               /* dest is valid block, try to recover from src to dest */
+               if (is_valid_blkaddr(sbi, dest, META_POR)) {
 
                        if (src == NULL_ADDR) {
                                err = reserve_new_block(&dn);
@@ -409,16 +436,11 @@ static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode,
                        if (err)
                                goto err;
 
-                       set_summary(&sum, dn.nid, dn.ofs_in_node, ni.version);
-
                        /* write dummy data page */
-                       recover_data_page(sbi, NULL, &sum, src, dest);
-                       dn.data_blkaddr = dest;
-                       set_data_blkaddr(&dn);
-                       f2fs_update_extent_cache(&dn);
+                       f2fs_replace_block(sbi, &dn, src, dest,
+                                                       ni.version, false);
                        recovered++;
                }
-               dn.ofs_in_node++;
        }
 
        if (IS_INODE(dn.node_page))
@@ -430,7 +452,6 @@ static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode,
        set_page_dirty(dn.node_page);
 err:
        f2fs_put_dnode(&dn);
-       f2fs_unlock_op(sbi);
 out:
        f2fs_msg(sbi->sb, KERN_NOTICE,
                "recover_data: ino = %lx, recovered = %d blocks, err = %d",
@@ -454,12 +475,12 @@ static int recover_data(struct f2fs_sb_info *sbi,
        while (1) {
                struct fsync_inode_entry *entry;
 
-               if (blkaddr < MAIN_BLKADDR(sbi) || blkaddr >= MAX_BLKADDR(sbi))
+               if (!is_valid_blkaddr(sbi, blkaddr, META_POR))
                        break;
 
                ra_meta_pages_cond(sbi, blkaddr);
 
-               page = get_meta_page(sbi, blkaddr);
+               page = get_tmp_page(sbi, blkaddr);
 
                if (cp_ver != cpver_of_node(page)) {
                        f2fs_put_page(page, 1);
@@ -519,14 +540,12 @@ int recover_fsync_data(struct f2fs_sb_info *sbi)
 
        INIT_LIST_HEAD(&inode_list);
 
-       /* step #1: find fsynced inode numbers */
-       set_sbi_flag(sbi, SBI_POR_DOING);
-
        /* prevent checkpoint */
        mutex_lock(&sbi->cp_mutex);
 
        blkaddr = NEXT_FREE_BLKADDR(sbi, curseg);
 
+       /* step #1: find fsynced inode numbers */
        err = find_fsync_dnodes(sbi, &inode_list);
        if (err)
                goto out;
@@ -546,7 +565,7 @@ out:
 
        /* truncate meta pages to be used by the recovery */
        truncate_inode_pages_range(META_MAPPING(sbi),
-                       MAIN_BLKADDR(sbi) << PAGE_CACHE_SHIFT, -1);
+                       (loff_t)MAIN_BLKADDR(sbi) << PAGE_CACHE_SHIFT, -1);
 
        if (err) {
                truncate_inode_pages_final(NODE_MAPPING(sbi));
@@ -555,11 +574,20 @@ out:
 
        clear_sbi_flag(sbi, SBI_POR_DOING);
        if (err) {
-               discard_next_dnode(sbi, blkaddr);
+               bool invalidate = false;
+
+               if (discard_next_dnode(sbi, blkaddr))
+                       invalidate = true;
 
                /* Flush all the NAT/SIT pages */
                while (get_pages(sbi, F2FS_DIRTY_META))
                        sync_meta_pages(sbi, META, LONG_MAX);
+
+               /* invalidate temporary meta page */
+               if (invalidate)
+                       invalidate_mapping_pages(META_MAPPING(sbi),
+                                                       blkaddr, blkaddr);
+
                set_ckpt_flags(sbi->ckpt, CP_ERROR_FLAG);
                mutex_unlock(&sbi->cp_mutex);
        } else if (need_writecp) {