18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Copyright (C) 2011 Novell Inc.
58c2ecf20Sopenharmony_ci */
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci#include <uapi/linux/magic.h>
88c2ecf20Sopenharmony_ci#include <linux/fs.h>
98c2ecf20Sopenharmony_ci#include <linux/namei.h>
108c2ecf20Sopenharmony_ci#include <linux/xattr.h>
118c2ecf20Sopenharmony_ci#include <linux/mount.h>
128c2ecf20Sopenharmony_ci#include <linux/parser.h>
138c2ecf20Sopenharmony_ci#include <linux/module.h>
148c2ecf20Sopenharmony_ci#include <linux/statfs.h>
158c2ecf20Sopenharmony_ci#include <linux/seq_file.h>
168c2ecf20Sopenharmony_ci#include <linux/posix_acl_xattr.h>
178c2ecf20Sopenharmony_ci#include <linux/exportfs.h>
188c2ecf20Sopenharmony_ci#include "overlayfs.h"
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ciMODULE_AUTHOR("Miklos Szeredi <miklos@szeredi.hu>");
218c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Overlay filesystem");
228c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_cistruct ovl_dir_cache;
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci#define OVL_MAX_STACK 500
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_cistatic bool ovl_redirect_dir_def = IS_ENABLED(CONFIG_OVERLAY_FS_REDIRECT_DIR);
308c2ecf20Sopenharmony_cimodule_param_named(redirect_dir, ovl_redirect_dir_def, bool, 0644);
318c2ecf20Sopenharmony_ciMODULE_PARM_DESC(redirect_dir,
328c2ecf20Sopenharmony_ci		 "Default to on or off for the redirect_dir feature");
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_cistatic bool ovl_redirect_always_follow =
358c2ecf20Sopenharmony_ci	IS_ENABLED(CONFIG_OVERLAY_FS_REDIRECT_ALWAYS_FOLLOW);
368c2ecf20Sopenharmony_cimodule_param_named(redirect_always_follow, ovl_redirect_always_follow,
378c2ecf20Sopenharmony_ci		   bool, 0644);
388c2ecf20Sopenharmony_ciMODULE_PARM_DESC(redirect_always_follow,
398c2ecf20Sopenharmony_ci		 "Follow redirects even if redirect_dir feature is turned off");
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_cistatic bool ovl_index_def = IS_ENABLED(CONFIG_OVERLAY_FS_INDEX);
428c2ecf20Sopenharmony_cimodule_param_named(index, ovl_index_def, bool, 0644);
438c2ecf20Sopenharmony_ciMODULE_PARM_DESC(index,
448c2ecf20Sopenharmony_ci		 "Default to on or off for the inodes index feature");
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_cistatic bool ovl_nfs_export_def = IS_ENABLED(CONFIG_OVERLAY_FS_NFS_EXPORT);
478c2ecf20Sopenharmony_cimodule_param_named(nfs_export, ovl_nfs_export_def, bool, 0644);
488c2ecf20Sopenharmony_ciMODULE_PARM_DESC(nfs_export,
498c2ecf20Sopenharmony_ci		 "Default to on or off for the NFS export feature");
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_cistatic bool ovl_xino_auto_def = IS_ENABLED(CONFIG_OVERLAY_FS_XINO_AUTO);
528c2ecf20Sopenharmony_cimodule_param_named(xino_auto, ovl_xino_auto_def, bool, 0644);
538c2ecf20Sopenharmony_ciMODULE_PARM_DESC(xino_auto,
548c2ecf20Sopenharmony_ci		 "Auto enable xino feature");
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_cistatic void ovl_entry_stack_free(struct ovl_entry *oe)
578c2ecf20Sopenharmony_ci{
588c2ecf20Sopenharmony_ci	unsigned int i;
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci	for (i = 0; i < oe->numlower; i++)
618c2ecf20Sopenharmony_ci		dput(oe->lowerstack[i].dentry);
628c2ecf20Sopenharmony_ci}
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_cistatic bool ovl_metacopy_def = IS_ENABLED(CONFIG_OVERLAY_FS_METACOPY);
658c2ecf20Sopenharmony_cimodule_param_named(metacopy, ovl_metacopy_def, bool, 0644);
668c2ecf20Sopenharmony_ciMODULE_PARM_DESC(metacopy,
678c2ecf20Sopenharmony_ci		 "Default to on or off for the metadata only copy up feature");
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_cistatic void ovl_dentry_release(struct dentry *dentry)
708c2ecf20Sopenharmony_ci{
718c2ecf20Sopenharmony_ci	struct ovl_entry *oe = dentry->d_fsdata;
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	if (oe) {
748c2ecf20Sopenharmony_ci		ovl_entry_stack_free(oe);
758c2ecf20Sopenharmony_ci		kfree_rcu(oe, rcu);
768c2ecf20Sopenharmony_ci	}
778c2ecf20Sopenharmony_ci}
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_cistatic struct dentry *ovl_d_real(struct dentry *dentry,
808c2ecf20Sopenharmony_ci				 const struct inode *inode)
818c2ecf20Sopenharmony_ci{
828c2ecf20Sopenharmony_ci	struct dentry *real = NULL, *lower;
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci	/* It's an overlay file */
858c2ecf20Sopenharmony_ci	if (inode && d_inode(dentry) == inode)
868c2ecf20Sopenharmony_ci		return dentry;
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	if (!d_is_reg(dentry)) {
898c2ecf20Sopenharmony_ci		if (!inode || inode == d_inode(dentry))
908c2ecf20Sopenharmony_ci			return dentry;
918c2ecf20Sopenharmony_ci		goto bug;
928c2ecf20Sopenharmony_ci	}
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	real = ovl_dentry_upper(dentry);
958c2ecf20Sopenharmony_ci	if (real && (inode == d_inode(real)))
968c2ecf20Sopenharmony_ci		return real;
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	if (real && !inode && ovl_has_upperdata(d_inode(dentry)))
998c2ecf20Sopenharmony_ci		return real;
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	lower = ovl_dentry_lowerdata(dentry);
1028c2ecf20Sopenharmony_ci	if (!lower)
1038c2ecf20Sopenharmony_ci		goto bug;
1048c2ecf20Sopenharmony_ci	real = lower;
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	/* Handle recursion */
1078c2ecf20Sopenharmony_ci	real = d_real(real, inode);
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	if (!inode || inode == d_inode(real))
1108c2ecf20Sopenharmony_ci		return real;
1118c2ecf20Sopenharmony_cibug:
1128c2ecf20Sopenharmony_ci	WARN(1, "%s(%pd4, %s:%lu): real dentry (%p/%lu) not found\n",
1138c2ecf20Sopenharmony_ci	     __func__, dentry, inode ? inode->i_sb->s_id : "NULL",
1148c2ecf20Sopenharmony_ci	     inode ? inode->i_ino : 0, real,
1158c2ecf20Sopenharmony_ci	     real && d_inode(real) ? d_inode(real)->i_ino : 0);
1168c2ecf20Sopenharmony_ci	return dentry;
1178c2ecf20Sopenharmony_ci}
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_cistatic int ovl_revalidate_real(struct dentry *d, unsigned int flags, bool weak)
1208c2ecf20Sopenharmony_ci{
1218c2ecf20Sopenharmony_ci	int ret = 1;
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	if (weak) {
1248c2ecf20Sopenharmony_ci		if (d->d_flags & DCACHE_OP_WEAK_REVALIDATE)
1258c2ecf20Sopenharmony_ci			ret =  d->d_op->d_weak_revalidate(d, flags);
1268c2ecf20Sopenharmony_ci	} else if (d->d_flags & DCACHE_OP_REVALIDATE) {
1278c2ecf20Sopenharmony_ci		ret = d->d_op->d_revalidate(d, flags);
1288c2ecf20Sopenharmony_ci		if (!ret) {
1298c2ecf20Sopenharmony_ci			if (!(flags & LOOKUP_RCU))
1308c2ecf20Sopenharmony_ci				d_invalidate(d);
1318c2ecf20Sopenharmony_ci			ret = -ESTALE;
1328c2ecf20Sopenharmony_ci		}
1338c2ecf20Sopenharmony_ci	}
1348c2ecf20Sopenharmony_ci	return ret;
1358c2ecf20Sopenharmony_ci}
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_cistatic int ovl_dentry_revalidate_common(struct dentry *dentry,
1388c2ecf20Sopenharmony_ci					unsigned int flags, bool weak)
1398c2ecf20Sopenharmony_ci{
1408c2ecf20Sopenharmony_ci	struct ovl_entry *oe = dentry->d_fsdata;
1418c2ecf20Sopenharmony_ci	struct inode *inode = d_inode_rcu(dentry);
1428c2ecf20Sopenharmony_ci	struct dentry *upper;
1438c2ecf20Sopenharmony_ci	unsigned int i;
1448c2ecf20Sopenharmony_ci	int ret = 1;
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci	/* Careful in RCU mode */
1478c2ecf20Sopenharmony_ci	if (!inode)
1488c2ecf20Sopenharmony_ci		return -ECHILD;
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	upper = ovl_i_dentry_upper(inode);
1518c2ecf20Sopenharmony_ci	if (upper)
1528c2ecf20Sopenharmony_ci		ret = ovl_revalidate_real(upper, flags, weak);
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	for (i = 0; ret > 0 && i < oe->numlower; i++) {
1558c2ecf20Sopenharmony_ci		ret = ovl_revalidate_real(oe->lowerstack[i].dentry, flags,
1568c2ecf20Sopenharmony_ci					  weak);
1578c2ecf20Sopenharmony_ci	}
1588c2ecf20Sopenharmony_ci	return ret;
1598c2ecf20Sopenharmony_ci}
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_cistatic int ovl_dentry_revalidate(struct dentry *dentry, unsigned int flags)
1628c2ecf20Sopenharmony_ci{
1638c2ecf20Sopenharmony_ci	return ovl_dentry_revalidate_common(dentry, flags, false);
1648c2ecf20Sopenharmony_ci}
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_cistatic int ovl_dentry_weak_revalidate(struct dentry *dentry, unsigned int flags)
1678c2ecf20Sopenharmony_ci{
1688c2ecf20Sopenharmony_ci	return ovl_dentry_revalidate_common(dentry, flags, true);
1698c2ecf20Sopenharmony_ci}
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_cistatic const struct dentry_operations ovl_dentry_operations = {
1728c2ecf20Sopenharmony_ci	.d_release = ovl_dentry_release,
1738c2ecf20Sopenharmony_ci	.d_real = ovl_d_real,
1748c2ecf20Sopenharmony_ci	.d_revalidate = ovl_dentry_revalidate,
1758c2ecf20Sopenharmony_ci	.d_weak_revalidate = ovl_dentry_weak_revalidate,
1768c2ecf20Sopenharmony_ci};
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_cistatic struct kmem_cache *ovl_inode_cachep;
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_cistatic struct inode *ovl_alloc_inode(struct super_block *sb)
1818c2ecf20Sopenharmony_ci{
1828c2ecf20Sopenharmony_ci	struct ovl_inode *oi = kmem_cache_alloc(ovl_inode_cachep, GFP_KERNEL);
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci	if (!oi)
1858c2ecf20Sopenharmony_ci		return NULL;
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci	oi->cache = NULL;
1888c2ecf20Sopenharmony_ci	oi->redirect = NULL;
1898c2ecf20Sopenharmony_ci	oi->version = 0;
1908c2ecf20Sopenharmony_ci	oi->flags = 0;
1918c2ecf20Sopenharmony_ci	oi->__upperdentry = NULL;
1928c2ecf20Sopenharmony_ci	oi->lower = NULL;
1938c2ecf20Sopenharmony_ci	oi->lowerdata = NULL;
1948c2ecf20Sopenharmony_ci	mutex_init(&oi->lock);
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci	return &oi->vfs_inode;
1978c2ecf20Sopenharmony_ci}
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_cistatic void ovl_free_inode(struct inode *inode)
2008c2ecf20Sopenharmony_ci{
2018c2ecf20Sopenharmony_ci	struct ovl_inode *oi = OVL_I(inode);
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	kfree(oi->redirect);
2048c2ecf20Sopenharmony_ci	mutex_destroy(&oi->lock);
2058c2ecf20Sopenharmony_ci	kmem_cache_free(ovl_inode_cachep, oi);
2068c2ecf20Sopenharmony_ci}
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_cistatic void ovl_destroy_inode(struct inode *inode)
2098c2ecf20Sopenharmony_ci{
2108c2ecf20Sopenharmony_ci	struct ovl_inode *oi = OVL_I(inode);
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci	dput(oi->__upperdentry);
2138c2ecf20Sopenharmony_ci	iput(oi->lower);
2148c2ecf20Sopenharmony_ci	if (S_ISDIR(inode->i_mode))
2158c2ecf20Sopenharmony_ci		ovl_dir_cache_free(inode);
2168c2ecf20Sopenharmony_ci	else
2178c2ecf20Sopenharmony_ci		iput(oi->lowerdata);
2188c2ecf20Sopenharmony_ci}
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_cistatic void ovl_free_fs(struct ovl_fs *ofs)
2218c2ecf20Sopenharmony_ci{
2228c2ecf20Sopenharmony_ci	struct vfsmount **mounts;
2238c2ecf20Sopenharmony_ci	unsigned i;
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci	iput(ofs->workbasedir_trap);
2268c2ecf20Sopenharmony_ci	iput(ofs->indexdir_trap);
2278c2ecf20Sopenharmony_ci	iput(ofs->workdir_trap);
2288c2ecf20Sopenharmony_ci	dput(ofs->whiteout);
2298c2ecf20Sopenharmony_ci	dput(ofs->indexdir);
2308c2ecf20Sopenharmony_ci	dput(ofs->workdir);
2318c2ecf20Sopenharmony_ci	if (ofs->workdir_locked)
2328c2ecf20Sopenharmony_ci		ovl_inuse_unlock(ofs->workbasedir);
2338c2ecf20Sopenharmony_ci	dput(ofs->workbasedir);
2348c2ecf20Sopenharmony_ci	if (ofs->upperdir_locked)
2358c2ecf20Sopenharmony_ci		ovl_inuse_unlock(ovl_upper_mnt(ofs)->mnt_root);
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci	/* Hack!  Reuse ofs->layers as a vfsmount array before freeing it */
2388c2ecf20Sopenharmony_ci	mounts = (struct vfsmount **) ofs->layers;
2398c2ecf20Sopenharmony_ci	for (i = 0; i < ofs->numlayer; i++) {
2408c2ecf20Sopenharmony_ci		iput(ofs->layers[i].trap);
2418c2ecf20Sopenharmony_ci		mounts[i] = ofs->layers[i].mnt;
2428c2ecf20Sopenharmony_ci	}
2438c2ecf20Sopenharmony_ci	kern_unmount_array(mounts, ofs->numlayer);
2448c2ecf20Sopenharmony_ci	kfree(ofs->layers);
2458c2ecf20Sopenharmony_ci	for (i = 0; i < ofs->numfs; i++)
2468c2ecf20Sopenharmony_ci		free_anon_bdev(ofs->fs[i].pseudo_dev);
2478c2ecf20Sopenharmony_ci	kfree(ofs->fs);
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci	kfree(ofs->config.lowerdir);
2508c2ecf20Sopenharmony_ci	kfree(ofs->config.upperdir);
2518c2ecf20Sopenharmony_ci	kfree(ofs->config.workdir);
2528c2ecf20Sopenharmony_ci	kfree(ofs->config.redirect_mode);
2538c2ecf20Sopenharmony_ci	if (ofs->creator_cred)
2548c2ecf20Sopenharmony_ci		put_cred(ofs->creator_cred);
2558c2ecf20Sopenharmony_ci	kfree(ofs);
2568c2ecf20Sopenharmony_ci}
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_cistatic void ovl_put_super(struct super_block *sb)
2598c2ecf20Sopenharmony_ci{
2608c2ecf20Sopenharmony_ci	struct ovl_fs *ofs = sb->s_fs_info;
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci	ovl_free_fs(ofs);
2638c2ecf20Sopenharmony_ci}
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci/* Sync real dirty inodes in upper filesystem (if it exists) */
2668c2ecf20Sopenharmony_cistatic int ovl_sync_fs(struct super_block *sb, int wait)
2678c2ecf20Sopenharmony_ci{
2688c2ecf20Sopenharmony_ci	struct ovl_fs *ofs = sb->s_fs_info;
2698c2ecf20Sopenharmony_ci	struct super_block *upper_sb;
2708c2ecf20Sopenharmony_ci	int ret;
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci	ret = ovl_sync_status(ofs);
2738c2ecf20Sopenharmony_ci	/*
2748c2ecf20Sopenharmony_ci	 * We have to always set the err, because the return value isn't
2758c2ecf20Sopenharmony_ci	 * checked in syncfs, and instead indirectly return an error via
2768c2ecf20Sopenharmony_ci	 * the sb's writeback errseq, which VFS inspects after this call.
2778c2ecf20Sopenharmony_ci	 */
2788c2ecf20Sopenharmony_ci	if (ret < 0) {
2798c2ecf20Sopenharmony_ci		errseq_set(&sb->s_wb_err, -EIO);
2808c2ecf20Sopenharmony_ci		return -EIO;
2818c2ecf20Sopenharmony_ci	}
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci	if (!ret)
2848c2ecf20Sopenharmony_ci		return ret;
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci	/*
2878c2ecf20Sopenharmony_ci	 * Not called for sync(2) call or an emergency sync (SB_I_SKIP_SYNC).
2888c2ecf20Sopenharmony_ci	 * All the super blocks will be iterated, including upper_sb.
2898c2ecf20Sopenharmony_ci	 *
2908c2ecf20Sopenharmony_ci	 * If this is a syncfs(2) call, then we do need to call
2918c2ecf20Sopenharmony_ci	 * sync_filesystem() on upper_sb, but enough if we do it when being
2928c2ecf20Sopenharmony_ci	 * called with wait == 1.
2938c2ecf20Sopenharmony_ci	 */
2948c2ecf20Sopenharmony_ci	if (!wait)
2958c2ecf20Sopenharmony_ci		return 0;
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci	upper_sb = ovl_upper_mnt(ofs)->mnt_sb;
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci	down_read(&upper_sb->s_umount);
3008c2ecf20Sopenharmony_ci	ret = sync_filesystem(upper_sb);
3018c2ecf20Sopenharmony_ci	up_read(&upper_sb->s_umount);
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci	return ret;
3048c2ecf20Sopenharmony_ci}
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci/**
3078c2ecf20Sopenharmony_ci * ovl_statfs
3088c2ecf20Sopenharmony_ci * @sb: The overlayfs super block
3098c2ecf20Sopenharmony_ci * @buf: The struct kstatfs to fill in with stats
3108c2ecf20Sopenharmony_ci *
3118c2ecf20Sopenharmony_ci * Get the filesystem statistics.  As writes always target the upper layer
3128c2ecf20Sopenharmony_ci * filesystem pass the statfs to the upper filesystem (if it exists)
3138c2ecf20Sopenharmony_ci */
3148c2ecf20Sopenharmony_cistatic int ovl_statfs(struct dentry *dentry, struct kstatfs *buf)
3158c2ecf20Sopenharmony_ci{
3168c2ecf20Sopenharmony_ci	struct ovl_fs *ofs = dentry->d_sb->s_fs_info;
3178c2ecf20Sopenharmony_ci	struct dentry *root_dentry = dentry->d_sb->s_root;
3188c2ecf20Sopenharmony_ci	struct path path;
3198c2ecf20Sopenharmony_ci	int err;
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci	ovl_path_real(root_dentry, &path);
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_ci	err = vfs_statfs(&path, buf);
3248c2ecf20Sopenharmony_ci	if (!err) {
3258c2ecf20Sopenharmony_ci		buf->f_namelen = ofs->namelen;
3268c2ecf20Sopenharmony_ci		buf->f_type = OVERLAYFS_SUPER_MAGIC;
3278c2ecf20Sopenharmony_ci	}
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci	return err;
3308c2ecf20Sopenharmony_ci}
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_ci/* Will this overlay be forced to mount/remount ro? */
3338c2ecf20Sopenharmony_cistatic bool ovl_force_readonly(struct ovl_fs *ofs)
3348c2ecf20Sopenharmony_ci{
3358c2ecf20Sopenharmony_ci	return (!ovl_upper_mnt(ofs) || !ofs->workdir);
3368c2ecf20Sopenharmony_ci}
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_cistatic const char *ovl_redirect_mode_def(void)
3398c2ecf20Sopenharmony_ci{
3408c2ecf20Sopenharmony_ci	return ovl_redirect_dir_def ? "on" : "off";
3418c2ecf20Sopenharmony_ci}
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_cistatic const char * const ovl_xino_str[] = {
3448c2ecf20Sopenharmony_ci	"off",
3458c2ecf20Sopenharmony_ci	"auto",
3468c2ecf20Sopenharmony_ci	"on",
3478c2ecf20Sopenharmony_ci};
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_cistatic inline int ovl_xino_def(void)
3508c2ecf20Sopenharmony_ci{
3518c2ecf20Sopenharmony_ci	return ovl_xino_auto_def ? OVL_XINO_AUTO : OVL_XINO_OFF;
3528c2ecf20Sopenharmony_ci}
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci/**
3558c2ecf20Sopenharmony_ci * ovl_show_options
3568c2ecf20Sopenharmony_ci *
3578c2ecf20Sopenharmony_ci * Prints the mount options for a given superblock.
3588c2ecf20Sopenharmony_ci * Returns zero; does not fail.
3598c2ecf20Sopenharmony_ci */
3608c2ecf20Sopenharmony_cistatic int ovl_show_options(struct seq_file *m, struct dentry *dentry)
3618c2ecf20Sopenharmony_ci{
3628c2ecf20Sopenharmony_ci	struct super_block *sb = dentry->d_sb;
3638c2ecf20Sopenharmony_ci	struct ovl_fs *ofs = sb->s_fs_info;
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci	seq_show_option(m, "lowerdir", ofs->config.lowerdir);
3668c2ecf20Sopenharmony_ci	if (ofs->config.upperdir) {
3678c2ecf20Sopenharmony_ci		seq_show_option(m, "upperdir", ofs->config.upperdir);
3688c2ecf20Sopenharmony_ci		seq_show_option(m, "workdir", ofs->config.workdir);
3698c2ecf20Sopenharmony_ci	}
3708c2ecf20Sopenharmony_ci	if (ofs->config.default_permissions)
3718c2ecf20Sopenharmony_ci		seq_puts(m, ",default_permissions");
3728c2ecf20Sopenharmony_ci	if (strcmp(ofs->config.redirect_mode, ovl_redirect_mode_def()) != 0)
3738c2ecf20Sopenharmony_ci		seq_printf(m, ",redirect_dir=%s", ofs->config.redirect_mode);
3748c2ecf20Sopenharmony_ci	if (ofs->config.index != ovl_index_def)
3758c2ecf20Sopenharmony_ci		seq_printf(m, ",index=%s", ofs->config.index ? "on" : "off");
3768c2ecf20Sopenharmony_ci	if (ofs->config.nfs_export != ovl_nfs_export_def)
3778c2ecf20Sopenharmony_ci		seq_printf(m, ",nfs_export=%s", ofs->config.nfs_export ?
3788c2ecf20Sopenharmony_ci						"on" : "off");
3798c2ecf20Sopenharmony_ci	if (ofs->config.xino != ovl_xino_def() && !ovl_same_fs(sb))
3808c2ecf20Sopenharmony_ci		seq_printf(m, ",xino=%s", ovl_xino_str[ofs->config.xino]);
3818c2ecf20Sopenharmony_ci	if (ofs->config.metacopy != ovl_metacopy_def)
3828c2ecf20Sopenharmony_ci		seq_printf(m, ",metacopy=%s",
3838c2ecf20Sopenharmony_ci			   ofs->config.metacopy ? "on" : "off");
3848c2ecf20Sopenharmony_ci	if (ofs->config.ovl_volatile)
3858c2ecf20Sopenharmony_ci		seq_puts(m, ",volatile");
3868c2ecf20Sopenharmony_ci	return 0;
3878c2ecf20Sopenharmony_ci}
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_cistatic int ovl_remount(struct super_block *sb, int *flags, char *data)
3908c2ecf20Sopenharmony_ci{
3918c2ecf20Sopenharmony_ci	struct ovl_fs *ofs = sb->s_fs_info;
3928c2ecf20Sopenharmony_ci	struct super_block *upper_sb;
3938c2ecf20Sopenharmony_ci	int ret = 0;
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_ci	if (!(*flags & SB_RDONLY) && ovl_force_readonly(ofs))
3968c2ecf20Sopenharmony_ci		return -EROFS;
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_ci	if (*flags & SB_RDONLY && !sb_rdonly(sb)) {
3998c2ecf20Sopenharmony_ci		upper_sb = ovl_upper_mnt(ofs)->mnt_sb;
4008c2ecf20Sopenharmony_ci		if (ovl_should_sync(ofs)) {
4018c2ecf20Sopenharmony_ci			down_read(&upper_sb->s_umount);
4028c2ecf20Sopenharmony_ci			ret = sync_filesystem(upper_sb);
4038c2ecf20Sopenharmony_ci			up_read(&upper_sb->s_umount);
4048c2ecf20Sopenharmony_ci		}
4058c2ecf20Sopenharmony_ci	}
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_ci	return ret;
4088c2ecf20Sopenharmony_ci}
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_cistatic const struct super_operations ovl_super_operations = {
4118c2ecf20Sopenharmony_ci	.alloc_inode	= ovl_alloc_inode,
4128c2ecf20Sopenharmony_ci	.free_inode	= ovl_free_inode,
4138c2ecf20Sopenharmony_ci	.destroy_inode	= ovl_destroy_inode,
4148c2ecf20Sopenharmony_ci	.drop_inode	= generic_delete_inode,
4158c2ecf20Sopenharmony_ci	.put_super	= ovl_put_super,
4168c2ecf20Sopenharmony_ci	.sync_fs	= ovl_sync_fs,
4178c2ecf20Sopenharmony_ci	.statfs		= ovl_statfs,
4188c2ecf20Sopenharmony_ci	.show_options	= ovl_show_options,
4198c2ecf20Sopenharmony_ci	.remount_fs	= ovl_remount,
4208c2ecf20Sopenharmony_ci};
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_cienum {
4238c2ecf20Sopenharmony_ci	OPT_LOWERDIR,
4248c2ecf20Sopenharmony_ci	OPT_UPPERDIR,
4258c2ecf20Sopenharmony_ci	OPT_WORKDIR,
4268c2ecf20Sopenharmony_ci	OPT_DEFAULT_PERMISSIONS,
4278c2ecf20Sopenharmony_ci	OPT_REDIRECT_DIR,
4288c2ecf20Sopenharmony_ci	OPT_INDEX_ON,
4298c2ecf20Sopenharmony_ci	OPT_INDEX_OFF,
4308c2ecf20Sopenharmony_ci	OPT_NFS_EXPORT_ON,
4318c2ecf20Sopenharmony_ci	OPT_NFS_EXPORT_OFF,
4328c2ecf20Sopenharmony_ci	OPT_XINO_ON,
4338c2ecf20Sopenharmony_ci	OPT_XINO_OFF,
4348c2ecf20Sopenharmony_ci	OPT_XINO_AUTO,
4358c2ecf20Sopenharmony_ci	OPT_METACOPY_ON,
4368c2ecf20Sopenharmony_ci	OPT_METACOPY_OFF,
4378c2ecf20Sopenharmony_ci	OPT_VOLATILE,
4388c2ecf20Sopenharmony_ci	OPT_ERR,
4398c2ecf20Sopenharmony_ci};
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_cistatic const match_table_t ovl_tokens = {
4428c2ecf20Sopenharmony_ci	{OPT_LOWERDIR,			"lowerdir=%s"},
4438c2ecf20Sopenharmony_ci	{OPT_UPPERDIR,			"upperdir=%s"},
4448c2ecf20Sopenharmony_ci	{OPT_WORKDIR,			"workdir=%s"},
4458c2ecf20Sopenharmony_ci	{OPT_DEFAULT_PERMISSIONS,	"default_permissions"},
4468c2ecf20Sopenharmony_ci	{OPT_REDIRECT_DIR,		"redirect_dir=%s"},
4478c2ecf20Sopenharmony_ci	{OPT_INDEX_ON,			"index=on"},
4488c2ecf20Sopenharmony_ci	{OPT_INDEX_OFF,			"index=off"},
4498c2ecf20Sopenharmony_ci	{OPT_NFS_EXPORT_ON,		"nfs_export=on"},
4508c2ecf20Sopenharmony_ci	{OPT_NFS_EXPORT_OFF,		"nfs_export=off"},
4518c2ecf20Sopenharmony_ci	{OPT_XINO_ON,			"xino=on"},
4528c2ecf20Sopenharmony_ci	{OPT_XINO_OFF,			"xino=off"},
4538c2ecf20Sopenharmony_ci	{OPT_XINO_AUTO,			"xino=auto"},
4548c2ecf20Sopenharmony_ci	{OPT_METACOPY_ON,		"metacopy=on"},
4558c2ecf20Sopenharmony_ci	{OPT_METACOPY_OFF,		"metacopy=off"},
4568c2ecf20Sopenharmony_ci	{OPT_VOLATILE,			"volatile"},
4578c2ecf20Sopenharmony_ci	{OPT_ERR,			NULL}
4588c2ecf20Sopenharmony_ci};
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_cistatic char *ovl_next_opt(char **s)
4618c2ecf20Sopenharmony_ci{
4628c2ecf20Sopenharmony_ci	char *sbegin = *s;
4638c2ecf20Sopenharmony_ci	char *p;
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_ci	if (sbegin == NULL)
4668c2ecf20Sopenharmony_ci		return NULL;
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_ci	for (p = sbegin; *p; p++) {
4698c2ecf20Sopenharmony_ci		if (*p == '\\') {
4708c2ecf20Sopenharmony_ci			p++;
4718c2ecf20Sopenharmony_ci			if (!*p)
4728c2ecf20Sopenharmony_ci				break;
4738c2ecf20Sopenharmony_ci		} else if (*p == ',') {
4748c2ecf20Sopenharmony_ci			*p = '\0';
4758c2ecf20Sopenharmony_ci			*s = p + 1;
4768c2ecf20Sopenharmony_ci			return sbegin;
4778c2ecf20Sopenharmony_ci		}
4788c2ecf20Sopenharmony_ci	}
4798c2ecf20Sopenharmony_ci	*s = NULL;
4808c2ecf20Sopenharmony_ci	return sbegin;
4818c2ecf20Sopenharmony_ci}
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_cistatic int ovl_parse_redirect_mode(struct ovl_config *config, const char *mode)
4848c2ecf20Sopenharmony_ci{
4858c2ecf20Sopenharmony_ci	if (strcmp(mode, "on") == 0) {
4868c2ecf20Sopenharmony_ci		config->redirect_dir = true;
4878c2ecf20Sopenharmony_ci		/*
4888c2ecf20Sopenharmony_ci		 * Does not make sense to have redirect creation without
4898c2ecf20Sopenharmony_ci		 * redirect following.
4908c2ecf20Sopenharmony_ci		 */
4918c2ecf20Sopenharmony_ci		config->redirect_follow = true;
4928c2ecf20Sopenharmony_ci	} else if (strcmp(mode, "follow") == 0) {
4938c2ecf20Sopenharmony_ci		config->redirect_follow = true;
4948c2ecf20Sopenharmony_ci	} else if (strcmp(mode, "off") == 0) {
4958c2ecf20Sopenharmony_ci		if (ovl_redirect_always_follow)
4968c2ecf20Sopenharmony_ci			config->redirect_follow = true;
4978c2ecf20Sopenharmony_ci	} else if (strcmp(mode, "nofollow") != 0) {
4988c2ecf20Sopenharmony_ci		pr_err("bad mount option \"redirect_dir=%s\"\n",
4998c2ecf20Sopenharmony_ci		       mode);
5008c2ecf20Sopenharmony_ci		return -EINVAL;
5018c2ecf20Sopenharmony_ci	}
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_ci	return 0;
5048c2ecf20Sopenharmony_ci}
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_cistatic int ovl_parse_opt(char *opt, struct ovl_config *config)
5078c2ecf20Sopenharmony_ci{
5088c2ecf20Sopenharmony_ci	char *p;
5098c2ecf20Sopenharmony_ci	int err;
5108c2ecf20Sopenharmony_ci	bool metacopy_opt = false, redirect_opt = false;
5118c2ecf20Sopenharmony_ci	bool nfs_export_opt = false, index_opt = false;
5128c2ecf20Sopenharmony_ci
5138c2ecf20Sopenharmony_ci	config->redirect_mode = kstrdup(ovl_redirect_mode_def(), GFP_KERNEL);
5148c2ecf20Sopenharmony_ci	if (!config->redirect_mode)
5158c2ecf20Sopenharmony_ci		return -ENOMEM;
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_ci	while ((p = ovl_next_opt(&opt)) != NULL) {
5188c2ecf20Sopenharmony_ci		int token;
5198c2ecf20Sopenharmony_ci		substring_t args[MAX_OPT_ARGS];
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_ci		if (!*p)
5228c2ecf20Sopenharmony_ci			continue;
5238c2ecf20Sopenharmony_ci
5248c2ecf20Sopenharmony_ci		token = match_token(p, ovl_tokens, args);
5258c2ecf20Sopenharmony_ci		switch (token) {
5268c2ecf20Sopenharmony_ci		case OPT_UPPERDIR:
5278c2ecf20Sopenharmony_ci			kfree(config->upperdir);
5288c2ecf20Sopenharmony_ci			config->upperdir = match_strdup(&args[0]);
5298c2ecf20Sopenharmony_ci			if (!config->upperdir)
5308c2ecf20Sopenharmony_ci				return -ENOMEM;
5318c2ecf20Sopenharmony_ci			break;
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_ci		case OPT_LOWERDIR:
5348c2ecf20Sopenharmony_ci			kfree(config->lowerdir);
5358c2ecf20Sopenharmony_ci			config->lowerdir = match_strdup(&args[0]);
5368c2ecf20Sopenharmony_ci			if (!config->lowerdir)
5378c2ecf20Sopenharmony_ci				return -ENOMEM;
5388c2ecf20Sopenharmony_ci			break;
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_ci		case OPT_WORKDIR:
5418c2ecf20Sopenharmony_ci			kfree(config->workdir);
5428c2ecf20Sopenharmony_ci			config->workdir = match_strdup(&args[0]);
5438c2ecf20Sopenharmony_ci			if (!config->workdir)
5448c2ecf20Sopenharmony_ci				return -ENOMEM;
5458c2ecf20Sopenharmony_ci			break;
5468c2ecf20Sopenharmony_ci
5478c2ecf20Sopenharmony_ci		case OPT_DEFAULT_PERMISSIONS:
5488c2ecf20Sopenharmony_ci			config->default_permissions = true;
5498c2ecf20Sopenharmony_ci			break;
5508c2ecf20Sopenharmony_ci
5518c2ecf20Sopenharmony_ci		case OPT_REDIRECT_DIR:
5528c2ecf20Sopenharmony_ci			kfree(config->redirect_mode);
5538c2ecf20Sopenharmony_ci			config->redirect_mode = match_strdup(&args[0]);
5548c2ecf20Sopenharmony_ci			if (!config->redirect_mode)
5558c2ecf20Sopenharmony_ci				return -ENOMEM;
5568c2ecf20Sopenharmony_ci			redirect_opt = true;
5578c2ecf20Sopenharmony_ci			break;
5588c2ecf20Sopenharmony_ci
5598c2ecf20Sopenharmony_ci		case OPT_INDEX_ON:
5608c2ecf20Sopenharmony_ci			config->index = true;
5618c2ecf20Sopenharmony_ci			index_opt = true;
5628c2ecf20Sopenharmony_ci			break;
5638c2ecf20Sopenharmony_ci
5648c2ecf20Sopenharmony_ci		case OPT_INDEX_OFF:
5658c2ecf20Sopenharmony_ci			config->index = false;
5668c2ecf20Sopenharmony_ci			index_opt = true;
5678c2ecf20Sopenharmony_ci			break;
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_ci		case OPT_NFS_EXPORT_ON:
5708c2ecf20Sopenharmony_ci			config->nfs_export = true;
5718c2ecf20Sopenharmony_ci			nfs_export_opt = true;
5728c2ecf20Sopenharmony_ci			break;
5738c2ecf20Sopenharmony_ci
5748c2ecf20Sopenharmony_ci		case OPT_NFS_EXPORT_OFF:
5758c2ecf20Sopenharmony_ci			config->nfs_export = false;
5768c2ecf20Sopenharmony_ci			nfs_export_opt = true;
5778c2ecf20Sopenharmony_ci			break;
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_ci		case OPT_XINO_ON:
5808c2ecf20Sopenharmony_ci			config->xino = OVL_XINO_ON;
5818c2ecf20Sopenharmony_ci			break;
5828c2ecf20Sopenharmony_ci
5838c2ecf20Sopenharmony_ci		case OPT_XINO_OFF:
5848c2ecf20Sopenharmony_ci			config->xino = OVL_XINO_OFF;
5858c2ecf20Sopenharmony_ci			break;
5868c2ecf20Sopenharmony_ci
5878c2ecf20Sopenharmony_ci		case OPT_XINO_AUTO:
5888c2ecf20Sopenharmony_ci			config->xino = OVL_XINO_AUTO;
5898c2ecf20Sopenharmony_ci			break;
5908c2ecf20Sopenharmony_ci
5918c2ecf20Sopenharmony_ci		case OPT_METACOPY_ON:
5928c2ecf20Sopenharmony_ci			config->metacopy = true;
5938c2ecf20Sopenharmony_ci			metacopy_opt = true;
5948c2ecf20Sopenharmony_ci			break;
5958c2ecf20Sopenharmony_ci
5968c2ecf20Sopenharmony_ci		case OPT_METACOPY_OFF:
5978c2ecf20Sopenharmony_ci			config->metacopy = false;
5988c2ecf20Sopenharmony_ci			metacopy_opt = true;
5998c2ecf20Sopenharmony_ci			break;
6008c2ecf20Sopenharmony_ci
6018c2ecf20Sopenharmony_ci		case OPT_VOLATILE:
6028c2ecf20Sopenharmony_ci			config->ovl_volatile = true;
6038c2ecf20Sopenharmony_ci			break;
6048c2ecf20Sopenharmony_ci
6058c2ecf20Sopenharmony_ci		default:
6068c2ecf20Sopenharmony_ci			pr_err("unrecognized mount option \"%s\" or missing value\n",
6078c2ecf20Sopenharmony_ci					p);
6088c2ecf20Sopenharmony_ci			return -EINVAL;
6098c2ecf20Sopenharmony_ci		}
6108c2ecf20Sopenharmony_ci	}
6118c2ecf20Sopenharmony_ci
6128c2ecf20Sopenharmony_ci	/* Workdir/index are useless in non-upper mount */
6138c2ecf20Sopenharmony_ci	if (!config->upperdir) {
6148c2ecf20Sopenharmony_ci		if (config->workdir) {
6158c2ecf20Sopenharmony_ci			pr_info("option \"workdir=%s\" is useless in a non-upper mount, ignore\n",
6168c2ecf20Sopenharmony_ci				config->workdir);
6178c2ecf20Sopenharmony_ci			kfree(config->workdir);
6188c2ecf20Sopenharmony_ci			config->workdir = NULL;
6198c2ecf20Sopenharmony_ci		}
6208c2ecf20Sopenharmony_ci		if (config->index && index_opt) {
6218c2ecf20Sopenharmony_ci			pr_info("option \"index=on\" is useless in a non-upper mount, ignore\n");
6228c2ecf20Sopenharmony_ci			index_opt = false;
6238c2ecf20Sopenharmony_ci		}
6248c2ecf20Sopenharmony_ci		config->index = false;
6258c2ecf20Sopenharmony_ci	}
6268c2ecf20Sopenharmony_ci
6278c2ecf20Sopenharmony_ci	if (!config->upperdir && config->ovl_volatile) {
6288c2ecf20Sopenharmony_ci		pr_info("option \"volatile\" is meaningless in a non-upper mount, ignoring it.\n");
6298c2ecf20Sopenharmony_ci		config->ovl_volatile = false;
6308c2ecf20Sopenharmony_ci	}
6318c2ecf20Sopenharmony_ci
6328c2ecf20Sopenharmony_ci	err = ovl_parse_redirect_mode(config, config->redirect_mode);
6338c2ecf20Sopenharmony_ci	if (err)
6348c2ecf20Sopenharmony_ci		return err;
6358c2ecf20Sopenharmony_ci
6368c2ecf20Sopenharmony_ci	/*
6378c2ecf20Sopenharmony_ci	 * This is to make the logic below simpler.  It doesn't make any other
6388c2ecf20Sopenharmony_ci	 * difference, since config->redirect_dir is only used for upper.
6398c2ecf20Sopenharmony_ci	 */
6408c2ecf20Sopenharmony_ci	if (!config->upperdir && config->redirect_follow)
6418c2ecf20Sopenharmony_ci		config->redirect_dir = true;
6428c2ecf20Sopenharmony_ci
6438c2ecf20Sopenharmony_ci	/* Resolve metacopy -> redirect_dir dependency */
6448c2ecf20Sopenharmony_ci	if (config->metacopy && !config->redirect_dir) {
6458c2ecf20Sopenharmony_ci		if (metacopy_opt && redirect_opt) {
6468c2ecf20Sopenharmony_ci			pr_err("conflicting options: metacopy=on,redirect_dir=%s\n",
6478c2ecf20Sopenharmony_ci			       config->redirect_mode);
6488c2ecf20Sopenharmony_ci			return -EINVAL;
6498c2ecf20Sopenharmony_ci		}
6508c2ecf20Sopenharmony_ci		if (redirect_opt) {
6518c2ecf20Sopenharmony_ci			/*
6528c2ecf20Sopenharmony_ci			 * There was an explicit redirect_dir=... that resulted
6538c2ecf20Sopenharmony_ci			 * in this conflict.
6548c2ecf20Sopenharmony_ci			 */
6558c2ecf20Sopenharmony_ci			pr_info("disabling metacopy due to redirect_dir=%s\n",
6568c2ecf20Sopenharmony_ci				config->redirect_mode);
6578c2ecf20Sopenharmony_ci			config->metacopy = false;
6588c2ecf20Sopenharmony_ci		} else {
6598c2ecf20Sopenharmony_ci			/* Automatically enable redirect otherwise. */
6608c2ecf20Sopenharmony_ci			config->redirect_follow = config->redirect_dir = true;
6618c2ecf20Sopenharmony_ci		}
6628c2ecf20Sopenharmony_ci	}
6638c2ecf20Sopenharmony_ci
6648c2ecf20Sopenharmony_ci	/* Resolve nfs_export -> index dependency */
6658c2ecf20Sopenharmony_ci	if (config->nfs_export && !config->index) {
6668c2ecf20Sopenharmony_ci		if (!config->upperdir && config->redirect_follow) {
6678c2ecf20Sopenharmony_ci			pr_info("NFS export requires \"redirect_dir=nofollow\" on non-upper mount, falling back to nfs_export=off.\n");
6688c2ecf20Sopenharmony_ci			config->nfs_export = false;
6698c2ecf20Sopenharmony_ci		} else if (nfs_export_opt && index_opt) {
6708c2ecf20Sopenharmony_ci			pr_err("conflicting options: nfs_export=on,index=off\n");
6718c2ecf20Sopenharmony_ci			return -EINVAL;
6728c2ecf20Sopenharmony_ci		} else if (index_opt) {
6738c2ecf20Sopenharmony_ci			/*
6748c2ecf20Sopenharmony_ci			 * There was an explicit index=off that resulted
6758c2ecf20Sopenharmony_ci			 * in this conflict.
6768c2ecf20Sopenharmony_ci			 */
6778c2ecf20Sopenharmony_ci			pr_info("disabling nfs_export due to index=off\n");
6788c2ecf20Sopenharmony_ci			config->nfs_export = false;
6798c2ecf20Sopenharmony_ci		} else {
6808c2ecf20Sopenharmony_ci			/* Automatically enable index otherwise. */
6818c2ecf20Sopenharmony_ci			config->index = true;
6828c2ecf20Sopenharmony_ci		}
6838c2ecf20Sopenharmony_ci	}
6848c2ecf20Sopenharmony_ci
6858c2ecf20Sopenharmony_ci	/* Resolve nfs_export -> !metacopy dependency */
6868c2ecf20Sopenharmony_ci	if (config->nfs_export && config->metacopy) {
6878c2ecf20Sopenharmony_ci		if (nfs_export_opt && metacopy_opt) {
6888c2ecf20Sopenharmony_ci			pr_err("conflicting options: nfs_export=on,metacopy=on\n");
6898c2ecf20Sopenharmony_ci			return -EINVAL;
6908c2ecf20Sopenharmony_ci		}
6918c2ecf20Sopenharmony_ci		if (metacopy_opt) {
6928c2ecf20Sopenharmony_ci			/*
6938c2ecf20Sopenharmony_ci			 * There was an explicit metacopy=on that resulted
6948c2ecf20Sopenharmony_ci			 * in this conflict.
6958c2ecf20Sopenharmony_ci			 */
6968c2ecf20Sopenharmony_ci			pr_info("disabling nfs_export due to metacopy=on\n");
6978c2ecf20Sopenharmony_ci			config->nfs_export = false;
6988c2ecf20Sopenharmony_ci		} else {
6998c2ecf20Sopenharmony_ci			/*
7008c2ecf20Sopenharmony_ci			 * There was an explicit nfs_export=on that resulted
7018c2ecf20Sopenharmony_ci			 * in this conflict.
7028c2ecf20Sopenharmony_ci			 */
7038c2ecf20Sopenharmony_ci			pr_info("disabling metacopy due to nfs_export=on\n");
7048c2ecf20Sopenharmony_ci			config->metacopy = false;
7058c2ecf20Sopenharmony_ci		}
7068c2ecf20Sopenharmony_ci	}
7078c2ecf20Sopenharmony_ci
7088c2ecf20Sopenharmony_ci	return 0;
7098c2ecf20Sopenharmony_ci}
7108c2ecf20Sopenharmony_ci
7118c2ecf20Sopenharmony_ci#define OVL_WORKDIR_NAME "work"
7128c2ecf20Sopenharmony_ci#define OVL_INDEXDIR_NAME "index"
7138c2ecf20Sopenharmony_ci
7148c2ecf20Sopenharmony_cistatic struct dentry *ovl_workdir_create(struct ovl_fs *ofs,
7158c2ecf20Sopenharmony_ci					 const char *name, bool persist)
7168c2ecf20Sopenharmony_ci{
7178c2ecf20Sopenharmony_ci	struct inode *dir =  ofs->workbasedir->d_inode;
7188c2ecf20Sopenharmony_ci	struct vfsmount *mnt = ovl_upper_mnt(ofs);
7198c2ecf20Sopenharmony_ci	struct dentry *work;
7208c2ecf20Sopenharmony_ci	int err;
7218c2ecf20Sopenharmony_ci	bool retried = false;
7228c2ecf20Sopenharmony_ci
7238c2ecf20Sopenharmony_ci	inode_lock_nested(dir, I_MUTEX_PARENT);
7248c2ecf20Sopenharmony_ciretry:
7258c2ecf20Sopenharmony_ci	work = lookup_one_len(name, ofs->workbasedir, strlen(name));
7268c2ecf20Sopenharmony_ci
7278c2ecf20Sopenharmony_ci	if (!IS_ERR(work)) {
7288c2ecf20Sopenharmony_ci		struct iattr attr = {
7298c2ecf20Sopenharmony_ci			.ia_valid = ATTR_MODE,
7308c2ecf20Sopenharmony_ci			.ia_mode = S_IFDIR | 0,
7318c2ecf20Sopenharmony_ci		};
7328c2ecf20Sopenharmony_ci
7338c2ecf20Sopenharmony_ci		if (work->d_inode) {
7348c2ecf20Sopenharmony_ci			err = -EEXIST;
7358c2ecf20Sopenharmony_ci			if (retried)
7368c2ecf20Sopenharmony_ci				goto out_dput;
7378c2ecf20Sopenharmony_ci
7388c2ecf20Sopenharmony_ci			if (persist)
7398c2ecf20Sopenharmony_ci				goto out_unlock;
7408c2ecf20Sopenharmony_ci
7418c2ecf20Sopenharmony_ci			retried = true;
7428c2ecf20Sopenharmony_ci			err = ovl_workdir_cleanup(dir, mnt, work, 0);
7438c2ecf20Sopenharmony_ci			dput(work);
7448c2ecf20Sopenharmony_ci			if (err == -EINVAL) {
7458c2ecf20Sopenharmony_ci				work = ERR_PTR(err);
7468c2ecf20Sopenharmony_ci				goto out_unlock;
7478c2ecf20Sopenharmony_ci			}
7488c2ecf20Sopenharmony_ci			goto retry;
7498c2ecf20Sopenharmony_ci		}
7508c2ecf20Sopenharmony_ci
7518c2ecf20Sopenharmony_ci		err = ovl_mkdir_real(dir, &work, attr.ia_mode);
7528c2ecf20Sopenharmony_ci		if (err)
7538c2ecf20Sopenharmony_ci			goto out_dput;
7548c2ecf20Sopenharmony_ci
7558c2ecf20Sopenharmony_ci		/* Weird filesystem returning with hashed negative (kernfs)? */
7568c2ecf20Sopenharmony_ci		err = -EINVAL;
7578c2ecf20Sopenharmony_ci		if (d_really_is_negative(work))
7588c2ecf20Sopenharmony_ci			goto out_dput;
7598c2ecf20Sopenharmony_ci
7608c2ecf20Sopenharmony_ci		/*
7618c2ecf20Sopenharmony_ci		 * Try to remove POSIX ACL xattrs from workdir.  We are good if:
7628c2ecf20Sopenharmony_ci		 *
7638c2ecf20Sopenharmony_ci		 * a) success (there was a POSIX ACL xattr and was removed)
7648c2ecf20Sopenharmony_ci		 * b) -ENODATA (there was no POSIX ACL xattr)
7658c2ecf20Sopenharmony_ci		 * c) -EOPNOTSUPP (POSIX ACL xattrs are not supported)
7668c2ecf20Sopenharmony_ci		 *
7678c2ecf20Sopenharmony_ci		 * There are various other error values that could effectively
7688c2ecf20Sopenharmony_ci		 * mean that the xattr doesn't exist (e.g. -ERANGE is returned
7698c2ecf20Sopenharmony_ci		 * if the xattr name is too long), but the set of filesystems
7708c2ecf20Sopenharmony_ci		 * allowed as upper are limited to "normal" ones, where checking
7718c2ecf20Sopenharmony_ci		 * for the above two errors is sufficient.
7728c2ecf20Sopenharmony_ci		 */
7738c2ecf20Sopenharmony_ci		err = vfs_removexattr(work, XATTR_NAME_POSIX_ACL_DEFAULT);
7748c2ecf20Sopenharmony_ci		if (err && err != -ENODATA && err != -EOPNOTSUPP)
7758c2ecf20Sopenharmony_ci			goto out_dput;
7768c2ecf20Sopenharmony_ci
7778c2ecf20Sopenharmony_ci		err = vfs_removexattr(work, XATTR_NAME_POSIX_ACL_ACCESS);
7788c2ecf20Sopenharmony_ci		if (err && err != -ENODATA && err != -EOPNOTSUPP)
7798c2ecf20Sopenharmony_ci			goto out_dput;
7808c2ecf20Sopenharmony_ci
7818c2ecf20Sopenharmony_ci		/* Clear any inherited mode bits */
7828c2ecf20Sopenharmony_ci		inode_lock(work->d_inode);
7838c2ecf20Sopenharmony_ci		err = notify_change(work, &attr, NULL);
7848c2ecf20Sopenharmony_ci		inode_unlock(work->d_inode);
7858c2ecf20Sopenharmony_ci		if (err)
7868c2ecf20Sopenharmony_ci			goto out_dput;
7878c2ecf20Sopenharmony_ci	} else {
7888c2ecf20Sopenharmony_ci		err = PTR_ERR(work);
7898c2ecf20Sopenharmony_ci		goto out_err;
7908c2ecf20Sopenharmony_ci	}
7918c2ecf20Sopenharmony_ciout_unlock:
7928c2ecf20Sopenharmony_ci	inode_unlock(dir);
7938c2ecf20Sopenharmony_ci	return work;
7948c2ecf20Sopenharmony_ci
7958c2ecf20Sopenharmony_ciout_dput:
7968c2ecf20Sopenharmony_ci	dput(work);
7978c2ecf20Sopenharmony_ciout_err:
7988c2ecf20Sopenharmony_ci	pr_warn("failed to create directory %s/%s (errno: %i); mounting read-only\n",
7998c2ecf20Sopenharmony_ci		ofs->config.workdir, name, -err);
8008c2ecf20Sopenharmony_ci	work = NULL;
8018c2ecf20Sopenharmony_ci	goto out_unlock;
8028c2ecf20Sopenharmony_ci}
8038c2ecf20Sopenharmony_ci
8048c2ecf20Sopenharmony_cistatic void ovl_unescape(char *s)
8058c2ecf20Sopenharmony_ci{
8068c2ecf20Sopenharmony_ci	char *d = s;
8078c2ecf20Sopenharmony_ci
8088c2ecf20Sopenharmony_ci	for (;; s++, d++) {
8098c2ecf20Sopenharmony_ci		if (*s == '\\')
8108c2ecf20Sopenharmony_ci			s++;
8118c2ecf20Sopenharmony_ci		*d = *s;
8128c2ecf20Sopenharmony_ci		if (!*s)
8138c2ecf20Sopenharmony_ci			break;
8148c2ecf20Sopenharmony_ci	}
8158c2ecf20Sopenharmony_ci}
8168c2ecf20Sopenharmony_ci
8178c2ecf20Sopenharmony_cistatic int ovl_mount_dir_noesc(const char *name, struct path *path)
8188c2ecf20Sopenharmony_ci{
8198c2ecf20Sopenharmony_ci	int err = -EINVAL;
8208c2ecf20Sopenharmony_ci
8218c2ecf20Sopenharmony_ci	if (!*name) {
8228c2ecf20Sopenharmony_ci		pr_err("empty lowerdir\n");
8238c2ecf20Sopenharmony_ci		goto out;
8248c2ecf20Sopenharmony_ci	}
8258c2ecf20Sopenharmony_ci	err = kern_path(name, LOOKUP_FOLLOW, path);
8268c2ecf20Sopenharmony_ci	if (err) {
8278c2ecf20Sopenharmony_ci		pr_err("failed to resolve '%s': %i\n", name, err);
8288c2ecf20Sopenharmony_ci		goto out;
8298c2ecf20Sopenharmony_ci	}
8308c2ecf20Sopenharmony_ci	err = -EINVAL;
8318c2ecf20Sopenharmony_ci	if (ovl_dentry_weird(path->dentry)) {
8328c2ecf20Sopenharmony_ci		pr_err("filesystem on '%s' not supported\n", name);
8338c2ecf20Sopenharmony_ci		goto out_put;
8348c2ecf20Sopenharmony_ci	}
8358c2ecf20Sopenharmony_ci	if (!d_is_dir(path->dentry)) {
8368c2ecf20Sopenharmony_ci		pr_err("'%s' not a directory\n", name);
8378c2ecf20Sopenharmony_ci		goto out_put;
8388c2ecf20Sopenharmony_ci	}
8398c2ecf20Sopenharmony_ci	return 0;
8408c2ecf20Sopenharmony_ci
8418c2ecf20Sopenharmony_ciout_put:
8428c2ecf20Sopenharmony_ci	path_put_init(path);
8438c2ecf20Sopenharmony_ciout:
8448c2ecf20Sopenharmony_ci	return err;
8458c2ecf20Sopenharmony_ci}
8468c2ecf20Sopenharmony_ci
8478c2ecf20Sopenharmony_cistatic int ovl_mount_dir(const char *name, struct path *path)
8488c2ecf20Sopenharmony_ci{
8498c2ecf20Sopenharmony_ci	int err = -ENOMEM;
8508c2ecf20Sopenharmony_ci	char *tmp = kstrdup(name, GFP_KERNEL);
8518c2ecf20Sopenharmony_ci
8528c2ecf20Sopenharmony_ci	if (tmp) {
8538c2ecf20Sopenharmony_ci		ovl_unescape(tmp);
8548c2ecf20Sopenharmony_ci		err = ovl_mount_dir_noesc(tmp, path);
8558c2ecf20Sopenharmony_ci
8568c2ecf20Sopenharmony_ci		if (!err && path->dentry->d_flags & DCACHE_OP_REAL) {
8578c2ecf20Sopenharmony_ci			pr_err("filesystem on '%s' not supported as upperdir\n",
8588c2ecf20Sopenharmony_ci			       tmp);
8598c2ecf20Sopenharmony_ci			path_put_init(path);
8608c2ecf20Sopenharmony_ci			err = -EINVAL;
8618c2ecf20Sopenharmony_ci		}
8628c2ecf20Sopenharmony_ci		kfree(tmp);
8638c2ecf20Sopenharmony_ci	}
8648c2ecf20Sopenharmony_ci	return err;
8658c2ecf20Sopenharmony_ci}
8668c2ecf20Sopenharmony_ci
8678c2ecf20Sopenharmony_cistatic int ovl_check_namelen(struct path *path, struct ovl_fs *ofs,
8688c2ecf20Sopenharmony_ci			     const char *name)
8698c2ecf20Sopenharmony_ci{
8708c2ecf20Sopenharmony_ci	struct kstatfs statfs;
8718c2ecf20Sopenharmony_ci	int err = vfs_statfs(path, &statfs);
8728c2ecf20Sopenharmony_ci
8738c2ecf20Sopenharmony_ci	if (err)
8748c2ecf20Sopenharmony_ci		pr_err("statfs failed on '%s'\n", name);
8758c2ecf20Sopenharmony_ci	else
8768c2ecf20Sopenharmony_ci		ofs->namelen = max(ofs->namelen, statfs.f_namelen);
8778c2ecf20Sopenharmony_ci
8788c2ecf20Sopenharmony_ci	return err;
8798c2ecf20Sopenharmony_ci}
8808c2ecf20Sopenharmony_ci
8818c2ecf20Sopenharmony_cistatic int ovl_lower_dir(const char *name, struct path *path,
8828c2ecf20Sopenharmony_ci			 struct ovl_fs *ofs, int *stack_depth)
8838c2ecf20Sopenharmony_ci{
8848c2ecf20Sopenharmony_ci	int fh_type;
8858c2ecf20Sopenharmony_ci	int err;
8868c2ecf20Sopenharmony_ci
8878c2ecf20Sopenharmony_ci	err = ovl_mount_dir_noesc(name, path);
8888c2ecf20Sopenharmony_ci	if (err)
8898c2ecf20Sopenharmony_ci		return err;
8908c2ecf20Sopenharmony_ci
8918c2ecf20Sopenharmony_ci	err = ovl_check_namelen(path, ofs, name);
8928c2ecf20Sopenharmony_ci	if (err)
8938c2ecf20Sopenharmony_ci		return err;
8948c2ecf20Sopenharmony_ci
8958c2ecf20Sopenharmony_ci	*stack_depth = max(*stack_depth, path->mnt->mnt_sb->s_stack_depth);
8968c2ecf20Sopenharmony_ci
8978c2ecf20Sopenharmony_ci	/*
8988c2ecf20Sopenharmony_ci	 * The inodes index feature and NFS export need to encode and decode
8998c2ecf20Sopenharmony_ci	 * file handles, so they require that all layers support them.
9008c2ecf20Sopenharmony_ci	 */
9018c2ecf20Sopenharmony_ci	fh_type = ovl_can_decode_fh(path->dentry->d_sb);
9028c2ecf20Sopenharmony_ci	if ((ofs->config.nfs_export ||
9038c2ecf20Sopenharmony_ci	     (ofs->config.index && ofs->config.upperdir)) && !fh_type) {
9048c2ecf20Sopenharmony_ci		ofs->config.index = false;
9058c2ecf20Sopenharmony_ci		ofs->config.nfs_export = false;
9068c2ecf20Sopenharmony_ci		pr_warn("fs on '%s' does not support file handles, falling back to index=off,nfs_export=off.\n",
9078c2ecf20Sopenharmony_ci			name);
9088c2ecf20Sopenharmony_ci	}
9098c2ecf20Sopenharmony_ci
9108c2ecf20Sopenharmony_ci	/* Check if lower fs has 32bit inode numbers */
9118c2ecf20Sopenharmony_ci	if (fh_type != FILEID_INO32_GEN)
9128c2ecf20Sopenharmony_ci		ofs->xino_mode = -1;
9138c2ecf20Sopenharmony_ci
9148c2ecf20Sopenharmony_ci	return 0;
9158c2ecf20Sopenharmony_ci}
9168c2ecf20Sopenharmony_ci
9178c2ecf20Sopenharmony_ci/* Workdir should not be subdir of upperdir and vice versa */
9188c2ecf20Sopenharmony_cistatic bool ovl_workdir_ok(struct dentry *workdir, struct dentry *upperdir)
9198c2ecf20Sopenharmony_ci{
9208c2ecf20Sopenharmony_ci	bool ok = false;
9218c2ecf20Sopenharmony_ci
9228c2ecf20Sopenharmony_ci	if (workdir != upperdir) {
9238c2ecf20Sopenharmony_ci		ok = (lock_rename(workdir, upperdir) == NULL);
9248c2ecf20Sopenharmony_ci		unlock_rename(workdir, upperdir);
9258c2ecf20Sopenharmony_ci	}
9268c2ecf20Sopenharmony_ci	return ok;
9278c2ecf20Sopenharmony_ci}
9288c2ecf20Sopenharmony_ci
9298c2ecf20Sopenharmony_cistatic unsigned int ovl_split_lowerdirs(char *str)
9308c2ecf20Sopenharmony_ci{
9318c2ecf20Sopenharmony_ci	unsigned int ctr = 1;
9328c2ecf20Sopenharmony_ci	char *s, *d;
9338c2ecf20Sopenharmony_ci
9348c2ecf20Sopenharmony_ci	for (s = d = str;; s++, d++) {
9358c2ecf20Sopenharmony_ci		if (*s == '\\') {
9368c2ecf20Sopenharmony_ci			s++;
9378c2ecf20Sopenharmony_ci		} else if (*s == ':') {
9388c2ecf20Sopenharmony_ci			*d = '\0';
9398c2ecf20Sopenharmony_ci			ctr++;
9408c2ecf20Sopenharmony_ci			continue;
9418c2ecf20Sopenharmony_ci		}
9428c2ecf20Sopenharmony_ci		*d = *s;
9438c2ecf20Sopenharmony_ci		if (!*s)
9448c2ecf20Sopenharmony_ci			break;
9458c2ecf20Sopenharmony_ci	}
9468c2ecf20Sopenharmony_ci	return ctr;
9478c2ecf20Sopenharmony_ci}
9488c2ecf20Sopenharmony_ci
9498c2ecf20Sopenharmony_cistatic int __maybe_unused
9508c2ecf20Sopenharmony_ciovl_posix_acl_xattr_get(const struct xattr_handler *handler,
9518c2ecf20Sopenharmony_ci			struct dentry *dentry, struct inode *inode,
9528c2ecf20Sopenharmony_ci			const char *name, void *buffer, size_t size)
9538c2ecf20Sopenharmony_ci{
9548c2ecf20Sopenharmony_ci	return ovl_xattr_get(dentry, inode, handler->name, buffer, size);
9558c2ecf20Sopenharmony_ci}
9568c2ecf20Sopenharmony_ci
9578c2ecf20Sopenharmony_cistatic int __maybe_unused
9588c2ecf20Sopenharmony_ciovl_posix_acl_xattr_set(const struct xattr_handler *handler,
9598c2ecf20Sopenharmony_ci			struct dentry *dentry, struct inode *inode,
9608c2ecf20Sopenharmony_ci			const char *name, const void *value,
9618c2ecf20Sopenharmony_ci			size_t size, int flags)
9628c2ecf20Sopenharmony_ci{
9638c2ecf20Sopenharmony_ci	struct dentry *workdir = ovl_workdir(dentry);
9648c2ecf20Sopenharmony_ci	struct inode *realinode = ovl_inode_real(inode);
9658c2ecf20Sopenharmony_ci	struct posix_acl *acl = NULL;
9668c2ecf20Sopenharmony_ci	int err;
9678c2ecf20Sopenharmony_ci
9688c2ecf20Sopenharmony_ci	/* Check that everything is OK before copy-up */
9698c2ecf20Sopenharmony_ci	if (value) {
9708c2ecf20Sopenharmony_ci		acl = posix_acl_from_xattr(&init_user_ns, value, size);
9718c2ecf20Sopenharmony_ci		if (IS_ERR(acl))
9728c2ecf20Sopenharmony_ci			return PTR_ERR(acl);
9738c2ecf20Sopenharmony_ci	}
9748c2ecf20Sopenharmony_ci	err = -EOPNOTSUPP;
9758c2ecf20Sopenharmony_ci	if (!IS_POSIXACL(d_inode(workdir)))
9768c2ecf20Sopenharmony_ci		goto out_acl_release;
9778c2ecf20Sopenharmony_ci	if (!realinode->i_op->set_acl)
9788c2ecf20Sopenharmony_ci		goto out_acl_release;
9798c2ecf20Sopenharmony_ci	if (handler->flags == ACL_TYPE_DEFAULT && !S_ISDIR(inode->i_mode)) {
9808c2ecf20Sopenharmony_ci		err = acl ? -EACCES : 0;
9818c2ecf20Sopenharmony_ci		goto out_acl_release;
9828c2ecf20Sopenharmony_ci	}
9838c2ecf20Sopenharmony_ci	err = -EPERM;
9848c2ecf20Sopenharmony_ci	if (!inode_owner_or_capable(inode))
9858c2ecf20Sopenharmony_ci		goto out_acl_release;
9868c2ecf20Sopenharmony_ci
9878c2ecf20Sopenharmony_ci	posix_acl_release(acl);
9888c2ecf20Sopenharmony_ci
9898c2ecf20Sopenharmony_ci	/*
9908c2ecf20Sopenharmony_ci	 * Check if sgid bit needs to be cleared (actual setacl operation will
9918c2ecf20Sopenharmony_ci	 * be done with mounter's capabilities and so that won't do it for us).
9928c2ecf20Sopenharmony_ci	 */
9938c2ecf20Sopenharmony_ci	if (unlikely(inode->i_mode & S_ISGID) &&
9948c2ecf20Sopenharmony_ci	    handler->flags == ACL_TYPE_ACCESS &&
9958c2ecf20Sopenharmony_ci	    !in_group_p(inode->i_gid) &&
9968c2ecf20Sopenharmony_ci	    !capable_wrt_inode_uidgid(inode, CAP_FSETID)) {
9978c2ecf20Sopenharmony_ci		struct iattr iattr = { .ia_valid = ATTR_KILL_SGID };
9988c2ecf20Sopenharmony_ci
9998c2ecf20Sopenharmony_ci		err = ovl_setattr(dentry, &iattr);
10008c2ecf20Sopenharmony_ci		if (err)
10018c2ecf20Sopenharmony_ci			return err;
10028c2ecf20Sopenharmony_ci	}
10038c2ecf20Sopenharmony_ci
10048c2ecf20Sopenharmony_ci	err = ovl_xattr_set(dentry, inode, handler->name, value, size, flags);
10058c2ecf20Sopenharmony_ci	if (!err)
10068c2ecf20Sopenharmony_ci		ovl_copyattr(ovl_inode_real(inode), inode);
10078c2ecf20Sopenharmony_ci
10088c2ecf20Sopenharmony_ci	return err;
10098c2ecf20Sopenharmony_ci
10108c2ecf20Sopenharmony_ciout_acl_release:
10118c2ecf20Sopenharmony_ci	posix_acl_release(acl);
10128c2ecf20Sopenharmony_ci	return err;
10138c2ecf20Sopenharmony_ci}
10148c2ecf20Sopenharmony_ci
10158c2ecf20Sopenharmony_cistatic int ovl_own_xattr_get(const struct xattr_handler *handler,
10168c2ecf20Sopenharmony_ci			     struct dentry *dentry, struct inode *inode,
10178c2ecf20Sopenharmony_ci			     const char *name, void *buffer, size_t size)
10188c2ecf20Sopenharmony_ci{
10198c2ecf20Sopenharmony_ci	return -EOPNOTSUPP;
10208c2ecf20Sopenharmony_ci}
10218c2ecf20Sopenharmony_ci
10228c2ecf20Sopenharmony_cistatic int ovl_own_xattr_set(const struct xattr_handler *handler,
10238c2ecf20Sopenharmony_ci			     struct dentry *dentry, struct inode *inode,
10248c2ecf20Sopenharmony_ci			     const char *name, const void *value,
10258c2ecf20Sopenharmony_ci			     size_t size, int flags)
10268c2ecf20Sopenharmony_ci{
10278c2ecf20Sopenharmony_ci	return -EOPNOTSUPP;
10288c2ecf20Sopenharmony_ci}
10298c2ecf20Sopenharmony_ci
10308c2ecf20Sopenharmony_cistatic int ovl_other_xattr_get(const struct xattr_handler *handler,
10318c2ecf20Sopenharmony_ci			       struct dentry *dentry, struct inode *inode,
10328c2ecf20Sopenharmony_ci			       const char *name, void *buffer, size_t size)
10338c2ecf20Sopenharmony_ci{
10348c2ecf20Sopenharmony_ci	return ovl_xattr_get(dentry, inode, name, buffer, size);
10358c2ecf20Sopenharmony_ci}
10368c2ecf20Sopenharmony_ci
10378c2ecf20Sopenharmony_cistatic int ovl_other_xattr_set(const struct xattr_handler *handler,
10388c2ecf20Sopenharmony_ci			       struct dentry *dentry, struct inode *inode,
10398c2ecf20Sopenharmony_ci			       const char *name, const void *value,
10408c2ecf20Sopenharmony_ci			       size_t size, int flags)
10418c2ecf20Sopenharmony_ci{
10428c2ecf20Sopenharmony_ci	return ovl_xattr_set(dentry, inode, name, value, size, flags);
10438c2ecf20Sopenharmony_ci}
10448c2ecf20Sopenharmony_ci
10458c2ecf20Sopenharmony_cistatic const struct xattr_handler __maybe_unused
10468c2ecf20Sopenharmony_ciovl_posix_acl_access_xattr_handler = {
10478c2ecf20Sopenharmony_ci	.name = XATTR_NAME_POSIX_ACL_ACCESS,
10488c2ecf20Sopenharmony_ci	.flags = ACL_TYPE_ACCESS,
10498c2ecf20Sopenharmony_ci	.get = ovl_posix_acl_xattr_get,
10508c2ecf20Sopenharmony_ci	.set = ovl_posix_acl_xattr_set,
10518c2ecf20Sopenharmony_ci};
10528c2ecf20Sopenharmony_ci
10538c2ecf20Sopenharmony_cistatic const struct xattr_handler __maybe_unused
10548c2ecf20Sopenharmony_ciovl_posix_acl_default_xattr_handler = {
10558c2ecf20Sopenharmony_ci	.name = XATTR_NAME_POSIX_ACL_DEFAULT,
10568c2ecf20Sopenharmony_ci	.flags = ACL_TYPE_DEFAULT,
10578c2ecf20Sopenharmony_ci	.get = ovl_posix_acl_xattr_get,
10588c2ecf20Sopenharmony_ci	.set = ovl_posix_acl_xattr_set,
10598c2ecf20Sopenharmony_ci};
10608c2ecf20Sopenharmony_ci
10618c2ecf20Sopenharmony_cistatic const struct xattr_handler ovl_own_xattr_handler = {
10628c2ecf20Sopenharmony_ci	.prefix	= OVL_XATTR_PREFIX,
10638c2ecf20Sopenharmony_ci	.get = ovl_own_xattr_get,
10648c2ecf20Sopenharmony_ci	.set = ovl_own_xattr_set,
10658c2ecf20Sopenharmony_ci};
10668c2ecf20Sopenharmony_ci
10678c2ecf20Sopenharmony_cistatic const struct xattr_handler ovl_other_xattr_handler = {
10688c2ecf20Sopenharmony_ci	.prefix	= "", /* catch all */
10698c2ecf20Sopenharmony_ci	.get = ovl_other_xattr_get,
10708c2ecf20Sopenharmony_ci	.set = ovl_other_xattr_set,
10718c2ecf20Sopenharmony_ci};
10728c2ecf20Sopenharmony_ci
10738c2ecf20Sopenharmony_cistatic const struct xattr_handler *ovl_xattr_handlers[] = {
10748c2ecf20Sopenharmony_ci#ifdef CONFIG_FS_POSIX_ACL
10758c2ecf20Sopenharmony_ci	&ovl_posix_acl_access_xattr_handler,
10768c2ecf20Sopenharmony_ci	&ovl_posix_acl_default_xattr_handler,
10778c2ecf20Sopenharmony_ci#endif
10788c2ecf20Sopenharmony_ci	&ovl_own_xattr_handler,
10798c2ecf20Sopenharmony_ci	&ovl_other_xattr_handler,
10808c2ecf20Sopenharmony_ci	NULL
10818c2ecf20Sopenharmony_ci};
10828c2ecf20Sopenharmony_ci
10838c2ecf20Sopenharmony_cistatic int ovl_setup_trap(struct super_block *sb, struct dentry *dir,
10848c2ecf20Sopenharmony_ci			  struct inode **ptrap, const char *name)
10858c2ecf20Sopenharmony_ci{
10868c2ecf20Sopenharmony_ci	struct inode *trap;
10878c2ecf20Sopenharmony_ci	int err;
10888c2ecf20Sopenharmony_ci
10898c2ecf20Sopenharmony_ci	trap = ovl_get_trap_inode(sb, dir);
10908c2ecf20Sopenharmony_ci	err = PTR_ERR_OR_ZERO(trap);
10918c2ecf20Sopenharmony_ci	if (err) {
10928c2ecf20Sopenharmony_ci		if (err == -ELOOP)
10938c2ecf20Sopenharmony_ci			pr_err("conflicting %s path\n", name);
10948c2ecf20Sopenharmony_ci		return err;
10958c2ecf20Sopenharmony_ci	}
10968c2ecf20Sopenharmony_ci
10978c2ecf20Sopenharmony_ci	*ptrap = trap;
10988c2ecf20Sopenharmony_ci	return 0;
10998c2ecf20Sopenharmony_ci}
11008c2ecf20Sopenharmony_ci
11018c2ecf20Sopenharmony_ci/*
11028c2ecf20Sopenharmony_ci * Determine how we treat concurrent use of upperdir/workdir based on the
11038c2ecf20Sopenharmony_ci * index feature. This is papering over mount leaks of container runtimes,
11048c2ecf20Sopenharmony_ci * for example, an old overlay mount is leaked and now its upperdir is
11058c2ecf20Sopenharmony_ci * attempted to be used as a lower layer in a new overlay mount.
11068c2ecf20Sopenharmony_ci */
11078c2ecf20Sopenharmony_cistatic int ovl_report_in_use(struct ovl_fs *ofs, const char *name)
11088c2ecf20Sopenharmony_ci{
11098c2ecf20Sopenharmony_ci	if (ofs->config.index) {
11108c2ecf20Sopenharmony_ci		pr_err("%s is in-use as upperdir/workdir of another mount, mount with '-o index=off' to override exclusive upperdir protection.\n",
11118c2ecf20Sopenharmony_ci		       name);
11128c2ecf20Sopenharmony_ci		return -EBUSY;
11138c2ecf20Sopenharmony_ci	} else {
11148c2ecf20Sopenharmony_ci		pr_warn("%s is in-use as upperdir/workdir of another mount, accessing files from both mounts will result in undefined behavior.\n",
11158c2ecf20Sopenharmony_ci			name);
11168c2ecf20Sopenharmony_ci		return 0;
11178c2ecf20Sopenharmony_ci	}
11188c2ecf20Sopenharmony_ci}
11198c2ecf20Sopenharmony_ci
11208c2ecf20Sopenharmony_cistatic int ovl_get_upper(struct super_block *sb, struct ovl_fs *ofs,
11218c2ecf20Sopenharmony_ci			 struct ovl_layer *upper_layer, struct path *upperpath)
11228c2ecf20Sopenharmony_ci{
11238c2ecf20Sopenharmony_ci	struct vfsmount *upper_mnt;
11248c2ecf20Sopenharmony_ci	int err;
11258c2ecf20Sopenharmony_ci
11268c2ecf20Sopenharmony_ci	err = ovl_mount_dir(ofs->config.upperdir, upperpath);
11278c2ecf20Sopenharmony_ci	if (err)
11288c2ecf20Sopenharmony_ci		goto out;
11298c2ecf20Sopenharmony_ci
11308c2ecf20Sopenharmony_ci	/* Upper fs should not be r/o */
11318c2ecf20Sopenharmony_ci	if (sb_rdonly(upperpath->mnt->mnt_sb)) {
11328c2ecf20Sopenharmony_ci		pr_err("upper fs is r/o, try multi-lower layers mount\n");
11338c2ecf20Sopenharmony_ci		err = -EINVAL;
11348c2ecf20Sopenharmony_ci		goto out;
11358c2ecf20Sopenharmony_ci	}
11368c2ecf20Sopenharmony_ci
11378c2ecf20Sopenharmony_ci	err = ovl_check_namelen(upperpath, ofs, ofs->config.upperdir);
11388c2ecf20Sopenharmony_ci	if (err)
11398c2ecf20Sopenharmony_ci		goto out;
11408c2ecf20Sopenharmony_ci
11418c2ecf20Sopenharmony_ci	err = ovl_setup_trap(sb, upperpath->dentry, &upper_layer->trap,
11428c2ecf20Sopenharmony_ci			     "upperdir");
11438c2ecf20Sopenharmony_ci	if (err)
11448c2ecf20Sopenharmony_ci		goto out;
11458c2ecf20Sopenharmony_ci
11468c2ecf20Sopenharmony_ci	upper_mnt = clone_private_mount(upperpath);
11478c2ecf20Sopenharmony_ci	err = PTR_ERR(upper_mnt);
11488c2ecf20Sopenharmony_ci	if (IS_ERR(upper_mnt)) {
11498c2ecf20Sopenharmony_ci		pr_err("failed to clone upperpath\n");
11508c2ecf20Sopenharmony_ci		goto out;
11518c2ecf20Sopenharmony_ci	}
11528c2ecf20Sopenharmony_ci
11538c2ecf20Sopenharmony_ci	/* Don't inherit atime flags */
11548c2ecf20Sopenharmony_ci	upper_mnt->mnt_flags &= ~(MNT_NOATIME | MNT_NODIRATIME | MNT_RELATIME);
11558c2ecf20Sopenharmony_ci	upper_layer->mnt = upper_mnt;
11568c2ecf20Sopenharmony_ci	upper_layer->idx = 0;
11578c2ecf20Sopenharmony_ci	upper_layer->fsid = 0;
11588c2ecf20Sopenharmony_ci
11598c2ecf20Sopenharmony_ci	/*
11608c2ecf20Sopenharmony_ci	 * Inherit SB_NOSEC flag from upperdir.
11618c2ecf20Sopenharmony_ci	 *
11628c2ecf20Sopenharmony_ci	 * This optimization changes behavior when a security related attribute
11638c2ecf20Sopenharmony_ci	 * (suid/sgid/security.*) is changed on an underlying layer.  This is
11648c2ecf20Sopenharmony_ci	 * okay because we don't yet have guarantees in that case, but it will
11658c2ecf20Sopenharmony_ci	 * need careful treatment once we want to honour changes to underlying
11668c2ecf20Sopenharmony_ci	 * filesystems.
11678c2ecf20Sopenharmony_ci	 */
11688c2ecf20Sopenharmony_ci	if (upper_mnt->mnt_sb->s_flags & SB_NOSEC)
11698c2ecf20Sopenharmony_ci		sb->s_flags |= SB_NOSEC;
11708c2ecf20Sopenharmony_ci
11718c2ecf20Sopenharmony_ci	if (ovl_inuse_trylock(ovl_upper_mnt(ofs)->mnt_root)) {
11728c2ecf20Sopenharmony_ci		ofs->upperdir_locked = true;
11738c2ecf20Sopenharmony_ci	} else {
11748c2ecf20Sopenharmony_ci		err = ovl_report_in_use(ofs, "upperdir");
11758c2ecf20Sopenharmony_ci		if (err)
11768c2ecf20Sopenharmony_ci			goto out;
11778c2ecf20Sopenharmony_ci	}
11788c2ecf20Sopenharmony_ci
11798c2ecf20Sopenharmony_ci	err = 0;
11808c2ecf20Sopenharmony_ciout:
11818c2ecf20Sopenharmony_ci	return err;
11828c2ecf20Sopenharmony_ci}
11838c2ecf20Sopenharmony_ci
11848c2ecf20Sopenharmony_ci/*
11858c2ecf20Sopenharmony_ci * Returns 1 if RENAME_WHITEOUT is supported, 0 if not supported and
11868c2ecf20Sopenharmony_ci * negative values if error is encountered.
11878c2ecf20Sopenharmony_ci */
11888c2ecf20Sopenharmony_cistatic int ovl_check_rename_whiteout(struct dentry *workdir)
11898c2ecf20Sopenharmony_ci{
11908c2ecf20Sopenharmony_ci	struct inode *dir = d_inode(workdir);
11918c2ecf20Sopenharmony_ci	struct dentry *temp;
11928c2ecf20Sopenharmony_ci	struct dentry *dest;
11938c2ecf20Sopenharmony_ci	struct dentry *whiteout;
11948c2ecf20Sopenharmony_ci	struct name_snapshot name;
11958c2ecf20Sopenharmony_ci	int err;
11968c2ecf20Sopenharmony_ci
11978c2ecf20Sopenharmony_ci	inode_lock_nested(dir, I_MUTEX_PARENT);
11988c2ecf20Sopenharmony_ci
11998c2ecf20Sopenharmony_ci	temp = ovl_create_temp(workdir, OVL_CATTR(S_IFREG | 0));
12008c2ecf20Sopenharmony_ci	err = PTR_ERR(temp);
12018c2ecf20Sopenharmony_ci	if (IS_ERR(temp))
12028c2ecf20Sopenharmony_ci		goto out_unlock;
12038c2ecf20Sopenharmony_ci
12048c2ecf20Sopenharmony_ci	dest = ovl_lookup_temp(workdir);
12058c2ecf20Sopenharmony_ci	err = PTR_ERR(dest);
12068c2ecf20Sopenharmony_ci	if (IS_ERR(dest)) {
12078c2ecf20Sopenharmony_ci		dput(temp);
12088c2ecf20Sopenharmony_ci		goto out_unlock;
12098c2ecf20Sopenharmony_ci	}
12108c2ecf20Sopenharmony_ci
12118c2ecf20Sopenharmony_ci	/* Name is inline and stable - using snapshot as a copy helper */
12128c2ecf20Sopenharmony_ci	take_dentry_name_snapshot(&name, temp);
12138c2ecf20Sopenharmony_ci	err = ovl_do_rename(dir, temp, dir, dest, RENAME_WHITEOUT);
12148c2ecf20Sopenharmony_ci	if (err) {
12158c2ecf20Sopenharmony_ci		if (err == -EINVAL)
12168c2ecf20Sopenharmony_ci			err = 0;
12178c2ecf20Sopenharmony_ci		goto cleanup_temp;
12188c2ecf20Sopenharmony_ci	}
12198c2ecf20Sopenharmony_ci
12208c2ecf20Sopenharmony_ci	whiteout = lookup_one_len(name.name.name, workdir, name.name.len);
12218c2ecf20Sopenharmony_ci	err = PTR_ERR(whiteout);
12228c2ecf20Sopenharmony_ci	if (IS_ERR(whiteout))
12238c2ecf20Sopenharmony_ci		goto cleanup_temp;
12248c2ecf20Sopenharmony_ci
12258c2ecf20Sopenharmony_ci	err = ovl_is_whiteout(whiteout);
12268c2ecf20Sopenharmony_ci
12278c2ecf20Sopenharmony_ci	/* Best effort cleanup of whiteout and temp file */
12288c2ecf20Sopenharmony_ci	if (err)
12298c2ecf20Sopenharmony_ci		ovl_cleanup(dir, whiteout);
12308c2ecf20Sopenharmony_ci	dput(whiteout);
12318c2ecf20Sopenharmony_ci
12328c2ecf20Sopenharmony_cicleanup_temp:
12338c2ecf20Sopenharmony_ci	ovl_cleanup(dir, temp);
12348c2ecf20Sopenharmony_ci	release_dentry_name_snapshot(&name);
12358c2ecf20Sopenharmony_ci	dput(temp);
12368c2ecf20Sopenharmony_ci	dput(dest);
12378c2ecf20Sopenharmony_ci
12388c2ecf20Sopenharmony_ciout_unlock:
12398c2ecf20Sopenharmony_ci	inode_unlock(dir);
12408c2ecf20Sopenharmony_ci
12418c2ecf20Sopenharmony_ci	return err;
12428c2ecf20Sopenharmony_ci}
12438c2ecf20Sopenharmony_ci
12448c2ecf20Sopenharmony_cistatic struct dentry *ovl_lookup_or_create(struct dentry *parent,
12458c2ecf20Sopenharmony_ci					   const char *name, umode_t mode)
12468c2ecf20Sopenharmony_ci{
12478c2ecf20Sopenharmony_ci	size_t len = strlen(name);
12488c2ecf20Sopenharmony_ci	struct dentry *child;
12498c2ecf20Sopenharmony_ci
12508c2ecf20Sopenharmony_ci	inode_lock_nested(parent->d_inode, I_MUTEX_PARENT);
12518c2ecf20Sopenharmony_ci	child = lookup_one_len(name, parent, len);
12528c2ecf20Sopenharmony_ci	if (!IS_ERR(child) && !child->d_inode)
12538c2ecf20Sopenharmony_ci		child = ovl_create_real(parent->d_inode, child,
12548c2ecf20Sopenharmony_ci					OVL_CATTR(mode));
12558c2ecf20Sopenharmony_ci	inode_unlock(parent->d_inode);
12568c2ecf20Sopenharmony_ci	dput(parent);
12578c2ecf20Sopenharmony_ci
12588c2ecf20Sopenharmony_ci	return child;
12598c2ecf20Sopenharmony_ci}
12608c2ecf20Sopenharmony_ci
12618c2ecf20Sopenharmony_ci/*
12628c2ecf20Sopenharmony_ci * Creates $workdir/work/incompat/volatile/dirty file if it is not already
12638c2ecf20Sopenharmony_ci * present.
12648c2ecf20Sopenharmony_ci */
12658c2ecf20Sopenharmony_cistatic int ovl_create_volatile_dirty(struct ovl_fs *ofs)
12668c2ecf20Sopenharmony_ci{
12678c2ecf20Sopenharmony_ci	unsigned int ctr;
12688c2ecf20Sopenharmony_ci	struct dentry *d = dget(ofs->workbasedir);
12698c2ecf20Sopenharmony_ci	static const char *const volatile_path[] = {
12708c2ecf20Sopenharmony_ci		OVL_WORKDIR_NAME, "incompat", "volatile", "dirty"
12718c2ecf20Sopenharmony_ci	};
12728c2ecf20Sopenharmony_ci	const char *const *name = volatile_path;
12738c2ecf20Sopenharmony_ci
12748c2ecf20Sopenharmony_ci	for (ctr = ARRAY_SIZE(volatile_path); ctr; ctr--, name++) {
12758c2ecf20Sopenharmony_ci		d = ovl_lookup_or_create(d, *name, ctr > 1 ? S_IFDIR : S_IFREG);
12768c2ecf20Sopenharmony_ci		if (IS_ERR(d))
12778c2ecf20Sopenharmony_ci			return PTR_ERR(d);
12788c2ecf20Sopenharmony_ci	}
12798c2ecf20Sopenharmony_ci	dput(d);
12808c2ecf20Sopenharmony_ci	return 0;
12818c2ecf20Sopenharmony_ci}
12828c2ecf20Sopenharmony_ci
12838c2ecf20Sopenharmony_cistatic int ovl_make_workdir(struct super_block *sb, struct ovl_fs *ofs,
12848c2ecf20Sopenharmony_ci			    struct path *workpath)
12858c2ecf20Sopenharmony_ci{
12868c2ecf20Sopenharmony_ci	struct vfsmount *mnt = ovl_upper_mnt(ofs);
12878c2ecf20Sopenharmony_ci	struct dentry *temp, *workdir;
12888c2ecf20Sopenharmony_ci	bool rename_whiteout;
12898c2ecf20Sopenharmony_ci	bool d_type;
12908c2ecf20Sopenharmony_ci	int fh_type;
12918c2ecf20Sopenharmony_ci	int err;
12928c2ecf20Sopenharmony_ci
12938c2ecf20Sopenharmony_ci	err = mnt_want_write(mnt);
12948c2ecf20Sopenharmony_ci	if (err)
12958c2ecf20Sopenharmony_ci		return err;
12968c2ecf20Sopenharmony_ci
12978c2ecf20Sopenharmony_ci	workdir = ovl_workdir_create(ofs, OVL_WORKDIR_NAME, false);
12988c2ecf20Sopenharmony_ci	err = PTR_ERR(workdir);
12998c2ecf20Sopenharmony_ci	if (IS_ERR_OR_NULL(workdir))
13008c2ecf20Sopenharmony_ci		goto out;
13018c2ecf20Sopenharmony_ci
13028c2ecf20Sopenharmony_ci	ofs->workdir = workdir;
13038c2ecf20Sopenharmony_ci
13048c2ecf20Sopenharmony_ci	err = ovl_setup_trap(sb, ofs->workdir, &ofs->workdir_trap, "workdir");
13058c2ecf20Sopenharmony_ci	if (err)
13068c2ecf20Sopenharmony_ci		goto out;
13078c2ecf20Sopenharmony_ci
13088c2ecf20Sopenharmony_ci	/*
13098c2ecf20Sopenharmony_ci	 * Upper should support d_type, else whiteouts are visible.  Given
13108c2ecf20Sopenharmony_ci	 * workdir and upper are on same fs, we can do iterate_dir() on
13118c2ecf20Sopenharmony_ci	 * workdir. This check requires successful creation of workdir in
13128c2ecf20Sopenharmony_ci	 * previous step.
13138c2ecf20Sopenharmony_ci	 */
13148c2ecf20Sopenharmony_ci	err = ovl_check_d_type_supported(workpath);
13158c2ecf20Sopenharmony_ci	if (err < 0)
13168c2ecf20Sopenharmony_ci		goto out;
13178c2ecf20Sopenharmony_ci
13188c2ecf20Sopenharmony_ci	d_type = err;
13198c2ecf20Sopenharmony_ci	if (!d_type)
13208c2ecf20Sopenharmony_ci		pr_warn("upper fs needs to support d_type.\n");
13218c2ecf20Sopenharmony_ci
13228c2ecf20Sopenharmony_ci	/* Check if upper/work fs supports O_TMPFILE */
13238c2ecf20Sopenharmony_ci	temp = ovl_do_tmpfile(ofs->workdir, S_IFREG | 0);
13248c2ecf20Sopenharmony_ci	ofs->tmpfile = !IS_ERR(temp);
13258c2ecf20Sopenharmony_ci	if (ofs->tmpfile)
13268c2ecf20Sopenharmony_ci		dput(temp);
13278c2ecf20Sopenharmony_ci	else
13288c2ecf20Sopenharmony_ci		pr_warn("upper fs does not support tmpfile.\n");
13298c2ecf20Sopenharmony_ci
13308c2ecf20Sopenharmony_ci
13318c2ecf20Sopenharmony_ci	/* Check if upper/work fs supports RENAME_WHITEOUT */
13328c2ecf20Sopenharmony_ci	err = ovl_check_rename_whiteout(ofs->workdir);
13338c2ecf20Sopenharmony_ci	if (err < 0)
13348c2ecf20Sopenharmony_ci		goto out;
13358c2ecf20Sopenharmony_ci
13368c2ecf20Sopenharmony_ci	rename_whiteout = err;
13378c2ecf20Sopenharmony_ci	if (!rename_whiteout)
13388c2ecf20Sopenharmony_ci		pr_warn("upper fs does not support RENAME_WHITEOUT.\n");
13398c2ecf20Sopenharmony_ci
13408c2ecf20Sopenharmony_ci	/*
13418c2ecf20Sopenharmony_ci	 * Check if upper/work fs supports trusted.overlay.* xattr
13428c2ecf20Sopenharmony_ci	 */
13438c2ecf20Sopenharmony_ci	err = ovl_do_setxattr(ofs, ofs->workdir, OVL_XATTR_OPAQUE, "0", 1);
13448c2ecf20Sopenharmony_ci	if (err) {
13458c2ecf20Sopenharmony_ci		ofs->noxattr = true;
13468c2ecf20Sopenharmony_ci		ofs->config.index = false;
13478c2ecf20Sopenharmony_ci		ofs->config.metacopy = false;
13488c2ecf20Sopenharmony_ci		pr_warn("upper fs does not support xattr, falling back to index=off and metacopy=off.\n");
13498c2ecf20Sopenharmony_ci		err = 0;
13508c2ecf20Sopenharmony_ci	} else {
13518c2ecf20Sopenharmony_ci		ovl_do_removexattr(ofs, ofs->workdir, OVL_XATTR_OPAQUE);
13528c2ecf20Sopenharmony_ci	}
13538c2ecf20Sopenharmony_ci
13548c2ecf20Sopenharmony_ci	/*
13558c2ecf20Sopenharmony_ci	 * We allowed sub-optimal upper fs configuration and don't want to break
13568c2ecf20Sopenharmony_ci	 * users over kernel upgrade, but we never allowed remote upper fs, so
13578c2ecf20Sopenharmony_ci	 * we can enforce strict requirements for remote upper fs.
13588c2ecf20Sopenharmony_ci	 */
13598c2ecf20Sopenharmony_ci	if (ovl_dentry_remote(ofs->workdir) &&
13608c2ecf20Sopenharmony_ci	    (!d_type || !rename_whiteout || ofs->noxattr)) {
13618c2ecf20Sopenharmony_ci		pr_err("upper fs missing required features.\n");
13628c2ecf20Sopenharmony_ci		err = -EINVAL;
13638c2ecf20Sopenharmony_ci		goto out;
13648c2ecf20Sopenharmony_ci	}
13658c2ecf20Sopenharmony_ci
13668c2ecf20Sopenharmony_ci	/*
13678c2ecf20Sopenharmony_ci	 * For volatile mount, create a incompat/volatile/dirty file to keep
13688c2ecf20Sopenharmony_ci	 * track of it.
13698c2ecf20Sopenharmony_ci	 */
13708c2ecf20Sopenharmony_ci	if (ofs->config.ovl_volatile) {
13718c2ecf20Sopenharmony_ci		err = ovl_create_volatile_dirty(ofs);
13728c2ecf20Sopenharmony_ci		if (err < 0) {
13738c2ecf20Sopenharmony_ci			pr_err("Failed to create volatile/dirty file.\n");
13748c2ecf20Sopenharmony_ci			goto out;
13758c2ecf20Sopenharmony_ci		}
13768c2ecf20Sopenharmony_ci	}
13778c2ecf20Sopenharmony_ci
13788c2ecf20Sopenharmony_ci	/* Check if upper/work fs supports file handles */
13798c2ecf20Sopenharmony_ci	fh_type = ovl_can_decode_fh(ofs->workdir->d_sb);
13808c2ecf20Sopenharmony_ci	if (ofs->config.index && !fh_type) {
13818c2ecf20Sopenharmony_ci		ofs->config.index = false;
13828c2ecf20Sopenharmony_ci		pr_warn("upper fs does not support file handles, falling back to index=off.\n");
13838c2ecf20Sopenharmony_ci	}
13848c2ecf20Sopenharmony_ci
13858c2ecf20Sopenharmony_ci	/* Check if upper fs has 32bit inode numbers */
13868c2ecf20Sopenharmony_ci	if (fh_type != FILEID_INO32_GEN)
13878c2ecf20Sopenharmony_ci		ofs->xino_mode = -1;
13888c2ecf20Sopenharmony_ci
13898c2ecf20Sopenharmony_ci	/* NFS export of r/w mount depends on index */
13908c2ecf20Sopenharmony_ci	if (ofs->config.nfs_export && !ofs->config.index) {
13918c2ecf20Sopenharmony_ci		pr_warn("NFS export requires \"index=on\", falling back to nfs_export=off.\n");
13928c2ecf20Sopenharmony_ci		ofs->config.nfs_export = false;
13938c2ecf20Sopenharmony_ci	}
13948c2ecf20Sopenharmony_ciout:
13958c2ecf20Sopenharmony_ci	mnt_drop_write(mnt);
13968c2ecf20Sopenharmony_ci	return err;
13978c2ecf20Sopenharmony_ci}
13988c2ecf20Sopenharmony_ci
13998c2ecf20Sopenharmony_cistatic int ovl_get_workdir(struct super_block *sb, struct ovl_fs *ofs,
14008c2ecf20Sopenharmony_ci			   struct path *upperpath)
14018c2ecf20Sopenharmony_ci{
14028c2ecf20Sopenharmony_ci	int err;
14038c2ecf20Sopenharmony_ci	struct path workpath = { };
14048c2ecf20Sopenharmony_ci
14058c2ecf20Sopenharmony_ci	err = ovl_mount_dir(ofs->config.workdir, &workpath);
14068c2ecf20Sopenharmony_ci	if (err)
14078c2ecf20Sopenharmony_ci		goto out;
14088c2ecf20Sopenharmony_ci
14098c2ecf20Sopenharmony_ci	err = -EINVAL;
14108c2ecf20Sopenharmony_ci	if (upperpath->mnt != workpath.mnt) {
14118c2ecf20Sopenharmony_ci		pr_err("workdir and upperdir must reside under the same mount\n");
14128c2ecf20Sopenharmony_ci		goto out;
14138c2ecf20Sopenharmony_ci	}
14148c2ecf20Sopenharmony_ci	if (!ovl_workdir_ok(workpath.dentry, upperpath->dentry)) {
14158c2ecf20Sopenharmony_ci		pr_err("workdir and upperdir must be separate subtrees\n");
14168c2ecf20Sopenharmony_ci		goto out;
14178c2ecf20Sopenharmony_ci	}
14188c2ecf20Sopenharmony_ci
14198c2ecf20Sopenharmony_ci	ofs->workbasedir = dget(workpath.dentry);
14208c2ecf20Sopenharmony_ci
14218c2ecf20Sopenharmony_ci	if (ovl_inuse_trylock(ofs->workbasedir)) {
14228c2ecf20Sopenharmony_ci		ofs->workdir_locked = true;
14238c2ecf20Sopenharmony_ci	} else {
14248c2ecf20Sopenharmony_ci		err = ovl_report_in_use(ofs, "workdir");
14258c2ecf20Sopenharmony_ci		if (err)
14268c2ecf20Sopenharmony_ci			goto out;
14278c2ecf20Sopenharmony_ci	}
14288c2ecf20Sopenharmony_ci
14298c2ecf20Sopenharmony_ci	err = ovl_setup_trap(sb, ofs->workbasedir, &ofs->workbasedir_trap,
14308c2ecf20Sopenharmony_ci			     "workdir");
14318c2ecf20Sopenharmony_ci	if (err)
14328c2ecf20Sopenharmony_ci		goto out;
14338c2ecf20Sopenharmony_ci
14348c2ecf20Sopenharmony_ci	err = ovl_make_workdir(sb, ofs, &workpath);
14358c2ecf20Sopenharmony_ci
14368c2ecf20Sopenharmony_ciout:
14378c2ecf20Sopenharmony_ci	path_put(&workpath);
14388c2ecf20Sopenharmony_ci
14398c2ecf20Sopenharmony_ci	return err;
14408c2ecf20Sopenharmony_ci}
14418c2ecf20Sopenharmony_ci
14428c2ecf20Sopenharmony_cistatic int ovl_get_indexdir(struct super_block *sb, struct ovl_fs *ofs,
14438c2ecf20Sopenharmony_ci			    struct ovl_entry *oe, struct path *upperpath)
14448c2ecf20Sopenharmony_ci{
14458c2ecf20Sopenharmony_ci	struct vfsmount *mnt = ovl_upper_mnt(ofs);
14468c2ecf20Sopenharmony_ci	struct dentry *indexdir;
14478c2ecf20Sopenharmony_ci	int err;
14488c2ecf20Sopenharmony_ci
14498c2ecf20Sopenharmony_ci	err = mnt_want_write(mnt);
14508c2ecf20Sopenharmony_ci	if (err)
14518c2ecf20Sopenharmony_ci		return err;
14528c2ecf20Sopenharmony_ci
14538c2ecf20Sopenharmony_ci	/* Verify lower root is upper root origin */
14548c2ecf20Sopenharmony_ci	err = ovl_verify_origin(ofs, upperpath->dentry,
14558c2ecf20Sopenharmony_ci				oe->lowerstack[0].dentry, true);
14568c2ecf20Sopenharmony_ci	if (err) {
14578c2ecf20Sopenharmony_ci		pr_err("failed to verify upper root origin\n");
14588c2ecf20Sopenharmony_ci		goto out;
14598c2ecf20Sopenharmony_ci	}
14608c2ecf20Sopenharmony_ci
14618c2ecf20Sopenharmony_ci	/* index dir will act also as workdir */
14628c2ecf20Sopenharmony_ci	iput(ofs->workdir_trap);
14638c2ecf20Sopenharmony_ci	ofs->workdir_trap = NULL;
14648c2ecf20Sopenharmony_ci	dput(ofs->workdir);
14658c2ecf20Sopenharmony_ci	ofs->workdir = NULL;
14668c2ecf20Sopenharmony_ci	indexdir = ovl_workdir_create(ofs, OVL_INDEXDIR_NAME, true);
14678c2ecf20Sopenharmony_ci	if (IS_ERR(indexdir)) {
14688c2ecf20Sopenharmony_ci		err = PTR_ERR(indexdir);
14698c2ecf20Sopenharmony_ci	} else if (indexdir) {
14708c2ecf20Sopenharmony_ci		ofs->indexdir = indexdir;
14718c2ecf20Sopenharmony_ci		ofs->workdir = dget(indexdir);
14728c2ecf20Sopenharmony_ci
14738c2ecf20Sopenharmony_ci		err = ovl_setup_trap(sb, ofs->indexdir, &ofs->indexdir_trap,
14748c2ecf20Sopenharmony_ci				     "indexdir");
14758c2ecf20Sopenharmony_ci		if (err)
14768c2ecf20Sopenharmony_ci			goto out;
14778c2ecf20Sopenharmony_ci
14788c2ecf20Sopenharmony_ci		/*
14798c2ecf20Sopenharmony_ci		 * Verify upper root is exclusively associated with index dir.
14808c2ecf20Sopenharmony_ci		 * Older kernels stored upper fh in "trusted.overlay.origin"
14818c2ecf20Sopenharmony_ci		 * xattr. If that xattr exists, verify that it is a match to
14828c2ecf20Sopenharmony_ci		 * upper dir file handle. In any case, verify or set xattr
14838c2ecf20Sopenharmony_ci		 * "trusted.overlay.upper" to indicate that index may have
14848c2ecf20Sopenharmony_ci		 * directory entries.
14858c2ecf20Sopenharmony_ci		 */
14868c2ecf20Sopenharmony_ci		if (ovl_check_origin_xattr(ofs, ofs->indexdir)) {
14878c2ecf20Sopenharmony_ci			err = ovl_verify_set_fh(ofs, ofs->indexdir,
14888c2ecf20Sopenharmony_ci						OVL_XATTR_ORIGIN,
14898c2ecf20Sopenharmony_ci						upperpath->dentry, true, false);
14908c2ecf20Sopenharmony_ci			if (err)
14918c2ecf20Sopenharmony_ci				pr_err("failed to verify index dir 'origin' xattr\n");
14928c2ecf20Sopenharmony_ci		}
14938c2ecf20Sopenharmony_ci		err = ovl_verify_upper(ofs, ofs->indexdir, upperpath->dentry,
14948c2ecf20Sopenharmony_ci				       true);
14958c2ecf20Sopenharmony_ci		if (err)
14968c2ecf20Sopenharmony_ci			pr_err("failed to verify index dir 'upper' xattr\n");
14978c2ecf20Sopenharmony_ci
14988c2ecf20Sopenharmony_ci		/* Cleanup bad/stale/orphan index entries */
14998c2ecf20Sopenharmony_ci		if (!err)
15008c2ecf20Sopenharmony_ci			err = ovl_indexdir_cleanup(ofs);
15018c2ecf20Sopenharmony_ci	}
15028c2ecf20Sopenharmony_ci	if (err || !ofs->indexdir)
15038c2ecf20Sopenharmony_ci		pr_warn("try deleting index dir or mounting with '-o index=off' to disable inodes index.\n");
15048c2ecf20Sopenharmony_ci
15058c2ecf20Sopenharmony_ciout:
15068c2ecf20Sopenharmony_ci	mnt_drop_write(mnt);
15078c2ecf20Sopenharmony_ci	return err;
15088c2ecf20Sopenharmony_ci}
15098c2ecf20Sopenharmony_ci
15108c2ecf20Sopenharmony_cistatic bool ovl_lower_uuid_ok(struct ovl_fs *ofs, const uuid_t *uuid)
15118c2ecf20Sopenharmony_ci{
15128c2ecf20Sopenharmony_ci	unsigned int i;
15138c2ecf20Sopenharmony_ci
15148c2ecf20Sopenharmony_ci	if (!ofs->config.nfs_export && !ovl_upper_mnt(ofs))
15158c2ecf20Sopenharmony_ci		return true;
15168c2ecf20Sopenharmony_ci
15178c2ecf20Sopenharmony_ci	/*
15188c2ecf20Sopenharmony_ci	 * We allow using single lower with null uuid for index and nfs_export
15198c2ecf20Sopenharmony_ci	 * for example to support those features with single lower squashfs.
15208c2ecf20Sopenharmony_ci	 * To avoid regressions in setups of overlay with re-formatted lower
15218c2ecf20Sopenharmony_ci	 * squashfs, do not allow decoding origin with lower null uuid unless
15228c2ecf20Sopenharmony_ci	 * user opted-in to one of the new features that require following the
15238c2ecf20Sopenharmony_ci	 * lower inode of non-dir upper.
15248c2ecf20Sopenharmony_ci	 */
15258c2ecf20Sopenharmony_ci	if (!ofs->config.index && !ofs->config.metacopy && !ofs->config.xino &&
15268c2ecf20Sopenharmony_ci	    uuid_is_null(uuid))
15278c2ecf20Sopenharmony_ci		return false;
15288c2ecf20Sopenharmony_ci
15298c2ecf20Sopenharmony_ci	for (i = 0; i < ofs->numfs; i++) {
15308c2ecf20Sopenharmony_ci		/*
15318c2ecf20Sopenharmony_ci		 * We use uuid to associate an overlay lower file handle with a
15328c2ecf20Sopenharmony_ci		 * lower layer, so we can accept lower fs with null uuid as long
15338c2ecf20Sopenharmony_ci		 * as all lower layers with null uuid are on the same fs.
15348c2ecf20Sopenharmony_ci		 * if we detect multiple lower fs with the same uuid, we
15358c2ecf20Sopenharmony_ci		 * disable lower file handle decoding on all of them.
15368c2ecf20Sopenharmony_ci		 */
15378c2ecf20Sopenharmony_ci		if (ofs->fs[i].is_lower &&
15388c2ecf20Sopenharmony_ci		    uuid_equal(&ofs->fs[i].sb->s_uuid, uuid)) {
15398c2ecf20Sopenharmony_ci			ofs->fs[i].bad_uuid = true;
15408c2ecf20Sopenharmony_ci			return false;
15418c2ecf20Sopenharmony_ci		}
15428c2ecf20Sopenharmony_ci	}
15438c2ecf20Sopenharmony_ci	return true;
15448c2ecf20Sopenharmony_ci}
15458c2ecf20Sopenharmony_ci
15468c2ecf20Sopenharmony_ci/* Get a unique fsid for the layer */
15478c2ecf20Sopenharmony_cistatic int ovl_get_fsid(struct ovl_fs *ofs, const struct path *path)
15488c2ecf20Sopenharmony_ci{
15498c2ecf20Sopenharmony_ci	struct super_block *sb = path->mnt->mnt_sb;
15508c2ecf20Sopenharmony_ci	unsigned int i;
15518c2ecf20Sopenharmony_ci	dev_t dev;
15528c2ecf20Sopenharmony_ci	int err;
15538c2ecf20Sopenharmony_ci	bool bad_uuid = false;
15548c2ecf20Sopenharmony_ci
15558c2ecf20Sopenharmony_ci	for (i = 0; i < ofs->numfs; i++) {
15568c2ecf20Sopenharmony_ci		if (ofs->fs[i].sb == sb)
15578c2ecf20Sopenharmony_ci			return i;
15588c2ecf20Sopenharmony_ci	}
15598c2ecf20Sopenharmony_ci
15608c2ecf20Sopenharmony_ci	if (!ovl_lower_uuid_ok(ofs, &sb->s_uuid)) {
15618c2ecf20Sopenharmony_ci		bad_uuid = true;
15628c2ecf20Sopenharmony_ci		if (ofs->config.index || ofs->config.nfs_export) {
15638c2ecf20Sopenharmony_ci			ofs->config.index = false;
15648c2ecf20Sopenharmony_ci			ofs->config.nfs_export = false;
15658c2ecf20Sopenharmony_ci			pr_warn("%s uuid detected in lower fs '%pd2', falling back to index=off,nfs_export=off.\n",
15668c2ecf20Sopenharmony_ci				uuid_is_null(&sb->s_uuid) ? "null" :
15678c2ecf20Sopenharmony_ci							    "conflicting",
15688c2ecf20Sopenharmony_ci				path->dentry);
15698c2ecf20Sopenharmony_ci		}
15708c2ecf20Sopenharmony_ci	}
15718c2ecf20Sopenharmony_ci
15728c2ecf20Sopenharmony_ci	err = get_anon_bdev(&dev);
15738c2ecf20Sopenharmony_ci	if (err) {
15748c2ecf20Sopenharmony_ci		pr_err("failed to get anonymous bdev for lowerpath\n");
15758c2ecf20Sopenharmony_ci		return err;
15768c2ecf20Sopenharmony_ci	}
15778c2ecf20Sopenharmony_ci
15788c2ecf20Sopenharmony_ci	ofs->fs[ofs->numfs].sb = sb;
15798c2ecf20Sopenharmony_ci	ofs->fs[ofs->numfs].pseudo_dev = dev;
15808c2ecf20Sopenharmony_ci	ofs->fs[ofs->numfs].bad_uuid = bad_uuid;
15818c2ecf20Sopenharmony_ci
15828c2ecf20Sopenharmony_ci	return ofs->numfs++;
15838c2ecf20Sopenharmony_ci}
15848c2ecf20Sopenharmony_ci
15858c2ecf20Sopenharmony_cistatic int ovl_get_layers(struct super_block *sb, struct ovl_fs *ofs,
15868c2ecf20Sopenharmony_ci			  struct path *stack, unsigned int numlower,
15878c2ecf20Sopenharmony_ci			  struct ovl_layer *layers)
15888c2ecf20Sopenharmony_ci{
15898c2ecf20Sopenharmony_ci	int err;
15908c2ecf20Sopenharmony_ci	unsigned int i;
15918c2ecf20Sopenharmony_ci
15928c2ecf20Sopenharmony_ci	err = -ENOMEM;
15938c2ecf20Sopenharmony_ci	ofs->fs = kcalloc(numlower + 1, sizeof(struct ovl_sb), GFP_KERNEL);
15948c2ecf20Sopenharmony_ci	if (ofs->fs == NULL)
15958c2ecf20Sopenharmony_ci		goto out;
15968c2ecf20Sopenharmony_ci
15978c2ecf20Sopenharmony_ci	/* idx/fsid 0 are reserved for upper fs even with lower only overlay */
15988c2ecf20Sopenharmony_ci	ofs->numfs++;
15998c2ecf20Sopenharmony_ci
16008c2ecf20Sopenharmony_ci	/*
16018c2ecf20Sopenharmony_ci	 * All lower layers that share the same fs as upper layer, use the same
16028c2ecf20Sopenharmony_ci	 * pseudo_dev as upper layer.  Allocate fs[0].pseudo_dev even for lower
16038c2ecf20Sopenharmony_ci	 * only overlay to simplify ovl_fs_free().
16048c2ecf20Sopenharmony_ci	 * is_lower will be set if upper fs is shared with a lower layer.
16058c2ecf20Sopenharmony_ci	 */
16068c2ecf20Sopenharmony_ci	err = get_anon_bdev(&ofs->fs[0].pseudo_dev);
16078c2ecf20Sopenharmony_ci	if (err) {
16088c2ecf20Sopenharmony_ci		pr_err("failed to get anonymous bdev for upper fs\n");
16098c2ecf20Sopenharmony_ci		goto out;
16108c2ecf20Sopenharmony_ci	}
16118c2ecf20Sopenharmony_ci
16128c2ecf20Sopenharmony_ci	if (ovl_upper_mnt(ofs)) {
16138c2ecf20Sopenharmony_ci		ofs->fs[0].sb = ovl_upper_mnt(ofs)->mnt_sb;
16148c2ecf20Sopenharmony_ci		ofs->fs[0].is_lower = false;
16158c2ecf20Sopenharmony_ci	}
16168c2ecf20Sopenharmony_ci
16178c2ecf20Sopenharmony_ci	for (i = 0; i < numlower; i++) {
16188c2ecf20Sopenharmony_ci		struct vfsmount *mnt;
16198c2ecf20Sopenharmony_ci		struct inode *trap;
16208c2ecf20Sopenharmony_ci		int fsid;
16218c2ecf20Sopenharmony_ci
16228c2ecf20Sopenharmony_ci		err = fsid = ovl_get_fsid(ofs, &stack[i]);
16238c2ecf20Sopenharmony_ci		if (err < 0)
16248c2ecf20Sopenharmony_ci			goto out;
16258c2ecf20Sopenharmony_ci
16268c2ecf20Sopenharmony_ci		/*
16278c2ecf20Sopenharmony_ci		 * Check if lower root conflicts with this overlay layers before
16288c2ecf20Sopenharmony_ci		 * checking if it is in-use as upperdir/workdir of "another"
16298c2ecf20Sopenharmony_ci		 * mount, because we do not bother to check in ovl_is_inuse() if
16308c2ecf20Sopenharmony_ci		 * the upperdir/workdir is in fact in-use by our
16318c2ecf20Sopenharmony_ci		 * upperdir/workdir.
16328c2ecf20Sopenharmony_ci		 */
16338c2ecf20Sopenharmony_ci		err = ovl_setup_trap(sb, stack[i].dentry, &trap, "lowerdir");
16348c2ecf20Sopenharmony_ci		if (err)
16358c2ecf20Sopenharmony_ci			goto out;
16368c2ecf20Sopenharmony_ci
16378c2ecf20Sopenharmony_ci		if (ovl_is_inuse(stack[i].dentry)) {
16388c2ecf20Sopenharmony_ci			err = ovl_report_in_use(ofs, "lowerdir");
16398c2ecf20Sopenharmony_ci			if (err) {
16408c2ecf20Sopenharmony_ci				iput(trap);
16418c2ecf20Sopenharmony_ci				goto out;
16428c2ecf20Sopenharmony_ci			}
16438c2ecf20Sopenharmony_ci		}
16448c2ecf20Sopenharmony_ci
16458c2ecf20Sopenharmony_ci		mnt = clone_private_mount(&stack[i]);
16468c2ecf20Sopenharmony_ci		err = PTR_ERR(mnt);
16478c2ecf20Sopenharmony_ci		if (IS_ERR(mnt)) {
16488c2ecf20Sopenharmony_ci			pr_err("failed to clone lowerpath\n");
16498c2ecf20Sopenharmony_ci			iput(trap);
16508c2ecf20Sopenharmony_ci			goto out;
16518c2ecf20Sopenharmony_ci		}
16528c2ecf20Sopenharmony_ci
16538c2ecf20Sopenharmony_ci		/*
16548c2ecf20Sopenharmony_ci		 * Make lower layers R/O.  That way fchmod/fchown on lower file
16558c2ecf20Sopenharmony_ci		 * will fail instead of modifying lower fs.
16568c2ecf20Sopenharmony_ci		 */
16578c2ecf20Sopenharmony_ci		mnt->mnt_flags |= MNT_READONLY | MNT_NOATIME;
16588c2ecf20Sopenharmony_ci
16598c2ecf20Sopenharmony_ci		layers[ofs->numlayer].trap = trap;
16608c2ecf20Sopenharmony_ci		layers[ofs->numlayer].mnt = mnt;
16618c2ecf20Sopenharmony_ci		layers[ofs->numlayer].idx = ofs->numlayer;
16628c2ecf20Sopenharmony_ci		layers[ofs->numlayer].fsid = fsid;
16638c2ecf20Sopenharmony_ci		layers[ofs->numlayer].fs = &ofs->fs[fsid];
16648c2ecf20Sopenharmony_ci		ofs->numlayer++;
16658c2ecf20Sopenharmony_ci		ofs->fs[fsid].is_lower = true;
16668c2ecf20Sopenharmony_ci	}
16678c2ecf20Sopenharmony_ci
16688c2ecf20Sopenharmony_ci	/*
16698c2ecf20Sopenharmony_ci	 * When all layers on same fs, overlay can use real inode numbers.
16708c2ecf20Sopenharmony_ci	 * With mount option "xino=<on|auto>", mounter declares that there are
16718c2ecf20Sopenharmony_ci	 * enough free high bits in underlying fs to hold the unique fsid.
16728c2ecf20Sopenharmony_ci	 * If overlayfs does encounter underlying inodes using the high xino
16738c2ecf20Sopenharmony_ci	 * bits reserved for fsid, it emits a warning and uses the original
16748c2ecf20Sopenharmony_ci	 * inode number or a non persistent inode number allocated from a
16758c2ecf20Sopenharmony_ci	 * dedicated range.
16768c2ecf20Sopenharmony_ci	 */
16778c2ecf20Sopenharmony_ci	if (ofs->numfs - !ovl_upper_mnt(ofs) == 1) {
16788c2ecf20Sopenharmony_ci		if (ofs->config.xino == OVL_XINO_ON)
16798c2ecf20Sopenharmony_ci			pr_info("\"xino=on\" is useless with all layers on same fs, ignore.\n");
16808c2ecf20Sopenharmony_ci		ofs->xino_mode = 0;
16818c2ecf20Sopenharmony_ci	} else if (ofs->config.xino == OVL_XINO_OFF) {
16828c2ecf20Sopenharmony_ci		ofs->xino_mode = -1;
16838c2ecf20Sopenharmony_ci	} else if (ofs->xino_mode < 0) {
16848c2ecf20Sopenharmony_ci		/*
16858c2ecf20Sopenharmony_ci		 * This is a roundup of number of bits needed for encoding
16868c2ecf20Sopenharmony_ci		 * fsid, where fsid 0 is reserved for upper fs (even with
16878c2ecf20Sopenharmony_ci		 * lower only overlay) +1 extra bit is reserved for the non
16888c2ecf20Sopenharmony_ci		 * persistent inode number range that is used for resolving
16898c2ecf20Sopenharmony_ci		 * xino lower bits overflow.
16908c2ecf20Sopenharmony_ci		 */
16918c2ecf20Sopenharmony_ci		BUILD_BUG_ON(ilog2(OVL_MAX_STACK) > 30);
16928c2ecf20Sopenharmony_ci		ofs->xino_mode = ilog2(ofs->numfs - 1) + 2;
16938c2ecf20Sopenharmony_ci	}
16948c2ecf20Sopenharmony_ci
16958c2ecf20Sopenharmony_ci	if (ofs->xino_mode > 0) {
16968c2ecf20Sopenharmony_ci		pr_info("\"xino\" feature enabled using %d upper inode bits.\n",
16978c2ecf20Sopenharmony_ci			ofs->xino_mode);
16988c2ecf20Sopenharmony_ci	}
16998c2ecf20Sopenharmony_ci
17008c2ecf20Sopenharmony_ci	err = 0;
17018c2ecf20Sopenharmony_ciout:
17028c2ecf20Sopenharmony_ci	return err;
17038c2ecf20Sopenharmony_ci}
17048c2ecf20Sopenharmony_ci
17058c2ecf20Sopenharmony_cistatic struct ovl_entry *ovl_get_lowerstack(struct super_block *sb,
17068c2ecf20Sopenharmony_ci				const char *lower, unsigned int numlower,
17078c2ecf20Sopenharmony_ci				struct ovl_fs *ofs, struct ovl_layer *layers)
17088c2ecf20Sopenharmony_ci{
17098c2ecf20Sopenharmony_ci	int err;
17108c2ecf20Sopenharmony_ci	struct path *stack = NULL;
17118c2ecf20Sopenharmony_ci	unsigned int i;
17128c2ecf20Sopenharmony_ci	struct ovl_entry *oe;
17138c2ecf20Sopenharmony_ci
17148c2ecf20Sopenharmony_ci	if (!ofs->config.upperdir && numlower == 1) {
17158c2ecf20Sopenharmony_ci		pr_err("at least 2 lowerdir are needed while upperdir nonexistent\n");
17168c2ecf20Sopenharmony_ci		return ERR_PTR(-EINVAL);
17178c2ecf20Sopenharmony_ci	}
17188c2ecf20Sopenharmony_ci
17198c2ecf20Sopenharmony_ci	stack = kcalloc(numlower, sizeof(struct path), GFP_KERNEL);
17208c2ecf20Sopenharmony_ci	if (!stack)
17218c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
17228c2ecf20Sopenharmony_ci
17238c2ecf20Sopenharmony_ci	err = -EINVAL;
17248c2ecf20Sopenharmony_ci	for (i = 0; i < numlower; i++) {
17258c2ecf20Sopenharmony_ci		err = ovl_lower_dir(lower, &stack[i], ofs, &sb->s_stack_depth);
17268c2ecf20Sopenharmony_ci		if (err)
17278c2ecf20Sopenharmony_ci			goto out_err;
17288c2ecf20Sopenharmony_ci
17298c2ecf20Sopenharmony_ci		lower = strchr(lower, '\0') + 1;
17308c2ecf20Sopenharmony_ci	}
17318c2ecf20Sopenharmony_ci
17328c2ecf20Sopenharmony_ci	err = -EINVAL;
17338c2ecf20Sopenharmony_ci	sb->s_stack_depth++;
17348c2ecf20Sopenharmony_ci	if (sb->s_stack_depth > FILESYSTEM_MAX_STACK_DEPTH) {
17358c2ecf20Sopenharmony_ci		pr_err("maximum fs stacking depth exceeded\n");
17368c2ecf20Sopenharmony_ci		goto out_err;
17378c2ecf20Sopenharmony_ci	}
17388c2ecf20Sopenharmony_ci
17398c2ecf20Sopenharmony_ci	err = ovl_get_layers(sb, ofs, stack, numlower, layers);
17408c2ecf20Sopenharmony_ci	if (err)
17418c2ecf20Sopenharmony_ci		goto out_err;
17428c2ecf20Sopenharmony_ci
17438c2ecf20Sopenharmony_ci	err = -ENOMEM;
17448c2ecf20Sopenharmony_ci	oe = ovl_alloc_entry(numlower);
17458c2ecf20Sopenharmony_ci	if (!oe)
17468c2ecf20Sopenharmony_ci		goto out_err;
17478c2ecf20Sopenharmony_ci
17488c2ecf20Sopenharmony_ci	for (i = 0; i < numlower; i++) {
17498c2ecf20Sopenharmony_ci		oe->lowerstack[i].dentry = dget(stack[i].dentry);
17508c2ecf20Sopenharmony_ci		oe->lowerstack[i].layer = &ofs->layers[i+1];
17518c2ecf20Sopenharmony_ci	}
17528c2ecf20Sopenharmony_ci
17538c2ecf20Sopenharmony_ciout:
17548c2ecf20Sopenharmony_ci	for (i = 0; i < numlower; i++)
17558c2ecf20Sopenharmony_ci		path_put(&stack[i]);
17568c2ecf20Sopenharmony_ci	kfree(stack);
17578c2ecf20Sopenharmony_ci
17588c2ecf20Sopenharmony_ci	return oe;
17598c2ecf20Sopenharmony_ci
17608c2ecf20Sopenharmony_ciout_err:
17618c2ecf20Sopenharmony_ci	oe = ERR_PTR(err);
17628c2ecf20Sopenharmony_ci	goto out;
17638c2ecf20Sopenharmony_ci}
17648c2ecf20Sopenharmony_ci
17658c2ecf20Sopenharmony_ci/*
17668c2ecf20Sopenharmony_ci * Check if this layer root is a descendant of:
17678c2ecf20Sopenharmony_ci * - another layer of this overlayfs instance
17688c2ecf20Sopenharmony_ci * - upper/work dir of any overlayfs instance
17698c2ecf20Sopenharmony_ci */
17708c2ecf20Sopenharmony_cistatic int ovl_check_layer(struct super_block *sb, struct ovl_fs *ofs,
17718c2ecf20Sopenharmony_ci			   struct dentry *dentry, const char *name,
17728c2ecf20Sopenharmony_ci			   bool is_lower)
17738c2ecf20Sopenharmony_ci{
17748c2ecf20Sopenharmony_ci	struct dentry *next = dentry, *parent;
17758c2ecf20Sopenharmony_ci	int err = 0;
17768c2ecf20Sopenharmony_ci
17778c2ecf20Sopenharmony_ci	if (!dentry)
17788c2ecf20Sopenharmony_ci		return 0;
17798c2ecf20Sopenharmony_ci
17808c2ecf20Sopenharmony_ci	parent = dget_parent(next);
17818c2ecf20Sopenharmony_ci
17828c2ecf20Sopenharmony_ci	/* Walk back ancestors to root (inclusive) looking for traps */
17838c2ecf20Sopenharmony_ci	while (!err && parent != next) {
17848c2ecf20Sopenharmony_ci		if (is_lower && ovl_lookup_trap_inode(sb, parent)) {
17858c2ecf20Sopenharmony_ci			err = -ELOOP;
17868c2ecf20Sopenharmony_ci			pr_err("overlapping %s path\n", name);
17878c2ecf20Sopenharmony_ci		} else if (ovl_is_inuse(parent)) {
17888c2ecf20Sopenharmony_ci			err = ovl_report_in_use(ofs, name);
17898c2ecf20Sopenharmony_ci		}
17908c2ecf20Sopenharmony_ci		next = parent;
17918c2ecf20Sopenharmony_ci		parent = dget_parent(next);
17928c2ecf20Sopenharmony_ci		dput(next);
17938c2ecf20Sopenharmony_ci	}
17948c2ecf20Sopenharmony_ci
17958c2ecf20Sopenharmony_ci	dput(parent);
17968c2ecf20Sopenharmony_ci
17978c2ecf20Sopenharmony_ci	return err;
17988c2ecf20Sopenharmony_ci}
17998c2ecf20Sopenharmony_ci
18008c2ecf20Sopenharmony_ci/*
18018c2ecf20Sopenharmony_ci * Check if any of the layers or work dirs overlap.
18028c2ecf20Sopenharmony_ci */
18038c2ecf20Sopenharmony_cistatic int ovl_check_overlapping_layers(struct super_block *sb,
18048c2ecf20Sopenharmony_ci					struct ovl_fs *ofs)
18058c2ecf20Sopenharmony_ci{
18068c2ecf20Sopenharmony_ci	int i, err;
18078c2ecf20Sopenharmony_ci
18088c2ecf20Sopenharmony_ci	if (ovl_upper_mnt(ofs)) {
18098c2ecf20Sopenharmony_ci		err = ovl_check_layer(sb, ofs, ovl_upper_mnt(ofs)->mnt_root,
18108c2ecf20Sopenharmony_ci				      "upperdir", false);
18118c2ecf20Sopenharmony_ci		if (err)
18128c2ecf20Sopenharmony_ci			return err;
18138c2ecf20Sopenharmony_ci
18148c2ecf20Sopenharmony_ci		/*
18158c2ecf20Sopenharmony_ci		 * Checking workbasedir avoids hitting ovl_is_inuse(parent) of
18168c2ecf20Sopenharmony_ci		 * this instance and covers overlapping work and index dirs,
18178c2ecf20Sopenharmony_ci		 * unless work or index dir have been moved since created inside
18188c2ecf20Sopenharmony_ci		 * workbasedir.  In that case, we already have their traps in
18198c2ecf20Sopenharmony_ci		 * inode cache and we will catch that case on lookup.
18208c2ecf20Sopenharmony_ci		 */
18218c2ecf20Sopenharmony_ci		err = ovl_check_layer(sb, ofs, ofs->workbasedir, "workdir",
18228c2ecf20Sopenharmony_ci				      false);
18238c2ecf20Sopenharmony_ci		if (err)
18248c2ecf20Sopenharmony_ci			return err;
18258c2ecf20Sopenharmony_ci	}
18268c2ecf20Sopenharmony_ci
18278c2ecf20Sopenharmony_ci	for (i = 1; i < ofs->numlayer; i++) {
18288c2ecf20Sopenharmony_ci		err = ovl_check_layer(sb, ofs,
18298c2ecf20Sopenharmony_ci				      ofs->layers[i].mnt->mnt_root,
18308c2ecf20Sopenharmony_ci				      "lowerdir", true);
18318c2ecf20Sopenharmony_ci		if (err)
18328c2ecf20Sopenharmony_ci			return err;
18338c2ecf20Sopenharmony_ci	}
18348c2ecf20Sopenharmony_ci
18358c2ecf20Sopenharmony_ci	return 0;
18368c2ecf20Sopenharmony_ci}
18378c2ecf20Sopenharmony_ci
18388c2ecf20Sopenharmony_cistatic struct dentry *ovl_get_root(struct super_block *sb,
18398c2ecf20Sopenharmony_ci				   struct dentry *upperdentry,
18408c2ecf20Sopenharmony_ci				   struct ovl_entry *oe)
18418c2ecf20Sopenharmony_ci{
18428c2ecf20Sopenharmony_ci	struct dentry *root;
18438c2ecf20Sopenharmony_ci	struct ovl_path *lowerpath = &oe->lowerstack[0];
18448c2ecf20Sopenharmony_ci	unsigned long ino = d_inode(lowerpath->dentry)->i_ino;
18458c2ecf20Sopenharmony_ci	int fsid = lowerpath->layer->fsid;
18468c2ecf20Sopenharmony_ci	struct ovl_inode_params oip = {
18478c2ecf20Sopenharmony_ci		.upperdentry = upperdentry,
18488c2ecf20Sopenharmony_ci		.lowerpath = lowerpath,
18498c2ecf20Sopenharmony_ci	};
18508c2ecf20Sopenharmony_ci
18518c2ecf20Sopenharmony_ci	root = d_make_root(ovl_new_inode(sb, S_IFDIR, 0));
18528c2ecf20Sopenharmony_ci	if (!root)
18538c2ecf20Sopenharmony_ci		return NULL;
18548c2ecf20Sopenharmony_ci
18558c2ecf20Sopenharmony_ci	root->d_fsdata = oe;
18568c2ecf20Sopenharmony_ci
18578c2ecf20Sopenharmony_ci	if (upperdentry) {
18588c2ecf20Sopenharmony_ci		/* Root inode uses upper st_ino/i_ino */
18598c2ecf20Sopenharmony_ci		ino = d_inode(upperdentry)->i_ino;
18608c2ecf20Sopenharmony_ci		fsid = 0;
18618c2ecf20Sopenharmony_ci		ovl_dentry_set_upper_alias(root);
18628c2ecf20Sopenharmony_ci		if (ovl_is_impuredir(sb, upperdentry))
18638c2ecf20Sopenharmony_ci			ovl_set_flag(OVL_IMPURE, d_inode(root));
18648c2ecf20Sopenharmony_ci	}
18658c2ecf20Sopenharmony_ci
18668c2ecf20Sopenharmony_ci	/* Root is always merge -> can have whiteouts */
18678c2ecf20Sopenharmony_ci	ovl_set_flag(OVL_WHITEOUTS, d_inode(root));
18688c2ecf20Sopenharmony_ci	ovl_dentry_set_flag(OVL_E_CONNECTED, root);
18698c2ecf20Sopenharmony_ci	ovl_set_upperdata(d_inode(root));
18708c2ecf20Sopenharmony_ci	ovl_inode_init(d_inode(root), &oip, ino, fsid);
18718c2ecf20Sopenharmony_ci	ovl_dentry_init_flags(root, upperdentry, DCACHE_OP_WEAK_REVALIDATE);
18728c2ecf20Sopenharmony_ci
18738c2ecf20Sopenharmony_ci	return root;
18748c2ecf20Sopenharmony_ci}
18758c2ecf20Sopenharmony_ci
18768c2ecf20Sopenharmony_cistatic int ovl_fill_super(struct super_block *sb, void *data, int silent)
18778c2ecf20Sopenharmony_ci{
18788c2ecf20Sopenharmony_ci	struct path upperpath = { };
18798c2ecf20Sopenharmony_ci	struct dentry *root_dentry;
18808c2ecf20Sopenharmony_ci	struct ovl_entry *oe;
18818c2ecf20Sopenharmony_ci	struct ovl_fs *ofs;
18828c2ecf20Sopenharmony_ci	struct ovl_layer *layers;
18838c2ecf20Sopenharmony_ci	struct cred *cred;
18848c2ecf20Sopenharmony_ci	char *splitlower = NULL;
18858c2ecf20Sopenharmony_ci	unsigned int numlower;
18868c2ecf20Sopenharmony_ci	int err;
18878c2ecf20Sopenharmony_ci
18888c2ecf20Sopenharmony_ci	sb->s_d_op = &ovl_dentry_operations;
18898c2ecf20Sopenharmony_ci
18908c2ecf20Sopenharmony_ci	err = -ENOMEM;
18918c2ecf20Sopenharmony_ci	ofs = kzalloc(sizeof(struct ovl_fs), GFP_KERNEL);
18928c2ecf20Sopenharmony_ci	if (!ofs)
18938c2ecf20Sopenharmony_ci		goto out;
18948c2ecf20Sopenharmony_ci
18958c2ecf20Sopenharmony_ci	ofs->creator_cred = cred = prepare_creds();
18968c2ecf20Sopenharmony_ci	if (!cred)
18978c2ecf20Sopenharmony_ci		goto out_err;
18988c2ecf20Sopenharmony_ci
18998c2ecf20Sopenharmony_ci	/* Is there a reason anyone would want not to share whiteouts? */
19008c2ecf20Sopenharmony_ci	ofs->share_whiteout = true;
19018c2ecf20Sopenharmony_ci
19028c2ecf20Sopenharmony_ci	ofs->config.index = ovl_index_def;
19038c2ecf20Sopenharmony_ci	ofs->config.nfs_export = ovl_nfs_export_def;
19048c2ecf20Sopenharmony_ci	ofs->config.xino = ovl_xino_def();
19058c2ecf20Sopenharmony_ci	ofs->config.metacopy = ovl_metacopy_def;
19068c2ecf20Sopenharmony_ci	err = ovl_parse_opt((char *) data, &ofs->config);
19078c2ecf20Sopenharmony_ci	if (err)
19088c2ecf20Sopenharmony_ci		goto out_err;
19098c2ecf20Sopenharmony_ci
19108c2ecf20Sopenharmony_ci	err = -EINVAL;
19118c2ecf20Sopenharmony_ci	if (!ofs->config.lowerdir) {
19128c2ecf20Sopenharmony_ci		if (!silent)
19138c2ecf20Sopenharmony_ci			pr_err("missing 'lowerdir'\n");
19148c2ecf20Sopenharmony_ci		goto out_err;
19158c2ecf20Sopenharmony_ci	}
19168c2ecf20Sopenharmony_ci
19178c2ecf20Sopenharmony_ci	err = -ENOMEM;
19188c2ecf20Sopenharmony_ci	splitlower = kstrdup(ofs->config.lowerdir, GFP_KERNEL);
19198c2ecf20Sopenharmony_ci	if (!splitlower)
19208c2ecf20Sopenharmony_ci		goto out_err;
19218c2ecf20Sopenharmony_ci
19228c2ecf20Sopenharmony_ci	numlower = ovl_split_lowerdirs(splitlower);
19238c2ecf20Sopenharmony_ci	if (numlower > OVL_MAX_STACK) {
19248c2ecf20Sopenharmony_ci		pr_err("too many lower directories, limit is %d\n",
19258c2ecf20Sopenharmony_ci		       OVL_MAX_STACK);
19268c2ecf20Sopenharmony_ci		goto out_err;
19278c2ecf20Sopenharmony_ci	}
19288c2ecf20Sopenharmony_ci
19298c2ecf20Sopenharmony_ci	layers = kcalloc(numlower + 1, sizeof(struct ovl_layer), GFP_KERNEL);
19308c2ecf20Sopenharmony_ci	if (!layers)
19318c2ecf20Sopenharmony_ci		goto out_err;
19328c2ecf20Sopenharmony_ci
19338c2ecf20Sopenharmony_ci	ofs->layers = layers;
19348c2ecf20Sopenharmony_ci	/* Layer 0 is reserved for upper even if there's no upper */
19358c2ecf20Sopenharmony_ci	ofs->numlayer = 1;
19368c2ecf20Sopenharmony_ci
19378c2ecf20Sopenharmony_ci	sb->s_stack_depth = 0;
19388c2ecf20Sopenharmony_ci	sb->s_maxbytes = MAX_LFS_FILESIZE;
19398c2ecf20Sopenharmony_ci	atomic_long_set(&ofs->last_ino, 1);
19408c2ecf20Sopenharmony_ci	/* Assume underlaying fs uses 32bit inodes unless proven otherwise */
19418c2ecf20Sopenharmony_ci	if (ofs->config.xino != OVL_XINO_OFF) {
19428c2ecf20Sopenharmony_ci		ofs->xino_mode = BITS_PER_LONG - 32;
19438c2ecf20Sopenharmony_ci		if (!ofs->xino_mode) {
19448c2ecf20Sopenharmony_ci			pr_warn("xino not supported on 32bit kernel, falling back to xino=off.\n");
19458c2ecf20Sopenharmony_ci			ofs->config.xino = OVL_XINO_OFF;
19468c2ecf20Sopenharmony_ci		}
19478c2ecf20Sopenharmony_ci	}
19488c2ecf20Sopenharmony_ci
19498c2ecf20Sopenharmony_ci	/* alloc/destroy_inode needed for setting up traps in inode cache */
19508c2ecf20Sopenharmony_ci	sb->s_op = &ovl_super_operations;
19518c2ecf20Sopenharmony_ci
19528c2ecf20Sopenharmony_ci	if (ofs->config.upperdir) {
19538c2ecf20Sopenharmony_ci		struct super_block *upper_sb;
19548c2ecf20Sopenharmony_ci
19558c2ecf20Sopenharmony_ci		if (!ofs->config.workdir) {
19568c2ecf20Sopenharmony_ci			pr_err("missing 'workdir'\n");
19578c2ecf20Sopenharmony_ci			goto out_err;
19588c2ecf20Sopenharmony_ci		}
19598c2ecf20Sopenharmony_ci
19608c2ecf20Sopenharmony_ci		err = ovl_get_upper(sb, ofs, &layers[0], &upperpath);
19618c2ecf20Sopenharmony_ci		if (err)
19628c2ecf20Sopenharmony_ci			goto out_err;
19638c2ecf20Sopenharmony_ci
19648c2ecf20Sopenharmony_ci		upper_sb = ovl_upper_mnt(ofs)->mnt_sb;
19658c2ecf20Sopenharmony_ci		if (!ovl_should_sync(ofs)) {
19668c2ecf20Sopenharmony_ci			ofs->errseq = errseq_sample(&upper_sb->s_wb_err);
19678c2ecf20Sopenharmony_ci			if (errseq_check(&upper_sb->s_wb_err, ofs->errseq)) {
19688c2ecf20Sopenharmony_ci				err = -EIO;
19698c2ecf20Sopenharmony_ci				pr_err("Cannot mount volatile when upperdir has an unseen error. Sync upperdir fs to clear state.\n");
19708c2ecf20Sopenharmony_ci				goto out_err;
19718c2ecf20Sopenharmony_ci			}
19728c2ecf20Sopenharmony_ci		}
19738c2ecf20Sopenharmony_ci
19748c2ecf20Sopenharmony_ci		err = ovl_get_workdir(sb, ofs, &upperpath);
19758c2ecf20Sopenharmony_ci		if (err)
19768c2ecf20Sopenharmony_ci			goto out_err;
19778c2ecf20Sopenharmony_ci
19788c2ecf20Sopenharmony_ci		if (!ofs->workdir)
19798c2ecf20Sopenharmony_ci			sb->s_flags |= SB_RDONLY;
19808c2ecf20Sopenharmony_ci
19818c2ecf20Sopenharmony_ci		sb->s_stack_depth = upper_sb->s_stack_depth;
19828c2ecf20Sopenharmony_ci		sb->s_time_gran = upper_sb->s_time_gran;
19838c2ecf20Sopenharmony_ci	}
19848c2ecf20Sopenharmony_ci	oe = ovl_get_lowerstack(sb, splitlower, numlower, ofs, layers);
19858c2ecf20Sopenharmony_ci	err = PTR_ERR(oe);
19868c2ecf20Sopenharmony_ci	if (IS_ERR(oe))
19878c2ecf20Sopenharmony_ci		goto out_err;
19888c2ecf20Sopenharmony_ci
19898c2ecf20Sopenharmony_ci	/* If the upper fs is nonexistent, we mark overlayfs r/o too */
19908c2ecf20Sopenharmony_ci	if (!ovl_upper_mnt(ofs))
19918c2ecf20Sopenharmony_ci		sb->s_flags |= SB_RDONLY;
19928c2ecf20Sopenharmony_ci
19938c2ecf20Sopenharmony_ci	if (!ovl_force_readonly(ofs) && ofs->config.index) {
19948c2ecf20Sopenharmony_ci		err = ovl_get_indexdir(sb, ofs, oe, &upperpath);
19958c2ecf20Sopenharmony_ci		if (err)
19968c2ecf20Sopenharmony_ci			goto out_free_oe;
19978c2ecf20Sopenharmony_ci
19988c2ecf20Sopenharmony_ci		/* Force r/o mount with no index dir */
19998c2ecf20Sopenharmony_ci		if (!ofs->indexdir)
20008c2ecf20Sopenharmony_ci			sb->s_flags |= SB_RDONLY;
20018c2ecf20Sopenharmony_ci	}
20028c2ecf20Sopenharmony_ci
20038c2ecf20Sopenharmony_ci	err = ovl_check_overlapping_layers(sb, ofs);
20048c2ecf20Sopenharmony_ci	if (err)
20058c2ecf20Sopenharmony_ci		goto out_free_oe;
20068c2ecf20Sopenharmony_ci
20078c2ecf20Sopenharmony_ci	/* Show index=off in /proc/mounts for forced r/o mount */
20088c2ecf20Sopenharmony_ci	if (!ofs->indexdir) {
20098c2ecf20Sopenharmony_ci		ofs->config.index = false;
20108c2ecf20Sopenharmony_ci		if (ovl_upper_mnt(ofs) && ofs->config.nfs_export) {
20118c2ecf20Sopenharmony_ci			pr_warn("NFS export requires an index dir, falling back to nfs_export=off.\n");
20128c2ecf20Sopenharmony_ci			ofs->config.nfs_export = false;
20138c2ecf20Sopenharmony_ci		}
20148c2ecf20Sopenharmony_ci	}
20158c2ecf20Sopenharmony_ci
20168c2ecf20Sopenharmony_ci	if (ofs->config.metacopy && ofs->config.nfs_export) {
20178c2ecf20Sopenharmony_ci		pr_warn("NFS export is not supported with metadata only copy up, falling back to nfs_export=off.\n");
20188c2ecf20Sopenharmony_ci		ofs->config.nfs_export = false;
20198c2ecf20Sopenharmony_ci	}
20208c2ecf20Sopenharmony_ci
20218c2ecf20Sopenharmony_ci	if (ofs->config.nfs_export)
20228c2ecf20Sopenharmony_ci		sb->s_export_op = &ovl_export_operations;
20238c2ecf20Sopenharmony_ci
20248c2ecf20Sopenharmony_ci	/* Never override disk quota limits or use reserved space */
20258c2ecf20Sopenharmony_ci	cap_lower(cred->cap_effective, CAP_SYS_RESOURCE);
20268c2ecf20Sopenharmony_ci
20278c2ecf20Sopenharmony_ci	sb->s_magic = OVERLAYFS_SUPER_MAGIC;
20288c2ecf20Sopenharmony_ci	sb->s_xattr = ovl_xattr_handlers;
20298c2ecf20Sopenharmony_ci	sb->s_fs_info = ofs;
20308c2ecf20Sopenharmony_ci	sb->s_flags |= SB_POSIXACL;
20318c2ecf20Sopenharmony_ci	sb->s_iflags |= SB_I_SKIP_SYNC;
20328c2ecf20Sopenharmony_ci
20338c2ecf20Sopenharmony_ci	err = -ENOMEM;
20348c2ecf20Sopenharmony_ci	root_dentry = ovl_get_root(sb, upperpath.dentry, oe);
20358c2ecf20Sopenharmony_ci	if (!root_dentry)
20368c2ecf20Sopenharmony_ci		goto out_free_oe;
20378c2ecf20Sopenharmony_ci
20388c2ecf20Sopenharmony_ci	mntput(upperpath.mnt);
20398c2ecf20Sopenharmony_ci	kfree(splitlower);
20408c2ecf20Sopenharmony_ci
20418c2ecf20Sopenharmony_ci	sb->s_root = root_dentry;
20428c2ecf20Sopenharmony_ci
20438c2ecf20Sopenharmony_ci	return 0;
20448c2ecf20Sopenharmony_ci
20458c2ecf20Sopenharmony_ciout_free_oe:
20468c2ecf20Sopenharmony_ci	ovl_entry_stack_free(oe);
20478c2ecf20Sopenharmony_ci	kfree(oe);
20488c2ecf20Sopenharmony_ciout_err:
20498c2ecf20Sopenharmony_ci	kfree(splitlower);
20508c2ecf20Sopenharmony_ci	path_put(&upperpath);
20518c2ecf20Sopenharmony_ci	ovl_free_fs(ofs);
20528c2ecf20Sopenharmony_ciout:
20538c2ecf20Sopenharmony_ci	return err;
20548c2ecf20Sopenharmony_ci}
20558c2ecf20Sopenharmony_ci
20568c2ecf20Sopenharmony_cistatic struct dentry *ovl_mount(struct file_system_type *fs_type, int flags,
20578c2ecf20Sopenharmony_ci				const char *dev_name, void *raw_data)
20588c2ecf20Sopenharmony_ci{
20598c2ecf20Sopenharmony_ci	return mount_nodev(fs_type, flags, raw_data, ovl_fill_super);
20608c2ecf20Sopenharmony_ci}
20618c2ecf20Sopenharmony_ci
20628c2ecf20Sopenharmony_cistatic struct file_system_type ovl_fs_type = {
20638c2ecf20Sopenharmony_ci	.owner		= THIS_MODULE,
20648c2ecf20Sopenharmony_ci	.name		= "overlay",
20658c2ecf20Sopenharmony_ci	.mount		= ovl_mount,
20668c2ecf20Sopenharmony_ci	.kill_sb	= kill_anon_super,
20678c2ecf20Sopenharmony_ci};
20688c2ecf20Sopenharmony_ciMODULE_ALIAS_FS("overlay");
20698c2ecf20Sopenharmony_ci
20708c2ecf20Sopenharmony_cistatic void ovl_inode_init_once(void *foo)
20718c2ecf20Sopenharmony_ci{
20728c2ecf20Sopenharmony_ci	struct ovl_inode *oi = foo;
20738c2ecf20Sopenharmony_ci
20748c2ecf20Sopenharmony_ci	inode_init_once(&oi->vfs_inode);
20758c2ecf20Sopenharmony_ci}
20768c2ecf20Sopenharmony_ci
20778c2ecf20Sopenharmony_cistatic int __init ovl_init(void)
20788c2ecf20Sopenharmony_ci{
20798c2ecf20Sopenharmony_ci	int err;
20808c2ecf20Sopenharmony_ci
20818c2ecf20Sopenharmony_ci	ovl_inode_cachep = kmem_cache_create("ovl_inode",
20828c2ecf20Sopenharmony_ci					     sizeof(struct ovl_inode), 0,
20838c2ecf20Sopenharmony_ci					     (SLAB_RECLAIM_ACCOUNT|
20848c2ecf20Sopenharmony_ci					      SLAB_MEM_SPREAD|SLAB_ACCOUNT),
20858c2ecf20Sopenharmony_ci					     ovl_inode_init_once);
20868c2ecf20Sopenharmony_ci	if (ovl_inode_cachep == NULL)
20878c2ecf20Sopenharmony_ci		return -ENOMEM;
20888c2ecf20Sopenharmony_ci
20898c2ecf20Sopenharmony_ci	err = ovl_aio_request_cache_init();
20908c2ecf20Sopenharmony_ci	if (!err) {
20918c2ecf20Sopenharmony_ci		err = register_filesystem(&ovl_fs_type);
20928c2ecf20Sopenharmony_ci		if (!err)
20938c2ecf20Sopenharmony_ci			return 0;
20948c2ecf20Sopenharmony_ci
20958c2ecf20Sopenharmony_ci		ovl_aio_request_cache_destroy();
20968c2ecf20Sopenharmony_ci	}
20978c2ecf20Sopenharmony_ci	kmem_cache_destroy(ovl_inode_cachep);
20988c2ecf20Sopenharmony_ci
20998c2ecf20Sopenharmony_ci	return err;
21008c2ecf20Sopenharmony_ci}
21018c2ecf20Sopenharmony_ci
21028c2ecf20Sopenharmony_cistatic void __exit ovl_exit(void)
21038c2ecf20Sopenharmony_ci{
21048c2ecf20Sopenharmony_ci	unregister_filesystem(&ovl_fs_type);
21058c2ecf20Sopenharmony_ci
21068c2ecf20Sopenharmony_ci	/*
21078c2ecf20Sopenharmony_ci	 * Make sure all delayed rcu free inodes are flushed before we
21088c2ecf20Sopenharmony_ci	 * destroy cache.
21098c2ecf20Sopenharmony_ci	 */
21108c2ecf20Sopenharmony_ci	rcu_barrier();
21118c2ecf20Sopenharmony_ci	kmem_cache_destroy(ovl_inode_cachep);
21128c2ecf20Sopenharmony_ci	ovl_aio_request_cache_destroy();
21138c2ecf20Sopenharmony_ci}
21148c2ecf20Sopenharmony_ci
21158c2ecf20Sopenharmony_cimodule_init(ovl_init);
21168c2ecf20Sopenharmony_cimodule_exit(ovl_exit);
2117