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