f2fs: support ->tmpfile()
authorChao Yu <chao2.yu@samsung.com>
Thu, 19 Jun 2014 08:23:19 +0000 (16:23 +0800)
committerJaegeuk Kim <jaegeuk@kernel.org>
Wed, 9 Jul 2014 21:04:24 +0000 (14:04 -0700)
Add function f2fs_tmpfile() to support O_TMPFILE file creation, and modify logic
of init_inode_metadata to enable linkat temp file.

Signed-off-by: Chao Yu <chao2.yu@samsung.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
fs/f2fs/dir.c
fs/f2fs/namei.c

index a4addd7..3677f41 100644 (file)
@@ -333,10 +333,12 @@ static int make_empty_dir(struct inode *inode,
 static struct page *init_inode_metadata(struct inode *inode,
                struct inode *dir, const struct qstr *name)
 {
+       struct f2fs_sb_info *sbi = F2FS_SB(dir->i_sb);
        struct page *page;
        int err;
 
-       if (is_inode_flag_set(F2FS_I(inode), FI_NEW_INODE)) {
+       if (is_inode_flag_set(F2FS_I(inode), FI_NEW_INODE) &&
+                       inode->i_nlink) {
                page = new_inode_page(inode, name);
                if (IS_ERR(page))
                        return page;
@@ -370,6 +372,12 @@ static struct page *init_inode_metadata(struct inode *inode,
         */
        if (is_inode_flag_set(F2FS_I(inode), FI_INC_LINK)) {
                file_lost_pino(inode);
+               /*
+                * If link the tmpfile to alias through linkat path,
+                * we should remove this inode from orphan list.
+                */
+               if (inode->i_nlink == 0)
+                       remove_orphan_inode(sbi, inode->i_ino);
                inc_nlink(inode);
        }
        return page;
index a6bdddc..5c08c54 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/pagemap.h>
 #include <linux/sched.h>
 #include <linux/ctype.h>
+#include <linux/dcache.h>
 
 #include "f2fs.h"
 #include "node.h"
@@ -487,6 +488,68 @@ out:
        return err;
 }
 
+static int f2fs_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode)
+{
+       struct super_block *sb = dir->i_sb;
+       struct f2fs_sb_info *sbi = F2FS_SB(sb);
+       struct inode *inode;
+       struct page *page;
+       int err;
+
+       inode = f2fs_new_inode(dir, mode);
+       if (IS_ERR(inode))
+               return PTR_ERR(inode);
+
+       inode->i_op = &f2fs_file_inode_operations;
+       inode->i_fop = &f2fs_file_operations;
+       inode->i_mapping->a_ops = &f2fs_dblock_aops;
+
+       f2fs_lock_op(sbi);
+       err = acquire_orphan_inode(sbi);
+       if (err)
+               goto out;
+       /*
+        * add this non-linked tmpfile to orphan list, in this way we could
+        * remove all unused data of tmpfile after abnormal power-off.
+        */
+       add_orphan_inode(sbi, inode->i_ino);
+
+       page = new_inode_page(inode, NULL);
+       if (IS_ERR(page)) {
+               err = PTR_ERR(page);
+               goto remove_out;
+       }
+
+       err = f2fs_init_acl(inode, dir, page);
+       if (err)
+               goto unlock_out;
+
+       err = f2fs_init_security(inode, dir, NULL, page);
+       if (err)
+               goto unlock_out;
+
+       f2fs_put_page(page, 1);
+       f2fs_unlock_op(sbi);
+
+       alloc_nid_done(sbi, inode->i_ino);
+       mark_inode_dirty(inode);
+       d_tmpfile(dentry, inode);
+       unlock_new_inode(inode);
+       return 0;
+unlock_out:
+       f2fs_put_page(page, 1);
+remove_out:
+       remove_orphan_inode(sbi, inode->i_ino);
+out:
+       f2fs_unlock_op(sbi);
+       clear_nlink(inode);
+       unlock_new_inode(inode);
+       make_bad_inode(inode);
+       iput(inode);
+       alloc_nid_failed(sbi, inode->i_ino);
+       return err;
+}
+
 const struct inode_operations f2fs_dir_inode_operations = {
        .create         = f2fs_create,
        .lookup         = f2fs_lookup,
@@ -497,6 +560,7 @@ const struct inode_operations f2fs_dir_inode_operations = {
        .rmdir          = f2fs_rmdir,
        .mknod          = f2fs_mknod,
        .rename         = f2fs_rename,
+       .tmpfile        = f2fs_tmpfile,
        .getattr        = f2fs_getattr,
        .setattr        = f2fs_setattr,
        .get_acl        = f2fs_get_acl,