162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci#include <linux/export.h>
362306a36Sopenharmony_ci#include <linux/fs.h>
462306a36Sopenharmony_ci#include <linux/fs_stack.h>
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci/* does _NOT_ require i_mutex to be held.
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * This function cannot be inlined since i_size_{read,write} is rather
962306a36Sopenharmony_ci * heavy-weight on 32-bit systems
1062306a36Sopenharmony_ci */
1162306a36Sopenharmony_civoid fsstack_copy_inode_size(struct inode *dst, struct inode *src)
1262306a36Sopenharmony_ci{
1362306a36Sopenharmony_ci	loff_t i_size;
1462306a36Sopenharmony_ci	blkcnt_t i_blocks;
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci	/*
1762306a36Sopenharmony_ci	 * i_size_read() includes its own seqlocking and protection from
1862306a36Sopenharmony_ci	 * preemption (see include/linux/fs.h): we need nothing extra for
1962306a36Sopenharmony_ci	 * that here, and prefer to avoid nesting locks than attempt to keep
2062306a36Sopenharmony_ci	 * i_size and i_blocks in sync together.
2162306a36Sopenharmony_ci	 */
2262306a36Sopenharmony_ci	i_size = i_size_read(src);
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci	/*
2562306a36Sopenharmony_ci	 * But on 32-bit, we ought to make an effort to keep the two halves of
2662306a36Sopenharmony_ci	 * i_blocks in sync despite SMP or PREEMPTION - though stat's
2762306a36Sopenharmony_ci	 * generic_fillattr() doesn't bother, and we won't be applying quotas
2862306a36Sopenharmony_ci	 * (where i_blocks does become important) at the upper level.
2962306a36Sopenharmony_ci	 *
3062306a36Sopenharmony_ci	 * We don't actually know what locking is used at the lower level;
3162306a36Sopenharmony_ci	 * but if it's a filesystem that supports quotas, it will be using
3262306a36Sopenharmony_ci	 * i_lock as in inode_add_bytes().
3362306a36Sopenharmony_ci	 */
3462306a36Sopenharmony_ci	if (sizeof(i_blocks) > sizeof(long))
3562306a36Sopenharmony_ci		spin_lock(&src->i_lock);
3662306a36Sopenharmony_ci	i_blocks = src->i_blocks;
3762306a36Sopenharmony_ci	if (sizeof(i_blocks) > sizeof(long))
3862306a36Sopenharmony_ci		spin_unlock(&src->i_lock);
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci	/*
4162306a36Sopenharmony_ci	 * If CONFIG_SMP or CONFIG_PREEMPTION on 32-bit, it's vital for
4262306a36Sopenharmony_ci	 * fsstack_copy_inode_size() to hold some lock around
4362306a36Sopenharmony_ci	 * i_size_write(), otherwise i_size_read() may spin forever (see
4462306a36Sopenharmony_ci	 * include/linux/fs.h).  We don't necessarily hold i_mutex when this
4562306a36Sopenharmony_ci	 * is called, so take i_lock for that case.
4662306a36Sopenharmony_ci	 *
4762306a36Sopenharmony_ci	 * And if on 32-bit, continue our effort to keep the two halves of
4862306a36Sopenharmony_ci	 * i_blocks in sync despite SMP or PREEMPTION: use i_lock for that case
4962306a36Sopenharmony_ci	 * too, and do both at once by combining the tests.
5062306a36Sopenharmony_ci	 *
5162306a36Sopenharmony_ci	 * There is none of this locking overhead in the 64-bit case.
5262306a36Sopenharmony_ci	 */
5362306a36Sopenharmony_ci	if (sizeof(i_size) > sizeof(long) || sizeof(i_blocks) > sizeof(long))
5462306a36Sopenharmony_ci		spin_lock(&dst->i_lock);
5562306a36Sopenharmony_ci	i_size_write(dst, i_size);
5662306a36Sopenharmony_ci	dst->i_blocks = i_blocks;
5762306a36Sopenharmony_ci	if (sizeof(i_size) > sizeof(long) || sizeof(i_blocks) > sizeof(long))
5862306a36Sopenharmony_ci		spin_unlock(&dst->i_lock);
5962306a36Sopenharmony_ci}
6062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(fsstack_copy_inode_size);
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci/* copy all attributes */
6362306a36Sopenharmony_civoid fsstack_copy_attr_all(struct inode *dest, const struct inode *src)
6462306a36Sopenharmony_ci{
6562306a36Sopenharmony_ci	dest->i_mode = src->i_mode;
6662306a36Sopenharmony_ci	dest->i_uid = src->i_uid;
6762306a36Sopenharmony_ci	dest->i_gid = src->i_gid;
6862306a36Sopenharmony_ci	dest->i_rdev = src->i_rdev;
6962306a36Sopenharmony_ci	dest->i_atime = src->i_atime;
7062306a36Sopenharmony_ci	dest->i_mtime = src->i_mtime;
7162306a36Sopenharmony_ci	inode_set_ctime_to_ts(dest, inode_get_ctime(src));
7262306a36Sopenharmony_ci	dest->i_blkbits = src->i_blkbits;
7362306a36Sopenharmony_ci	dest->i_flags = src->i_flags;
7462306a36Sopenharmony_ci	set_nlink(dest, src->i_nlink);
7562306a36Sopenharmony_ci}
7662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(fsstack_copy_attr_all);
77