162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * fs/f2fs/namei.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (c) 2012 Samsung Electronics Co., Ltd.
662306a36Sopenharmony_ci *             http://www.samsung.com/
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci#include <linux/fs.h>
962306a36Sopenharmony_ci#include <linux/f2fs_fs.h>
1062306a36Sopenharmony_ci#include <linux/pagemap.h>
1162306a36Sopenharmony_ci#include <linux/sched.h>
1262306a36Sopenharmony_ci#include <linux/ctype.h>
1362306a36Sopenharmony_ci#include <linux/random.h>
1462306a36Sopenharmony_ci#include <linux/dcache.h>
1562306a36Sopenharmony_ci#include <linux/namei.h>
1662306a36Sopenharmony_ci#include <linux/quotaops.h>
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#include "f2fs.h"
1962306a36Sopenharmony_ci#include "node.h"
2062306a36Sopenharmony_ci#include "segment.h"
2162306a36Sopenharmony_ci#include "xattr.h"
2262306a36Sopenharmony_ci#include "acl.h"
2362306a36Sopenharmony_ci#include <trace/events/f2fs.h>
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_cistatic inline bool is_extension_exist(const unsigned char *s, const char *sub,
2662306a36Sopenharmony_ci						bool tmp_ext, bool tmp_dot)
2762306a36Sopenharmony_ci{
2862306a36Sopenharmony_ci	size_t slen = strlen(s);
2962306a36Sopenharmony_ci	size_t sublen = strlen(sub);
3062306a36Sopenharmony_ci	int i;
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci	if (sublen == 1 && *sub == '*')
3362306a36Sopenharmony_ci		return true;
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci	/*
3662306a36Sopenharmony_ci	 * filename format of multimedia file should be defined as:
3762306a36Sopenharmony_ci	 * "filename + '.' + extension + (optional: '.' + temp extension)".
3862306a36Sopenharmony_ci	 */
3962306a36Sopenharmony_ci	if (slen < sublen + 2)
4062306a36Sopenharmony_ci		return false;
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci	if (!tmp_ext) {
4362306a36Sopenharmony_ci		/* file has no temp extension */
4462306a36Sopenharmony_ci		if (s[slen - sublen - 1] != '.')
4562306a36Sopenharmony_ci			return false;
4662306a36Sopenharmony_ci		return !strncasecmp(s + slen - sublen, sub, sublen);
4762306a36Sopenharmony_ci	}
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci	for (i = 1; i < slen - sublen; i++) {
5062306a36Sopenharmony_ci		if (s[i] != '.')
5162306a36Sopenharmony_ci			continue;
5262306a36Sopenharmony_ci		if (!strncasecmp(s + i + 1, sub, sublen)) {
5362306a36Sopenharmony_ci			if (!tmp_dot)
5462306a36Sopenharmony_ci				return true;
5562306a36Sopenharmony_ci			if (i == slen - sublen - 1 || s[i + 1 + sublen] == '.')
5662306a36Sopenharmony_ci				return true;
5762306a36Sopenharmony_ci		}
5862306a36Sopenharmony_ci	}
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	return false;
6162306a36Sopenharmony_ci}
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_cistatic inline bool is_temperature_extension(const unsigned char *s, const char *sub)
6462306a36Sopenharmony_ci{
6562306a36Sopenharmony_ci	return is_extension_exist(s, sub, true, false);
6662306a36Sopenharmony_ci}
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_cistatic inline bool is_compress_extension(const unsigned char *s, const char *sub)
6962306a36Sopenharmony_ci{
7062306a36Sopenharmony_ci	return is_extension_exist(s, sub, true, true);
7162306a36Sopenharmony_ci}
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ciint f2fs_update_extension_list(struct f2fs_sb_info *sbi, const char *name,
7462306a36Sopenharmony_ci							bool hot, bool set)
7562306a36Sopenharmony_ci{
7662306a36Sopenharmony_ci	__u8 (*extlist)[F2FS_EXTENSION_LEN] = sbi->raw_super->extension_list;
7762306a36Sopenharmony_ci	int cold_count = le32_to_cpu(sbi->raw_super->extension_count);
7862306a36Sopenharmony_ci	int hot_count = sbi->raw_super->hot_ext_count;
7962306a36Sopenharmony_ci	int total_count = cold_count + hot_count;
8062306a36Sopenharmony_ci	int start, count;
8162306a36Sopenharmony_ci	int i;
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci	if (set) {
8462306a36Sopenharmony_ci		if (total_count == F2FS_MAX_EXTENSION)
8562306a36Sopenharmony_ci			return -EINVAL;
8662306a36Sopenharmony_ci	} else {
8762306a36Sopenharmony_ci		if (!hot && !cold_count)
8862306a36Sopenharmony_ci			return -EINVAL;
8962306a36Sopenharmony_ci		if (hot && !hot_count)
9062306a36Sopenharmony_ci			return -EINVAL;
9162306a36Sopenharmony_ci	}
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	if (hot) {
9462306a36Sopenharmony_ci		start = cold_count;
9562306a36Sopenharmony_ci		count = total_count;
9662306a36Sopenharmony_ci	} else {
9762306a36Sopenharmony_ci		start = 0;
9862306a36Sopenharmony_ci		count = cold_count;
9962306a36Sopenharmony_ci	}
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	for (i = start; i < count; i++) {
10262306a36Sopenharmony_ci		if (strcmp(name, extlist[i]))
10362306a36Sopenharmony_ci			continue;
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci		if (set)
10662306a36Sopenharmony_ci			return -EINVAL;
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci		memcpy(extlist[i], extlist[i + 1],
10962306a36Sopenharmony_ci				F2FS_EXTENSION_LEN * (total_count - i - 1));
11062306a36Sopenharmony_ci		memset(extlist[total_count - 1], 0, F2FS_EXTENSION_LEN);
11162306a36Sopenharmony_ci		if (hot)
11262306a36Sopenharmony_ci			sbi->raw_super->hot_ext_count = hot_count - 1;
11362306a36Sopenharmony_ci		else
11462306a36Sopenharmony_ci			sbi->raw_super->extension_count =
11562306a36Sopenharmony_ci						cpu_to_le32(cold_count - 1);
11662306a36Sopenharmony_ci		return 0;
11762306a36Sopenharmony_ci	}
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	if (!set)
12062306a36Sopenharmony_ci		return -EINVAL;
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci	if (hot) {
12362306a36Sopenharmony_ci		memcpy(extlist[count], name, strlen(name));
12462306a36Sopenharmony_ci		sbi->raw_super->hot_ext_count = hot_count + 1;
12562306a36Sopenharmony_ci	} else {
12662306a36Sopenharmony_ci		char buf[F2FS_MAX_EXTENSION][F2FS_EXTENSION_LEN];
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci		memcpy(buf, &extlist[cold_count],
12962306a36Sopenharmony_ci				F2FS_EXTENSION_LEN * hot_count);
13062306a36Sopenharmony_ci		memset(extlist[cold_count], 0, F2FS_EXTENSION_LEN);
13162306a36Sopenharmony_ci		memcpy(extlist[cold_count], name, strlen(name));
13262306a36Sopenharmony_ci		memcpy(&extlist[cold_count + 1], buf,
13362306a36Sopenharmony_ci				F2FS_EXTENSION_LEN * hot_count);
13462306a36Sopenharmony_ci		sbi->raw_super->extension_count = cpu_to_le32(cold_count + 1);
13562306a36Sopenharmony_ci	}
13662306a36Sopenharmony_ci	return 0;
13762306a36Sopenharmony_ci}
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_cistatic void set_compress_new_inode(struct f2fs_sb_info *sbi, struct inode *dir,
14062306a36Sopenharmony_ci				struct inode *inode, const unsigned char *name)
14162306a36Sopenharmony_ci{
14262306a36Sopenharmony_ci	__u8 (*extlist)[F2FS_EXTENSION_LEN] = sbi->raw_super->extension_list;
14362306a36Sopenharmony_ci	unsigned char (*noext)[F2FS_EXTENSION_LEN] =
14462306a36Sopenharmony_ci						F2FS_OPTION(sbi).noextensions;
14562306a36Sopenharmony_ci	unsigned char (*ext)[F2FS_EXTENSION_LEN] = F2FS_OPTION(sbi).extensions;
14662306a36Sopenharmony_ci	unsigned char ext_cnt = F2FS_OPTION(sbi).compress_ext_cnt;
14762306a36Sopenharmony_ci	unsigned char noext_cnt = F2FS_OPTION(sbi).nocompress_ext_cnt;
14862306a36Sopenharmony_ci	int i, cold_count, hot_count;
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	if (!f2fs_sb_has_compression(sbi))
15162306a36Sopenharmony_ci		return;
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	if (S_ISDIR(inode->i_mode))
15462306a36Sopenharmony_ci		goto inherit_comp;
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	/* This name comes only from normal files. */
15762306a36Sopenharmony_ci	if (!name)
15862306a36Sopenharmony_ci		return;
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	/* Don't compress hot files. */
16162306a36Sopenharmony_ci	f2fs_down_read(&sbi->sb_lock);
16262306a36Sopenharmony_ci	cold_count = le32_to_cpu(sbi->raw_super->extension_count);
16362306a36Sopenharmony_ci	hot_count = sbi->raw_super->hot_ext_count;
16462306a36Sopenharmony_ci	for (i = cold_count; i < cold_count + hot_count; i++)
16562306a36Sopenharmony_ci		if (is_temperature_extension(name, extlist[i]))
16662306a36Sopenharmony_ci			break;
16762306a36Sopenharmony_ci	f2fs_up_read(&sbi->sb_lock);
16862306a36Sopenharmony_ci	if (i < (cold_count + hot_count))
16962306a36Sopenharmony_ci		return;
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci	/* Don't compress unallowed extension. */
17262306a36Sopenharmony_ci	for (i = 0; i < noext_cnt; i++)
17362306a36Sopenharmony_ci		if (is_compress_extension(name, noext[i]))
17462306a36Sopenharmony_ci			return;
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci	/* Compress wanting extension. */
17762306a36Sopenharmony_ci	for (i = 0; i < ext_cnt; i++) {
17862306a36Sopenharmony_ci		if (is_compress_extension(name, ext[i])) {
17962306a36Sopenharmony_ci			set_compress_context(inode);
18062306a36Sopenharmony_ci			return;
18162306a36Sopenharmony_ci		}
18262306a36Sopenharmony_ci	}
18362306a36Sopenharmony_ciinherit_comp:
18462306a36Sopenharmony_ci	/* Inherit the {no-}compression flag in directory */
18562306a36Sopenharmony_ci	if (F2FS_I(dir)->i_flags & F2FS_NOCOMP_FL) {
18662306a36Sopenharmony_ci		F2FS_I(inode)->i_flags |= F2FS_NOCOMP_FL;
18762306a36Sopenharmony_ci		f2fs_mark_inode_dirty_sync(inode, true);
18862306a36Sopenharmony_ci	} else if (F2FS_I(dir)->i_flags & F2FS_COMPR_FL) {
18962306a36Sopenharmony_ci		set_compress_context(inode);
19062306a36Sopenharmony_ci	}
19162306a36Sopenharmony_ci}
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci/*
19462306a36Sopenharmony_ci * Set file's temperature for hot/cold data separation
19562306a36Sopenharmony_ci */
19662306a36Sopenharmony_cistatic void set_file_temperature(struct f2fs_sb_info *sbi, struct inode *inode,
19762306a36Sopenharmony_ci		const unsigned char *name)
19862306a36Sopenharmony_ci{
19962306a36Sopenharmony_ci	__u8 (*extlist)[F2FS_EXTENSION_LEN] = sbi->raw_super->extension_list;
20062306a36Sopenharmony_ci	int i, cold_count, hot_count;
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	f2fs_down_read(&sbi->sb_lock);
20362306a36Sopenharmony_ci	cold_count = le32_to_cpu(sbi->raw_super->extension_count);
20462306a36Sopenharmony_ci	hot_count = sbi->raw_super->hot_ext_count;
20562306a36Sopenharmony_ci	for (i = 0; i < cold_count + hot_count; i++)
20662306a36Sopenharmony_ci		if (is_temperature_extension(name, extlist[i]))
20762306a36Sopenharmony_ci			break;
20862306a36Sopenharmony_ci	f2fs_up_read(&sbi->sb_lock);
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci	if (i == cold_count + hot_count)
21162306a36Sopenharmony_ci		return;
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	if (i < cold_count)
21462306a36Sopenharmony_ci		file_set_cold(inode);
21562306a36Sopenharmony_ci	else
21662306a36Sopenharmony_ci		file_set_hot(inode);
21762306a36Sopenharmony_ci}
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_cistatic struct inode *f2fs_new_inode(struct mnt_idmap *idmap,
22062306a36Sopenharmony_ci						struct inode *dir, umode_t mode,
22162306a36Sopenharmony_ci						const char *name)
22262306a36Sopenharmony_ci{
22362306a36Sopenharmony_ci	struct f2fs_sb_info *sbi = F2FS_I_SB(dir);
22462306a36Sopenharmony_ci	nid_t ino;
22562306a36Sopenharmony_ci	struct inode *inode;
22662306a36Sopenharmony_ci	bool nid_free = false;
22762306a36Sopenharmony_ci	bool encrypt = false;
22862306a36Sopenharmony_ci	int xattr_size = 0;
22962306a36Sopenharmony_ci	int err;
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	inode = new_inode(dir->i_sb);
23262306a36Sopenharmony_ci	if (!inode)
23362306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci	if (!f2fs_alloc_nid(sbi, &ino)) {
23662306a36Sopenharmony_ci		err = -ENOSPC;
23762306a36Sopenharmony_ci		goto fail;
23862306a36Sopenharmony_ci	}
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	nid_free = true;
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci	inode_init_owner(idmap, inode, dir, mode);
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	inode->i_ino = ino;
24562306a36Sopenharmony_ci	inode->i_blocks = 0;
24662306a36Sopenharmony_ci	inode->i_mtime = inode->i_atime = inode_set_ctime_current(inode);
24762306a36Sopenharmony_ci	F2FS_I(inode)->i_crtime = inode->i_mtime;
24862306a36Sopenharmony_ci	inode->i_generation = get_random_u32();
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci	if (S_ISDIR(inode->i_mode))
25162306a36Sopenharmony_ci		F2FS_I(inode)->i_current_depth = 1;
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	err = insert_inode_locked(inode);
25462306a36Sopenharmony_ci	if (err) {
25562306a36Sopenharmony_ci		err = -EINVAL;
25662306a36Sopenharmony_ci		goto fail;
25762306a36Sopenharmony_ci	}
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci	if (f2fs_sb_has_project_quota(sbi) &&
26062306a36Sopenharmony_ci		(F2FS_I(dir)->i_flags & F2FS_PROJINHERIT_FL))
26162306a36Sopenharmony_ci		F2FS_I(inode)->i_projid = F2FS_I(dir)->i_projid;
26262306a36Sopenharmony_ci	else
26362306a36Sopenharmony_ci		F2FS_I(inode)->i_projid = make_kprojid(&init_user_ns,
26462306a36Sopenharmony_ci							F2FS_DEF_PROJID);
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci	err = fscrypt_prepare_new_inode(dir, inode, &encrypt);
26762306a36Sopenharmony_ci	if (err)
26862306a36Sopenharmony_ci		goto fail_drop;
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci	err = f2fs_dquot_initialize(inode);
27162306a36Sopenharmony_ci	if (err)
27262306a36Sopenharmony_ci		goto fail_drop;
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci	set_inode_flag(inode, FI_NEW_INODE);
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci	if (encrypt)
27762306a36Sopenharmony_ci		f2fs_set_encrypted_inode(inode);
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci	if (f2fs_sb_has_extra_attr(sbi)) {
28062306a36Sopenharmony_ci		set_inode_flag(inode, FI_EXTRA_ATTR);
28162306a36Sopenharmony_ci		F2FS_I(inode)->i_extra_isize = F2FS_TOTAL_EXTRA_ATTR_SIZE;
28262306a36Sopenharmony_ci	}
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci	if (test_opt(sbi, INLINE_XATTR))
28562306a36Sopenharmony_ci		set_inode_flag(inode, FI_INLINE_XATTR);
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci	if (f2fs_may_inline_dentry(inode))
28862306a36Sopenharmony_ci		set_inode_flag(inode, FI_INLINE_DENTRY);
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	if (f2fs_sb_has_flexible_inline_xattr(sbi)) {
29162306a36Sopenharmony_ci		f2fs_bug_on(sbi, !f2fs_has_extra_attr(inode));
29262306a36Sopenharmony_ci		if (f2fs_has_inline_xattr(inode))
29362306a36Sopenharmony_ci			xattr_size = F2FS_OPTION(sbi).inline_xattr_size;
29462306a36Sopenharmony_ci		/* Otherwise, will be 0 */
29562306a36Sopenharmony_ci	} else if (f2fs_has_inline_xattr(inode) ||
29662306a36Sopenharmony_ci				f2fs_has_inline_dentry(inode)) {
29762306a36Sopenharmony_ci		xattr_size = DEFAULT_INLINE_XATTR_ADDRS;
29862306a36Sopenharmony_ci	}
29962306a36Sopenharmony_ci	F2FS_I(inode)->i_inline_xattr_size = xattr_size;
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci	F2FS_I(inode)->i_flags =
30262306a36Sopenharmony_ci		f2fs_mask_flags(mode, F2FS_I(dir)->i_flags & F2FS_FL_INHERITED);
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci	if (S_ISDIR(inode->i_mode))
30562306a36Sopenharmony_ci		F2FS_I(inode)->i_flags |= F2FS_INDEX_FL;
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci	if (F2FS_I(inode)->i_flags & F2FS_PROJINHERIT_FL)
30862306a36Sopenharmony_ci		set_inode_flag(inode, FI_PROJ_INHERIT);
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	/* Check compression first. */
31162306a36Sopenharmony_ci	set_compress_new_inode(sbi, dir, inode, name);
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci	/* Should enable inline_data after compression set */
31462306a36Sopenharmony_ci	if (test_opt(sbi, INLINE_DATA) && f2fs_may_inline_data(inode))
31562306a36Sopenharmony_ci		set_inode_flag(inode, FI_INLINE_DATA);
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	if (name && !test_opt(sbi, DISABLE_EXT_IDENTIFY))
31862306a36Sopenharmony_ci		set_file_temperature(sbi, inode, name);
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci	stat_inc_inline_xattr(inode);
32162306a36Sopenharmony_ci	stat_inc_inline_inode(inode);
32262306a36Sopenharmony_ci	stat_inc_inline_dir(inode);
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci	f2fs_set_inode_flags(inode);
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci	f2fs_init_extent_tree(inode);
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	trace_f2fs_new_inode(inode, 0);
32962306a36Sopenharmony_ci	return inode;
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_cifail:
33262306a36Sopenharmony_ci	trace_f2fs_new_inode(inode, err);
33362306a36Sopenharmony_ci	make_bad_inode(inode);
33462306a36Sopenharmony_ci	if (nid_free)
33562306a36Sopenharmony_ci		set_inode_flag(inode, FI_FREE_NID);
33662306a36Sopenharmony_ci	iput(inode);
33762306a36Sopenharmony_ci	return ERR_PTR(err);
33862306a36Sopenharmony_cifail_drop:
33962306a36Sopenharmony_ci	trace_f2fs_new_inode(inode, err);
34062306a36Sopenharmony_ci	dquot_drop(inode);
34162306a36Sopenharmony_ci	inode->i_flags |= S_NOQUOTA;
34262306a36Sopenharmony_ci	if (nid_free)
34362306a36Sopenharmony_ci		set_inode_flag(inode, FI_FREE_NID);
34462306a36Sopenharmony_ci	clear_nlink(inode);
34562306a36Sopenharmony_ci	unlock_new_inode(inode);
34662306a36Sopenharmony_ci	iput(inode);
34762306a36Sopenharmony_ci	return ERR_PTR(err);
34862306a36Sopenharmony_ci}
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_cistatic int f2fs_create(struct mnt_idmap *idmap, struct inode *dir,
35162306a36Sopenharmony_ci		       struct dentry *dentry, umode_t mode, bool excl)
35262306a36Sopenharmony_ci{
35362306a36Sopenharmony_ci	struct f2fs_sb_info *sbi = F2FS_I_SB(dir);
35462306a36Sopenharmony_ci	struct inode *inode;
35562306a36Sopenharmony_ci	nid_t ino = 0;
35662306a36Sopenharmony_ci	int err;
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci	if (unlikely(f2fs_cp_error(sbi)))
35962306a36Sopenharmony_ci		return -EIO;
36062306a36Sopenharmony_ci	if (!f2fs_is_checkpoint_ready(sbi))
36162306a36Sopenharmony_ci		return -ENOSPC;
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	err = f2fs_dquot_initialize(dir);
36462306a36Sopenharmony_ci	if (err)
36562306a36Sopenharmony_ci		return err;
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci	inode = f2fs_new_inode(idmap, dir, mode, dentry->d_name.name);
36862306a36Sopenharmony_ci	if (IS_ERR(inode))
36962306a36Sopenharmony_ci		return PTR_ERR(inode);
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	inode->i_op = &f2fs_file_inode_operations;
37262306a36Sopenharmony_ci	inode->i_fop = &f2fs_file_operations;
37362306a36Sopenharmony_ci	inode->i_mapping->a_ops = &f2fs_dblock_aops;
37462306a36Sopenharmony_ci	ino = inode->i_ino;
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci	f2fs_lock_op(sbi);
37762306a36Sopenharmony_ci	err = f2fs_add_link(dentry, inode);
37862306a36Sopenharmony_ci	if (err)
37962306a36Sopenharmony_ci		goto out;
38062306a36Sopenharmony_ci	f2fs_unlock_op(sbi);
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci	f2fs_alloc_nid_done(sbi, ino);
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci	d_instantiate_new(dentry, inode);
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci	if (IS_DIRSYNC(dir))
38762306a36Sopenharmony_ci		f2fs_sync_fs(sbi->sb, 1);
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci	f2fs_balance_fs(sbi, true);
39062306a36Sopenharmony_ci	return 0;
39162306a36Sopenharmony_ciout:
39262306a36Sopenharmony_ci	f2fs_handle_failed_inode(inode);
39362306a36Sopenharmony_ci	return err;
39462306a36Sopenharmony_ci}
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_cistatic int f2fs_link(struct dentry *old_dentry, struct inode *dir,
39762306a36Sopenharmony_ci		struct dentry *dentry)
39862306a36Sopenharmony_ci{
39962306a36Sopenharmony_ci	struct inode *inode = d_inode(old_dentry);
40062306a36Sopenharmony_ci	struct f2fs_sb_info *sbi = F2FS_I_SB(dir);
40162306a36Sopenharmony_ci	int err;
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci	if (unlikely(f2fs_cp_error(sbi)))
40462306a36Sopenharmony_ci		return -EIO;
40562306a36Sopenharmony_ci	if (!f2fs_is_checkpoint_ready(sbi))
40662306a36Sopenharmony_ci		return -ENOSPC;
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	err = fscrypt_prepare_link(old_dentry, dir, dentry);
40962306a36Sopenharmony_ci	if (err)
41062306a36Sopenharmony_ci		return err;
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci	if (is_inode_flag_set(dir, FI_PROJ_INHERIT) &&
41362306a36Sopenharmony_ci			(!projid_eq(F2FS_I(dir)->i_projid,
41462306a36Sopenharmony_ci			F2FS_I(old_dentry->d_inode)->i_projid)))
41562306a36Sopenharmony_ci		return -EXDEV;
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci	err = f2fs_dquot_initialize(dir);
41862306a36Sopenharmony_ci	if (err)
41962306a36Sopenharmony_ci		return err;
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci	f2fs_balance_fs(sbi, true);
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	inode_set_ctime_current(inode);
42462306a36Sopenharmony_ci	ihold(inode);
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	set_inode_flag(inode, FI_INC_LINK);
42762306a36Sopenharmony_ci	f2fs_lock_op(sbi);
42862306a36Sopenharmony_ci	err = f2fs_add_link(dentry, inode);
42962306a36Sopenharmony_ci	if (err)
43062306a36Sopenharmony_ci		goto out;
43162306a36Sopenharmony_ci	f2fs_unlock_op(sbi);
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci	d_instantiate(dentry, inode);
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	if (IS_DIRSYNC(dir))
43662306a36Sopenharmony_ci		f2fs_sync_fs(sbi->sb, 1);
43762306a36Sopenharmony_ci	return 0;
43862306a36Sopenharmony_ciout:
43962306a36Sopenharmony_ci	clear_inode_flag(inode, FI_INC_LINK);
44062306a36Sopenharmony_ci	iput(inode);
44162306a36Sopenharmony_ci	f2fs_unlock_op(sbi);
44262306a36Sopenharmony_ci	return err;
44362306a36Sopenharmony_ci}
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_cistruct dentry *f2fs_get_parent(struct dentry *child)
44662306a36Sopenharmony_ci{
44762306a36Sopenharmony_ci	struct page *page;
44862306a36Sopenharmony_ci	unsigned long ino = f2fs_inode_by_name(d_inode(child), &dotdot_name, &page);
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci	if (!ino) {
45162306a36Sopenharmony_ci		if (IS_ERR(page))
45262306a36Sopenharmony_ci			return ERR_CAST(page);
45362306a36Sopenharmony_ci		return ERR_PTR(-ENOENT);
45462306a36Sopenharmony_ci	}
45562306a36Sopenharmony_ci	return d_obtain_alias(f2fs_iget(child->d_sb, ino));
45662306a36Sopenharmony_ci}
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_cistatic int __recover_dot_dentries(struct inode *dir, nid_t pino)
45962306a36Sopenharmony_ci{
46062306a36Sopenharmony_ci	struct f2fs_sb_info *sbi = F2FS_I_SB(dir);
46162306a36Sopenharmony_ci	struct qstr dot = QSTR_INIT(".", 1);
46262306a36Sopenharmony_ci	struct qstr dotdot = QSTR_INIT("..", 2);
46362306a36Sopenharmony_ci	struct f2fs_dir_entry *de;
46462306a36Sopenharmony_ci	struct page *page;
46562306a36Sopenharmony_ci	int err = 0;
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci	if (f2fs_readonly(sbi->sb)) {
46862306a36Sopenharmony_ci		f2fs_info(sbi, "skip recovering inline_dots inode (ino:%lu, pino:%u) in readonly mountpoint",
46962306a36Sopenharmony_ci			  dir->i_ino, pino);
47062306a36Sopenharmony_ci		return 0;
47162306a36Sopenharmony_ci	}
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_ci	if (!S_ISDIR(dir->i_mode)) {
47462306a36Sopenharmony_ci		f2fs_err(sbi, "inconsistent inode status, skip recovering inline_dots inode (ino:%lu, i_mode:%u, pino:%u)",
47562306a36Sopenharmony_ci			  dir->i_ino, dir->i_mode, pino);
47662306a36Sopenharmony_ci		set_sbi_flag(sbi, SBI_NEED_FSCK);
47762306a36Sopenharmony_ci		return -ENOTDIR;
47862306a36Sopenharmony_ci	}
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci	err = f2fs_dquot_initialize(dir);
48162306a36Sopenharmony_ci	if (err)
48262306a36Sopenharmony_ci		return err;
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci	f2fs_balance_fs(sbi, true);
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci	f2fs_lock_op(sbi);
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_ci	de = f2fs_find_entry(dir, &dot, &page);
48962306a36Sopenharmony_ci	if (de) {
49062306a36Sopenharmony_ci		f2fs_put_page(page, 0);
49162306a36Sopenharmony_ci	} else if (IS_ERR(page)) {
49262306a36Sopenharmony_ci		err = PTR_ERR(page);
49362306a36Sopenharmony_ci		goto out;
49462306a36Sopenharmony_ci	} else {
49562306a36Sopenharmony_ci		err = f2fs_do_add_link(dir, &dot, NULL, dir->i_ino, S_IFDIR);
49662306a36Sopenharmony_ci		if (err)
49762306a36Sopenharmony_ci			goto out;
49862306a36Sopenharmony_ci	}
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ci	de = f2fs_find_entry(dir, &dotdot, &page);
50162306a36Sopenharmony_ci	if (de)
50262306a36Sopenharmony_ci		f2fs_put_page(page, 0);
50362306a36Sopenharmony_ci	else if (IS_ERR(page))
50462306a36Sopenharmony_ci		err = PTR_ERR(page);
50562306a36Sopenharmony_ci	else
50662306a36Sopenharmony_ci		err = f2fs_do_add_link(dir, &dotdot, NULL, pino, S_IFDIR);
50762306a36Sopenharmony_ciout:
50862306a36Sopenharmony_ci	if (!err)
50962306a36Sopenharmony_ci		clear_inode_flag(dir, FI_INLINE_DOTS);
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci	f2fs_unlock_op(sbi);
51262306a36Sopenharmony_ci	return err;
51362306a36Sopenharmony_ci}
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_cistatic struct dentry *f2fs_lookup(struct inode *dir, struct dentry *dentry,
51662306a36Sopenharmony_ci		unsigned int flags)
51762306a36Sopenharmony_ci{
51862306a36Sopenharmony_ci	struct inode *inode = NULL;
51962306a36Sopenharmony_ci	struct f2fs_dir_entry *de;
52062306a36Sopenharmony_ci	struct page *page;
52162306a36Sopenharmony_ci	struct dentry *new;
52262306a36Sopenharmony_ci	nid_t ino = -1;
52362306a36Sopenharmony_ci	int err = 0;
52462306a36Sopenharmony_ci	unsigned int root_ino = F2FS_ROOT_INO(F2FS_I_SB(dir));
52562306a36Sopenharmony_ci	struct f2fs_filename fname;
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci	trace_f2fs_lookup_start(dir, dentry, flags);
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci	if (dentry->d_name.len > F2FS_NAME_LEN) {
53062306a36Sopenharmony_ci		err = -ENAMETOOLONG;
53162306a36Sopenharmony_ci		goto out;
53262306a36Sopenharmony_ci	}
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci	err = f2fs_prepare_lookup(dir, dentry, &fname);
53562306a36Sopenharmony_ci	generic_set_encrypted_ci_d_ops(dentry);
53662306a36Sopenharmony_ci	if (err == -ENOENT)
53762306a36Sopenharmony_ci		goto out_splice;
53862306a36Sopenharmony_ci	if (err)
53962306a36Sopenharmony_ci		goto out;
54062306a36Sopenharmony_ci	de = __f2fs_find_entry(dir, &fname, &page);
54162306a36Sopenharmony_ci	f2fs_free_filename(&fname);
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci	if (!de) {
54462306a36Sopenharmony_ci		if (IS_ERR(page)) {
54562306a36Sopenharmony_ci			err = PTR_ERR(page);
54662306a36Sopenharmony_ci			goto out;
54762306a36Sopenharmony_ci		}
54862306a36Sopenharmony_ci		err = -ENOENT;
54962306a36Sopenharmony_ci		goto out_splice;
55062306a36Sopenharmony_ci	}
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ci	ino = le32_to_cpu(de->ino);
55362306a36Sopenharmony_ci	f2fs_put_page(page, 0);
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci	inode = f2fs_iget(dir->i_sb, ino);
55662306a36Sopenharmony_ci	if (IS_ERR(inode)) {
55762306a36Sopenharmony_ci		err = PTR_ERR(inode);
55862306a36Sopenharmony_ci		goto out;
55962306a36Sopenharmony_ci	}
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci	if ((dir->i_ino == root_ino) && f2fs_has_inline_dots(dir)) {
56262306a36Sopenharmony_ci		err = __recover_dot_dentries(dir, root_ino);
56362306a36Sopenharmony_ci		if (err)
56462306a36Sopenharmony_ci			goto out_iput;
56562306a36Sopenharmony_ci	}
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_ci	if (f2fs_has_inline_dots(inode)) {
56862306a36Sopenharmony_ci		err = __recover_dot_dentries(inode, dir->i_ino);
56962306a36Sopenharmony_ci		if (err)
57062306a36Sopenharmony_ci			goto out_iput;
57162306a36Sopenharmony_ci	}
57262306a36Sopenharmony_ci	if (IS_ENCRYPTED(dir) &&
57362306a36Sopenharmony_ci	    (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)) &&
57462306a36Sopenharmony_ci	    !fscrypt_has_permitted_context(dir, inode)) {
57562306a36Sopenharmony_ci		f2fs_warn(F2FS_I_SB(inode), "Inconsistent encryption contexts: %lu/%lu",
57662306a36Sopenharmony_ci			  dir->i_ino, inode->i_ino);
57762306a36Sopenharmony_ci		err = -EPERM;
57862306a36Sopenharmony_ci		goto out_iput;
57962306a36Sopenharmony_ci	}
58062306a36Sopenharmony_ciout_splice:
58162306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_UNICODE)
58262306a36Sopenharmony_ci	if (!inode && IS_CASEFOLDED(dir)) {
58362306a36Sopenharmony_ci		/* Eventually we want to call d_add_ci(dentry, NULL)
58462306a36Sopenharmony_ci		 * for negative dentries in the encoding case as
58562306a36Sopenharmony_ci		 * well.  For now, prevent the negative dentry
58662306a36Sopenharmony_ci		 * from being cached.
58762306a36Sopenharmony_ci		 */
58862306a36Sopenharmony_ci		trace_f2fs_lookup_end(dir, dentry, ino, err);
58962306a36Sopenharmony_ci		return NULL;
59062306a36Sopenharmony_ci	}
59162306a36Sopenharmony_ci#endif
59262306a36Sopenharmony_ci	new = d_splice_alias(inode, dentry);
59362306a36Sopenharmony_ci	trace_f2fs_lookup_end(dir, !IS_ERR_OR_NULL(new) ? new : dentry,
59462306a36Sopenharmony_ci				ino, IS_ERR(new) ? PTR_ERR(new) : err);
59562306a36Sopenharmony_ci	return new;
59662306a36Sopenharmony_ciout_iput:
59762306a36Sopenharmony_ci	iput(inode);
59862306a36Sopenharmony_ciout:
59962306a36Sopenharmony_ci	trace_f2fs_lookup_end(dir, dentry, ino, err);
60062306a36Sopenharmony_ci	return ERR_PTR(err);
60162306a36Sopenharmony_ci}
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_cistatic int f2fs_unlink(struct inode *dir, struct dentry *dentry)
60462306a36Sopenharmony_ci{
60562306a36Sopenharmony_ci	struct f2fs_sb_info *sbi = F2FS_I_SB(dir);
60662306a36Sopenharmony_ci	struct inode *inode = d_inode(dentry);
60762306a36Sopenharmony_ci	struct f2fs_dir_entry *de;
60862306a36Sopenharmony_ci	struct page *page;
60962306a36Sopenharmony_ci	int err;
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ci	trace_f2fs_unlink_enter(dir, dentry);
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci	if (unlikely(f2fs_cp_error(sbi))) {
61462306a36Sopenharmony_ci		err = -EIO;
61562306a36Sopenharmony_ci		goto fail;
61662306a36Sopenharmony_ci	}
61762306a36Sopenharmony_ci
61862306a36Sopenharmony_ci	err = f2fs_dquot_initialize(dir);
61962306a36Sopenharmony_ci	if (err)
62062306a36Sopenharmony_ci		goto fail;
62162306a36Sopenharmony_ci	err = f2fs_dquot_initialize(inode);
62262306a36Sopenharmony_ci	if (err)
62362306a36Sopenharmony_ci		goto fail;
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_ci	de = f2fs_find_entry(dir, &dentry->d_name, &page);
62662306a36Sopenharmony_ci	if (!de) {
62762306a36Sopenharmony_ci		if (IS_ERR(page))
62862306a36Sopenharmony_ci			err = PTR_ERR(page);
62962306a36Sopenharmony_ci		goto fail;
63062306a36Sopenharmony_ci	}
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ci	f2fs_balance_fs(sbi, true);
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_ci	f2fs_lock_op(sbi);
63562306a36Sopenharmony_ci	err = f2fs_acquire_orphan_inode(sbi);
63662306a36Sopenharmony_ci	if (err) {
63762306a36Sopenharmony_ci		f2fs_unlock_op(sbi);
63862306a36Sopenharmony_ci		f2fs_put_page(page, 0);
63962306a36Sopenharmony_ci		goto fail;
64062306a36Sopenharmony_ci	}
64162306a36Sopenharmony_ci	f2fs_delete_entry(de, page, dir, inode);
64262306a36Sopenharmony_ci	f2fs_unlock_op(sbi);
64362306a36Sopenharmony_ci
64462306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_UNICODE)
64562306a36Sopenharmony_ci	/* VFS negative dentries are incompatible with Encoding and
64662306a36Sopenharmony_ci	 * Case-insensitiveness. Eventually we'll want avoid
64762306a36Sopenharmony_ci	 * invalidating the dentries here, alongside with returning the
64862306a36Sopenharmony_ci	 * negative dentries at f2fs_lookup(), when it is better
64962306a36Sopenharmony_ci	 * supported by the VFS for the CI case.
65062306a36Sopenharmony_ci	 */
65162306a36Sopenharmony_ci	if (IS_CASEFOLDED(dir))
65262306a36Sopenharmony_ci		d_invalidate(dentry);
65362306a36Sopenharmony_ci#endif
65462306a36Sopenharmony_ci	if (IS_DIRSYNC(dir))
65562306a36Sopenharmony_ci		f2fs_sync_fs(sbi->sb, 1);
65662306a36Sopenharmony_cifail:
65762306a36Sopenharmony_ci	trace_f2fs_unlink_exit(inode, err);
65862306a36Sopenharmony_ci	return err;
65962306a36Sopenharmony_ci}
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_cistatic const char *f2fs_get_link(struct dentry *dentry,
66262306a36Sopenharmony_ci				 struct inode *inode,
66362306a36Sopenharmony_ci				 struct delayed_call *done)
66462306a36Sopenharmony_ci{
66562306a36Sopenharmony_ci	const char *link = page_get_link(dentry, inode, done);
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_ci	if (!IS_ERR(link) && !*link) {
66862306a36Sopenharmony_ci		/* this is broken symlink case */
66962306a36Sopenharmony_ci		do_delayed_call(done);
67062306a36Sopenharmony_ci		clear_delayed_call(done);
67162306a36Sopenharmony_ci		link = ERR_PTR(-ENOENT);
67262306a36Sopenharmony_ci	}
67362306a36Sopenharmony_ci	return link;
67462306a36Sopenharmony_ci}
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_cistatic int f2fs_symlink(struct mnt_idmap *idmap, struct inode *dir,
67762306a36Sopenharmony_ci			struct dentry *dentry, const char *symname)
67862306a36Sopenharmony_ci{
67962306a36Sopenharmony_ci	struct f2fs_sb_info *sbi = F2FS_I_SB(dir);
68062306a36Sopenharmony_ci	struct inode *inode;
68162306a36Sopenharmony_ci	size_t len = strlen(symname);
68262306a36Sopenharmony_ci	struct fscrypt_str disk_link;
68362306a36Sopenharmony_ci	int err;
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_ci	if (unlikely(f2fs_cp_error(sbi)))
68662306a36Sopenharmony_ci		return -EIO;
68762306a36Sopenharmony_ci	if (!f2fs_is_checkpoint_ready(sbi))
68862306a36Sopenharmony_ci		return -ENOSPC;
68962306a36Sopenharmony_ci
69062306a36Sopenharmony_ci	err = fscrypt_prepare_symlink(dir, symname, len, dir->i_sb->s_blocksize,
69162306a36Sopenharmony_ci				      &disk_link);
69262306a36Sopenharmony_ci	if (err)
69362306a36Sopenharmony_ci		return err;
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_ci	err = f2fs_dquot_initialize(dir);
69662306a36Sopenharmony_ci	if (err)
69762306a36Sopenharmony_ci		return err;
69862306a36Sopenharmony_ci
69962306a36Sopenharmony_ci	inode = f2fs_new_inode(idmap, dir, S_IFLNK | S_IRWXUGO, NULL);
70062306a36Sopenharmony_ci	if (IS_ERR(inode))
70162306a36Sopenharmony_ci		return PTR_ERR(inode);
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_ci	if (IS_ENCRYPTED(inode))
70462306a36Sopenharmony_ci		inode->i_op = &f2fs_encrypted_symlink_inode_operations;
70562306a36Sopenharmony_ci	else
70662306a36Sopenharmony_ci		inode->i_op = &f2fs_symlink_inode_operations;
70762306a36Sopenharmony_ci	inode_nohighmem(inode);
70862306a36Sopenharmony_ci	inode->i_mapping->a_ops = &f2fs_dblock_aops;
70962306a36Sopenharmony_ci
71062306a36Sopenharmony_ci	f2fs_lock_op(sbi);
71162306a36Sopenharmony_ci	err = f2fs_add_link(dentry, inode);
71262306a36Sopenharmony_ci	if (err)
71362306a36Sopenharmony_ci		goto out_f2fs_handle_failed_inode;
71462306a36Sopenharmony_ci	f2fs_unlock_op(sbi);
71562306a36Sopenharmony_ci	f2fs_alloc_nid_done(sbi, inode->i_ino);
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_ci	err = fscrypt_encrypt_symlink(inode, symname, len, &disk_link);
71862306a36Sopenharmony_ci	if (err)
71962306a36Sopenharmony_ci		goto err_out;
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_ci	err = page_symlink(inode, disk_link.name, disk_link.len);
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_cierr_out:
72462306a36Sopenharmony_ci	d_instantiate_new(dentry, inode);
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_ci	/*
72762306a36Sopenharmony_ci	 * Let's flush symlink data in order to avoid broken symlink as much as
72862306a36Sopenharmony_ci	 * possible. Nevertheless, fsyncing is the best way, but there is no
72962306a36Sopenharmony_ci	 * way to get a file descriptor in order to flush that.
73062306a36Sopenharmony_ci	 *
73162306a36Sopenharmony_ci	 * Note that, it needs to do dir->fsync to make this recoverable.
73262306a36Sopenharmony_ci	 * If the symlink path is stored into inline_data, there is no
73362306a36Sopenharmony_ci	 * performance regression.
73462306a36Sopenharmony_ci	 */
73562306a36Sopenharmony_ci	if (!err) {
73662306a36Sopenharmony_ci		filemap_write_and_wait_range(inode->i_mapping, 0,
73762306a36Sopenharmony_ci							disk_link.len - 1);
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_ci		if (IS_DIRSYNC(dir))
74062306a36Sopenharmony_ci			f2fs_sync_fs(sbi->sb, 1);
74162306a36Sopenharmony_ci	} else {
74262306a36Sopenharmony_ci		f2fs_unlink(dir, dentry);
74362306a36Sopenharmony_ci	}
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_ci	f2fs_balance_fs(sbi, true);
74662306a36Sopenharmony_ci	goto out_free_encrypted_link;
74762306a36Sopenharmony_ci
74862306a36Sopenharmony_ciout_f2fs_handle_failed_inode:
74962306a36Sopenharmony_ci	f2fs_handle_failed_inode(inode);
75062306a36Sopenharmony_ciout_free_encrypted_link:
75162306a36Sopenharmony_ci	if (disk_link.name != (unsigned char *)symname)
75262306a36Sopenharmony_ci		kfree(disk_link.name);
75362306a36Sopenharmony_ci	return err;
75462306a36Sopenharmony_ci}
75562306a36Sopenharmony_ci
75662306a36Sopenharmony_cistatic int f2fs_mkdir(struct mnt_idmap *idmap, struct inode *dir,
75762306a36Sopenharmony_ci		      struct dentry *dentry, umode_t mode)
75862306a36Sopenharmony_ci{
75962306a36Sopenharmony_ci	struct f2fs_sb_info *sbi = F2FS_I_SB(dir);
76062306a36Sopenharmony_ci	struct inode *inode;
76162306a36Sopenharmony_ci	int err;
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_ci	if (unlikely(f2fs_cp_error(sbi)))
76462306a36Sopenharmony_ci		return -EIO;
76562306a36Sopenharmony_ci
76662306a36Sopenharmony_ci	err = f2fs_dquot_initialize(dir);
76762306a36Sopenharmony_ci	if (err)
76862306a36Sopenharmony_ci		return err;
76962306a36Sopenharmony_ci
77062306a36Sopenharmony_ci	inode = f2fs_new_inode(idmap, dir, S_IFDIR | mode, NULL);
77162306a36Sopenharmony_ci	if (IS_ERR(inode))
77262306a36Sopenharmony_ci		return PTR_ERR(inode);
77362306a36Sopenharmony_ci
77462306a36Sopenharmony_ci	inode->i_op = &f2fs_dir_inode_operations;
77562306a36Sopenharmony_ci	inode->i_fop = &f2fs_dir_operations;
77662306a36Sopenharmony_ci	inode->i_mapping->a_ops = &f2fs_dblock_aops;
77762306a36Sopenharmony_ci	mapping_set_gfp_mask(inode->i_mapping, GFP_NOFS);
77862306a36Sopenharmony_ci
77962306a36Sopenharmony_ci	set_inode_flag(inode, FI_INC_LINK);
78062306a36Sopenharmony_ci	f2fs_lock_op(sbi);
78162306a36Sopenharmony_ci	err = f2fs_add_link(dentry, inode);
78262306a36Sopenharmony_ci	if (err)
78362306a36Sopenharmony_ci		goto out_fail;
78462306a36Sopenharmony_ci	f2fs_unlock_op(sbi);
78562306a36Sopenharmony_ci
78662306a36Sopenharmony_ci	f2fs_alloc_nid_done(sbi, inode->i_ino);
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_ci	d_instantiate_new(dentry, inode);
78962306a36Sopenharmony_ci
79062306a36Sopenharmony_ci	if (IS_DIRSYNC(dir))
79162306a36Sopenharmony_ci		f2fs_sync_fs(sbi->sb, 1);
79262306a36Sopenharmony_ci
79362306a36Sopenharmony_ci	f2fs_balance_fs(sbi, true);
79462306a36Sopenharmony_ci	return 0;
79562306a36Sopenharmony_ci
79662306a36Sopenharmony_ciout_fail:
79762306a36Sopenharmony_ci	clear_inode_flag(inode, FI_INC_LINK);
79862306a36Sopenharmony_ci	f2fs_handle_failed_inode(inode);
79962306a36Sopenharmony_ci	return err;
80062306a36Sopenharmony_ci}
80162306a36Sopenharmony_ci
80262306a36Sopenharmony_cistatic int f2fs_rmdir(struct inode *dir, struct dentry *dentry)
80362306a36Sopenharmony_ci{
80462306a36Sopenharmony_ci	struct inode *inode = d_inode(dentry);
80562306a36Sopenharmony_ci
80662306a36Sopenharmony_ci	if (f2fs_empty_dir(inode))
80762306a36Sopenharmony_ci		return f2fs_unlink(dir, dentry);
80862306a36Sopenharmony_ci	return -ENOTEMPTY;
80962306a36Sopenharmony_ci}
81062306a36Sopenharmony_ci
81162306a36Sopenharmony_cistatic int f2fs_mknod(struct mnt_idmap *idmap, struct inode *dir,
81262306a36Sopenharmony_ci		      struct dentry *dentry, umode_t mode, dev_t rdev)
81362306a36Sopenharmony_ci{
81462306a36Sopenharmony_ci	struct f2fs_sb_info *sbi = F2FS_I_SB(dir);
81562306a36Sopenharmony_ci	struct inode *inode;
81662306a36Sopenharmony_ci	int err = 0;
81762306a36Sopenharmony_ci
81862306a36Sopenharmony_ci	if (unlikely(f2fs_cp_error(sbi)))
81962306a36Sopenharmony_ci		return -EIO;
82062306a36Sopenharmony_ci	if (!f2fs_is_checkpoint_ready(sbi))
82162306a36Sopenharmony_ci		return -ENOSPC;
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_ci	err = f2fs_dquot_initialize(dir);
82462306a36Sopenharmony_ci	if (err)
82562306a36Sopenharmony_ci		return err;
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_ci	inode = f2fs_new_inode(idmap, dir, mode, NULL);
82862306a36Sopenharmony_ci	if (IS_ERR(inode))
82962306a36Sopenharmony_ci		return PTR_ERR(inode);
83062306a36Sopenharmony_ci
83162306a36Sopenharmony_ci	init_special_inode(inode, inode->i_mode, rdev);
83262306a36Sopenharmony_ci	inode->i_op = &f2fs_special_inode_operations;
83362306a36Sopenharmony_ci
83462306a36Sopenharmony_ci	f2fs_lock_op(sbi);
83562306a36Sopenharmony_ci	err = f2fs_add_link(dentry, inode);
83662306a36Sopenharmony_ci	if (err)
83762306a36Sopenharmony_ci		goto out;
83862306a36Sopenharmony_ci	f2fs_unlock_op(sbi);
83962306a36Sopenharmony_ci
84062306a36Sopenharmony_ci	f2fs_alloc_nid_done(sbi, inode->i_ino);
84162306a36Sopenharmony_ci
84262306a36Sopenharmony_ci	d_instantiate_new(dentry, inode);
84362306a36Sopenharmony_ci
84462306a36Sopenharmony_ci	if (IS_DIRSYNC(dir))
84562306a36Sopenharmony_ci		f2fs_sync_fs(sbi->sb, 1);
84662306a36Sopenharmony_ci
84762306a36Sopenharmony_ci	f2fs_balance_fs(sbi, true);
84862306a36Sopenharmony_ci	return 0;
84962306a36Sopenharmony_ciout:
85062306a36Sopenharmony_ci	f2fs_handle_failed_inode(inode);
85162306a36Sopenharmony_ci	return err;
85262306a36Sopenharmony_ci}
85362306a36Sopenharmony_ci
85462306a36Sopenharmony_cistatic int __f2fs_tmpfile(struct mnt_idmap *idmap, struct inode *dir,
85562306a36Sopenharmony_ci			  struct file *file, umode_t mode, bool is_whiteout,
85662306a36Sopenharmony_ci			  struct inode **new_inode, struct f2fs_filename *fname)
85762306a36Sopenharmony_ci{
85862306a36Sopenharmony_ci	struct f2fs_sb_info *sbi = F2FS_I_SB(dir);
85962306a36Sopenharmony_ci	struct inode *inode;
86062306a36Sopenharmony_ci	int err;
86162306a36Sopenharmony_ci
86262306a36Sopenharmony_ci	err = f2fs_dquot_initialize(dir);
86362306a36Sopenharmony_ci	if (err)
86462306a36Sopenharmony_ci		return err;
86562306a36Sopenharmony_ci
86662306a36Sopenharmony_ci	inode = f2fs_new_inode(idmap, dir, mode, NULL);
86762306a36Sopenharmony_ci	if (IS_ERR(inode))
86862306a36Sopenharmony_ci		return PTR_ERR(inode);
86962306a36Sopenharmony_ci
87062306a36Sopenharmony_ci	if (is_whiteout) {
87162306a36Sopenharmony_ci		init_special_inode(inode, inode->i_mode, WHITEOUT_DEV);
87262306a36Sopenharmony_ci		inode->i_op = &f2fs_special_inode_operations;
87362306a36Sopenharmony_ci	} else {
87462306a36Sopenharmony_ci		inode->i_op = &f2fs_file_inode_operations;
87562306a36Sopenharmony_ci		inode->i_fop = &f2fs_file_operations;
87662306a36Sopenharmony_ci		inode->i_mapping->a_ops = &f2fs_dblock_aops;
87762306a36Sopenharmony_ci	}
87862306a36Sopenharmony_ci
87962306a36Sopenharmony_ci	f2fs_lock_op(sbi);
88062306a36Sopenharmony_ci	err = f2fs_acquire_orphan_inode(sbi);
88162306a36Sopenharmony_ci	if (err)
88262306a36Sopenharmony_ci		goto out;
88362306a36Sopenharmony_ci
88462306a36Sopenharmony_ci	err = f2fs_do_tmpfile(inode, dir, fname);
88562306a36Sopenharmony_ci	if (err)
88662306a36Sopenharmony_ci		goto release_out;
88762306a36Sopenharmony_ci
88862306a36Sopenharmony_ci	/*
88962306a36Sopenharmony_ci	 * add this non-linked tmpfile to orphan list, in this way we could
89062306a36Sopenharmony_ci	 * remove all unused data of tmpfile after abnormal power-off.
89162306a36Sopenharmony_ci	 */
89262306a36Sopenharmony_ci	f2fs_add_orphan_inode(inode);
89362306a36Sopenharmony_ci	f2fs_alloc_nid_done(sbi, inode->i_ino);
89462306a36Sopenharmony_ci
89562306a36Sopenharmony_ci	if (is_whiteout) {
89662306a36Sopenharmony_ci		f2fs_i_links_write(inode, false);
89762306a36Sopenharmony_ci
89862306a36Sopenharmony_ci		spin_lock(&inode->i_lock);
89962306a36Sopenharmony_ci		inode->i_state |= I_LINKABLE;
90062306a36Sopenharmony_ci		spin_unlock(&inode->i_lock);
90162306a36Sopenharmony_ci	} else {
90262306a36Sopenharmony_ci		if (file)
90362306a36Sopenharmony_ci			d_tmpfile(file, inode);
90462306a36Sopenharmony_ci		else
90562306a36Sopenharmony_ci			f2fs_i_links_write(inode, false);
90662306a36Sopenharmony_ci	}
90762306a36Sopenharmony_ci	/* link_count was changed by d_tmpfile as well. */
90862306a36Sopenharmony_ci	f2fs_unlock_op(sbi);
90962306a36Sopenharmony_ci	unlock_new_inode(inode);
91062306a36Sopenharmony_ci
91162306a36Sopenharmony_ci	if (new_inode)
91262306a36Sopenharmony_ci		*new_inode = inode;
91362306a36Sopenharmony_ci
91462306a36Sopenharmony_ci	f2fs_balance_fs(sbi, true);
91562306a36Sopenharmony_ci	return 0;
91662306a36Sopenharmony_ci
91762306a36Sopenharmony_cirelease_out:
91862306a36Sopenharmony_ci	f2fs_release_orphan_inode(sbi);
91962306a36Sopenharmony_ciout:
92062306a36Sopenharmony_ci	f2fs_handle_failed_inode(inode);
92162306a36Sopenharmony_ci	return err;
92262306a36Sopenharmony_ci}
92362306a36Sopenharmony_ci
92462306a36Sopenharmony_cistatic int f2fs_tmpfile(struct mnt_idmap *idmap, struct inode *dir,
92562306a36Sopenharmony_ci			struct file *file, umode_t mode)
92662306a36Sopenharmony_ci{
92762306a36Sopenharmony_ci	struct f2fs_sb_info *sbi = F2FS_I_SB(dir);
92862306a36Sopenharmony_ci	int err;
92962306a36Sopenharmony_ci
93062306a36Sopenharmony_ci	if (unlikely(f2fs_cp_error(sbi)))
93162306a36Sopenharmony_ci		return -EIO;
93262306a36Sopenharmony_ci	if (!f2fs_is_checkpoint_ready(sbi))
93362306a36Sopenharmony_ci		return -ENOSPC;
93462306a36Sopenharmony_ci
93562306a36Sopenharmony_ci	err = __f2fs_tmpfile(idmap, dir, file, mode, false, NULL, NULL);
93662306a36Sopenharmony_ci
93762306a36Sopenharmony_ci	return finish_open_simple(file, err);
93862306a36Sopenharmony_ci}
93962306a36Sopenharmony_ci
94062306a36Sopenharmony_cistatic int f2fs_create_whiteout(struct mnt_idmap *idmap,
94162306a36Sopenharmony_ci				struct inode *dir, struct inode **whiteout,
94262306a36Sopenharmony_ci				struct f2fs_filename *fname)
94362306a36Sopenharmony_ci{
94462306a36Sopenharmony_ci	return __f2fs_tmpfile(idmap, dir, NULL, S_IFCHR | WHITEOUT_MODE,
94562306a36Sopenharmony_ci						true, whiteout, fname);
94662306a36Sopenharmony_ci}
94762306a36Sopenharmony_ci
94862306a36Sopenharmony_ciint f2fs_get_tmpfile(struct mnt_idmap *idmap, struct inode *dir,
94962306a36Sopenharmony_ci		     struct inode **new_inode)
95062306a36Sopenharmony_ci{
95162306a36Sopenharmony_ci	return __f2fs_tmpfile(idmap, dir, NULL, S_IFREG,
95262306a36Sopenharmony_ci				false, new_inode, NULL);
95362306a36Sopenharmony_ci}
95462306a36Sopenharmony_ci
95562306a36Sopenharmony_cistatic int f2fs_rename(struct mnt_idmap *idmap, struct inode *old_dir,
95662306a36Sopenharmony_ci			struct dentry *old_dentry, struct inode *new_dir,
95762306a36Sopenharmony_ci			struct dentry *new_dentry, unsigned int flags)
95862306a36Sopenharmony_ci{
95962306a36Sopenharmony_ci	struct f2fs_sb_info *sbi = F2FS_I_SB(old_dir);
96062306a36Sopenharmony_ci	struct inode *old_inode = d_inode(old_dentry);
96162306a36Sopenharmony_ci	struct inode *new_inode = d_inode(new_dentry);
96262306a36Sopenharmony_ci	struct inode *whiteout = NULL;
96362306a36Sopenharmony_ci	struct page *old_dir_page = NULL;
96462306a36Sopenharmony_ci	struct page *old_page, *new_page = NULL;
96562306a36Sopenharmony_ci	struct f2fs_dir_entry *old_dir_entry = NULL;
96662306a36Sopenharmony_ci	struct f2fs_dir_entry *old_entry;
96762306a36Sopenharmony_ci	struct f2fs_dir_entry *new_entry;
96862306a36Sopenharmony_ci	int err;
96962306a36Sopenharmony_ci
97062306a36Sopenharmony_ci	if (unlikely(f2fs_cp_error(sbi)))
97162306a36Sopenharmony_ci		return -EIO;
97262306a36Sopenharmony_ci	if (!f2fs_is_checkpoint_ready(sbi))
97362306a36Sopenharmony_ci		return -ENOSPC;
97462306a36Sopenharmony_ci
97562306a36Sopenharmony_ci	if (is_inode_flag_set(new_dir, FI_PROJ_INHERIT) &&
97662306a36Sopenharmony_ci			(!projid_eq(F2FS_I(new_dir)->i_projid,
97762306a36Sopenharmony_ci			F2FS_I(old_dentry->d_inode)->i_projid)))
97862306a36Sopenharmony_ci		return -EXDEV;
97962306a36Sopenharmony_ci
98062306a36Sopenharmony_ci	/*
98162306a36Sopenharmony_ci	 * If new_inode is null, the below renaming flow will
98262306a36Sopenharmony_ci	 * add a link in old_dir which can convert inline_dir.
98362306a36Sopenharmony_ci	 * After then, if we failed to get the entry due to other
98462306a36Sopenharmony_ci	 * reasons like ENOMEM, we had to remove the new entry.
98562306a36Sopenharmony_ci	 * Instead of adding such the error handling routine, let's
98662306a36Sopenharmony_ci	 * simply convert first here.
98762306a36Sopenharmony_ci	 */
98862306a36Sopenharmony_ci	if (old_dir == new_dir && !new_inode) {
98962306a36Sopenharmony_ci		err = f2fs_try_convert_inline_dir(old_dir, new_dentry);
99062306a36Sopenharmony_ci		if (err)
99162306a36Sopenharmony_ci			return err;
99262306a36Sopenharmony_ci	}
99362306a36Sopenharmony_ci
99462306a36Sopenharmony_ci	if (flags & RENAME_WHITEOUT) {
99562306a36Sopenharmony_ci		struct f2fs_filename fname;
99662306a36Sopenharmony_ci
99762306a36Sopenharmony_ci		err = f2fs_setup_filename(old_dir, &old_dentry->d_name,
99862306a36Sopenharmony_ci							0, &fname);
99962306a36Sopenharmony_ci		if (err)
100062306a36Sopenharmony_ci			return err;
100162306a36Sopenharmony_ci
100262306a36Sopenharmony_ci		err = f2fs_create_whiteout(idmap, old_dir, &whiteout, &fname);
100362306a36Sopenharmony_ci		if (err)
100462306a36Sopenharmony_ci			return err;
100562306a36Sopenharmony_ci	}
100662306a36Sopenharmony_ci
100762306a36Sopenharmony_ci	err = f2fs_dquot_initialize(old_dir);
100862306a36Sopenharmony_ci	if (err)
100962306a36Sopenharmony_ci		goto out;
101062306a36Sopenharmony_ci
101162306a36Sopenharmony_ci	err = f2fs_dquot_initialize(new_dir);
101262306a36Sopenharmony_ci	if (err)
101362306a36Sopenharmony_ci		goto out;
101462306a36Sopenharmony_ci
101562306a36Sopenharmony_ci	if (new_inode) {
101662306a36Sopenharmony_ci		err = f2fs_dquot_initialize(new_inode);
101762306a36Sopenharmony_ci		if (err)
101862306a36Sopenharmony_ci			goto out;
101962306a36Sopenharmony_ci	}
102062306a36Sopenharmony_ci
102162306a36Sopenharmony_ci	err = -ENOENT;
102262306a36Sopenharmony_ci	old_entry = f2fs_find_entry(old_dir, &old_dentry->d_name, &old_page);
102362306a36Sopenharmony_ci	if (!old_entry) {
102462306a36Sopenharmony_ci		if (IS_ERR(old_page))
102562306a36Sopenharmony_ci			err = PTR_ERR(old_page);
102662306a36Sopenharmony_ci		goto out;
102762306a36Sopenharmony_ci	}
102862306a36Sopenharmony_ci
102962306a36Sopenharmony_ci	if (S_ISDIR(old_inode->i_mode)) {
103062306a36Sopenharmony_ci		old_dir_entry = f2fs_parent_dir(old_inode, &old_dir_page);
103162306a36Sopenharmony_ci		if (!old_dir_entry) {
103262306a36Sopenharmony_ci			if (IS_ERR(old_dir_page))
103362306a36Sopenharmony_ci				err = PTR_ERR(old_dir_page);
103462306a36Sopenharmony_ci			goto out_old;
103562306a36Sopenharmony_ci		}
103662306a36Sopenharmony_ci	}
103762306a36Sopenharmony_ci
103862306a36Sopenharmony_ci	if (new_inode) {
103962306a36Sopenharmony_ci
104062306a36Sopenharmony_ci		err = -ENOTEMPTY;
104162306a36Sopenharmony_ci		if (old_dir_entry && !f2fs_empty_dir(new_inode))
104262306a36Sopenharmony_ci			goto out_dir;
104362306a36Sopenharmony_ci
104462306a36Sopenharmony_ci		err = -ENOENT;
104562306a36Sopenharmony_ci		new_entry = f2fs_find_entry(new_dir, &new_dentry->d_name,
104662306a36Sopenharmony_ci						&new_page);
104762306a36Sopenharmony_ci		if (!new_entry) {
104862306a36Sopenharmony_ci			if (IS_ERR(new_page))
104962306a36Sopenharmony_ci				err = PTR_ERR(new_page);
105062306a36Sopenharmony_ci			goto out_dir;
105162306a36Sopenharmony_ci		}
105262306a36Sopenharmony_ci
105362306a36Sopenharmony_ci		f2fs_balance_fs(sbi, true);
105462306a36Sopenharmony_ci
105562306a36Sopenharmony_ci		f2fs_lock_op(sbi);
105662306a36Sopenharmony_ci
105762306a36Sopenharmony_ci		err = f2fs_acquire_orphan_inode(sbi);
105862306a36Sopenharmony_ci		if (err)
105962306a36Sopenharmony_ci			goto put_out_dir;
106062306a36Sopenharmony_ci
106162306a36Sopenharmony_ci		f2fs_set_link(new_dir, new_entry, new_page, old_inode);
106262306a36Sopenharmony_ci		new_page = NULL;
106362306a36Sopenharmony_ci
106462306a36Sopenharmony_ci		inode_set_ctime_current(new_inode);
106562306a36Sopenharmony_ci		f2fs_down_write(&F2FS_I(new_inode)->i_sem);
106662306a36Sopenharmony_ci		if (old_dir_entry)
106762306a36Sopenharmony_ci			f2fs_i_links_write(new_inode, false);
106862306a36Sopenharmony_ci		f2fs_i_links_write(new_inode, false);
106962306a36Sopenharmony_ci		f2fs_up_write(&F2FS_I(new_inode)->i_sem);
107062306a36Sopenharmony_ci
107162306a36Sopenharmony_ci		if (!new_inode->i_nlink)
107262306a36Sopenharmony_ci			f2fs_add_orphan_inode(new_inode);
107362306a36Sopenharmony_ci		else
107462306a36Sopenharmony_ci			f2fs_release_orphan_inode(sbi);
107562306a36Sopenharmony_ci	} else {
107662306a36Sopenharmony_ci		f2fs_balance_fs(sbi, true);
107762306a36Sopenharmony_ci
107862306a36Sopenharmony_ci		f2fs_lock_op(sbi);
107962306a36Sopenharmony_ci
108062306a36Sopenharmony_ci		err = f2fs_add_link(new_dentry, old_inode);
108162306a36Sopenharmony_ci		if (err) {
108262306a36Sopenharmony_ci			f2fs_unlock_op(sbi);
108362306a36Sopenharmony_ci			goto out_dir;
108462306a36Sopenharmony_ci		}
108562306a36Sopenharmony_ci
108662306a36Sopenharmony_ci		if (old_dir_entry)
108762306a36Sopenharmony_ci			f2fs_i_links_write(new_dir, true);
108862306a36Sopenharmony_ci	}
108962306a36Sopenharmony_ci
109062306a36Sopenharmony_ci	f2fs_down_write(&F2FS_I(old_inode)->i_sem);
109162306a36Sopenharmony_ci	if (!old_dir_entry || whiteout)
109262306a36Sopenharmony_ci		file_lost_pino(old_inode);
109362306a36Sopenharmony_ci	else
109462306a36Sopenharmony_ci		/* adjust dir's i_pino to pass fsck check */
109562306a36Sopenharmony_ci		f2fs_i_pino_write(old_inode, new_dir->i_ino);
109662306a36Sopenharmony_ci	f2fs_up_write(&F2FS_I(old_inode)->i_sem);
109762306a36Sopenharmony_ci
109862306a36Sopenharmony_ci	inode_set_ctime_current(old_inode);
109962306a36Sopenharmony_ci	f2fs_mark_inode_dirty_sync(old_inode, false);
110062306a36Sopenharmony_ci
110162306a36Sopenharmony_ci	f2fs_delete_entry(old_entry, old_page, old_dir, NULL);
110262306a36Sopenharmony_ci	old_page = NULL;
110362306a36Sopenharmony_ci
110462306a36Sopenharmony_ci	if (whiteout) {
110562306a36Sopenharmony_ci		set_inode_flag(whiteout, FI_INC_LINK);
110662306a36Sopenharmony_ci		err = f2fs_add_link(old_dentry, whiteout);
110762306a36Sopenharmony_ci		if (err)
110862306a36Sopenharmony_ci			goto put_out_dir;
110962306a36Sopenharmony_ci
111062306a36Sopenharmony_ci		spin_lock(&whiteout->i_lock);
111162306a36Sopenharmony_ci		whiteout->i_state &= ~I_LINKABLE;
111262306a36Sopenharmony_ci		spin_unlock(&whiteout->i_lock);
111362306a36Sopenharmony_ci
111462306a36Sopenharmony_ci		iput(whiteout);
111562306a36Sopenharmony_ci	}
111662306a36Sopenharmony_ci
111762306a36Sopenharmony_ci	if (old_dir_entry) {
111862306a36Sopenharmony_ci		if (old_dir != new_dir)
111962306a36Sopenharmony_ci			f2fs_set_link(old_inode, old_dir_entry,
112062306a36Sopenharmony_ci						old_dir_page, new_dir);
112162306a36Sopenharmony_ci		else
112262306a36Sopenharmony_ci			f2fs_put_page(old_dir_page, 0);
112362306a36Sopenharmony_ci		f2fs_i_links_write(old_dir, false);
112462306a36Sopenharmony_ci	}
112562306a36Sopenharmony_ci	if (F2FS_OPTION(sbi).fsync_mode == FSYNC_MODE_STRICT) {
112662306a36Sopenharmony_ci		f2fs_add_ino_entry(sbi, new_dir->i_ino, TRANS_DIR_INO);
112762306a36Sopenharmony_ci		if (S_ISDIR(old_inode->i_mode))
112862306a36Sopenharmony_ci			f2fs_add_ino_entry(sbi, old_inode->i_ino,
112962306a36Sopenharmony_ci							TRANS_DIR_INO);
113062306a36Sopenharmony_ci	}
113162306a36Sopenharmony_ci
113262306a36Sopenharmony_ci	f2fs_unlock_op(sbi);
113362306a36Sopenharmony_ci
113462306a36Sopenharmony_ci	if (IS_DIRSYNC(old_dir) || IS_DIRSYNC(new_dir))
113562306a36Sopenharmony_ci		f2fs_sync_fs(sbi->sb, 1);
113662306a36Sopenharmony_ci
113762306a36Sopenharmony_ci	f2fs_update_time(sbi, REQ_TIME);
113862306a36Sopenharmony_ci	return 0;
113962306a36Sopenharmony_ci
114062306a36Sopenharmony_ciput_out_dir:
114162306a36Sopenharmony_ci	f2fs_unlock_op(sbi);
114262306a36Sopenharmony_ci	f2fs_put_page(new_page, 0);
114362306a36Sopenharmony_ciout_dir:
114462306a36Sopenharmony_ci	if (old_dir_entry)
114562306a36Sopenharmony_ci		f2fs_put_page(old_dir_page, 0);
114662306a36Sopenharmony_ciout_old:
114762306a36Sopenharmony_ci	f2fs_put_page(old_page, 0);
114862306a36Sopenharmony_ciout:
114962306a36Sopenharmony_ci	iput(whiteout);
115062306a36Sopenharmony_ci	return err;
115162306a36Sopenharmony_ci}
115262306a36Sopenharmony_ci
115362306a36Sopenharmony_cistatic int f2fs_cross_rename(struct inode *old_dir, struct dentry *old_dentry,
115462306a36Sopenharmony_ci			     struct inode *new_dir, struct dentry *new_dentry)
115562306a36Sopenharmony_ci{
115662306a36Sopenharmony_ci	struct f2fs_sb_info *sbi = F2FS_I_SB(old_dir);
115762306a36Sopenharmony_ci	struct inode *old_inode = d_inode(old_dentry);
115862306a36Sopenharmony_ci	struct inode *new_inode = d_inode(new_dentry);
115962306a36Sopenharmony_ci	struct page *old_dir_page, *new_dir_page;
116062306a36Sopenharmony_ci	struct page *old_page, *new_page;
116162306a36Sopenharmony_ci	struct f2fs_dir_entry *old_dir_entry = NULL, *new_dir_entry = NULL;
116262306a36Sopenharmony_ci	struct f2fs_dir_entry *old_entry, *new_entry;
116362306a36Sopenharmony_ci	int old_nlink = 0, new_nlink = 0;
116462306a36Sopenharmony_ci	int err;
116562306a36Sopenharmony_ci
116662306a36Sopenharmony_ci	if (unlikely(f2fs_cp_error(sbi)))
116762306a36Sopenharmony_ci		return -EIO;
116862306a36Sopenharmony_ci	if (!f2fs_is_checkpoint_ready(sbi))
116962306a36Sopenharmony_ci		return -ENOSPC;
117062306a36Sopenharmony_ci
117162306a36Sopenharmony_ci	if ((is_inode_flag_set(new_dir, FI_PROJ_INHERIT) &&
117262306a36Sopenharmony_ci			!projid_eq(F2FS_I(new_dir)->i_projid,
117362306a36Sopenharmony_ci			F2FS_I(old_dentry->d_inode)->i_projid)) ||
117462306a36Sopenharmony_ci	    (is_inode_flag_set(new_dir, FI_PROJ_INHERIT) &&
117562306a36Sopenharmony_ci			!projid_eq(F2FS_I(old_dir)->i_projid,
117662306a36Sopenharmony_ci			F2FS_I(new_dentry->d_inode)->i_projid)))
117762306a36Sopenharmony_ci		return -EXDEV;
117862306a36Sopenharmony_ci
117962306a36Sopenharmony_ci	err = f2fs_dquot_initialize(old_dir);
118062306a36Sopenharmony_ci	if (err)
118162306a36Sopenharmony_ci		goto out;
118262306a36Sopenharmony_ci
118362306a36Sopenharmony_ci	err = f2fs_dquot_initialize(new_dir);
118462306a36Sopenharmony_ci	if (err)
118562306a36Sopenharmony_ci		goto out;
118662306a36Sopenharmony_ci
118762306a36Sopenharmony_ci	err = -ENOENT;
118862306a36Sopenharmony_ci	old_entry = f2fs_find_entry(old_dir, &old_dentry->d_name, &old_page);
118962306a36Sopenharmony_ci	if (!old_entry) {
119062306a36Sopenharmony_ci		if (IS_ERR(old_page))
119162306a36Sopenharmony_ci			err = PTR_ERR(old_page);
119262306a36Sopenharmony_ci		goto out;
119362306a36Sopenharmony_ci	}
119462306a36Sopenharmony_ci
119562306a36Sopenharmony_ci	new_entry = f2fs_find_entry(new_dir, &new_dentry->d_name, &new_page);
119662306a36Sopenharmony_ci	if (!new_entry) {
119762306a36Sopenharmony_ci		if (IS_ERR(new_page))
119862306a36Sopenharmony_ci			err = PTR_ERR(new_page);
119962306a36Sopenharmony_ci		goto out_old;
120062306a36Sopenharmony_ci	}
120162306a36Sopenharmony_ci
120262306a36Sopenharmony_ci	/* prepare for updating ".." directory entry info later */
120362306a36Sopenharmony_ci	if (old_dir != new_dir) {
120462306a36Sopenharmony_ci		if (S_ISDIR(old_inode->i_mode)) {
120562306a36Sopenharmony_ci			old_dir_entry = f2fs_parent_dir(old_inode,
120662306a36Sopenharmony_ci							&old_dir_page);
120762306a36Sopenharmony_ci			if (!old_dir_entry) {
120862306a36Sopenharmony_ci				if (IS_ERR(old_dir_page))
120962306a36Sopenharmony_ci					err = PTR_ERR(old_dir_page);
121062306a36Sopenharmony_ci				goto out_new;
121162306a36Sopenharmony_ci			}
121262306a36Sopenharmony_ci		}
121362306a36Sopenharmony_ci
121462306a36Sopenharmony_ci		if (S_ISDIR(new_inode->i_mode)) {
121562306a36Sopenharmony_ci			new_dir_entry = f2fs_parent_dir(new_inode,
121662306a36Sopenharmony_ci							&new_dir_page);
121762306a36Sopenharmony_ci			if (!new_dir_entry) {
121862306a36Sopenharmony_ci				if (IS_ERR(new_dir_page))
121962306a36Sopenharmony_ci					err = PTR_ERR(new_dir_page);
122062306a36Sopenharmony_ci				goto out_old_dir;
122162306a36Sopenharmony_ci			}
122262306a36Sopenharmony_ci		}
122362306a36Sopenharmony_ci	}
122462306a36Sopenharmony_ci
122562306a36Sopenharmony_ci	/*
122662306a36Sopenharmony_ci	 * If cross rename between file and directory those are not
122762306a36Sopenharmony_ci	 * in the same directory, we will inc nlink of file's parent
122862306a36Sopenharmony_ci	 * later, so we should check upper boundary of its nlink.
122962306a36Sopenharmony_ci	 */
123062306a36Sopenharmony_ci	if ((!old_dir_entry || !new_dir_entry) &&
123162306a36Sopenharmony_ci				old_dir_entry != new_dir_entry) {
123262306a36Sopenharmony_ci		old_nlink = old_dir_entry ? -1 : 1;
123362306a36Sopenharmony_ci		new_nlink = -old_nlink;
123462306a36Sopenharmony_ci		err = -EMLINK;
123562306a36Sopenharmony_ci		if ((old_nlink > 0 && old_dir->i_nlink >= F2FS_LINK_MAX) ||
123662306a36Sopenharmony_ci			(new_nlink > 0 && new_dir->i_nlink >= F2FS_LINK_MAX))
123762306a36Sopenharmony_ci			goto out_new_dir;
123862306a36Sopenharmony_ci	}
123962306a36Sopenharmony_ci
124062306a36Sopenharmony_ci	f2fs_balance_fs(sbi, true);
124162306a36Sopenharmony_ci
124262306a36Sopenharmony_ci	f2fs_lock_op(sbi);
124362306a36Sopenharmony_ci
124462306a36Sopenharmony_ci	/* update ".." directory entry info of old dentry */
124562306a36Sopenharmony_ci	if (old_dir_entry)
124662306a36Sopenharmony_ci		f2fs_set_link(old_inode, old_dir_entry, old_dir_page, new_dir);
124762306a36Sopenharmony_ci
124862306a36Sopenharmony_ci	/* update ".." directory entry info of new dentry */
124962306a36Sopenharmony_ci	if (new_dir_entry)
125062306a36Sopenharmony_ci		f2fs_set_link(new_inode, new_dir_entry, new_dir_page, old_dir);
125162306a36Sopenharmony_ci
125262306a36Sopenharmony_ci	/* update directory entry info of old dir inode */
125362306a36Sopenharmony_ci	f2fs_set_link(old_dir, old_entry, old_page, new_inode);
125462306a36Sopenharmony_ci
125562306a36Sopenharmony_ci	f2fs_down_write(&F2FS_I(old_inode)->i_sem);
125662306a36Sopenharmony_ci	if (!old_dir_entry)
125762306a36Sopenharmony_ci		file_lost_pino(old_inode);
125862306a36Sopenharmony_ci	else
125962306a36Sopenharmony_ci		/* adjust dir's i_pino to pass fsck check */
126062306a36Sopenharmony_ci		f2fs_i_pino_write(old_inode, new_dir->i_ino);
126162306a36Sopenharmony_ci	f2fs_up_write(&F2FS_I(old_inode)->i_sem);
126262306a36Sopenharmony_ci
126362306a36Sopenharmony_ci	inode_set_ctime_current(old_dir);
126462306a36Sopenharmony_ci	if (old_nlink) {
126562306a36Sopenharmony_ci		f2fs_down_write(&F2FS_I(old_dir)->i_sem);
126662306a36Sopenharmony_ci		f2fs_i_links_write(old_dir, old_nlink > 0);
126762306a36Sopenharmony_ci		f2fs_up_write(&F2FS_I(old_dir)->i_sem);
126862306a36Sopenharmony_ci	}
126962306a36Sopenharmony_ci	f2fs_mark_inode_dirty_sync(old_dir, false);
127062306a36Sopenharmony_ci
127162306a36Sopenharmony_ci	/* update directory entry info of new dir inode */
127262306a36Sopenharmony_ci	f2fs_set_link(new_dir, new_entry, new_page, old_inode);
127362306a36Sopenharmony_ci
127462306a36Sopenharmony_ci	f2fs_down_write(&F2FS_I(new_inode)->i_sem);
127562306a36Sopenharmony_ci	if (!new_dir_entry)
127662306a36Sopenharmony_ci		file_lost_pino(new_inode);
127762306a36Sopenharmony_ci	else
127862306a36Sopenharmony_ci		/* adjust dir's i_pino to pass fsck check */
127962306a36Sopenharmony_ci		f2fs_i_pino_write(new_inode, old_dir->i_ino);
128062306a36Sopenharmony_ci	f2fs_up_write(&F2FS_I(new_inode)->i_sem);
128162306a36Sopenharmony_ci
128262306a36Sopenharmony_ci	inode_set_ctime_current(new_dir);
128362306a36Sopenharmony_ci	if (new_nlink) {
128462306a36Sopenharmony_ci		f2fs_down_write(&F2FS_I(new_dir)->i_sem);
128562306a36Sopenharmony_ci		f2fs_i_links_write(new_dir, new_nlink > 0);
128662306a36Sopenharmony_ci		f2fs_up_write(&F2FS_I(new_dir)->i_sem);
128762306a36Sopenharmony_ci	}
128862306a36Sopenharmony_ci	f2fs_mark_inode_dirty_sync(new_dir, false);
128962306a36Sopenharmony_ci
129062306a36Sopenharmony_ci	if (F2FS_OPTION(sbi).fsync_mode == FSYNC_MODE_STRICT) {
129162306a36Sopenharmony_ci		f2fs_add_ino_entry(sbi, old_dir->i_ino, TRANS_DIR_INO);
129262306a36Sopenharmony_ci		f2fs_add_ino_entry(sbi, new_dir->i_ino, TRANS_DIR_INO);
129362306a36Sopenharmony_ci	}
129462306a36Sopenharmony_ci
129562306a36Sopenharmony_ci	f2fs_unlock_op(sbi);
129662306a36Sopenharmony_ci
129762306a36Sopenharmony_ci	if (IS_DIRSYNC(old_dir) || IS_DIRSYNC(new_dir))
129862306a36Sopenharmony_ci		f2fs_sync_fs(sbi->sb, 1);
129962306a36Sopenharmony_ci
130062306a36Sopenharmony_ci	f2fs_update_time(sbi, REQ_TIME);
130162306a36Sopenharmony_ci	return 0;
130262306a36Sopenharmony_ciout_new_dir:
130362306a36Sopenharmony_ci	if (new_dir_entry) {
130462306a36Sopenharmony_ci		f2fs_put_page(new_dir_page, 0);
130562306a36Sopenharmony_ci	}
130662306a36Sopenharmony_ciout_old_dir:
130762306a36Sopenharmony_ci	if (old_dir_entry) {
130862306a36Sopenharmony_ci		f2fs_put_page(old_dir_page, 0);
130962306a36Sopenharmony_ci	}
131062306a36Sopenharmony_ciout_new:
131162306a36Sopenharmony_ci	f2fs_put_page(new_page, 0);
131262306a36Sopenharmony_ciout_old:
131362306a36Sopenharmony_ci	f2fs_put_page(old_page, 0);
131462306a36Sopenharmony_ciout:
131562306a36Sopenharmony_ci	return err;
131662306a36Sopenharmony_ci}
131762306a36Sopenharmony_ci
131862306a36Sopenharmony_cistatic int f2fs_rename2(struct mnt_idmap *idmap,
131962306a36Sopenharmony_ci			struct inode *old_dir, struct dentry *old_dentry,
132062306a36Sopenharmony_ci			struct inode *new_dir, struct dentry *new_dentry,
132162306a36Sopenharmony_ci			unsigned int flags)
132262306a36Sopenharmony_ci{
132362306a36Sopenharmony_ci	int err;
132462306a36Sopenharmony_ci
132562306a36Sopenharmony_ci	if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE | RENAME_WHITEOUT))
132662306a36Sopenharmony_ci		return -EINVAL;
132762306a36Sopenharmony_ci
132862306a36Sopenharmony_ci	err = fscrypt_prepare_rename(old_dir, old_dentry, new_dir, new_dentry,
132962306a36Sopenharmony_ci				     flags);
133062306a36Sopenharmony_ci	if (err)
133162306a36Sopenharmony_ci		return err;
133262306a36Sopenharmony_ci
133362306a36Sopenharmony_ci	if (flags & RENAME_EXCHANGE) {
133462306a36Sopenharmony_ci		return f2fs_cross_rename(old_dir, old_dentry,
133562306a36Sopenharmony_ci					 new_dir, new_dentry);
133662306a36Sopenharmony_ci	}
133762306a36Sopenharmony_ci	/*
133862306a36Sopenharmony_ci	 * VFS has already handled the new dentry existence case,
133962306a36Sopenharmony_ci	 * here, we just deal with "RENAME_NOREPLACE" as regular rename.
134062306a36Sopenharmony_ci	 */
134162306a36Sopenharmony_ci	return f2fs_rename(idmap, old_dir, old_dentry,
134262306a36Sopenharmony_ci					new_dir, new_dentry, flags);
134362306a36Sopenharmony_ci}
134462306a36Sopenharmony_ci
134562306a36Sopenharmony_cistatic const char *f2fs_encrypted_get_link(struct dentry *dentry,
134662306a36Sopenharmony_ci					   struct inode *inode,
134762306a36Sopenharmony_ci					   struct delayed_call *done)
134862306a36Sopenharmony_ci{
134962306a36Sopenharmony_ci	struct page *page;
135062306a36Sopenharmony_ci	const char *target;
135162306a36Sopenharmony_ci
135262306a36Sopenharmony_ci	if (!dentry)
135362306a36Sopenharmony_ci		return ERR_PTR(-ECHILD);
135462306a36Sopenharmony_ci
135562306a36Sopenharmony_ci	page = read_mapping_page(inode->i_mapping, 0, NULL);
135662306a36Sopenharmony_ci	if (IS_ERR(page))
135762306a36Sopenharmony_ci		return ERR_CAST(page);
135862306a36Sopenharmony_ci
135962306a36Sopenharmony_ci	target = fscrypt_get_symlink(inode, page_address(page),
136062306a36Sopenharmony_ci				     inode->i_sb->s_blocksize, done);
136162306a36Sopenharmony_ci	put_page(page);
136262306a36Sopenharmony_ci	return target;
136362306a36Sopenharmony_ci}
136462306a36Sopenharmony_ci
136562306a36Sopenharmony_cistatic int f2fs_encrypted_symlink_getattr(struct mnt_idmap *idmap,
136662306a36Sopenharmony_ci					  const struct path *path,
136762306a36Sopenharmony_ci					  struct kstat *stat, u32 request_mask,
136862306a36Sopenharmony_ci					  unsigned int query_flags)
136962306a36Sopenharmony_ci{
137062306a36Sopenharmony_ci	f2fs_getattr(idmap, path, stat, request_mask, query_flags);
137162306a36Sopenharmony_ci
137262306a36Sopenharmony_ci	return fscrypt_symlink_getattr(path, stat);
137362306a36Sopenharmony_ci}
137462306a36Sopenharmony_ci
137562306a36Sopenharmony_ciconst struct inode_operations f2fs_encrypted_symlink_inode_operations = {
137662306a36Sopenharmony_ci	.get_link	= f2fs_encrypted_get_link,
137762306a36Sopenharmony_ci	.getattr	= f2fs_encrypted_symlink_getattr,
137862306a36Sopenharmony_ci	.setattr	= f2fs_setattr,
137962306a36Sopenharmony_ci	.listxattr	= f2fs_listxattr,
138062306a36Sopenharmony_ci};
138162306a36Sopenharmony_ci
138262306a36Sopenharmony_ciconst struct inode_operations f2fs_dir_inode_operations = {
138362306a36Sopenharmony_ci	.create		= f2fs_create,
138462306a36Sopenharmony_ci	.lookup		= f2fs_lookup,
138562306a36Sopenharmony_ci	.link		= f2fs_link,
138662306a36Sopenharmony_ci	.unlink		= f2fs_unlink,
138762306a36Sopenharmony_ci	.symlink	= f2fs_symlink,
138862306a36Sopenharmony_ci	.mkdir		= f2fs_mkdir,
138962306a36Sopenharmony_ci	.rmdir		= f2fs_rmdir,
139062306a36Sopenharmony_ci	.mknod		= f2fs_mknod,
139162306a36Sopenharmony_ci	.rename		= f2fs_rename2,
139262306a36Sopenharmony_ci	.tmpfile	= f2fs_tmpfile,
139362306a36Sopenharmony_ci	.getattr	= f2fs_getattr,
139462306a36Sopenharmony_ci	.setattr	= f2fs_setattr,
139562306a36Sopenharmony_ci	.get_inode_acl	= f2fs_get_acl,
139662306a36Sopenharmony_ci	.set_acl	= f2fs_set_acl,
139762306a36Sopenharmony_ci	.listxattr	= f2fs_listxattr,
139862306a36Sopenharmony_ci	.fiemap		= f2fs_fiemap,
139962306a36Sopenharmony_ci	.fileattr_get	= f2fs_fileattr_get,
140062306a36Sopenharmony_ci	.fileattr_set	= f2fs_fileattr_set,
140162306a36Sopenharmony_ci};
140262306a36Sopenharmony_ci
140362306a36Sopenharmony_ciconst struct inode_operations f2fs_symlink_inode_operations = {
140462306a36Sopenharmony_ci	.get_link	= f2fs_get_link,
140562306a36Sopenharmony_ci	.getattr	= f2fs_getattr,
140662306a36Sopenharmony_ci	.setattr	= f2fs_setattr,
140762306a36Sopenharmony_ci	.listxattr	= f2fs_listxattr,
140862306a36Sopenharmony_ci};
140962306a36Sopenharmony_ci
141062306a36Sopenharmony_ciconst struct inode_operations f2fs_special_inode_operations = {
141162306a36Sopenharmony_ci	.getattr	= f2fs_getattr,
141262306a36Sopenharmony_ci	.setattr	= f2fs_setattr,
141362306a36Sopenharmony_ci	.get_inode_acl	= f2fs_get_acl,
141462306a36Sopenharmony_ci	.set_acl	= f2fs_set_acl,
141562306a36Sopenharmony_ci	.listxattr	= f2fs_listxattr,
141662306a36Sopenharmony_ci};
1417