xref: /openbmc/linux/fs/f2fs/namei.c (revision 34d6f206a88c2651d216bd3487ac956a40b2ba8e)
17c1a000dSChao Yu // SPDX-License-Identifier: GPL-2.0
20a8165d7SJaegeuk Kim /*
357397d86SJaegeuk Kim  * fs/f2fs/namei.c
457397d86SJaegeuk Kim  *
557397d86SJaegeuk Kim  * Copyright (c) 2012 Samsung Electronics Co., Ltd.
657397d86SJaegeuk Kim  *             http://www.samsung.com/
757397d86SJaegeuk Kim  */
857397d86SJaegeuk Kim #include <linux/fs.h>
957397d86SJaegeuk Kim #include <linux/f2fs_fs.h>
1057397d86SJaegeuk Kim #include <linux/pagemap.h>
1157397d86SJaegeuk Kim #include <linux/sched.h>
1257397d86SJaegeuk Kim #include <linux/ctype.h>
13428e3bcfSJaegeuk Kim #include <linux/random.h>
1450732df0SChao Yu #include <linux/dcache.h>
15feb7cbb0SJaegeuk Kim #include <linux/namei.h>
160abd675eSChao Yu #include <linux/quotaops.h>
1757397d86SJaegeuk Kim 
1857397d86SJaegeuk Kim #include "f2fs.h"
19953a3e27SJaegeuk Kim #include "node.h"
204354994fSDaniel Rosenberg #include "segment.h"
2157397d86SJaegeuk Kim #include "xattr.h"
2257397d86SJaegeuk Kim #include "acl.h"
23a2a4a7e4SNamjae Jeon #include <trace/events/f2fs.h>
2457397d86SJaegeuk Kim 
is_extension_exist(const unsigned char * s,const char * sub,bool tmp_ext,bool tmp_dot)25c0abbdf2SYangtao Li static inline bool is_extension_exist(const unsigned char *s, const char *sub,
262724daf6SJaegeuk Kim 						bool tmp_ext, bool tmp_dot)
27787caf1bSSheng Yong {
28787caf1bSSheng Yong 	size_t slen = strlen(s);
29787caf1bSSheng Yong 	size_t sublen = strlen(sub);
30787caf1bSSheng Yong 	int i;
31787caf1bSSheng Yong 
32787caf1bSSheng Yong 	if (sublen == 1 && *sub == '*')
33c0abbdf2SYangtao Li 		return true;
34787caf1bSSheng Yong 
35787caf1bSSheng Yong 	/*
36787caf1bSSheng Yong 	 * filename format of multimedia file should be defined as:
37787caf1bSSheng Yong 	 * "filename + '.' + extension + (optional: '.' + temp extension)".
38787caf1bSSheng Yong 	 */
39787caf1bSSheng Yong 	if (slen < sublen + 2)
40c0abbdf2SYangtao Li 		return false;
41787caf1bSSheng Yong 
42787caf1bSSheng Yong 	if (!tmp_ext) {
43787caf1bSSheng Yong 		/* file has no temp extension */
44787caf1bSSheng Yong 		if (s[slen - sublen - 1] != '.')
45c0abbdf2SYangtao Li 			return false;
46787caf1bSSheng Yong 		return !strncasecmp(s + slen - sublen, sub, sublen);
47787caf1bSSheng Yong 	}
48787caf1bSSheng Yong 
49787caf1bSSheng Yong 	for (i = 1; i < slen - sublen; i++) {
50787caf1bSSheng Yong 		if (s[i] != '.')
51787caf1bSSheng Yong 			continue;
522724daf6SJaegeuk Kim 		if (!strncasecmp(s + i + 1, sub, sublen)) {
532724daf6SJaegeuk Kim 			if (!tmp_dot)
54c0abbdf2SYangtao Li 				return true;
552724daf6SJaegeuk Kim 			if (i == slen - sublen - 1 || s[i + 1 + sublen] == '.')
562724daf6SJaegeuk Kim 				return true;
572724daf6SJaegeuk Kim 		}
58787caf1bSSheng Yong 	}
59787caf1bSSheng Yong 
60c0abbdf2SYangtao Li 	return false;
61787caf1bSSheng Yong }
62787caf1bSSheng Yong 
is_temperature_extension(const unsigned char * s,const char * sub)632724daf6SJaegeuk Kim static inline bool is_temperature_extension(const unsigned char *s, const char *sub)
642724daf6SJaegeuk Kim {
652724daf6SJaegeuk Kim 	return is_extension_exist(s, sub, true, false);
662724daf6SJaegeuk Kim }
672724daf6SJaegeuk Kim 
is_compress_extension(const unsigned char * s,const char * sub)682724daf6SJaegeuk Kim static inline bool is_compress_extension(const unsigned char *s, const char *sub)
692724daf6SJaegeuk Kim {
702724daf6SJaegeuk Kim 	return is_extension_exist(s, sub, true, true);
712724daf6SJaegeuk Kim }
722724daf6SJaegeuk Kim 
f2fs_update_extension_list(struct f2fs_sb_info * sbi,const char * name,bool hot,bool set)73787caf1bSSheng Yong int f2fs_update_extension_list(struct f2fs_sb_info *sbi, const char *name,
74787caf1bSSheng Yong 							bool hot, bool set)
75787caf1bSSheng Yong {
76787caf1bSSheng Yong 	__u8 (*extlist)[F2FS_EXTENSION_LEN] = sbi->raw_super->extension_list;
77787caf1bSSheng Yong 	int cold_count = le32_to_cpu(sbi->raw_super->extension_count);
78787caf1bSSheng Yong 	int hot_count = sbi->raw_super->hot_ext_count;
79787caf1bSSheng Yong 	int total_count = cold_count + hot_count;
80787caf1bSSheng Yong 	int start, count;
81787caf1bSSheng Yong 	int i;
82787caf1bSSheng Yong 
83787caf1bSSheng Yong 	if (set) {
84787caf1bSSheng Yong 		if (total_count == F2FS_MAX_EXTENSION)
85787caf1bSSheng Yong 			return -EINVAL;
86787caf1bSSheng Yong 	} else {
87787caf1bSSheng Yong 		if (!hot && !cold_count)
88787caf1bSSheng Yong 			return -EINVAL;
89787caf1bSSheng Yong 		if (hot && !hot_count)
90787caf1bSSheng Yong 			return -EINVAL;
91787caf1bSSheng Yong 	}
92787caf1bSSheng Yong 
93787caf1bSSheng Yong 	if (hot) {
94787caf1bSSheng Yong 		start = cold_count;
95787caf1bSSheng Yong 		count = total_count;
96787caf1bSSheng Yong 	} else {
97787caf1bSSheng Yong 		start = 0;
98787caf1bSSheng Yong 		count = cold_count;
99787caf1bSSheng Yong 	}
100787caf1bSSheng Yong 
101787caf1bSSheng Yong 	for (i = start; i < count; i++) {
102787caf1bSSheng Yong 		if (strcmp(name, extlist[i]))
103787caf1bSSheng Yong 			continue;
104787caf1bSSheng Yong 
105787caf1bSSheng Yong 		if (set)
106787caf1bSSheng Yong 			return -EINVAL;
107787caf1bSSheng Yong 
108787caf1bSSheng Yong 		memcpy(extlist[i], extlist[i + 1],
109787caf1bSSheng Yong 				F2FS_EXTENSION_LEN * (total_count - i - 1));
110787caf1bSSheng Yong 		memset(extlist[total_count - 1], 0, F2FS_EXTENSION_LEN);
111787caf1bSSheng Yong 		if (hot)
112787caf1bSSheng Yong 			sbi->raw_super->hot_ext_count = hot_count - 1;
113787caf1bSSheng Yong 		else
114787caf1bSSheng Yong 			sbi->raw_super->extension_count =
115787caf1bSSheng Yong 						cpu_to_le32(cold_count - 1);
116787caf1bSSheng Yong 		return 0;
117787caf1bSSheng Yong 	}
118787caf1bSSheng Yong 
119787caf1bSSheng Yong 	if (!set)
120787caf1bSSheng Yong 		return -EINVAL;
121787caf1bSSheng Yong 
122787caf1bSSheng Yong 	if (hot) {
123787caf1bSSheng Yong 		memcpy(extlist[count], name, strlen(name));
124787caf1bSSheng Yong 		sbi->raw_super->hot_ext_count = hot_count + 1;
125787caf1bSSheng Yong 	} else {
126787caf1bSSheng Yong 		char buf[F2FS_MAX_EXTENSION][F2FS_EXTENSION_LEN];
127787caf1bSSheng Yong 
128787caf1bSSheng Yong 		memcpy(buf, &extlist[cold_count],
129787caf1bSSheng Yong 				F2FS_EXTENSION_LEN * hot_count);
130787caf1bSSheng Yong 		memset(extlist[cold_count], 0, F2FS_EXTENSION_LEN);
131787caf1bSSheng Yong 		memcpy(extlist[cold_count], name, strlen(name));
132787caf1bSSheng Yong 		memcpy(&extlist[cold_count + 1], buf,
133787caf1bSSheng Yong 				F2FS_EXTENSION_LEN * hot_count);
134787caf1bSSheng Yong 		sbi->raw_super->extension_count = cpu_to_le32(cold_count + 1);
135787caf1bSSheng Yong 	}
136787caf1bSSheng Yong 	return 0;
137787caf1bSSheng Yong }
138787caf1bSSheng Yong 
set_compress_new_inode(struct f2fs_sb_info * sbi,struct inode * dir,struct inode * inode,const unsigned char * name)139787caf1bSSheng Yong static void set_compress_new_inode(struct f2fs_sb_info *sbi, struct inode *dir,
140787caf1bSSheng Yong 				struct inode *inode, const unsigned char *name)
141787caf1bSSheng Yong {
142787caf1bSSheng Yong 	__u8 (*extlist)[F2FS_EXTENSION_LEN] = sbi->raw_super->extension_list;
143787caf1bSSheng Yong 	unsigned char (*noext)[F2FS_EXTENSION_LEN] =
144787caf1bSSheng Yong 						F2FS_OPTION(sbi).noextensions;
145787caf1bSSheng Yong 	unsigned char (*ext)[F2FS_EXTENSION_LEN] = F2FS_OPTION(sbi).extensions;
146787caf1bSSheng Yong 	unsigned char ext_cnt = F2FS_OPTION(sbi).compress_ext_cnt;
147787caf1bSSheng Yong 	unsigned char noext_cnt = F2FS_OPTION(sbi).nocompress_ext_cnt;
148787caf1bSSheng Yong 	int i, cold_count, hot_count;
149787caf1bSSheng Yong 
150787caf1bSSheng Yong 	if (!f2fs_sb_has_compression(sbi))
151787caf1bSSheng Yong 		return;
152787caf1bSSheng Yong 
153787caf1bSSheng Yong 	if (S_ISDIR(inode->i_mode))
154787caf1bSSheng Yong 		goto inherit_comp;
155787caf1bSSheng Yong 
156787caf1bSSheng Yong 	/* This name comes only from normal files. */
157787caf1bSSheng Yong 	if (!name)
158787caf1bSSheng Yong 		return;
159787caf1bSSheng Yong 
160787caf1bSSheng Yong 	/* Don't compress hot files. */
161787caf1bSSheng Yong 	f2fs_down_read(&sbi->sb_lock);
162787caf1bSSheng Yong 	cold_count = le32_to_cpu(sbi->raw_super->extension_count);
163787caf1bSSheng Yong 	hot_count = sbi->raw_super->hot_ext_count;
164787caf1bSSheng Yong 	for (i = cold_count; i < cold_count + hot_count; i++)
1652724daf6SJaegeuk Kim 		if (is_temperature_extension(name, extlist[i]))
166787caf1bSSheng Yong 			break;
167787caf1bSSheng Yong 	f2fs_up_read(&sbi->sb_lock);
168787caf1bSSheng Yong 	if (i < (cold_count + hot_count))
169787caf1bSSheng Yong 		return;
170787caf1bSSheng Yong 
171787caf1bSSheng Yong 	/* Don't compress unallowed extension. */
172787caf1bSSheng Yong 	for (i = 0; i < noext_cnt; i++)
1732724daf6SJaegeuk Kim 		if (is_compress_extension(name, noext[i]))
174787caf1bSSheng Yong 			return;
175787caf1bSSheng Yong 
176787caf1bSSheng Yong 	/* Compress wanting extension. */
177787caf1bSSheng Yong 	for (i = 0; i < ext_cnt; i++) {
1782724daf6SJaegeuk Kim 		if (is_compress_extension(name, ext[i])) {
179787caf1bSSheng Yong 			set_compress_context(inode);
180787caf1bSSheng Yong 			return;
181787caf1bSSheng Yong 		}
182787caf1bSSheng Yong 	}
183787caf1bSSheng Yong inherit_comp:
184787caf1bSSheng Yong 	/* Inherit the {no-}compression flag in directory */
185787caf1bSSheng Yong 	if (F2FS_I(dir)->i_flags & F2FS_NOCOMP_FL) {
186787caf1bSSheng Yong 		F2FS_I(inode)->i_flags |= F2FS_NOCOMP_FL;
187787caf1bSSheng Yong 		f2fs_mark_inode_dirty_sync(inode, true);
188787caf1bSSheng Yong 	} else if (F2FS_I(dir)->i_flags & F2FS_COMPR_FL) {
189787caf1bSSheng Yong 		set_compress_context(inode);
190787caf1bSSheng Yong 	}
191787caf1bSSheng Yong }
192787caf1bSSheng Yong 
193b16bcaafSSheng Yong /*
194b16bcaafSSheng Yong  * Set file's temperature for hot/cold data separation
195b16bcaafSSheng Yong  */
set_file_temperature(struct f2fs_sb_info * sbi,struct inode * inode,const unsigned char * name)196b16bcaafSSheng Yong static void set_file_temperature(struct f2fs_sb_info *sbi, struct inode *inode,
197b16bcaafSSheng Yong 		const unsigned char *name)
198b16bcaafSSheng Yong {
199b16bcaafSSheng Yong 	__u8 (*extlist)[F2FS_EXTENSION_LEN] = sbi->raw_super->extension_list;
200b16bcaafSSheng Yong 	int i, cold_count, hot_count;
201b16bcaafSSheng Yong 
202b16bcaafSSheng Yong 	f2fs_down_read(&sbi->sb_lock);
203b16bcaafSSheng Yong 	cold_count = le32_to_cpu(sbi->raw_super->extension_count);
204b16bcaafSSheng Yong 	hot_count = sbi->raw_super->hot_ext_count;
205b16bcaafSSheng Yong 	for (i = 0; i < cold_count + hot_count; i++)
2062724daf6SJaegeuk Kim 		if (is_temperature_extension(name, extlist[i]))
207b16bcaafSSheng Yong 			break;
208b16bcaafSSheng Yong 	f2fs_up_read(&sbi->sb_lock);
209b16bcaafSSheng Yong 
210b16bcaafSSheng Yong 	if (i == cold_count + hot_count)
211b16bcaafSSheng Yong 		return;
212b16bcaafSSheng Yong 
213b16bcaafSSheng Yong 	if (i < cold_count)
214b16bcaafSSheng Yong 		file_set_cold(inode);
215b16bcaafSSheng Yong 	else
216b16bcaafSSheng Yong 		file_set_hot(inode);
217b16bcaafSSheng Yong }
218b16bcaafSSheng Yong 
f2fs_new_inode(struct mnt_idmap * idmap,struct inode * dir,umode_t mode,const char * name)219f2d40141SChristian Brauner static struct inode *f2fs_new_inode(struct mnt_idmap *idmap,
220787caf1bSSheng Yong 						struct inode *dir, umode_t mode,
221787caf1bSSheng Yong 						const char *name)
22257397d86SJaegeuk Kim {
2234081363fSJaegeuk Kim 	struct f2fs_sb_info *sbi = F2FS_I_SB(dir);
22457397d86SJaegeuk Kim 	nid_t ino;
22557397d86SJaegeuk Kim 	struct inode *inode;
22657397d86SJaegeuk Kim 	bool nid_free = false;
227e075b690SEric Biggers 	bool encrypt = false;
2286afc662eSChao Yu 	int xattr_size = 0;
229e479556bSGu Zheng 	int err;
23057397d86SJaegeuk Kim 
231a014e037SJaegeuk Kim 	inode = new_inode(dir->i_sb);
23257397d86SJaegeuk Kim 	if (!inode)
23357397d86SJaegeuk Kim 		return ERR_PTR(-ENOMEM);
23457397d86SJaegeuk Kim 
2354d57b86dSChao Yu 	if (!f2fs_alloc_nid(sbi, &ino)) {
23657397d86SJaegeuk Kim 		err = -ENOSPC;
23757397d86SJaegeuk Kim 		goto fail;
23857397d86SJaegeuk Kim 	}
23957397d86SJaegeuk Kim 
2400abd675eSChao Yu 	nid_free = true;
2410abd675eSChao Yu 
242f2d40141SChristian Brauner 	inode_init_owner(idmap, inode, dir, mode);
24357397d86SJaegeuk Kim 
24457397d86SJaegeuk Kim 	inode->i_ino = ino;
24557397d86SJaegeuk Kim 	inode->i_blocks = 0;
246c62ebd35SJeff Layton 	inode->i_mtime = inode->i_atime = inode_set_ctime_current(inode);
24724b81dfcSArnd Bergmann 	F2FS_I(inode)->i_crtime = inode->i_mtime;
248a251c17aSJason A. Donenfeld 	inode->i_generation = get_random_u32();
24957397d86SJaegeuk Kim 
2501c41e680SChao Yu 	if (S_ISDIR(inode->i_mode))
2511c41e680SChao Yu 		F2FS_I(inode)->i_current_depth = 1;
2521c41e680SChao Yu 
25357397d86SJaegeuk Kim 	err = insert_inode_locked(inode);
25457397d86SJaegeuk Kim 	if (err) {
25557397d86SJaegeuk Kim 		err = -EINVAL;
256a21c20f0SJaegeuk Kim 		goto fail;
25757397d86SJaegeuk Kim 	}
258622f28aeSChao Yu 
2597beb01f7SChao Yu 	if (f2fs_sb_has_project_quota(sbi) &&
26059c84408SChao Yu 		(F2FS_I(dir)->i_flags & F2FS_PROJINHERIT_FL))
2615c57132eSChao Yu 		F2FS_I(inode)->i_projid = F2FS_I(dir)->i_projid;
2625c57132eSChao Yu 	else
26364b4cdf2SChristian Brauner 		F2FS_I(inode)->i_projid = make_kprojid(&init_user_ns,
2645c57132eSChao Yu 							F2FS_DEF_PROJID);
2655c57132eSChao Yu 
266e075b690SEric Biggers 	err = fscrypt_prepare_new_inode(dir, inode, &encrypt);
267e075b690SEric Biggers 	if (err)
268e075b690SEric Biggers 		goto fail_drop;
269e075b690SEric Biggers 
27010a26878SChao Yu 	err = f2fs_dquot_initialize(inode);
2710abd675eSChao Yu 	if (err)
2720abd675eSChao Yu 		goto fail_drop;
2730abd675eSChao Yu 
2749ac1e2d8SDaeho Jeong 	set_inode_flag(inode, FI_NEW_INODE);
2759ac1e2d8SDaeho Jeong 
276e075b690SEric Biggers 	if (encrypt)
277fcc85a4dSJaegeuk Kim 		f2fs_set_encrypted_inode(inode);
278fcc85a4dSJaegeuk Kim 
2797beb01f7SChao Yu 	if (f2fs_sb_has_extra_attr(sbi)) {
2807a2af766SChao Yu 		set_inode_flag(inode, FI_EXTRA_ATTR);
2817a2af766SChao Yu 		F2FS_I(inode)->i_extra_isize = F2FS_TOTAL_EXTRA_ATTR_SIZE;
2827a2af766SChao Yu 	}
2837a2af766SChao Yu 
28491942321SJaegeuk Kim 	if (test_opt(sbi, INLINE_XATTR))
28591942321SJaegeuk Kim 		set_inode_flag(inode, FI_INLINE_XATTR);
2866afc662eSChao Yu 
28701b960e9SJaegeuk Kim 	if (f2fs_may_inline_dentry(inode))
28891942321SJaegeuk Kim 		set_inode_flag(inode, FI_INLINE_DENTRY);
289622f28aeSChao Yu 
2907beb01f7SChao Yu 	if (f2fs_sb_has_flexible_inline_xattr(sbi)) {
2916afc662eSChao Yu 		f2fs_bug_on(sbi, !f2fs_has_extra_attr(inode));
2926afc662eSChao Yu 		if (f2fs_has_inline_xattr(inode))
29363189b78SChao Yu 			xattr_size = F2FS_OPTION(sbi).inline_xattr_size;
2946afc662eSChao Yu 		/* Otherwise, will be 0 */
2956afc662eSChao Yu 	} else if (f2fs_has_inline_xattr(inode) ||
2966afc662eSChao Yu 				f2fs_has_inline_dentry(inode)) {
2976afc662eSChao Yu 		xattr_size = DEFAULT_INLINE_XATTR_ADDRS;
2986afc662eSChao Yu 	}
2996afc662eSChao Yu 	F2FS_I(inode)->i_inline_xattr_size = xattr_size;
3006afc662eSChao Yu 
3015c57132eSChao Yu 	F2FS_I(inode)->i_flags =
3025c57132eSChao Yu 		f2fs_mask_flags(mode, F2FS_I(dir)->i_flags & F2FS_FL_INHERITED);
3035c57132eSChao Yu 
30411f5020dSChao Yu 	if (S_ISDIR(inode->i_mode))
30559c84408SChao Yu 		F2FS_I(inode)->i_flags |= F2FS_INDEX_FL;
30611f5020dSChao Yu 
30759c84408SChao Yu 	if (F2FS_I(inode)->i_flags & F2FS_PROJINHERIT_FL)
3085c57132eSChao Yu 		set_inode_flag(inode, FI_PROJ_INHERIT);
3095c57132eSChao Yu 
310787caf1bSSheng Yong 	/* Check compression first. */
311787caf1bSSheng Yong 	set_compress_new_inode(sbi, dir, inode, name);
3124c8ff709SChao Yu 
3134cde00d5SJaegeuk Kim 	/* Should enable inline_data after compression set */
3144cde00d5SJaegeuk Kim 	if (test_opt(sbi, INLINE_DATA) && f2fs_may_inline_data(inode))
3154cde00d5SJaegeuk Kim 		set_inode_flag(inode, FI_INLINE_DATA);
3164cde00d5SJaegeuk Kim 
317b16bcaafSSheng Yong 	if (name && !test_opt(sbi, DISABLE_EXT_IDENTIFY))
318b16bcaafSSheng Yong 		set_file_temperature(sbi, inode, name);
319b16bcaafSSheng Yong 
3204cde00d5SJaegeuk Kim 	stat_inc_inline_xattr(inode);
3214cde00d5SJaegeuk Kim 	stat_inc_inline_inode(inode);
3224cde00d5SJaegeuk Kim 	stat_inc_inline_dir(inode);
3234cde00d5SJaegeuk Kim 
3249149a5ebSChao Yu 	f2fs_set_inode_flags(inode);
3259149a5ebSChao Yu 
32672840cccSJaegeuk Kim 	f2fs_init_extent_tree(inode);
32772840cccSJaegeuk Kim 
328d70b4f53SJaegeuk Kim 	trace_f2fs_new_inode(inode, 0);
32957397d86SJaegeuk Kim 	return inode;
33057397d86SJaegeuk Kim 
33157397d86SJaegeuk Kim fail:
332d70b4f53SJaegeuk Kim 	trace_f2fs_new_inode(inode, err);
333531ad7d5SJaegeuk Kim 	make_bad_inode(inode);
33457397d86SJaegeuk Kim 	if (nid_free)
33591942321SJaegeuk Kim 		set_inode_flag(inode, FI_FREE_NID);
336c9b63bd0SJaegeuk Kim 	iput(inode);
33757397d86SJaegeuk Kim 	return ERR_PTR(err);
3380abd675eSChao Yu fail_drop:
3390abd675eSChao Yu 	trace_f2fs_new_inode(inode, err);
3400abd675eSChao Yu 	dquot_drop(inode);
3410abd675eSChao Yu 	inode->i_flags |= S_NOQUOTA;
3420abd675eSChao Yu 	if (nid_free)
3430abd675eSChao Yu 		set_inode_flag(inode, FI_FREE_NID);
3440abd675eSChao Yu 	clear_nlink(inode);
3450abd675eSChao Yu 	unlock_new_inode(inode);
3460abd675eSChao Yu 	iput(inode);
3470abd675eSChao Yu 	return ERR_PTR(err);
34857397d86SJaegeuk Kim }
34957397d86SJaegeuk Kim 
f2fs_create(struct mnt_idmap * idmap,struct inode * dir,struct dentry * dentry,umode_t mode,bool excl)3506c960e68SChristian Brauner static int f2fs_create(struct mnt_idmap *idmap, struct inode *dir,
351549c7297SChristian Brauner 		       struct dentry *dentry, umode_t mode, bool excl)
35257397d86SJaegeuk Kim {
3534081363fSJaegeuk Kim 	struct f2fs_sb_info *sbi = F2FS_I_SB(dir);
35457397d86SJaegeuk Kim 	struct inode *inode;
35557397d86SJaegeuk Kim 	nid_t ino = 0;
356e479556bSGu Zheng 	int err;
35757397d86SJaegeuk Kim 
3581f227a3eSJaegeuk Kim 	if (unlikely(f2fs_cp_error(sbi)))
3591f227a3eSJaegeuk Kim 		return -EIO;
36000e09c0bSChao Yu 	if (!f2fs_is_checkpoint_ready(sbi))
36100e09c0bSChao Yu 		return -ENOSPC;
3621f227a3eSJaegeuk Kim 
36310a26878SChao Yu 	err = f2fs_dquot_initialize(dir);
3640abd675eSChao Yu 	if (err)
3650abd675eSChao Yu 		return err;
3660abd675eSChao Yu 
367f2d40141SChristian Brauner 	inode = f2fs_new_inode(idmap, dir, mode, dentry->d_name.name);
36857397d86SJaegeuk Kim 	if (IS_ERR(inode))
36957397d86SJaegeuk Kim 		return PTR_ERR(inode);
37057397d86SJaegeuk Kim 
37157397d86SJaegeuk Kim 	inode->i_op = &f2fs_file_inode_operations;
37257397d86SJaegeuk Kim 	inode->i_fop = &f2fs_file_operations;
37357397d86SJaegeuk Kim 	inode->i_mapping->a_ops = &f2fs_dblock_aops;
37457397d86SJaegeuk Kim 	ino = inode->i_ino;
37557397d86SJaegeuk Kim 
376e479556bSGu Zheng 	f2fs_lock_op(sbi);
37757397d86SJaegeuk Kim 	err = f2fs_add_link(dentry, inode);
37857397d86SJaegeuk Kim 	if (err)
37957397d86SJaegeuk Kim 		goto out;
38044c16156SJaegeuk Kim 	f2fs_unlock_op(sbi);
38157397d86SJaegeuk Kim 
3824d57b86dSChao Yu 	f2fs_alloc_nid_done(sbi, ino);
38357397d86SJaegeuk Kim 
3841e2e547aSAl Viro 	d_instantiate_new(dentry, inode);
385b7e1d800SJaegeuk Kim 
386b7e1d800SJaegeuk Kim 	if (IS_DIRSYNC(dir))
387b7e1d800SJaegeuk Kim 		f2fs_sync_fs(sbi->sb, 1);
3889bb02c36SJaegeuk Kim 
3899bb02c36SJaegeuk Kim 	f2fs_balance_fs(sbi, true);
39057397d86SJaegeuk Kim 	return 0;
39157397d86SJaegeuk Kim out:
3924d57b86dSChao Yu 	f2fs_handle_failed_inode(inode);
39357397d86SJaegeuk Kim 	return err;
39457397d86SJaegeuk Kim }
39557397d86SJaegeuk Kim 
f2fs_link(struct dentry * old_dentry,struct inode * dir,struct dentry * dentry)39657397d86SJaegeuk Kim static int f2fs_link(struct dentry *old_dentry, struct inode *dir,
39757397d86SJaegeuk Kim 		struct dentry *dentry)
39857397d86SJaegeuk Kim {
3992b0143b5SDavid Howells 	struct inode *inode = d_inode(old_dentry);
4004081363fSJaegeuk Kim 	struct f2fs_sb_info *sbi = F2FS_I_SB(dir);
401e479556bSGu Zheng 	int err;
40257397d86SJaegeuk Kim 
4031f227a3eSJaegeuk Kim 	if (unlikely(f2fs_cp_error(sbi)))
4041f227a3eSJaegeuk Kim 		return -EIO;
40500e09c0bSChao Yu 	if (!f2fs_is_checkpoint_ready(sbi))
40600e09c0bSChao Yu 		return -ENOSPC;
4071f227a3eSJaegeuk Kim 
408b05157e7SEric Biggers 	err = fscrypt_prepare_link(old_dentry, dir, dentry);
409b05157e7SEric Biggers 	if (err)
410b05157e7SEric Biggers 		return err;
411fcc85a4dSJaegeuk Kim 
4125c57132eSChao Yu 	if (is_inode_flag_set(dir, FI_PROJ_INHERIT) &&
4135c57132eSChao Yu 			(!projid_eq(F2FS_I(dir)->i_projid,
4145c57132eSChao Yu 			F2FS_I(old_dentry->d_inode)->i_projid)))
4155c57132eSChao Yu 		return -EXDEV;
4165c57132eSChao Yu 
41710a26878SChao Yu 	err = f2fs_dquot_initialize(dir);
4180abd675eSChao Yu 	if (err)
4190abd675eSChao Yu 		return err;
4200abd675eSChao Yu 
4212c4db1a6SJaegeuk Kim 	f2fs_balance_fs(sbi, true);
4221efef832SJaegeuk Kim 
423c62ebd35SJeff Layton 	inode_set_ctime_current(inode);
4246f6fd833SJaegeuk Kim 	ihold(inode);
42557397d86SJaegeuk Kim 
42691942321SJaegeuk Kim 	set_inode_flag(inode, FI_INC_LINK);
427e479556bSGu Zheng 	f2fs_lock_op(sbi);
42857397d86SJaegeuk Kim 	err = f2fs_add_link(dentry, inode);
42957397d86SJaegeuk Kim 	if (err)
43057397d86SJaegeuk Kim 		goto out;
43144c16156SJaegeuk Kim 	f2fs_unlock_op(sbi);
43257397d86SJaegeuk Kim 
43357397d86SJaegeuk Kim 	d_instantiate(dentry, inode);
434b7e1d800SJaegeuk Kim 
435b7e1d800SJaegeuk Kim 	if (IS_DIRSYNC(dir))
436b7e1d800SJaegeuk Kim 		f2fs_sync_fs(sbi->sb, 1);
43757397d86SJaegeuk Kim 	return 0;
43857397d86SJaegeuk Kim out:
43991942321SJaegeuk Kim 	clear_inode_flag(inode, FI_INC_LINK);
44057397d86SJaegeuk Kim 	iput(inode);
44144c16156SJaegeuk Kim 	f2fs_unlock_op(sbi);
44257397d86SJaegeuk Kim 	return err;
44357397d86SJaegeuk Kim }
44457397d86SJaegeuk Kim 
f2fs_get_parent(struct dentry * child)44557397d86SJaegeuk Kim struct dentry *f2fs_get_parent(struct dentry *child)
44657397d86SJaegeuk Kim {
44791246c21SChao Yu 	struct page *page;
44880e5d1ffSAl Viro 	unsigned long ino = f2fs_inode_by_name(d_inode(child), &dotdot_name, &page);
4495f029c04SYi Zhuang 
45091246c21SChao Yu 	if (!ino) {
45191246c21SChao Yu 		if (IS_ERR(page))
45291246c21SChao Yu 			return ERR_CAST(page);
45357397d86SJaegeuk Kim 		return ERR_PTR(-ENOENT);
45491246c21SChao Yu 	}
455fc64005cSAl Viro 	return d_obtain_alias(f2fs_iget(child->d_sb, ino));
45657397d86SJaegeuk Kim }
45757397d86SJaegeuk Kim 
f2fs_lookup(struct inode * dir,struct dentry * dentry,unsigned int flags)45857397d86SJaegeuk Kim static struct dentry *f2fs_lookup(struct inode *dir, struct dentry *dentry,
45957397d86SJaegeuk Kim 		unsigned int flags)
46057397d86SJaegeuk Kim {
46157397d86SJaegeuk Kim 	struct inode *inode = NULL;
46257397d86SJaegeuk Kim 	struct f2fs_dir_entry *de;
46357397d86SJaegeuk Kim 	struct page *page;
4640c5e36dbSChao Yu 	struct dentry *new;
4650c5e36dbSChao Yu 	nid_t ino = -1;
466fcc85a4dSJaegeuk Kim 	int err = 0;
46743c780baSEric Biggers 	struct f2fs_filename fname;
46857397d86SJaegeuk Kim 
4690c5e36dbSChao Yu 	trace_f2fs_lookup_start(dir, dentry, flags);
4700c5e36dbSChao Yu 
4710c5e36dbSChao Yu 	if (dentry->d_name.len > F2FS_NAME_LEN) {
4720c5e36dbSChao Yu 		err = -ENAMETOOLONG;
4730c5e36dbSChao Yu 		goto out;
4740c5e36dbSChao Yu 	}
47557397d86SJaegeuk Kim 
47643c780baSEric Biggers 	err = f2fs_prepare_lookup(dir, dentry, &fname);
477bb9cd910SDaniel Rosenberg 	generic_set_encrypted_ci_d_ops(dentry);
478b01531dbSEric Biggers 	if (err == -ENOENT)
479b01531dbSEric Biggers 		goto out_splice;
480b01531dbSEric Biggers 	if (err)
481b01531dbSEric Biggers 		goto out;
482b01531dbSEric Biggers 	de = __f2fs_find_entry(dir, &fname, &page);
48343c780baSEric Biggers 	f2fs_free_filename(&fname);
484b01531dbSEric Biggers 
485eb4246dcSJaegeuk Kim 	if (!de) {
4860c5e36dbSChao Yu 		if (IS_ERR(page)) {
4870c5e36dbSChao Yu 			err = PTR_ERR(page);
4880c5e36dbSChao Yu 			goto out;
4890c5e36dbSChao Yu 		}
49084597b1fSChao Yu 		err = -ENOENT;
4910c5e36dbSChao Yu 		goto out_splice;
492eb4246dcSJaegeuk Kim 	}
49306957e8fSJaegeuk Kim 
49406957e8fSJaegeuk Kim 	ino = le32_to_cpu(de->ino);
49557397d86SJaegeuk Kim 	f2fs_put_page(page, 0);
49657397d86SJaegeuk Kim 
49757397d86SJaegeuk Kim 	inode = f2fs_iget(dir->i_sb, ino);
4980c5e36dbSChao Yu 	if (IS_ERR(inode)) {
4990c5e36dbSChao Yu 		err = PTR_ERR(inode);
5000c5e36dbSChao Yu 		goto out;
5010c5e36dbSChao Yu 	}
502510022a8SJaegeuk Kim 
50362230e0dSChandan Rajendra 	if (IS_ENCRYPTED(dir) &&
5048074bb51SJaegeuk Kim 	    (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)) &&
5058074bb51SJaegeuk Kim 	    !fscrypt_has_permitted_context(dir, inode)) {
506dcbb4c10SJoe Perches 		f2fs_warn(F2FS_I_SB(inode), "Inconsistent encryption contexts: %lu/%lu",
507faac7fd9SEric Biggers 			  dir->i_ino, inode->i_ino);
508faac7fd9SEric Biggers 		err = -EPERM;
5090c5e36dbSChao Yu 		goto out_iput;
5108074bb51SJaegeuk Kim 	}
5110c5e36dbSChao Yu out_splice:
5125298d4bfSChristoph Hellwig #if IS_ENABLED(CONFIG_UNICODE)
5132c2eb7a3SDaniel Rosenberg 	if (!inode && IS_CASEFOLDED(dir)) {
5142c2eb7a3SDaniel Rosenberg 		/* Eventually we want to call d_add_ci(dentry, NULL)
5152c2eb7a3SDaniel Rosenberg 		 * for negative dentries in the encoding case as
5162c2eb7a3SDaniel Rosenberg 		 * well.  For now, prevent the negative dentry
5172c2eb7a3SDaniel Rosenberg 		 * from being cached.
5182c2eb7a3SDaniel Rosenberg 		 */
5192c2eb7a3SDaniel Rosenberg 		trace_f2fs_lookup_end(dir, dentry, ino, err);
5202c2eb7a3SDaniel Rosenberg 		return NULL;
5212c2eb7a3SDaniel Rosenberg 	}
5222c2eb7a3SDaniel Rosenberg #endif
5230c5e36dbSChao Yu 	new = d_splice_alias(inode, dentry);
524cadfc2f9SWu Bo 	trace_f2fs_lookup_end(dir, !IS_ERR_OR_NULL(new) ? new : dentry,
525cadfc2f9SWu Bo 				ino, IS_ERR(new) ? PTR_ERR(new) : err);
5260c5e36dbSChao Yu 	return new;
5270c5e36dbSChao Yu out_iput:
528d726732cSChao Yu 	iput(inode);
5290c5e36dbSChao Yu out:
5300c5e36dbSChao Yu 	trace_f2fs_lookup_end(dir, dentry, ino, err);
531510022a8SJaegeuk Kim 	return ERR_PTR(err);
532510022a8SJaegeuk Kim }
53357397d86SJaegeuk Kim 
f2fs_unlink(struct inode * dir,struct dentry * dentry)53457397d86SJaegeuk Kim static int f2fs_unlink(struct inode *dir, struct dentry *dentry)
53557397d86SJaegeuk Kim {
5364081363fSJaegeuk Kim 	struct f2fs_sb_info *sbi = F2FS_I_SB(dir);
5372b0143b5SDavid Howells 	struct inode *inode = d_inode(dentry);
53857397d86SJaegeuk Kim 	struct f2fs_dir_entry *de;
53957397d86SJaegeuk Kim 	struct page *page;
540deaf160fSColin Ian King 	int err;
54157397d86SJaegeuk Kim 
542a2a4a7e4SNamjae Jeon 	trace_f2fs_unlink_enter(dir, dentry);
5431efef832SJaegeuk Kim 
5449a99c17dSLihong Kou 	if (unlikely(f2fs_cp_error(sbi))) {
5459a99c17dSLihong Kou 		err = -EIO;
5469a99c17dSLihong Kou 		goto fail;
5479a99c17dSLihong Kou 	}
5481f227a3eSJaegeuk Kim 
54910a26878SChao Yu 	err = f2fs_dquot_initialize(dir);
5500abd675eSChao Yu 	if (err)
5519a99c17dSLihong Kou 		goto fail;
55210a26878SChao Yu 	err = f2fs_dquot_initialize(inode);
553d8d1389eSJaegeuk Kim 	if (err)
5549a99c17dSLihong Kou 		goto fail;
5550abd675eSChao Yu 
55657397d86SJaegeuk Kim 	de = f2fs_find_entry(dir, &dentry->d_name, &page);
55791246c21SChao Yu 	if (!de) {
55891246c21SChao Yu 		if (IS_ERR(page))
55991246c21SChao Yu 			err = PTR_ERR(page);
56057397d86SJaegeuk Kim 		goto fail;
56191246c21SChao Yu 	}
56257397d86SJaegeuk Kim 
5632c4db1a6SJaegeuk Kim 	f2fs_balance_fs(sbi, true);
56400623e6bSJaegeuk Kim 
565ccaaca25SJaegeuk Kim 	f2fs_lock_op(sbi);
5664d57b86dSChao Yu 	err = f2fs_acquire_orphan_inode(sbi);
56757397d86SJaegeuk Kim 	if (err) {
568ccaaca25SJaegeuk Kim 		f2fs_unlock_op(sbi);
56957397d86SJaegeuk Kim 		f2fs_put_page(page, 0);
57057397d86SJaegeuk Kim 		goto fail;
57157397d86SJaegeuk Kim 	}
572dbeacf02SChao Yu 	f2fs_delete_entry(de, page, dir, inode);
57314dc00a0SJaegeuk Kim 	f2fs_unlock_op(sbi);
57414dc00a0SJaegeuk Kim 
5755298d4bfSChristoph Hellwig #if IS_ENABLED(CONFIG_UNICODE)
5762c2eb7a3SDaniel Rosenberg 	/* VFS negative dentries are incompatible with Encoding and
5772c2eb7a3SDaniel Rosenberg 	 * Case-insensitiveness. Eventually we'll want avoid
5782c2eb7a3SDaniel Rosenberg 	 * invalidating the dentries here, alongside with returning the
5792c2eb7a3SDaniel Rosenberg 	 * negative dentries at f2fs_lookup(), when it is better
5802c2eb7a3SDaniel Rosenberg 	 * supported by the VFS for the CI case.
5812c2eb7a3SDaniel Rosenberg 	 */
5822c2eb7a3SDaniel Rosenberg 	if (IS_CASEFOLDED(dir))
5832c2eb7a3SDaniel Rosenberg 		d_invalidate(dentry);
5842c2eb7a3SDaniel Rosenberg #endif
585b7e1d800SJaegeuk Kim 	if (IS_DIRSYNC(dir))
586b7e1d800SJaegeuk Kim 		f2fs_sync_fs(sbi->sb, 1);
58757397d86SJaegeuk Kim fail:
588a2a4a7e4SNamjae Jeon 	trace_f2fs_unlink_exit(inode, err);
58957397d86SJaegeuk Kim 	return err;
59057397d86SJaegeuk Kim }
59157397d86SJaegeuk Kim 
f2fs_get_link(struct dentry * dentry,struct inode * inode,struct delayed_call * done)5926b255391SAl Viro static const char *f2fs_get_link(struct dentry *dentry,
593fceef393SAl Viro 				 struct inode *inode,
594fceef393SAl Viro 				 struct delayed_call *done)
595feb7cbb0SJaegeuk Kim {
596fceef393SAl Viro 	const char *link = page_get_link(dentry, inode, done);
5975f029c04SYi Zhuang 
598680baacbSAl Viro 	if (!IS_ERR(link) && !*link) {
599feb7cbb0SJaegeuk Kim 		/* this is broken symlink case */
600fceef393SAl Viro 		do_delayed_call(done);
601fceef393SAl Viro 		clear_delayed_call(done);
602680baacbSAl Viro 		link = ERR_PTR(-ENOENT);
603feb7cbb0SJaegeuk Kim 	}
604680baacbSAl Viro 	return link;
605feb7cbb0SJaegeuk Kim }
606feb7cbb0SJaegeuk Kim 
f2fs_symlink(struct mnt_idmap * idmap,struct inode * dir,struct dentry * dentry,const char * symname)6077a77db95SChristian Brauner static int f2fs_symlink(struct mnt_idmap *idmap, struct inode *dir,
608549c7297SChristian Brauner 			struct dentry *dentry, const char *symname)
60957397d86SJaegeuk Kim {
6104081363fSJaegeuk Kim 	struct f2fs_sb_info *sbi = F2FS_I_SB(dir);
61157397d86SJaegeuk Kim 	struct inode *inode;
612cbaf042aSJaegeuk Kim 	size_t len = strlen(symname);
613393c038fSEric Biggers 	struct fscrypt_str disk_link;
614e479556bSGu Zheng 	int err;
61557397d86SJaegeuk Kim 
6161f227a3eSJaegeuk Kim 	if (unlikely(f2fs_cp_error(sbi)))
6171f227a3eSJaegeuk Kim 		return -EIO;
61800e09c0bSChao Yu 	if (!f2fs_is_checkpoint_ready(sbi))
61900e09c0bSChao Yu 		return -ENOSPC;
6201f227a3eSJaegeuk Kim 
621393c038fSEric Biggers 	err = fscrypt_prepare_symlink(dir, symname, len, dir->i_sb->s_blocksize,
622393c038fSEric Biggers 				      &disk_link);
623922ec355SChao Yu 	if (err)
624922ec355SChao Yu 		return err;
625922ec355SChao Yu 
62610a26878SChao Yu 	err = f2fs_dquot_initialize(dir);
6270abd675eSChao Yu 	if (err)
6280abd675eSChao Yu 		return err;
6290abd675eSChao Yu 
630f2d40141SChristian Brauner 	inode = f2fs_new_inode(idmap, dir, S_IFLNK | S_IRWXUGO, NULL);
63157397d86SJaegeuk Kim 	if (IS_ERR(inode))
63257397d86SJaegeuk Kim 		return PTR_ERR(inode);
63357397d86SJaegeuk Kim 
634393c038fSEric Biggers 	if (IS_ENCRYPTED(inode))
635cbaf042aSJaegeuk Kim 		inode->i_op = &f2fs_encrypted_symlink_inode_operations;
636cbaf042aSJaegeuk Kim 	else
63757397d86SJaegeuk Kim 		inode->i_op = &f2fs_symlink_inode_operations;
63821fc61c7SAl Viro 	inode_nohighmem(inode);
63957397d86SJaegeuk Kim 	inode->i_mapping->a_ops = &f2fs_dblock_aops;
64057397d86SJaegeuk Kim 
641e479556bSGu Zheng 	f2fs_lock_op(sbi);
64257397d86SJaegeuk Kim 	err = f2fs_add_link(dentry, inode);
64357397d86SJaegeuk Kim 	if (err)
6444d57b86dSChao Yu 		goto out_f2fs_handle_failed_inode;
64544c16156SJaegeuk Kim 	f2fs_unlock_op(sbi);
6464d57b86dSChao Yu 	f2fs_alloc_nid_done(sbi, inode->i_ino);
64757397d86SJaegeuk Kim 
648393c038fSEric Biggers 	err = fscrypt_encrypt_symlink(inode, symname, len, &disk_link);
649cbaf042aSJaegeuk Kim 	if (err)
650cbaf042aSJaegeuk Kim 		goto err_out;
651cbaf042aSJaegeuk Kim 
652922ec355SChao Yu 	err = page_symlink(inode, disk_link.name, disk_link.len);
653cbaf042aSJaegeuk Kim 
654cbaf042aSJaegeuk Kim err_out:
6551e2e547aSAl Viro 	d_instantiate_new(dentry, inode);
656b7e1d800SJaegeuk Kim 
657d0cae97cSJaegeuk Kim 	/*
658d0cae97cSJaegeuk Kim 	 * Let's flush symlink data in order to avoid broken symlink as much as
659d0cae97cSJaegeuk Kim 	 * possible. Nevertheless, fsyncing is the best way, but there is no
660d0cae97cSJaegeuk Kim 	 * way to get a file descriptor in order to flush that.
661d0cae97cSJaegeuk Kim 	 *
662d0cae97cSJaegeuk Kim 	 * Note that, it needs to do dir->fsync to make this recoverable.
663d0cae97cSJaegeuk Kim 	 * If the symlink path is stored into inline_data, there is no
664d0cae97cSJaegeuk Kim 	 * performance regression.
665d0cae97cSJaegeuk Kim 	 */
666a6be014eSChao Yu 	if (!err) {
667922ec355SChao Yu 		filemap_write_and_wait_range(inode->i_mapping, 0,
668922ec355SChao Yu 							disk_link.len - 1);
669d0cae97cSJaegeuk Kim 
670b7e1d800SJaegeuk Kim 		if (IS_DIRSYNC(dir))
671b7e1d800SJaegeuk Kim 			f2fs_sync_fs(sbi->sb, 1);
672a6be014eSChao Yu 	} else {
673a6be014eSChao Yu 		f2fs_unlink(dir, dentry);
674a6be014eSChao Yu 	}
675cbaf042aSJaegeuk Kim 
6769bb02c36SJaegeuk Kim 	f2fs_balance_fs(sbi, true);
677393c038fSEric Biggers 	goto out_free_encrypted_link;
678393c038fSEric Biggers 
6794d57b86dSChao Yu out_f2fs_handle_failed_inode:
6804d57b86dSChao Yu 	f2fs_handle_failed_inode(inode);
681393c038fSEric Biggers out_free_encrypted_link:
682393c038fSEric Biggers 	if (disk_link.name != (unsigned char *)symname)
683c8eb7024SChao Yu 		kfree(disk_link.name);
68457397d86SJaegeuk Kim 	return err;
68557397d86SJaegeuk Kim }
68657397d86SJaegeuk Kim 
f2fs_mkdir(struct mnt_idmap * idmap,struct inode * dir,struct dentry * dentry,umode_t mode)687c54bd91eSChristian Brauner static int f2fs_mkdir(struct mnt_idmap *idmap, struct inode *dir,
688549c7297SChristian Brauner 		      struct dentry *dentry, umode_t mode)
68957397d86SJaegeuk Kim {
6904081363fSJaegeuk Kim 	struct f2fs_sb_info *sbi = F2FS_I_SB(dir);
69157397d86SJaegeuk Kim 	struct inode *inode;
692e479556bSGu Zheng 	int err;
69357397d86SJaegeuk Kim 
6941f227a3eSJaegeuk Kim 	if (unlikely(f2fs_cp_error(sbi)))
6951f227a3eSJaegeuk Kim 		return -EIO;
6961f227a3eSJaegeuk Kim 
69710a26878SChao Yu 	err = f2fs_dquot_initialize(dir);
6980abd675eSChao Yu 	if (err)
6990abd675eSChao Yu 		return err;
7000abd675eSChao Yu 
701f2d40141SChristian Brauner 	inode = f2fs_new_inode(idmap, dir, S_IFDIR | mode, NULL);
70257397d86SJaegeuk Kim 	if (IS_ERR(inode))
70361412b64SNamjae Jeon 		return PTR_ERR(inode);
70457397d86SJaegeuk Kim 
70557397d86SJaegeuk Kim 	inode->i_op = &f2fs_dir_inode_operations;
70657397d86SJaegeuk Kim 	inode->i_fop = &f2fs_dir_operations;
70757397d86SJaegeuk Kim 	inode->i_mapping->a_ops = &f2fs_dblock_aops;
70892d602bcSJaegeuk Kim 	mapping_set_gfp_mask(inode->i_mapping, GFP_NOFS);
70957397d86SJaegeuk Kim 
71091942321SJaegeuk Kim 	set_inode_flag(inode, FI_INC_LINK);
711e479556bSGu Zheng 	f2fs_lock_op(sbi);
71257397d86SJaegeuk Kim 	err = f2fs_add_link(dentry, inode);
71357397d86SJaegeuk Kim 	if (err)
71457397d86SJaegeuk Kim 		goto out_fail;
71544c16156SJaegeuk Kim 	f2fs_unlock_op(sbi);
71657397d86SJaegeuk Kim 
7174d57b86dSChao Yu 	f2fs_alloc_nid_done(sbi, inode->i_ino);
71857397d86SJaegeuk Kim 
7191e2e547aSAl Viro 	d_instantiate_new(dentry, inode);
72057397d86SJaegeuk Kim 
721b7e1d800SJaegeuk Kim 	if (IS_DIRSYNC(dir))
722b7e1d800SJaegeuk Kim 		f2fs_sync_fs(sbi->sb, 1);
7239bb02c36SJaegeuk Kim 
7249bb02c36SJaegeuk Kim 	f2fs_balance_fs(sbi, true);
72557397d86SJaegeuk Kim 	return 0;
72657397d86SJaegeuk Kim 
72757397d86SJaegeuk Kim out_fail:
72891942321SJaegeuk Kim 	clear_inode_flag(inode, FI_INC_LINK);
7294d57b86dSChao Yu 	f2fs_handle_failed_inode(inode);
73057397d86SJaegeuk Kim 	return err;
73157397d86SJaegeuk Kim }
73257397d86SJaegeuk Kim 
f2fs_rmdir(struct inode * dir,struct dentry * dentry)73357397d86SJaegeuk Kim static int f2fs_rmdir(struct inode *dir, struct dentry *dentry)
73457397d86SJaegeuk Kim {
7352b0143b5SDavid Howells 	struct inode *inode = d_inode(dentry);
7365f029c04SYi Zhuang 
73757397d86SJaegeuk Kim 	if (f2fs_empty_dir(inode))
73857397d86SJaegeuk Kim 		return f2fs_unlink(dir, dentry);
73957397d86SJaegeuk Kim 	return -ENOTEMPTY;
74057397d86SJaegeuk Kim }
74157397d86SJaegeuk Kim 
f2fs_mknod(struct mnt_idmap * idmap,struct inode * dir,struct dentry * dentry,umode_t mode,dev_t rdev)7425ebb29beSChristian Brauner static int f2fs_mknod(struct mnt_idmap *idmap, struct inode *dir,
743549c7297SChristian Brauner 		      struct dentry *dentry, umode_t mode, dev_t rdev)
74457397d86SJaegeuk Kim {
7454081363fSJaegeuk Kim 	struct f2fs_sb_info *sbi = F2FS_I_SB(dir);
74657397d86SJaegeuk Kim 	struct inode *inode;
74757397d86SJaegeuk Kim 	int err = 0;
74857397d86SJaegeuk Kim 
7491f227a3eSJaegeuk Kim 	if (unlikely(f2fs_cp_error(sbi)))
7501f227a3eSJaegeuk Kim 		return -EIO;
75100e09c0bSChao Yu 	if (!f2fs_is_checkpoint_ready(sbi))
75200e09c0bSChao Yu 		return -ENOSPC;
7531f227a3eSJaegeuk Kim 
75410a26878SChao Yu 	err = f2fs_dquot_initialize(dir);
7550abd675eSChao Yu 	if (err)
7560abd675eSChao Yu 		return err;
7570abd675eSChao Yu 
758f2d40141SChristian Brauner 	inode = f2fs_new_inode(idmap, dir, mode, NULL);
75957397d86SJaegeuk Kim 	if (IS_ERR(inode))
76057397d86SJaegeuk Kim 		return PTR_ERR(inode);
76157397d86SJaegeuk Kim 
76257397d86SJaegeuk Kim 	init_special_inode(inode, inode->i_mode, rdev);
76357397d86SJaegeuk Kim 	inode->i_op = &f2fs_special_inode_operations;
76457397d86SJaegeuk Kim 
765e479556bSGu Zheng 	f2fs_lock_op(sbi);
76657397d86SJaegeuk Kim 	err = f2fs_add_link(dentry, inode);
76757397d86SJaegeuk Kim 	if (err)
76857397d86SJaegeuk Kim 		goto out;
76944c16156SJaegeuk Kim 	f2fs_unlock_op(sbi);
77057397d86SJaegeuk Kim 
7714d57b86dSChao Yu 	f2fs_alloc_nid_done(sbi, inode->i_ino);
772b7e1d800SJaegeuk Kim 
7731e2e547aSAl Viro 	d_instantiate_new(dentry, inode);
774b7e1d800SJaegeuk Kim 
775b7e1d800SJaegeuk Kim 	if (IS_DIRSYNC(dir))
776b7e1d800SJaegeuk Kim 		f2fs_sync_fs(sbi->sb, 1);
7779bb02c36SJaegeuk Kim 
7789bb02c36SJaegeuk Kim 	f2fs_balance_fs(sbi, true);
77957397d86SJaegeuk Kim 	return 0;
78057397d86SJaegeuk Kim out:
7814d57b86dSChao Yu 	f2fs_handle_failed_inode(inode);
78257397d86SJaegeuk Kim 	return err;
78357397d86SJaegeuk Kim }
78457397d86SJaegeuk Kim 
__f2fs_tmpfile(struct mnt_idmap * idmap,struct inode * dir,struct file * file,umode_t mode,bool is_whiteout,struct inode ** new_inode,struct f2fs_filename * fname)785f2d40141SChristian Brauner static int __f2fs_tmpfile(struct mnt_idmap *idmap, struct inode *dir,
786863f144fSMiklos Szeredi 			  struct file *file, umode_t mode, bool is_whiteout,
787*7525dec4SChao Yu 			  struct inode **new_inode, struct f2fs_filename *fname)
7887e01e7adSChao Yu {
7897e01e7adSChao Yu 	struct f2fs_sb_info *sbi = F2FS_I_SB(dir);
7907e01e7adSChao Yu 	struct inode *inode;
7917e01e7adSChao Yu 	int err;
7927e01e7adSChao Yu 
79310a26878SChao Yu 	err = f2fs_dquot_initialize(dir);
7940abd675eSChao Yu 	if (err)
7950abd675eSChao Yu 		return err;
7960abd675eSChao Yu 
797f2d40141SChristian Brauner 	inode = f2fs_new_inode(idmap, dir, mode, NULL);
7987e01e7adSChao Yu 	if (IS_ERR(inode))
7997e01e7adSChao Yu 		return PTR_ERR(inode);
8007e01e7adSChao Yu 
8013db1de0eSDaeho Jeong 	if (is_whiteout) {
8027e01e7adSChao Yu 		init_special_inode(inode, inode->i_mode, WHITEOUT_DEV);
8037e01e7adSChao Yu 		inode->i_op = &f2fs_special_inode_operations;
8047e01e7adSChao Yu 	} else {
8057e01e7adSChao Yu 		inode->i_op = &f2fs_file_inode_operations;
8067e01e7adSChao Yu 		inode->i_fop = &f2fs_file_operations;
8077e01e7adSChao Yu 		inode->i_mapping->a_ops = &f2fs_dblock_aops;
8087e01e7adSChao Yu 	}
8097e01e7adSChao Yu 
8107e01e7adSChao Yu 	f2fs_lock_op(sbi);
8114d57b86dSChao Yu 	err = f2fs_acquire_orphan_inode(sbi);
8127e01e7adSChao Yu 	if (err)
8137e01e7adSChao Yu 		goto out;
8147e01e7adSChao Yu 
815*7525dec4SChao Yu 	err = f2fs_do_tmpfile(inode, dir, fname);
8167e01e7adSChao Yu 	if (err)
8177e01e7adSChao Yu 		goto release_out;
8187e01e7adSChao Yu 
8197e01e7adSChao Yu 	/*
8207e01e7adSChao Yu 	 * add this non-linked tmpfile to orphan list, in this way we could
8217e01e7adSChao Yu 	 * remove all unused data of tmpfile after abnormal power-off.
8227e01e7adSChao Yu 	 */
8234d57b86dSChao Yu 	f2fs_add_orphan_inode(inode);
8244d57b86dSChao Yu 	f2fs_alloc_nid_done(sbi, inode->i_ino);
8257e01e7adSChao Yu 
8263db1de0eSDaeho Jeong 	if (is_whiteout) {
827a1961246SJaegeuk Kim 		f2fs_i_links_write(inode, false);
82846085f37SChao Yu 
82946085f37SChao Yu 		spin_lock(&inode->i_lock);
8305b1dbb08SJaegeuk Kim 		inode->i_state |= I_LINKABLE;
83146085f37SChao Yu 		spin_unlock(&inode->i_lock);
8327e01e7adSChao Yu 	} else {
833863f144fSMiklos Szeredi 		if (file)
834863f144fSMiklos Szeredi 			d_tmpfile(file, inode);
8353db1de0eSDaeho Jeong 		else
8363db1de0eSDaeho Jeong 			f2fs_i_links_write(inode, false);
8377e01e7adSChao Yu 	}
838a1961246SJaegeuk Kim 	/* link_count was changed by d_tmpfile as well. */
839a1961246SJaegeuk Kim 	f2fs_unlock_op(sbi);
8407e01e7adSChao Yu 	unlock_new_inode(inode);
8419bb02c36SJaegeuk Kim 
8423db1de0eSDaeho Jeong 	if (new_inode)
8433db1de0eSDaeho Jeong 		*new_inode = inode;
8443db1de0eSDaeho Jeong 
8459bb02c36SJaegeuk Kim 	f2fs_balance_fs(sbi, true);
8467e01e7adSChao Yu 	return 0;
8477e01e7adSChao Yu 
8487e01e7adSChao Yu release_out:
8494d57b86dSChao Yu 	f2fs_release_orphan_inode(sbi);
8507e01e7adSChao Yu out:
8514d57b86dSChao Yu 	f2fs_handle_failed_inode(inode);
8527e01e7adSChao Yu 	return err;
8537e01e7adSChao Yu }
8547e01e7adSChao Yu 
f2fs_tmpfile(struct mnt_idmap * idmap,struct inode * dir,struct file * file,umode_t mode)855011e2b71SChristian Brauner static int f2fs_tmpfile(struct mnt_idmap *idmap, struct inode *dir,
856863f144fSMiklos Szeredi 			struct file *file, umode_t mode)
8577e01e7adSChao Yu {
858ff62af20SSheng Yong 	struct f2fs_sb_info *sbi = F2FS_I_SB(dir);
859863f144fSMiklos Szeredi 	int err;
860ff62af20SSheng Yong 
861ff62af20SSheng Yong 	if (unlikely(f2fs_cp_error(sbi)))
8621f227a3eSJaegeuk Kim 		return -EIO;
86300e09c0bSChao Yu 	if (!f2fs_is_checkpoint_ready(sbi))
86400e09c0bSChao Yu 		return -ENOSPC;
8651f227a3eSJaegeuk Kim 
866*7525dec4SChao Yu 	err = __f2fs_tmpfile(idmap, dir, file, mode, false, NULL, NULL);
867863f144fSMiklos Szeredi 
868863f144fSMiklos Szeredi 	return finish_open_simple(file, err);
8697e01e7adSChao Yu }
8707e01e7adSChao Yu 
f2fs_create_whiteout(struct mnt_idmap * idmap,struct inode * dir,struct inode ** whiteout,struct f2fs_filename * fname)871f2d40141SChristian Brauner static int f2fs_create_whiteout(struct mnt_idmap *idmap,
872*7525dec4SChao Yu 				struct inode *dir, struct inode **whiteout,
873*7525dec4SChao Yu 				struct f2fs_filename *fname)
8747e01e7adSChao Yu {
875*7525dec4SChao Yu 	return __f2fs_tmpfile(idmap, dir, NULL, S_IFCHR | WHITEOUT_MODE,
876*7525dec4SChao Yu 						true, whiteout, fname);
8773db1de0eSDaeho Jeong }
8783db1de0eSDaeho Jeong 
f2fs_get_tmpfile(struct mnt_idmap * idmap,struct inode * dir,struct inode ** new_inode)879f2d40141SChristian Brauner int f2fs_get_tmpfile(struct mnt_idmap *idmap, struct inode *dir,
8803db1de0eSDaeho Jeong 		     struct inode **new_inode)
8813db1de0eSDaeho Jeong {
882*7525dec4SChao Yu 	return __f2fs_tmpfile(idmap, dir, NULL, S_IFREG,
883*7525dec4SChao Yu 				false, new_inode, NULL);
8847e01e7adSChao Yu }
8857e01e7adSChao Yu 
f2fs_rename(struct mnt_idmap * idmap,struct inode * old_dir,struct dentry * old_dentry,struct inode * new_dir,struct dentry * new_dentry,unsigned int flags)886f2d40141SChristian Brauner static int f2fs_rename(struct mnt_idmap *idmap, struct inode *old_dir,
887984fc4e7SChao Yu 			struct dentry *old_dentry, struct inode *new_dir,
888984fc4e7SChao Yu 			struct dentry *new_dentry, unsigned int flags)
88957397d86SJaegeuk Kim {
8904081363fSJaegeuk Kim 	struct f2fs_sb_info *sbi = F2FS_I_SB(old_dir);
8912b0143b5SDavid Howells 	struct inode *old_inode = d_inode(old_dentry);
8922b0143b5SDavid Howells 	struct inode *new_inode = d_inode(new_dentry);
8937e01e7adSChao Yu 	struct inode *whiteout = NULL;
894762e4db5SJaegeuk Kim 	struct page *old_dir_page = NULL;
8957e01e7adSChao Yu 	struct page *old_page, *new_page = NULL;
89657397d86SJaegeuk Kim 	struct f2fs_dir_entry *old_dir_entry = NULL;
89757397d86SJaegeuk Kim 	struct f2fs_dir_entry *old_entry;
89857397d86SJaegeuk Kim 	struct f2fs_dir_entry *new_entry;
899d83d0f5bSJaegeuk Kim 	int err;
90057397d86SJaegeuk Kim 
9011f227a3eSJaegeuk Kim 	if (unlikely(f2fs_cp_error(sbi)))
9021f227a3eSJaegeuk Kim 		return -EIO;
90300e09c0bSChao Yu 	if (!f2fs_is_checkpoint_ready(sbi))
90400e09c0bSChao Yu 		return -ENOSPC;
9051f227a3eSJaegeuk Kim 
9065c57132eSChao Yu 	if (is_inode_flag_set(new_dir, FI_PROJ_INHERIT) &&
9075c57132eSChao Yu 			(!projid_eq(F2FS_I(new_dir)->i_projid,
9085c57132eSChao Yu 			F2FS_I(old_dentry->d_inode)->i_projid)))
9095c57132eSChao Yu 		return -EXDEV;
9105c57132eSChao Yu 
911b06af2afSJaegeuk Kim 	/*
912b06af2afSJaegeuk Kim 	 * If new_inode is null, the below renaming flow will
913146949deSJinyoung CHOI 	 * add a link in old_dir which can convert inline_dir.
914b06af2afSJaegeuk Kim 	 * After then, if we failed to get the entry due to other
915b06af2afSJaegeuk Kim 	 * reasons like ENOMEM, we had to remove the new entry.
916b06af2afSJaegeuk Kim 	 * Instead of adding such the error handling routine, let's
917b06af2afSJaegeuk Kim 	 * simply convert first here.
918b06af2afSJaegeuk Kim 	 */
919b06af2afSJaegeuk Kim 	if (old_dir == new_dir && !new_inode) {
920b06af2afSJaegeuk Kim 		err = f2fs_try_convert_inline_dir(old_dir, new_dentry);
921b06af2afSJaegeuk Kim 		if (err)
922b06af2afSJaegeuk Kim 			return err;
923b06af2afSJaegeuk Kim 	}
924b06af2afSJaegeuk Kim 
9255b1dbb08SJaegeuk Kim 	if (flags & RENAME_WHITEOUT) {
926*7525dec4SChao Yu 		struct f2fs_filename fname;
927*7525dec4SChao Yu 
928*7525dec4SChao Yu 		err = f2fs_setup_filename(old_dir, &old_dentry->d_name,
929*7525dec4SChao Yu 							0, &fname);
930*7525dec4SChao Yu 		if (err)
931*7525dec4SChao Yu 			return err;
932*7525dec4SChao Yu 
933*7525dec4SChao Yu 		err = f2fs_create_whiteout(idmap, old_dir, &whiteout, &fname);
9345b1dbb08SJaegeuk Kim 		if (err)
9355b1dbb08SJaegeuk Kim 			return err;
9365b1dbb08SJaegeuk Kim 	}
9375b1dbb08SJaegeuk Kim 
93810a26878SChao Yu 	err = f2fs_dquot_initialize(old_dir);
9390abd675eSChao Yu 	if (err)
9400abd675eSChao Yu 		goto out;
9410abd675eSChao Yu 
94210a26878SChao Yu 	err = f2fs_dquot_initialize(new_dir);
9430abd675eSChao Yu 	if (err)
9440abd675eSChao Yu 		goto out;
9450abd675eSChao Yu 
946d8d1389eSJaegeuk Kim 	if (new_inode) {
94710a26878SChao Yu 		err = f2fs_dquot_initialize(new_inode);
948d8d1389eSJaegeuk Kim 		if (err)
949d8d1389eSJaegeuk Kim 			goto out;
950d8d1389eSJaegeuk Kim 	}
951d8d1389eSJaegeuk Kim 
952d83d0f5bSJaegeuk Kim 	err = -ENOENT;
95357397d86SJaegeuk Kim 	old_entry = f2fs_find_entry(old_dir, &old_dentry->d_name, &old_page);
95491246c21SChao Yu 	if (!old_entry) {
95591246c21SChao Yu 		if (IS_ERR(old_page))
95691246c21SChao Yu 			err = PTR_ERR(old_page);
957cde3c9d7SJan Kara 		goto out;
95891246c21SChao Yu 	}
95957397d86SJaegeuk Kim 
96057397d86SJaegeuk Kim 	if (S_ISDIR(old_inode->i_mode)) {
96157397d86SJaegeuk Kim 		old_dir_entry = f2fs_parent_dir(old_inode, &old_dir_page);
9623e19886eSJaegeuk Kim 		if (!old_dir_entry) {
96391246c21SChao Yu 			if (IS_ERR(old_dir_page))
9643e19886eSJaegeuk Kim 				err = PTR_ERR(old_dir_page);
96557397d86SJaegeuk Kim 			goto out_old;
96657397d86SJaegeuk Kim 		}
9673e19886eSJaegeuk Kim 	}
96857397d86SJaegeuk Kim 
96957397d86SJaegeuk Kim 	if (new_inode) {
97057397d86SJaegeuk Kim 
97157397d86SJaegeuk Kim 		err = -ENOTEMPTY;
97257397d86SJaegeuk Kim 		if (old_dir_entry && !f2fs_empty_dir(new_inode))
9735b1dbb08SJaegeuk Kim 			goto out_dir;
97457397d86SJaegeuk Kim 
97557397d86SJaegeuk Kim 		err = -ENOENT;
97657397d86SJaegeuk Kim 		new_entry = f2fs_find_entry(new_dir, &new_dentry->d_name,
97757397d86SJaegeuk Kim 						&new_page);
97891246c21SChao Yu 		if (!new_entry) {
97991246c21SChao Yu 			if (IS_ERR(new_page))
98091246c21SChao Yu 				err = PTR_ERR(new_page);
9815b1dbb08SJaegeuk Kim 			goto out_dir;
98291246c21SChao Yu 		}
98357397d86SJaegeuk Kim 
9842c4db1a6SJaegeuk Kim 		f2fs_balance_fs(sbi, true);
98500623e6bSJaegeuk Kim 
9861256010aSChao Yu 		f2fs_lock_op(sbi);
9871256010aSChao Yu 
9884d57b86dSChao Yu 		err = f2fs_acquire_orphan_inode(sbi);
989cbd56e7dSJaegeuk Kim 		if (err)
990cbd56e7dSJaegeuk Kim 			goto put_out_dir;
991cbd56e7dSJaegeuk Kim 
99257397d86SJaegeuk Kim 		f2fs_set_link(new_dir, new_entry, new_page, old_inode);
993762e4db5SJaegeuk Kim 		new_page = NULL;
99457397d86SJaegeuk Kim 
995c62ebd35SJeff Layton 		inode_set_ctime_current(new_inode);
996e4544b63STim Murray 		f2fs_down_write(&F2FS_I(new_inode)->i_sem);
99757397d86SJaegeuk Kim 		if (old_dir_entry)
998a1961246SJaegeuk Kim 			f2fs_i_links_write(new_inode, false);
999a1961246SJaegeuk Kim 		f2fs_i_links_write(new_inode, false);
1000e4544b63STim Murray 		f2fs_up_write(&F2FS_I(new_inode)->i_sem);
1001d928bfbfSJaegeuk Kim 
100257397d86SJaegeuk Kim 		if (!new_inode->i_nlink)
10034d57b86dSChao Yu 			f2fs_add_orphan_inode(new_inode);
1004cbd56e7dSJaegeuk Kim 		else
10054d57b86dSChao Yu 			f2fs_release_orphan_inode(sbi);
100657397d86SJaegeuk Kim 	} else {
10072c4db1a6SJaegeuk Kim 		f2fs_balance_fs(sbi, true);
100800623e6bSJaegeuk Kim 
10091256010aSChao Yu 		f2fs_lock_op(sbi);
10101256010aSChao Yu 
101157397d86SJaegeuk Kim 		err = f2fs_add_link(new_dentry, old_inode);
10121256010aSChao Yu 		if (err) {
10131256010aSChao Yu 			f2fs_unlock_op(sbi);
10145b1dbb08SJaegeuk Kim 			goto out_dir;
10151256010aSChao Yu 		}
101657397d86SJaegeuk Kim 
1017ee6d182fSJaegeuk Kim 		if (old_dir_entry)
1018a1961246SJaegeuk Kim 			f2fs_i_links_write(new_dir, true);
101957397d86SJaegeuk Kim 	}
102057397d86SJaegeuk Kim 
1021e4544b63STim Murray 	f2fs_down_write(&F2FS_I(old_inode)->i_sem);
1022b855bf0eSSheng Yong 	if (!old_dir_entry || whiteout)
1023b2c08299SJaegeuk Kim 		file_lost_pino(old_inode);
1024b855bf0eSSheng Yong 	else
10252a60637fSChao Yu 		/* adjust dir's i_pino to pass fsck check */
10262a60637fSChao Yu 		f2fs_i_pino_write(old_inode, new_dir->i_ino);
1027e4544b63STim Murray 	f2fs_up_write(&F2FS_I(old_inode)->i_sem);
1028b2c08299SJaegeuk Kim 
1029c62ebd35SJeff Layton 	inode_set_ctime_current(old_inode);
10307c45729aSJaegeuk Kim 	f2fs_mark_inode_dirty_sync(old_inode, false);
103157397d86SJaegeuk Kim 
1032dbeacf02SChao Yu 	f2fs_delete_entry(old_entry, old_page, old_dir, NULL);
1033762e4db5SJaegeuk Kim 	old_page = NULL;
103457397d86SJaegeuk Kim 
10357e01e7adSChao Yu 	if (whiteout) {
103691942321SJaegeuk Kim 		set_inode_flag(whiteout, FI_INC_LINK);
10377e01e7adSChao Yu 		err = f2fs_add_link(old_dentry, whiteout);
10387e01e7adSChao Yu 		if (err)
10397e01e7adSChao Yu 			goto put_out_dir;
104046085f37SChao Yu 
104146085f37SChao Yu 		spin_lock(&whiteout->i_lock);
10427e01e7adSChao Yu 		whiteout->i_state &= ~I_LINKABLE;
104346085f37SChao Yu 		spin_unlock(&whiteout->i_lock);
104446085f37SChao Yu 
10457e01e7adSChao Yu 		iput(whiteout);
10467e01e7adSChao Yu 	}
10477e01e7adSChao Yu 
104857397d86SJaegeuk Kim 	if (old_dir_entry) {
1049d3c0b49aSChao Yu 		if (old_dir != new_dir)
105057397d86SJaegeuk Kim 			f2fs_set_link(old_inode, old_dir_entry,
105157397d86SJaegeuk Kim 						old_dir_page, new_dir);
1052bdbc90faSYunlong Song 		else
105357397d86SJaegeuk Kim 			f2fs_put_page(old_dir_page, 0);
1054a1961246SJaegeuk Kim 		f2fs_i_links_write(old_dir, false);
105557397d86SJaegeuk Kim 	}
1056ade990f9SJaegeuk Kim 	if (F2FS_OPTION(sbi).fsync_mode == FSYNC_MODE_STRICT) {
10574d57b86dSChao Yu 		f2fs_add_ino_entry(sbi, new_dir->i_ino, TRANS_DIR_INO);
1058ade990f9SJaegeuk Kim 		if (S_ISDIR(old_inode->i_mode))
10594d57b86dSChao Yu 			f2fs_add_ino_entry(sbi, old_inode->i_ino,
10604d57b86dSChao Yu 							TRANS_DIR_INO);
1061ade990f9SJaegeuk Kim 	}
106257397d86SJaegeuk Kim 
1063e479556bSGu Zheng 	f2fs_unlock_op(sbi);
1064b7e1d800SJaegeuk Kim 
1065b7e1d800SJaegeuk Kim 	if (IS_DIRSYNC(old_dir) || IS_DIRSYNC(new_dir))
1066b7e1d800SJaegeuk Kim 		f2fs_sync_fs(sbi->sb, 1);
10676390398eSSahitya Tummala 
10686390398eSSahitya Tummala 	f2fs_update_time(sbi, REQ_TIME);
106957397d86SJaegeuk Kim 	return 0;
107057397d86SJaegeuk Kim 
1071cbd56e7dSJaegeuk Kim put_out_dir:
10721256010aSChao Yu 	f2fs_unlock_op(sbi);
1073dd4d961fSChao Yu 	f2fs_put_page(new_page, 0);
107457397d86SJaegeuk Kim out_dir:
1075bdbc90faSYunlong Song 	if (old_dir_entry)
107657397d86SJaegeuk Kim 		f2fs_put_page(old_dir_page, 0);
107757397d86SJaegeuk Kim out_old:
107857397d86SJaegeuk Kim 	f2fs_put_page(old_page, 0);
107957397d86SJaegeuk Kim out:
10805b1dbb08SJaegeuk Kim 	iput(whiteout);
108157397d86SJaegeuk Kim 	return err;
108257397d86SJaegeuk Kim }
108357397d86SJaegeuk Kim 
f2fs_cross_rename(struct inode * old_dir,struct dentry * old_dentry,struct inode * new_dir,struct dentry * new_dentry)108432f9bc25SChao Yu static int f2fs_cross_rename(struct inode *old_dir, struct dentry *old_dentry,
108532f9bc25SChao Yu 			     struct inode *new_dir, struct dentry *new_dentry)
108632f9bc25SChao Yu {
10874081363fSJaegeuk Kim 	struct f2fs_sb_info *sbi = F2FS_I_SB(old_dir);
10882b0143b5SDavid Howells 	struct inode *old_inode = d_inode(old_dentry);
10892b0143b5SDavid Howells 	struct inode *new_inode = d_inode(new_dentry);
109032f9bc25SChao Yu 	struct page *old_dir_page, *new_dir_page;
109132f9bc25SChao Yu 	struct page *old_page, *new_page;
109232f9bc25SChao Yu 	struct f2fs_dir_entry *old_dir_entry = NULL, *new_dir_entry = NULL;
109332f9bc25SChao Yu 	struct f2fs_dir_entry *old_entry, *new_entry;
109432f9bc25SChao Yu 	int old_nlink = 0, new_nlink = 0;
1095d83d0f5bSJaegeuk Kim 	int err;
109632f9bc25SChao Yu 
10971f227a3eSJaegeuk Kim 	if (unlikely(f2fs_cp_error(sbi)))
10981f227a3eSJaegeuk Kim 		return -EIO;
109900e09c0bSChao Yu 	if (!f2fs_is_checkpoint_ready(sbi))
110000e09c0bSChao Yu 		return -ENOSPC;
11011f227a3eSJaegeuk Kim 
11025c57132eSChao Yu 	if ((is_inode_flag_set(new_dir, FI_PROJ_INHERIT) &&
11035c57132eSChao Yu 			!projid_eq(F2FS_I(new_dir)->i_projid,
11045c57132eSChao Yu 			F2FS_I(old_dentry->d_inode)->i_projid)) ||
11055c57132eSChao Yu 	    (is_inode_flag_set(new_dir, FI_PROJ_INHERIT) &&
11065c57132eSChao Yu 			!projid_eq(F2FS_I(old_dir)->i_projid,
11075c57132eSChao Yu 			F2FS_I(new_dentry->d_inode)->i_projid)))
11085c57132eSChao Yu 		return -EXDEV;
11095c57132eSChao Yu 
111010a26878SChao Yu 	err = f2fs_dquot_initialize(old_dir);
11110abd675eSChao Yu 	if (err)
11120abd675eSChao Yu 		goto out;
11130abd675eSChao Yu 
111410a26878SChao Yu 	err = f2fs_dquot_initialize(new_dir);
11150abd675eSChao Yu 	if (err)
11160abd675eSChao Yu 		goto out;
11170abd675eSChao Yu 
1118d83d0f5bSJaegeuk Kim 	err = -ENOENT;
111932f9bc25SChao Yu 	old_entry = f2fs_find_entry(old_dir, &old_dentry->d_name, &old_page);
112091246c21SChao Yu 	if (!old_entry) {
112191246c21SChao Yu 		if (IS_ERR(old_page))
112291246c21SChao Yu 			err = PTR_ERR(old_page);
112332f9bc25SChao Yu 		goto out;
112491246c21SChao Yu 	}
112532f9bc25SChao Yu 
112632f9bc25SChao Yu 	new_entry = f2fs_find_entry(new_dir, &new_dentry->d_name, &new_page);
112791246c21SChao Yu 	if (!new_entry) {
112891246c21SChao Yu 		if (IS_ERR(new_page))
112991246c21SChao Yu 			err = PTR_ERR(new_page);
113032f9bc25SChao Yu 		goto out_old;
113191246c21SChao Yu 	}
113232f9bc25SChao Yu 
113332f9bc25SChao Yu 	/* prepare for updating ".." directory entry info later */
113432f9bc25SChao Yu 	if (old_dir != new_dir) {
113532f9bc25SChao Yu 		if (S_ISDIR(old_inode->i_mode)) {
113632f9bc25SChao Yu 			old_dir_entry = f2fs_parent_dir(old_inode,
113732f9bc25SChao Yu 							&old_dir_page);
11383e19886eSJaegeuk Kim 			if (!old_dir_entry) {
113991246c21SChao Yu 				if (IS_ERR(old_dir_page))
11403e19886eSJaegeuk Kim 					err = PTR_ERR(old_dir_page);
114132f9bc25SChao Yu 				goto out_new;
114232f9bc25SChao Yu 			}
11433e19886eSJaegeuk Kim 		}
114432f9bc25SChao Yu 
114532f9bc25SChao Yu 		if (S_ISDIR(new_inode->i_mode)) {
114632f9bc25SChao Yu 			new_dir_entry = f2fs_parent_dir(new_inode,
114732f9bc25SChao Yu 							&new_dir_page);
11483e19886eSJaegeuk Kim 			if (!new_dir_entry) {
114991246c21SChao Yu 				if (IS_ERR(new_dir_page))
11503e19886eSJaegeuk Kim 					err = PTR_ERR(new_dir_page);
115132f9bc25SChao Yu 				goto out_old_dir;
115232f9bc25SChao Yu 			}
115332f9bc25SChao Yu 		}
11543e19886eSJaegeuk Kim 	}
115532f9bc25SChao Yu 
115632f9bc25SChao Yu 	/*
115732f9bc25SChao Yu 	 * If cross rename between file and directory those are not
115832f9bc25SChao Yu 	 * in the same directory, we will inc nlink of file's parent
115932f9bc25SChao Yu 	 * later, so we should check upper boundary of its nlink.
116032f9bc25SChao Yu 	 */
116132f9bc25SChao Yu 	if ((!old_dir_entry || !new_dir_entry) &&
116232f9bc25SChao Yu 				old_dir_entry != new_dir_entry) {
116332f9bc25SChao Yu 		old_nlink = old_dir_entry ? -1 : 1;
116432f9bc25SChao Yu 		new_nlink = -old_nlink;
116532f9bc25SChao Yu 		err = -EMLINK;
1166e2f0e962SKinglong Mee 		if ((old_nlink > 0 && old_dir->i_nlink >= F2FS_LINK_MAX) ||
1167e2f0e962SKinglong Mee 			(new_nlink > 0 && new_dir->i_nlink >= F2FS_LINK_MAX))
116832f9bc25SChao Yu 			goto out_new_dir;
116932f9bc25SChao Yu 	}
117032f9bc25SChao Yu 
11712c4db1a6SJaegeuk Kim 	f2fs_balance_fs(sbi, true);
117200623e6bSJaegeuk Kim 
117332f9bc25SChao Yu 	f2fs_lock_op(sbi);
117432f9bc25SChao Yu 
117532f9bc25SChao Yu 	/* update ".." directory entry info of old dentry */
117632f9bc25SChao Yu 	if (old_dir_entry)
117732f9bc25SChao Yu 		f2fs_set_link(old_inode, old_dir_entry, old_dir_page, new_dir);
117832f9bc25SChao Yu 
117932f9bc25SChao Yu 	/* update ".." directory entry info of new dentry */
118032f9bc25SChao Yu 	if (new_dir_entry)
118132f9bc25SChao Yu 		f2fs_set_link(new_inode, new_dir_entry, new_dir_page, old_dir);
118232f9bc25SChao Yu 
118332f9bc25SChao Yu 	/* update directory entry info of old dir inode */
118432f9bc25SChao Yu 	f2fs_set_link(old_dir, old_entry, old_page, new_inode);
118532f9bc25SChao Yu 
1186e4544b63STim Murray 	f2fs_down_write(&F2FS_I(old_inode)->i_sem);
11872a60637fSChao Yu 	if (!old_dir_entry)
118832f9bc25SChao Yu 		file_lost_pino(old_inode);
11892a60637fSChao Yu 	else
11902a60637fSChao Yu 		/* adjust dir's i_pino to pass fsck check */
11912a60637fSChao Yu 		f2fs_i_pino_write(old_inode, new_dir->i_ino);
1192e4544b63STim Murray 	f2fs_up_write(&F2FS_I(old_inode)->i_sem);
119332f9bc25SChao Yu 
1194c62ebd35SJeff Layton 	inode_set_ctime_current(old_dir);
119532f9bc25SChao Yu 	if (old_nlink) {
1196e4544b63STim Murray 		f2fs_down_write(&F2FS_I(old_dir)->i_sem);
1197a1961246SJaegeuk Kim 		f2fs_i_links_write(old_dir, old_nlink > 0);
1198e4544b63STim Murray 		f2fs_up_write(&F2FS_I(old_dir)->i_sem);
119932f9bc25SChao Yu 	}
12007c45729aSJaegeuk Kim 	f2fs_mark_inode_dirty_sync(old_dir, false);
120132f9bc25SChao Yu 
120232f9bc25SChao Yu 	/* update directory entry info of new dir inode */
120332f9bc25SChao Yu 	f2fs_set_link(new_dir, new_entry, new_page, old_inode);
120432f9bc25SChao Yu 
1205e4544b63STim Murray 	f2fs_down_write(&F2FS_I(new_inode)->i_sem);
12062a60637fSChao Yu 	if (!new_dir_entry)
120732f9bc25SChao Yu 		file_lost_pino(new_inode);
12082a60637fSChao Yu 	else
12092a60637fSChao Yu 		/* adjust dir's i_pino to pass fsck check */
12102a60637fSChao Yu 		f2fs_i_pino_write(new_inode, old_dir->i_ino);
1211e4544b63STim Murray 	f2fs_up_write(&F2FS_I(new_inode)->i_sem);
121232f9bc25SChao Yu 
1213c62ebd35SJeff Layton 	inode_set_ctime_current(new_dir);
121432f9bc25SChao Yu 	if (new_nlink) {
1215e4544b63STim Murray 		f2fs_down_write(&F2FS_I(new_dir)->i_sem);
1216a1961246SJaegeuk Kim 		f2fs_i_links_write(new_dir, new_nlink > 0);
1217e4544b63STim Murray 		f2fs_up_write(&F2FS_I(new_dir)->i_sem);
121832f9bc25SChao Yu 	}
12197c45729aSJaegeuk Kim 	f2fs_mark_inode_dirty_sync(new_dir, false);
122032f9bc25SChao Yu 
122163189b78SChao Yu 	if (F2FS_OPTION(sbi).fsync_mode == FSYNC_MODE_STRICT) {
12224d57b86dSChao Yu 		f2fs_add_ino_entry(sbi, old_dir->i_ino, TRANS_DIR_INO);
12234d57b86dSChao Yu 		f2fs_add_ino_entry(sbi, new_dir->i_ino, TRANS_DIR_INO);
122493cf93f1SJunling Zheng 	}
12250a007b97SJaegeuk Kim 
122632f9bc25SChao Yu 	f2fs_unlock_op(sbi);
1227b7e1d800SJaegeuk Kim 
1228b7e1d800SJaegeuk Kim 	if (IS_DIRSYNC(old_dir) || IS_DIRSYNC(new_dir))
1229b7e1d800SJaegeuk Kim 		f2fs_sync_fs(sbi->sb, 1);
12306390398eSSahitya Tummala 
12316390398eSSahitya Tummala 	f2fs_update_time(sbi, REQ_TIME);
123232f9bc25SChao Yu 	return 0;
123332f9bc25SChao Yu out_new_dir:
123432f9bc25SChao Yu 	if (new_dir_entry) {
123532f9bc25SChao Yu 		f2fs_put_page(new_dir_page, 0);
123632f9bc25SChao Yu 	}
123732f9bc25SChao Yu out_old_dir:
123832f9bc25SChao Yu 	if (old_dir_entry) {
123932f9bc25SChao Yu 		f2fs_put_page(old_dir_page, 0);
124032f9bc25SChao Yu 	}
124132f9bc25SChao Yu out_new:
124232f9bc25SChao Yu 	f2fs_put_page(new_page, 0);
124332f9bc25SChao Yu out_old:
124432f9bc25SChao Yu 	f2fs_put_page(old_page, 0);
124532f9bc25SChao Yu out:
124632f9bc25SChao Yu 	return err;
124732f9bc25SChao Yu }
124832f9bc25SChao Yu 
f2fs_rename2(struct mnt_idmap * idmap,struct inode * old_dir,struct dentry * old_dentry,struct inode * new_dir,struct dentry * new_dentry,unsigned int flags)1249e18275aeSChristian Brauner static int f2fs_rename2(struct mnt_idmap *idmap,
1250549c7297SChristian Brauner 			struct inode *old_dir, struct dentry *old_dentry,
125132f9bc25SChao Yu 			struct inode *new_dir, struct dentry *new_dentry,
125232f9bc25SChao Yu 			unsigned int flags)
125332f9bc25SChao Yu {
12542e45b07fSEric Biggers 	int err;
12552e45b07fSEric Biggers 
12567e01e7adSChao Yu 	if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE | RENAME_WHITEOUT))
125732f9bc25SChao Yu 		return -EINVAL;
125832f9bc25SChao Yu 
12592e45b07fSEric Biggers 	err = fscrypt_prepare_rename(old_dir, old_dentry, new_dir, new_dentry,
12602e45b07fSEric Biggers 				     flags);
12612e45b07fSEric Biggers 	if (err)
12622e45b07fSEric Biggers 		return err;
12632e45b07fSEric Biggers 
126432f9bc25SChao Yu 	if (flags & RENAME_EXCHANGE) {
126532f9bc25SChao Yu 		return f2fs_cross_rename(old_dir, old_dentry,
126632f9bc25SChao Yu 					 new_dir, new_dentry);
126732f9bc25SChao Yu 	}
126832f9bc25SChao Yu 	/*
126932f9bc25SChao Yu 	 * VFS has already handled the new dentry existence case,
127032f9bc25SChao Yu 	 * here, we just deal with "RENAME_NOREPLACE" as regular rename.
127132f9bc25SChao Yu 	 */
1272f2d40141SChristian Brauner 	return f2fs_rename(idmap, old_dir, old_dentry,
1273984fc4e7SChao Yu 					new_dir, new_dentry, flags);
127432f9bc25SChao Yu }
127532f9bc25SChao Yu 
f2fs_encrypted_get_link(struct dentry * dentry,struct inode * inode,struct delayed_call * done)12766b255391SAl Viro static const char *f2fs_encrypted_get_link(struct dentry *dentry,
1277fceef393SAl Viro 					   struct inode *inode,
1278fceef393SAl Viro 					   struct delayed_call *done)
127950732df0SChao Yu {
1280f2329cb6SEric Biggers 	struct page *page;
1281f2329cb6SEric Biggers 	const char *target;
128250732df0SChao Yu 
12836b255391SAl Viro 	if (!dentry)
12846b255391SAl Viro 		return ERR_PTR(-ECHILD);
12856b255391SAl Viro 
1286f2329cb6SEric Biggers 	page = read_mapping_page(inode->i_mapping, 0, NULL);
1287f2329cb6SEric Biggers 	if (IS_ERR(page))
1288f2329cb6SEric Biggers 		return ERR_CAST(page);
128950732df0SChao Yu 
1290f2329cb6SEric Biggers 	target = fscrypt_get_symlink(inode, page_address(page),
1291f2329cb6SEric Biggers 				     inode->i_sb->s_blocksize, done);
1292f2329cb6SEric Biggers 	put_page(page);
1293f2329cb6SEric Biggers 	return target;
1294cbaf042aSJaegeuk Kim }
1295cbaf042aSJaegeuk Kim 
f2fs_encrypted_symlink_getattr(struct mnt_idmap * idmap,const struct path * path,struct kstat * stat,u32 request_mask,unsigned int query_flags)1296b74d24f7SChristian Brauner static int f2fs_encrypted_symlink_getattr(struct mnt_idmap *idmap,
1297461b43a8SEric Biggers 					  const struct path *path,
1298461b43a8SEric Biggers 					  struct kstat *stat, u32 request_mask,
1299461b43a8SEric Biggers 					  unsigned int query_flags)
1300461b43a8SEric Biggers {
1301b74d24f7SChristian Brauner 	f2fs_getattr(idmap, path, stat, request_mask, query_flags);
1302461b43a8SEric Biggers 
1303461b43a8SEric Biggers 	return fscrypt_symlink_getattr(path, stat);
1304461b43a8SEric Biggers }
1305461b43a8SEric Biggers 
1306cbaf042aSJaegeuk Kim const struct inode_operations f2fs_encrypted_symlink_inode_operations = {
13076b255391SAl Viro 	.get_link	= f2fs_encrypted_get_link,
1308461b43a8SEric Biggers 	.getattr	= f2fs_encrypted_symlink_getattr,
1309cbaf042aSJaegeuk Kim 	.setattr	= f2fs_setattr,
1310cbaf042aSJaegeuk Kim 	.listxattr	= f2fs_listxattr,
1311cbaf042aSJaegeuk Kim };
1312cbaf042aSJaegeuk Kim 
131357397d86SJaegeuk Kim const struct inode_operations f2fs_dir_inode_operations = {
131457397d86SJaegeuk Kim 	.create		= f2fs_create,
131557397d86SJaegeuk Kim 	.lookup		= f2fs_lookup,
131657397d86SJaegeuk Kim 	.link		= f2fs_link,
131757397d86SJaegeuk Kim 	.unlink		= f2fs_unlink,
131857397d86SJaegeuk Kim 	.symlink	= f2fs_symlink,
131957397d86SJaegeuk Kim 	.mkdir		= f2fs_mkdir,
132057397d86SJaegeuk Kim 	.rmdir		= f2fs_rmdir,
132157397d86SJaegeuk Kim 	.mknod		= f2fs_mknod,
13222773bf00SMiklos Szeredi 	.rename		= f2fs_rename2,
132350732df0SChao Yu 	.tmpfile	= f2fs_tmpfile,
13242d4d9fb5SJaegeuk Kim 	.getattr	= f2fs_getattr,
132557397d86SJaegeuk Kim 	.setattr	= f2fs_setattr,
1326cac2f8b8SChristian Brauner 	.get_inode_acl	= f2fs_get_acl,
1327a6dda0e6SChristoph Hellwig 	.set_acl	= f2fs_set_acl,
132857397d86SJaegeuk Kim 	.listxattr	= f2fs_listxattr,
13297975f349SChao Yu 	.fiemap		= f2fs_fiemap,
13309b1bb01cSMiklos Szeredi 	.fileattr_get	= f2fs_fileattr_get,
13319b1bb01cSMiklos Szeredi 	.fileattr_set	= f2fs_fileattr_set,
133257397d86SJaegeuk Kim };
133357397d86SJaegeuk Kim 
133457397d86SJaegeuk Kim const struct inode_operations f2fs_symlink_inode_operations = {
13356b255391SAl Viro 	.get_link	= f2fs_get_link,
13362d4d9fb5SJaegeuk Kim 	.getattr	= f2fs_getattr,
133757397d86SJaegeuk Kim 	.setattr	= f2fs_setattr,
133857397d86SJaegeuk Kim 	.listxattr	= f2fs_listxattr,
133957397d86SJaegeuk Kim };
134057397d86SJaegeuk Kim 
134157397d86SJaegeuk Kim const struct inode_operations f2fs_special_inode_operations = {
13422d4d9fb5SJaegeuk Kim 	.getattr	= f2fs_getattr,
134357397d86SJaegeuk Kim 	.setattr	= f2fs_setattr,
1344cac2f8b8SChristian Brauner 	.get_inode_acl	= f2fs_get_acl,
1345a6dda0e6SChristoph Hellwig 	.set_acl	= f2fs_set_acl,
134657397d86SJaegeuk Kim 	.listxattr	= f2fs_listxattr,
134757397d86SJaegeuk Kim };
1348