diff options
author | Chao Yu <chao2.yu@samsung.com> | 2014-06-19 16:23:19 +0800 |
---|---|---|
committer | Jaegeuk Kim <jaegeuk@kernel.org> | 2014-07-09 14:04:24 -0700 |
commit | 50732df02eefb39ab414ef655979c2c9b64ad21c (patch) | |
tree | e8cb6cb0be5951f112ced0406d5bd0c6721aa60e | |
parent | ca0a81b397b5f153ac2a9880c5e85b08b0447e4e (diff) | |
download | linux-50732df02eefb39ab414ef655979c2c9b64ad21c.tar.bz2 |
f2fs: support ->tmpfile()
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>
-rw-r--r-- | fs/f2fs/dir.c | 10 | ||||
-rw-r--r-- | fs/f2fs/namei.c | 64 |
2 files changed, 73 insertions, 1 deletions
diff --git a/fs/f2fs/dir.c b/fs/f2fs/dir.c index a4addd72ebbd..3677f4124541 100644 --- a/fs/f2fs/dir.c +++ b/fs/f2fs/dir.c @@ -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; diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c index a6bdddc33ce2..5c08c546e4c8 100644 --- a/fs/f2fs/namei.c +++ b/fs/f2fs/namei.c @@ -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, |