xref: /kernel/linux/linux-5.10/fs/ext4/ioctl.c (revision 8c2ecf20)
18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * linux/fs/ext4/ioctl.c
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 1993, 1994, 1995
68c2ecf20Sopenharmony_ci * Remy Card (card@masi.ibp.fr)
78c2ecf20Sopenharmony_ci * Laboratoire MASI - Institut Blaise Pascal
88c2ecf20Sopenharmony_ci * Universite Pierre et Marie Curie (Paris VI)
98c2ecf20Sopenharmony_ci */
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include <linux/fs.h>
128c2ecf20Sopenharmony_ci#include <linux/capability.h>
138c2ecf20Sopenharmony_ci#include <linux/time.h>
148c2ecf20Sopenharmony_ci#include <linux/compat.h>
158c2ecf20Sopenharmony_ci#include <linux/mount.h>
168c2ecf20Sopenharmony_ci#include <linux/file.h>
178c2ecf20Sopenharmony_ci#include <linux/quotaops.h>
188c2ecf20Sopenharmony_ci#include <linux/random.h>
198c2ecf20Sopenharmony_ci#include <linux/uuid.h>
208c2ecf20Sopenharmony_ci#include <linux/uaccess.h>
218c2ecf20Sopenharmony_ci#include <linux/delay.h>
228c2ecf20Sopenharmony_ci#include <linux/iversion.h>
238c2ecf20Sopenharmony_ci#include "ext4_jbd2.h"
248c2ecf20Sopenharmony_ci#include "ext4.h"
258c2ecf20Sopenharmony_ci#include <linux/fsmap.h>
268c2ecf20Sopenharmony_ci#include "fsmap.h"
278c2ecf20Sopenharmony_ci#include <trace/events/ext4.h>
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci/**
308c2ecf20Sopenharmony_ci * Swap memory between @a and @b for @len bytes.
318c2ecf20Sopenharmony_ci *
328c2ecf20Sopenharmony_ci * @a:          pointer to first memory area
338c2ecf20Sopenharmony_ci * @b:          pointer to second memory area
348c2ecf20Sopenharmony_ci * @len:        number of bytes to swap
358c2ecf20Sopenharmony_ci *
368c2ecf20Sopenharmony_ci */
378c2ecf20Sopenharmony_cistatic void memswap(void *a, void *b, size_t len)
388c2ecf20Sopenharmony_ci{
398c2ecf20Sopenharmony_ci	unsigned char *ap, *bp;
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci	ap = (unsigned char *)a;
428c2ecf20Sopenharmony_ci	bp = (unsigned char *)b;
438c2ecf20Sopenharmony_ci	while (len-- > 0) {
448c2ecf20Sopenharmony_ci		swap(*ap, *bp);
458c2ecf20Sopenharmony_ci		ap++;
468c2ecf20Sopenharmony_ci		bp++;
478c2ecf20Sopenharmony_ci	}
488c2ecf20Sopenharmony_ci}
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci/**
518c2ecf20Sopenharmony_ci * Swap i_data and associated attributes between @inode1 and @inode2.
528c2ecf20Sopenharmony_ci * This function is used for the primary swap between inode1 and inode2
538c2ecf20Sopenharmony_ci * and also to revert this primary swap in case of errors.
548c2ecf20Sopenharmony_ci *
558c2ecf20Sopenharmony_ci * Therefore you have to make sure, that calling this method twice
568c2ecf20Sopenharmony_ci * will revert all changes.
578c2ecf20Sopenharmony_ci *
588c2ecf20Sopenharmony_ci * @inode1:     pointer to first inode
598c2ecf20Sopenharmony_ci * @inode2:     pointer to second inode
608c2ecf20Sopenharmony_ci */
618c2ecf20Sopenharmony_cistatic void swap_inode_data(struct inode *inode1, struct inode *inode2)
628c2ecf20Sopenharmony_ci{
638c2ecf20Sopenharmony_ci	loff_t isize;
648c2ecf20Sopenharmony_ci	struct ext4_inode_info *ei1;
658c2ecf20Sopenharmony_ci	struct ext4_inode_info *ei2;
668c2ecf20Sopenharmony_ci	unsigned long tmp;
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci	ei1 = EXT4_I(inode1);
698c2ecf20Sopenharmony_ci	ei2 = EXT4_I(inode2);
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci	swap(inode1->i_version, inode2->i_version);
728c2ecf20Sopenharmony_ci	swap(inode1->i_atime, inode2->i_atime);
738c2ecf20Sopenharmony_ci	swap(inode1->i_mtime, inode2->i_mtime);
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci	memswap(ei1->i_data, ei2->i_data, sizeof(ei1->i_data));
768c2ecf20Sopenharmony_ci	tmp = ei1->i_flags & EXT4_FL_SHOULD_SWAP;
778c2ecf20Sopenharmony_ci	ei1->i_flags = (ei2->i_flags & EXT4_FL_SHOULD_SWAP) |
788c2ecf20Sopenharmony_ci		(ei1->i_flags & ~EXT4_FL_SHOULD_SWAP);
798c2ecf20Sopenharmony_ci	ei2->i_flags = tmp | (ei2->i_flags & ~EXT4_FL_SHOULD_SWAP);
808c2ecf20Sopenharmony_ci	swap(ei1->i_disksize, ei2->i_disksize);
818c2ecf20Sopenharmony_ci	ext4_es_remove_extent(inode1, 0, EXT_MAX_BLOCKS);
828c2ecf20Sopenharmony_ci	ext4_es_remove_extent(inode2, 0, EXT_MAX_BLOCKS);
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci	isize = i_size_read(inode1);
858c2ecf20Sopenharmony_ci	i_size_write(inode1, i_size_read(inode2));
868c2ecf20Sopenharmony_ci	i_size_write(inode2, isize);
878c2ecf20Sopenharmony_ci}
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_civoid ext4_reset_inode_seed(struct inode *inode)
908c2ecf20Sopenharmony_ci{
918c2ecf20Sopenharmony_ci	struct ext4_inode_info *ei = EXT4_I(inode);
928c2ecf20Sopenharmony_ci	struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
938c2ecf20Sopenharmony_ci	__le32 inum = cpu_to_le32(inode->i_ino);
948c2ecf20Sopenharmony_ci	__le32 gen = cpu_to_le32(inode->i_generation);
958c2ecf20Sopenharmony_ci	__u32 csum;
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci	if (!ext4_has_metadata_csum(inode->i_sb))
988c2ecf20Sopenharmony_ci		return;
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci	csum = ext4_chksum(sbi, sbi->s_csum_seed, (__u8 *)&inum, sizeof(inum));
1018c2ecf20Sopenharmony_ci	ei->i_csum_seed = ext4_chksum(sbi, csum, (__u8 *)&gen, sizeof(gen));
1028c2ecf20Sopenharmony_ci}
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci/**
1058c2ecf20Sopenharmony_ci * Swap the information from the given @inode and the inode
1068c2ecf20Sopenharmony_ci * EXT4_BOOT_LOADER_INO. It will basically swap i_data and all other
1078c2ecf20Sopenharmony_ci * important fields of the inodes.
1088c2ecf20Sopenharmony_ci *
1098c2ecf20Sopenharmony_ci * @sb:         the super block of the filesystem
1108c2ecf20Sopenharmony_ci * @inode:      the inode to swap with EXT4_BOOT_LOADER_INO
1118c2ecf20Sopenharmony_ci *
1128c2ecf20Sopenharmony_ci */
1138c2ecf20Sopenharmony_cistatic long swap_inode_boot_loader(struct super_block *sb,
1148c2ecf20Sopenharmony_ci				struct inode *inode)
1158c2ecf20Sopenharmony_ci{
1168c2ecf20Sopenharmony_ci	handle_t *handle;
1178c2ecf20Sopenharmony_ci	int err;
1188c2ecf20Sopenharmony_ci	struct inode *inode_bl;
1198c2ecf20Sopenharmony_ci	struct ext4_inode_info *ei_bl;
1208c2ecf20Sopenharmony_ci	qsize_t size, size_bl, diff;
1218c2ecf20Sopenharmony_ci	blkcnt_t blocks;
1228c2ecf20Sopenharmony_ci	unsigned short bytes;
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci	inode_bl = ext4_iget(sb, EXT4_BOOT_LOADER_INO,
1258c2ecf20Sopenharmony_ci			EXT4_IGET_SPECIAL | EXT4_IGET_BAD);
1268c2ecf20Sopenharmony_ci	if (IS_ERR(inode_bl))
1278c2ecf20Sopenharmony_ci		return PTR_ERR(inode_bl);
1288c2ecf20Sopenharmony_ci	ei_bl = EXT4_I(inode_bl);
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	/* Protect orig inodes against a truncate and make sure,
1318c2ecf20Sopenharmony_ci	 * that only 1 swap_inode_boot_loader is running. */
1328c2ecf20Sopenharmony_ci	lock_two_nondirectories(inode, inode_bl);
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci	if (inode->i_nlink != 1 || !S_ISREG(inode->i_mode) ||
1358c2ecf20Sopenharmony_ci	    IS_SWAPFILE(inode) || IS_ENCRYPTED(inode) ||
1368c2ecf20Sopenharmony_ci	    (EXT4_I(inode)->i_flags & EXT4_JOURNAL_DATA_FL) ||
1378c2ecf20Sopenharmony_ci	    ext4_has_inline_data(inode)) {
1388c2ecf20Sopenharmony_ci		err = -EINVAL;
1398c2ecf20Sopenharmony_ci		goto journal_err_out;
1408c2ecf20Sopenharmony_ci	}
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci	if (IS_RDONLY(inode) || IS_APPEND(inode) || IS_IMMUTABLE(inode) ||
1438c2ecf20Sopenharmony_ci	    !inode_owner_or_capable(inode) || !capable(CAP_SYS_ADMIN)) {
1448c2ecf20Sopenharmony_ci		err = -EPERM;
1458c2ecf20Sopenharmony_ci		goto journal_err_out;
1468c2ecf20Sopenharmony_ci	}
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci	down_write(&EXT4_I(inode)->i_mmap_sem);
1498c2ecf20Sopenharmony_ci	err = filemap_write_and_wait(inode->i_mapping);
1508c2ecf20Sopenharmony_ci	if (err)
1518c2ecf20Sopenharmony_ci		goto err_out;
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci	err = filemap_write_and_wait(inode_bl->i_mapping);
1548c2ecf20Sopenharmony_ci	if (err)
1558c2ecf20Sopenharmony_ci		goto err_out;
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci	/* Wait for all existing dio workers */
1588c2ecf20Sopenharmony_ci	inode_dio_wait(inode);
1598c2ecf20Sopenharmony_ci	inode_dio_wait(inode_bl);
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci	truncate_inode_pages(&inode->i_data, 0);
1628c2ecf20Sopenharmony_ci	truncate_inode_pages(&inode_bl->i_data, 0);
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci	handle = ext4_journal_start(inode_bl, EXT4_HT_MOVE_EXTENTS, 2);
1658c2ecf20Sopenharmony_ci	if (IS_ERR(handle)) {
1668c2ecf20Sopenharmony_ci		err = -EINVAL;
1678c2ecf20Sopenharmony_ci		goto err_out;
1688c2ecf20Sopenharmony_ci	}
1698c2ecf20Sopenharmony_ci	ext4_fc_start_ineligible(sb, EXT4_FC_REASON_SWAP_BOOT);
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci	/* Protect extent tree against block allocations via delalloc */
1728c2ecf20Sopenharmony_ci	ext4_double_down_write_data_sem(inode, inode_bl);
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci	if (is_bad_inode(inode_bl) || !S_ISREG(inode_bl->i_mode)) {
1758c2ecf20Sopenharmony_ci		/* this inode has never been used as a BOOT_LOADER */
1768c2ecf20Sopenharmony_ci		set_nlink(inode_bl, 1);
1778c2ecf20Sopenharmony_ci		i_uid_write(inode_bl, 0);
1788c2ecf20Sopenharmony_ci		i_gid_write(inode_bl, 0);
1798c2ecf20Sopenharmony_ci		inode_bl->i_flags = 0;
1808c2ecf20Sopenharmony_ci		ei_bl->i_flags = 0;
1818c2ecf20Sopenharmony_ci		inode_set_iversion(inode_bl, 1);
1828c2ecf20Sopenharmony_ci		i_size_write(inode_bl, 0);
1838c2ecf20Sopenharmony_ci		EXT4_I(inode_bl)->i_disksize = inode_bl->i_size;
1848c2ecf20Sopenharmony_ci		inode_bl->i_mode = S_IFREG;
1858c2ecf20Sopenharmony_ci		if (ext4_has_feature_extents(sb)) {
1868c2ecf20Sopenharmony_ci			ext4_set_inode_flag(inode_bl, EXT4_INODE_EXTENTS);
1878c2ecf20Sopenharmony_ci			ext4_ext_tree_init(handle, inode_bl);
1888c2ecf20Sopenharmony_ci		} else
1898c2ecf20Sopenharmony_ci			memset(ei_bl->i_data, 0, sizeof(ei_bl->i_data));
1908c2ecf20Sopenharmony_ci	}
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci	err = dquot_initialize(inode);
1938c2ecf20Sopenharmony_ci	if (err)
1948c2ecf20Sopenharmony_ci		goto err_out1;
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci	size = (qsize_t)(inode->i_blocks) * (1 << 9) + inode->i_bytes;
1978c2ecf20Sopenharmony_ci	size_bl = (qsize_t)(inode_bl->i_blocks) * (1 << 9) + inode_bl->i_bytes;
1988c2ecf20Sopenharmony_ci	diff = size - size_bl;
1998c2ecf20Sopenharmony_ci	swap_inode_data(inode, inode_bl);
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci	inode->i_ctime = inode_bl->i_ctime = current_time(inode);
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	inode->i_generation = prandom_u32();
2048c2ecf20Sopenharmony_ci	inode_bl->i_generation = prandom_u32();
2058c2ecf20Sopenharmony_ci	ext4_reset_inode_seed(inode);
2068c2ecf20Sopenharmony_ci	ext4_reset_inode_seed(inode_bl);
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci	ext4_discard_preallocations(inode, 0);
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci	err = ext4_mark_inode_dirty(handle, inode);
2118c2ecf20Sopenharmony_ci	if (err < 0) {
2128c2ecf20Sopenharmony_ci		/* No need to update quota information. */
2138c2ecf20Sopenharmony_ci		ext4_warning(inode->i_sb,
2148c2ecf20Sopenharmony_ci			"couldn't mark inode #%lu dirty (err %d)",
2158c2ecf20Sopenharmony_ci			inode->i_ino, err);
2168c2ecf20Sopenharmony_ci		/* Revert all changes: */
2178c2ecf20Sopenharmony_ci		swap_inode_data(inode, inode_bl);
2188c2ecf20Sopenharmony_ci		ext4_mark_inode_dirty(handle, inode);
2198c2ecf20Sopenharmony_ci		goto err_out1;
2208c2ecf20Sopenharmony_ci	}
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci	blocks = inode_bl->i_blocks;
2238c2ecf20Sopenharmony_ci	bytes = inode_bl->i_bytes;
2248c2ecf20Sopenharmony_ci	inode_bl->i_blocks = inode->i_blocks;
2258c2ecf20Sopenharmony_ci	inode_bl->i_bytes = inode->i_bytes;
2268c2ecf20Sopenharmony_ci	err = ext4_mark_inode_dirty(handle, inode_bl);
2278c2ecf20Sopenharmony_ci	if (err < 0) {
2288c2ecf20Sopenharmony_ci		/* No need to update quota information. */
2298c2ecf20Sopenharmony_ci		ext4_warning(inode_bl->i_sb,
2308c2ecf20Sopenharmony_ci			"couldn't mark inode #%lu dirty (err %d)",
2318c2ecf20Sopenharmony_ci			inode_bl->i_ino, err);
2328c2ecf20Sopenharmony_ci		goto revert;
2338c2ecf20Sopenharmony_ci	}
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci	/* Bootloader inode should not be counted into quota information. */
2368c2ecf20Sopenharmony_ci	if (diff > 0)
2378c2ecf20Sopenharmony_ci		dquot_free_space(inode, diff);
2388c2ecf20Sopenharmony_ci	else
2398c2ecf20Sopenharmony_ci		err = dquot_alloc_space(inode, -1 * diff);
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci	if (err < 0) {
2428c2ecf20Sopenharmony_cirevert:
2438c2ecf20Sopenharmony_ci		/* Revert all changes: */
2448c2ecf20Sopenharmony_ci		inode_bl->i_blocks = blocks;
2458c2ecf20Sopenharmony_ci		inode_bl->i_bytes = bytes;
2468c2ecf20Sopenharmony_ci		swap_inode_data(inode, inode_bl);
2478c2ecf20Sopenharmony_ci		ext4_mark_inode_dirty(handle, inode);
2488c2ecf20Sopenharmony_ci		ext4_mark_inode_dirty(handle, inode_bl);
2498c2ecf20Sopenharmony_ci	}
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_cierr_out1:
2528c2ecf20Sopenharmony_ci	ext4_journal_stop(handle);
2538c2ecf20Sopenharmony_ci	ext4_fc_stop_ineligible(sb);
2548c2ecf20Sopenharmony_ci	ext4_double_up_write_data_sem(inode, inode_bl);
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_cierr_out:
2578c2ecf20Sopenharmony_ci	up_write(&EXT4_I(inode)->i_mmap_sem);
2588c2ecf20Sopenharmony_cijournal_err_out:
2598c2ecf20Sopenharmony_ci	unlock_two_nondirectories(inode, inode_bl);
2608c2ecf20Sopenharmony_ci	iput(inode_bl);
2618c2ecf20Sopenharmony_ci	return err;
2628c2ecf20Sopenharmony_ci}
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci#ifdef CONFIG_FS_ENCRYPTION
2658c2ecf20Sopenharmony_cistatic int uuid_is_zero(__u8 u[16])
2668c2ecf20Sopenharmony_ci{
2678c2ecf20Sopenharmony_ci	int	i;
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci	for (i = 0; i < 16; i++)
2708c2ecf20Sopenharmony_ci		if (u[i])
2718c2ecf20Sopenharmony_ci			return 0;
2728c2ecf20Sopenharmony_ci	return 1;
2738c2ecf20Sopenharmony_ci}
2748c2ecf20Sopenharmony_ci#endif
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ci/*
2778c2ecf20Sopenharmony_ci * If immutable is set and we are not clearing it, we're not allowed to change
2788c2ecf20Sopenharmony_ci * anything else in the inode.  Don't error out if we're only trying to set
2798c2ecf20Sopenharmony_ci * immutable on an immutable file.
2808c2ecf20Sopenharmony_ci */
2818c2ecf20Sopenharmony_cistatic int ext4_ioctl_check_immutable(struct inode *inode, __u32 new_projid,
2828c2ecf20Sopenharmony_ci				      unsigned int flags)
2838c2ecf20Sopenharmony_ci{
2848c2ecf20Sopenharmony_ci	struct ext4_inode_info *ei = EXT4_I(inode);
2858c2ecf20Sopenharmony_ci	unsigned int oldflags = ei->i_flags;
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ci	if (!(oldflags & EXT4_IMMUTABLE_FL) || !(flags & EXT4_IMMUTABLE_FL))
2888c2ecf20Sopenharmony_ci		return 0;
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci	if ((oldflags & ~EXT4_IMMUTABLE_FL) != (flags & ~EXT4_IMMUTABLE_FL))
2918c2ecf20Sopenharmony_ci		return -EPERM;
2928c2ecf20Sopenharmony_ci	if (ext4_has_feature_project(inode->i_sb) &&
2938c2ecf20Sopenharmony_ci	    __kprojid_val(ei->i_projid) != new_projid)
2948c2ecf20Sopenharmony_ci		return -EPERM;
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	return 0;
2978c2ecf20Sopenharmony_ci}
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_cistatic void ext4_dax_dontcache(struct inode *inode, unsigned int flags)
3008c2ecf20Sopenharmony_ci{
3018c2ecf20Sopenharmony_ci	struct ext4_inode_info *ei = EXT4_I(inode);
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci	if (S_ISDIR(inode->i_mode))
3048c2ecf20Sopenharmony_ci		return;
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci	if (test_opt2(inode->i_sb, DAX_NEVER) ||
3078c2ecf20Sopenharmony_ci	    test_opt(inode->i_sb, DAX_ALWAYS))
3088c2ecf20Sopenharmony_ci		return;
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci	if ((ei->i_flags ^ flags) & EXT4_DAX_FL)
3118c2ecf20Sopenharmony_ci		d_mark_dontcache(inode);
3128c2ecf20Sopenharmony_ci}
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_cistatic bool dax_compatible(struct inode *inode, unsigned int oldflags,
3158c2ecf20Sopenharmony_ci			   unsigned int flags)
3168c2ecf20Sopenharmony_ci{
3178c2ecf20Sopenharmony_ci	/* Allow the DAX flag to be changed on inline directories */
3188c2ecf20Sopenharmony_ci	if (S_ISDIR(inode->i_mode)) {
3198c2ecf20Sopenharmony_ci		flags &= ~EXT4_INLINE_DATA_FL;
3208c2ecf20Sopenharmony_ci		oldflags &= ~EXT4_INLINE_DATA_FL;
3218c2ecf20Sopenharmony_ci	}
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_ci	if (flags & EXT4_DAX_FL) {
3248c2ecf20Sopenharmony_ci		if ((oldflags & EXT4_DAX_MUT_EXCL) ||
3258c2ecf20Sopenharmony_ci		     ext4_test_inode_state(inode,
3268c2ecf20Sopenharmony_ci					  EXT4_STATE_VERITY_IN_PROGRESS)) {
3278c2ecf20Sopenharmony_ci			return false;
3288c2ecf20Sopenharmony_ci		}
3298c2ecf20Sopenharmony_ci	}
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci	if ((flags & EXT4_DAX_MUT_EXCL) && (oldflags & EXT4_DAX_FL))
3328c2ecf20Sopenharmony_ci			return false;
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	return true;
3358c2ecf20Sopenharmony_ci}
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_cistatic int ext4_ioctl_setflags(struct inode *inode,
3388c2ecf20Sopenharmony_ci			       unsigned int flags)
3398c2ecf20Sopenharmony_ci{
3408c2ecf20Sopenharmony_ci	struct ext4_inode_info *ei = EXT4_I(inode);
3418c2ecf20Sopenharmony_ci	handle_t *handle = NULL;
3428c2ecf20Sopenharmony_ci	int err = -EPERM, migrate = 0;
3438c2ecf20Sopenharmony_ci	struct ext4_iloc iloc;
3448c2ecf20Sopenharmony_ci	unsigned int oldflags, mask, i;
3458c2ecf20Sopenharmony_ci	struct super_block *sb = inode->i_sb;
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ci	/* Is it quota file? Do not allow user to mess with it */
3488c2ecf20Sopenharmony_ci	if (ext4_is_quota_file(inode))
3498c2ecf20Sopenharmony_ci		goto flags_out;
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci	oldflags = ei->i_flags;
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ci	err = vfs_ioc_setflags_prepare(inode, oldflags, flags);
3548c2ecf20Sopenharmony_ci	if (err)
3558c2ecf20Sopenharmony_ci		goto flags_out;
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci	/*
3588c2ecf20Sopenharmony_ci	 * The JOURNAL_DATA flag can only be changed by
3598c2ecf20Sopenharmony_ci	 * the relevant capability.
3608c2ecf20Sopenharmony_ci	 */
3618c2ecf20Sopenharmony_ci	if ((flags ^ oldflags) & (EXT4_JOURNAL_DATA_FL)) {
3628c2ecf20Sopenharmony_ci		if (!capable(CAP_SYS_RESOURCE))
3638c2ecf20Sopenharmony_ci			goto flags_out;
3648c2ecf20Sopenharmony_ci	}
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci	if (!dax_compatible(inode, oldflags, flags)) {
3678c2ecf20Sopenharmony_ci		err = -EOPNOTSUPP;
3688c2ecf20Sopenharmony_ci		goto flags_out;
3698c2ecf20Sopenharmony_ci	}
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_ci	if ((flags ^ oldflags) & EXT4_EXTENTS_FL)
3728c2ecf20Sopenharmony_ci		migrate = 1;
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci	if ((flags ^ oldflags) & EXT4_CASEFOLD_FL) {
3758c2ecf20Sopenharmony_ci		if (!ext4_has_feature_casefold(sb)) {
3768c2ecf20Sopenharmony_ci			err = -EOPNOTSUPP;
3778c2ecf20Sopenharmony_ci			goto flags_out;
3788c2ecf20Sopenharmony_ci		}
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci		if (!S_ISDIR(inode->i_mode)) {
3818c2ecf20Sopenharmony_ci			err = -ENOTDIR;
3828c2ecf20Sopenharmony_ci			goto flags_out;
3838c2ecf20Sopenharmony_ci		}
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_ci		if (!ext4_empty_dir(inode)) {
3868c2ecf20Sopenharmony_ci			err = -ENOTEMPTY;
3878c2ecf20Sopenharmony_ci			goto flags_out;
3888c2ecf20Sopenharmony_ci		}
3898c2ecf20Sopenharmony_ci	}
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci	/*
3928c2ecf20Sopenharmony_ci	 * Wait for all pending directio and then flush all the dirty pages
3938c2ecf20Sopenharmony_ci	 * for this file.  The flush marks all the pages readonly, so any
3948c2ecf20Sopenharmony_ci	 * subsequent attempt to write to the file (particularly mmap pages)
3958c2ecf20Sopenharmony_ci	 * will come through the filesystem and fail.
3968c2ecf20Sopenharmony_ci	 */
3978c2ecf20Sopenharmony_ci	if (S_ISREG(inode->i_mode) && !IS_IMMUTABLE(inode) &&
3988c2ecf20Sopenharmony_ci	    (flags & EXT4_IMMUTABLE_FL)) {
3998c2ecf20Sopenharmony_ci		inode_dio_wait(inode);
4008c2ecf20Sopenharmony_ci		err = filemap_write_and_wait(inode->i_mapping);
4018c2ecf20Sopenharmony_ci		if (err)
4028c2ecf20Sopenharmony_ci			goto flags_out;
4038c2ecf20Sopenharmony_ci	}
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci	handle = ext4_journal_start(inode, EXT4_HT_INODE, 1);
4068c2ecf20Sopenharmony_ci	if (IS_ERR(handle)) {
4078c2ecf20Sopenharmony_ci		err = PTR_ERR(handle);
4088c2ecf20Sopenharmony_ci		goto flags_out;
4098c2ecf20Sopenharmony_ci	}
4108c2ecf20Sopenharmony_ci	if (IS_SYNC(inode))
4118c2ecf20Sopenharmony_ci		ext4_handle_sync(handle);
4128c2ecf20Sopenharmony_ci	err = ext4_reserve_inode_write(handle, inode, &iloc);
4138c2ecf20Sopenharmony_ci	if (err)
4148c2ecf20Sopenharmony_ci		goto flags_err;
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_ci	ext4_dax_dontcache(inode, flags);
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci	for (i = 0, mask = 1; i < 32; i++, mask <<= 1) {
4198c2ecf20Sopenharmony_ci		if (!(mask & EXT4_FL_USER_MODIFIABLE))
4208c2ecf20Sopenharmony_ci			continue;
4218c2ecf20Sopenharmony_ci		/* These flags get special treatment later */
4228c2ecf20Sopenharmony_ci		if (mask == EXT4_JOURNAL_DATA_FL || mask == EXT4_EXTENTS_FL)
4238c2ecf20Sopenharmony_ci			continue;
4248c2ecf20Sopenharmony_ci		if (mask & flags)
4258c2ecf20Sopenharmony_ci			ext4_set_inode_flag(inode, i);
4268c2ecf20Sopenharmony_ci		else
4278c2ecf20Sopenharmony_ci			ext4_clear_inode_flag(inode, i);
4288c2ecf20Sopenharmony_ci	}
4298c2ecf20Sopenharmony_ci
4308c2ecf20Sopenharmony_ci	ext4_set_inode_flags(inode, false);
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_ci	inode->i_ctime = current_time(inode);
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci	err = ext4_mark_iloc_dirty(handle, inode, &iloc);
4358c2ecf20Sopenharmony_ciflags_err:
4368c2ecf20Sopenharmony_ci	ext4_journal_stop(handle);
4378c2ecf20Sopenharmony_ci	if (err)
4388c2ecf20Sopenharmony_ci		goto flags_out;
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_ci	if ((flags ^ oldflags) & (EXT4_JOURNAL_DATA_FL)) {
4418c2ecf20Sopenharmony_ci		/*
4428c2ecf20Sopenharmony_ci		 * Changes to the journaling mode can cause unsafe changes to
4438c2ecf20Sopenharmony_ci		 * S_DAX if the inode is DAX
4448c2ecf20Sopenharmony_ci		 */
4458c2ecf20Sopenharmony_ci		if (IS_DAX(inode)) {
4468c2ecf20Sopenharmony_ci			err = -EBUSY;
4478c2ecf20Sopenharmony_ci			goto flags_out;
4488c2ecf20Sopenharmony_ci		}
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_ci		err = ext4_change_inode_journal_flag(inode,
4518c2ecf20Sopenharmony_ci						     flags & EXT4_JOURNAL_DATA_FL);
4528c2ecf20Sopenharmony_ci		if (err)
4538c2ecf20Sopenharmony_ci			goto flags_out;
4548c2ecf20Sopenharmony_ci	}
4558c2ecf20Sopenharmony_ci	if (migrate) {
4568c2ecf20Sopenharmony_ci		if (flags & EXT4_EXTENTS_FL)
4578c2ecf20Sopenharmony_ci			err = ext4_ext_migrate(inode);
4588c2ecf20Sopenharmony_ci		else
4598c2ecf20Sopenharmony_ci			err = ext4_ind_migrate(inode);
4608c2ecf20Sopenharmony_ci	}
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_ciflags_out:
4638c2ecf20Sopenharmony_ci	return err;
4648c2ecf20Sopenharmony_ci}
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci#ifdef CONFIG_QUOTA
4678c2ecf20Sopenharmony_cistatic int ext4_ioctl_setproject(struct file *filp, __u32 projid)
4688c2ecf20Sopenharmony_ci{
4698c2ecf20Sopenharmony_ci	struct inode *inode = file_inode(filp);
4708c2ecf20Sopenharmony_ci	struct super_block *sb = inode->i_sb;
4718c2ecf20Sopenharmony_ci	struct ext4_inode_info *ei = EXT4_I(inode);
4728c2ecf20Sopenharmony_ci	int err, rc;
4738c2ecf20Sopenharmony_ci	handle_t *handle;
4748c2ecf20Sopenharmony_ci	kprojid_t kprojid;
4758c2ecf20Sopenharmony_ci	struct ext4_iloc iloc;
4768c2ecf20Sopenharmony_ci	struct ext4_inode *raw_inode;
4778c2ecf20Sopenharmony_ci	struct dquot *transfer_to[MAXQUOTAS] = { };
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_ci	if (!ext4_has_feature_project(sb)) {
4808c2ecf20Sopenharmony_ci		if (projid != EXT4_DEF_PROJID)
4818c2ecf20Sopenharmony_ci			return -EOPNOTSUPP;
4828c2ecf20Sopenharmony_ci		else
4838c2ecf20Sopenharmony_ci			return 0;
4848c2ecf20Sopenharmony_ci	}
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ci	if (EXT4_INODE_SIZE(sb) <= EXT4_GOOD_OLD_INODE_SIZE)
4878c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_ci	kprojid = make_kprojid(&init_user_ns, (projid_t)projid);
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_ci	if (projid_eq(kprojid, EXT4_I(inode)->i_projid))
4928c2ecf20Sopenharmony_ci		return 0;
4938c2ecf20Sopenharmony_ci
4948c2ecf20Sopenharmony_ci	err = -EPERM;
4958c2ecf20Sopenharmony_ci	/* Is it quota file? Do not allow user to mess with it */
4968c2ecf20Sopenharmony_ci	if (ext4_is_quota_file(inode))
4978c2ecf20Sopenharmony_ci		return err;
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_ci	err = dquot_initialize(inode);
5008c2ecf20Sopenharmony_ci	if (err)
5018c2ecf20Sopenharmony_ci		return err;
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_ci	err = ext4_get_inode_loc(inode, &iloc);
5048c2ecf20Sopenharmony_ci	if (err)
5058c2ecf20Sopenharmony_ci		return err;
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_ci	raw_inode = ext4_raw_inode(&iloc);
5088c2ecf20Sopenharmony_ci	if (!EXT4_FITS_IN_INODE(raw_inode, ei, i_projid)) {
5098c2ecf20Sopenharmony_ci		err = ext4_expand_extra_isize(inode,
5108c2ecf20Sopenharmony_ci					      EXT4_SB(sb)->s_want_extra_isize,
5118c2ecf20Sopenharmony_ci					      &iloc);
5128c2ecf20Sopenharmony_ci		if (err)
5138c2ecf20Sopenharmony_ci			return err;
5148c2ecf20Sopenharmony_ci	} else {
5158c2ecf20Sopenharmony_ci		brelse(iloc.bh);
5168c2ecf20Sopenharmony_ci	}
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_ci	handle = ext4_journal_start(inode, EXT4_HT_QUOTA,
5198c2ecf20Sopenharmony_ci		EXT4_QUOTA_INIT_BLOCKS(sb) +
5208c2ecf20Sopenharmony_ci		EXT4_QUOTA_DEL_BLOCKS(sb) + 3);
5218c2ecf20Sopenharmony_ci	if (IS_ERR(handle))
5228c2ecf20Sopenharmony_ci		return PTR_ERR(handle);
5238c2ecf20Sopenharmony_ci
5248c2ecf20Sopenharmony_ci	err = ext4_reserve_inode_write(handle, inode, &iloc);
5258c2ecf20Sopenharmony_ci	if (err)
5268c2ecf20Sopenharmony_ci		goto out_stop;
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_ci	transfer_to[PRJQUOTA] = dqget(sb, make_kqid_projid(kprojid));
5298c2ecf20Sopenharmony_ci	if (!IS_ERR(transfer_to[PRJQUOTA])) {
5308c2ecf20Sopenharmony_ci
5318c2ecf20Sopenharmony_ci		/* __dquot_transfer() calls back ext4_get_inode_usage() which
5328c2ecf20Sopenharmony_ci		 * counts xattr inode references.
5338c2ecf20Sopenharmony_ci		 */
5348c2ecf20Sopenharmony_ci		down_read(&EXT4_I(inode)->xattr_sem);
5358c2ecf20Sopenharmony_ci		err = __dquot_transfer(inode, transfer_to);
5368c2ecf20Sopenharmony_ci		up_read(&EXT4_I(inode)->xattr_sem);
5378c2ecf20Sopenharmony_ci		dqput(transfer_to[PRJQUOTA]);
5388c2ecf20Sopenharmony_ci		if (err)
5398c2ecf20Sopenharmony_ci			goto out_dirty;
5408c2ecf20Sopenharmony_ci	}
5418c2ecf20Sopenharmony_ci
5428c2ecf20Sopenharmony_ci	EXT4_I(inode)->i_projid = kprojid;
5438c2ecf20Sopenharmony_ci	inode->i_ctime = current_time(inode);
5448c2ecf20Sopenharmony_ciout_dirty:
5458c2ecf20Sopenharmony_ci	rc = ext4_mark_iloc_dirty(handle, inode, &iloc);
5468c2ecf20Sopenharmony_ci	if (!err)
5478c2ecf20Sopenharmony_ci		err = rc;
5488c2ecf20Sopenharmony_ciout_stop:
5498c2ecf20Sopenharmony_ci	ext4_journal_stop(handle);
5508c2ecf20Sopenharmony_ci	return err;
5518c2ecf20Sopenharmony_ci}
5528c2ecf20Sopenharmony_ci#else
5538c2ecf20Sopenharmony_cistatic int ext4_ioctl_setproject(struct file *filp, __u32 projid)
5548c2ecf20Sopenharmony_ci{
5558c2ecf20Sopenharmony_ci	if (projid != EXT4_DEF_PROJID)
5568c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
5578c2ecf20Sopenharmony_ci	return 0;
5588c2ecf20Sopenharmony_ci}
5598c2ecf20Sopenharmony_ci#endif
5608c2ecf20Sopenharmony_ci
5618c2ecf20Sopenharmony_ci/* Transfer internal flags to xflags */
5628c2ecf20Sopenharmony_cistatic inline __u32 ext4_iflags_to_xflags(unsigned long iflags)
5638c2ecf20Sopenharmony_ci{
5648c2ecf20Sopenharmony_ci	__u32 xflags = 0;
5658c2ecf20Sopenharmony_ci
5668c2ecf20Sopenharmony_ci	if (iflags & EXT4_SYNC_FL)
5678c2ecf20Sopenharmony_ci		xflags |= FS_XFLAG_SYNC;
5688c2ecf20Sopenharmony_ci	if (iflags & EXT4_IMMUTABLE_FL)
5698c2ecf20Sopenharmony_ci		xflags |= FS_XFLAG_IMMUTABLE;
5708c2ecf20Sopenharmony_ci	if (iflags & EXT4_APPEND_FL)
5718c2ecf20Sopenharmony_ci		xflags |= FS_XFLAG_APPEND;
5728c2ecf20Sopenharmony_ci	if (iflags & EXT4_NODUMP_FL)
5738c2ecf20Sopenharmony_ci		xflags |= FS_XFLAG_NODUMP;
5748c2ecf20Sopenharmony_ci	if (iflags & EXT4_NOATIME_FL)
5758c2ecf20Sopenharmony_ci		xflags |= FS_XFLAG_NOATIME;
5768c2ecf20Sopenharmony_ci	if (iflags & EXT4_PROJINHERIT_FL)
5778c2ecf20Sopenharmony_ci		xflags |= FS_XFLAG_PROJINHERIT;
5788c2ecf20Sopenharmony_ci	if (iflags & EXT4_DAX_FL)
5798c2ecf20Sopenharmony_ci		xflags |= FS_XFLAG_DAX;
5808c2ecf20Sopenharmony_ci	return xflags;
5818c2ecf20Sopenharmony_ci}
5828c2ecf20Sopenharmony_ci
5838c2ecf20Sopenharmony_ci#define EXT4_SUPPORTED_FS_XFLAGS (FS_XFLAG_SYNC | FS_XFLAG_IMMUTABLE | \
5848c2ecf20Sopenharmony_ci				  FS_XFLAG_APPEND | FS_XFLAG_NODUMP | \
5858c2ecf20Sopenharmony_ci				  FS_XFLAG_NOATIME | FS_XFLAG_PROJINHERIT | \
5868c2ecf20Sopenharmony_ci				  FS_XFLAG_DAX)
5878c2ecf20Sopenharmony_ci
5888c2ecf20Sopenharmony_ci/* Transfer xflags flags to internal */
5898c2ecf20Sopenharmony_cistatic inline unsigned long ext4_xflags_to_iflags(__u32 xflags)
5908c2ecf20Sopenharmony_ci{
5918c2ecf20Sopenharmony_ci	unsigned long iflags = 0;
5928c2ecf20Sopenharmony_ci
5938c2ecf20Sopenharmony_ci	if (xflags & FS_XFLAG_SYNC)
5948c2ecf20Sopenharmony_ci		iflags |= EXT4_SYNC_FL;
5958c2ecf20Sopenharmony_ci	if (xflags & FS_XFLAG_IMMUTABLE)
5968c2ecf20Sopenharmony_ci		iflags |= EXT4_IMMUTABLE_FL;
5978c2ecf20Sopenharmony_ci	if (xflags & FS_XFLAG_APPEND)
5988c2ecf20Sopenharmony_ci		iflags |= EXT4_APPEND_FL;
5998c2ecf20Sopenharmony_ci	if (xflags & FS_XFLAG_NODUMP)
6008c2ecf20Sopenharmony_ci		iflags |= EXT4_NODUMP_FL;
6018c2ecf20Sopenharmony_ci	if (xflags & FS_XFLAG_NOATIME)
6028c2ecf20Sopenharmony_ci		iflags |= EXT4_NOATIME_FL;
6038c2ecf20Sopenharmony_ci	if (xflags & FS_XFLAG_PROJINHERIT)
6048c2ecf20Sopenharmony_ci		iflags |= EXT4_PROJINHERIT_FL;
6058c2ecf20Sopenharmony_ci	if (xflags & FS_XFLAG_DAX)
6068c2ecf20Sopenharmony_ci		iflags |= EXT4_DAX_FL;
6078c2ecf20Sopenharmony_ci
6088c2ecf20Sopenharmony_ci	return iflags;
6098c2ecf20Sopenharmony_ci}
6108c2ecf20Sopenharmony_ci
6118c2ecf20Sopenharmony_cistatic int ext4_shutdown(struct super_block *sb, unsigned long arg)
6128c2ecf20Sopenharmony_ci{
6138c2ecf20Sopenharmony_ci	struct ext4_sb_info *sbi = EXT4_SB(sb);
6148c2ecf20Sopenharmony_ci	__u32 flags;
6158c2ecf20Sopenharmony_ci	struct super_block *ret;
6168c2ecf20Sopenharmony_ci
6178c2ecf20Sopenharmony_ci	if (!capable(CAP_SYS_ADMIN))
6188c2ecf20Sopenharmony_ci		return -EPERM;
6198c2ecf20Sopenharmony_ci
6208c2ecf20Sopenharmony_ci	if (get_user(flags, (__u32 __user *)arg))
6218c2ecf20Sopenharmony_ci		return -EFAULT;
6228c2ecf20Sopenharmony_ci
6238c2ecf20Sopenharmony_ci	if (flags > EXT4_GOING_FLAGS_NOLOGFLUSH)
6248c2ecf20Sopenharmony_ci		return -EINVAL;
6258c2ecf20Sopenharmony_ci
6268c2ecf20Sopenharmony_ci	if (ext4_forced_shutdown(sbi))
6278c2ecf20Sopenharmony_ci		return 0;
6288c2ecf20Sopenharmony_ci
6298c2ecf20Sopenharmony_ci	ext4_msg(sb, KERN_ALERT, "shut down requested (%d)", flags);
6308c2ecf20Sopenharmony_ci	trace_ext4_shutdown(sb, flags);
6318c2ecf20Sopenharmony_ci
6328c2ecf20Sopenharmony_ci	switch (flags) {
6338c2ecf20Sopenharmony_ci	case EXT4_GOING_FLAGS_DEFAULT:
6348c2ecf20Sopenharmony_ci		ret = freeze_bdev(sb->s_bdev);
6358c2ecf20Sopenharmony_ci		if (IS_ERR(ret))
6368c2ecf20Sopenharmony_ci			return PTR_ERR(ret);
6378c2ecf20Sopenharmony_ci		set_bit(EXT4_FLAGS_SHUTDOWN, &sbi->s_ext4_flags);
6388c2ecf20Sopenharmony_ci		thaw_bdev(sb->s_bdev, sb);
6398c2ecf20Sopenharmony_ci		break;
6408c2ecf20Sopenharmony_ci	case EXT4_GOING_FLAGS_LOGFLUSH:
6418c2ecf20Sopenharmony_ci		set_bit(EXT4_FLAGS_SHUTDOWN, &sbi->s_ext4_flags);
6428c2ecf20Sopenharmony_ci		if (sbi->s_journal && !is_journal_aborted(sbi->s_journal)) {
6438c2ecf20Sopenharmony_ci			(void) ext4_force_commit(sb);
6448c2ecf20Sopenharmony_ci			jbd2_journal_abort(sbi->s_journal, -ESHUTDOWN);
6458c2ecf20Sopenharmony_ci		}
6468c2ecf20Sopenharmony_ci		break;
6478c2ecf20Sopenharmony_ci	case EXT4_GOING_FLAGS_NOLOGFLUSH:
6488c2ecf20Sopenharmony_ci		set_bit(EXT4_FLAGS_SHUTDOWN, &sbi->s_ext4_flags);
6498c2ecf20Sopenharmony_ci		if (sbi->s_journal && !is_journal_aborted(sbi->s_journal))
6508c2ecf20Sopenharmony_ci			jbd2_journal_abort(sbi->s_journal, -ESHUTDOWN);
6518c2ecf20Sopenharmony_ci		break;
6528c2ecf20Sopenharmony_ci	default:
6538c2ecf20Sopenharmony_ci		return -EINVAL;
6548c2ecf20Sopenharmony_ci	}
6558c2ecf20Sopenharmony_ci	clear_opt(sb, DISCARD);
6568c2ecf20Sopenharmony_ci	return 0;
6578c2ecf20Sopenharmony_ci}
6588c2ecf20Sopenharmony_ci
6598c2ecf20Sopenharmony_cistruct getfsmap_info {
6608c2ecf20Sopenharmony_ci	struct super_block	*gi_sb;
6618c2ecf20Sopenharmony_ci	struct fsmap_head __user *gi_data;
6628c2ecf20Sopenharmony_ci	unsigned int		gi_idx;
6638c2ecf20Sopenharmony_ci	__u32			gi_last_flags;
6648c2ecf20Sopenharmony_ci};
6658c2ecf20Sopenharmony_ci
6668c2ecf20Sopenharmony_cistatic int ext4_getfsmap_format(struct ext4_fsmap *xfm, void *priv)
6678c2ecf20Sopenharmony_ci{
6688c2ecf20Sopenharmony_ci	struct getfsmap_info *info = priv;
6698c2ecf20Sopenharmony_ci	struct fsmap fm;
6708c2ecf20Sopenharmony_ci
6718c2ecf20Sopenharmony_ci	trace_ext4_getfsmap_mapping(info->gi_sb, xfm);
6728c2ecf20Sopenharmony_ci
6738c2ecf20Sopenharmony_ci	info->gi_last_flags = xfm->fmr_flags;
6748c2ecf20Sopenharmony_ci	ext4_fsmap_from_internal(info->gi_sb, &fm, xfm);
6758c2ecf20Sopenharmony_ci	if (copy_to_user(&info->gi_data->fmh_recs[info->gi_idx++], &fm,
6768c2ecf20Sopenharmony_ci			sizeof(struct fsmap)))
6778c2ecf20Sopenharmony_ci		return -EFAULT;
6788c2ecf20Sopenharmony_ci
6798c2ecf20Sopenharmony_ci	return 0;
6808c2ecf20Sopenharmony_ci}
6818c2ecf20Sopenharmony_ci
6828c2ecf20Sopenharmony_cistatic int ext4_ioc_getfsmap(struct super_block *sb,
6838c2ecf20Sopenharmony_ci			     struct fsmap_head __user *arg)
6848c2ecf20Sopenharmony_ci{
6858c2ecf20Sopenharmony_ci	struct getfsmap_info info = { NULL };
6868c2ecf20Sopenharmony_ci	struct ext4_fsmap_head xhead = {0};
6878c2ecf20Sopenharmony_ci	struct fsmap_head head;
6888c2ecf20Sopenharmony_ci	bool aborted = false;
6898c2ecf20Sopenharmony_ci	int error;
6908c2ecf20Sopenharmony_ci
6918c2ecf20Sopenharmony_ci	if (copy_from_user(&head, arg, sizeof(struct fsmap_head)))
6928c2ecf20Sopenharmony_ci		return -EFAULT;
6938c2ecf20Sopenharmony_ci	if (memchr_inv(head.fmh_reserved, 0, sizeof(head.fmh_reserved)) ||
6948c2ecf20Sopenharmony_ci	    memchr_inv(head.fmh_keys[0].fmr_reserved, 0,
6958c2ecf20Sopenharmony_ci		       sizeof(head.fmh_keys[0].fmr_reserved)) ||
6968c2ecf20Sopenharmony_ci	    memchr_inv(head.fmh_keys[1].fmr_reserved, 0,
6978c2ecf20Sopenharmony_ci		       sizeof(head.fmh_keys[1].fmr_reserved)))
6988c2ecf20Sopenharmony_ci		return -EINVAL;
6998c2ecf20Sopenharmony_ci	/*
7008c2ecf20Sopenharmony_ci	 * ext4 doesn't report file extents at all, so the only valid
7018c2ecf20Sopenharmony_ci	 * file offsets are the magic ones (all zeroes or all ones).
7028c2ecf20Sopenharmony_ci	 */
7038c2ecf20Sopenharmony_ci	if (head.fmh_keys[0].fmr_offset ||
7048c2ecf20Sopenharmony_ci	    (head.fmh_keys[1].fmr_offset != 0 &&
7058c2ecf20Sopenharmony_ci	     head.fmh_keys[1].fmr_offset != -1ULL))
7068c2ecf20Sopenharmony_ci		return -EINVAL;
7078c2ecf20Sopenharmony_ci
7088c2ecf20Sopenharmony_ci	xhead.fmh_iflags = head.fmh_iflags;
7098c2ecf20Sopenharmony_ci	xhead.fmh_count = head.fmh_count;
7108c2ecf20Sopenharmony_ci	ext4_fsmap_to_internal(sb, &xhead.fmh_keys[0], &head.fmh_keys[0]);
7118c2ecf20Sopenharmony_ci	ext4_fsmap_to_internal(sb, &xhead.fmh_keys[1], &head.fmh_keys[1]);
7128c2ecf20Sopenharmony_ci
7138c2ecf20Sopenharmony_ci	trace_ext4_getfsmap_low_key(sb, &xhead.fmh_keys[0]);
7148c2ecf20Sopenharmony_ci	trace_ext4_getfsmap_high_key(sb, &xhead.fmh_keys[1]);
7158c2ecf20Sopenharmony_ci
7168c2ecf20Sopenharmony_ci	info.gi_sb = sb;
7178c2ecf20Sopenharmony_ci	info.gi_data = arg;
7188c2ecf20Sopenharmony_ci	error = ext4_getfsmap(sb, &xhead, ext4_getfsmap_format, &info);
7198c2ecf20Sopenharmony_ci	if (error == EXT4_QUERY_RANGE_ABORT) {
7208c2ecf20Sopenharmony_ci		error = 0;
7218c2ecf20Sopenharmony_ci		aborted = true;
7228c2ecf20Sopenharmony_ci	} else if (error)
7238c2ecf20Sopenharmony_ci		return error;
7248c2ecf20Sopenharmony_ci
7258c2ecf20Sopenharmony_ci	/* If we didn't abort, set the "last" flag in the last fmx */
7268c2ecf20Sopenharmony_ci	if (!aborted && info.gi_idx) {
7278c2ecf20Sopenharmony_ci		info.gi_last_flags |= FMR_OF_LAST;
7288c2ecf20Sopenharmony_ci		if (copy_to_user(&info.gi_data->fmh_recs[info.gi_idx - 1].fmr_flags,
7298c2ecf20Sopenharmony_ci				 &info.gi_last_flags,
7308c2ecf20Sopenharmony_ci				 sizeof(info.gi_last_flags)))
7318c2ecf20Sopenharmony_ci			return -EFAULT;
7328c2ecf20Sopenharmony_ci	}
7338c2ecf20Sopenharmony_ci
7348c2ecf20Sopenharmony_ci	/* copy back header */
7358c2ecf20Sopenharmony_ci	head.fmh_entries = xhead.fmh_entries;
7368c2ecf20Sopenharmony_ci	head.fmh_oflags = xhead.fmh_oflags;
7378c2ecf20Sopenharmony_ci	if (copy_to_user(arg, &head, sizeof(struct fsmap_head)))
7388c2ecf20Sopenharmony_ci		return -EFAULT;
7398c2ecf20Sopenharmony_ci
7408c2ecf20Sopenharmony_ci	return 0;
7418c2ecf20Sopenharmony_ci}
7428c2ecf20Sopenharmony_ci
7438c2ecf20Sopenharmony_cistatic long ext4_ioctl_group_add(struct file *file,
7448c2ecf20Sopenharmony_ci				 struct ext4_new_group_data *input)
7458c2ecf20Sopenharmony_ci{
7468c2ecf20Sopenharmony_ci	struct super_block *sb = file_inode(file)->i_sb;
7478c2ecf20Sopenharmony_ci	int err, err2=0;
7488c2ecf20Sopenharmony_ci
7498c2ecf20Sopenharmony_ci	err = ext4_resize_begin(sb);
7508c2ecf20Sopenharmony_ci	if (err)
7518c2ecf20Sopenharmony_ci		return err;
7528c2ecf20Sopenharmony_ci
7538c2ecf20Sopenharmony_ci	if (ext4_has_feature_bigalloc(sb)) {
7548c2ecf20Sopenharmony_ci		ext4_msg(sb, KERN_ERR,
7558c2ecf20Sopenharmony_ci			 "Online resizing not supported with bigalloc");
7568c2ecf20Sopenharmony_ci		err = -EOPNOTSUPP;
7578c2ecf20Sopenharmony_ci		goto group_add_out;
7588c2ecf20Sopenharmony_ci	}
7598c2ecf20Sopenharmony_ci
7608c2ecf20Sopenharmony_ci	err = mnt_want_write_file(file);
7618c2ecf20Sopenharmony_ci	if (err)
7628c2ecf20Sopenharmony_ci		goto group_add_out;
7638c2ecf20Sopenharmony_ci
7648c2ecf20Sopenharmony_ci	err = ext4_group_add(sb, input);
7658c2ecf20Sopenharmony_ci	if (EXT4_SB(sb)->s_journal) {
7668c2ecf20Sopenharmony_ci		jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal);
7678c2ecf20Sopenharmony_ci		err2 = jbd2_journal_flush(EXT4_SB(sb)->s_journal);
7688c2ecf20Sopenharmony_ci		jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal);
7698c2ecf20Sopenharmony_ci	}
7708c2ecf20Sopenharmony_ci	if (err == 0)
7718c2ecf20Sopenharmony_ci		err = err2;
7728c2ecf20Sopenharmony_ci	mnt_drop_write_file(file);
7738c2ecf20Sopenharmony_ci	if (!err && ext4_has_group_desc_csum(sb) &&
7748c2ecf20Sopenharmony_ci	    test_opt(sb, INIT_INODE_TABLE))
7758c2ecf20Sopenharmony_ci		err = ext4_register_li_request(sb, input->group);
7768c2ecf20Sopenharmony_cigroup_add_out:
7778c2ecf20Sopenharmony_ci	ext4_resize_end(sb);
7788c2ecf20Sopenharmony_ci	return err;
7798c2ecf20Sopenharmony_ci}
7808c2ecf20Sopenharmony_ci
7818c2ecf20Sopenharmony_cistatic void ext4_fill_fsxattr(struct inode *inode, struct fsxattr *fa)
7828c2ecf20Sopenharmony_ci{
7838c2ecf20Sopenharmony_ci	struct ext4_inode_info *ei = EXT4_I(inode);
7848c2ecf20Sopenharmony_ci
7858c2ecf20Sopenharmony_ci	simple_fill_fsxattr(fa, ext4_iflags_to_xflags(ei->i_flags &
7868c2ecf20Sopenharmony_ci						      EXT4_FL_USER_VISIBLE));
7878c2ecf20Sopenharmony_ci
7888c2ecf20Sopenharmony_ci	if (ext4_has_feature_project(inode->i_sb))
7898c2ecf20Sopenharmony_ci		fa->fsx_projid = from_kprojid(&init_user_ns, ei->i_projid);
7908c2ecf20Sopenharmony_ci}
7918c2ecf20Sopenharmony_ci
7928c2ecf20Sopenharmony_ci/* So that the fiemap access checks can't overflow on 32 bit machines. */
7938c2ecf20Sopenharmony_ci#define FIEMAP_MAX_EXTENTS	(UINT_MAX / sizeof(struct fiemap_extent))
7948c2ecf20Sopenharmony_ci
7958c2ecf20Sopenharmony_cistatic int ext4_ioctl_get_es_cache(struct file *filp, unsigned long arg)
7968c2ecf20Sopenharmony_ci{
7978c2ecf20Sopenharmony_ci	struct fiemap fiemap;
7988c2ecf20Sopenharmony_ci	struct fiemap __user *ufiemap = (struct fiemap __user *) arg;
7998c2ecf20Sopenharmony_ci	struct fiemap_extent_info fieinfo = { 0, };
8008c2ecf20Sopenharmony_ci	struct inode *inode = file_inode(filp);
8018c2ecf20Sopenharmony_ci	int error;
8028c2ecf20Sopenharmony_ci
8038c2ecf20Sopenharmony_ci	if (copy_from_user(&fiemap, ufiemap, sizeof(fiemap)))
8048c2ecf20Sopenharmony_ci		return -EFAULT;
8058c2ecf20Sopenharmony_ci
8068c2ecf20Sopenharmony_ci	if (fiemap.fm_extent_count > FIEMAP_MAX_EXTENTS)
8078c2ecf20Sopenharmony_ci		return -EINVAL;
8088c2ecf20Sopenharmony_ci
8098c2ecf20Sopenharmony_ci	fieinfo.fi_flags = fiemap.fm_flags;
8108c2ecf20Sopenharmony_ci	fieinfo.fi_extents_max = fiemap.fm_extent_count;
8118c2ecf20Sopenharmony_ci	fieinfo.fi_extents_start = ufiemap->fm_extents;
8128c2ecf20Sopenharmony_ci
8138c2ecf20Sopenharmony_ci	error = ext4_get_es_cache(inode, &fieinfo, fiemap.fm_start,
8148c2ecf20Sopenharmony_ci			fiemap.fm_length);
8158c2ecf20Sopenharmony_ci	fiemap.fm_flags = fieinfo.fi_flags;
8168c2ecf20Sopenharmony_ci	fiemap.fm_mapped_extents = fieinfo.fi_extents_mapped;
8178c2ecf20Sopenharmony_ci	if (copy_to_user(ufiemap, &fiemap, sizeof(fiemap)))
8188c2ecf20Sopenharmony_ci		error = -EFAULT;
8198c2ecf20Sopenharmony_ci
8208c2ecf20Sopenharmony_ci	return error;
8218c2ecf20Sopenharmony_ci}
8228c2ecf20Sopenharmony_ci
8238c2ecf20Sopenharmony_cistatic long __ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
8248c2ecf20Sopenharmony_ci{
8258c2ecf20Sopenharmony_ci	struct inode *inode = file_inode(filp);
8268c2ecf20Sopenharmony_ci	struct super_block *sb = inode->i_sb;
8278c2ecf20Sopenharmony_ci	struct ext4_inode_info *ei = EXT4_I(inode);
8288c2ecf20Sopenharmony_ci	unsigned int flags;
8298c2ecf20Sopenharmony_ci
8308c2ecf20Sopenharmony_ci	ext4_debug("cmd = %u, arg = %lu\n", cmd, arg);
8318c2ecf20Sopenharmony_ci
8328c2ecf20Sopenharmony_ci	switch (cmd) {
8338c2ecf20Sopenharmony_ci	case FS_IOC_GETFSMAP:
8348c2ecf20Sopenharmony_ci		return ext4_ioc_getfsmap(sb, (void __user *)arg);
8358c2ecf20Sopenharmony_ci	case FS_IOC_GETFLAGS:
8368c2ecf20Sopenharmony_ci		flags = ei->i_flags & EXT4_FL_USER_VISIBLE;
8378c2ecf20Sopenharmony_ci		if (S_ISREG(inode->i_mode))
8388c2ecf20Sopenharmony_ci			flags &= ~EXT4_PROJINHERIT_FL;
8398c2ecf20Sopenharmony_ci		return put_user(flags, (int __user *) arg);
8408c2ecf20Sopenharmony_ci	case FS_IOC_SETFLAGS: {
8418c2ecf20Sopenharmony_ci		int err;
8428c2ecf20Sopenharmony_ci
8438c2ecf20Sopenharmony_ci		if (!inode_owner_or_capable(inode))
8448c2ecf20Sopenharmony_ci			return -EACCES;
8458c2ecf20Sopenharmony_ci
8468c2ecf20Sopenharmony_ci		if (get_user(flags, (int __user *) arg))
8478c2ecf20Sopenharmony_ci			return -EFAULT;
8488c2ecf20Sopenharmony_ci
8498c2ecf20Sopenharmony_ci		if (flags & ~EXT4_FL_USER_VISIBLE)
8508c2ecf20Sopenharmony_ci			return -EOPNOTSUPP;
8518c2ecf20Sopenharmony_ci		/*
8528c2ecf20Sopenharmony_ci		 * chattr(1) grabs flags via GETFLAGS, modifies the result and
8538c2ecf20Sopenharmony_ci		 * passes that to SETFLAGS. So we cannot easily make SETFLAGS
8548c2ecf20Sopenharmony_ci		 * more restrictive than just silently masking off visible but
8558c2ecf20Sopenharmony_ci		 * not settable flags as we always did.
8568c2ecf20Sopenharmony_ci		 */
8578c2ecf20Sopenharmony_ci		flags &= EXT4_FL_USER_MODIFIABLE;
8588c2ecf20Sopenharmony_ci		if (ext4_mask_flags(inode->i_mode, flags) != flags)
8598c2ecf20Sopenharmony_ci			return -EOPNOTSUPP;
8608c2ecf20Sopenharmony_ci
8618c2ecf20Sopenharmony_ci		err = mnt_want_write_file(filp);
8628c2ecf20Sopenharmony_ci		if (err)
8638c2ecf20Sopenharmony_ci			return err;
8648c2ecf20Sopenharmony_ci
8658c2ecf20Sopenharmony_ci		inode_lock(inode);
8668c2ecf20Sopenharmony_ci		err = ext4_ioctl_check_immutable(inode,
8678c2ecf20Sopenharmony_ci				from_kprojid(&init_user_ns, ei->i_projid),
8688c2ecf20Sopenharmony_ci				flags);
8698c2ecf20Sopenharmony_ci		if (!err)
8708c2ecf20Sopenharmony_ci			err = ext4_ioctl_setflags(inode, flags);
8718c2ecf20Sopenharmony_ci		inode_unlock(inode);
8728c2ecf20Sopenharmony_ci		mnt_drop_write_file(filp);
8738c2ecf20Sopenharmony_ci		return err;
8748c2ecf20Sopenharmony_ci	}
8758c2ecf20Sopenharmony_ci	case EXT4_IOC_GETVERSION:
8768c2ecf20Sopenharmony_ci	case EXT4_IOC_GETVERSION_OLD:
8778c2ecf20Sopenharmony_ci		return put_user(inode->i_generation, (int __user *) arg);
8788c2ecf20Sopenharmony_ci	case EXT4_IOC_SETVERSION:
8798c2ecf20Sopenharmony_ci	case EXT4_IOC_SETVERSION_OLD: {
8808c2ecf20Sopenharmony_ci		handle_t *handle;
8818c2ecf20Sopenharmony_ci		struct ext4_iloc iloc;
8828c2ecf20Sopenharmony_ci		__u32 generation;
8838c2ecf20Sopenharmony_ci		int err;
8848c2ecf20Sopenharmony_ci
8858c2ecf20Sopenharmony_ci		if (!inode_owner_or_capable(inode))
8868c2ecf20Sopenharmony_ci			return -EPERM;
8878c2ecf20Sopenharmony_ci
8888c2ecf20Sopenharmony_ci		if (ext4_has_metadata_csum(inode->i_sb)) {
8898c2ecf20Sopenharmony_ci			ext4_warning(sb, "Setting inode version is not "
8908c2ecf20Sopenharmony_ci				     "supported with metadata_csum enabled.");
8918c2ecf20Sopenharmony_ci			return -ENOTTY;
8928c2ecf20Sopenharmony_ci		}
8938c2ecf20Sopenharmony_ci
8948c2ecf20Sopenharmony_ci		err = mnt_want_write_file(filp);
8958c2ecf20Sopenharmony_ci		if (err)
8968c2ecf20Sopenharmony_ci			return err;
8978c2ecf20Sopenharmony_ci		if (get_user(generation, (int __user *) arg)) {
8988c2ecf20Sopenharmony_ci			err = -EFAULT;
8998c2ecf20Sopenharmony_ci			goto setversion_out;
9008c2ecf20Sopenharmony_ci		}
9018c2ecf20Sopenharmony_ci
9028c2ecf20Sopenharmony_ci		inode_lock(inode);
9038c2ecf20Sopenharmony_ci		handle = ext4_journal_start(inode, EXT4_HT_INODE, 1);
9048c2ecf20Sopenharmony_ci		if (IS_ERR(handle)) {
9058c2ecf20Sopenharmony_ci			err = PTR_ERR(handle);
9068c2ecf20Sopenharmony_ci			goto unlock_out;
9078c2ecf20Sopenharmony_ci		}
9088c2ecf20Sopenharmony_ci		err = ext4_reserve_inode_write(handle, inode, &iloc);
9098c2ecf20Sopenharmony_ci		if (err == 0) {
9108c2ecf20Sopenharmony_ci			inode->i_ctime = current_time(inode);
9118c2ecf20Sopenharmony_ci			inode->i_generation = generation;
9128c2ecf20Sopenharmony_ci			err = ext4_mark_iloc_dirty(handle, inode, &iloc);
9138c2ecf20Sopenharmony_ci		}
9148c2ecf20Sopenharmony_ci		ext4_journal_stop(handle);
9158c2ecf20Sopenharmony_ci
9168c2ecf20Sopenharmony_ciunlock_out:
9178c2ecf20Sopenharmony_ci		inode_unlock(inode);
9188c2ecf20Sopenharmony_cisetversion_out:
9198c2ecf20Sopenharmony_ci		mnt_drop_write_file(filp);
9208c2ecf20Sopenharmony_ci		return err;
9218c2ecf20Sopenharmony_ci	}
9228c2ecf20Sopenharmony_ci	case EXT4_IOC_GROUP_EXTEND: {
9238c2ecf20Sopenharmony_ci		ext4_fsblk_t n_blocks_count;
9248c2ecf20Sopenharmony_ci		int err, err2=0;
9258c2ecf20Sopenharmony_ci
9268c2ecf20Sopenharmony_ci		err = ext4_resize_begin(sb);
9278c2ecf20Sopenharmony_ci		if (err)
9288c2ecf20Sopenharmony_ci			return err;
9298c2ecf20Sopenharmony_ci
9308c2ecf20Sopenharmony_ci		if (get_user(n_blocks_count, (__u32 __user *)arg)) {
9318c2ecf20Sopenharmony_ci			err = -EFAULT;
9328c2ecf20Sopenharmony_ci			goto group_extend_out;
9338c2ecf20Sopenharmony_ci		}
9348c2ecf20Sopenharmony_ci
9358c2ecf20Sopenharmony_ci		if (ext4_has_feature_bigalloc(sb)) {
9368c2ecf20Sopenharmony_ci			ext4_msg(sb, KERN_ERR,
9378c2ecf20Sopenharmony_ci				 "Online resizing not supported with bigalloc");
9388c2ecf20Sopenharmony_ci			err = -EOPNOTSUPP;
9398c2ecf20Sopenharmony_ci			goto group_extend_out;
9408c2ecf20Sopenharmony_ci		}
9418c2ecf20Sopenharmony_ci
9428c2ecf20Sopenharmony_ci		err = mnt_want_write_file(filp);
9438c2ecf20Sopenharmony_ci		if (err)
9448c2ecf20Sopenharmony_ci			goto group_extend_out;
9458c2ecf20Sopenharmony_ci
9468c2ecf20Sopenharmony_ci		err = ext4_group_extend(sb, EXT4_SB(sb)->s_es, n_blocks_count);
9478c2ecf20Sopenharmony_ci		if (EXT4_SB(sb)->s_journal) {
9488c2ecf20Sopenharmony_ci			jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal);
9498c2ecf20Sopenharmony_ci			err2 = jbd2_journal_flush(EXT4_SB(sb)->s_journal);
9508c2ecf20Sopenharmony_ci			jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal);
9518c2ecf20Sopenharmony_ci		}
9528c2ecf20Sopenharmony_ci		if (err == 0)
9538c2ecf20Sopenharmony_ci			err = err2;
9548c2ecf20Sopenharmony_ci		mnt_drop_write_file(filp);
9558c2ecf20Sopenharmony_cigroup_extend_out:
9568c2ecf20Sopenharmony_ci		ext4_resize_end(sb);
9578c2ecf20Sopenharmony_ci		return err;
9588c2ecf20Sopenharmony_ci	}
9598c2ecf20Sopenharmony_ci
9608c2ecf20Sopenharmony_ci	case EXT4_IOC_MOVE_EXT: {
9618c2ecf20Sopenharmony_ci		struct move_extent me;
9628c2ecf20Sopenharmony_ci		struct fd donor;
9638c2ecf20Sopenharmony_ci		int err;
9648c2ecf20Sopenharmony_ci
9658c2ecf20Sopenharmony_ci		if (!(filp->f_mode & FMODE_READ) ||
9668c2ecf20Sopenharmony_ci		    !(filp->f_mode & FMODE_WRITE))
9678c2ecf20Sopenharmony_ci			return -EBADF;
9688c2ecf20Sopenharmony_ci
9698c2ecf20Sopenharmony_ci		if (copy_from_user(&me,
9708c2ecf20Sopenharmony_ci			(struct move_extent __user *)arg, sizeof(me)))
9718c2ecf20Sopenharmony_ci			return -EFAULT;
9728c2ecf20Sopenharmony_ci		me.moved_len = 0;
9738c2ecf20Sopenharmony_ci
9748c2ecf20Sopenharmony_ci		donor = fdget(me.donor_fd);
9758c2ecf20Sopenharmony_ci		if (!donor.file)
9768c2ecf20Sopenharmony_ci			return -EBADF;
9778c2ecf20Sopenharmony_ci
9788c2ecf20Sopenharmony_ci		if (!(donor.file->f_mode & FMODE_WRITE)) {
9798c2ecf20Sopenharmony_ci			err = -EBADF;
9808c2ecf20Sopenharmony_ci			goto mext_out;
9818c2ecf20Sopenharmony_ci		}
9828c2ecf20Sopenharmony_ci
9838c2ecf20Sopenharmony_ci		if (ext4_has_feature_bigalloc(sb)) {
9848c2ecf20Sopenharmony_ci			ext4_msg(sb, KERN_ERR,
9858c2ecf20Sopenharmony_ci				 "Online defrag not supported with bigalloc");
9868c2ecf20Sopenharmony_ci			err = -EOPNOTSUPP;
9878c2ecf20Sopenharmony_ci			goto mext_out;
9888c2ecf20Sopenharmony_ci		} else if (IS_DAX(inode)) {
9898c2ecf20Sopenharmony_ci			ext4_msg(sb, KERN_ERR,
9908c2ecf20Sopenharmony_ci				 "Online defrag not supported with DAX");
9918c2ecf20Sopenharmony_ci			err = -EOPNOTSUPP;
9928c2ecf20Sopenharmony_ci			goto mext_out;
9938c2ecf20Sopenharmony_ci		}
9948c2ecf20Sopenharmony_ci
9958c2ecf20Sopenharmony_ci		err = mnt_want_write_file(filp);
9968c2ecf20Sopenharmony_ci		if (err)
9978c2ecf20Sopenharmony_ci			goto mext_out;
9988c2ecf20Sopenharmony_ci
9998c2ecf20Sopenharmony_ci		err = ext4_move_extents(filp, donor.file, me.orig_start,
10008c2ecf20Sopenharmony_ci					me.donor_start, me.len, &me.moved_len);
10018c2ecf20Sopenharmony_ci		mnt_drop_write_file(filp);
10028c2ecf20Sopenharmony_ci
10038c2ecf20Sopenharmony_ci		if (copy_to_user((struct move_extent __user *)arg,
10048c2ecf20Sopenharmony_ci				 &me, sizeof(me)))
10058c2ecf20Sopenharmony_ci			err = -EFAULT;
10068c2ecf20Sopenharmony_cimext_out:
10078c2ecf20Sopenharmony_ci		fdput(donor);
10088c2ecf20Sopenharmony_ci		return err;
10098c2ecf20Sopenharmony_ci	}
10108c2ecf20Sopenharmony_ci
10118c2ecf20Sopenharmony_ci	case EXT4_IOC_GROUP_ADD: {
10128c2ecf20Sopenharmony_ci		struct ext4_new_group_data input;
10138c2ecf20Sopenharmony_ci
10148c2ecf20Sopenharmony_ci		if (copy_from_user(&input, (struct ext4_new_group_input __user *)arg,
10158c2ecf20Sopenharmony_ci				sizeof(input)))
10168c2ecf20Sopenharmony_ci			return -EFAULT;
10178c2ecf20Sopenharmony_ci
10188c2ecf20Sopenharmony_ci		return ext4_ioctl_group_add(filp, &input);
10198c2ecf20Sopenharmony_ci	}
10208c2ecf20Sopenharmony_ci
10218c2ecf20Sopenharmony_ci	case EXT4_IOC_MIGRATE:
10228c2ecf20Sopenharmony_ci	{
10238c2ecf20Sopenharmony_ci		int err;
10248c2ecf20Sopenharmony_ci		if (!inode_owner_or_capable(inode))
10258c2ecf20Sopenharmony_ci			return -EACCES;
10268c2ecf20Sopenharmony_ci
10278c2ecf20Sopenharmony_ci		err = mnt_want_write_file(filp);
10288c2ecf20Sopenharmony_ci		if (err)
10298c2ecf20Sopenharmony_ci			return err;
10308c2ecf20Sopenharmony_ci		/*
10318c2ecf20Sopenharmony_ci		 * inode_mutex prevent write and truncate on the file.
10328c2ecf20Sopenharmony_ci		 * Read still goes through. We take i_data_sem in
10338c2ecf20Sopenharmony_ci		 * ext4_ext_swap_inode_data before we switch the
10348c2ecf20Sopenharmony_ci		 * inode format to prevent read.
10358c2ecf20Sopenharmony_ci		 */
10368c2ecf20Sopenharmony_ci		inode_lock((inode));
10378c2ecf20Sopenharmony_ci		err = ext4_ext_migrate(inode);
10388c2ecf20Sopenharmony_ci		inode_unlock((inode));
10398c2ecf20Sopenharmony_ci		mnt_drop_write_file(filp);
10408c2ecf20Sopenharmony_ci		return err;
10418c2ecf20Sopenharmony_ci	}
10428c2ecf20Sopenharmony_ci
10438c2ecf20Sopenharmony_ci	case EXT4_IOC_ALLOC_DA_BLKS:
10448c2ecf20Sopenharmony_ci	{
10458c2ecf20Sopenharmony_ci		int err;
10468c2ecf20Sopenharmony_ci		if (!inode_owner_or_capable(inode))
10478c2ecf20Sopenharmony_ci			return -EACCES;
10488c2ecf20Sopenharmony_ci
10498c2ecf20Sopenharmony_ci		err = mnt_want_write_file(filp);
10508c2ecf20Sopenharmony_ci		if (err)
10518c2ecf20Sopenharmony_ci			return err;
10528c2ecf20Sopenharmony_ci		err = ext4_alloc_da_blocks(inode);
10538c2ecf20Sopenharmony_ci		mnt_drop_write_file(filp);
10548c2ecf20Sopenharmony_ci		return err;
10558c2ecf20Sopenharmony_ci	}
10568c2ecf20Sopenharmony_ci
10578c2ecf20Sopenharmony_ci	case EXT4_IOC_SWAP_BOOT:
10588c2ecf20Sopenharmony_ci	{
10598c2ecf20Sopenharmony_ci		int err;
10608c2ecf20Sopenharmony_ci		if (!(filp->f_mode & FMODE_WRITE))
10618c2ecf20Sopenharmony_ci			return -EBADF;
10628c2ecf20Sopenharmony_ci		err = mnt_want_write_file(filp);
10638c2ecf20Sopenharmony_ci		if (err)
10648c2ecf20Sopenharmony_ci			return err;
10658c2ecf20Sopenharmony_ci		err = swap_inode_boot_loader(sb, inode);
10668c2ecf20Sopenharmony_ci		mnt_drop_write_file(filp);
10678c2ecf20Sopenharmony_ci		return err;
10688c2ecf20Sopenharmony_ci	}
10698c2ecf20Sopenharmony_ci
10708c2ecf20Sopenharmony_ci	case EXT4_IOC_RESIZE_FS: {
10718c2ecf20Sopenharmony_ci		ext4_fsblk_t n_blocks_count;
10728c2ecf20Sopenharmony_ci		int err = 0, err2 = 0;
10738c2ecf20Sopenharmony_ci		ext4_group_t o_group = EXT4_SB(sb)->s_groups_count;
10748c2ecf20Sopenharmony_ci
10758c2ecf20Sopenharmony_ci		if (copy_from_user(&n_blocks_count, (__u64 __user *)arg,
10768c2ecf20Sopenharmony_ci				   sizeof(__u64))) {
10778c2ecf20Sopenharmony_ci			return -EFAULT;
10788c2ecf20Sopenharmony_ci		}
10798c2ecf20Sopenharmony_ci
10808c2ecf20Sopenharmony_ci		err = ext4_resize_begin(sb);
10818c2ecf20Sopenharmony_ci		if (err)
10828c2ecf20Sopenharmony_ci			return err;
10838c2ecf20Sopenharmony_ci
10848c2ecf20Sopenharmony_ci		err = mnt_want_write_file(filp);
10858c2ecf20Sopenharmony_ci		if (err)
10868c2ecf20Sopenharmony_ci			goto resizefs_out;
10878c2ecf20Sopenharmony_ci
10888c2ecf20Sopenharmony_ci		err = ext4_resize_fs(sb, n_blocks_count);
10898c2ecf20Sopenharmony_ci		if (EXT4_SB(sb)->s_journal) {
10908c2ecf20Sopenharmony_ci			ext4_fc_mark_ineligible(sb, EXT4_FC_REASON_RESIZE);
10918c2ecf20Sopenharmony_ci			jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal);
10928c2ecf20Sopenharmony_ci			err2 = jbd2_journal_flush(EXT4_SB(sb)->s_journal);
10938c2ecf20Sopenharmony_ci			jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal);
10948c2ecf20Sopenharmony_ci		}
10958c2ecf20Sopenharmony_ci		if (err == 0)
10968c2ecf20Sopenharmony_ci			err = err2;
10978c2ecf20Sopenharmony_ci		mnt_drop_write_file(filp);
10988c2ecf20Sopenharmony_ci		if (!err && (o_group < EXT4_SB(sb)->s_groups_count) &&
10998c2ecf20Sopenharmony_ci		    ext4_has_group_desc_csum(sb) &&
11008c2ecf20Sopenharmony_ci		    test_opt(sb, INIT_INODE_TABLE))
11018c2ecf20Sopenharmony_ci			err = ext4_register_li_request(sb, o_group);
11028c2ecf20Sopenharmony_ci
11038c2ecf20Sopenharmony_ciresizefs_out:
11048c2ecf20Sopenharmony_ci		ext4_resize_end(sb);
11058c2ecf20Sopenharmony_ci		return err;
11068c2ecf20Sopenharmony_ci	}
11078c2ecf20Sopenharmony_ci
11088c2ecf20Sopenharmony_ci	case FITRIM:
11098c2ecf20Sopenharmony_ci	{
11108c2ecf20Sopenharmony_ci		struct request_queue *q = bdev_get_queue(sb->s_bdev);
11118c2ecf20Sopenharmony_ci		struct fstrim_range range;
11128c2ecf20Sopenharmony_ci		int ret = 0;
11138c2ecf20Sopenharmony_ci
11148c2ecf20Sopenharmony_ci		if (!capable(CAP_SYS_ADMIN))
11158c2ecf20Sopenharmony_ci			return -EPERM;
11168c2ecf20Sopenharmony_ci
11178c2ecf20Sopenharmony_ci		if (!blk_queue_discard(q))
11188c2ecf20Sopenharmony_ci			return -EOPNOTSUPP;
11198c2ecf20Sopenharmony_ci
11208c2ecf20Sopenharmony_ci		/*
11218c2ecf20Sopenharmony_ci		 * We haven't replayed the journal, so we cannot use our
11228c2ecf20Sopenharmony_ci		 * block-bitmap-guided storage zapping commands.
11238c2ecf20Sopenharmony_ci		 */
11248c2ecf20Sopenharmony_ci		if (test_opt(sb, NOLOAD) && ext4_has_feature_journal(sb))
11258c2ecf20Sopenharmony_ci			return -EROFS;
11268c2ecf20Sopenharmony_ci
11278c2ecf20Sopenharmony_ci		if (copy_from_user(&range, (struct fstrim_range __user *)arg,
11288c2ecf20Sopenharmony_ci		    sizeof(range)))
11298c2ecf20Sopenharmony_ci			return -EFAULT;
11308c2ecf20Sopenharmony_ci
11318c2ecf20Sopenharmony_ci		ret = ext4_trim_fs(sb, &range);
11328c2ecf20Sopenharmony_ci		if (ret < 0)
11338c2ecf20Sopenharmony_ci			return ret;
11348c2ecf20Sopenharmony_ci
11358c2ecf20Sopenharmony_ci		if (copy_to_user((struct fstrim_range __user *)arg, &range,
11368c2ecf20Sopenharmony_ci		    sizeof(range)))
11378c2ecf20Sopenharmony_ci			return -EFAULT;
11388c2ecf20Sopenharmony_ci
11398c2ecf20Sopenharmony_ci		return 0;
11408c2ecf20Sopenharmony_ci	}
11418c2ecf20Sopenharmony_ci	case EXT4_IOC_PRECACHE_EXTENTS:
11428c2ecf20Sopenharmony_ci		return ext4_ext_precache(inode);
11438c2ecf20Sopenharmony_ci
11448c2ecf20Sopenharmony_ci	case FS_IOC_SET_ENCRYPTION_POLICY:
11458c2ecf20Sopenharmony_ci		if (!ext4_has_feature_encrypt(sb))
11468c2ecf20Sopenharmony_ci			return -EOPNOTSUPP;
11478c2ecf20Sopenharmony_ci		return fscrypt_ioctl_set_policy(filp, (const void __user *)arg);
11488c2ecf20Sopenharmony_ci
11498c2ecf20Sopenharmony_ci	case FS_IOC_GET_ENCRYPTION_PWSALT: {
11508c2ecf20Sopenharmony_ci#ifdef CONFIG_FS_ENCRYPTION
11518c2ecf20Sopenharmony_ci		int err, err2;
11528c2ecf20Sopenharmony_ci		struct ext4_sb_info *sbi = EXT4_SB(sb);
11538c2ecf20Sopenharmony_ci		handle_t *handle;
11548c2ecf20Sopenharmony_ci
11558c2ecf20Sopenharmony_ci		if (!ext4_has_feature_encrypt(sb))
11568c2ecf20Sopenharmony_ci			return -EOPNOTSUPP;
11578c2ecf20Sopenharmony_ci		if (uuid_is_zero(sbi->s_es->s_encrypt_pw_salt)) {
11588c2ecf20Sopenharmony_ci			err = mnt_want_write_file(filp);
11598c2ecf20Sopenharmony_ci			if (err)
11608c2ecf20Sopenharmony_ci				return err;
11618c2ecf20Sopenharmony_ci			handle = ext4_journal_start_sb(sb, EXT4_HT_MISC, 1);
11628c2ecf20Sopenharmony_ci			if (IS_ERR(handle)) {
11638c2ecf20Sopenharmony_ci				err = PTR_ERR(handle);
11648c2ecf20Sopenharmony_ci				goto pwsalt_err_exit;
11658c2ecf20Sopenharmony_ci			}
11668c2ecf20Sopenharmony_ci			err = ext4_journal_get_write_access(handle, sbi->s_sbh);
11678c2ecf20Sopenharmony_ci			if (err)
11688c2ecf20Sopenharmony_ci				goto pwsalt_err_journal;
11698c2ecf20Sopenharmony_ci			lock_buffer(sbi->s_sbh);
11708c2ecf20Sopenharmony_ci			generate_random_uuid(sbi->s_es->s_encrypt_pw_salt);
11718c2ecf20Sopenharmony_ci			ext4_superblock_csum_set(sb);
11728c2ecf20Sopenharmony_ci			unlock_buffer(sbi->s_sbh);
11738c2ecf20Sopenharmony_ci			err = ext4_handle_dirty_metadata(handle, NULL,
11748c2ecf20Sopenharmony_ci							 sbi->s_sbh);
11758c2ecf20Sopenharmony_ci		pwsalt_err_journal:
11768c2ecf20Sopenharmony_ci			err2 = ext4_journal_stop(handle);
11778c2ecf20Sopenharmony_ci			if (err2 && !err)
11788c2ecf20Sopenharmony_ci				err = err2;
11798c2ecf20Sopenharmony_ci		pwsalt_err_exit:
11808c2ecf20Sopenharmony_ci			mnt_drop_write_file(filp);
11818c2ecf20Sopenharmony_ci			if (err)
11828c2ecf20Sopenharmony_ci				return err;
11838c2ecf20Sopenharmony_ci		}
11848c2ecf20Sopenharmony_ci		if (copy_to_user((void __user *) arg,
11858c2ecf20Sopenharmony_ci				 sbi->s_es->s_encrypt_pw_salt, 16))
11868c2ecf20Sopenharmony_ci			return -EFAULT;
11878c2ecf20Sopenharmony_ci		return 0;
11888c2ecf20Sopenharmony_ci#else
11898c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
11908c2ecf20Sopenharmony_ci#endif
11918c2ecf20Sopenharmony_ci	}
11928c2ecf20Sopenharmony_ci	case FS_IOC_GET_ENCRYPTION_POLICY:
11938c2ecf20Sopenharmony_ci		if (!ext4_has_feature_encrypt(sb))
11948c2ecf20Sopenharmony_ci			return -EOPNOTSUPP;
11958c2ecf20Sopenharmony_ci		return fscrypt_ioctl_get_policy(filp, (void __user *)arg);
11968c2ecf20Sopenharmony_ci
11978c2ecf20Sopenharmony_ci	case FS_IOC_GET_ENCRYPTION_POLICY_EX:
11988c2ecf20Sopenharmony_ci		if (!ext4_has_feature_encrypt(sb))
11998c2ecf20Sopenharmony_ci			return -EOPNOTSUPP;
12008c2ecf20Sopenharmony_ci		return fscrypt_ioctl_get_policy_ex(filp, (void __user *)arg);
12018c2ecf20Sopenharmony_ci
12028c2ecf20Sopenharmony_ci	case FS_IOC_ADD_ENCRYPTION_KEY:
12038c2ecf20Sopenharmony_ci		if (!ext4_has_feature_encrypt(sb))
12048c2ecf20Sopenharmony_ci			return -EOPNOTSUPP;
12058c2ecf20Sopenharmony_ci		return fscrypt_ioctl_add_key(filp, (void __user *)arg);
12068c2ecf20Sopenharmony_ci
12078c2ecf20Sopenharmony_ci	case FS_IOC_REMOVE_ENCRYPTION_KEY:
12088c2ecf20Sopenharmony_ci		if (!ext4_has_feature_encrypt(sb))
12098c2ecf20Sopenharmony_ci			return -EOPNOTSUPP;
12108c2ecf20Sopenharmony_ci		return fscrypt_ioctl_remove_key(filp, (void __user *)arg);
12118c2ecf20Sopenharmony_ci
12128c2ecf20Sopenharmony_ci	case FS_IOC_REMOVE_ENCRYPTION_KEY_ALL_USERS:
12138c2ecf20Sopenharmony_ci		if (!ext4_has_feature_encrypt(sb))
12148c2ecf20Sopenharmony_ci			return -EOPNOTSUPP;
12158c2ecf20Sopenharmony_ci		return fscrypt_ioctl_remove_key_all_users(filp,
12168c2ecf20Sopenharmony_ci							  (void __user *)arg);
12178c2ecf20Sopenharmony_ci	case FS_IOC_GET_ENCRYPTION_KEY_STATUS:
12188c2ecf20Sopenharmony_ci		if (!ext4_has_feature_encrypt(sb))
12198c2ecf20Sopenharmony_ci			return -EOPNOTSUPP;
12208c2ecf20Sopenharmony_ci		return fscrypt_ioctl_get_key_status(filp, (void __user *)arg);
12218c2ecf20Sopenharmony_ci
12228c2ecf20Sopenharmony_ci	case FS_IOC_GET_ENCRYPTION_NONCE:
12238c2ecf20Sopenharmony_ci		if (!ext4_has_feature_encrypt(sb))
12248c2ecf20Sopenharmony_ci			return -EOPNOTSUPP;
12258c2ecf20Sopenharmony_ci		return fscrypt_ioctl_get_nonce(filp, (void __user *)arg);
12268c2ecf20Sopenharmony_ci
12278c2ecf20Sopenharmony_ci	case EXT4_IOC_CLEAR_ES_CACHE:
12288c2ecf20Sopenharmony_ci	{
12298c2ecf20Sopenharmony_ci		if (!inode_owner_or_capable(inode))
12308c2ecf20Sopenharmony_ci			return -EACCES;
12318c2ecf20Sopenharmony_ci		ext4_clear_inode_es(inode);
12328c2ecf20Sopenharmony_ci		return 0;
12338c2ecf20Sopenharmony_ci	}
12348c2ecf20Sopenharmony_ci
12358c2ecf20Sopenharmony_ci	case EXT4_IOC_GETSTATE:
12368c2ecf20Sopenharmony_ci	{
12378c2ecf20Sopenharmony_ci		__u32	state = 0;
12388c2ecf20Sopenharmony_ci
12398c2ecf20Sopenharmony_ci		if (ext4_test_inode_state(inode, EXT4_STATE_EXT_PRECACHED))
12408c2ecf20Sopenharmony_ci			state |= EXT4_STATE_FLAG_EXT_PRECACHED;
12418c2ecf20Sopenharmony_ci		if (ext4_test_inode_state(inode, EXT4_STATE_NEW))
12428c2ecf20Sopenharmony_ci			state |= EXT4_STATE_FLAG_NEW;
12438c2ecf20Sopenharmony_ci		if (ext4_test_inode_state(inode, EXT4_STATE_NEWENTRY))
12448c2ecf20Sopenharmony_ci			state |= EXT4_STATE_FLAG_NEWENTRY;
12458c2ecf20Sopenharmony_ci		if (ext4_test_inode_state(inode, EXT4_STATE_DA_ALLOC_CLOSE))
12468c2ecf20Sopenharmony_ci			state |= EXT4_STATE_FLAG_DA_ALLOC_CLOSE;
12478c2ecf20Sopenharmony_ci
12488c2ecf20Sopenharmony_ci		return put_user(state, (__u32 __user *) arg);
12498c2ecf20Sopenharmony_ci	}
12508c2ecf20Sopenharmony_ci
12518c2ecf20Sopenharmony_ci	case EXT4_IOC_GET_ES_CACHE:
12528c2ecf20Sopenharmony_ci		return ext4_ioctl_get_es_cache(filp, arg);
12538c2ecf20Sopenharmony_ci
12548c2ecf20Sopenharmony_ci	case FS_IOC_FSGETXATTR:
12558c2ecf20Sopenharmony_ci	{
12568c2ecf20Sopenharmony_ci		struct fsxattr fa;
12578c2ecf20Sopenharmony_ci
12588c2ecf20Sopenharmony_ci		ext4_fill_fsxattr(inode, &fa);
12598c2ecf20Sopenharmony_ci
12608c2ecf20Sopenharmony_ci		if (copy_to_user((struct fsxattr __user *)arg,
12618c2ecf20Sopenharmony_ci				 &fa, sizeof(fa)))
12628c2ecf20Sopenharmony_ci			return -EFAULT;
12638c2ecf20Sopenharmony_ci		return 0;
12648c2ecf20Sopenharmony_ci	}
12658c2ecf20Sopenharmony_ci	case FS_IOC_FSSETXATTR:
12668c2ecf20Sopenharmony_ci	{
12678c2ecf20Sopenharmony_ci		struct fsxattr fa, old_fa;
12688c2ecf20Sopenharmony_ci		int err;
12698c2ecf20Sopenharmony_ci
12708c2ecf20Sopenharmony_ci		if (copy_from_user(&fa, (struct fsxattr __user *)arg,
12718c2ecf20Sopenharmony_ci				   sizeof(fa)))
12728c2ecf20Sopenharmony_ci			return -EFAULT;
12738c2ecf20Sopenharmony_ci
12748c2ecf20Sopenharmony_ci		/* Make sure caller has proper permission */
12758c2ecf20Sopenharmony_ci		if (!inode_owner_or_capable(inode))
12768c2ecf20Sopenharmony_ci			return -EACCES;
12778c2ecf20Sopenharmony_ci
12788c2ecf20Sopenharmony_ci		if (fa.fsx_xflags & ~EXT4_SUPPORTED_FS_XFLAGS)
12798c2ecf20Sopenharmony_ci			return -EOPNOTSUPP;
12808c2ecf20Sopenharmony_ci
12818c2ecf20Sopenharmony_ci		flags = ext4_xflags_to_iflags(fa.fsx_xflags);
12828c2ecf20Sopenharmony_ci		if (ext4_mask_flags(inode->i_mode, flags) != flags)
12838c2ecf20Sopenharmony_ci			return -EOPNOTSUPP;
12848c2ecf20Sopenharmony_ci
12858c2ecf20Sopenharmony_ci		err = mnt_want_write_file(filp);
12868c2ecf20Sopenharmony_ci		if (err)
12878c2ecf20Sopenharmony_ci			return err;
12888c2ecf20Sopenharmony_ci
12898c2ecf20Sopenharmony_ci		inode_lock(inode);
12908c2ecf20Sopenharmony_ci		ext4_fill_fsxattr(inode, &old_fa);
12918c2ecf20Sopenharmony_ci		err = vfs_ioc_fssetxattr_check(inode, &old_fa, &fa);
12928c2ecf20Sopenharmony_ci		if (err)
12938c2ecf20Sopenharmony_ci			goto out;
12948c2ecf20Sopenharmony_ci		flags = (ei->i_flags & ~EXT4_FL_XFLAG_VISIBLE) |
12958c2ecf20Sopenharmony_ci			 (flags & EXT4_FL_XFLAG_VISIBLE);
12968c2ecf20Sopenharmony_ci		err = ext4_ioctl_check_immutable(inode, fa.fsx_projid, flags);
12978c2ecf20Sopenharmony_ci		if (err)
12988c2ecf20Sopenharmony_ci			goto out;
12998c2ecf20Sopenharmony_ci		err = ext4_ioctl_setflags(inode, flags);
13008c2ecf20Sopenharmony_ci		if (err)
13018c2ecf20Sopenharmony_ci			goto out;
13028c2ecf20Sopenharmony_ci		err = ext4_ioctl_setproject(filp, fa.fsx_projid);
13038c2ecf20Sopenharmony_ciout:
13048c2ecf20Sopenharmony_ci		inode_unlock(inode);
13058c2ecf20Sopenharmony_ci		mnt_drop_write_file(filp);
13068c2ecf20Sopenharmony_ci		return err;
13078c2ecf20Sopenharmony_ci	}
13088c2ecf20Sopenharmony_ci	case EXT4_IOC_SHUTDOWN:
13098c2ecf20Sopenharmony_ci		return ext4_shutdown(sb, arg);
13108c2ecf20Sopenharmony_ci
13118c2ecf20Sopenharmony_ci	case FS_IOC_ENABLE_VERITY:
13128c2ecf20Sopenharmony_ci		if (!ext4_has_feature_verity(sb))
13138c2ecf20Sopenharmony_ci			return -EOPNOTSUPP;
13148c2ecf20Sopenharmony_ci		return fsverity_ioctl_enable(filp, (const void __user *)arg);
13158c2ecf20Sopenharmony_ci
13168c2ecf20Sopenharmony_ci	case FS_IOC_MEASURE_VERITY:
13178c2ecf20Sopenharmony_ci		if (!ext4_has_feature_verity(sb))
13188c2ecf20Sopenharmony_ci			return -EOPNOTSUPP;
13198c2ecf20Sopenharmony_ci		return fsverity_ioctl_measure(filp, (void __user *)arg);
13208c2ecf20Sopenharmony_ci
13218c2ecf20Sopenharmony_ci	default:
13228c2ecf20Sopenharmony_ci		return -ENOTTY;
13238c2ecf20Sopenharmony_ci	}
13248c2ecf20Sopenharmony_ci}
13258c2ecf20Sopenharmony_ci
13268c2ecf20Sopenharmony_cilong ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
13278c2ecf20Sopenharmony_ci{
13288c2ecf20Sopenharmony_ci	return __ext4_ioctl(filp, cmd, arg);
13298c2ecf20Sopenharmony_ci}
13308c2ecf20Sopenharmony_ci
13318c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT
13328c2ecf20Sopenharmony_cilong ext4_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
13338c2ecf20Sopenharmony_ci{
13348c2ecf20Sopenharmony_ci	/* These are just misnamed, they actually get/put from/to user an int */
13358c2ecf20Sopenharmony_ci	switch (cmd) {
13368c2ecf20Sopenharmony_ci	case FS_IOC32_GETFLAGS:
13378c2ecf20Sopenharmony_ci		cmd = FS_IOC_GETFLAGS;
13388c2ecf20Sopenharmony_ci		break;
13398c2ecf20Sopenharmony_ci	case FS_IOC32_SETFLAGS:
13408c2ecf20Sopenharmony_ci		cmd = FS_IOC_SETFLAGS;
13418c2ecf20Sopenharmony_ci		break;
13428c2ecf20Sopenharmony_ci	case EXT4_IOC32_GETVERSION:
13438c2ecf20Sopenharmony_ci		cmd = EXT4_IOC_GETVERSION;
13448c2ecf20Sopenharmony_ci		break;
13458c2ecf20Sopenharmony_ci	case EXT4_IOC32_SETVERSION:
13468c2ecf20Sopenharmony_ci		cmd = EXT4_IOC_SETVERSION;
13478c2ecf20Sopenharmony_ci		break;
13488c2ecf20Sopenharmony_ci	case EXT4_IOC32_GROUP_EXTEND:
13498c2ecf20Sopenharmony_ci		cmd = EXT4_IOC_GROUP_EXTEND;
13508c2ecf20Sopenharmony_ci		break;
13518c2ecf20Sopenharmony_ci	case EXT4_IOC32_GETVERSION_OLD:
13528c2ecf20Sopenharmony_ci		cmd = EXT4_IOC_GETVERSION_OLD;
13538c2ecf20Sopenharmony_ci		break;
13548c2ecf20Sopenharmony_ci	case EXT4_IOC32_SETVERSION_OLD:
13558c2ecf20Sopenharmony_ci		cmd = EXT4_IOC_SETVERSION_OLD;
13568c2ecf20Sopenharmony_ci		break;
13578c2ecf20Sopenharmony_ci	case EXT4_IOC32_GETRSVSZ:
13588c2ecf20Sopenharmony_ci		cmd = EXT4_IOC_GETRSVSZ;
13598c2ecf20Sopenharmony_ci		break;
13608c2ecf20Sopenharmony_ci	case EXT4_IOC32_SETRSVSZ:
13618c2ecf20Sopenharmony_ci		cmd = EXT4_IOC_SETRSVSZ;
13628c2ecf20Sopenharmony_ci		break;
13638c2ecf20Sopenharmony_ci	case EXT4_IOC32_GROUP_ADD: {
13648c2ecf20Sopenharmony_ci		struct compat_ext4_new_group_input __user *uinput;
13658c2ecf20Sopenharmony_ci		struct ext4_new_group_data input;
13668c2ecf20Sopenharmony_ci		int err;
13678c2ecf20Sopenharmony_ci
13688c2ecf20Sopenharmony_ci		uinput = compat_ptr(arg);
13698c2ecf20Sopenharmony_ci		err = get_user(input.group, &uinput->group);
13708c2ecf20Sopenharmony_ci		err |= get_user(input.block_bitmap, &uinput->block_bitmap);
13718c2ecf20Sopenharmony_ci		err |= get_user(input.inode_bitmap, &uinput->inode_bitmap);
13728c2ecf20Sopenharmony_ci		err |= get_user(input.inode_table, &uinput->inode_table);
13738c2ecf20Sopenharmony_ci		err |= get_user(input.blocks_count, &uinput->blocks_count);
13748c2ecf20Sopenharmony_ci		err |= get_user(input.reserved_blocks,
13758c2ecf20Sopenharmony_ci				&uinput->reserved_blocks);
13768c2ecf20Sopenharmony_ci		if (err)
13778c2ecf20Sopenharmony_ci			return -EFAULT;
13788c2ecf20Sopenharmony_ci		return ext4_ioctl_group_add(file, &input);
13798c2ecf20Sopenharmony_ci	}
13808c2ecf20Sopenharmony_ci	case EXT4_IOC_MOVE_EXT:
13818c2ecf20Sopenharmony_ci	case EXT4_IOC_RESIZE_FS:
13828c2ecf20Sopenharmony_ci	case FITRIM:
13838c2ecf20Sopenharmony_ci	case EXT4_IOC_PRECACHE_EXTENTS:
13848c2ecf20Sopenharmony_ci	case FS_IOC_SET_ENCRYPTION_POLICY:
13858c2ecf20Sopenharmony_ci	case FS_IOC_GET_ENCRYPTION_PWSALT:
13868c2ecf20Sopenharmony_ci	case FS_IOC_GET_ENCRYPTION_POLICY:
13878c2ecf20Sopenharmony_ci	case FS_IOC_GET_ENCRYPTION_POLICY_EX:
13888c2ecf20Sopenharmony_ci	case FS_IOC_ADD_ENCRYPTION_KEY:
13898c2ecf20Sopenharmony_ci	case FS_IOC_REMOVE_ENCRYPTION_KEY:
13908c2ecf20Sopenharmony_ci	case FS_IOC_REMOVE_ENCRYPTION_KEY_ALL_USERS:
13918c2ecf20Sopenharmony_ci	case FS_IOC_GET_ENCRYPTION_KEY_STATUS:
13928c2ecf20Sopenharmony_ci	case FS_IOC_GET_ENCRYPTION_NONCE:
13938c2ecf20Sopenharmony_ci	case EXT4_IOC_SHUTDOWN:
13948c2ecf20Sopenharmony_ci	case FS_IOC_GETFSMAP:
13958c2ecf20Sopenharmony_ci	case FS_IOC_ENABLE_VERITY:
13968c2ecf20Sopenharmony_ci	case FS_IOC_MEASURE_VERITY:
13978c2ecf20Sopenharmony_ci	case EXT4_IOC_CLEAR_ES_CACHE:
13988c2ecf20Sopenharmony_ci	case EXT4_IOC_GETSTATE:
13998c2ecf20Sopenharmony_ci	case EXT4_IOC_GET_ES_CACHE:
14008c2ecf20Sopenharmony_ci	case FS_IOC_FSGETXATTR:
14018c2ecf20Sopenharmony_ci	case FS_IOC_FSSETXATTR:
14028c2ecf20Sopenharmony_ci		break;
14038c2ecf20Sopenharmony_ci	default:
14048c2ecf20Sopenharmony_ci		return -ENOIOCTLCMD;
14058c2ecf20Sopenharmony_ci	}
14068c2ecf20Sopenharmony_ci	return ext4_ioctl(file, cmd, (unsigned long) compat_ptr(arg));
14078c2ecf20Sopenharmony_ci}
14088c2ecf20Sopenharmony_ci#endif
1409