Merge branch 'work.const-qstr' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
[cascardo/linux.git] / fs / f2fs / dir.c
index 3b095a3..9054aea 100644 (file)
@@ -185,8 +185,13 @@ static struct f2fs_dir_entry *find_in_level(struct inode *dir,
                /* no need to allocate new dentry pages to all the indices */
                dentry_page = find_data_page(dir, bidx);
                if (IS_ERR(dentry_page)) {
-                       room = true;
-                       continue;
+                       if (PTR_ERR(dentry_page) == -ENOENT) {
+                               room = true;
+                               continue;
+                       } else {
+                               *res_page = dentry_page;
+                               break;
+                       }
                }
 
                de = find_in_block(dentry_page, fname, namehash, &max_slots,
@@ -223,19 +228,22 @@ struct f2fs_dir_entry *f2fs_find_entry(struct inode *dir,
        struct fscrypt_name fname;
        int err;
 
-       *res_page = NULL;
-
        err = fscrypt_setup_filename(dir, child, 1, &fname);
-       if (err)
+       if (err) {
+               *res_page = ERR_PTR(err);
                return NULL;
+       }
 
        if (f2fs_has_inline_dentry(dir)) {
+               *res_page = NULL;
                de = find_in_inline_dir(dir, &fname, res_page);
                goto out;
        }
 
-       if (npages == 0)
+       if (npages == 0) {
+               *res_page = NULL;
                goto out;
+       }
 
        max_depth = F2FS_I(dir)->i_current_depth;
        if (unlikely(max_depth > MAX_DIR_HASH_DEPTH)) {
@@ -243,13 +251,13 @@ struct f2fs_dir_entry *f2fs_find_entry(struct inode *dir,
                                "Corrupted max_depth of %lu: %u",
                                dir->i_ino, max_depth);
                max_depth = MAX_DIR_HASH_DEPTH;
-               F2FS_I(dir)->i_current_depth = max_depth;
-               mark_inode_dirty(dir);
+               f2fs_i_depth_write(dir, max_depth);
        }
 
        for (level = 0; level < max_depth; level++) {
+               *res_page = NULL;
                de = find_in_level(dir, level, &fname, res_page);
-               if (de)
+               if (de || IS_ERR(*res_page))
                        break;
        }
 out:
@@ -259,35 +267,22 @@ out:
 
 struct f2fs_dir_entry *f2fs_parent_dir(struct inode *dir, struct page **p)
 {
-       struct page *page;
-       struct f2fs_dir_entry *de;
-       struct f2fs_dentry_block *dentry_blk;
-
-       if (f2fs_has_inline_dentry(dir))
-               return f2fs_parent_inline_dir(dir, p);
-
-       page = get_lock_data_page(dir, 0, false);
-       if (IS_ERR(page))
-               return NULL;
+       struct qstr dotdot = QSTR_INIT("..", 2);
 
-       dentry_blk = kmap(page);
-       de = &dentry_blk->dentry[1];
-       *p = page;
-       unlock_page(page);
-       return de;
+       return f2fs_find_entry(dir, &dotdot, p);
 }
 
-ino_t f2fs_inode_by_name(struct inode *dir, const struct qstr *qstr)
+ino_t f2fs_inode_by_name(struct inode *dir, const struct qstr *qstr,
+                                                       struct page **page)
 {
        ino_t res = 0;
        struct f2fs_dir_entry *de;
-       struct page *page;
 
-       de = f2fs_find_entry(dir, qstr, &page);
+       de = f2fs_find_entry(dir, qstr, page);
        if (de) {
                res = le32_to_cpu(de->ino);
-               f2fs_dentry_kunmap(dir, page);
-               f2fs_put_page(page, 0);
+               f2fs_dentry_kunmap(dir, *page);
+               f2fs_put_page(*page, 0);
        }
 
        return res;
@@ -303,9 +298,9 @@ void f2fs_set_link(struct inode *dir, struct f2fs_dir_entry *de,
        set_de_type(de, inode->i_mode);
        f2fs_dentry_kunmap(dir, page);
        set_page_dirty(page);
-       dir->i_mtime = dir->i_ctime = CURRENT_TIME;
-       mark_inode_dirty(dir);
 
+       dir->i_mtime = dir->i_ctime = CURRENT_TIME;
+       f2fs_mark_inode_dirty_sync(dir);
        f2fs_put_page(page, 1);
 }
 
@@ -385,7 +380,7 @@ struct page *init_inode_metadata(struct inode *inode, struct inode *dir,
        struct page *page;
        int err;
 
-       if (is_inode_flag_set(F2FS_I(inode), FI_NEW_INODE)) {
+       if (is_inode_flag_set(inode, FI_NEW_INODE)) {
                page = new_inode_page(inode);
                if (IS_ERR(page))
                        return page;
@@ -429,7 +424,7 @@ struct page *init_inode_metadata(struct inode *inode, struct inode *dir,
         * This file should be checkpointed during fsync.
         * We lost i_pino from now on.
         */
-       if (is_inode_flag_set(F2FS_I(inode), FI_INC_LINK)) {
+       if (is_inode_flag_set(inode, FI_INC_LINK)) {
                file_lost_pino(inode);
                /*
                 * If link the tmpfile to alias through linkat path,
@@ -437,14 +432,11 @@ struct page *init_inode_metadata(struct inode *inode, struct inode *dir,
                 */
                if (inode->i_nlink == 0)
                        remove_orphan_inode(F2FS_I_SB(dir), inode->i_ino);
-               inc_nlink(inode);
+               f2fs_i_links_write(inode, true);
        }
        return page;
 
 put_error:
-       /* truncate empty dir pages */
-       truncate_inode_pages(&inode->i_data, 0);
-
        clear_nlink(inode);
        update_inode(inode, page);
        f2fs_put_page(page, 1);
@@ -454,23 +446,19 @@ put_error:
 void update_parent_metadata(struct inode *dir, struct inode *inode,
                                                unsigned int current_depth)
 {
-       if (inode && is_inode_flag_set(F2FS_I(inode), FI_NEW_INODE)) {
-               if (S_ISDIR(inode->i_mode)) {
-                       inc_nlink(dir);
-                       set_inode_flag(F2FS_I(dir), FI_UPDATE_DIR);
-               }
-               clear_inode_flag(F2FS_I(inode), FI_NEW_INODE);
+       if (inode && is_inode_flag_set(inode, FI_NEW_INODE)) {
+               if (S_ISDIR(inode->i_mode))
+                       f2fs_i_links_write(dir, true);
+               clear_inode_flag(inode, FI_NEW_INODE);
        }
        dir->i_mtime = dir->i_ctime = CURRENT_TIME;
-       mark_inode_dirty(dir);
+       f2fs_mark_inode_dirty_sync(dir);
 
-       if (F2FS_I(dir)->i_current_depth != current_depth) {
-               F2FS_I(dir)->i_current_depth = current_depth;
-               set_inode_flag(F2FS_I(dir), FI_UPDATE_DIR);
-       }
+       if (F2FS_I(dir)->i_current_depth != current_depth)
+               f2fs_i_depth_write(dir, current_depth);
 
-       if (inode && is_inode_flag_set(F2FS_I(inode), FI_INC_LINK))
-               clear_inode_flag(F2FS_I(inode), FI_INC_LINK);
+       if (inode && is_inode_flag_set(inode, FI_INC_LINK))
+               clear_inode_flag(inode, FI_INC_LINK);
 }
 
 int room_for_filename(const void *bitmap, int slots, int max_slots)
@@ -596,9 +584,7 @@ add_dentry:
        set_page_dirty(dentry_page);
 
        if (inode) {
-               /* we don't need to mark_inode_dirty now */
-               F2FS_I(inode)->i_pino = dir->i_ino;
-               update_inode(inode, page);
+               f2fs_i_pino_write(inode, dir->i_ino);
                f2fs_put_page(page, 1);
        }
 
@@ -607,10 +593,6 @@ fail:
        if (inode)
                up_write(&F2FS_I(inode)->i_sem);
 
-       if (is_inode_flag_set(F2FS_I(dir), FI_UPDATE_DIR)) {
-               update_inode_page(dir);
-               clear_inode_flag(F2FS_I(dir), FI_UPDATE_DIR);
-       }
        kunmap(dentry_page);
        f2fs_put_page(dentry_page, 1);
 
@@ -657,42 +639,34 @@ int f2fs_do_tmpfile(struct inode *inode, struct inode *dir)
                err = PTR_ERR(page);
                goto fail;
        }
-       /* we don't need to mark_inode_dirty now */
-       update_inode(inode, page);
        f2fs_put_page(page, 1);
 
-       clear_inode_flag(F2FS_I(inode), FI_NEW_INODE);
+       clear_inode_flag(inode, FI_NEW_INODE);
 fail:
        up_write(&F2FS_I(inode)->i_sem);
        f2fs_update_time(F2FS_I_SB(inode), REQ_TIME);
        return err;
 }
 
-void f2fs_drop_nlink(struct inode *dir, struct inode *inode, struct page *page)
+void f2fs_drop_nlink(struct inode *dir, struct inode *inode)
 {
        struct f2fs_sb_info *sbi = F2FS_I_SB(dir);
 
        down_write(&F2FS_I(inode)->i_sem);
 
-       if (S_ISDIR(inode->i_mode)) {
-               drop_nlink(dir);
-               if (page)
-                       update_inode(dir, page);
-               else
-                       update_inode_page(dir);
-       }
+       if (S_ISDIR(inode->i_mode))
+               f2fs_i_links_write(dir, false);
        inode->i_ctime = CURRENT_TIME;
 
-       drop_nlink(inode);
+       f2fs_i_links_write(inode, false);
        if (S_ISDIR(inode->i_mode)) {
-               drop_nlink(inode);
-               i_size_write(inode, 0);
+               f2fs_i_links_write(inode, false);
+               f2fs_i_size_write(inode, 0);
        }
        up_write(&F2FS_I(inode)->i_sem);
-       update_inode_page(inode);
 
        if (inode->i_nlink == 0)
-               add_orphan_inode(sbi, inode->i_ino);
+               add_orphan_inode(inode);
        else
                release_orphan_inode(sbi);
 }
@@ -730,9 +704,10 @@ void f2fs_delete_entry(struct f2fs_dir_entry *dentry, struct page *page,
        set_page_dirty(page);
 
        dir->i_ctime = dir->i_mtime = CURRENT_TIME;
+       f2fs_mark_inode_dirty_sync(dir);
 
        if (inode)
-               f2fs_drop_nlink(dir, inode, NULL);
+               f2fs_drop_nlink(dir, inode);
 
        if (bit_pos == NR_DENTRY_IN_BLOCK &&
                        !truncate_hole(dir, page->index, page->index + 1)) {