18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2011 Novell Inc.
48c2ecf20Sopenharmony_ci * Copyright (C) 2016 Red Hat, Inc.
58c2ecf20Sopenharmony_ci */
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci#include <linux/fs.h>
88c2ecf20Sopenharmony_ci#include <linux/mount.h>
98c2ecf20Sopenharmony_ci#include <linux/slab.h>
108c2ecf20Sopenharmony_ci#include <linux/cred.h>
118c2ecf20Sopenharmony_ci#include <linux/xattr.h>
128c2ecf20Sopenharmony_ci#include <linux/exportfs.h>
138c2ecf20Sopenharmony_ci#include <linux/uuid.h>
148c2ecf20Sopenharmony_ci#include <linux/namei.h>
158c2ecf20Sopenharmony_ci#include <linux/ratelimit.h>
168c2ecf20Sopenharmony_ci#include "overlayfs.h"
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ciint ovl_want_write(struct dentry *dentry)
198c2ecf20Sopenharmony_ci{
208c2ecf20Sopenharmony_ci	struct ovl_fs *ofs = dentry->d_sb->s_fs_info;
218c2ecf20Sopenharmony_ci	return mnt_want_write(ovl_upper_mnt(ofs));
228c2ecf20Sopenharmony_ci}
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_civoid ovl_drop_write(struct dentry *dentry)
258c2ecf20Sopenharmony_ci{
268c2ecf20Sopenharmony_ci	struct ovl_fs *ofs = dentry->d_sb->s_fs_info;
278c2ecf20Sopenharmony_ci	mnt_drop_write(ovl_upper_mnt(ofs));
288c2ecf20Sopenharmony_ci}
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_cistruct dentry *ovl_workdir(struct dentry *dentry)
318c2ecf20Sopenharmony_ci{
328c2ecf20Sopenharmony_ci	struct ovl_fs *ofs = dentry->d_sb->s_fs_info;
338c2ecf20Sopenharmony_ci	return ofs->workdir;
348c2ecf20Sopenharmony_ci}
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ciconst struct cred *ovl_override_creds(struct super_block *sb)
378c2ecf20Sopenharmony_ci{
388c2ecf20Sopenharmony_ci	struct ovl_fs *ofs = sb->s_fs_info;
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci	return override_creds(ofs->creator_cred);
418c2ecf20Sopenharmony_ci}
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci/*
448c2ecf20Sopenharmony_ci * Check if underlying fs supports file handles and try to determine encoding
458c2ecf20Sopenharmony_ci * type, in order to deduce maximum inode number used by fs.
468c2ecf20Sopenharmony_ci *
478c2ecf20Sopenharmony_ci * Return 0 if file handles are not supported.
488c2ecf20Sopenharmony_ci * Return 1 (FILEID_INO32_GEN) if fs uses the default 32bit inode encoding.
498c2ecf20Sopenharmony_ci * Return -1 if fs uses a non default encoding with unknown inode size.
508c2ecf20Sopenharmony_ci */
518c2ecf20Sopenharmony_ciint ovl_can_decode_fh(struct super_block *sb)
528c2ecf20Sopenharmony_ci{
538c2ecf20Sopenharmony_ci	if (!sb->s_export_op || !sb->s_export_op->fh_to_dentry)
548c2ecf20Sopenharmony_ci		return 0;
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci	return sb->s_export_op->encode_fh ? -1 : FILEID_INO32_GEN;
578c2ecf20Sopenharmony_ci}
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_cistruct dentry *ovl_indexdir(struct super_block *sb)
608c2ecf20Sopenharmony_ci{
618c2ecf20Sopenharmony_ci	struct ovl_fs *ofs = sb->s_fs_info;
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci	return ofs->indexdir;
648c2ecf20Sopenharmony_ci}
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci/* Index all files on copy up. For now only enabled for NFS export */
678c2ecf20Sopenharmony_cibool ovl_index_all(struct super_block *sb)
688c2ecf20Sopenharmony_ci{
698c2ecf20Sopenharmony_ci	struct ovl_fs *ofs = sb->s_fs_info;
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci	return ofs->config.nfs_export && ofs->config.index;
728c2ecf20Sopenharmony_ci}
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci/* Verify lower origin on lookup. For now only enabled for NFS export */
758c2ecf20Sopenharmony_cibool ovl_verify_lower(struct super_block *sb)
768c2ecf20Sopenharmony_ci{
778c2ecf20Sopenharmony_ci	struct ovl_fs *ofs = sb->s_fs_info;
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	return ofs->config.nfs_export && ofs->config.index;
808c2ecf20Sopenharmony_ci}
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_cistruct ovl_entry *ovl_alloc_entry(unsigned int numlower)
838c2ecf20Sopenharmony_ci{
848c2ecf20Sopenharmony_ci	size_t size = offsetof(struct ovl_entry, lowerstack[numlower]);
858c2ecf20Sopenharmony_ci	struct ovl_entry *oe = kzalloc(size, GFP_KERNEL);
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci	if (oe)
888c2ecf20Sopenharmony_ci		oe->numlower = numlower;
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci	return oe;
918c2ecf20Sopenharmony_ci}
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci#define OVL_D_REVALIDATE (DCACHE_OP_REVALIDATE | DCACHE_OP_WEAK_REVALIDATE)
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_cibool ovl_dentry_remote(struct dentry *dentry)
968c2ecf20Sopenharmony_ci{
978c2ecf20Sopenharmony_ci	return dentry->d_flags & OVL_D_REVALIDATE;
988c2ecf20Sopenharmony_ci}
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_civoid ovl_dentry_update_reval(struct dentry *dentry, struct dentry *realdentry)
1018c2ecf20Sopenharmony_ci{
1028c2ecf20Sopenharmony_ci	if (!ovl_dentry_remote(realdentry))
1038c2ecf20Sopenharmony_ci		return;
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	spin_lock(&dentry->d_lock);
1068c2ecf20Sopenharmony_ci	dentry->d_flags |= realdentry->d_flags & OVL_D_REVALIDATE;
1078c2ecf20Sopenharmony_ci	spin_unlock(&dentry->d_lock);
1088c2ecf20Sopenharmony_ci}
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_civoid ovl_dentry_init_reval(struct dentry *dentry, struct dentry *upperdentry)
1118c2ecf20Sopenharmony_ci{
1128c2ecf20Sopenharmony_ci	return ovl_dentry_init_flags(dentry, upperdentry, OVL_D_REVALIDATE);
1138c2ecf20Sopenharmony_ci}
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_civoid ovl_dentry_init_flags(struct dentry *dentry, struct dentry *upperdentry,
1168c2ecf20Sopenharmony_ci			   unsigned int mask)
1178c2ecf20Sopenharmony_ci{
1188c2ecf20Sopenharmony_ci	struct ovl_entry *oe = OVL_E(dentry);
1198c2ecf20Sopenharmony_ci	unsigned int i, flags = 0;
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci	if (upperdentry)
1228c2ecf20Sopenharmony_ci		flags |= upperdentry->d_flags;
1238c2ecf20Sopenharmony_ci	for (i = 0; i < oe->numlower; i++)
1248c2ecf20Sopenharmony_ci		flags |= oe->lowerstack[i].dentry->d_flags;
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci	spin_lock(&dentry->d_lock);
1278c2ecf20Sopenharmony_ci	dentry->d_flags &= ~mask;
1288c2ecf20Sopenharmony_ci	dentry->d_flags |= flags & mask;
1298c2ecf20Sopenharmony_ci	spin_unlock(&dentry->d_lock);
1308c2ecf20Sopenharmony_ci}
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_cibool ovl_dentry_weird(struct dentry *dentry)
1338c2ecf20Sopenharmony_ci{
1348c2ecf20Sopenharmony_ci	return dentry->d_flags & (DCACHE_NEED_AUTOMOUNT |
1358c2ecf20Sopenharmony_ci				  DCACHE_MANAGE_TRANSIT |
1368c2ecf20Sopenharmony_ci				  DCACHE_OP_HASH |
1378c2ecf20Sopenharmony_ci				  DCACHE_OP_COMPARE);
1388c2ecf20Sopenharmony_ci}
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_cienum ovl_path_type ovl_path_type(struct dentry *dentry)
1418c2ecf20Sopenharmony_ci{
1428c2ecf20Sopenharmony_ci	struct ovl_entry *oe = dentry->d_fsdata;
1438c2ecf20Sopenharmony_ci	enum ovl_path_type type = 0;
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci	if (ovl_dentry_upper(dentry)) {
1468c2ecf20Sopenharmony_ci		type = __OVL_PATH_UPPER;
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci		/*
1498c2ecf20Sopenharmony_ci		 * Non-dir dentry can hold lower dentry of its copy up origin.
1508c2ecf20Sopenharmony_ci		 */
1518c2ecf20Sopenharmony_ci		if (oe->numlower) {
1528c2ecf20Sopenharmony_ci			if (ovl_test_flag(OVL_CONST_INO, d_inode(dentry)))
1538c2ecf20Sopenharmony_ci				type |= __OVL_PATH_ORIGIN;
1548c2ecf20Sopenharmony_ci			if (d_is_dir(dentry) ||
1558c2ecf20Sopenharmony_ci			    !ovl_has_upperdata(d_inode(dentry)))
1568c2ecf20Sopenharmony_ci				type |= __OVL_PATH_MERGE;
1578c2ecf20Sopenharmony_ci		}
1588c2ecf20Sopenharmony_ci	} else {
1598c2ecf20Sopenharmony_ci		if (oe->numlower > 1)
1608c2ecf20Sopenharmony_ci			type |= __OVL_PATH_MERGE;
1618c2ecf20Sopenharmony_ci	}
1628c2ecf20Sopenharmony_ci	return type;
1638c2ecf20Sopenharmony_ci}
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_civoid ovl_path_upper(struct dentry *dentry, struct path *path)
1668c2ecf20Sopenharmony_ci{
1678c2ecf20Sopenharmony_ci	struct ovl_fs *ofs = dentry->d_sb->s_fs_info;
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	path->mnt = ovl_upper_mnt(ofs);
1708c2ecf20Sopenharmony_ci	path->dentry = ovl_dentry_upper(dentry);
1718c2ecf20Sopenharmony_ci}
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_civoid ovl_path_lower(struct dentry *dentry, struct path *path)
1748c2ecf20Sopenharmony_ci{
1758c2ecf20Sopenharmony_ci	struct ovl_entry *oe = dentry->d_fsdata;
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci	if (oe->numlower) {
1788c2ecf20Sopenharmony_ci		path->mnt = oe->lowerstack[0].layer->mnt;
1798c2ecf20Sopenharmony_ci		path->dentry = oe->lowerstack[0].dentry;
1808c2ecf20Sopenharmony_ci	} else {
1818c2ecf20Sopenharmony_ci		*path = (struct path) { };
1828c2ecf20Sopenharmony_ci	}
1838c2ecf20Sopenharmony_ci}
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_civoid ovl_path_lowerdata(struct dentry *dentry, struct path *path)
1868c2ecf20Sopenharmony_ci{
1878c2ecf20Sopenharmony_ci	struct ovl_entry *oe = dentry->d_fsdata;
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci	if (oe->numlower) {
1908c2ecf20Sopenharmony_ci		path->mnt = oe->lowerstack[oe->numlower - 1].layer->mnt;
1918c2ecf20Sopenharmony_ci		path->dentry = oe->lowerstack[oe->numlower - 1].dentry;
1928c2ecf20Sopenharmony_ci	} else {
1938c2ecf20Sopenharmony_ci		*path = (struct path) { };
1948c2ecf20Sopenharmony_ci	}
1958c2ecf20Sopenharmony_ci}
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_cienum ovl_path_type ovl_path_real(struct dentry *dentry, struct path *path)
1988c2ecf20Sopenharmony_ci{
1998c2ecf20Sopenharmony_ci	enum ovl_path_type type = ovl_path_type(dentry);
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci	if (!OVL_TYPE_UPPER(type))
2028c2ecf20Sopenharmony_ci		ovl_path_lower(dentry, path);
2038c2ecf20Sopenharmony_ci	else
2048c2ecf20Sopenharmony_ci		ovl_path_upper(dentry, path);
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci	return type;
2078c2ecf20Sopenharmony_ci}
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_cistruct dentry *ovl_dentry_upper(struct dentry *dentry)
2108c2ecf20Sopenharmony_ci{
2118c2ecf20Sopenharmony_ci	return ovl_upperdentry_dereference(OVL_I(d_inode(dentry)));
2128c2ecf20Sopenharmony_ci}
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_cistruct dentry *ovl_dentry_lower(struct dentry *dentry)
2158c2ecf20Sopenharmony_ci{
2168c2ecf20Sopenharmony_ci	struct ovl_entry *oe = dentry->d_fsdata;
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci	return oe->numlower ? oe->lowerstack[0].dentry : NULL;
2198c2ecf20Sopenharmony_ci}
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ciconst struct ovl_layer *ovl_layer_lower(struct dentry *dentry)
2228c2ecf20Sopenharmony_ci{
2238c2ecf20Sopenharmony_ci	struct ovl_entry *oe = dentry->d_fsdata;
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci	return oe->numlower ? oe->lowerstack[0].layer : NULL;
2268c2ecf20Sopenharmony_ci}
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci/*
2298c2ecf20Sopenharmony_ci * ovl_dentry_lower() could return either a data dentry or metacopy dentry
2308c2ecf20Sopenharmony_ci * dependig on what is stored in lowerstack[0]. At times we need to find
2318c2ecf20Sopenharmony_ci * lower dentry which has data (and not metacopy dentry). This helper
2328c2ecf20Sopenharmony_ci * returns the lower data dentry.
2338c2ecf20Sopenharmony_ci */
2348c2ecf20Sopenharmony_cistruct dentry *ovl_dentry_lowerdata(struct dentry *dentry)
2358c2ecf20Sopenharmony_ci{
2368c2ecf20Sopenharmony_ci	struct ovl_entry *oe = dentry->d_fsdata;
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci	return oe->numlower ? oe->lowerstack[oe->numlower - 1].dentry : NULL;
2398c2ecf20Sopenharmony_ci}
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_cistruct dentry *ovl_dentry_real(struct dentry *dentry)
2428c2ecf20Sopenharmony_ci{
2438c2ecf20Sopenharmony_ci	return ovl_dentry_upper(dentry) ?: ovl_dentry_lower(dentry);
2448c2ecf20Sopenharmony_ci}
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_cistruct dentry *ovl_i_dentry_upper(struct inode *inode)
2478c2ecf20Sopenharmony_ci{
2488c2ecf20Sopenharmony_ci	return ovl_upperdentry_dereference(OVL_I(inode));
2498c2ecf20Sopenharmony_ci}
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_cistruct inode *ovl_inode_upper(struct inode *inode)
2528c2ecf20Sopenharmony_ci{
2538c2ecf20Sopenharmony_ci	struct dentry *upperdentry = ovl_i_dentry_upper(inode);
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci	return upperdentry ? d_inode(upperdentry) : NULL;
2568c2ecf20Sopenharmony_ci}
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_cistruct inode *ovl_inode_lower(struct inode *inode)
2598c2ecf20Sopenharmony_ci{
2608c2ecf20Sopenharmony_ci	return OVL_I(inode)->lower;
2618c2ecf20Sopenharmony_ci}
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_cistruct inode *ovl_inode_real(struct inode *inode)
2648c2ecf20Sopenharmony_ci{
2658c2ecf20Sopenharmony_ci	return ovl_inode_upper(inode) ?: ovl_inode_lower(inode);
2668c2ecf20Sopenharmony_ci}
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci/* Return inode which contains lower data. Do not return metacopy */
2698c2ecf20Sopenharmony_cistruct inode *ovl_inode_lowerdata(struct inode *inode)
2708c2ecf20Sopenharmony_ci{
2718c2ecf20Sopenharmony_ci	if (WARN_ON(!S_ISREG(inode->i_mode)))
2728c2ecf20Sopenharmony_ci		return NULL;
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	return OVL_I(inode)->lowerdata ?: ovl_inode_lower(inode);
2758c2ecf20Sopenharmony_ci}
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci/* Return real inode which contains data. Does not return metacopy inode */
2788c2ecf20Sopenharmony_cistruct inode *ovl_inode_realdata(struct inode *inode)
2798c2ecf20Sopenharmony_ci{
2808c2ecf20Sopenharmony_ci	struct inode *upperinode;
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci	upperinode = ovl_inode_upper(inode);
2838c2ecf20Sopenharmony_ci	if (upperinode && ovl_has_upperdata(inode))
2848c2ecf20Sopenharmony_ci		return upperinode;
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci	return ovl_inode_lowerdata(inode);
2878c2ecf20Sopenharmony_ci}
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_cistruct ovl_dir_cache *ovl_dir_cache(struct inode *inode)
2908c2ecf20Sopenharmony_ci{
2918c2ecf20Sopenharmony_ci	return OVL_I(inode)->cache;
2928c2ecf20Sopenharmony_ci}
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_civoid ovl_set_dir_cache(struct inode *inode, struct ovl_dir_cache *cache)
2958c2ecf20Sopenharmony_ci{
2968c2ecf20Sopenharmony_ci	OVL_I(inode)->cache = cache;
2978c2ecf20Sopenharmony_ci}
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_civoid ovl_dentry_set_flag(unsigned long flag, struct dentry *dentry)
3008c2ecf20Sopenharmony_ci{
3018c2ecf20Sopenharmony_ci	set_bit(flag, &OVL_E(dentry)->flags);
3028c2ecf20Sopenharmony_ci}
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_civoid ovl_dentry_clear_flag(unsigned long flag, struct dentry *dentry)
3058c2ecf20Sopenharmony_ci{
3068c2ecf20Sopenharmony_ci	clear_bit(flag, &OVL_E(dentry)->flags);
3078c2ecf20Sopenharmony_ci}
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_cibool ovl_dentry_test_flag(unsigned long flag, struct dentry *dentry)
3108c2ecf20Sopenharmony_ci{
3118c2ecf20Sopenharmony_ci	return test_bit(flag, &OVL_E(dentry)->flags);
3128c2ecf20Sopenharmony_ci}
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_cibool ovl_dentry_is_opaque(struct dentry *dentry)
3158c2ecf20Sopenharmony_ci{
3168c2ecf20Sopenharmony_ci	return ovl_dentry_test_flag(OVL_E_OPAQUE, dentry);
3178c2ecf20Sopenharmony_ci}
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_cibool ovl_dentry_is_whiteout(struct dentry *dentry)
3208c2ecf20Sopenharmony_ci{
3218c2ecf20Sopenharmony_ci	return !dentry->d_inode && ovl_dentry_is_opaque(dentry);
3228c2ecf20Sopenharmony_ci}
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_civoid ovl_dentry_set_opaque(struct dentry *dentry)
3258c2ecf20Sopenharmony_ci{
3268c2ecf20Sopenharmony_ci	ovl_dentry_set_flag(OVL_E_OPAQUE, dentry);
3278c2ecf20Sopenharmony_ci}
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci/*
3308c2ecf20Sopenharmony_ci * For hard links and decoded file handles, it's possible for ovl_dentry_upper()
3318c2ecf20Sopenharmony_ci * to return positive, while there's no actual upper alias for the inode.
3328c2ecf20Sopenharmony_ci * Copy up code needs to know about the existence of the upper alias, so it
3338c2ecf20Sopenharmony_ci * can't use ovl_dentry_upper().
3348c2ecf20Sopenharmony_ci */
3358c2ecf20Sopenharmony_cibool ovl_dentry_has_upper_alias(struct dentry *dentry)
3368c2ecf20Sopenharmony_ci{
3378c2ecf20Sopenharmony_ci	return ovl_dentry_test_flag(OVL_E_UPPER_ALIAS, dentry);
3388c2ecf20Sopenharmony_ci}
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_civoid ovl_dentry_set_upper_alias(struct dentry *dentry)
3418c2ecf20Sopenharmony_ci{
3428c2ecf20Sopenharmony_ci	ovl_dentry_set_flag(OVL_E_UPPER_ALIAS, dentry);
3438c2ecf20Sopenharmony_ci}
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_cistatic bool ovl_should_check_upperdata(struct inode *inode)
3468c2ecf20Sopenharmony_ci{
3478c2ecf20Sopenharmony_ci	if (!S_ISREG(inode->i_mode))
3488c2ecf20Sopenharmony_ci		return false;
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	if (!ovl_inode_lower(inode))
3518c2ecf20Sopenharmony_ci		return false;
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ci	return true;
3548c2ecf20Sopenharmony_ci}
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_cibool ovl_has_upperdata(struct inode *inode)
3578c2ecf20Sopenharmony_ci{
3588c2ecf20Sopenharmony_ci	if (!ovl_should_check_upperdata(inode))
3598c2ecf20Sopenharmony_ci		return true;
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_ci	if (!ovl_test_flag(OVL_UPPERDATA, inode))
3628c2ecf20Sopenharmony_ci		return false;
3638c2ecf20Sopenharmony_ci	/*
3648c2ecf20Sopenharmony_ci	 * Pairs with smp_wmb() in ovl_set_upperdata(). Main user of
3658c2ecf20Sopenharmony_ci	 * ovl_has_upperdata() is ovl_copy_up_meta_inode_data(). Make sure
3668c2ecf20Sopenharmony_ci	 * if setting of OVL_UPPERDATA is visible, then effects of writes
3678c2ecf20Sopenharmony_ci	 * before that are visible too.
3688c2ecf20Sopenharmony_ci	 */
3698c2ecf20Sopenharmony_ci	smp_rmb();
3708c2ecf20Sopenharmony_ci	return true;
3718c2ecf20Sopenharmony_ci}
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_civoid ovl_set_upperdata(struct inode *inode)
3748c2ecf20Sopenharmony_ci{
3758c2ecf20Sopenharmony_ci	/*
3768c2ecf20Sopenharmony_ci	 * Pairs with smp_rmb() in ovl_has_upperdata(). Make sure
3778c2ecf20Sopenharmony_ci	 * if OVL_UPPERDATA flag is visible, then effects of write operations
3788c2ecf20Sopenharmony_ci	 * before it are visible as well.
3798c2ecf20Sopenharmony_ci	 */
3808c2ecf20Sopenharmony_ci	smp_wmb();
3818c2ecf20Sopenharmony_ci	ovl_set_flag(OVL_UPPERDATA, inode);
3828c2ecf20Sopenharmony_ci}
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ci/* Caller should hold ovl_inode->lock */
3858c2ecf20Sopenharmony_cibool ovl_dentry_needs_data_copy_up_locked(struct dentry *dentry, int flags)
3868c2ecf20Sopenharmony_ci{
3878c2ecf20Sopenharmony_ci	if (!ovl_open_flags_need_copy_up(flags))
3888c2ecf20Sopenharmony_ci		return false;
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ci	return !ovl_test_flag(OVL_UPPERDATA, d_inode(dentry));
3918c2ecf20Sopenharmony_ci}
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_cibool ovl_dentry_needs_data_copy_up(struct dentry *dentry, int flags)
3948c2ecf20Sopenharmony_ci{
3958c2ecf20Sopenharmony_ci	if (!ovl_open_flags_need_copy_up(flags))
3968c2ecf20Sopenharmony_ci		return false;
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_ci	return !ovl_has_upperdata(d_inode(dentry));
3998c2ecf20Sopenharmony_ci}
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_cibool ovl_redirect_dir(struct super_block *sb)
4028c2ecf20Sopenharmony_ci{
4038c2ecf20Sopenharmony_ci	struct ovl_fs *ofs = sb->s_fs_info;
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci	return ofs->config.redirect_dir && !ofs->noxattr;
4068c2ecf20Sopenharmony_ci}
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ciconst char *ovl_dentry_get_redirect(struct dentry *dentry)
4098c2ecf20Sopenharmony_ci{
4108c2ecf20Sopenharmony_ci	return OVL_I(d_inode(dentry))->redirect;
4118c2ecf20Sopenharmony_ci}
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_civoid ovl_dentry_set_redirect(struct dentry *dentry, const char *redirect)
4148c2ecf20Sopenharmony_ci{
4158c2ecf20Sopenharmony_ci	struct ovl_inode *oi = OVL_I(d_inode(dentry));
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_ci	kfree(oi->redirect);
4188c2ecf20Sopenharmony_ci	oi->redirect = redirect;
4198c2ecf20Sopenharmony_ci}
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_civoid ovl_inode_update(struct inode *inode, struct dentry *upperdentry)
4228c2ecf20Sopenharmony_ci{
4238c2ecf20Sopenharmony_ci	struct inode *upperinode = d_inode(upperdentry);
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_ci	WARN_ON(OVL_I(inode)->__upperdentry);
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_ci	/*
4288c2ecf20Sopenharmony_ci	 * Make sure upperdentry is consistent before making it visible
4298c2ecf20Sopenharmony_ci	 */
4308c2ecf20Sopenharmony_ci	smp_wmb();
4318c2ecf20Sopenharmony_ci	OVL_I(inode)->__upperdentry = upperdentry;
4328c2ecf20Sopenharmony_ci	if (inode_unhashed(inode)) {
4338c2ecf20Sopenharmony_ci		inode->i_private = upperinode;
4348c2ecf20Sopenharmony_ci		__insert_inode_hash(inode, (unsigned long) upperinode);
4358c2ecf20Sopenharmony_ci	}
4368c2ecf20Sopenharmony_ci}
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_cistatic void ovl_dir_version_inc(struct dentry *dentry, bool impurity)
4398c2ecf20Sopenharmony_ci{
4408c2ecf20Sopenharmony_ci	struct inode *inode = d_inode(dentry);
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_ci	WARN_ON(!inode_is_locked(inode));
4438c2ecf20Sopenharmony_ci	WARN_ON(!d_is_dir(dentry));
4448c2ecf20Sopenharmony_ci	/*
4458c2ecf20Sopenharmony_ci	 * Version is used by readdir code to keep cache consistent.
4468c2ecf20Sopenharmony_ci	 * For merge dirs (or dirs with origin) all changes need to be noted.
4478c2ecf20Sopenharmony_ci	 * For non-merge dirs, cache contains only impure entries (i.e. ones
4488c2ecf20Sopenharmony_ci	 * which have been copied up and have origins), so only need to note
4498c2ecf20Sopenharmony_ci	 * changes to impure entries.
4508c2ecf20Sopenharmony_ci	 */
4518c2ecf20Sopenharmony_ci	if (!ovl_dir_is_real(dentry) || impurity)
4528c2ecf20Sopenharmony_ci		OVL_I(inode)->version++;
4538c2ecf20Sopenharmony_ci}
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_civoid ovl_dir_modified(struct dentry *dentry, bool impurity)
4568c2ecf20Sopenharmony_ci{
4578c2ecf20Sopenharmony_ci	/* Copy mtime/ctime */
4588c2ecf20Sopenharmony_ci	ovl_copyattr(d_inode(ovl_dentry_upper(dentry)), d_inode(dentry));
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_ci	ovl_dir_version_inc(dentry, impurity);
4618c2ecf20Sopenharmony_ci}
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_ciu64 ovl_dentry_version_get(struct dentry *dentry)
4648c2ecf20Sopenharmony_ci{
4658c2ecf20Sopenharmony_ci	struct inode *inode = d_inode(dentry);
4668c2ecf20Sopenharmony_ci
4678c2ecf20Sopenharmony_ci	WARN_ON(!inode_is_locked(inode));
4688c2ecf20Sopenharmony_ci	return OVL_I(inode)->version;
4698c2ecf20Sopenharmony_ci}
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_cibool ovl_is_whiteout(struct dentry *dentry)
4728c2ecf20Sopenharmony_ci{
4738c2ecf20Sopenharmony_ci	struct inode *inode = dentry->d_inode;
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_ci	return inode && IS_WHITEOUT(inode);
4768c2ecf20Sopenharmony_ci}
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_cistruct file *ovl_path_open(struct path *path, int flags)
4798c2ecf20Sopenharmony_ci{
4808c2ecf20Sopenharmony_ci	struct inode *inode = d_inode(path->dentry);
4818c2ecf20Sopenharmony_ci	int err, acc_mode;
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_ci	if (flags & ~(O_ACCMODE | O_LARGEFILE))
4848c2ecf20Sopenharmony_ci		BUG();
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ci	switch (flags & O_ACCMODE) {
4878c2ecf20Sopenharmony_ci	case O_RDONLY:
4888c2ecf20Sopenharmony_ci		acc_mode = MAY_READ;
4898c2ecf20Sopenharmony_ci		break;
4908c2ecf20Sopenharmony_ci	case O_WRONLY:
4918c2ecf20Sopenharmony_ci		acc_mode = MAY_WRITE;
4928c2ecf20Sopenharmony_ci		break;
4938c2ecf20Sopenharmony_ci	default:
4948c2ecf20Sopenharmony_ci		BUG();
4958c2ecf20Sopenharmony_ci	}
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_ci	err = inode_permission(inode, acc_mode | MAY_OPEN);
4988c2ecf20Sopenharmony_ci	if (err)
4998c2ecf20Sopenharmony_ci		return ERR_PTR(err);
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_ci	/* O_NOATIME is an optimization, don't fail if not permitted */
5028c2ecf20Sopenharmony_ci	if (inode_owner_or_capable(inode))
5038c2ecf20Sopenharmony_ci		flags |= O_NOATIME;
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_ci	return dentry_open(path, flags, current_cred());
5068c2ecf20Sopenharmony_ci}
5078c2ecf20Sopenharmony_ci
5088c2ecf20Sopenharmony_ci/* Caller should hold ovl_inode->lock */
5098c2ecf20Sopenharmony_cistatic bool ovl_already_copied_up_locked(struct dentry *dentry, int flags)
5108c2ecf20Sopenharmony_ci{
5118c2ecf20Sopenharmony_ci	bool disconnected = dentry->d_flags & DCACHE_DISCONNECTED;
5128c2ecf20Sopenharmony_ci
5138c2ecf20Sopenharmony_ci	if (ovl_dentry_upper(dentry) &&
5148c2ecf20Sopenharmony_ci	    (ovl_dentry_has_upper_alias(dentry) || disconnected) &&
5158c2ecf20Sopenharmony_ci	    !ovl_dentry_needs_data_copy_up_locked(dentry, flags))
5168c2ecf20Sopenharmony_ci		return true;
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_ci	return false;
5198c2ecf20Sopenharmony_ci}
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_cibool ovl_already_copied_up(struct dentry *dentry, int flags)
5228c2ecf20Sopenharmony_ci{
5238c2ecf20Sopenharmony_ci	bool disconnected = dentry->d_flags & DCACHE_DISCONNECTED;
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_ci	/*
5268c2ecf20Sopenharmony_ci	 * Check if copy-up has happened as well as for upper alias (in
5278c2ecf20Sopenharmony_ci	 * case of hard links) is there.
5288c2ecf20Sopenharmony_ci	 *
5298c2ecf20Sopenharmony_ci	 * Both checks are lockless:
5308c2ecf20Sopenharmony_ci	 *  - false negatives: will recheck under oi->lock
5318c2ecf20Sopenharmony_ci	 *  - false positives:
5328c2ecf20Sopenharmony_ci	 *    + ovl_dentry_upper() uses memory barriers to ensure the
5338c2ecf20Sopenharmony_ci	 *      upper dentry is up-to-date
5348c2ecf20Sopenharmony_ci	 *    + ovl_dentry_has_upper_alias() relies on locking of
5358c2ecf20Sopenharmony_ci	 *      upper parent i_rwsem to prevent reordering copy-up
5368c2ecf20Sopenharmony_ci	 *      with rename.
5378c2ecf20Sopenharmony_ci	 */
5388c2ecf20Sopenharmony_ci	if (ovl_dentry_upper(dentry) &&
5398c2ecf20Sopenharmony_ci	    (ovl_dentry_has_upper_alias(dentry) || disconnected) &&
5408c2ecf20Sopenharmony_ci	    !ovl_dentry_needs_data_copy_up(dentry, flags))
5418c2ecf20Sopenharmony_ci		return true;
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_ci	return false;
5448c2ecf20Sopenharmony_ci}
5458c2ecf20Sopenharmony_ci
5468c2ecf20Sopenharmony_ciint ovl_copy_up_start(struct dentry *dentry, int flags)
5478c2ecf20Sopenharmony_ci{
5488c2ecf20Sopenharmony_ci	struct inode *inode = d_inode(dentry);
5498c2ecf20Sopenharmony_ci	int err;
5508c2ecf20Sopenharmony_ci
5518c2ecf20Sopenharmony_ci	err = ovl_inode_lock_interruptible(inode);
5528c2ecf20Sopenharmony_ci	if (!err && ovl_already_copied_up_locked(dentry, flags)) {
5538c2ecf20Sopenharmony_ci		err = 1; /* Already copied up */
5548c2ecf20Sopenharmony_ci		ovl_inode_unlock(inode);
5558c2ecf20Sopenharmony_ci	}
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_ci	return err;
5588c2ecf20Sopenharmony_ci}
5598c2ecf20Sopenharmony_ci
5608c2ecf20Sopenharmony_civoid ovl_copy_up_end(struct dentry *dentry)
5618c2ecf20Sopenharmony_ci{
5628c2ecf20Sopenharmony_ci	ovl_inode_unlock(d_inode(dentry));
5638c2ecf20Sopenharmony_ci}
5648c2ecf20Sopenharmony_ci
5658c2ecf20Sopenharmony_cibool ovl_check_origin_xattr(struct ovl_fs *ofs, struct dentry *dentry)
5668c2ecf20Sopenharmony_ci{
5678c2ecf20Sopenharmony_ci	int res;
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_ci	res = ovl_do_getxattr(ofs, dentry, OVL_XATTR_ORIGIN, NULL, 0);
5708c2ecf20Sopenharmony_ci
5718c2ecf20Sopenharmony_ci	/* Zero size value means "copied up but origin unknown" */
5728c2ecf20Sopenharmony_ci	if (res >= 0)
5738c2ecf20Sopenharmony_ci		return true;
5748c2ecf20Sopenharmony_ci
5758c2ecf20Sopenharmony_ci	return false;
5768c2ecf20Sopenharmony_ci}
5778c2ecf20Sopenharmony_ci
5788c2ecf20Sopenharmony_cibool ovl_check_dir_xattr(struct super_block *sb, struct dentry *dentry,
5798c2ecf20Sopenharmony_ci			 enum ovl_xattr ox)
5808c2ecf20Sopenharmony_ci{
5818c2ecf20Sopenharmony_ci	int res;
5828c2ecf20Sopenharmony_ci	char val;
5838c2ecf20Sopenharmony_ci
5848c2ecf20Sopenharmony_ci	if (!d_is_dir(dentry))
5858c2ecf20Sopenharmony_ci		return false;
5868c2ecf20Sopenharmony_ci
5878c2ecf20Sopenharmony_ci	res = ovl_do_getxattr(OVL_FS(sb), dentry, ox, &val, 1);
5888c2ecf20Sopenharmony_ci	if (res == 1 && val == 'y')
5898c2ecf20Sopenharmony_ci		return true;
5908c2ecf20Sopenharmony_ci
5918c2ecf20Sopenharmony_ci	return false;
5928c2ecf20Sopenharmony_ci}
5938c2ecf20Sopenharmony_ci
5948c2ecf20Sopenharmony_ci#define OVL_XATTR_OPAQUE_POSTFIX	"opaque"
5958c2ecf20Sopenharmony_ci#define OVL_XATTR_REDIRECT_POSTFIX	"redirect"
5968c2ecf20Sopenharmony_ci#define OVL_XATTR_ORIGIN_POSTFIX	"origin"
5978c2ecf20Sopenharmony_ci#define OVL_XATTR_IMPURE_POSTFIX	"impure"
5988c2ecf20Sopenharmony_ci#define OVL_XATTR_NLINK_POSTFIX		"nlink"
5998c2ecf20Sopenharmony_ci#define OVL_XATTR_UPPER_POSTFIX		"upper"
6008c2ecf20Sopenharmony_ci#define OVL_XATTR_METACOPY_POSTFIX	"metacopy"
6018c2ecf20Sopenharmony_ci
6028c2ecf20Sopenharmony_ci#define OVL_XATTR_TAB_ENTRY(x) \
6038c2ecf20Sopenharmony_ci	[x] = OVL_XATTR_PREFIX x ## _POSTFIX
6048c2ecf20Sopenharmony_ci
6058c2ecf20Sopenharmony_ciconst char *ovl_xattr_table[] = {
6068c2ecf20Sopenharmony_ci	OVL_XATTR_TAB_ENTRY(OVL_XATTR_OPAQUE),
6078c2ecf20Sopenharmony_ci	OVL_XATTR_TAB_ENTRY(OVL_XATTR_REDIRECT),
6088c2ecf20Sopenharmony_ci	OVL_XATTR_TAB_ENTRY(OVL_XATTR_ORIGIN),
6098c2ecf20Sopenharmony_ci	OVL_XATTR_TAB_ENTRY(OVL_XATTR_IMPURE),
6108c2ecf20Sopenharmony_ci	OVL_XATTR_TAB_ENTRY(OVL_XATTR_NLINK),
6118c2ecf20Sopenharmony_ci	OVL_XATTR_TAB_ENTRY(OVL_XATTR_UPPER),
6128c2ecf20Sopenharmony_ci	OVL_XATTR_TAB_ENTRY(OVL_XATTR_METACOPY),
6138c2ecf20Sopenharmony_ci};
6148c2ecf20Sopenharmony_ci
6158c2ecf20Sopenharmony_ciint ovl_check_setxattr(struct dentry *dentry, struct dentry *upperdentry,
6168c2ecf20Sopenharmony_ci		       enum ovl_xattr ox, const void *value, size_t size,
6178c2ecf20Sopenharmony_ci		       int xerr)
6188c2ecf20Sopenharmony_ci{
6198c2ecf20Sopenharmony_ci	int err;
6208c2ecf20Sopenharmony_ci	struct ovl_fs *ofs = dentry->d_sb->s_fs_info;
6218c2ecf20Sopenharmony_ci
6228c2ecf20Sopenharmony_ci	if (ofs->noxattr)
6238c2ecf20Sopenharmony_ci		return xerr;
6248c2ecf20Sopenharmony_ci
6258c2ecf20Sopenharmony_ci	err = ovl_do_setxattr(ofs, upperdentry, ox, value, size);
6268c2ecf20Sopenharmony_ci
6278c2ecf20Sopenharmony_ci	if (err == -EOPNOTSUPP) {
6288c2ecf20Sopenharmony_ci		pr_warn("cannot set %s xattr on upper\n", ovl_xattr(ofs, ox));
6298c2ecf20Sopenharmony_ci		ofs->noxattr = true;
6308c2ecf20Sopenharmony_ci		return xerr;
6318c2ecf20Sopenharmony_ci	}
6328c2ecf20Sopenharmony_ci
6338c2ecf20Sopenharmony_ci	return err;
6348c2ecf20Sopenharmony_ci}
6358c2ecf20Sopenharmony_ci
6368c2ecf20Sopenharmony_ciint ovl_set_impure(struct dentry *dentry, struct dentry *upperdentry)
6378c2ecf20Sopenharmony_ci{
6388c2ecf20Sopenharmony_ci	int err;
6398c2ecf20Sopenharmony_ci
6408c2ecf20Sopenharmony_ci	if (ovl_test_flag(OVL_IMPURE, d_inode(dentry)))
6418c2ecf20Sopenharmony_ci		return 0;
6428c2ecf20Sopenharmony_ci
6438c2ecf20Sopenharmony_ci	/*
6448c2ecf20Sopenharmony_ci	 * Do not fail when upper doesn't support xattrs.
6458c2ecf20Sopenharmony_ci	 * Upper inodes won't have origin nor redirect xattr anyway.
6468c2ecf20Sopenharmony_ci	 */
6478c2ecf20Sopenharmony_ci	err = ovl_check_setxattr(dentry, upperdentry, OVL_XATTR_IMPURE,
6488c2ecf20Sopenharmony_ci				 "y", 1, 0);
6498c2ecf20Sopenharmony_ci	if (!err)
6508c2ecf20Sopenharmony_ci		ovl_set_flag(OVL_IMPURE, d_inode(dentry));
6518c2ecf20Sopenharmony_ci
6528c2ecf20Sopenharmony_ci	return err;
6538c2ecf20Sopenharmony_ci}
6548c2ecf20Sopenharmony_ci
6558c2ecf20Sopenharmony_ci/**
6568c2ecf20Sopenharmony_ci * Caller must hold a reference to inode to prevent it from being freed while
6578c2ecf20Sopenharmony_ci * it is marked inuse.
6588c2ecf20Sopenharmony_ci */
6598c2ecf20Sopenharmony_cibool ovl_inuse_trylock(struct dentry *dentry)
6608c2ecf20Sopenharmony_ci{
6618c2ecf20Sopenharmony_ci	struct inode *inode = d_inode(dentry);
6628c2ecf20Sopenharmony_ci	bool locked = false;
6638c2ecf20Sopenharmony_ci
6648c2ecf20Sopenharmony_ci	spin_lock(&inode->i_lock);
6658c2ecf20Sopenharmony_ci	if (!(inode->i_state & I_OVL_INUSE)) {
6668c2ecf20Sopenharmony_ci		inode->i_state |= I_OVL_INUSE;
6678c2ecf20Sopenharmony_ci		locked = true;
6688c2ecf20Sopenharmony_ci	}
6698c2ecf20Sopenharmony_ci	spin_unlock(&inode->i_lock);
6708c2ecf20Sopenharmony_ci
6718c2ecf20Sopenharmony_ci	return locked;
6728c2ecf20Sopenharmony_ci}
6738c2ecf20Sopenharmony_ci
6748c2ecf20Sopenharmony_civoid ovl_inuse_unlock(struct dentry *dentry)
6758c2ecf20Sopenharmony_ci{
6768c2ecf20Sopenharmony_ci	if (dentry) {
6778c2ecf20Sopenharmony_ci		struct inode *inode = d_inode(dentry);
6788c2ecf20Sopenharmony_ci
6798c2ecf20Sopenharmony_ci		spin_lock(&inode->i_lock);
6808c2ecf20Sopenharmony_ci		WARN_ON(!(inode->i_state & I_OVL_INUSE));
6818c2ecf20Sopenharmony_ci		inode->i_state &= ~I_OVL_INUSE;
6828c2ecf20Sopenharmony_ci		spin_unlock(&inode->i_lock);
6838c2ecf20Sopenharmony_ci	}
6848c2ecf20Sopenharmony_ci}
6858c2ecf20Sopenharmony_ci
6868c2ecf20Sopenharmony_cibool ovl_is_inuse(struct dentry *dentry)
6878c2ecf20Sopenharmony_ci{
6888c2ecf20Sopenharmony_ci	struct inode *inode = d_inode(dentry);
6898c2ecf20Sopenharmony_ci	bool inuse;
6908c2ecf20Sopenharmony_ci
6918c2ecf20Sopenharmony_ci	spin_lock(&inode->i_lock);
6928c2ecf20Sopenharmony_ci	inuse = (inode->i_state & I_OVL_INUSE);
6938c2ecf20Sopenharmony_ci	spin_unlock(&inode->i_lock);
6948c2ecf20Sopenharmony_ci
6958c2ecf20Sopenharmony_ci	return inuse;
6968c2ecf20Sopenharmony_ci}
6978c2ecf20Sopenharmony_ci
6988c2ecf20Sopenharmony_ci/*
6998c2ecf20Sopenharmony_ci * Does this overlay dentry need to be indexed on copy up?
7008c2ecf20Sopenharmony_ci */
7018c2ecf20Sopenharmony_cibool ovl_need_index(struct dentry *dentry)
7028c2ecf20Sopenharmony_ci{
7038c2ecf20Sopenharmony_ci	struct dentry *lower = ovl_dentry_lower(dentry);
7048c2ecf20Sopenharmony_ci
7058c2ecf20Sopenharmony_ci	if (!lower || !ovl_indexdir(dentry->d_sb))
7068c2ecf20Sopenharmony_ci		return false;
7078c2ecf20Sopenharmony_ci
7088c2ecf20Sopenharmony_ci	/* Index all files for NFS export and consistency verification */
7098c2ecf20Sopenharmony_ci	if (ovl_index_all(dentry->d_sb))
7108c2ecf20Sopenharmony_ci		return true;
7118c2ecf20Sopenharmony_ci
7128c2ecf20Sopenharmony_ci	/* Index only lower hardlinks on copy up */
7138c2ecf20Sopenharmony_ci	if (!d_is_dir(lower) && d_inode(lower)->i_nlink > 1)
7148c2ecf20Sopenharmony_ci		return true;
7158c2ecf20Sopenharmony_ci
7168c2ecf20Sopenharmony_ci	return false;
7178c2ecf20Sopenharmony_ci}
7188c2ecf20Sopenharmony_ci
7198c2ecf20Sopenharmony_ci/* Caller must hold OVL_I(inode)->lock */
7208c2ecf20Sopenharmony_cistatic void ovl_cleanup_index(struct dentry *dentry)
7218c2ecf20Sopenharmony_ci{
7228c2ecf20Sopenharmony_ci	struct dentry *indexdir = ovl_indexdir(dentry->d_sb);
7238c2ecf20Sopenharmony_ci	struct inode *dir = indexdir->d_inode;
7248c2ecf20Sopenharmony_ci	struct dentry *lowerdentry = ovl_dentry_lower(dentry);
7258c2ecf20Sopenharmony_ci	struct dentry *upperdentry = ovl_dentry_upper(dentry);
7268c2ecf20Sopenharmony_ci	struct dentry *index = NULL;
7278c2ecf20Sopenharmony_ci	struct inode *inode;
7288c2ecf20Sopenharmony_ci	struct qstr name = { };
7298c2ecf20Sopenharmony_ci	int err;
7308c2ecf20Sopenharmony_ci
7318c2ecf20Sopenharmony_ci	err = ovl_get_index_name(lowerdentry, &name);
7328c2ecf20Sopenharmony_ci	if (err)
7338c2ecf20Sopenharmony_ci		goto fail;
7348c2ecf20Sopenharmony_ci
7358c2ecf20Sopenharmony_ci	inode = d_inode(upperdentry);
7368c2ecf20Sopenharmony_ci	if (!S_ISDIR(inode->i_mode) && inode->i_nlink != 1) {
7378c2ecf20Sopenharmony_ci		pr_warn_ratelimited("cleanup linked index (%pd2, ino=%lu, nlink=%u)\n",
7388c2ecf20Sopenharmony_ci				    upperdentry, inode->i_ino, inode->i_nlink);
7398c2ecf20Sopenharmony_ci		/*
7408c2ecf20Sopenharmony_ci		 * We either have a bug with persistent union nlink or a lower
7418c2ecf20Sopenharmony_ci		 * hardlink was added while overlay is mounted. Adding a lower
7428c2ecf20Sopenharmony_ci		 * hardlink and then unlinking all overlay hardlinks would drop
7438c2ecf20Sopenharmony_ci		 * overlay nlink to zero before all upper inodes are unlinked.
7448c2ecf20Sopenharmony_ci		 * As a safety measure, when that situation is detected, set
7458c2ecf20Sopenharmony_ci		 * the overlay nlink to the index inode nlink minus one for the
7468c2ecf20Sopenharmony_ci		 * index entry itself.
7478c2ecf20Sopenharmony_ci		 */
7488c2ecf20Sopenharmony_ci		set_nlink(d_inode(dentry), inode->i_nlink - 1);
7498c2ecf20Sopenharmony_ci		ovl_set_nlink_upper(dentry);
7508c2ecf20Sopenharmony_ci		goto out;
7518c2ecf20Sopenharmony_ci	}
7528c2ecf20Sopenharmony_ci
7538c2ecf20Sopenharmony_ci	inode_lock_nested(dir, I_MUTEX_PARENT);
7548c2ecf20Sopenharmony_ci	index = lookup_one_len(name.name, indexdir, name.len);
7558c2ecf20Sopenharmony_ci	err = PTR_ERR(index);
7568c2ecf20Sopenharmony_ci	if (IS_ERR(index)) {
7578c2ecf20Sopenharmony_ci		index = NULL;
7588c2ecf20Sopenharmony_ci	} else if (ovl_index_all(dentry->d_sb)) {
7598c2ecf20Sopenharmony_ci		/* Whiteout orphan index to block future open by handle */
7608c2ecf20Sopenharmony_ci		err = ovl_cleanup_and_whiteout(OVL_FS(dentry->d_sb),
7618c2ecf20Sopenharmony_ci					       dir, index);
7628c2ecf20Sopenharmony_ci	} else {
7638c2ecf20Sopenharmony_ci		/* Cleanup orphan index entries */
7648c2ecf20Sopenharmony_ci		err = ovl_cleanup(dir, index);
7658c2ecf20Sopenharmony_ci	}
7668c2ecf20Sopenharmony_ci
7678c2ecf20Sopenharmony_ci	inode_unlock(dir);
7688c2ecf20Sopenharmony_ci	if (err)
7698c2ecf20Sopenharmony_ci		goto fail;
7708c2ecf20Sopenharmony_ci
7718c2ecf20Sopenharmony_ciout:
7728c2ecf20Sopenharmony_ci	kfree(name.name);
7738c2ecf20Sopenharmony_ci	dput(index);
7748c2ecf20Sopenharmony_ci	return;
7758c2ecf20Sopenharmony_ci
7768c2ecf20Sopenharmony_cifail:
7778c2ecf20Sopenharmony_ci	pr_err("cleanup index of '%pd2' failed (%i)\n", dentry, err);
7788c2ecf20Sopenharmony_ci	goto out;
7798c2ecf20Sopenharmony_ci}
7808c2ecf20Sopenharmony_ci
7818c2ecf20Sopenharmony_ci/*
7828c2ecf20Sopenharmony_ci * Operations that change overlay inode and upper inode nlink need to be
7838c2ecf20Sopenharmony_ci * synchronized with copy up for persistent nlink accounting.
7848c2ecf20Sopenharmony_ci */
7858c2ecf20Sopenharmony_ciint ovl_nlink_start(struct dentry *dentry)
7868c2ecf20Sopenharmony_ci{
7878c2ecf20Sopenharmony_ci	struct inode *inode = d_inode(dentry);
7888c2ecf20Sopenharmony_ci	const struct cred *old_cred;
7898c2ecf20Sopenharmony_ci	int err;
7908c2ecf20Sopenharmony_ci
7918c2ecf20Sopenharmony_ci	if (WARN_ON(!inode))
7928c2ecf20Sopenharmony_ci		return -ENOENT;
7938c2ecf20Sopenharmony_ci
7948c2ecf20Sopenharmony_ci	/*
7958c2ecf20Sopenharmony_ci	 * With inodes index is enabled, we store the union overlay nlink
7968c2ecf20Sopenharmony_ci	 * in an xattr on the index inode. When whiting out an indexed lower,
7978c2ecf20Sopenharmony_ci	 * we need to decrement the overlay persistent nlink, but before the
7988c2ecf20Sopenharmony_ci	 * first copy up, we have no upper index inode to store the xattr.
7998c2ecf20Sopenharmony_ci	 *
8008c2ecf20Sopenharmony_ci	 * As a workaround, before whiteout/rename over an indexed lower,
8018c2ecf20Sopenharmony_ci	 * copy up to create the upper index. Creating the upper index will
8028c2ecf20Sopenharmony_ci	 * initialize the overlay nlink, so it could be dropped if unlink
8038c2ecf20Sopenharmony_ci	 * or rename succeeds.
8048c2ecf20Sopenharmony_ci	 *
8058c2ecf20Sopenharmony_ci	 * TODO: implement metadata only index copy up when called with
8068c2ecf20Sopenharmony_ci	 *       ovl_copy_up_flags(dentry, O_PATH).
8078c2ecf20Sopenharmony_ci	 */
8088c2ecf20Sopenharmony_ci	if (ovl_need_index(dentry) && !ovl_dentry_has_upper_alias(dentry)) {
8098c2ecf20Sopenharmony_ci		err = ovl_copy_up(dentry);
8108c2ecf20Sopenharmony_ci		if (err)
8118c2ecf20Sopenharmony_ci			return err;
8128c2ecf20Sopenharmony_ci	}
8138c2ecf20Sopenharmony_ci
8148c2ecf20Sopenharmony_ci	err = ovl_inode_lock_interruptible(inode);
8158c2ecf20Sopenharmony_ci	if (err)
8168c2ecf20Sopenharmony_ci		return err;
8178c2ecf20Sopenharmony_ci
8188c2ecf20Sopenharmony_ci	if (d_is_dir(dentry) || !ovl_test_flag(OVL_INDEX, inode))
8198c2ecf20Sopenharmony_ci		goto out;
8208c2ecf20Sopenharmony_ci
8218c2ecf20Sopenharmony_ci	old_cred = ovl_override_creds(dentry->d_sb);
8228c2ecf20Sopenharmony_ci	/*
8238c2ecf20Sopenharmony_ci	 * The overlay inode nlink should be incremented/decremented IFF the
8248c2ecf20Sopenharmony_ci	 * upper operation succeeds, along with nlink change of upper inode.
8258c2ecf20Sopenharmony_ci	 * Therefore, before link/unlink/rename, we store the union nlink
8268c2ecf20Sopenharmony_ci	 * value relative to the upper inode nlink in an upper inode xattr.
8278c2ecf20Sopenharmony_ci	 */
8288c2ecf20Sopenharmony_ci	err = ovl_set_nlink_upper(dentry);
8298c2ecf20Sopenharmony_ci	revert_creds(old_cred);
8308c2ecf20Sopenharmony_ci
8318c2ecf20Sopenharmony_ciout:
8328c2ecf20Sopenharmony_ci	if (err)
8338c2ecf20Sopenharmony_ci		ovl_inode_unlock(inode);
8348c2ecf20Sopenharmony_ci
8358c2ecf20Sopenharmony_ci	return err;
8368c2ecf20Sopenharmony_ci}
8378c2ecf20Sopenharmony_ci
8388c2ecf20Sopenharmony_civoid ovl_nlink_end(struct dentry *dentry)
8398c2ecf20Sopenharmony_ci{
8408c2ecf20Sopenharmony_ci	struct inode *inode = d_inode(dentry);
8418c2ecf20Sopenharmony_ci
8428c2ecf20Sopenharmony_ci	if (ovl_test_flag(OVL_INDEX, inode) && inode->i_nlink == 0) {
8438c2ecf20Sopenharmony_ci		const struct cred *old_cred;
8448c2ecf20Sopenharmony_ci
8458c2ecf20Sopenharmony_ci		old_cred = ovl_override_creds(dentry->d_sb);
8468c2ecf20Sopenharmony_ci		ovl_cleanup_index(dentry);
8478c2ecf20Sopenharmony_ci		revert_creds(old_cred);
8488c2ecf20Sopenharmony_ci	}
8498c2ecf20Sopenharmony_ci
8508c2ecf20Sopenharmony_ci	ovl_inode_unlock(inode);
8518c2ecf20Sopenharmony_ci}
8528c2ecf20Sopenharmony_ci
8538c2ecf20Sopenharmony_ciint ovl_lock_rename_workdir(struct dentry *workdir, struct dentry *upperdir)
8548c2ecf20Sopenharmony_ci{
8558c2ecf20Sopenharmony_ci	/* Workdir should not be the same as upperdir */
8568c2ecf20Sopenharmony_ci	if (workdir == upperdir)
8578c2ecf20Sopenharmony_ci		goto err;
8588c2ecf20Sopenharmony_ci
8598c2ecf20Sopenharmony_ci	/* Workdir should not be subdir of upperdir and vice versa */
8608c2ecf20Sopenharmony_ci	if (lock_rename(workdir, upperdir) != NULL)
8618c2ecf20Sopenharmony_ci		goto err_unlock;
8628c2ecf20Sopenharmony_ci
8638c2ecf20Sopenharmony_ci	return 0;
8648c2ecf20Sopenharmony_ci
8658c2ecf20Sopenharmony_cierr_unlock:
8668c2ecf20Sopenharmony_ci	unlock_rename(workdir, upperdir);
8678c2ecf20Sopenharmony_cierr:
8688c2ecf20Sopenharmony_ci	pr_err("failed to lock workdir+upperdir\n");
8698c2ecf20Sopenharmony_ci	return -EIO;
8708c2ecf20Sopenharmony_ci}
8718c2ecf20Sopenharmony_ci
8728c2ecf20Sopenharmony_ci/* err < 0, 0 if no metacopy xattr, 1 if metacopy xattr found */
8738c2ecf20Sopenharmony_ciint ovl_check_metacopy_xattr(struct ovl_fs *ofs, struct dentry *dentry)
8748c2ecf20Sopenharmony_ci{
8758c2ecf20Sopenharmony_ci	int res;
8768c2ecf20Sopenharmony_ci
8778c2ecf20Sopenharmony_ci	/* Only regular files can have metacopy xattr */
8788c2ecf20Sopenharmony_ci	if (!S_ISREG(d_inode(dentry)->i_mode))
8798c2ecf20Sopenharmony_ci		return 0;
8808c2ecf20Sopenharmony_ci
8818c2ecf20Sopenharmony_ci	res = ovl_do_getxattr(ofs, dentry, OVL_XATTR_METACOPY, NULL, 0);
8828c2ecf20Sopenharmony_ci	if (res < 0) {
8838c2ecf20Sopenharmony_ci		if (res == -ENODATA || res == -EOPNOTSUPP)
8848c2ecf20Sopenharmony_ci			return 0;
8858c2ecf20Sopenharmony_ci		goto out;
8868c2ecf20Sopenharmony_ci	}
8878c2ecf20Sopenharmony_ci
8888c2ecf20Sopenharmony_ci	return 1;
8898c2ecf20Sopenharmony_ciout:
8908c2ecf20Sopenharmony_ci	pr_warn_ratelimited("failed to get metacopy (%i)\n", res);
8918c2ecf20Sopenharmony_ci	return res;
8928c2ecf20Sopenharmony_ci}
8938c2ecf20Sopenharmony_ci
8948c2ecf20Sopenharmony_cibool ovl_is_metacopy_dentry(struct dentry *dentry)
8958c2ecf20Sopenharmony_ci{
8968c2ecf20Sopenharmony_ci	struct ovl_entry *oe = dentry->d_fsdata;
8978c2ecf20Sopenharmony_ci
8988c2ecf20Sopenharmony_ci	if (!d_is_reg(dentry))
8998c2ecf20Sopenharmony_ci		return false;
9008c2ecf20Sopenharmony_ci
9018c2ecf20Sopenharmony_ci	if (ovl_dentry_upper(dentry)) {
9028c2ecf20Sopenharmony_ci		if (!ovl_has_upperdata(d_inode(dentry)))
9038c2ecf20Sopenharmony_ci			return true;
9048c2ecf20Sopenharmony_ci		return false;
9058c2ecf20Sopenharmony_ci	}
9068c2ecf20Sopenharmony_ci
9078c2ecf20Sopenharmony_ci	return (oe->numlower > 1);
9088c2ecf20Sopenharmony_ci}
9098c2ecf20Sopenharmony_ci
9108c2ecf20Sopenharmony_cichar *ovl_get_redirect_xattr(struct ovl_fs *ofs, struct dentry *dentry,
9118c2ecf20Sopenharmony_ci			     int padding)
9128c2ecf20Sopenharmony_ci{
9138c2ecf20Sopenharmony_ci	int res;
9148c2ecf20Sopenharmony_ci	char *s, *next, *buf = NULL;
9158c2ecf20Sopenharmony_ci
9168c2ecf20Sopenharmony_ci	res = ovl_do_getxattr(ofs, dentry, OVL_XATTR_REDIRECT, NULL, 0);
9178c2ecf20Sopenharmony_ci	if (res == -ENODATA || res == -EOPNOTSUPP)
9188c2ecf20Sopenharmony_ci		return NULL;
9198c2ecf20Sopenharmony_ci	if (res < 0)
9208c2ecf20Sopenharmony_ci		goto fail;
9218c2ecf20Sopenharmony_ci	if (res == 0)
9228c2ecf20Sopenharmony_ci		goto invalid;
9238c2ecf20Sopenharmony_ci
9248c2ecf20Sopenharmony_ci	buf = kzalloc(res + padding + 1, GFP_KERNEL);
9258c2ecf20Sopenharmony_ci	if (!buf)
9268c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
9278c2ecf20Sopenharmony_ci
9288c2ecf20Sopenharmony_ci	res = ovl_do_getxattr(ofs, dentry, OVL_XATTR_REDIRECT, buf, res);
9298c2ecf20Sopenharmony_ci	if (res < 0)
9308c2ecf20Sopenharmony_ci		goto fail;
9318c2ecf20Sopenharmony_ci	if (res == 0)
9328c2ecf20Sopenharmony_ci		goto invalid;
9338c2ecf20Sopenharmony_ci
9348c2ecf20Sopenharmony_ci	if (buf[0] == '/') {
9358c2ecf20Sopenharmony_ci		for (s = buf; *s++ == '/'; s = next) {
9368c2ecf20Sopenharmony_ci			next = strchrnul(s, '/');
9378c2ecf20Sopenharmony_ci			if (s == next)
9388c2ecf20Sopenharmony_ci				goto invalid;
9398c2ecf20Sopenharmony_ci		}
9408c2ecf20Sopenharmony_ci	} else {
9418c2ecf20Sopenharmony_ci		if (strchr(buf, '/') != NULL)
9428c2ecf20Sopenharmony_ci			goto invalid;
9438c2ecf20Sopenharmony_ci	}
9448c2ecf20Sopenharmony_ci
9458c2ecf20Sopenharmony_ci	return buf;
9468c2ecf20Sopenharmony_ciinvalid:
9478c2ecf20Sopenharmony_ci	pr_warn_ratelimited("invalid redirect (%s)\n", buf);
9488c2ecf20Sopenharmony_ci	res = -EINVAL;
9498c2ecf20Sopenharmony_ci	goto err_free;
9508c2ecf20Sopenharmony_cifail:
9518c2ecf20Sopenharmony_ci	pr_warn_ratelimited("failed to get redirect (%i)\n", res);
9528c2ecf20Sopenharmony_cierr_free:
9538c2ecf20Sopenharmony_ci	kfree(buf);
9548c2ecf20Sopenharmony_ci	return ERR_PTR(res);
9558c2ecf20Sopenharmony_ci}
9568c2ecf20Sopenharmony_ci
9578c2ecf20Sopenharmony_ci/*
9588c2ecf20Sopenharmony_ci * ovl_sync_status() - Check fs sync status for volatile mounts
9598c2ecf20Sopenharmony_ci *
9608c2ecf20Sopenharmony_ci * Returns 1 if this is not a volatile mount and a real sync is required.
9618c2ecf20Sopenharmony_ci *
9628c2ecf20Sopenharmony_ci * Returns 0 if syncing can be skipped because mount is volatile, and no errors
9638c2ecf20Sopenharmony_ci * have occurred on the upperdir since the mount.
9648c2ecf20Sopenharmony_ci *
9658c2ecf20Sopenharmony_ci * Returns -errno if it is a volatile mount, and the error that occurred since
9668c2ecf20Sopenharmony_ci * the last mount. If the error code changes, it'll return the latest error
9678c2ecf20Sopenharmony_ci * code.
9688c2ecf20Sopenharmony_ci */
9698c2ecf20Sopenharmony_ci
9708c2ecf20Sopenharmony_ciint ovl_sync_status(struct ovl_fs *ofs)
9718c2ecf20Sopenharmony_ci{
9728c2ecf20Sopenharmony_ci	struct vfsmount *mnt;
9738c2ecf20Sopenharmony_ci
9748c2ecf20Sopenharmony_ci	if (ovl_should_sync(ofs))
9758c2ecf20Sopenharmony_ci		return 1;
9768c2ecf20Sopenharmony_ci
9778c2ecf20Sopenharmony_ci	mnt = ovl_upper_mnt(ofs);
9788c2ecf20Sopenharmony_ci	if (!mnt)
9798c2ecf20Sopenharmony_ci		return 0;
9808c2ecf20Sopenharmony_ci
9818c2ecf20Sopenharmony_ci	return errseq_check(&mnt->mnt_sb->s_wb_err, ofs->errseq);
9828c2ecf20Sopenharmony_ci}
983