18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * fs/f2fs/file.c
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (c) 2012 Samsung Electronics Co., Ltd.
68c2ecf20Sopenharmony_ci *             http://www.samsung.com/
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci#include <linux/fs.h>
98c2ecf20Sopenharmony_ci#include <linux/f2fs_fs.h>
108c2ecf20Sopenharmony_ci#include <linux/stat.h>
118c2ecf20Sopenharmony_ci#include <linux/buffer_head.h>
128c2ecf20Sopenharmony_ci#include <linux/writeback.h>
138c2ecf20Sopenharmony_ci#include <linux/blkdev.h>
148c2ecf20Sopenharmony_ci#include <linux/falloc.h>
158c2ecf20Sopenharmony_ci#include <linux/types.h>
168c2ecf20Sopenharmony_ci#include <linux/compat.h>
178c2ecf20Sopenharmony_ci#include <linux/uaccess.h>
188c2ecf20Sopenharmony_ci#include <linux/mount.h>
198c2ecf20Sopenharmony_ci#include <linux/pagevec.h>
208c2ecf20Sopenharmony_ci#include <linux/uio.h>
218c2ecf20Sopenharmony_ci#include <linux/uuid.h>
228c2ecf20Sopenharmony_ci#include <linux/file.h>
238c2ecf20Sopenharmony_ci#include <linux/nls.h>
248c2ecf20Sopenharmony_ci#include <linux/sched/signal.h>
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci#include "f2fs.h"
278c2ecf20Sopenharmony_ci#include "node.h"
288c2ecf20Sopenharmony_ci#include "segment.h"
298c2ecf20Sopenharmony_ci#include "xattr.h"
308c2ecf20Sopenharmony_ci#include "acl.h"
318c2ecf20Sopenharmony_ci#include "gc.h"
328c2ecf20Sopenharmony_ci#include "trace.h"
338c2ecf20Sopenharmony_ci#include <trace/events/f2fs.h>
348c2ecf20Sopenharmony_ci#include <uapi/linux/f2fs.h>
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_cistatic vm_fault_t f2fs_filemap_fault(struct vm_fault *vmf)
378c2ecf20Sopenharmony_ci{
388c2ecf20Sopenharmony_ci	struct inode *inode = file_inode(vmf->vma->vm_file);
398c2ecf20Sopenharmony_ci	vm_fault_t ret;
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci	down_read(&F2FS_I(inode)->i_mmap_sem);
428c2ecf20Sopenharmony_ci	ret = filemap_fault(vmf);
438c2ecf20Sopenharmony_ci	up_read(&F2FS_I(inode)->i_mmap_sem);
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci	if (ret & VM_FAULT_LOCKED)
468c2ecf20Sopenharmony_ci		f2fs_update_iostat(F2FS_I_SB(inode), APP_MAPPED_READ_IO,
478c2ecf20Sopenharmony_ci							F2FS_BLKSIZE);
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci	trace_f2fs_filemap_fault(inode, vmf->pgoff, (unsigned long)ret);
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci	return ret;
528c2ecf20Sopenharmony_ci}
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_cistatic vm_fault_t f2fs_vm_page_mkwrite(struct vm_fault *vmf)
558c2ecf20Sopenharmony_ci{
568c2ecf20Sopenharmony_ci	struct page *page = vmf->page;
578c2ecf20Sopenharmony_ci	struct inode *inode = file_inode(vmf->vma->vm_file);
588c2ecf20Sopenharmony_ci	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
598c2ecf20Sopenharmony_ci	struct dnode_of_data dn;
608c2ecf20Sopenharmony_ci	bool need_alloc = true;
618c2ecf20Sopenharmony_ci	int err = 0;
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci	if (unlikely(IS_IMMUTABLE(inode)))
648c2ecf20Sopenharmony_ci		return VM_FAULT_SIGBUS;
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci	if (unlikely(f2fs_cp_error(sbi))) {
678c2ecf20Sopenharmony_ci		err = -EIO;
688c2ecf20Sopenharmony_ci		goto err;
698c2ecf20Sopenharmony_ci	}
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci	if (!f2fs_is_checkpoint_ready(sbi)) {
728c2ecf20Sopenharmony_ci		err = -ENOSPC;
738c2ecf20Sopenharmony_ci		goto err;
748c2ecf20Sopenharmony_ci	}
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci#ifdef CONFIG_F2FS_FS_COMPRESSION
778c2ecf20Sopenharmony_ci	if (f2fs_compressed_file(inode)) {
788c2ecf20Sopenharmony_ci		int ret = f2fs_is_compressed_cluster(inode, page->index);
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci		if (ret < 0) {
818c2ecf20Sopenharmony_ci			err = ret;
828c2ecf20Sopenharmony_ci			goto err;
838c2ecf20Sopenharmony_ci		} else if (ret) {
848c2ecf20Sopenharmony_ci			if (ret < F2FS_I(inode)->i_cluster_size) {
858c2ecf20Sopenharmony_ci				err = -EAGAIN;
868c2ecf20Sopenharmony_ci				goto err;
878c2ecf20Sopenharmony_ci			}
888c2ecf20Sopenharmony_ci			need_alloc = false;
898c2ecf20Sopenharmony_ci		}
908c2ecf20Sopenharmony_ci	}
918c2ecf20Sopenharmony_ci#endif
928c2ecf20Sopenharmony_ci	/* should do out of any locked page */
938c2ecf20Sopenharmony_ci	if (need_alloc)
948c2ecf20Sopenharmony_ci		f2fs_balance_fs(sbi, true);
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci	sb_start_pagefault(inode->i_sb);
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	f2fs_bug_on(sbi, f2fs_has_inline_data(inode));
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci	file_update_time(vmf->vma->vm_file);
1018c2ecf20Sopenharmony_ci	down_read(&F2FS_I(inode)->i_mmap_sem);
1028c2ecf20Sopenharmony_ci	lock_page(page);
1038c2ecf20Sopenharmony_ci	if (unlikely(page->mapping != inode->i_mapping ||
1048c2ecf20Sopenharmony_ci			page_offset(page) > i_size_read(inode) ||
1058c2ecf20Sopenharmony_ci			!PageUptodate(page))) {
1068c2ecf20Sopenharmony_ci		unlock_page(page);
1078c2ecf20Sopenharmony_ci		err = -EFAULT;
1088c2ecf20Sopenharmony_ci		goto out_sem;
1098c2ecf20Sopenharmony_ci	}
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	if (need_alloc) {
1128c2ecf20Sopenharmony_ci		/* block allocation */
1138c2ecf20Sopenharmony_ci		f2fs_do_map_lock(sbi, F2FS_GET_BLOCK_PRE_AIO, true);
1148c2ecf20Sopenharmony_ci		set_new_dnode(&dn, inode, NULL, NULL, 0);
1158c2ecf20Sopenharmony_ci		err = f2fs_get_block(&dn, page->index);
1168c2ecf20Sopenharmony_ci		f2fs_put_dnode(&dn);
1178c2ecf20Sopenharmony_ci		f2fs_do_map_lock(sbi, F2FS_GET_BLOCK_PRE_AIO, false);
1188c2ecf20Sopenharmony_ci	}
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci#ifdef CONFIG_F2FS_FS_COMPRESSION
1218c2ecf20Sopenharmony_ci	if (!need_alloc) {
1228c2ecf20Sopenharmony_ci		set_new_dnode(&dn, inode, NULL, NULL, 0);
1238c2ecf20Sopenharmony_ci		err = f2fs_get_dnode_of_data(&dn, page->index, LOOKUP_NODE);
1248c2ecf20Sopenharmony_ci		f2fs_put_dnode(&dn);
1258c2ecf20Sopenharmony_ci	}
1268c2ecf20Sopenharmony_ci#endif
1278c2ecf20Sopenharmony_ci	if (err) {
1288c2ecf20Sopenharmony_ci		unlock_page(page);
1298c2ecf20Sopenharmony_ci		goto out_sem;
1308c2ecf20Sopenharmony_ci	}
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci	f2fs_wait_on_page_writeback(page, DATA, false, true);
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci	/* wait for GCed page writeback via META_MAPPING */
1358c2ecf20Sopenharmony_ci	f2fs_wait_on_block_writeback(inode, dn.data_blkaddr);
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci	/*
1388c2ecf20Sopenharmony_ci	 * check to see if the page is mapped already (no holes)
1398c2ecf20Sopenharmony_ci	 */
1408c2ecf20Sopenharmony_ci	if (PageMappedToDisk(page))
1418c2ecf20Sopenharmony_ci		goto out_sem;
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci	/* page is wholly or partially inside EOF */
1448c2ecf20Sopenharmony_ci	if (((loff_t)(page->index + 1) << PAGE_SHIFT) >
1458c2ecf20Sopenharmony_ci						i_size_read(inode)) {
1468c2ecf20Sopenharmony_ci		loff_t offset;
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci		offset = i_size_read(inode) & ~PAGE_MASK;
1498c2ecf20Sopenharmony_ci		zero_user_segment(page, offset, PAGE_SIZE);
1508c2ecf20Sopenharmony_ci	}
1518c2ecf20Sopenharmony_ci	set_page_dirty(page);
1528c2ecf20Sopenharmony_ci	if (!PageUptodate(page))
1538c2ecf20Sopenharmony_ci		SetPageUptodate(page);
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci	f2fs_update_iostat(sbi, APP_MAPPED_IO, F2FS_BLKSIZE);
1568c2ecf20Sopenharmony_ci	f2fs_update_time(sbi, REQ_TIME);
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	trace_f2fs_vm_page_mkwrite(page, DATA);
1598c2ecf20Sopenharmony_ciout_sem:
1608c2ecf20Sopenharmony_ci	up_read(&F2FS_I(inode)->i_mmap_sem);
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci	sb_end_pagefault(inode->i_sb);
1638c2ecf20Sopenharmony_cierr:
1648c2ecf20Sopenharmony_ci	return block_page_mkwrite_return(err);
1658c2ecf20Sopenharmony_ci}
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_cistatic const struct vm_operations_struct f2fs_file_vm_ops = {
1688c2ecf20Sopenharmony_ci	.fault		= f2fs_filemap_fault,
1698c2ecf20Sopenharmony_ci	.map_pages	= filemap_map_pages,
1708c2ecf20Sopenharmony_ci	.page_mkwrite	= f2fs_vm_page_mkwrite,
1718c2ecf20Sopenharmony_ci};
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_cistatic int get_parent_ino(struct inode *inode, nid_t *pino)
1748c2ecf20Sopenharmony_ci{
1758c2ecf20Sopenharmony_ci	struct dentry *dentry;
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci	/*
1788c2ecf20Sopenharmony_ci	 * Make sure to get the non-deleted alias.  The alias associated with
1798c2ecf20Sopenharmony_ci	 * the open file descriptor being fsync()'ed may be deleted already.
1808c2ecf20Sopenharmony_ci	 */
1818c2ecf20Sopenharmony_ci	dentry = d_find_alias(inode);
1828c2ecf20Sopenharmony_ci	if (!dentry)
1838c2ecf20Sopenharmony_ci		return 0;
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci	*pino = parent_ino(dentry);
1868c2ecf20Sopenharmony_ci	dput(dentry);
1878c2ecf20Sopenharmony_ci	return 1;
1888c2ecf20Sopenharmony_ci}
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_cistatic inline enum cp_reason_type need_do_checkpoint(struct inode *inode)
1918c2ecf20Sopenharmony_ci{
1928c2ecf20Sopenharmony_ci	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
1938c2ecf20Sopenharmony_ci	enum cp_reason_type cp_reason = CP_NO_NEEDED;
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci	if (!S_ISREG(inode->i_mode))
1968c2ecf20Sopenharmony_ci		cp_reason = CP_NON_REGULAR;
1978c2ecf20Sopenharmony_ci	else if (f2fs_compressed_file(inode))
1988c2ecf20Sopenharmony_ci		cp_reason = CP_COMPRESSED;
1998c2ecf20Sopenharmony_ci	else if (inode->i_nlink != 1)
2008c2ecf20Sopenharmony_ci		cp_reason = CP_HARDLINK;
2018c2ecf20Sopenharmony_ci	else if (is_sbi_flag_set(sbi, SBI_NEED_CP))
2028c2ecf20Sopenharmony_ci		cp_reason = CP_SB_NEED_CP;
2038c2ecf20Sopenharmony_ci	else if (file_wrong_pino(inode))
2048c2ecf20Sopenharmony_ci		cp_reason = CP_WRONG_PINO;
2058c2ecf20Sopenharmony_ci	else if (!f2fs_space_for_roll_forward(sbi))
2068c2ecf20Sopenharmony_ci		cp_reason = CP_NO_SPC_ROLL;
2078c2ecf20Sopenharmony_ci	else if (!f2fs_is_checkpointed_node(sbi, F2FS_I(inode)->i_pino))
2088c2ecf20Sopenharmony_ci		cp_reason = CP_NODE_NEED_CP;
2098c2ecf20Sopenharmony_ci	else if (test_opt(sbi, FASTBOOT))
2108c2ecf20Sopenharmony_ci		cp_reason = CP_FASTBOOT_MODE;
2118c2ecf20Sopenharmony_ci	else if (F2FS_OPTION(sbi).active_logs == 2)
2128c2ecf20Sopenharmony_ci		cp_reason = CP_SPEC_LOG_NUM;
2138c2ecf20Sopenharmony_ci	else if (F2FS_OPTION(sbi).fsync_mode == FSYNC_MODE_STRICT &&
2148c2ecf20Sopenharmony_ci		f2fs_need_dentry_mark(sbi, inode->i_ino) &&
2158c2ecf20Sopenharmony_ci		f2fs_exist_written_data(sbi, F2FS_I(inode)->i_pino,
2168c2ecf20Sopenharmony_ci							TRANS_DIR_INO))
2178c2ecf20Sopenharmony_ci		cp_reason = CP_RECOVER_DIR;
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci	return cp_reason;
2208c2ecf20Sopenharmony_ci}
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_cistatic bool need_inode_page_update(struct f2fs_sb_info *sbi, nid_t ino)
2238c2ecf20Sopenharmony_ci{
2248c2ecf20Sopenharmony_ci	struct page *i = find_get_page(NODE_MAPPING(sbi), ino);
2258c2ecf20Sopenharmony_ci	bool ret = false;
2268c2ecf20Sopenharmony_ci	/* But we need to avoid that there are some inode updates */
2278c2ecf20Sopenharmony_ci	if ((i && PageDirty(i)) || f2fs_need_inode_block_update(sbi, ino))
2288c2ecf20Sopenharmony_ci		ret = true;
2298c2ecf20Sopenharmony_ci	f2fs_put_page(i, 0);
2308c2ecf20Sopenharmony_ci	return ret;
2318c2ecf20Sopenharmony_ci}
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_cistatic void try_to_fix_pino(struct inode *inode)
2348c2ecf20Sopenharmony_ci{
2358c2ecf20Sopenharmony_ci	struct f2fs_inode_info *fi = F2FS_I(inode);
2368c2ecf20Sopenharmony_ci	nid_t pino;
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci	down_write(&fi->i_sem);
2398c2ecf20Sopenharmony_ci	if (file_wrong_pino(inode) && inode->i_nlink == 1 &&
2408c2ecf20Sopenharmony_ci			get_parent_ino(inode, &pino)) {
2418c2ecf20Sopenharmony_ci		f2fs_i_pino_write(inode, pino);
2428c2ecf20Sopenharmony_ci		file_got_pino(inode);
2438c2ecf20Sopenharmony_ci	}
2448c2ecf20Sopenharmony_ci	up_write(&fi->i_sem);
2458c2ecf20Sopenharmony_ci}
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_cistatic int f2fs_do_sync_file(struct file *file, loff_t start, loff_t end,
2488c2ecf20Sopenharmony_ci						int datasync, bool atomic)
2498c2ecf20Sopenharmony_ci{
2508c2ecf20Sopenharmony_ci	struct inode *inode = file->f_mapping->host;
2518c2ecf20Sopenharmony_ci	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
2528c2ecf20Sopenharmony_ci	nid_t ino = inode->i_ino;
2538c2ecf20Sopenharmony_ci	int ret = 0;
2548c2ecf20Sopenharmony_ci	enum cp_reason_type cp_reason = 0;
2558c2ecf20Sopenharmony_ci	struct writeback_control wbc = {
2568c2ecf20Sopenharmony_ci		.sync_mode = WB_SYNC_ALL,
2578c2ecf20Sopenharmony_ci		.nr_to_write = LONG_MAX,
2588c2ecf20Sopenharmony_ci		.for_reclaim = 0,
2598c2ecf20Sopenharmony_ci	};
2608c2ecf20Sopenharmony_ci	unsigned int seq_id = 0;
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci	if (unlikely(f2fs_readonly(inode->i_sb)))
2638c2ecf20Sopenharmony_ci		return 0;
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci	trace_f2fs_sync_file_enter(inode);
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci	if (S_ISDIR(inode->i_mode))
2688c2ecf20Sopenharmony_ci		goto go_write;
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci	/* if fdatasync is triggered, let's do in-place-update */
2718c2ecf20Sopenharmony_ci	if (datasync || get_dirty_pages(inode) <= SM_I(sbi)->min_fsync_blocks)
2728c2ecf20Sopenharmony_ci		set_inode_flag(inode, FI_NEED_IPU);
2738c2ecf20Sopenharmony_ci	ret = file_write_and_wait_range(file, start, end);
2748c2ecf20Sopenharmony_ci	clear_inode_flag(inode, FI_NEED_IPU);
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ci	if (ret || is_sbi_flag_set(sbi, SBI_CP_DISABLED)) {
2778c2ecf20Sopenharmony_ci		trace_f2fs_sync_file_exit(inode, cp_reason, datasync, ret);
2788c2ecf20Sopenharmony_ci		return ret;
2798c2ecf20Sopenharmony_ci	}
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci	/* if the inode is dirty, let's recover all the time */
2828c2ecf20Sopenharmony_ci	if (!f2fs_skip_inode_update(inode, datasync)) {
2838c2ecf20Sopenharmony_ci		f2fs_write_inode(inode, NULL);
2848c2ecf20Sopenharmony_ci		goto go_write;
2858c2ecf20Sopenharmony_ci	}
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ci	/*
2888c2ecf20Sopenharmony_ci	 * if there is no written data, don't waste time to write recovery info.
2898c2ecf20Sopenharmony_ci	 */
2908c2ecf20Sopenharmony_ci	if (!is_inode_flag_set(inode, FI_APPEND_WRITE) &&
2918c2ecf20Sopenharmony_ci			!f2fs_exist_written_data(sbi, ino, APPEND_INO)) {
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci		/* it may call write_inode just prior to fsync */
2948c2ecf20Sopenharmony_ci		if (need_inode_page_update(sbi, ino))
2958c2ecf20Sopenharmony_ci			goto go_write;
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci		if (is_inode_flag_set(inode, FI_UPDATE_WRITE) ||
2988c2ecf20Sopenharmony_ci				f2fs_exist_written_data(sbi, ino, UPDATE_INO))
2998c2ecf20Sopenharmony_ci			goto flush_out;
3008c2ecf20Sopenharmony_ci		goto out;
3018c2ecf20Sopenharmony_ci	}
3028c2ecf20Sopenharmony_cigo_write:
3038c2ecf20Sopenharmony_ci	/*
3048c2ecf20Sopenharmony_ci	 * Both of fdatasync() and fsync() are able to be recovered from
3058c2ecf20Sopenharmony_ci	 * sudden-power-off.
3068c2ecf20Sopenharmony_ci	 */
3078c2ecf20Sopenharmony_ci	down_read(&F2FS_I(inode)->i_sem);
3088c2ecf20Sopenharmony_ci	cp_reason = need_do_checkpoint(inode);
3098c2ecf20Sopenharmony_ci	up_read(&F2FS_I(inode)->i_sem);
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci	if (cp_reason) {
3128c2ecf20Sopenharmony_ci		/* all the dirty node pages should be flushed for POR */
3138c2ecf20Sopenharmony_ci		ret = f2fs_sync_fs(inode->i_sb, 1);
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_ci		/*
3168c2ecf20Sopenharmony_ci		 * We've secured consistency through sync_fs. Following pino
3178c2ecf20Sopenharmony_ci		 * will be used only for fsynced inodes after checkpoint.
3188c2ecf20Sopenharmony_ci		 */
3198c2ecf20Sopenharmony_ci		try_to_fix_pino(inode);
3208c2ecf20Sopenharmony_ci		clear_inode_flag(inode, FI_APPEND_WRITE);
3218c2ecf20Sopenharmony_ci		clear_inode_flag(inode, FI_UPDATE_WRITE);
3228c2ecf20Sopenharmony_ci		goto out;
3238c2ecf20Sopenharmony_ci	}
3248c2ecf20Sopenharmony_cisync_nodes:
3258c2ecf20Sopenharmony_ci	atomic_inc(&sbi->wb_sync_req[NODE]);
3268c2ecf20Sopenharmony_ci	ret = f2fs_fsync_node_pages(sbi, inode, &wbc, atomic, &seq_id);
3278c2ecf20Sopenharmony_ci	atomic_dec(&sbi->wb_sync_req[NODE]);
3288c2ecf20Sopenharmony_ci	if (ret)
3298c2ecf20Sopenharmony_ci		goto out;
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci	/* if cp_error was enabled, we should avoid infinite loop */
3328c2ecf20Sopenharmony_ci	if (unlikely(f2fs_cp_error(sbi))) {
3338c2ecf20Sopenharmony_ci		ret = -EIO;
3348c2ecf20Sopenharmony_ci		goto out;
3358c2ecf20Sopenharmony_ci	}
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci	if (f2fs_need_inode_block_update(sbi, ino)) {
3388c2ecf20Sopenharmony_ci		f2fs_mark_inode_dirty_sync(inode, true);
3398c2ecf20Sopenharmony_ci		f2fs_write_inode(inode, NULL);
3408c2ecf20Sopenharmony_ci		goto sync_nodes;
3418c2ecf20Sopenharmony_ci	}
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci	/*
3448c2ecf20Sopenharmony_ci	 * If it's atomic_write, it's just fine to keep write ordering. So
3458c2ecf20Sopenharmony_ci	 * here we don't need to wait for node write completion, since we use
3468c2ecf20Sopenharmony_ci	 * node chain which serializes node blocks. If one of node writes are
3478c2ecf20Sopenharmony_ci	 * reordered, we can see simply broken chain, resulting in stopping
3488c2ecf20Sopenharmony_ci	 * roll-forward recovery. It means we'll recover all or none node blocks
3498c2ecf20Sopenharmony_ci	 * given fsync mark.
3508c2ecf20Sopenharmony_ci	 */
3518c2ecf20Sopenharmony_ci	if (!atomic) {
3528c2ecf20Sopenharmony_ci		ret = f2fs_wait_on_node_pages_writeback(sbi, seq_id);
3538c2ecf20Sopenharmony_ci		if (ret)
3548c2ecf20Sopenharmony_ci			goto out;
3558c2ecf20Sopenharmony_ci	}
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci	/* once recovery info is written, don't need to tack this */
3588c2ecf20Sopenharmony_ci	f2fs_remove_ino_entry(sbi, ino, APPEND_INO);
3598c2ecf20Sopenharmony_ci	clear_inode_flag(inode, FI_APPEND_WRITE);
3608c2ecf20Sopenharmony_ciflush_out:
3618c2ecf20Sopenharmony_ci	if (!atomic && F2FS_OPTION(sbi).fsync_mode != FSYNC_MODE_NOBARRIER)
3628c2ecf20Sopenharmony_ci		ret = f2fs_issue_flush(sbi, inode->i_ino);
3638c2ecf20Sopenharmony_ci	if (!ret) {
3648c2ecf20Sopenharmony_ci		f2fs_remove_ino_entry(sbi, ino, UPDATE_INO);
3658c2ecf20Sopenharmony_ci		clear_inode_flag(inode, FI_UPDATE_WRITE);
3668c2ecf20Sopenharmony_ci		f2fs_remove_ino_entry(sbi, ino, FLUSH_INO);
3678c2ecf20Sopenharmony_ci	}
3688c2ecf20Sopenharmony_ci	f2fs_update_time(sbi, REQ_TIME);
3698c2ecf20Sopenharmony_ciout:
3708c2ecf20Sopenharmony_ci	trace_f2fs_sync_file_exit(inode, cp_reason, datasync, ret);
3718c2ecf20Sopenharmony_ci	f2fs_trace_ios(NULL, 1);
3728c2ecf20Sopenharmony_ci	return ret;
3738c2ecf20Sopenharmony_ci}
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ciint f2fs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
3768c2ecf20Sopenharmony_ci{
3778c2ecf20Sopenharmony_ci	if (unlikely(f2fs_cp_error(F2FS_I_SB(file_inode(file)))))
3788c2ecf20Sopenharmony_ci		return -EIO;
3798c2ecf20Sopenharmony_ci	return f2fs_do_sync_file(file, start, end, datasync, false);
3808c2ecf20Sopenharmony_ci}
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_cistatic bool __found_offset(struct address_space *mapping, block_t blkaddr,
3838c2ecf20Sopenharmony_ci				pgoff_t index, int whence)
3848c2ecf20Sopenharmony_ci{
3858c2ecf20Sopenharmony_ci	switch (whence) {
3868c2ecf20Sopenharmony_ci	case SEEK_DATA:
3878c2ecf20Sopenharmony_ci		if (__is_valid_data_blkaddr(blkaddr))
3888c2ecf20Sopenharmony_ci			return true;
3898c2ecf20Sopenharmony_ci		if (blkaddr == NEW_ADDR &&
3908c2ecf20Sopenharmony_ci		    xa_get_mark(&mapping->i_pages, index, PAGECACHE_TAG_DIRTY))
3918c2ecf20Sopenharmony_ci			return true;
3928c2ecf20Sopenharmony_ci		break;
3938c2ecf20Sopenharmony_ci	case SEEK_HOLE:
3948c2ecf20Sopenharmony_ci		if (blkaddr == NULL_ADDR)
3958c2ecf20Sopenharmony_ci			return true;
3968c2ecf20Sopenharmony_ci		break;
3978c2ecf20Sopenharmony_ci	}
3988c2ecf20Sopenharmony_ci	return false;
3998c2ecf20Sopenharmony_ci}
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_cistatic loff_t f2fs_seek_block(struct file *file, loff_t offset, int whence)
4028c2ecf20Sopenharmony_ci{
4038c2ecf20Sopenharmony_ci	struct inode *inode = file->f_mapping->host;
4048c2ecf20Sopenharmony_ci	loff_t maxbytes = inode->i_sb->s_maxbytes;
4058c2ecf20Sopenharmony_ci	struct dnode_of_data dn;
4068c2ecf20Sopenharmony_ci	pgoff_t pgofs, end_offset;
4078c2ecf20Sopenharmony_ci	loff_t data_ofs = offset;
4088c2ecf20Sopenharmony_ci	loff_t isize;
4098c2ecf20Sopenharmony_ci	int err = 0;
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_ci	inode_lock(inode);
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_ci	isize = i_size_read(inode);
4148c2ecf20Sopenharmony_ci	if (offset >= isize)
4158c2ecf20Sopenharmony_ci		goto fail;
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_ci	/* handle inline data case */
4188c2ecf20Sopenharmony_ci	if (f2fs_has_inline_data(inode)) {
4198c2ecf20Sopenharmony_ci		if (whence == SEEK_HOLE) {
4208c2ecf20Sopenharmony_ci			data_ofs = isize;
4218c2ecf20Sopenharmony_ci			goto found;
4228c2ecf20Sopenharmony_ci		} else if (whence == SEEK_DATA) {
4238c2ecf20Sopenharmony_ci			data_ofs = offset;
4248c2ecf20Sopenharmony_ci			goto found;
4258c2ecf20Sopenharmony_ci		}
4268c2ecf20Sopenharmony_ci	}
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci	pgofs = (pgoff_t)(offset >> PAGE_SHIFT);
4298c2ecf20Sopenharmony_ci
4308c2ecf20Sopenharmony_ci	for (; data_ofs < isize; data_ofs = (loff_t)pgofs << PAGE_SHIFT) {
4318c2ecf20Sopenharmony_ci		set_new_dnode(&dn, inode, NULL, NULL, 0);
4328c2ecf20Sopenharmony_ci		err = f2fs_get_dnode_of_data(&dn, pgofs, LOOKUP_NODE);
4338c2ecf20Sopenharmony_ci		if (err && err != -ENOENT) {
4348c2ecf20Sopenharmony_ci			goto fail;
4358c2ecf20Sopenharmony_ci		} else if (err == -ENOENT) {
4368c2ecf20Sopenharmony_ci			/* direct node does not exists */
4378c2ecf20Sopenharmony_ci			if (whence == SEEK_DATA) {
4388c2ecf20Sopenharmony_ci				pgofs = f2fs_get_next_page_offset(&dn, pgofs);
4398c2ecf20Sopenharmony_ci				continue;
4408c2ecf20Sopenharmony_ci			} else {
4418c2ecf20Sopenharmony_ci				goto found;
4428c2ecf20Sopenharmony_ci			}
4438c2ecf20Sopenharmony_ci		}
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_ci		end_offset = ADDRS_PER_PAGE(dn.node_page, inode);
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci		/* find data/hole in dnode block */
4488c2ecf20Sopenharmony_ci		for (; dn.ofs_in_node < end_offset;
4498c2ecf20Sopenharmony_ci				dn.ofs_in_node++, pgofs++,
4508c2ecf20Sopenharmony_ci				data_ofs = (loff_t)pgofs << PAGE_SHIFT) {
4518c2ecf20Sopenharmony_ci			block_t blkaddr;
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_ci			blkaddr = f2fs_data_blkaddr(&dn);
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci			if (__is_valid_data_blkaddr(blkaddr) &&
4568c2ecf20Sopenharmony_ci				!f2fs_is_valid_blkaddr(F2FS_I_SB(inode),
4578c2ecf20Sopenharmony_ci					blkaddr, DATA_GENERIC_ENHANCE)) {
4588c2ecf20Sopenharmony_ci				f2fs_put_dnode(&dn);
4598c2ecf20Sopenharmony_ci				goto fail;
4608c2ecf20Sopenharmony_ci			}
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_ci			if (__found_offset(file->f_mapping, blkaddr,
4638c2ecf20Sopenharmony_ci							pgofs, whence)) {
4648c2ecf20Sopenharmony_ci				f2fs_put_dnode(&dn);
4658c2ecf20Sopenharmony_ci				goto found;
4668c2ecf20Sopenharmony_ci			}
4678c2ecf20Sopenharmony_ci		}
4688c2ecf20Sopenharmony_ci		f2fs_put_dnode(&dn);
4698c2ecf20Sopenharmony_ci	}
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci	if (whence == SEEK_DATA)
4728c2ecf20Sopenharmony_ci		goto fail;
4738c2ecf20Sopenharmony_cifound:
4748c2ecf20Sopenharmony_ci	if (whence == SEEK_HOLE && data_ofs > isize)
4758c2ecf20Sopenharmony_ci		data_ofs = isize;
4768c2ecf20Sopenharmony_ci	inode_unlock(inode);
4778c2ecf20Sopenharmony_ci	return vfs_setpos(file, data_ofs, maxbytes);
4788c2ecf20Sopenharmony_cifail:
4798c2ecf20Sopenharmony_ci	inode_unlock(inode);
4808c2ecf20Sopenharmony_ci	return -ENXIO;
4818c2ecf20Sopenharmony_ci}
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_cistatic loff_t f2fs_llseek(struct file *file, loff_t offset, int whence)
4848c2ecf20Sopenharmony_ci{
4858c2ecf20Sopenharmony_ci	struct inode *inode = file->f_mapping->host;
4868c2ecf20Sopenharmony_ci	loff_t maxbytes = inode->i_sb->s_maxbytes;
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_ci	switch (whence) {
4898c2ecf20Sopenharmony_ci	case SEEK_SET:
4908c2ecf20Sopenharmony_ci	case SEEK_CUR:
4918c2ecf20Sopenharmony_ci	case SEEK_END:
4928c2ecf20Sopenharmony_ci		return generic_file_llseek_size(file, offset, whence,
4938c2ecf20Sopenharmony_ci						maxbytes, i_size_read(inode));
4948c2ecf20Sopenharmony_ci	case SEEK_DATA:
4958c2ecf20Sopenharmony_ci	case SEEK_HOLE:
4968c2ecf20Sopenharmony_ci		if (offset < 0)
4978c2ecf20Sopenharmony_ci			return -ENXIO;
4988c2ecf20Sopenharmony_ci		return f2fs_seek_block(file, offset, whence);
4998c2ecf20Sopenharmony_ci	}
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_ci	return -EINVAL;
5028c2ecf20Sopenharmony_ci}
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_cistatic int f2fs_file_mmap(struct file *file, struct vm_area_struct *vma)
5058c2ecf20Sopenharmony_ci{
5068c2ecf20Sopenharmony_ci	struct inode *inode = file_inode(file);
5078c2ecf20Sopenharmony_ci	int err;
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_ci	if (unlikely(f2fs_cp_error(F2FS_I_SB(inode))))
5108c2ecf20Sopenharmony_ci		return -EIO;
5118c2ecf20Sopenharmony_ci
5128c2ecf20Sopenharmony_ci	if (!f2fs_is_compress_backend_ready(inode))
5138c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_ci	/* we don't need to use inline_data strictly */
5168c2ecf20Sopenharmony_ci	err = f2fs_convert_inline_inode(inode);
5178c2ecf20Sopenharmony_ci	if (err)
5188c2ecf20Sopenharmony_ci		return err;
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_ci	file_accessed(file);
5218c2ecf20Sopenharmony_ci	vma->vm_ops = &f2fs_file_vm_ops;
5228c2ecf20Sopenharmony_ci	set_inode_flag(inode, FI_MMAP_FILE);
5238c2ecf20Sopenharmony_ci	return 0;
5248c2ecf20Sopenharmony_ci}
5258c2ecf20Sopenharmony_ci
5268c2ecf20Sopenharmony_cistatic int f2fs_file_open(struct inode *inode, struct file *filp)
5278c2ecf20Sopenharmony_ci{
5288c2ecf20Sopenharmony_ci	int err = fscrypt_file_open(inode, filp);
5298c2ecf20Sopenharmony_ci
5308c2ecf20Sopenharmony_ci	if (err)
5318c2ecf20Sopenharmony_ci		return err;
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_ci	if (!f2fs_is_compress_backend_ready(inode))
5348c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
5358c2ecf20Sopenharmony_ci
5368c2ecf20Sopenharmony_ci	err = fsverity_file_open(inode, filp);
5378c2ecf20Sopenharmony_ci	if (err)
5388c2ecf20Sopenharmony_ci		return err;
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_ci	filp->f_mode |= FMODE_NOWAIT;
5418c2ecf20Sopenharmony_ci
5428c2ecf20Sopenharmony_ci	return dquot_file_open(inode, filp);
5438c2ecf20Sopenharmony_ci}
5448c2ecf20Sopenharmony_ci
5458c2ecf20Sopenharmony_civoid f2fs_truncate_data_blocks_range(struct dnode_of_data *dn, int count)
5468c2ecf20Sopenharmony_ci{
5478c2ecf20Sopenharmony_ci	struct f2fs_sb_info *sbi = F2FS_I_SB(dn->inode);
5488c2ecf20Sopenharmony_ci	struct f2fs_node *raw_node;
5498c2ecf20Sopenharmony_ci	int nr_free = 0, ofs = dn->ofs_in_node, len = count;
5508c2ecf20Sopenharmony_ci	__le32 *addr;
5518c2ecf20Sopenharmony_ci	int base = 0;
5528c2ecf20Sopenharmony_ci	bool compressed_cluster = false;
5538c2ecf20Sopenharmony_ci	int cluster_index = 0, valid_blocks = 0;
5548c2ecf20Sopenharmony_ci	int cluster_size = F2FS_I(dn->inode)->i_cluster_size;
5558c2ecf20Sopenharmony_ci	bool released = !atomic_read(&F2FS_I(dn->inode)->i_compr_blocks);
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_ci	if (IS_INODE(dn->node_page) && f2fs_has_extra_attr(dn->inode))
5588c2ecf20Sopenharmony_ci		base = get_extra_isize(dn->inode);
5598c2ecf20Sopenharmony_ci
5608c2ecf20Sopenharmony_ci	raw_node = F2FS_NODE(dn->node_page);
5618c2ecf20Sopenharmony_ci	addr = blkaddr_in_node(raw_node) + base + ofs;
5628c2ecf20Sopenharmony_ci
5638c2ecf20Sopenharmony_ci	/* Assumption: truncateion starts with cluster */
5648c2ecf20Sopenharmony_ci	for (; count > 0; count--, addr++, dn->ofs_in_node++, cluster_index++) {
5658c2ecf20Sopenharmony_ci		block_t blkaddr = le32_to_cpu(*addr);
5668c2ecf20Sopenharmony_ci
5678c2ecf20Sopenharmony_ci		if (f2fs_compressed_file(dn->inode) &&
5688c2ecf20Sopenharmony_ci					!(cluster_index & (cluster_size - 1))) {
5698c2ecf20Sopenharmony_ci			if (compressed_cluster)
5708c2ecf20Sopenharmony_ci				f2fs_i_compr_blocks_update(dn->inode,
5718c2ecf20Sopenharmony_ci							valid_blocks, false);
5728c2ecf20Sopenharmony_ci			compressed_cluster = (blkaddr == COMPRESS_ADDR);
5738c2ecf20Sopenharmony_ci			valid_blocks = 0;
5748c2ecf20Sopenharmony_ci		}
5758c2ecf20Sopenharmony_ci
5768c2ecf20Sopenharmony_ci		if (blkaddr == NULL_ADDR)
5778c2ecf20Sopenharmony_ci			continue;
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_ci		dn->data_blkaddr = NULL_ADDR;
5808c2ecf20Sopenharmony_ci		f2fs_set_data_blkaddr(dn);
5818c2ecf20Sopenharmony_ci
5828c2ecf20Sopenharmony_ci		if (__is_valid_data_blkaddr(blkaddr)) {
5838c2ecf20Sopenharmony_ci			if (!f2fs_is_valid_blkaddr(sbi, blkaddr,
5848c2ecf20Sopenharmony_ci					DATA_GENERIC_ENHANCE))
5858c2ecf20Sopenharmony_ci				continue;
5868c2ecf20Sopenharmony_ci			if (compressed_cluster)
5878c2ecf20Sopenharmony_ci				valid_blocks++;
5888c2ecf20Sopenharmony_ci		}
5898c2ecf20Sopenharmony_ci
5908c2ecf20Sopenharmony_ci		if (dn->ofs_in_node == 0 && IS_INODE(dn->node_page))
5918c2ecf20Sopenharmony_ci			clear_inode_flag(dn->inode, FI_FIRST_BLOCK_WRITTEN);
5928c2ecf20Sopenharmony_ci
5938c2ecf20Sopenharmony_ci		f2fs_invalidate_blocks(sbi, blkaddr);
5948c2ecf20Sopenharmony_ci
5958c2ecf20Sopenharmony_ci		if (!released || blkaddr != COMPRESS_ADDR)
5968c2ecf20Sopenharmony_ci			nr_free++;
5978c2ecf20Sopenharmony_ci	}
5988c2ecf20Sopenharmony_ci
5998c2ecf20Sopenharmony_ci	if (compressed_cluster)
6008c2ecf20Sopenharmony_ci		f2fs_i_compr_blocks_update(dn->inode, valid_blocks, false);
6018c2ecf20Sopenharmony_ci
6028c2ecf20Sopenharmony_ci	if (nr_free) {
6038c2ecf20Sopenharmony_ci		pgoff_t fofs;
6048c2ecf20Sopenharmony_ci		/*
6058c2ecf20Sopenharmony_ci		 * once we invalidate valid blkaddr in range [ofs, ofs + count],
6068c2ecf20Sopenharmony_ci		 * we will invalidate all blkaddr in the whole range.
6078c2ecf20Sopenharmony_ci		 */
6088c2ecf20Sopenharmony_ci		fofs = f2fs_start_bidx_of_node(ofs_of_node(dn->node_page),
6098c2ecf20Sopenharmony_ci							dn->inode) + ofs;
6108c2ecf20Sopenharmony_ci		f2fs_update_extent_cache_range(dn, fofs, 0, len);
6118c2ecf20Sopenharmony_ci		dec_valid_block_count(sbi, dn->inode, nr_free);
6128c2ecf20Sopenharmony_ci	}
6138c2ecf20Sopenharmony_ci	dn->ofs_in_node = ofs;
6148c2ecf20Sopenharmony_ci
6158c2ecf20Sopenharmony_ci	f2fs_update_time(sbi, REQ_TIME);
6168c2ecf20Sopenharmony_ci	trace_f2fs_truncate_data_blocks_range(dn->inode, dn->nid,
6178c2ecf20Sopenharmony_ci					 dn->ofs_in_node, nr_free);
6188c2ecf20Sopenharmony_ci}
6198c2ecf20Sopenharmony_ci
6208c2ecf20Sopenharmony_civoid f2fs_truncate_data_blocks(struct dnode_of_data *dn)
6218c2ecf20Sopenharmony_ci{
6228c2ecf20Sopenharmony_ci	f2fs_truncate_data_blocks_range(dn, ADDRS_PER_BLOCK(dn->inode));
6238c2ecf20Sopenharmony_ci}
6248c2ecf20Sopenharmony_ci
6258c2ecf20Sopenharmony_cistatic int truncate_partial_data_page(struct inode *inode, u64 from,
6268c2ecf20Sopenharmony_ci								bool cache_only)
6278c2ecf20Sopenharmony_ci{
6288c2ecf20Sopenharmony_ci	loff_t offset = from & (PAGE_SIZE - 1);
6298c2ecf20Sopenharmony_ci	pgoff_t index = from >> PAGE_SHIFT;
6308c2ecf20Sopenharmony_ci	struct address_space *mapping = inode->i_mapping;
6318c2ecf20Sopenharmony_ci	struct page *page;
6328c2ecf20Sopenharmony_ci
6338c2ecf20Sopenharmony_ci	if (!offset && !cache_only)
6348c2ecf20Sopenharmony_ci		return 0;
6358c2ecf20Sopenharmony_ci
6368c2ecf20Sopenharmony_ci	if (cache_only) {
6378c2ecf20Sopenharmony_ci		page = find_lock_page(mapping, index);
6388c2ecf20Sopenharmony_ci		if (page && PageUptodate(page))
6398c2ecf20Sopenharmony_ci			goto truncate_out;
6408c2ecf20Sopenharmony_ci		f2fs_put_page(page, 1);
6418c2ecf20Sopenharmony_ci		return 0;
6428c2ecf20Sopenharmony_ci	}
6438c2ecf20Sopenharmony_ci
6448c2ecf20Sopenharmony_ci	page = f2fs_get_lock_data_page(inode, index, true);
6458c2ecf20Sopenharmony_ci	if (IS_ERR(page))
6468c2ecf20Sopenharmony_ci		return PTR_ERR(page) == -ENOENT ? 0 : PTR_ERR(page);
6478c2ecf20Sopenharmony_citruncate_out:
6488c2ecf20Sopenharmony_ci	f2fs_wait_on_page_writeback(page, DATA, true, true);
6498c2ecf20Sopenharmony_ci	zero_user(page, offset, PAGE_SIZE - offset);
6508c2ecf20Sopenharmony_ci
6518c2ecf20Sopenharmony_ci	/* An encrypted inode should have a key and truncate the last page. */
6528c2ecf20Sopenharmony_ci	f2fs_bug_on(F2FS_I_SB(inode), cache_only && IS_ENCRYPTED(inode));
6538c2ecf20Sopenharmony_ci	if (!cache_only)
6548c2ecf20Sopenharmony_ci		set_page_dirty(page);
6558c2ecf20Sopenharmony_ci	f2fs_put_page(page, 1);
6568c2ecf20Sopenharmony_ci	return 0;
6578c2ecf20Sopenharmony_ci}
6588c2ecf20Sopenharmony_ci
6598c2ecf20Sopenharmony_ciint f2fs_do_truncate_blocks(struct inode *inode, u64 from, bool lock)
6608c2ecf20Sopenharmony_ci{
6618c2ecf20Sopenharmony_ci	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
6628c2ecf20Sopenharmony_ci	struct dnode_of_data dn;
6638c2ecf20Sopenharmony_ci	pgoff_t free_from;
6648c2ecf20Sopenharmony_ci	int count = 0, err = 0;
6658c2ecf20Sopenharmony_ci	struct page *ipage;
6668c2ecf20Sopenharmony_ci	bool truncate_page = false;
6678c2ecf20Sopenharmony_ci
6688c2ecf20Sopenharmony_ci	trace_f2fs_truncate_blocks_enter(inode, from);
6698c2ecf20Sopenharmony_ci
6708c2ecf20Sopenharmony_ci	free_from = (pgoff_t)F2FS_BLK_ALIGN(from);
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_ci	if (free_from >= sbi->max_file_blocks)
6738c2ecf20Sopenharmony_ci		goto free_partial;
6748c2ecf20Sopenharmony_ci
6758c2ecf20Sopenharmony_ci	if (lock)
6768c2ecf20Sopenharmony_ci		f2fs_lock_op(sbi);
6778c2ecf20Sopenharmony_ci
6788c2ecf20Sopenharmony_ci	ipage = f2fs_get_node_page(sbi, inode->i_ino);
6798c2ecf20Sopenharmony_ci	if (IS_ERR(ipage)) {
6808c2ecf20Sopenharmony_ci		err = PTR_ERR(ipage);
6818c2ecf20Sopenharmony_ci		goto out;
6828c2ecf20Sopenharmony_ci	}
6838c2ecf20Sopenharmony_ci
6848c2ecf20Sopenharmony_ci	if (f2fs_has_inline_data(inode)) {
6858c2ecf20Sopenharmony_ci		f2fs_truncate_inline_inode(inode, ipage, from);
6868c2ecf20Sopenharmony_ci		f2fs_put_page(ipage, 1);
6878c2ecf20Sopenharmony_ci		truncate_page = true;
6888c2ecf20Sopenharmony_ci		goto out;
6898c2ecf20Sopenharmony_ci	}
6908c2ecf20Sopenharmony_ci
6918c2ecf20Sopenharmony_ci	set_new_dnode(&dn, inode, ipage, NULL, 0);
6928c2ecf20Sopenharmony_ci	err = f2fs_get_dnode_of_data(&dn, free_from, LOOKUP_NODE_RA);
6938c2ecf20Sopenharmony_ci	if (err) {
6948c2ecf20Sopenharmony_ci		if (err == -ENOENT)
6958c2ecf20Sopenharmony_ci			goto free_next;
6968c2ecf20Sopenharmony_ci		goto out;
6978c2ecf20Sopenharmony_ci	}
6988c2ecf20Sopenharmony_ci
6998c2ecf20Sopenharmony_ci	count = ADDRS_PER_PAGE(dn.node_page, inode);
7008c2ecf20Sopenharmony_ci
7018c2ecf20Sopenharmony_ci	count -= dn.ofs_in_node;
7028c2ecf20Sopenharmony_ci	f2fs_bug_on(sbi, count < 0);
7038c2ecf20Sopenharmony_ci
7048c2ecf20Sopenharmony_ci	if (dn.ofs_in_node || IS_INODE(dn.node_page)) {
7058c2ecf20Sopenharmony_ci		f2fs_truncate_data_blocks_range(&dn, count);
7068c2ecf20Sopenharmony_ci		free_from += count;
7078c2ecf20Sopenharmony_ci	}
7088c2ecf20Sopenharmony_ci
7098c2ecf20Sopenharmony_ci	f2fs_put_dnode(&dn);
7108c2ecf20Sopenharmony_cifree_next:
7118c2ecf20Sopenharmony_ci	err = f2fs_truncate_inode_blocks(inode, free_from);
7128c2ecf20Sopenharmony_ciout:
7138c2ecf20Sopenharmony_ci	if (lock)
7148c2ecf20Sopenharmony_ci		f2fs_unlock_op(sbi);
7158c2ecf20Sopenharmony_cifree_partial:
7168c2ecf20Sopenharmony_ci	/* lastly zero out the first data page */
7178c2ecf20Sopenharmony_ci	if (!err)
7188c2ecf20Sopenharmony_ci		err = truncate_partial_data_page(inode, from, truncate_page);
7198c2ecf20Sopenharmony_ci
7208c2ecf20Sopenharmony_ci	trace_f2fs_truncate_blocks_exit(inode, err);
7218c2ecf20Sopenharmony_ci	return err;
7228c2ecf20Sopenharmony_ci}
7238c2ecf20Sopenharmony_ci
7248c2ecf20Sopenharmony_ciint f2fs_truncate_blocks(struct inode *inode, u64 from, bool lock)
7258c2ecf20Sopenharmony_ci{
7268c2ecf20Sopenharmony_ci	u64 free_from = from;
7278c2ecf20Sopenharmony_ci	int err;
7288c2ecf20Sopenharmony_ci
7298c2ecf20Sopenharmony_ci#ifdef CONFIG_F2FS_FS_COMPRESSION
7308c2ecf20Sopenharmony_ci	/*
7318c2ecf20Sopenharmony_ci	 * for compressed file, only support cluster size
7328c2ecf20Sopenharmony_ci	 * aligned truncation.
7338c2ecf20Sopenharmony_ci	 */
7348c2ecf20Sopenharmony_ci	if (f2fs_compressed_file(inode))
7358c2ecf20Sopenharmony_ci		free_from = round_up(from,
7368c2ecf20Sopenharmony_ci				F2FS_I(inode)->i_cluster_size << PAGE_SHIFT);
7378c2ecf20Sopenharmony_ci#endif
7388c2ecf20Sopenharmony_ci
7398c2ecf20Sopenharmony_ci	err = f2fs_do_truncate_blocks(inode, free_from, lock);
7408c2ecf20Sopenharmony_ci	if (err)
7418c2ecf20Sopenharmony_ci		return err;
7428c2ecf20Sopenharmony_ci
7438c2ecf20Sopenharmony_ci#ifdef CONFIG_F2FS_FS_COMPRESSION
7448c2ecf20Sopenharmony_ci	if (from != free_from) {
7458c2ecf20Sopenharmony_ci		err = f2fs_truncate_partial_cluster(inode, from, lock);
7468c2ecf20Sopenharmony_ci		if (err)
7478c2ecf20Sopenharmony_ci			return err;
7488c2ecf20Sopenharmony_ci	}
7498c2ecf20Sopenharmony_ci#endif
7508c2ecf20Sopenharmony_ci
7518c2ecf20Sopenharmony_ci	return 0;
7528c2ecf20Sopenharmony_ci}
7538c2ecf20Sopenharmony_ci
7548c2ecf20Sopenharmony_ciint f2fs_truncate(struct inode *inode)
7558c2ecf20Sopenharmony_ci{
7568c2ecf20Sopenharmony_ci	int err;
7578c2ecf20Sopenharmony_ci
7588c2ecf20Sopenharmony_ci	if (unlikely(f2fs_cp_error(F2FS_I_SB(inode))))
7598c2ecf20Sopenharmony_ci		return -EIO;
7608c2ecf20Sopenharmony_ci
7618c2ecf20Sopenharmony_ci	if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
7628c2ecf20Sopenharmony_ci				S_ISLNK(inode->i_mode)))
7638c2ecf20Sopenharmony_ci		return 0;
7648c2ecf20Sopenharmony_ci
7658c2ecf20Sopenharmony_ci	trace_f2fs_truncate(inode);
7668c2ecf20Sopenharmony_ci
7678c2ecf20Sopenharmony_ci	if (time_to_inject(F2FS_I_SB(inode), FAULT_TRUNCATE)) {
7688c2ecf20Sopenharmony_ci		f2fs_show_injection_info(F2FS_I_SB(inode), FAULT_TRUNCATE);
7698c2ecf20Sopenharmony_ci		return -EIO;
7708c2ecf20Sopenharmony_ci	}
7718c2ecf20Sopenharmony_ci
7728c2ecf20Sopenharmony_ci	err = dquot_initialize(inode);
7738c2ecf20Sopenharmony_ci	if (err)
7748c2ecf20Sopenharmony_ci		return err;
7758c2ecf20Sopenharmony_ci
7768c2ecf20Sopenharmony_ci	/* we should check inline_data size */
7778c2ecf20Sopenharmony_ci	if (!f2fs_may_inline_data(inode)) {
7788c2ecf20Sopenharmony_ci		err = f2fs_convert_inline_inode(inode);
7798c2ecf20Sopenharmony_ci		if (err)
7808c2ecf20Sopenharmony_ci			return err;
7818c2ecf20Sopenharmony_ci	}
7828c2ecf20Sopenharmony_ci
7838c2ecf20Sopenharmony_ci	err = f2fs_truncate_blocks(inode, i_size_read(inode), true);
7848c2ecf20Sopenharmony_ci	if (err)
7858c2ecf20Sopenharmony_ci		return err;
7868c2ecf20Sopenharmony_ci
7878c2ecf20Sopenharmony_ci	inode->i_mtime = inode->i_ctime = current_time(inode);
7888c2ecf20Sopenharmony_ci	f2fs_mark_inode_dirty_sync(inode, false);
7898c2ecf20Sopenharmony_ci	return 0;
7908c2ecf20Sopenharmony_ci}
7918c2ecf20Sopenharmony_ci
7928c2ecf20Sopenharmony_ciint f2fs_getattr(const struct path *path, struct kstat *stat,
7938c2ecf20Sopenharmony_ci		 u32 request_mask, unsigned int query_flags)
7948c2ecf20Sopenharmony_ci{
7958c2ecf20Sopenharmony_ci	struct inode *inode = d_inode(path->dentry);
7968c2ecf20Sopenharmony_ci	struct f2fs_inode_info *fi = F2FS_I(inode);
7978c2ecf20Sopenharmony_ci	struct f2fs_inode *ri;
7988c2ecf20Sopenharmony_ci	unsigned int flags;
7998c2ecf20Sopenharmony_ci
8008c2ecf20Sopenharmony_ci	if (f2fs_has_extra_attr(inode) &&
8018c2ecf20Sopenharmony_ci			f2fs_sb_has_inode_crtime(F2FS_I_SB(inode)) &&
8028c2ecf20Sopenharmony_ci			F2FS_FITS_IN_INODE(ri, fi->i_extra_isize, i_crtime)) {
8038c2ecf20Sopenharmony_ci		stat->result_mask |= STATX_BTIME;
8048c2ecf20Sopenharmony_ci		stat->btime.tv_sec = fi->i_crtime.tv_sec;
8058c2ecf20Sopenharmony_ci		stat->btime.tv_nsec = fi->i_crtime.tv_nsec;
8068c2ecf20Sopenharmony_ci	}
8078c2ecf20Sopenharmony_ci
8088c2ecf20Sopenharmony_ci	flags = fi->i_flags;
8098c2ecf20Sopenharmony_ci	if (flags & F2FS_COMPR_FL)
8108c2ecf20Sopenharmony_ci		stat->attributes |= STATX_ATTR_COMPRESSED;
8118c2ecf20Sopenharmony_ci	if (flags & F2FS_APPEND_FL)
8128c2ecf20Sopenharmony_ci		stat->attributes |= STATX_ATTR_APPEND;
8138c2ecf20Sopenharmony_ci	if (IS_ENCRYPTED(inode))
8148c2ecf20Sopenharmony_ci		stat->attributes |= STATX_ATTR_ENCRYPTED;
8158c2ecf20Sopenharmony_ci	if (flags & F2FS_IMMUTABLE_FL)
8168c2ecf20Sopenharmony_ci		stat->attributes |= STATX_ATTR_IMMUTABLE;
8178c2ecf20Sopenharmony_ci	if (flags & F2FS_NODUMP_FL)
8188c2ecf20Sopenharmony_ci		stat->attributes |= STATX_ATTR_NODUMP;
8198c2ecf20Sopenharmony_ci	if (IS_VERITY(inode))
8208c2ecf20Sopenharmony_ci		stat->attributes |= STATX_ATTR_VERITY;
8218c2ecf20Sopenharmony_ci
8228c2ecf20Sopenharmony_ci	stat->attributes_mask |= (STATX_ATTR_COMPRESSED |
8238c2ecf20Sopenharmony_ci				  STATX_ATTR_APPEND |
8248c2ecf20Sopenharmony_ci				  STATX_ATTR_ENCRYPTED |
8258c2ecf20Sopenharmony_ci				  STATX_ATTR_IMMUTABLE |
8268c2ecf20Sopenharmony_ci				  STATX_ATTR_NODUMP |
8278c2ecf20Sopenharmony_ci				  STATX_ATTR_VERITY);
8288c2ecf20Sopenharmony_ci
8298c2ecf20Sopenharmony_ci	generic_fillattr(inode, stat);
8308c2ecf20Sopenharmony_ci
8318c2ecf20Sopenharmony_ci	/* we need to show initial sectors used for inline_data/dentries */
8328c2ecf20Sopenharmony_ci	if ((S_ISREG(inode->i_mode) && f2fs_has_inline_data(inode)) ||
8338c2ecf20Sopenharmony_ci					f2fs_has_inline_dentry(inode))
8348c2ecf20Sopenharmony_ci		stat->blocks += (stat->size + 511) >> 9;
8358c2ecf20Sopenharmony_ci
8368c2ecf20Sopenharmony_ci	return 0;
8378c2ecf20Sopenharmony_ci}
8388c2ecf20Sopenharmony_ci
8398c2ecf20Sopenharmony_ci#ifdef CONFIG_F2FS_FS_POSIX_ACL
8408c2ecf20Sopenharmony_cistatic void __setattr_copy(struct inode *inode, const struct iattr *attr)
8418c2ecf20Sopenharmony_ci{
8428c2ecf20Sopenharmony_ci	unsigned int ia_valid = attr->ia_valid;
8438c2ecf20Sopenharmony_ci
8448c2ecf20Sopenharmony_ci	if (ia_valid & ATTR_UID)
8458c2ecf20Sopenharmony_ci		inode->i_uid = attr->ia_uid;
8468c2ecf20Sopenharmony_ci	if (ia_valid & ATTR_GID)
8478c2ecf20Sopenharmony_ci		inode->i_gid = attr->ia_gid;
8488c2ecf20Sopenharmony_ci	if (ia_valid & ATTR_ATIME)
8498c2ecf20Sopenharmony_ci		inode->i_atime = attr->ia_atime;
8508c2ecf20Sopenharmony_ci	if (ia_valid & ATTR_MTIME)
8518c2ecf20Sopenharmony_ci		inode->i_mtime = attr->ia_mtime;
8528c2ecf20Sopenharmony_ci	if (ia_valid & ATTR_CTIME)
8538c2ecf20Sopenharmony_ci		inode->i_ctime = attr->ia_ctime;
8548c2ecf20Sopenharmony_ci	if (ia_valid & ATTR_MODE) {
8558c2ecf20Sopenharmony_ci		umode_t mode = attr->ia_mode;
8568c2ecf20Sopenharmony_ci
8578c2ecf20Sopenharmony_ci		if (!in_group_p(inode->i_gid) &&
8588c2ecf20Sopenharmony_ci			!capable_wrt_inode_uidgid(inode, CAP_FSETID))
8598c2ecf20Sopenharmony_ci			mode &= ~S_ISGID;
8608c2ecf20Sopenharmony_ci		set_acl_inode(inode, mode);
8618c2ecf20Sopenharmony_ci	}
8628c2ecf20Sopenharmony_ci}
8638c2ecf20Sopenharmony_ci#else
8648c2ecf20Sopenharmony_ci#define __setattr_copy setattr_copy
8658c2ecf20Sopenharmony_ci#endif
8668c2ecf20Sopenharmony_ci
8678c2ecf20Sopenharmony_ciint f2fs_setattr(struct dentry *dentry, struct iattr *attr)
8688c2ecf20Sopenharmony_ci{
8698c2ecf20Sopenharmony_ci	struct inode *inode = d_inode(dentry);
8708c2ecf20Sopenharmony_ci	int err;
8718c2ecf20Sopenharmony_ci
8728c2ecf20Sopenharmony_ci	if (unlikely(f2fs_cp_error(F2FS_I_SB(inode))))
8738c2ecf20Sopenharmony_ci		return -EIO;
8748c2ecf20Sopenharmony_ci
8758c2ecf20Sopenharmony_ci	if (unlikely(IS_IMMUTABLE(inode)))
8768c2ecf20Sopenharmony_ci		return -EPERM;
8778c2ecf20Sopenharmony_ci
8788c2ecf20Sopenharmony_ci	if (unlikely(IS_APPEND(inode) &&
8798c2ecf20Sopenharmony_ci			(attr->ia_valid & (ATTR_MODE | ATTR_UID |
8808c2ecf20Sopenharmony_ci				  ATTR_GID | ATTR_TIMES_SET))))
8818c2ecf20Sopenharmony_ci		return -EPERM;
8828c2ecf20Sopenharmony_ci
8838c2ecf20Sopenharmony_ci	if ((attr->ia_valid & ATTR_SIZE) &&
8848c2ecf20Sopenharmony_ci		!f2fs_is_compress_backend_ready(inode))
8858c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
8868c2ecf20Sopenharmony_ci
8878c2ecf20Sopenharmony_ci	err = setattr_prepare(dentry, attr);
8888c2ecf20Sopenharmony_ci	if (err)
8898c2ecf20Sopenharmony_ci		return err;
8908c2ecf20Sopenharmony_ci
8918c2ecf20Sopenharmony_ci	err = fscrypt_prepare_setattr(dentry, attr);
8928c2ecf20Sopenharmony_ci	if (err)
8938c2ecf20Sopenharmony_ci		return err;
8948c2ecf20Sopenharmony_ci
8958c2ecf20Sopenharmony_ci	err = fsverity_prepare_setattr(dentry, attr);
8968c2ecf20Sopenharmony_ci	if (err)
8978c2ecf20Sopenharmony_ci		return err;
8988c2ecf20Sopenharmony_ci
8998c2ecf20Sopenharmony_ci	if (is_quota_modification(inode, attr)) {
9008c2ecf20Sopenharmony_ci		err = dquot_initialize(inode);
9018c2ecf20Sopenharmony_ci		if (err)
9028c2ecf20Sopenharmony_ci			return err;
9038c2ecf20Sopenharmony_ci	}
9048c2ecf20Sopenharmony_ci	if ((attr->ia_valid & ATTR_UID &&
9058c2ecf20Sopenharmony_ci		!uid_eq(attr->ia_uid, inode->i_uid)) ||
9068c2ecf20Sopenharmony_ci		(attr->ia_valid & ATTR_GID &&
9078c2ecf20Sopenharmony_ci		!gid_eq(attr->ia_gid, inode->i_gid))) {
9088c2ecf20Sopenharmony_ci		f2fs_lock_op(F2FS_I_SB(inode));
9098c2ecf20Sopenharmony_ci		err = dquot_transfer(inode, attr);
9108c2ecf20Sopenharmony_ci		if (err) {
9118c2ecf20Sopenharmony_ci			set_sbi_flag(F2FS_I_SB(inode),
9128c2ecf20Sopenharmony_ci					SBI_QUOTA_NEED_REPAIR);
9138c2ecf20Sopenharmony_ci			f2fs_unlock_op(F2FS_I_SB(inode));
9148c2ecf20Sopenharmony_ci			return err;
9158c2ecf20Sopenharmony_ci		}
9168c2ecf20Sopenharmony_ci		/*
9178c2ecf20Sopenharmony_ci		 * update uid/gid under lock_op(), so that dquot and inode can
9188c2ecf20Sopenharmony_ci		 * be updated atomically.
9198c2ecf20Sopenharmony_ci		 */
9208c2ecf20Sopenharmony_ci		if (attr->ia_valid & ATTR_UID)
9218c2ecf20Sopenharmony_ci			inode->i_uid = attr->ia_uid;
9228c2ecf20Sopenharmony_ci		if (attr->ia_valid & ATTR_GID)
9238c2ecf20Sopenharmony_ci			inode->i_gid = attr->ia_gid;
9248c2ecf20Sopenharmony_ci		f2fs_mark_inode_dirty_sync(inode, true);
9258c2ecf20Sopenharmony_ci		f2fs_unlock_op(F2FS_I_SB(inode));
9268c2ecf20Sopenharmony_ci	}
9278c2ecf20Sopenharmony_ci
9288c2ecf20Sopenharmony_ci	if (attr->ia_valid & ATTR_SIZE) {
9298c2ecf20Sopenharmony_ci		loff_t old_size = i_size_read(inode);
9308c2ecf20Sopenharmony_ci
9318c2ecf20Sopenharmony_ci		if (attr->ia_size > MAX_INLINE_DATA(inode)) {
9328c2ecf20Sopenharmony_ci			/*
9338c2ecf20Sopenharmony_ci			 * should convert inline inode before i_size_write to
9348c2ecf20Sopenharmony_ci			 * keep smaller than inline_data size with inline flag.
9358c2ecf20Sopenharmony_ci			 */
9368c2ecf20Sopenharmony_ci			err = f2fs_convert_inline_inode(inode);
9378c2ecf20Sopenharmony_ci			if (err)
9388c2ecf20Sopenharmony_ci				return err;
9398c2ecf20Sopenharmony_ci		}
9408c2ecf20Sopenharmony_ci
9418c2ecf20Sopenharmony_ci		down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
9428c2ecf20Sopenharmony_ci		down_write(&F2FS_I(inode)->i_mmap_sem);
9438c2ecf20Sopenharmony_ci
9448c2ecf20Sopenharmony_ci		truncate_setsize(inode, attr->ia_size);
9458c2ecf20Sopenharmony_ci
9468c2ecf20Sopenharmony_ci		if (attr->ia_size <= old_size)
9478c2ecf20Sopenharmony_ci			err = f2fs_truncate(inode);
9488c2ecf20Sopenharmony_ci		/*
9498c2ecf20Sopenharmony_ci		 * do not trim all blocks after i_size if target size is
9508c2ecf20Sopenharmony_ci		 * larger than i_size.
9518c2ecf20Sopenharmony_ci		 */
9528c2ecf20Sopenharmony_ci		up_write(&F2FS_I(inode)->i_mmap_sem);
9538c2ecf20Sopenharmony_ci		up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
9548c2ecf20Sopenharmony_ci		if (err)
9558c2ecf20Sopenharmony_ci			return err;
9568c2ecf20Sopenharmony_ci
9578c2ecf20Sopenharmony_ci		spin_lock(&F2FS_I(inode)->i_size_lock);
9588c2ecf20Sopenharmony_ci		inode->i_mtime = inode->i_ctime = current_time(inode);
9598c2ecf20Sopenharmony_ci		F2FS_I(inode)->last_disk_size = i_size_read(inode);
9608c2ecf20Sopenharmony_ci		spin_unlock(&F2FS_I(inode)->i_size_lock);
9618c2ecf20Sopenharmony_ci	}
9628c2ecf20Sopenharmony_ci
9638c2ecf20Sopenharmony_ci	__setattr_copy(inode, attr);
9648c2ecf20Sopenharmony_ci
9658c2ecf20Sopenharmony_ci	if (attr->ia_valid & ATTR_MODE) {
9668c2ecf20Sopenharmony_ci		err = posix_acl_chmod(inode, f2fs_get_inode_mode(inode));
9678c2ecf20Sopenharmony_ci		if (err || is_inode_flag_set(inode, FI_ACL_MODE)) {
9688c2ecf20Sopenharmony_ci			inode->i_mode = F2FS_I(inode)->i_acl_mode;
9698c2ecf20Sopenharmony_ci			clear_inode_flag(inode, FI_ACL_MODE);
9708c2ecf20Sopenharmony_ci		}
9718c2ecf20Sopenharmony_ci	}
9728c2ecf20Sopenharmony_ci
9738c2ecf20Sopenharmony_ci	/* file size may changed here */
9748c2ecf20Sopenharmony_ci	f2fs_mark_inode_dirty_sync(inode, true);
9758c2ecf20Sopenharmony_ci
9768c2ecf20Sopenharmony_ci	/* inode change will produce dirty node pages flushed by checkpoint */
9778c2ecf20Sopenharmony_ci	f2fs_balance_fs(F2FS_I_SB(inode), true);
9788c2ecf20Sopenharmony_ci
9798c2ecf20Sopenharmony_ci	return err;
9808c2ecf20Sopenharmony_ci}
9818c2ecf20Sopenharmony_ci
9828c2ecf20Sopenharmony_ciconst struct inode_operations f2fs_file_inode_operations = {
9838c2ecf20Sopenharmony_ci	.getattr	= f2fs_getattr,
9848c2ecf20Sopenharmony_ci	.setattr	= f2fs_setattr,
9858c2ecf20Sopenharmony_ci	.get_acl	= f2fs_get_acl,
9868c2ecf20Sopenharmony_ci	.set_acl	= f2fs_set_acl,
9878c2ecf20Sopenharmony_ci	.listxattr	= f2fs_listxattr,
9888c2ecf20Sopenharmony_ci	.fiemap		= f2fs_fiemap,
9898c2ecf20Sopenharmony_ci};
9908c2ecf20Sopenharmony_ci
9918c2ecf20Sopenharmony_cistatic int fill_zero(struct inode *inode, pgoff_t index,
9928c2ecf20Sopenharmony_ci					loff_t start, loff_t len)
9938c2ecf20Sopenharmony_ci{
9948c2ecf20Sopenharmony_ci	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
9958c2ecf20Sopenharmony_ci	struct page *page;
9968c2ecf20Sopenharmony_ci
9978c2ecf20Sopenharmony_ci	if (!len)
9988c2ecf20Sopenharmony_ci		return 0;
9998c2ecf20Sopenharmony_ci
10008c2ecf20Sopenharmony_ci	f2fs_balance_fs(sbi, true);
10018c2ecf20Sopenharmony_ci
10028c2ecf20Sopenharmony_ci	f2fs_lock_op(sbi);
10038c2ecf20Sopenharmony_ci	page = f2fs_get_new_data_page(inode, NULL, index, false);
10048c2ecf20Sopenharmony_ci	f2fs_unlock_op(sbi);
10058c2ecf20Sopenharmony_ci
10068c2ecf20Sopenharmony_ci	if (IS_ERR(page))
10078c2ecf20Sopenharmony_ci		return PTR_ERR(page);
10088c2ecf20Sopenharmony_ci
10098c2ecf20Sopenharmony_ci	f2fs_wait_on_page_writeback(page, DATA, true, true);
10108c2ecf20Sopenharmony_ci	zero_user(page, start, len);
10118c2ecf20Sopenharmony_ci	set_page_dirty(page);
10128c2ecf20Sopenharmony_ci	f2fs_put_page(page, 1);
10138c2ecf20Sopenharmony_ci	return 0;
10148c2ecf20Sopenharmony_ci}
10158c2ecf20Sopenharmony_ci
10168c2ecf20Sopenharmony_ciint f2fs_truncate_hole(struct inode *inode, pgoff_t pg_start, pgoff_t pg_end)
10178c2ecf20Sopenharmony_ci{
10188c2ecf20Sopenharmony_ci	int err;
10198c2ecf20Sopenharmony_ci
10208c2ecf20Sopenharmony_ci	while (pg_start < pg_end) {
10218c2ecf20Sopenharmony_ci		struct dnode_of_data dn;
10228c2ecf20Sopenharmony_ci		pgoff_t end_offset, count;
10238c2ecf20Sopenharmony_ci
10248c2ecf20Sopenharmony_ci		set_new_dnode(&dn, inode, NULL, NULL, 0);
10258c2ecf20Sopenharmony_ci		err = f2fs_get_dnode_of_data(&dn, pg_start, LOOKUP_NODE);
10268c2ecf20Sopenharmony_ci		if (err) {
10278c2ecf20Sopenharmony_ci			if (err == -ENOENT) {
10288c2ecf20Sopenharmony_ci				pg_start = f2fs_get_next_page_offset(&dn,
10298c2ecf20Sopenharmony_ci								pg_start);
10308c2ecf20Sopenharmony_ci				continue;
10318c2ecf20Sopenharmony_ci			}
10328c2ecf20Sopenharmony_ci			return err;
10338c2ecf20Sopenharmony_ci		}
10348c2ecf20Sopenharmony_ci
10358c2ecf20Sopenharmony_ci		end_offset = ADDRS_PER_PAGE(dn.node_page, inode);
10368c2ecf20Sopenharmony_ci		count = min(end_offset - dn.ofs_in_node, pg_end - pg_start);
10378c2ecf20Sopenharmony_ci
10388c2ecf20Sopenharmony_ci		f2fs_bug_on(F2FS_I_SB(inode), count == 0 || count > end_offset);
10398c2ecf20Sopenharmony_ci
10408c2ecf20Sopenharmony_ci		f2fs_truncate_data_blocks_range(&dn, count);
10418c2ecf20Sopenharmony_ci		f2fs_put_dnode(&dn);
10428c2ecf20Sopenharmony_ci
10438c2ecf20Sopenharmony_ci		pg_start += count;
10448c2ecf20Sopenharmony_ci	}
10458c2ecf20Sopenharmony_ci	return 0;
10468c2ecf20Sopenharmony_ci}
10478c2ecf20Sopenharmony_ci
10488c2ecf20Sopenharmony_cistatic int punch_hole(struct inode *inode, loff_t offset, loff_t len)
10498c2ecf20Sopenharmony_ci{
10508c2ecf20Sopenharmony_ci	pgoff_t pg_start, pg_end;
10518c2ecf20Sopenharmony_ci	loff_t off_start, off_end;
10528c2ecf20Sopenharmony_ci	int ret;
10538c2ecf20Sopenharmony_ci
10548c2ecf20Sopenharmony_ci	ret = f2fs_convert_inline_inode(inode);
10558c2ecf20Sopenharmony_ci	if (ret)
10568c2ecf20Sopenharmony_ci		return ret;
10578c2ecf20Sopenharmony_ci
10588c2ecf20Sopenharmony_ci	pg_start = ((unsigned long long) offset) >> PAGE_SHIFT;
10598c2ecf20Sopenharmony_ci	pg_end = ((unsigned long long) offset + len) >> PAGE_SHIFT;
10608c2ecf20Sopenharmony_ci
10618c2ecf20Sopenharmony_ci	off_start = offset & (PAGE_SIZE - 1);
10628c2ecf20Sopenharmony_ci	off_end = (offset + len) & (PAGE_SIZE - 1);
10638c2ecf20Sopenharmony_ci
10648c2ecf20Sopenharmony_ci	if (pg_start == pg_end) {
10658c2ecf20Sopenharmony_ci		ret = fill_zero(inode, pg_start, off_start,
10668c2ecf20Sopenharmony_ci						off_end - off_start);
10678c2ecf20Sopenharmony_ci		if (ret)
10688c2ecf20Sopenharmony_ci			return ret;
10698c2ecf20Sopenharmony_ci	} else {
10708c2ecf20Sopenharmony_ci		if (off_start) {
10718c2ecf20Sopenharmony_ci			ret = fill_zero(inode, pg_start++, off_start,
10728c2ecf20Sopenharmony_ci						PAGE_SIZE - off_start);
10738c2ecf20Sopenharmony_ci			if (ret)
10748c2ecf20Sopenharmony_ci				return ret;
10758c2ecf20Sopenharmony_ci		}
10768c2ecf20Sopenharmony_ci		if (off_end) {
10778c2ecf20Sopenharmony_ci			ret = fill_zero(inode, pg_end, 0, off_end);
10788c2ecf20Sopenharmony_ci			if (ret)
10798c2ecf20Sopenharmony_ci				return ret;
10808c2ecf20Sopenharmony_ci		}
10818c2ecf20Sopenharmony_ci
10828c2ecf20Sopenharmony_ci		if (pg_start < pg_end) {
10838c2ecf20Sopenharmony_ci			loff_t blk_start, blk_end;
10848c2ecf20Sopenharmony_ci			struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
10858c2ecf20Sopenharmony_ci
10868c2ecf20Sopenharmony_ci			f2fs_balance_fs(sbi, true);
10878c2ecf20Sopenharmony_ci
10888c2ecf20Sopenharmony_ci			blk_start = (loff_t)pg_start << PAGE_SHIFT;
10898c2ecf20Sopenharmony_ci			blk_end = (loff_t)pg_end << PAGE_SHIFT;
10908c2ecf20Sopenharmony_ci
10918c2ecf20Sopenharmony_ci			down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
10928c2ecf20Sopenharmony_ci			down_write(&F2FS_I(inode)->i_mmap_sem);
10938c2ecf20Sopenharmony_ci
10948c2ecf20Sopenharmony_ci			truncate_pagecache_range(inode, blk_start, blk_end - 1);
10958c2ecf20Sopenharmony_ci
10968c2ecf20Sopenharmony_ci			f2fs_lock_op(sbi);
10978c2ecf20Sopenharmony_ci			ret = f2fs_truncate_hole(inode, pg_start, pg_end);
10988c2ecf20Sopenharmony_ci			f2fs_unlock_op(sbi);
10998c2ecf20Sopenharmony_ci
11008c2ecf20Sopenharmony_ci			up_write(&F2FS_I(inode)->i_mmap_sem);
11018c2ecf20Sopenharmony_ci			up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
11028c2ecf20Sopenharmony_ci		}
11038c2ecf20Sopenharmony_ci	}
11048c2ecf20Sopenharmony_ci
11058c2ecf20Sopenharmony_ci	return ret;
11068c2ecf20Sopenharmony_ci}
11078c2ecf20Sopenharmony_ci
11088c2ecf20Sopenharmony_cistatic int __read_out_blkaddrs(struct inode *inode, block_t *blkaddr,
11098c2ecf20Sopenharmony_ci				int *do_replace, pgoff_t off, pgoff_t len)
11108c2ecf20Sopenharmony_ci{
11118c2ecf20Sopenharmony_ci	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
11128c2ecf20Sopenharmony_ci	struct dnode_of_data dn;
11138c2ecf20Sopenharmony_ci	int ret, done, i;
11148c2ecf20Sopenharmony_ci
11158c2ecf20Sopenharmony_cinext_dnode:
11168c2ecf20Sopenharmony_ci	set_new_dnode(&dn, inode, NULL, NULL, 0);
11178c2ecf20Sopenharmony_ci	ret = f2fs_get_dnode_of_data(&dn, off, LOOKUP_NODE_RA);
11188c2ecf20Sopenharmony_ci	if (ret && ret != -ENOENT) {
11198c2ecf20Sopenharmony_ci		return ret;
11208c2ecf20Sopenharmony_ci	} else if (ret == -ENOENT) {
11218c2ecf20Sopenharmony_ci		if (dn.max_level == 0)
11228c2ecf20Sopenharmony_ci			return -ENOENT;
11238c2ecf20Sopenharmony_ci		done = min((pgoff_t)ADDRS_PER_BLOCK(inode) -
11248c2ecf20Sopenharmony_ci						dn.ofs_in_node, len);
11258c2ecf20Sopenharmony_ci		blkaddr += done;
11268c2ecf20Sopenharmony_ci		do_replace += done;
11278c2ecf20Sopenharmony_ci		goto next;
11288c2ecf20Sopenharmony_ci	}
11298c2ecf20Sopenharmony_ci
11308c2ecf20Sopenharmony_ci	done = min((pgoff_t)ADDRS_PER_PAGE(dn.node_page, inode) -
11318c2ecf20Sopenharmony_ci							dn.ofs_in_node, len);
11328c2ecf20Sopenharmony_ci	for (i = 0; i < done; i++, blkaddr++, do_replace++, dn.ofs_in_node++) {
11338c2ecf20Sopenharmony_ci		*blkaddr = f2fs_data_blkaddr(&dn);
11348c2ecf20Sopenharmony_ci
11358c2ecf20Sopenharmony_ci		if (__is_valid_data_blkaddr(*blkaddr) &&
11368c2ecf20Sopenharmony_ci			!f2fs_is_valid_blkaddr(sbi, *blkaddr,
11378c2ecf20Sopenharmony_ci					DATA_GENERIC_ENHANCE)) {
11388c2ecf20Sopenharmony_ci			f2fs_put_dnode(&dn);
11398c2ecf20Sopenharmony_ci			return -EFSCORRUPTED;
11408c2ecf20Sopenharmony_ci		}
11418c2ecf20Sopenharmony_ci
11428c2ecf20Sopenharmony_ci		if (!f2fs_is_checkpointed_data(sbi, *blkaddr)) {
11438c2ecf20Sopenharmony_ci
11448c2ecf20Sopenharmony_ci			if (f2fs_lfs_mode(sbi)) {
11458c2ecf20Sopenharmony_ci				f2fs_put_dnode(&dn);
11468c2ecf20Sopenharmony_ci				return -EOPNOTSUPP;
11478c2ecf20Sopenharmony_ci			}
11488c2ecf20Sopenharmony_ci
11498c2ecf20Sopenharmony_ci			/* do not invalidate this block address */
11508c2ecf20Sopenharmony_ci			f2fs_update_data_blkaddr(&dn, NULL_ADDR);
11518c2ecf20Sopenharmony_ci			*do_replace = 1;
11528c2ecf20Sopenharmony_ci		}
11538c2ecf20Sopenharmony_ci	}
11548c2ecf20Sopenharmony_ci	f2fs_put_dnode(&dn);
11558c2ecf20Sopenharmony_cinext:
11568c2ecf20Sopenharmony_ci	len -= done;
11578c2ecf20Sopenharmony_ci	off += done;
11588c2ecf20Sopenharmony_ci	if (len)
11598c2ecf20Sopenharmony_ci		goto next_dnode;
11608c2ecf20Sopenharmony_ci	return 0;
11618c2ecf20Sopenharmony_ci}
11628c2ecf20Sopenharmony_ci
11638c2ecf20Sopenharmony_cistatic int __roll_back_blkaddrs(struct inode *inode, block_t *blkaddr,
11648c2ecf20Sopenharmony_ci				int *do_replace, pgoff_t off, int len)
11658c2ecf20Sopenharmony_ci{
11668c2ecf20Sopenharmony_ci	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
11678c2ecf20Sopenharmony_ci	struct dnode_of_data dn;
11688c2ecf20Sopenharmony_ci	int ret, i;
11698c2ecf20Sopenharmony_ci
11708c2ecf20Sopenharmony_ci	for (i = 0; i < len; i++, do_replace++, blkaddr++) {
11718c2ecf20Sopenharmony_ci		if (*do_replace == 0)
11728c2ecf20Sopenharmony_ci			continue;
11738c2ecf20Sopenharmony_ci
11748c2ecf20Sopenharmony_ci		set_new_dnode(&dn, inode, NULL, NULL, 0);
11758c2ecf20Sopenharmony_ci		ret = f2fs_get_dnode_of_data(&dn, off + i, LOOKUP_NODE_RA);
11768c2ecf20Sopenharmony_ci		if (ret) {
11778c2ecf20Sopenharmony_ci			dec_valid_block_count(sbi, inode, 1);
11788c2ecf20Sopenharmony_ci			f2fs_invalidate_blocks(sbi, *blkaddr);
11798c2ecf20Sopenharmony_ci		} else {
11808c2ecf20Sopenharmony_ci			f2fs_update_data_blkaddr(&dn, *blkaddr);
11818c2ecf20Sopenharmony_ci		}
11828c2ecf20Sopenharmony_ci		f2fs_put_dnode(&dn);
11838c2ecf20Sopenharmony_ci	}
11848c2ecf20Sopenharmony_ci	return 0;
11858c2ecf20Sopenharmony_ci}
11868c2ecf20Sopenharmony_ci
11878c2ecf20Sopenharmony_cistatic int __clone_blkaddrs(struct inode *src_inode, struct inode *dst_inode,
11888c2ecf20Sopenharmony_ci			block_t *blkaddr, int *do_replace,
11898c2ecf20Sopenharmony_ci			pgoff_t src, pgoff_t dst, pgoff_t len, bool full)
11908c2ecf20Sopenharmony_ci{
11918c2ecf20Sopenharmony_ci	struct f2fs_sb_info *sbi = F2FS_I_SB(src_inode);
11928c2ecf20Sopenharmony_ci	pgoff_t i = 0;
11938c2ecf20Sopenharmony_ci	int ret;
11948c2ecf20Sopenharmony_ci
11958c2ecf20Sopenharmony_ci	while (i < len) {
11968c2ecf20Sopenharmony_ci		if (blkaddr[i] == NULL_ADDR && !full) {
11978c2ecf20Sopenharmony_ci			i++;
11988c2ecf20Sopenharmony_ci			continue;
11998c2ecf20Sopenharmony_ci		}
12008c2ecf20Sopenharmony_ci
12018c2ecf20Sopenharmony_ci		if (do_replace[i] || blkaddr[i] == NULL_ADDR) {
12028c2ecf20Sopenharmony_ci			struct dnode_of_data dn;
12038c2ecf20Sopenharmony_ci			struct node_info ni;
12048c2ecf20Sopenharmony_ci			size_t new_size;
12058c2ecf20Sopenharmony_ci			pgoff_t ilen;
12068c2ecf20Sopenharmony_ci
12078c2ecf20Sopenharmony_ci			set_new_dnode(&dn, dst_inode, NULL, NULL, 0);
12088c2ecf20Sopenharmony_ci			ret = f2fs_get_dnode_of_data(&dn, dst + i, ALLOC_NODE);
12098c2ecf20Sopenharmony_ci			if (ret)
12108c2ecf20Sopenharmony_ci				return ret;
12118c2ecf20Sopenharmony_ci
12128c2ecf20Sopenharmony_ci			ret = f2fs_get_node_info(sbi, dn.nid, &ni);
12138c2ecf20Sopenharmony_ci			if (ret) {
12148c2ecf20Sopenharmony_ci				f2fs_put_dnode(&dn);
12158c2ecf20Sopenharmony_ci				return ret;
12168c2ecf20Sopenharmony_ci			}
12178c2ecf20Sopenharmony_ci
12188c2ecf20Sopenharmony_ci			ilen = min((pgoff_t)
12198c2ecf20Sopenharmony_ci				ADDRS_PER_PAGE(dn.node_page, dst_inode) -
12208c2ecf20Sopenharmony_ci						dn.ofs_in_node, len - i);
12218c2ecf20Sopenharmony_ci			do {
12228c2ecf20Sopenharmony_ci				dn.data_blkaddr = f2fs_data_blkaddr(&dn);
12238c2ecf20Sopenharmony_ci				f2fs_truncate_data_blocks_range(&dn, 1);
12248c2ecf20Sopenharmony_ci
12258c2ecf20Sopenharmony_ci				if (do_replace[i]) {
12268c2ecf20Sopenharmony_ci					f2fs_i_blocks_write(src_inode,
12278c2ecf20Sopenharmony_ci							1, false, false);
12288c2ecf20Sopenharmony_ci					f2fs_i_blocks_write(dst_inode,
12298c2ecf20Sopenharmony_ci							1, true, false);
12308c2ecf20Sopenharmony_ci					f2fs_replace_block(sbi, &dn, dn.data_blkaddr,
12318c2ecf20Sopenharmony_ci					blkaddr[i], ni.version, true, false);
12328c2ecf20Sopenharmony_ci
12338c2ecf20Sopenharmony_ci					do_replace[i] = 0;
12348c2ecf20Sopenharmony_ci				}
12358c2ecf20Sopenharmony_ci				dn.ofs_in_node++;
12368c2ecf20Sopenharmony_ci				i++;
12378c2ecf20Sopenharmony_ci				new_size = (loff_t)(dst + i) << PAGE_SHIFT;
12388c2ecf20Sopenharmony_ci				if (dst_inode->i_size < new_size)
12398c2ecf20Sopenharmony_ci					f2fs_i_size_write(dst_inode, new_size);
12408c2ecf20Sopenharmony_ci			} while (--ilen && (do_replace[i] || blkaddr[i] == NULL_ADDR));
12418c2ecf20Sopenharmony_ci
12428c2ecf20Sopenharmony_ci			f2fs_put_dnode(&dn);
12438c2ecf20Sopenharmony_ci		} else {
12448c2ecf20Sopenharmony_ci			struct page *psrc, *pdst;
12458c2ecf20Sopenharmony_ci
12468c2ecf20Sopenharmony_ci			psrc = f2fs_get_lock_data_page(src_inode,
12478c2ecf20Sopenharmony_ci							src + i, true);
12488c2ecf20Sopenharmony_ci			if (IS_ERR(psrc))
12498c2ecf20Sopenharmony_ci				return PTR_ERR(psrc);
12508c2ecf20Sopenharmony_ci			pdst = f2fs_get_new_data_page(dst_inode, NULL, dst + i,
12518c2ecf20Sopenharmony_ci								true);
12528c2ecf20Sopenharmony_ci			if (IS_ERR(pdst)) {
12538c2ecf20Sopenharmony_ci				f2fs_put_page(psrc, 1);
12548c2ecf20Sopenharmony_ci				return PTR_ERR(pdst);
12558c2ecf20Sopenharmony_ci			}
12568c2ecf20Sopenharmony_ci			f2fs_copy_page(psrc, pdst);
12578c2ecf20Sopenharmony_ci			set_page_dirty(pdst);
12588c2ecf20Sopenharmony_ci			f2fs_put_page(pdst, 1);
12598c2ecf20Sopenharmony_ci			f2fs_put_page(psrc, 1);
12608c2ecf20Sopenharmony_ci
12618c2ecf20Sopenharmony_ci			ret = f2fs_truncate_hole(src_inode,
12628c2ecf20Sopenharmony_ci						src + i, src + i + 1);
12638c2ecf20Sopenharmony_ci			if (ret)
12648c2ecf20Sopenharmony_ci				return ret;
12658c2ecf20Sopenharmony_ci			i++;
12668c2ecf20Sopenharmony_ci		}
12678c2ecf20Sopenharmony_ci	}
12688c2ecf20Sopenharmony_ci	return 0;
12698c2ecf20Sopenharmony_ci}
12708c2ecf20Sopenharmony_ci
12718c2ecf20Sopenharmony_cistatic int __exchange_data_block(struct inode *src_inode,
12728c2ecf20Sopenharmony_ci			struct inode *dst_inode, pgoff_t src, pgoff_t dst,
12738c2ecf20Sopenharmony_ci			pgoff_t len, bool full)
12748c2ecf20Sopenharmony_ci{
12758c2ecf20Sopenharmony_ci	block_t *src_blkaddr;
12768c2ecf20Sopenharmony_ci	int *do_replace;
12778c2ecf20Sopenharmony_ci	pgoff_t olen;
12788c2ecf20Sopenharmony_ci	int ret;
12798c2ecf20Sopenharmony_ci
12808c2ecf20Sopenharmony_ci	while (len) {
12818c2ecf20Sopenharmony_ci		olen = min((pgoff_t)4 * ADDRS_PER_BLOCK(src_inode), len);
12828c2ecf20Sopenharmony_ci
12838c2ecf20Sopenharmony_ci		src_blkaddr = f2fs_kvzalloc(F2FS_I_SB(src_inode),
12848c2ecf20Sopenharmony_ci					array_size(olen, sizeof(block_t)),
12858c2ecf20Sopenharmony_ci					GFP_NOFS);
12868c2ecf20Sopenharmony_ci		if (!src_blkaddr)
12878c2ecf20Sopenharmony_ci			return -ENOMEM;
12888c2ecf20Sopenharmony_ci
12898c2ecf20Sopenharmony_ci		do_replace = f2fs_kvzalloc(F2FS_I_SB(src_inode),
12908c2ecf20Sopenharmony_ci					array_size(olen, sizeof(int)),
12918c2ecf20Sopenharmony_ci					GFP_NOFS);
12928c2ecf20Sopenharmony_ci		if (!do_replace) {
12938c2ecf20Sopenharmony_ci			kvfree(src_blkaddr);
12948c2ecf20Sopenharmony_ci			return -ENOMEM;
12958c2ecf20Sopenharmony_ci		}
12968c2ecf20Sopenharmony_ci
12978c2ecf20Sopenharmony_ci		ret = __read_out_blkaddrs(src_inode, src_blkaddr,
12988c2ecf20Sopenharmony_ci					do_replace, src, olen);
12998c2ecf20Sopenharmony_ci		if (ret)
13008c2ecf20Sopenharmony_ci			goto roll_back;
13018c2ecf20Sopenharmony_ci
13028c2ecf20Sopenharmony_ci		ret = __clone_blkaddrs(src_inode, dst_inode, src_blkaddr,
13038c2ecf20Sopenharmony_ci					do_replace, src, dst, olen, full);
13048c2ecf20Sopenharmony_ci		if (ret)
13058c2ecf20Sopenharmony_ci			goto roll_back;
13068c2ecf20Sopenharmony_ci
13078c2ecf20Sopenharmony_ci		src += olen;
13088c2ecf20Sopenharmony_ci		dst += olen;
13098c2ecf20Sopenharmony_ci		len -= olen;
13108c2ecf20Sopenharmony_ci
13118c2ecf20Sopenharmony_ci		kvfree(src_blkaddr);
13128c2ecf20Sopenharmony_ci		kvfree(do_replace);
13138c2ecf20Sopenharmony_ci	}
13148c2ecf20Sopenharmony_ci	return 0;
13158c2ecf20Sopenharmony_ci
13168c2ecf20Sopenharmony_ciroll_back:
13178c2ecf20Sopenharmony_ci	__roll_back_blkaddrs(src_inode, src_blkaddr, do_replace, src, olen);
13188c2ecf20Sopenharmony_ci	kvfree(src_blkaddr);
13198c2ecf20Sopenharmony_ci	kvfree(do_replace);
13208c2ecf20Sopenharmony_ci	return ret;
13218c2ecf20Sopenharmony_ci}
13228c2ecf20Sopenharmony_ci
13238c2ecf20Sopenharmony_cistatic int f2fs_do_collapse(struct inode *inode, loff_t offset, loff_t len)
13248c2ecf20Sopenharmony_ci{
13258c2ecf20Sopenharmony_ci	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
13268c2ecf20Sopenharmony_ci	pgoff_t nrpages = DIV_ROUND_UP(i_size_read(inode), PAGE_SIZE);
13278c2ecf20Sopenharmony_ci	pgoff_t start = offset >> PAGE_SHIFT;
13288c2ecf20Sopenharmony_ci	pgoff_t end = (offset + len) >> PAGE_SHIFT;
13298c2ecf20Sopenharmony_ci	int ret;
13308c2ecf20Sopenharmony_ci
13318c2ecf20Sopenharmony_ci	f2fs_balance_fs(sbi, true);
13328c2ecf20Sopenharmony_ci
13338c2ecf20Sopenharmony_ci	/* avoid gc operation during block exchange */
13348c2ecf20Sopenharmony_ci	down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
13358c2ecf20Sopenharmony_ci	down_write(&F2FS_I(inode)->i_mmap_sem);
13368c2ecf20Sopenharmony_ci
13378c2ecf20Sopenharmony_ci	f2fs_lock_op(sbi);
13388c2ecf20Sopenharmony_ci	f2fs_drop_extent_tree(inode);
13398c2ecf20Sopenharmony_ci	truncate_pagecache(inode, offset);
13408c2ecf20Sopenharmony_ci	ret = __exchange_data_block(inode, inode, end, start, nrpages - end, true);
13418c2ecf20Sopenharmony_ci	f2fs_unlock_op(sbi);
13428c2ecf20Sopenharmony_ci
13438c2ecf20Sopenharmony_ci	up_write(&F2FS_I(inode)->i_mmap_sem);
13448c2ecf20Sopenharmony_ci	up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
13458c2ecf20Sopenharmony_ci	return ret;
13468c2ecf20Sopenharmony_ci}
13478c2ecf20Sopenharmony_ci
13488c2ecf20Sopenharmony_cistatic int f2fs_collapse_range(struct inode *inode, loff_t offset, loff_t len)
13498c2ecf20Sopenharmony_ci{
13508c2ecf20Sopenharmony_ci	loff_t new_size;
13518c2ecf20Sopenharmony_ci	int ret;
13528c2ecf20Sopenharmony_ci
13538c2ecf20Sopenharmony_ci	if (offset + len >= i_size_read(inode))
13548c2ecf20Sopenharmony_ci		return -EINVAL;
13558c2ecf20Sopenharmony_ci
13568c2ecf20Sopenharmony_ci	/* collapse range should be aligned to block size of f2fs. */
13578c2ecf20Sopenharmony_ci	if (offset & (F2FS_BLKSIZE - 1) || len & (F2FS_BLKSIZE - 1))
13588c2ecf20Sopenharmony_ci		return -EINVAL;
13598c2ecf20Sopenharmony_ci
13608c2ecf20Sopenharmony_ci	ret = f2fs_convert_inline_inode(inode);
13618c2ecf20Sopenharmony_ci	if (ret)
13628c2ecf20Sopenharmony_ci		return ret;
13638c2ecf20Sopenharmony_ci
13648c2ecf20Sopenharmony_ci	/* write out all dirty pages from offset */
13658c2ecf20Sopenharmony_ci	ret = filemap_write_and_wait_range(inode->i_mapping, offset, LLONG_MAX);
13668c2ecf20Sopenharmony_ci	if (ret)
13678c2ecf20Sopenharmony_ci		return ret;
13688c2ecf20Sopenharmony_ci
13698c2ecf20Sopenharmony_ci	ret = f2fs_do_collapse(inode, offset, len);
13708c2ecf20Sopenharmony_ci	if (ret)
13718c2ecf20Sopenharmony_ci		return ret;
13728c2ecf20Sopenharmony_ci
13738c2ecf20Sopenharmony_ci	/* write out all moved pages, if possible */
13748c2ecf20Sopenharmony_ci	down_write(&F2FS_I(inode)->i_mmap_sem);
13758c2ecf20Sopenharmony_ci	filemap_write_and_wait_range(inode->i_mapping, offset, LLONG_MAX);
13768c2ecf20Sopenharmony_ci	truncate_pagecache(inode, offset);
13778c2ecf20Sopenharmony_ci
13788c2ecf20Sopenharmony_ci	new_size = i_size_read(inode) - len;
13798c2ecf20Sopenharmony_ci	ret = f2fs_truncate_blocks(inode, new_size, true);
13808c2ecf20Sopenharmony_ci	up_write(&F2FS_I(inode)->i_mmap_sem);
13818c2ecf20Sopenharmony_ci	if (!ret)
13828c2ecf20Sopenharmony_ci		f2fs_i_size_write(inode, new_size);
13838c2ecf20Sopenharmony_ci	return ret;
13848c2ecf20Sopenharmony_ci}
13858c2ecf20Sopenharmony_ci
13868c2ecf20Sopenharmony_cistatic int f2fs_do_zero_range(struct dnode_of_data *dn, pgoff_t start,
13878c2ecf20Sopenharmony_ci								pgoff_t end)
13888c2ecf20Sopenharmony_ci{
13898c2ecf20Sopenharmony_ci	struct f2fs_sb_info *sbi = F2FS_I_SB(dn->inode);
13908c2ecf20Sopenharmony_ci	pgoff_t index = start;
13918c2ecf20Sopenharmony_ci	unsigned int ofs_in_node = dn->ofs_in_node;
13928c2ecf20Sopenharmony_ci	blkcnt_t count = 0;
13938c2ecf20Sopenharmony_ci	int ret;
13948c2ecf20Sopenharmony_ci
13958c2ecf20Sopenharmony_ci	for (; index < end; index++, dn->ofs_in_node++) {
13968c2ecf20Sopenharmony_ci		if (f2fs_data_blkaddr(dn) == NULL_ADDR)
13978c2ecf20Sopenharmony_ci			count++;
13988c2ecf20Sopenharmony_ci	}
13998c2ecf20Sopenharmony_ci
14008c2ecf20Sopenharmony_ci	dn->ofs_in_node = ofs_in_node;
14018c2ecf20Sopenharmony_ci	ret = f2fs_reserve_new_blocks(dn, count);
14028c2ecf20Sopenharmony_ci	if (ret)
14038c2ecf20Sopenharmony_ci		return ret;
14048c2ecf20Sopenharmony_ci
14058c2ecf20Sopenharmony_ci	dn->ofs_in_node = ofs_in_node;
14068c2ecf20Sopenharmony_ci	for (index = start; index < end; index++, dn->ofs_in_node++) {
14078c2ecf20Sopenharmony_ci		dn->data_blkaddr = f2fs_data_blkaddr(dn);
14088c2ecf20Sopenharmony_ci		/*
14098c2ecf20Sopenharmony_ci		 * f2fs_reserve_new_blocks will not guarantee entire block
14108c2ecf20Sopenharmony_ci		 * allocation.
14118c2ecf20Sopenharmony_ci		 */
14128c2ecf20Sopenharmony_ci		if (dn->data_blkaddr == NULL_ADDR) {
14138c2ecf20Sopenharmony_ci			ret = -ENOSPC;
14148c2ecf20Sopenharmony_ci			break;
14158c2ecf20Sopenharmony_ci		}
14168c2ecf20Sopenharmony_ci
14178c2ecf20Sopenharmony_ci		if (dn->data_blkaddr == NEW_ADDR)
14188c2ecf20Sopenharmony_ci			continue;
14198c2ecf20Sopenharmony_ci
14208c2ecf20Sopenharmony_ci		if (!f2fs_is_valid_blkaddr(sbi, dn->data_blkaddr,
14218c2ecf20Sopenharmony_ci					DATA_GENERIC_ENHANCE)) {
14228c2ecf20Sopenharmony_ci			ret = -EFSCORRUPTED;
14238c2ecf20Sopenharmony_ci			break;
14248c2ecf20Sopenharmony_ci		}
14258c2ecf20Sopenharmony_ci
14268c2ecf20Sopenharmony_ci		f2fs_invalidate_blocks(sbi, dn->data_blkaddr);
14278c2ecf20Sopenharmony_ci		dn->data_blkaddr = NEW_ADDR;
14288c2ecf20Sopenharmony_ci		f2fs_set_data_blkaddr(dn);
14298c2ecf20Sopenharmony_ci	}
14308c2ecf20Sopenharmony_ci
14318c2ecf20Sopenharmony_ci	f2fs_update_extent_cache_range(dn, start, 0, index - start);
14328c2ecf20Sopenharmony_ci
14338c2ecf20Sopenharmony_ci	return ret;
14348c2ecf20Sopenharmony_ci}
14358c2ecf20Sopenharmony_ci
14368c2ecf20Sopenharmony_cistatic int f2fs_zero_range(struct inode *inode, loff_t offset, loff_t len,
14378c2ecf20Sopenharmony_ci								int mode)
14388c2ecf20Sopenharmony_ci{
14398c2ecf20Sopenharmony_ci	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
14408c2ecf20Sopenharmony_ci	struct address_space *mapping = inode->i_mapping;
14418c2ecf20Sopenharmony_ci	pgoff_t index, pg_start, pg_end;
14428c2ecf20Sopenharmony_ci	loff_t new_size = i_size_read(inode);
14438c2ecf20Sopenharmony_ci	loff_t off_start, off_end;
14448c2ecf20Sopenharmony_ci	int ret = 0;
14458c2ecf20Sopenharmony_ci
14468c2ecf20Sopenharmony_ci	ret = inode_newsize_ok(inode, (len + offset));
14478c2ecf20Sopenharmony_ci	if (ret)
14488c2ecf20Sopenharmony_ci		return ret;
14498c2ecf20Sopenharmony_ci
14508c2ecf20Sopenharmony_ci	ret = f2fs_convert_inline_inode(inode);
14518c2ecf20Sopenharmony_ci	if (ret)
14528c2ecf20Sopenharmony_ci		return ret;
14538c2ecf20Sopenharmony_ci
14548c2ecf20Sopenharmony_ci	ret = filemap_write_and_wait_range(mapping, offset, offset + len - 1);
14558c2ecf20Sopenharmony_ci	if (ret)
14568c2ecf20Sopenharmony_ci		return ret;
14578c2ecf20Sopenharmony_ci
14588c2ecf20Sopenharmony_ci	pg_start = ((unsigned long long) offset) >> PAGE_SHIFT;
14598c2ecf20Sopenharmony_ci	pg_end = ((unsigned long long) offset + len) >> PAGE_SHIFT;
14608c2ecf20Sopenharmony_ci
14618c2ecf20Sopenharmony_ci	off_start = offset & (PAGE_SIZE - 1);
14628c2ecf20Sopenharmony_ci	off_end = (offset + len) & (PAGE_SIZE - 1);
14638c2ecf20Sopenharmony_ci
14648c2ecf20Sopenharmony_ci	if (pg_start == pg_end) {
14658c2ecf20Sopenharmony_ci		ret = fill_zero(inode, pg_start, off_start,
14668c2ecf20Sopenharmony_ci						off_end - off_start);
14678c2ecf20Sopenharmony_ci		if (ret)
14688c2ecf20Sopenharmony_ci			return ret;
14698c2ecf20Sopenharmony_ci
14708c2ecf20Sopenharmony_ci		new_size = max_t(loff_t, new_size, offset + len);
14718c2ecf20Sopenharmony_ci	} else {
14728c2ecf20Sopenharmony_ci		if (off_start) {
14738c2ecf20Sopenharmony_ci			ret = fill_zero(inode, pg_start++, off_start,
14748c2ecf20Sopenharmony_ci						PAGE_SIZE - off_start);
14758c2ecf20Sopenharmony_ci			if (ret)
14768c2ecf20Sopenharmony_ci				return ret;
14778c2ecf20Sopenharmony_ci
14788c2ecf20Sopenharmony_ci			new_size = max_t(loff_t, new_size,
14798c2ecf20Sopenharmony_ci					(loff_t)pg_start << PAGE_SHIFT);
14808c2ecf20Sopenharmony_ci		}
14818c2ecf20Sopenharmony_ci
14828c2ecf20Sopenharmony_ci		for (index = pg_start; index < pg_end;) {
14838c2ecf20Sopenharmony_ci			struct dnode_of_data dn;
14848c2ecf20Sopenharmony_ci			unsigned int end_offset;
14858c2ecf20Sopenharmony_ci			pgoff_t end;
14868c2ecf20Sopenharmony_ci
14878c2ecf20Sopenharmony_ci			down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
14888c2ecf20Sopenharmony_ci			down_write(&F2FS_I(inode)->i_mmap_sem);
14898c2ecf20Sopenharmony_ci
14908c2ecf20Sopenharmony_ci			truncate_pagecache_range(inode,
14918c2ecf20Sopenharmony_ci				(loff_t)index << PAGE_SHIFT,
14928c2ecf20Sopenharmony_ci				((loff_t)pg_end << PAGE_SHIFT) - 1);
14938c2ecf20Sopenharmony_ci
14948c2ecf20Sopenharmony_ci			f2fs_lock_op(sbi);
14958c2ecf20Sopenharmony_ci
14968c2ecf20Sopenharmony_ci			set_new_dnode(&dn, inode, NULL, NULL, 0);
14978c2ecf20Sopenharmony_ci			ret = f2fs_get_dnode_of_data(&dn, index, ALLOC_NODE);
14988c2ecf20Sopenharmony_ci			if (ret) {
14998c2ecf20Sopenharmony_ci				f2fs_unlock_op(sbi);
15008c2ecf20Sopenharmony_ci				up_write(&F2FS_I(inode)->i_mmap_sem);
15018c2ecf20Sopenharmony_ci				up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
15028c2ecf20Sopenharmony_ci				goto out;
15038c2ecf20Sopenharmony_ci			}
15048c2ecf20Sopenharmony_ci
15058c2ecf20Sopenharmony_ci			end_offset = ADDRS_PER_PAGE(dn.node_page, inode);
15068c2ecf20Sopenharmony_ci			end = min(pg_end, end_offset - dn.ofs_in_node + index);
15078c2ecf20Sopenharmony_ci
15088c2ecf20Sopenharmony_ci			ret = f2fs_do_zero_range(&dn, index, end);
15098c2ecf20Sopenharmony_ci			f2fs_put_dnode(&dn);
15108c2ecf20Sopenharmony_ci
15118c2ecf20Sopenharmony_ci			f2fs_unlock_op(sbi);
15128c2ecf20Sopenharmony_ci			up_write(&F2FS_I(inode)->i_mmap_sem);
15138c2ecf20Sopenharmony_ci			up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
15148c2ecf20Sopenharmony_ci
15158c2ecf20Sopenharmony_ci			f2fs_balance_fs(sbi, dn.node_changed);
15168c2ecf20Sopenharmony_ci
15178c2ecf20Sopenharmony_ci			if (ret)
15188c2ecf20Sopenharmony_ci				goto out;
15198c2ecf20Sopenharmony_ci
15208c2ecf20Sopenharmony_ci			index = end;
15218c2ecf20Sopenharmony_ci			new_size = max_t(loff_t, new_size,
15228c2ecf20Sopenharmony_ci					(loff_t)index << PAGE_SHIFT);
15238c2ecf20Sopenharmony_ci		}
15248c2ecf20Sopenharmony_ci
15258c2ecf20Sopenharmony_ci		if (off_end) {
15268c2ecf20Sopenharmony_ci			ret = fill_zero(inode, pg_end, 0, off_end);
15278c2ecf20Sopenharmony_ci			if (ret)
15288c2ecf20Sopenharmony_ci				goto out;
15298c2ecf20Sopenharmony_ci
15308c2ecf20Sopenharmony_ci			new_size = max_t(loff_t, new_size, offset + len);
15318c2ecf20Sopenharmony_ci		}
15328c2ecf20Sopenharmony_ci	}
15338c2ecf20Sopenharmony_ci
15348c2ecf20Sopenharmony_ciout:
15358c2ecf20Sopenharmony_ci	if (new_size > i_size_read(inode)) {
15368c2ecf20Sopenharmony_ci		if (mode & FALLOC_FL_KEEP_SIZE)
15378c2ecf20Sopenharmony_ci			file_set_keep_isize(inode);
15388c2ecf20Sopenharmony_ci		else
15398c2ecf20Sopenharmony_ci			f2fs_i_size_write(inode, new_size);
15408c2ecf20Sopenharmony_ci	}
15418c2ecf20Sopenharmony_ci	return ret;
15428c2ecf20Sopenharmony_ci}
15438c2ecf20Sopenharmony_ci
15448c2ecf20Sopenharmony_cistatic int f2fs_insert_range(struct inode *inode, loff_t offset, loff_t len)
15458c2ecf20Sopenharmony_ci{
15468c2ecf20Sopenharmony_ci	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
15478c2ecf20Sopenharmony_ci	pgoff_t nr, pg_start, pg_end, delta, idx;
15488c2ecf20Sopenharmony_ci	loff_t new_size;
15498c2ecf20Sopenharmony_ci	int ret = 0;
15508c2ecf20Sopenharmony_ci
15518c2ecf20Sopenharmony_ci	new_size = i_size_read(inode) + len;
15528c2ecf20Sopenharmony_ci	ret = inode_newsize_ok(inode, new_size);
15538c2ecf20Sopenharmony_ci	if (ret)
15548c2ecf20Sopenharmony_ci		return ret;
15558c2ecf20Sopenharmony_ci
15568c2ecf20Sopenharmony_ci	if (offset >= i_size_read(inode))
15578c2ecf20Sopenharmony_ci		return -EINVAL;
15588c2ecf20Sopenharmony_ci
15598c2ecf20Sopenharmony_ci	/* insert range should be aligned to block size of f2fs. */
15608c2ecf20Sopenharmony_ci	if (offset & (F2FS_BLKSIZE - 1) || len & (F2FS_BLKSIZE - 1))
15618c2ecf20Sopenharmony_ci		return -EINVAL;
15628c2ecf20Sopenharmony_ci
15638c2ecf20Sopenharmony_ci	ret = f2fs_convert_inline_inode(inode);
15648c2ecf20Sopenharmony_ci	if (ret)
15658c2ecf20Sopenharmony_ci		return ret;
15668c2ecf20Sopenharmony_ci
15678c2ecf20Sopenharmony_ci	f2fs_balance_fs(sbi, true);
15688c2ecf20Sopenharmony_ci
15698c2ecf20Sopenharmony_ci	down_write(&F2FS_I(inode)->i_mmap_sem);
15708c2ecf20Sopenharmony_ci	ret = f2fs_truncate_blocks(inode, i_size_read(inode), true);
15718c2ecf20Sopenharmony_ci	up_write(&F2FS_I(inode)->i_mmap_sem);
15728c2ecf20Sopenharmony_ci	if (ret)
15738c2ecf20Sopenharmony_ci		return ret;
15748c2ecf20Sopenharmony_ci
15758c2ecf20Sopenharmony_ci	/* write out all dirty pages from offset */
15768c2ecf20Sopenharmony_ci	ret = filemap_write_and_wait_range(inode->i_mapping, offset, LLONG_MAX);
15778c2ecf20Sopenharmony_ci	if (ret)
15788c2ecf20Sopenharmony_ci		return ret;
15798c2ecf20Sopenharmony_ci
15808c2ecf20Sopenharmony_ci	pg_start = offset >> PAGE_SHIFT;
15818c2ecf20Sopenharmony_ci	pg_end = (offset + len) >> PAGE_SHIFT;
15828c2ecf20Sopenharmony_ci	delta = pg_end - pg_start;
15838c2ecf20Sopenharmony_ci	idx = DIV_ROUND_UP(i_size_read(inode), PAGE_SIZE);
15848c2ecf20Sopenharmony_ci
15858c2ecf20Sopenharmony_ci	/* avoid gc operation during block exchange */
15868c2ecf20Sopenharmony_ci	down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
15878c2ecf20Sopenharmony_ci	down_write(&F2FS_I(inode)->i_mmap_sem);
15888c2ecf20Sopenharmony_ci	truncate_pagecache(inode, offset);
15898c2ecf20Sopenharmony_ci
15908c2ecf20Sopenharmony_ci	while (!ret && idx > pg_start) {
15918c2ecf20Sopenharmony_ci		nr = idx - pg_start;
15928c2ecf20Sopenharmony_ci		if (nr > delta)
15938c2ecf20Sopenharmony_ci			nr = delta;
15948c2ecf20Sopenharmony_ci		idx -= nr;
15958c2ecf20Sopenharmony_ci
15968c2ecf20Sopenharmony_ci		f2fs_lock_op(sbi);
15978c2ecf20Sopenharmony_ci		f2fs_drop_extent_tree(inode);
15988c2ecf20Sopenharmony_ci
15998c2ecf20Sopenharmony_ci		ret = __exchange_data_block(inode, inode, idx,
16008c2ecf20Sopenharmony_ci					idx + delta, nr, false);
16018c2ecf20Sopenharmony_ci		f2fs_unlock_op(sbi);
16028c2ecf20Sopenharmony_ci	}
16038c2ecf20Sopenharmony_ci	up_write(&F2FS_I(inode)->i_mmap_sem);
16048c2ecf20Sopenharmony_ci	up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
16058c2ecf20Sopenharmony_ci
16068c2ecf20Sopenharmony_ci	/* write out all moved pages, if possible */
16078c2ecf20Sopenharmony_ci	down_write(&F2FS_I(inode)->i_mmap_sem);
16088c2ecf20Sopenharmony_ci	filemap_write_and_wait_range(inode->i_mapping, offset, LLONG_MAX);
16098c2ecf20Sopenharmony_ci	truncate_pagecache(inode, offset);
16108c2ecf20Sopenharmony_ci	up_write(&F2FS_I(inode)->i_mmap_sem);
16118c2ecf20Sopenharmony_ci
16128c2ecf20Sopenharmony_ci	if (!ret)
16138c2ecf20Sopenharmony_ci		f2fs_i_size_write(inode, new_size);
16148c2ecf20Sopenharmony_ci	return ret;
16158c2ecf20Sopenharmony_ci}
16168c2ecf20Sopenharmony_ci
16178c2ecf20Sopenharmony_cistatic int expand_inode_data(struct inode *inode, loff_t offset,
16188c2ecf20Sopenharmony_ci					loff_t len, int mode)
16198c2ecf20Sopenharmony_ci{
16208c2ecf20Sopenharmony_ci	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
16218c2ecf20Sopenharmony_ci	struct f2fs_map_blocks map = { .m_next_pgofs = NULL,
16228c2ecf20Sopenharmony_ci			.m_next_extent = NULL, .m_seg_type = NO_CHECK_TYPE,
16238c2ecf20Sopenharmony_ci			.m_may_create = true };
16248c2ecf20Sopenharmony_ci	pgoff_t pg_start, pg_end;
16258c2ecf20Sopenharmony_ci	loff_t new_size = i_size_read(inode);
16268c2ecf20Sopenharmony_ci	loff_t off_end;
16278c2ecf20Sopenharmony_ci	block_t expanded = 0;
16288c2ecf20Sopenharmony_ci	int err;
16298c2ecf20Sopenharmony_ci
16308c2ecf20Sopenharmony_ci	err = inode_newsize_ok(inode, (len + offset));
16318c2ecf20Sopenharmony_ci	if (err)
16328c2ecf20Sopenharmony_ci		return err;
16338c2ecf20Sopenharmony_ci
16348c2ecf20Sopenharmony_ci	err = f2fs_convert_inline_inode(inode);
16358c2ecf20Sopenharmony_ci	if (err)
16368c2ecf20Sopenharmony_ci		return err;
16378c2ecf20Sopenharmony_ci
16388c2ecf20Sopenharmony_ci	f2fs_balance_fs(sbi, true);
16398c2ecf20Sopenharmony_ci
16408c2ecf20Sopenharmony_ci	pg_start = ((unsigned long long)offset) >> PAGE_SHIFT;
16418c2ecf20Sopenharmony_ci	pg_end = ((unsigned long long)offset + len) >> PAGE_SHIFT;
16428c2ecf20Sopenharmony_ci	off_end = (offset + len) & (PAGE_SIZE - 1);
16438c2ecf20Sopenharmony_ci
16448c2ecf20Sopenharmony_ci	map.m_lblk = pg_start;
16458c2ecf20Sopenharmony_ci	map.m_len = pg_end - pg_start;
16468c2ecf20Sopenharmony_ci	if (off_end)
16478c2ecf20Sopenharmony_ci		map.m_len++;
16488c2ecf20Sopenharmony_ci
16498c2ecf20Sopenharmony_ci	if (!map.m_len)
16508c2ecf20Sopenharmony_ci		return 0;
16518c2ecf20Sopenharmony_ci
16528c2ecf20Sopenharmony_ci	if (f2fs_is_pinned_file(inode)) {
16538c2ecf20Sopenharmony_ci		block_t sec_blks = BLKS_PER_SEC(sbi);
16548c2ecf20Sopenharmony_ci		block_t sec_len = roundup(map.m_len, sec_blks);
16558c2ecf20Sopenharmony_ci
16568c2ecf20Sopenharmony_ci		map.m_len = sec_blks;
16578c2ecf20Sopenharmony_cinext_alloc:
16588c2ecf20Sopenharmony_ci		if (has_not_enough_free_secs(sbi, 0,
16598c2ecf20Sopenharmony_ci			GET_SEC_FROM_SEG(sbi, overprovision_segments(sbi)))) {
16608c2ecf20Sopenharmony_ci			down_write(&sbi->gc_lock);
16618c2ecf20Sopenharmony_ci			err = f2fs_gc(sbi, true, false, false, NULL_SEGNO);
16628c2ecf20Sopenharmony_ci			if (err && err != -ENODATA && err != -EAGAIN)
16638c2ecf20Sopenharmony_ci				goto out_err;
16648c2ecf20Sopenharmony_ci		}
16658c2ecf20Sopenharmony_ci
16668c2ecf20Sopenharmony_ci		down_write(&sbi->pin_sem);
16678c2ecf20Sopenharmony_ci
16688c2ecf20Sopenharmony_ci		f2fs_lock_op(sbi);
16698c2ecf20Sopenharmony_ci		f2fs_allocate_new_section(sbi, CURSEG_COLD_DATA_PINNED);
16708c2ecf20Sopenharmony_ci		f2fs_unlock_op(sbi);
16718c2ecf20Sopenharmony_ci
16728c2ecf20Sopenharmony_ci		map.m_seg_type = CURSEG_COLD_DATA_PINNED;
16738c2ecf20Sopenharmony_ci		err = f2fs_map_blocks(inode, &map, 1, F2FS_GET_BLOCK_PRE_DIO);
16748c2ecf20Sopenharmony_ci
16758c2ecf20Sopenharmony_ci		up_write(&sbi->pin_sem);
16768c2ecf20Sopenharmony_ci
16778c2ecf20Sopenharmony_ci		expanded += map.m_len;
16788c2ecf20Sopenharmony_ci		sec_len -= map.m_len;
16798c2ecf20Sopenharmony_ci		map.m_lblk += map.m_len;
16808c2ecf20Sopenharmony_ci		if (!err && sec_len)
16818c2ecf20Sopenharmony_ci			goto next_alloc;
16828c2ecf20Sopenharmony_ci
16838c2ecf20Sopenharmony_ci		map.m_len = expanded;
16848c2ecf20Sopenharmony_ci	} else {
16858c2ecf20Sopenharmony_ci		err = f2fs_map_blocks(inode, &map, 1, F2FS_GET_BLOCK_PRE_AIO);
16868c2ecf20Sopenharmony_ci		expanded = map.m_len;
16878c2ecf20Sopenharmony_ci	}
16888c2ecf20Sopenharmony_ciout_err:
16898c2ecf20Sopenharmony_ci	if (err) {
16908c2ecf20Sopenharmony_ci		pgoff_t last_off;
16918c2ecf20Sopenharmony_ci
16928c2ecf20Sopenharmony_ci		if (!expanded)
16938c2ecf20Sopenharmony_ci			return err;
16948c2ecf20Sopenharmony_ci
16958c2ecf20Sopenharmony_ci		last_off = pg_start + expanded - 1;
16968c2ecf20Sopenharmony_ci
16978c2ecf20Sopenharmony_ci		/* update new size to the failed position */
16988c2ecf20Sopenharmony_ci		new_size = (last_off == pg_end) ? offset + len :
16998c2ecf20Sopenharmony_ci					(loff_t)(last_off + 1) << PAGE_SHIFT;
17008c2ecf20Sopenharmony_ci	} else {
17018c2ecf20Sopenharmony_ci		new_size = ((loff_t)pg_end << PAGE_SHIFT) + off_end;
17028c2ecf20Sopenharmony_ci	}
17038c2ecf20Sopenharmony_ci
17048c2ecf20Sopenharmony_ci	if (new_size > i_size_read(inode)) {
17058c2ecf20Sopenharmony_ci		if (mode & FALLOC_FL_KEEP_SIZE)
17068c2ecf20Sopenharmony_ci			file_set_keep_isize(inode);
17078c2ecf20Sopenharmony_ci		else
17088c2ecf20Sopenharmony_ci			f2fs_i_size_write(inode, new_size);
17098c2ecf20Sopenharmony_ci	}
17108c2ecf20Sopenharmony_ci
17118c2ecf20Sopenharmony_ci	return err;
17128c2ecf20Sopenharmony_ci}
17138c2ecf20Sopenharmony_ci
17148c2ecf20Sopenharmony_cistatic long f2fs_fallocate(struct file *file, int mode,
17158c2ecf20Sopenharmony_ci				loff_t offset, loff_t len)
17168c2ecf20Sopenharmony_ci{
17178c2ecf20Sopenharmony_ci	struct inode *inode = file_inode(file);
17188c2ecf20Sopenharmony_ci	long ret = 0;
17198c2ecf20Sopenharmony_ci
17208c2ecf20Sopenharmony_ci	if (unlikely(f2fs_cp_error(F2FS_I_SB(inode))))
17218c2ecf20Sopenharmony_ci		return -EIO;
17228c2ecf20Sopenharmony_ci	if (!f2fs_is_checkpoint_ready(F2FS_I_SB(inode)))
17238c2ecf20Sopenharmony_ci		return -ENOSPC;
17248c2ecf20Sopenharmony_ci	if (!f2fs_is_compress_backend_ready(inode))
17258c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
17268c2ecf20Sopenharmony_ci
17278c2ecf20Sopenharmony_ci	/* f2fs only support ->fallocate for regular file */
17288c2ecf20Sopenharmony_ci	if (!S_ISREG(inode->i_mode))
17298c2ecf20Sopenharmony_ci		return -EINVAL;
17308c2ecf20Sopenharmony_ci
17318c2ecf20Sopenharmony_ci	if (IS_ENCRYPTED(inode) &&
17328c2ecf20Sopenharmony_ci		(mode & (FALLOC_FL_COLLAPSE_RANGE | FALLOC_FL_INSERT_RANGE)))
17338c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
17348c2ecf20Sopenharmony_ci
17358c2ecf20Sopenharmony_ci	if (f2fs_compressed_file(inode) &&
17368c2ecf20Sopenharmony_ci		(mode & (FALLOC_FL_PUNCH_HOLE | FALLOC_FL_COLLAPSE_RANGE |
17378c2ecf20Sopenharmony_ci			FALLOC_FL_ZERO_RANGE | FALLOC_FL_INSERT_RANGE)))
17388c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
17398c2ecf20Sopenharmony_ci
17408c2ecf20Sopenharmony_ci	if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE |
17418c2ecf20Sopenharmony_ci			FALLOC_FL_COLLAPSE_RANGE | FALLOC_FL_ZERO_RANGE |
17428c2ecf20Sopenharmony_ci			FALLOC_FL_INSERT_RANGE))
17438c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
17448c2ecf20Sopenharmony_ci
17458c2ecf20Sopenharmony_ci	inode_lock(inode);
17468c2ecf20Sopenharmony_ci
17478c2ecf20Sopenharmony_ci	ret = file_modified(file);
17488c2ecf20Sopenharmony_ci	if (ret)
17498c2ecf20Sopenharmony_ci		goto out;
17508c2ecf20Sopenharmony_ci
17518c2ecf20Sopenharmony_ci	if (mode & FALLOC_FL_PUNCH_HOLE) {
17528c2ecf20Sopenharmony_ci		if (offset >= inode->i_size)
17538c2ecf20Sopenharmony_ci			goto out;
17548c2ecf20Sopenharmony_ci
17558c2ecf20Sopenharmony_ci		ret = punch_hole(inode, offset, len);
17568c2ecf20Sopenharmony_ci	} else if (mode & FALLOC_FL_COLLAPSE_RANGE) {
17578c2ecf20Sopenharmony_ci		ret = f2fs_collapse_range(inode, offset, len);
17588c2ecf20Sopenharmony_ci	} else if (mode & FALLOC_FL_ZERO_RANGE) {
17598c2ecf20Sopenharmony_ci		ret = f2fs_zero_range(inode, offset, len, mode);
17608c2ecf20Sopenharmony_ci	} else if (mode & FALLOC_FL_INSERT_RANGE) {
17618c2ecf20Sopenharmony_ci		ret = f2fs_insert_range(inode, offset, len);
17628c2ecf20Sopenharmony_ci	} else {
17638c2ecf20Sopenharmony_ci		ret = expand_inode_data(inode, offset, len, mode);
17648c2ecf20Sopenharmony_ci	}
17658c2ecf20Sopenharmony_ci
17668c2ecf20Sopenharmony_ci	if (!ret) {
17678c2ecf20Sopenharmony_ci		inode->i_mtime = inode->i_ctime = current_time(inode);
17688c2ecf20Sopenharmony_ci		f2fs_mark_inode_dirty_sync(inode, false);
17698c2ecf20Sopenharmony_ci		f2fs_update_time(F2FS_I_SB(inode), REQ_TIME);
17708c2ecf20Sopenharmony_ci	}
17718c2ecf20Sopenharmony_ci
17728c2ecf20Sopenharmony_ciout:
17738c2ecf20Sopenharmony_ci	inode_unlock(inode);
17748c2ecf20Sopenharmony_ci
17758c2ecf20Sopenharmony_ci	trace_f2fs_fallocate(inode, mode, offset, len, ret);
17768c2ecf20Sopenharmony_ci	return ret;
17778c2ecf20Sopenharmony_ci}
17788c2ecf20Sopenharmony_ci
17798c2ecf20Sopenharmony_cistatic int f2fs_release_file(struct inode *inode, struct file *filp)
17808c2ecf20Sopenharmony_ci{
17818c2ecf20Sopenharmony_ci	/*
17828c2ecf20Sopenharmony_ci	 * f2fs_relase_file is called at every close calls. So we should
17838c2ecf20Sopenharmony_ci	 * not drop any inmemory pages by close called by other process.
17848c2ecf20Sopenharmony_ci	 */
17858c2ecf20Sopenharmony_ci	if (!(filp->f_mode & FMODE_WRITE) ||
17868c2ecf20Sopenharmony_ci			atomic_read(&inode->i_writecount) != 1)
17878c2ecf20Sopenharmony_ci		return 0;
17888c2ecf20Sopenharmony_ci
17898c2ecf20Sopenharmony_ci	/* some remained atomic pages should discarded */
17908c2ecf20Sopenharmony_ci	if (f2fs_is_atomic_file(inode))
17918c2ecf20Sopenharmony_ci		f2fs_drop_inmem_pages(inode);
17928c2ecf20Sopenharmony_ci	if (f2fs_is_volatile_file(inode)) {
17938c2ecf20Sopenharmony_ci		set_inode_flag(inode, FI_DROP_CACHE);
17948c2ecf20Sopenharmony_ci		filemap_fdatawrite(inode->i_mapping);
17958c2ecf20Sopenharmony_ci		clear_inode_flag(inode, FI_DROP_CACHE);
17968c2ecf20Sopenharmony_ci		clear_inode_flag(inode, FI_VOLATILE_FILE);
17978c2ecf20Sopenharmony_ci		stat_dec_volatile_write(inode);
17988c2ecf20Sopenharmony_ci	}
17998c2ecf20Sopenharmony_ci	return 0;
18008c2ecf20Sopenharmony_ci}
18018c2ecf20Sopenharmony_ci
18028c2ecf20Sopenharmony_cistatic int f2fs_file_flush(struct file *file, fl_owner_t id)
18038c2ecf20Sopenharmony_ci{
18048c2ecf20Sopenharmony_ci	struct inode *inode = file_inode(file);
18058c2ecf20Sopenharmony_ci
18068c2ecf20Sopenharmony_ci	/*
18078c2ecf20Sopenharmony_ci	 * If the process doing a transaction is crashed, we should do
18088c2ecf20Sopenharmony_ci	 * roll-back. Otherwise, other reader/write can see corrupted database
18098c2ecf20Sopenharmony_ci	 * until all the writers close its file. Since this should be done
18108c2ecf20Sopenharmony_ci	 * before dropping file lock, it needs to do in ->flush.
18118c2ecf20Sopenharmony_ci	 */
18128c2ecf20Sopenharmony_ci	if (f2fs_is_atomic_file(inode) &&
18138c2ecf20Sopenharmony_ci			F2FS_I(inode)->inmem_task == current)
18148c2ecf20Sopenharmony_ci		f2fs_drop_inmem_pages(inode);
18158c2ecf20Sopenharmony_ci	return 0;
18168c2ecf20Sopenharmony_ci}
18178c2ecf20Sopenharmony_ci
18188c2ecf20Sopenharmony_cistatic int f2fs_setflags_common(struct inode *inode, u32 iflags, u32 mask)
18198c2ecf20Sopenharmony_ci{
18208c2ecf20Sopenharmony_ci	struct f2fs_inode_info *fi = F2FS_I(inode);
18218c2ecf20Sopenharmony_ci	u32 masked_flags = fi->i_flags & mask;
18228c2ecf20Sopenharmony_ci
18238c2ecf20Sopenharmony_ci	f2fs_bug_on(F2FS_I_SB(inode), (iflags & ~mask));
18248c2ecf20Sopenharmony_ci
18258c2ecf20Sopenharmony_ci	/* Is it quota file? Do not allow user to mess with it */
18268c2ecf20Sopenharmony_ci	if (IS_NOQUOTA(inode))
18278c2ecf20Sopenharmony_ci		return -EPERM;
18288c2ecf20Sopenharmony_ci
18298c2ecf20Sopenharmony_ci	if ((iflags ^ masked_flags) & F2FS_CASEFOLD_FL) {
18308c2ecf20Sopenharmony_ci		if (!f2fs_sb_has_casefold(F2FS_I_SB(inode)))
18318c2ecf20Sopenharmony_ci			return -EOPNOTSUPP;
18328c2ecf20Sopenharmony_ci		if (!f2fs_empty_dir(inode))
18338c2ecf20Sopenharmony_ci			return -ENOTEMPTY;
18348c2ecf20Sopenharmony_ci	}
18358c2ecf20Sopenharmony_ci
18368c2ecf20Sopenharmony_ci	if (iflags & (F2FS_COMPR_FL | F2FS_NOCOMP_FL)) {
18378c2ecf20Sopenharmony_ci		if (!f2fs_sb_has_compression(F2FS_I_SB(inode)))
18388c2ecf20Sopenharmony_ci			return -EOPNOTSUPP;
18398c2ecf20Sopenharmony_ci		if ((iflags & F2FS_COMPR_FL) && (iflags & F2FS_NOCOMP_FL))
18408c2ecf20Sopenharmony_ci			return -EINVAL;
18418c2ecf20Sopenharmony_ci	}
18428c2ecf20Sopenharmony_ci
18438c2ecf20Sopenharmony_ci	if ((iflags ^ masked_flags) & F2FS_COMPR_FL) {
18448c2ecf20Sopenharmony_ci		if (masked_flags & F2FS_COMPR_FL) {
18458c2ecf20Sopenharmony_ci			if (!f2fs_disable_compressed_file(inode))
18468c2ecf20Sopenharmony_ci				return -EINVAL;
18478c2ecf20Sopenharmony_ci		} else {
18488c2ecf20Sopenharmony_ci			if (!f2fs_may_compress(inode))
18498c2ecf20Sopenharmony_ci				return -EINVAL;
18508c2ecf20Sopenharmony_ci			if (S_ISREG(inode->i_mode) && inode->i_size)
18518c2ecf20Sopenharmony_ci				return -EINVAL;
18528c2ecf20Sopenharmony_ci
18538c2ecf20Sopenharmony_ci			set_compress_context(inode);
18548c2ecf20Sopenharmony_ci		}
18558c2ecf20Sopenharmony_ci	}
18568c2ecf20Sopenharmony_ci
18578c2ecf20Sopenharmony_ci	fi->i_flags = iflags | (fi->i_flags & ~mask);
18588c2ecf20Sopenharmony_ci	f2fs_bug_on(F2FS_I_SB(inode), (fi->i_flags & F2FS_COMPR_FL) &&
18598c2ecf20Sopenharmony_ci					(fi->i_flags & F2FS_NOCOMP_FL));
18608c2ecf20Sopenharmony_ci
18618c2ecf20Sopenharmony_ci	if (fi->i_flags & F2FS_PROJINHERIT_FL)
18628c2ecf20Sopenharmony_ci		set_inode_flag(inode, FI_PROJ_INHERIT);
18638c2ecf20Sopenharmony_ci	else
18648c2ecf20Sopenharmony_ci		clear_inode_flag(inode, FI_PROJ_INHERIT);
18658c2ecf20Sopenharmony_ci
18668c2ecf20Sopenharmony_ci	inode->i_ctime = current_time(inode);
18678c2ecf20Sopenharmony_ci	f2fs_set_inode_flags(inode);
18688c2ecf20Sopenharmony_ci	f2fs_mark_inode_dirty_sync(inode, true);
18698c2ecf20Sopenharmony_ci	return 0;
18708c2ecf20Sopenharmony_ci}
18718c2ecf20Sopenharmony_ci
18728c2ecf20Sopenharmony_ci/* FS_IOC_GETFLAGS and FS_IOC_SETFLAGS support */
18738c2ecf20Sopenharmony_ci
18748c2ecf20Sopenharmony_ci/*
18758c2ecf20Sopenharmony_ci * To make a new on-disk f2fs i_flag gettable via FS_IOC_GETFLAGS, add an entry
18768c2ecf20Sopenharmony_ci * for it to f2fs_fsflags_map[], and add its FS_*_FL equivalent to
18778c2ecf20Sopenharmony_ci * F2FS_GETTABLE_FS_FL.  To also make it settable via FS_IOC_SETFLAGS, also add
18788c2ecf20Sopenharmony_ci * its FS_*_FL equivalent to F2FS_SETTABLE_FS_FL.
18798c2ecf20Sopenharmony_ci */
18808c2ecf20Sopenharmony_ci
18818c2ecf20Sopenharmony_cistatic const struct {
18828c2ecf20Sopenharmony_ci	u32 iflag;
18838c2ecf20Sopenharmony_ci	u32 fsflag;
18848c2ecf20Sopenharmony_ci} f2fs_fsflags_map[] = {
18858c2ecf20Sopenharmony_ci	{ F2FS_COMPR_FL,	FS_COMPR_FL },
18868c2ecf20Sopenharmony_ci	{ F2FS_SYNC_FL,		FS_SYNC_FL },
18878c2ecf20Sopenharmony_ci	{ F2FS_IMMUTABLE_FL,	FS_IMMUTABLE_FL },
18888c2ecf20Sopenharmony_ci	{ F2FS_APPEND_FL,	FS_APPEND_FL },
18898c2ecf20Sopenharmony_ci	{ F2FS_NODUMP_FL,	FS_NODUMP_FL },
18908c2ecf20Sopenharmony_ci	{ F2FS_NOATIME_FL,	FS_NOATIME_FL },
18918c2ecf20Sopenharmony_ci	{ F2FS_NOCOMP_FL,	FS_NOCOMP_FL },
18928c2ecf20Sopenharmony_ci	{ F2FS_INDEX_FL,	FS_INDEX_FL },
18938c2ecf20Sopenharmony_ci	{ F2FS_DIRSYNC_FL,	FS_DIRSYNC_FL },
18948c2ecf20Sopenharmony_ci	{ F2FS_PROJINHERIT_FL,	FS_PROJINHERIT_FL },
18958c2ecf20Sopenharmony_ci	{ F2FS_CASEFOLD_FL,	FS_CASEFOLD_FL },
18968c2ecf20Sopenharmony_ci};
18978c2ecf20Sopenharmony_ci
18988c2ecf20Sopenharmony_ci#define F2FS_GETTABLE_FS_FL (		\
18998c2ecf20Sopenharmony_ci		FS_COMPR_FL |		\
19008c2ecf20Sopenharmony_ci		FS_SYNC_FL |		\
19018c2ecf20Sopenharmony_ci		FS_IMMUTABLE_FL |	\
19028c2ecf20Sopenharmony_ci		FS_APPEND_FL |		\
19038c2ecf20Sopenharmony_ci		FS_NODUMP_FL |		\
19048c2ecf20Sopenharmony_ci		FS_NOATIME_FL |		\
19058c2ecf20Sopenharmony_ci		FS_NOCOMP_FL |		\
19068c2ecf20Sopenharmony_ci		FS_INDEX_FL |		\
19078c2ecf20Sopenharmony_ci		FS_DIRSYNC_FL |		\
19088c2ecf20Sopenharmony_ci		FS_PROJINHERIT_FL |	\
19098c2ecf20Sopenharmony_ci		FS_ENCRYPT_FL |		\
19108c2ecf20Sopenharmony_ci		FS_INLINE_DATA_FL |	\
19118c2ecf20Sopenharmony_ci		FS_NOCOW_FL |		\
19128c2ecf20Sopenharmony_ci		FS_VERITY_FL |		\
19138c2ecf20Sopenharmony_ci		FS_CASEFOLD_FL)
19148c2ecf20Sopenharmony_ci
19158c2ecf20Sopenharmony_ci#define F2FS_SETTABLE_FS_FL (		\
19168c2ecf20Sopenharmony_ci		FS_COMPR_FL |		\
19178c2ecf20Sopenharmony_ci		FS_SYNC_FL |		\
19188c2ecf20Sopenharmony_ci		FS_IMMUTABLE_FL |	\
19198c2ecf20Sopenharmony_ci		FS_APPEND_FL |		\
19208c2ecf20Sopenharmony_ci		FS_NODUMP_FL |		\
19218c2ecf20Sopenharmony_ci		FS_NOATIME_FL |		\
19228c2ecf20Sopenharmony_ci		FS_NOCOMP_FL |		\
19238c2ecf20Sopenharmony_ci		FS_DIRSYNC_FL |		\
19248c2ecf20Sopenharmony_ci		FS_PROJINHERIT_FL |	\
19258c2ecf20Sopenharmony_ci		FS_CASEFOLD_FL)
19268c2ecf20Sopenharmony_ci
19278c2ecf20Sopenharmony_ci/* Convert f2fs on-disk i_flags to FS_IOC_{GET,SET}FLAGS flags */
19288c2ecf20Sopenharmony_cistatic inline u32 f2fs_iflags_to_fsflags(u32 iflags)
19298c2ecf20Sopenharmony_ci{
19308c2ecf20Sopenharmony_ci	u32 fsflags = 0;
19318c2ecf20Sopenharmony_ci	int i;
19328c2ecf20Sopenharmony_ci
19338c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(f2fs_fsflags_map); i++)
19348c2ecf20Sopenharmony_ci		if (iflags & f2fs_fsflags_map[i].iflag)
19358c2ecf20Sopenharmony_ci			fsflags |= f2fs_fsflags_map[i].fsflag;
19368c2ecf20Sopenharmony_ci
19378c2ecf20Sopenharmony_ci	return fsflags;
19388c2ecf20Sopenharmony_ci}
19398c2ecf20Sopenharmony_ci
19408c2ecf20Sopenharmony_ci/* Convert FS_IOC_{GET,SET}FLAGS flags to f2fs on-disk i_flags */
19418c2ecf20Sopenharmony_cistatic inline u32 f2fs_fsflags_to_iflags(u32 fsflags)
19428c2ecf20Sopenharmony_ci{
19438c2ecf20Sopenharmony_ci	u32 iflags = 0;
19448c2ecf20Sopenharmony_ci	int i;
19458c2ecf20Sopenharmony_ci
19468c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(f2fs_fsflags_map); i++)
19478c2ecf20Sopenharmony_ci		if (fsflags & f2fs_fsflags_map[i].fsflag)
19488c2ecf20Sopenharmony_ci			iflags |= f2fs_fsflags_map[i].iflag;
19498c2ecf20Sopenharmony_ci
19508c2ecf20Sopenharmony_ci	return iflags;
19518c2ecf20Sopenharmony_ci}
19528c2ecf20Sopenharmony_ci
19538c2ecf20Sopenharmony_cistatic int f2fs_ioc_getflags(struct file *filp, unsigned long arg)
19548c2ecf20Sopenharmony_ci{
19558c2ecf20Sopenharmony_ci	struct inode *inode = file_inode(filp);
19568c2ecf20Sopenharmony_ci	struct f2fs_inode_info *fi = F2FS_I(inode);
19578c2ecf20Sopenharmony_ci	u32 fsflags = f2fs_iflags_to_fsflags(fi->i_flags);
19588c2ecf20Sopenharmony_ci
19598c2ecf20Sopenharmony_ci	if (IS_ENCRYPTED(inode))
19608c2ecf20Sopenharmony_ci		fsflags |= FS_ENCRYPT_FL;
19618c2ecf20Sopenharmony_ci	if (IS_VERITY(inode))
19628c2ecf20Sopenharmony_ci		fsflags |= FS_VERITY_FL;
19638c2ecf20Sopenharmony_ci	if (f2fs_has_inline_data(inode) || f2fs_has_inline_dentry(inode))
19648c2ecf20Sopenharmony_ci		fsflags |= FS_INLINE_DATA_FL;
19658c2ecf20Sopenharmony_ci	if (is_inode_flag_set(inode, FI_PIN_FILE))
19668c2ecf20Sopenharmony_ci		fsflags |= FS_NOCOW_FL;
19678c2ecf20Sopenharmony_ci
19688c2ecf20Sopenharmony_ci	fsflags &= F2FS_GETTABLE_FS_FL;
19698c2ecf20Sopenharmony_ci
19708c2ecf20Sopenharmony_ci	return put_user(fsflags, (int __user *)arg);
19718c2ecf20Sopenharmony_ci}
19728c2ecf20Sopenharmony_ci
19738c2ecf20Sopenharmony_cistatic int f2fs_ioc_setflags(struct file *filp, unsigned long arg)
19748c2ecf20Sopenharmony_ci{
19758c2ecf20Sopenharmony_ci	struct inode *inode = file_inode(filp);
19768c2ecf20Sopenharmony_ci	struct f2fs_inode_info *fi = F2FS_I(inode);
19778c2ecf20Sopenharmony_ci	u32 fsflags, old_fsflags;
19788c2ecf20Sopenharmony_ci	u32 iflags;
19798c2ecf20Sopenharmony_ci	int ret;
19808c2ecf20Sopenharmony_ci
19818c2ecf20Sopenharmony_ci	if (!inode_owner_or_capable(inode))
19828c2ecf20Sopenharmony_ci		return -EACCES;
19838c2ecf20Sopenharmony_ci
19848c2ecf20Sopenharmony_ci	if (get_user(fsflags, (int __user *)arg))
19858c2ecf20Sopenharmony_ci		return -EFAULT;
19868c2ecf20Sopenharmony_ci
19878c2ecf20Sopenharmony_ci	if (fsflags & ~F2FS_GETTABLE_FS_FL)
19888c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
19898c2ecf20Sopenharmony_ci	fsflags &= F2FS_SETTABLE_FS_FL;
19908c2ecf20Sopenharmony_ci
19918c2ecf20Sopenharmony_ci	iflags = f2fs_fsflags_to_iflags(fsflags);
19928c2ecf20Sopenharmony_ci	if (f2fs_mask_flags(inode->i_mode, iflags) != iflags)
19938c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
19948c2ecf20Sopenharmony_ci
19958c2ecf20Sopenharmony_ci	ret = mnt_want_write_file(filp);
19968c2ecf20Sopenharmony_ci	if (ret)
19978c2ecf20Sopenharmony_ci		return ret;
19988c2ecf20Sopenharmony_ci
19998c2ecf20Sopenharmony_ci	inode_lock(inode);
20008c2ecf20Sopenharmony_ci
20018c2ecf20Sopenharmony_ci	old_fsflags = f2fs_iflags_to_fsflags(fi->i_flags);
20028c2ecf20Sopenharmony_ci	ret = vfs_ioc_setflags_prepare(inode, old_fsflags, fsflags);
20038c2ecf20Sopenharmony_ci	if (ret)
20048c2ecf20Sopenharmony_ci		goto out;
20058c2ecf20Sopenharmony_ci
20068c2ecf20Sopenharmony_ci	ret = f2fs_setflags_common(inode, iflags,
20078c2ecf20Sopenharmony_ci			f2fs_fsflags_to_iflags(F2FS_SETTABLE_FS_FL));
20088c2ecf20Sopenharmony_ciout:
20098c2ecf20Sopenharmony_ci	inode_unlock(inode);
20108c2ecf20Sopenharmony_ci	mnt_drop_write_file(filp);
20118c2ecf20Sopenharmony_ci	return ret;
20128c2ecf20Sopenharmony_ci}
20138c2ecf20Sopenharmony_ci
20148c2ecf20Sopenharmony_cistatic int f2fs_ioc_getversion(struct file *filp, unsigned long arg)
20158c2ecf20Sopenharmony_ci{
20168c2ecf20Sopenharmony_ci	struct inode *inode = file_inode(filp);
20178c2ecf20Sopenharmony_ci
20188c2ecf20Sopenharmony_ci	return put_user(inode->i_generation, (int __user *)arg);
20198c2ecf20Sopenharmony_ci}
20208c2ecf20Sopenharmony_ci
20218c2ecf20Sopenharmony_cistatic int f2fs_ioc_start_atomic_write(struct file *filp)
20228c2ecf20Sopenharmony_ci{
20238c2ecf20Sopenharmony_ci	struct inode *inode = file_inode(filp);
20248c2ecf20Sopenharmony_ci	struct f2fs_inode_info *fi = F2FS_I(inode);
20258c2ecf20Sopenharmony_ci	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
20268c2ecf20Sopenharmony_ci	int ret;
20278c2ecf20Sopenharmony_ci
20288c2ecf20Sopenharmony_ci	if (!inode_owner_or_capable(inode))
20298c2ecf20Sopenharmony_ci		return -EACCES;
20308c2ecf20Sopenharmony_ci
20318c2ecf20Sopenharmony_ci	if (!S_ISREG(inode->i_mode))
20328c2ecf20Sopenharmony_ci		return -EINVAL;
20338c2ecf20Sopenharmony_ci
20348c2ecf20Sopenharmony_ci	if (filp->f_flags & O_DIRECT)
20358c2ecf20Sopenharmony_ci		return -EINVAL;
20368c2ecf20Sopenharmony_ci
20378c2ecf20Sopenharmony_ci	ret = mnt_want_write_file(filp);
20388c2ecf20Sopenharmony_ci	if (ret)
20398c2ecf20Sopenharmony_ci		return ret;
20408c2ecf20Sopenharmony_ci
20418c2ecf20Sopenharmony_ci	inode_lock(inode);
20428c2ecf20Sopenharmony_ci
20438c2ecf20Sopenharmony_ci	if (!f2fs_disable_compressed_file(inode)) {
20448c2ecf20Sopenharmony_ci		ret = -EINVAL;
20458c2ecf20Sopenharmony_ci		goto out;
20468c2ecf20Sopenharmony_ci	}
20478c2ecf20Sopenharmony_ci
20488c2ecf20Sopenharmony_ci	if (f2fs_is_atomic_file(inode)) {
20498c2ecf20Sopenharmony_ci		if (is_inode_flag_set(inode, FI_ATOMIC_REVOKE_REQUEST))
20508c2ecf20Sopenharmony_ci			ret = -EINVAL;
20518c2ecf20Sopenharmony_ci		goto out;
20528c2ecf20Sopenharmony_ci	}
20538c2ecf20Sopenharmony_ci
20548c2ecf20Sopenharmony_ci	ret = f2fs_convert_inline_inode(inode);
20558c2ecf20Sopenharmony_ci	if (ret)
20568c2ecf20Sopenharmony_ci		goto out;
20578c2ecf20Sopenharmony_ci
20588c2ecf20Sopenharmony_ci	down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
20598c2ecf20Sopenharmony_ci
20608c2ecf20Sopenharmony_ci	/*
20618c2ecf20Sopenharmony_ci	 * Should wait end_io to count F2FS_WB_CP_DATA correctly by
20628c2ecf20Sopenharmony_ci	 * f2fs_is_atomic_file.
20638c2ecf20Sopenharmony_ci	 */
20648c2ecf20Sopenharmony_ci	if (get_dirty_pages(inode))
20658c2ecf20Sopenharmony_ci		f2fs_warn(F2FS_I_SB(inode), "Unexpected flush for atomic writes: ino=%lu, npages=%u",
20668c2ecf20Sopenharmony_ci			  inode->i_ino, get_dirty_pages(inode));
20678c2ecf20Sopenharmony_ci	ret = filemap_write_and_wait_range(inode->i_mapping, 0, LLONG_MAX);
20688c2ecf20Sopenharmony_ci	if (ret) {
20698c2ecf20Sopenharmony_ci		up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
20708c2ecf20Sopenharmony_ci		goto out;
20718c2ecf20Sopenharmony_ci	}
20728c2ecf20Sopenharmony_ci
20738c2ecf20Sopenharmony_ci	spin_lock(&sbi->inode_lock[ATOMIC_FILE]);
20748c2ecf20Sopenharmony_ci	if (list_empty(&fi->inmem_ilist))
20758c2ecf20Sopenharmony_ci		list_add_tail(&fi->inmem_ilist, &sbi->inode_list[ATOMIC_FILE]);
20768c2ecf20Sopenharmony_ci	sbi->atomic_files++;
20778c2ecf20Sopenharmony_ci	spin_unlock(&sbi->inode_lock[ATOMIC_FILE]);
20788c2ecf20Sopenharmony_ci
20798c2ecf20Sopenharmony_ci	/* add inode in inmem_list first and set atomic_file */
20808c2ecf20Sopenharmony_ci	set_inode_flag(inode, FI_ATOMIC_FILE);
20818c2ecf20Sopenharmony_ci	clear_inode_flag(inode, FI_ATOMIC_REVOKE_REQUEST);
20828c2ecf20Sopenharmony_ci	up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
20838c2ecf20Sopenharmony_ci
20848c2ecf20Sopenharmony_ci	f2fs_update_time(F2FS_I_SB(inode), REQ_TIME);
20858c2ecf20Sopenharmony_ci	F2FS_I(inode)->inmem_task = current;
20868c2ecf20Sopenharmony_ci	stat_update_max_atomic_write(inode);
20878c2ecf20Sopenharmony_ciout:
20888c2ecf20Sopenharmony_ci	inode_unlock(inode);
20898c2ecf20Sopenharmony_ci	mnt_drop_write_file(filp);
20908c2ecf20Sopenharmony_ci	return ret;
20918c2ecf20Sopenharmony_ci}
20928c2ecf20Sopenharmony_ci
20938c2ecf20Sopenharmony_cistatic int f2fs_ioc_commit_atomic_write(struct file *filp)
20948c2ecf20Sopenharmony_ci{
20958c2ecf20Sopenharmony_ci	struct inode *inode = file_inode(filp);
20968c2ecf20Sopenharmony_ci	int ret;
20978c2ecf20Sopenharmony_ci
20988c2ecf20Sopenharmony_ci	if (!inode_owner_or_capable(inode))
20998c2ecf20Sopenharmony_ci		return -EACCES;
21008c2ecf20Sopenharmony_ci
21018c2ecf20Sopenharmony_ci	ret = mnt_want_write_file(filp);
21028c2ecf20Sopenharmony_ci	if (ret)
21038c2ecf20Sopenharmony_ci		return ret;
21048c2ecf20Sopenharmony_ci
21058c2ecf20Sopenharmony_ci	f2fs_balance_fs(F2FS_I_SB(inode), true);
21068c2ecf20Sopenharmony_ci
21078c2ecf20Sopenharmony_ci	inode_lock(inode);
21088c2ecf20Sopenharmony_ci
21098c2ecf20Sopenharmony_ci	if (f2fs_is_volatile_file(inode)) {
21108c2ecf20Sopenharmony_ci		ret = -EINVAL;
21118c2ecf20Sopenharmony_ci		goto err_out;
21128c2ecf20Sopenharmony_ci	}
21138c2ecf20Sopenharmony_ci
21148c2ecf20Sopenharmony_ci	if (f2fs_is_atomic_file(inode)) {
21158c2ecf20Sopenharmony_ci		ret = f2fs_commit_inmem_pages(inode);
21168c2ecf20Sopenharmony_ci		if (ret)
21178c2ecf20Sopenharmony_ci			goto err_out;
21188c2ecf20Sopenharmony_ci
21198c2ecf20Sopenharmony_ci		ret = f2fs_do_sync_file(filp, 0, LLONG_MAX, 0, true);
21208c2ecf20Sopenharmony_ci		if (!ret)
21218c2ecf20Sopenharmony_ci			f2fs_drop_inmem_pages(inode);
21228c2ecf20Sopenharmony_ci	} else {
21238c2ecf20Sopenharmony_ci		ret = f2fs_do_sync_file(filp, 0, LLONG_MAX, 1, false);
21248c2ecf20Sopenharmony_ci	}
21258c2ecf20Sopenharmony_cierr_out:
21268c2ecf20Sopenharmony_ci	if (is_inode_flag_set(inode, FI_ATOMIC_REVOKE_REQUEST)) {
21278c2ecf20Sopenharmony_ci		clear_inode_flag(inode, FI_ATOMIC_REVOKE_REQUEST);
21288c2ecf20Sopenharmony_ci		ret = -EINVAL;
21298c2ecf20Sopenharmony_ci	}
21308c2ecf20Sopenharmony_ci	inode_unlock(inode);
21318c2ecf20Sopenharmony_ci	mnt_drop_write_file(filp);
21328c2ecf20Sopenharmony_ci	return ret;
21338c2ecf20Sopenharmony_ci}
21348c2ecf20Sopenharmony_ci
21358c2ecf20Sopenharmony_cistatic int f2fs_ioc_start_volatile_write(struct file *filp)
21368c2ecf20Sopenharmony_ci{
21378c2ecf20Sopenharmony_ci	struct inode *inode = file_inode(filp);
21388c2ecf20Sopenharmony_ci	int ret;
21398c2ecf20Sopenharmony_ci
21408c2ecf20Sopenharmony_ci	if (!inode_owner_or_capable(inode))
21418c2ecf20Sopenharmony_ci		return -EACCES;
21428c2ecf20Sopenharmony_ci
21438c2ecf20Sopenharmony_ci	if (!S_ISREG(inode->i_mode))
21448c2ecf20Sopenharmony_ci		return -EINVAL;
21458c2ecf20Sopenharmony_ci
21468c2ecf20Sopenharmony_ci	ret = mnt_want_write_file(filp);
21478c2ecf20Sopenharmony_ci	if (ret)
21488c2ecf20Sopenharmony_ci		return ret;
21498c2ecf20Sopenharmony_ci
21508c2ecf20Sopenharmony_ci	inode_lock(inode);
21518c2ecf20Sopenharmony_ci
21528c2ecf20Sopenharmony_ci	if (f2fs_is_volatile_file(inode))
21538c2ecf20Sopenharmony_ci		goto out;
21548c2ecf20Sopenharmony_ci
21558c2ecf20Sopenharmony_ci	ret = f2fs_convert_inline_inode(inode);
21568c2ecf20Sopenharmony_ci	if (ret)
21578c2ecf20Sopenharmony_ci		goto out;
21588c2ecf20Sopenharmony_ci
21598c2ecf20Sopenharmony_ci	stat_inc_volatile_write(inode);
21608c2ecf20Sopenharmony_ci	stat_update_max_volatile_write(inode);
21618c2ecf20Sopenharmony_ci
21628c2ecf20Sopenharmony_ci	set_inode_flag(inode, FI_VOLATILE_FILE);
21638c2ecf20Sopenharmony_ci	f2fs_update_time(F2FS_I_SB(inode), REQ_TIME);
21648c2ecf20Sopenharmony_ciout:
21658c2ecf20Sopenharmony_ci	inode_unlock(inode);
21668c2ecf20Sopenharmony_ci	mnt_drop_write_file(filp);
21678c2ecf20Sopenharmony_ci	return ret;
21688c2ecf20Sopenharmony_ci}
21698c2ecf20Sopenharmony_ci
21708c2ecf20Sopenharmony_cistatic int f2fs_ioc_release_volatile_write(struct file *filp)
21718c2ecf20Sopenharmony_ci{
21728c2ecf20Sopenharmony_ci	struct inode *inode = file_inode(filp);
21738c2ecf20Sopenharmony_ci	int ret;
21748c2ecf20Sopenharmony_ci
21758c2ecf20Sopenharmony_ci	if (!inode_owner_or_capable(inode))
21768c2ecf20Sopenharmony_ci		return -EACCES;
21778c2ecf20Sopenharmony_ci
21788c2ecf20Sopenharmony_ci	ret = mnt_want_write_file(filp);
21798c2ecf20Sopenharmony_ci	if (ret)
21808c2ecf20Sopenharmony_ci		return ret;
21818c2ecf20Sopenharmony_ci
21828c2ecf20Sopenharmony_ci	inode_lock(inode);
21838c2ecf20Sopenharmony_ci
21848c2ecf20Sopenharmony_ci	if (!f2fs_is_volatile_file(inode))
21858c2ecf20Sopenharmony_ci		goto out;
21868c2ecf20Sopenharmony_ci
21878c2ecf20Sopenharmony_ci	if (!f2fs_is_first_block_written(inode)) {
21888c2ecf20Sopenharmony_ci		ret = truncate_partial_data_page(inode, 0, true);
21898c2ecf20Sopenharmony_ci		goto out;
21908c2ecf20Sopenharmony_ci	}
21918c2ecf20Sopenharmony_ci
21928c2ecf20Sopenharmony_ci	ret = punch_hole(inode, 0, F2FS_BLKSIZE);
21938c2ecf20Sopenharmony_ciout:
21948c2ecf20Sopenharmony_ci	inode_unlock(inode);
21958c2ecf20Sopenharmony_ci	mnt_drop_write_file(filp);
21968c2ecf20Sopenharmony_ci	return ret;
21978c2ecf20Sopenharmony_ci}
21988c2ecf20Sopenharmony_ci
21998c2ecf20Sopenharmony_cistatic int f2fs_ioc_abort_volatile_write(struct file *filp)
22008c2ecf20Sopenharmony_ci{
22018c2ecf20Sopenharmony_ci	struct inode *inode = file_inode(filp);
22028c2ecf20Sopenharmony_ci	int ret;
22038c2ecf20Sopenharmony_ci
22048c2ecf20Sopenharmony_ci	if (!inode_owner_or_capable(inode))
22058c2ecf20Sopenharmony_ci		return -EACCES;
22068c2ecf20Sopenharmony_ci
22078c2ecf20Sopenharmony_ci	ret = mnt_want_write_file(filp);
22088c2ecf20Sopenharmony_ci	if (ret)
22098c2ecf20Sopenharmony_ci		return ret;
22108c2ecf20Sopenharmony_ci
22118c2ecf20Sopenharmony_ci	inode_lock(inode);
22128c2ecf20Sopenharmony_ci
22138c2ecf20Sopenharmony_ci	if (f2fs_is_atomic_file(inode))
22148c2ecf20Sopenharmony_ci		f2fs_drop_inmem_pages(inode);
22158c2ecf20Sopenharmony_ci	if (f2fs_is_volatile_file(inode)) {
22168c2ecf20Sopenharmony_ci		clear_inode_flag(inode, FI_VOLATILE_FILE);
22178c2ecf20Sopenharmony_ci		stat_dec_volatile_write(inode);
22188c2ecf20Sopenharmony_ci		ret = f2fs_do_sync_file(filp, 0, LLONG_MAX, 0, true);
22198c2ecf20Sopenharmony_ci	}
22208c2ecf20Sopenharmony_ci
22218c2ecf20Sopenharmony_ci	clear_inode_flag(inode, FI_ATOMIC_REVOKE_REQUEST);
22228c2ecf20Sopenharmony_ci
22238c2ecf20Sopenharmony_ci	inode_unlock(inode);
22248c2ecf20Sopenharmony_ci
22258c2ecf20Sopenharmony_ci	mnt_drop_write_file(filp);
22268c2ecf20Sopenharmony_ci	f2fs_update_time(F2FS_I_SB(inode), REQ_TIME);
22278c2ecf20Sopenharmony_ci	return ret;
22288c2ecf20Sopenharmony_ci}
22298c2ecf20Sopenharmony_ci
22308c2ecf20Sopenharmony_cistatic int f2fs_ioc_shutdown(struct file *filp, unsigned long arg)
22318c2ecf20Sopenharmony_ci{
22328c2ecf20Sopenharmony_ci	struct inode *inode = file_inode(filp);
22338c2ecf20Sopenharmony_ci	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
22348c2ecf20Sopenharmony_ci	struct super_block *sb = sbi->sb;
22358c2ecf20Sopenharmony_ci	__u32 in;
22368c2ecf20Sopenharmony_ci	int ret = 0;
22378c2ecf20Sopenharmony_ci
22388c2ecf20Sopenharmony_ci	if (!capable(CAP_SYS_ADMIN))
22398c2ecf20Sopenharmony_ci		return -EPERM;
22408c2ecf20Sopenharmony_ci
22418c2ecf20Sopenharmony_ci	if (get_user(in, (__u32 __user *)arg))
22428c2ecf20Sopenharmony_ci		return -EFAULT;
22438c2ecf20Sopenharmony_ci
22448c2ecf20Sopenharmony_ci	if (in != F2FS_GOING_DOWN_FULLSYNC) {
22458c2ecf20Sopenharmony_ci		ret = mnt_want_write_file(filp);
22468c2ecf20Sopenharmony_ci		if (ret) {
22478c2ecf20Sopenharmony_ci			if (ret == -EROFS) {
22488c2ecf20Sopenharmony_ci				ret = 0;
22498c2ecf20Sopenharmony_ci				f2fs_stop_checkpoint(sbi, false);
22508c2ecf20Sopenharmony_ci				set_sbi_flag(sbi, SBI_IS_SHUTDOWN);
22518c2ecf20Sopenharmony_ci				trace_f2fs_shutdown(sbi, in, ret);
22528c2ecf20Sopenharmony_ci			}
22538c2ecf20Sopenharmony_ci			return ret;
22548c2ecf20Sopenharmony_ci		}
22558c2ecf20Sopenharmony_ci	}
22568c2ecf20Sopenharmony_ci
22578c2ecf20Sopenharmony_ci	switch (in) {
22588c2ecf20Sopenharmony_ci	case F2FS_GOING_DOWN_FULLSYNC:
22598c2ecf20Sopenharmony_ci		sb = freeze_bdev(sb->s_bdev);
22608c2ecf20Sopenharmony_ci		if (IS_ERR(sb)) {
22618c2ecf20Sopenharmony_ci			ret = PTR_ERR(sb);
22628c2ecf20Sopenharmony_ci			goto out;
22638c2ecf20Sopenharmony_ci		}
22648c2ecf20Sopenharmony_ci		if (sb) {
22658c2ecf20Sopenharmony_ci			f2fs_stop_checkpoint(sbi, false);
22668c2ecf20Sopenharmony_ci			set_sbi_flag(sbi, SBI_IS_SHUTDOWN);
22678c2ecf20Sopenharmony_ci			thaw_bdev(sb->s_bdev, sb);
22688c2ecf20Sopenharmony_ci		}
22698c2ecf20Sopenharmony_ci		break;
22708c2ecf20Sopenharmony_ci	case F2FS_GOING_DOWN_METASYNC:
22718c2ecf20Sopenharmony_ci		/* do checkpoint only */
22728c2ecf20Sopenharmony_ci		ret = f2fs_sync_fs(sb, 1);
22738c2ecf20Sopenharmony_ci		if (ret)
22748c2ecf20Sopenharmony_ci			goto out;
22758c2ecf20Sopenharmony_ci		f2fs_stop_checkpoint(sbi, false);
22768c2ecf20Sopenharmony_ci		set_sbi_flag(sbi, SBI_IS_SHUTDOWN);
22778c2ecf20Sopenharmony_ci		break;
22788c2ecf20Sopenharmony_ci	case F2FS_GOING_DOWN_NOSYNC:
22798c2ecf20Sopenharmony_ci		f2fs_stop_checkpoint(sbi, false);
22808c2ecf20Sopenharmony_ci		set_sbi_flag(sbi, SBI_IS_SHUTDOWN);
22818c2ecf20Sopenharmony_ci		break;
22828c2ecf20Sopenharmony_ci	case F2FS_GOING_DOWN_METAFLUSH:
22838c2ecf20Sopenharmony_ci		f2fs_sync_meta_pages(sbi, META, LONG_MAX, FS_META_IO);
22848c2ecf20Sopenharmony_ci		f2fs_stop_checkpoint(sbi, false);
22858c2ecf20Sopenharmony_ci		set_sbi_flag(sbi, SBI_IS_SHUTDOWN);
22868c2ecf20Sopenharmony_ci		break;
22878c2ecf20Sopenharmony_ci	case F2FS_GOING_DOWN_NEED_FSCK:
22888c2ecf20Sopenharmony_ci		set_sbi_flag(sbi, SBI_NEED_FSCK);
22898c2ecf20Sopenharmony_ci		set_sbi_flag(sbi, SBI_CP_DISABLED_QUICK);
22908c2ecf20Sopenharmony_ci		set_sbi_flag(sbi, SBI_IS_DIRTY);
22918c2ecf20Sopenharmony_ci		/* do checkpoint only */
22928c2ecf20Sopenharmony_ci		ret = f2fs_sync_fs(sb, 1);
22938c2ecf20Sopenharmony_ci		goto out;
22948c2ecf20Sopenharmony_ci	default:
22958c2ecf20Sopenharmony_ci		ret = -EINVAL;
22968c2ecf20Sopenharmony_ci		goto out;
22978c2ecf20Sopenharmony_ci	}
22988c2ecf20Sopenharmony_ci
22998c2ecf20Sopenharmony_ci	f2fs_stop_gc_thread(sbi);
23008c2ecf20Sopenharmony_ci	f2fs_stop_discard_thread(sbi);
23018c2ecf20Sopenharmony_ci
23028c2ecf20Sopenharmony_ci	f2fs_drop_discard_cmd(sbi);
23038c2ecf20Sopenharmony_ci	clear_opt(sbi, DISCARD);
23048c2ecf20Sopenharmony_ci
23058c2ecf20Sopenharmony_ci	f2fs_update_time(sbi, REQ_TIME);
23068c2ecf20Sopenharmony_ciout:
23078c2ecf20Sopenharmony_ci	if (in != F2FS_GOING_DOWN_FULLSYNC)
23088c2ecf20Sopenharmony_ci		mnt_drop_write_file(filp);
23098c2ecf20Sopenharmony_ci
23108c2ecf20Sopenharmony_ci	trace_f2fs_shutdown(sbi, in, ret);
23118c2ecf20Sopenharmony_ci
23128c2ecf20Sopenharmony_ci	return ret;
23138c2ecf20Sopenharmony_ci}
23148c2ecf20Sopenharmony_ci
23158c2ecf20Sopenharmony_cistatic int f2fs_ioc_fitrim(struct file *filp, unsigned long arg)
23168c2ecf20Sopenharmony_ci{
23178c2ecf20Sopenharmony_ci	struct inode *inode = file_inode(filp);
23188c2ecf20Sopenharmony_ci	struct super_block *sb = inode->i_sb;
23198c2ecf20Sopenharmony_ci	struct request_queue *q = bdev_get_queue(sb->s_bdev);
23208c2ecf20Sopenharmony_ci	struct fstrim_range range;
23218c2ecf20Sopenharmony_ci	int ret;
23228c2ecf20Sopenharmony_ci
23238c2ecf20Sopenharmony_ci	if (!capable(CAP_SYS_ADMIN))
23248c2ecf20Sopenharmony_ci		return -EPERM;
23258c2ecf20Sopenharmony_ci
23268c2ecf20Sopenharmony_ci	if (!f2fs_hw_support_discard(F2FS_SB(sb)))
23278c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
23288c2ecf20Sopenharmony_ci
23298c2ecf20Sopenharmony_ci	if (copy_from_user(&range, (struct fstrim_range __user *)arg,
23308c2ecf20Sopenharmony_ci				sizeof(range)))
23318c2ecf20Sopenharmony_ci		return -EFAULT;
23328c2ecf20Sopenharmony_ci
23338c2ecf20Sopenharmony_ci	ret = mnt_want_write_file(filp);
23348c2ecf20Sopenharmony_ci	if (ret)
23358c2ecf20Sopenharmony_ci		return ret;
23368c2ecf20Sopenharmony_ci
23378c2ecf20Sopenharmony_ci	range.minlen = max((unsigned int)range.minlen,
23388c2ecf20Sopenharmony_ci				q->limits.discard_granularity);
23398c2ecf20Sopenharmony_ci	ret = f2fs_trim_fs(F2FS_SB(sb), &range);
23408c2ecf20Sopenharmony_ci	mnt_drop_write_file(filp);
23418c2ecf20Sopenharmony_ci	if (ret < 0)
23428c2ecf20Sopenharmony_ci		return ret;
23438c2ecf20Sopenharmony_ci
23448c2ecf20Sopenharmony_ci	if (copy_to_user((struct fstrim_range __user *)arg, &range,
23458c2ecf20Sopenharmony_ci				sizeof(range)))
23468c2ecf20Sopenharmony_ci		return -EFAULT;
23478c2ecf20Sopenharmony_ci	f2fs_update_time(F2FS_I_SB(inode), REQ_TIME);
23488c2ecf20Sopenharmony_ci	return 0;
23498c2ecf20Sopenharmony_ci}
23508c2ecf20Sopenharmony_ci
23518c2ecf20Sopenharmony_cistatic bool uuid_is_nonzero(__u8 u[16])
23528c2ecf20Sopenharmony_ci{
23538c2ecf20Sopenharmony_ci	int i;
23548c2ecf20Sopenharmony_ci
23558c2ecf20Sopenharmony_ci	for (i = 0; i < 16; i++)
23568c2ecf20Sopenharmony_ci		if (u[i])
23578c2ecf20Sopenharmony_ci			return true;
23588c2ecf20Sopenharmony_ci	return false;
23598c2ecf20Sopenharmony_ci}
23608c2ecf20Sopenharmony_ci
23618c2ecf20Sopenharmony_cistatic int f2fs_ioc_set_encryption_policy(struct file *filp, unsigned long arg)
23628c2ecf20Sopenharmony_ci{
23638c2ecf20Sopenharmony_ci	struct inode *inode = file_inode(filp);
23648c2ecf20Sopenharmony_ci
23658c2ecf20Sopenharmony_ci	if (!f2fs_sb_has_encrypt(F2FS_I_SB(inode)))
23668c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
23678c2ecf20Sopenharmony_ci
23688c2ecf20Sopenharmony_ci	f2fs_update_time(F2FS_I_SB(inode), REQ_TIME);
23698c2ecf20Sopenharmony_ci
23708c2ecf20Sopenharmony_ci	return fscrypt_ioctl_set_policy(filp, (const void __user *)arg);
23718c2ecf20Sopenharmony_ci}
23728c2ecf20Sopenharmony_ci
23738c2ecf20Sopenharmony_cistatic int f2fs_ioc_get_encryption_policy(struct file *filp, unsigned long arg)
23748c2ecf20Sopenharmony_ci{
23758c2ecf20Sopenharmony_ci	if (!f2fs_sb_has_encrypt(F2FS_I_SB(file_inode(filp))))
23768c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
23778c2ecf20Sopenharmony_ci	return fscrypt_ioctl_get_policy(filp, (void __user *)arg);
23788c2ecf20Sopenharmony_ci}
23798c2ecf20Sopenharmony_ci
23808c2ecf20Sopenharmony_cistatic int f2fs_ioc_get_encryption_pwsalt(struct file *filp, unsigned long arg)
23818c2ecf20Sopenharmony_ci{
23828c2ecf20Sopenharmony_ci	struct inode *inode = file_inode(filp);
23838c2ecf20Sopenharmony_ci	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
23848c2ecf20Sopenharmony_ci	int err;
23858c2ecf20Sopenharmony_ci
23868c2ecf20Sopenharmony_ci	if (!f2fs_sb_has_encrypt(sbi))
23878c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
23888c2ecf20Sopenharmony_ci
23898c2ecf20Sopenharmony_ci	err = mnt_want_write_file(filp);
23908c2ecf20Sopenharmony_ci	if (err)
23918c2ecf20Sopenharmony_ci		return err;
23928c2ecf20Sopenharmony_ci
23938c2ecf20Sopenharmony_ci	down_write(&sbi->sb_lock);
23948c2ecf20Sopenharmony_ci
23958c2ecf20Sopenharmony_ci	if (uuid_is_nonzero(sbi->raw_super->encrypt_pw_salt))
23968c2ecf20Sopenharmony_ci		goto got_it;
23978c2ecf20Sopenharmony_ci
23988c2ecf20Sopenharmony_ci	/* update superblock with uuid */
23998c2ecf20Sopenharmony_ci	generate_random_uuid(sbi->raw_super->encrypt_pw_salt);
24008c2ecf20Sopenharmony_ci
24018c2ecf20Sopenharmony_ci	err = f2fs_commit_super(sbi, false);
24028c2ecf20Sopenharmony_ci	if (err) {
24038c2ecf20Sopenharmony_ci		/* undo new data */
24048c2ecf20Sopenharmony_ci		memset(sbi->raw_super->encrypt_pw_salt, 0, 16);
24058c2ecf20Sopenharmony_ci		goto out_err;
24068c2ecf20Sopenharmony_ci	}
24078c2ecf20Sopenharmony_cigot_it:
24088c2ecf20Sopenharmony_ci	if (copy_to_user((__u8 __user *)arg, sbi->raw_super->encrypt_pw_salt,
24098c2ecf20Sopenharmony_ci									16))
24108c2ecf20Sopenharmony_ci		err = -EFAULT;
24118c2ecf20Sopenharmony_ciout_err:
24128c2ecf20Sopenharmony_ci	up_write(&sbi->sb_lock);
24138c2ecf20Sopenharmony_ci	mnt_drop_write_file(filp);
24148c2ecf20Sopenharmony_ci	return err;
24158c2ecf20Sopenharmony_ci}
24168c2ecf20Sopenharmony_ci
24178c2ecf20Sopenharmony_cistatic int f2fs_ioc_get_encryption_policy_ex(struct file *filp,
24188c2ecf20Sopenharmony_ci					     unsigned long arg)
24198c2ecf20Sopenharmony_ci{
24208c2ecf20Sopenharmony_ci	if (!f2fs_sb_has_encrypt(F2FS_I_SB(file_inode(filp))))
24218c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
24228c2ecf20Sopenharmony_ci
24238c2ecf20Sopenharmony_ci	return fscrypt_ioctl_get_policy_ex(filp, (void __user *)arg);
24248c2ecf20Sopenharmony_ci}
24258c2ecf20Sopenharmony_ci
24268c2ecf20Sopenharmony_cistatic int f2fs_ioc_add_encryption_key(struct file *filp, unsigned long arg)
24278c2ecf20Sopenharmony_ci{
24288c2ecf20Sopenharmony_ci	if (!f2fs_sb_has_encrypt(F2FS_I_SB(file_inode(filp))))
24298c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
24308c2ecf20Sopenharmony_ci
24318c2ecf20Sopenharmony_ci	return fscrypt_ioctl_add_key(filp, (void __user *)arg);
24328c2ecf20Sopenharmony_ci}
24338c2ecf20Sopenharmony_ci
24348c2ecf20Sopenharmony_cistatic int f2fs_ioc_remove_encryption_key(struct file *filp, unsigned long arg)
24358c2ecf20Sopenharmony_ci{
24368c2ecf20Sopenharmony_ci	if (!f2fs_sb_has_encrypt(F2FS_I_SB(file_inode(filp))))
24378c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
24388c2ecf20Sopenharmony_ci
24398c2ecf20Sopenharmony_ci	return fscrypt_ioctl_remove_key(filp, (void __user *)arg);
24408c2ecf20Sopenharmony_ci}
24418c2ecf20Sopenharmony_ci
24428c2ecf20Sopenharmony_cistatic int f2fs_ioc_remove_encryption_key_all_users(struct file *filp,
24438c2ecf20Sopenharmony_ci						    unsigned long arg)
24448c2ecf20Sopenharmony_ci{
24458c2ecf20Sopenharmony_ci	if (!f2fs_sb_has_encrypt(F2FS_I_SB(file_inode(filp))))
24468c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
24478c2ecf20Sopenharmony_ci
24488c2ecf20Sopenharmony_ci	return fscrypt_ioctl_remove_key_all_users(filp, (void __user *)arg);
24498c2ecf20Sopenharmony_ci}
24508c2ecf20Sopenharmony_ci
24518c2ecf20Sopenharmony_cistatic int f2fs_ioc_get_encryption_key_status(struct file *filp,
24528c2ecf20Sopenharmony_ci					      unsigned long arg)
24538c2ecf20Sopenharmony_ci{
24548c2ecf20Sopenharmony_ci	if (!f2fs_sb_has_encrypt(F2FS_I_SB(file_inode(filp))))
24558c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
24568c2ecf20Sopenharmony_ci
24578c2ecf20Sopenharmony_ci	return fscrypt_ioctl_get_key_status(filp, (void __user *)arg);
24588c2ecf20Sopenharmony_ci}
24598c2ecf20Sopenharmony_ci
24608c2ecf20Sopenharmony_cistatic int f2fs_ioc_get_encryption_nonce(struct file *filp, unsigned long arg)
24618c2ecf20Sopenharmony_ci{
24628c2ecf20Sopenharmony_ci	if (!f2fs_sb_has_encrypt(F2FS_I_SB(file_inode(filp))))
24638c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
24648c2ecf20Sopenharmony_ci
24658c2ecf20Sopenharmony_ci	return fscrypt_ioctl_get_nonce(filp, (void __user *)arg);
24668c2ecf20Sopenharmony_ci}
24678c2ecf20Sopenharmony_ci
24688c2ecf20Sopenharmony_cistatic int f2fs_ioc_gc(struct file *filp, unsigned long arg)
24698c2ecf20Sopenharmony_ci{
24708c2ecf20Sopenharmony_ci	struct inode *inode = file_inode(filp);
24718c2ecf20Sopenharmony_ci	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
24728c2ecf20Sopenharmony_ci	__u32 sync;
24738c2ecf20Sopenharmony_ci	int ret;
24748c2ecf20Sopenharmony_ci
24758c2ecf20Sopenharmony_ci	if (!capable(CAP_SYS_ADMIN))
24768c2ecf20Sopenharmony_ci		return -EPERM;
24778c2ecf20Sopenharmony_ci
24788c2ecf20Sopenharmony_ci	if (get_user(sync, (__u32 __user *)arg))
24798c2ecf20Sopenharmony_ci		return -EFAULT;
24808c2ecf20Sopenharmony_ci
24818c2ecf20Sopenharmony_ci	if (f2fs_readonly(sbi->sb))
24828c2ecf20Sopenharmony_ci		return -EROFS;
24838c2ecf20Sopenharmony_ci
24848c2ecf20Sopenharmony_ci	ret = mnt_want_write_file(filp);
24858c2ecf20Sopenharmony_ci	if (ret)
24868c2ecf20Sopenharmony_ci		return ret;
24878c2ecf20Sopenharmony_ci
24888c2ecf20Sopenharmony_ci	if (!sync) {
24898c2ecf20Sopenharmony_ci		if (!down_write_trylock(&sbi->gc_lock)) {
24908c2ecf20Sopenharmony_ci			ret = -EBUSY;
24918c2ecf20Sopenharmony_ci			goto out;
24928c2ecf20Sopenharmony_ci		}
24938c2ecf20Sopenharmony_ci	} else {
24948c2ecf20Sopenharmony_ci		down_write(&sbi->gc_lock);
24958c2ecf20Sopenharmony_ci	}
24968c2ecf20Sopenharmony_ci
24978c2ecf20Sopenharmony_ci	ret = f2fs_gc(sbi, sync, true, false, NULL_SEGNO);
24988c2ecf20Sopenharmony_ciout:
24998c2ecf20Sopenharmony_ci	mnt_drop_write_file(filp);
25008c2ecf20Sopenharmony_ci	return ret;
25018c2ecf20Sopenharmony_ci}
25028c2ecf20Sopenharmony_ci
25038c2ecf20Sopenharmony_cistatic int __f2fs_ioc_gc_range(struct file *filp, struct f2fs_gc_range *range)
25048c2ecf20Sopenharmony_ci{
25058c2ecf20Sopenharmony_ci	struct f2fs_sb_info *sbi = F2FS_I_SB(file_inode(filp));
25068c2ecf20Sopenharmony_ci	u64 end;
25078c2ecf20Sopenharmony_ci	int ret;
25088c2ecf20Sopenharmony_ci
25098c2ecf20Sopenharmony_ci	if (!capable(CAP_SYS_ADMIN))
25108c2ecf20Sopenharmony_ci		return -EPERM;
25118c2ecf20Sopenharmony_ci	if (f2fs_readonly(sbi->sb))
25128c2ecf20Sopenharmony_ci		return -EROFS;
25138c2ecf20Sopenharmony_ci
25148c2ecf20Sopenharmony_ci	end = range->start + range->len;
25158c2ecf20Sopenharmony_ci	if (end < range->start || range->start < MAIN_BLKADDR(sbi) ||
25168c2ecf20Sopenharmony_ci					end >= MAX_BLKADDR(sbi))
25178c2ecf20Sopenharmony_ci		return -EINVAL;
25188c2ecf20Sopenharmony_ci
25198c2ecf20Sopenharmony_ci	ret = mnt_want_write_file(filp);
25208c2ecf20Sopenharmony_ci	if (ret)
25218c2ecf20Sopenharmony_ci		return ret;
25228c2ecf20Sopenharmony_ci
25238c2ecf20Sopenharmony_cido_more:
25248c2ecf20Sopenharmony_ci	if (!range->sync) {
25258c2ecf20Sopenharmony_ci		if (!down_write_trylock(&sbi->gc_lock)) {
25268c2ecf20Sopenharmony_ci			ret = -EBUSY;
25278c2ecf20Sopenharmony_ci			goto out;
25288c2ecf20Sopenharmony_ci		}
25298c2ecf20Sopenharmony_ci	} else {
25308c2ecf20Sopenharmony_ci		down_write(&sbi->gc_lock);
25318c2ecf20Sopenharmony_ci	}
25328c2ecf20Sopenharmony_ci
25338c2ecf20Sopenharmony_ci	ret = f2fs_gc(sbi, range->sync, true, false,
25348c2ecf20Sopenharmony_ci				GET_SEGNO(sbi, range->start));
25358c2ecf20Sopenharmony_ci	if (ret) {
25368c2ecf20Sopenharmony_ci		if (ret == -EBUSY)
25378c2ecf20Sopenharmony_ci			ret = -EAGAIN;
25388c2ecf20Sopenharmony_ci		goto out;
25398c2ecf20Sopenharmony_ci	}
25408c2ecf20Sopenharmony_ci	range->start += BLKS_PER_SEC(sbi);
25418c2ecf20Sopenharmony_ci	if (range->start <= end)
25428c2ecf20Sopenharmony_ci		goto do_more;
25438c2ecf20Sopenharmony_ciout:
25448c2ecf20Sopenharmony_ci	mnt_drop_write_file(filp);
25458c2ecf20Sopenharmony_ci	return ret;
25468c2ecf20Sopenharmony_ci}
25478c2ecf20Sopenharmony_ci
25488c2ecf20Sopenharmony_cistatic int f2fs_ioc_gc_range(struct file *filp, unsigned long arg)
25498c2ecf20Sopenharmony_ci{
25508c2ecf20Sopenharmony_ci	struct f2fs_gc_range range;
25518c2ecf20Sopenharmony_ci
25528c2ecf20Sopenharmony_ci	if (copy_from_user(&range, (struct f2fs_gc_range __user *)arg,
25538c2ecf20Sopenharmony_ci							sizeof(range)))
25548c2ecf20Sopenharmony_ci		return -EFAULT;
25558c2ecf20Sopenharmony_ci	return __f2fs_ioc_gc_range(filp, &range);
25568c2ecf20Sopenharmony_ci}
25578c2ecf20Sopenharmony_ci
25588c2ecf20Sopenharmony_cistatic int f2fs_ioc_write_checkpoint(struct file *filp, unsigned long arg)
25598c2ecf20Sopenharmony_ci{
25608c2ecf20Sopenharmony_ci	struct inode *inode = file_inode(filp);
25618c2ecf20Sopenharmony_ci	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
25628c2ecf20Sopenharmony_ci	int ret;
25638c2ecf20Sopenharmony_ci
25648c2ecf20Sopenharmony_ci	if (!capable(CAP_SYS_ADMIN))
25658c2ecf20Sopenharmony_ci		return -EPERM;
25668c2ecf20Sopenharmony_ci
25678c2ecf20Sopenharmony_ci	if (f2fs_readonly(sbi->sb))
25688c2ecf20Sopenharmony_ci		return -EROFS;
25698c2ecf20Sopenharmony_ci
25708c2ecf20Sopenharmony_ci	if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED))) {
25718c2ecf20Sopenharmony_ci		f2fs_info(sbi, "Skipping Checkpoint. Checkpoints currently disabled.");
25728c2ecf20Sopenharmony_ci		return -EINVAL;
25738c2ecf20Sopenharmony_ci	}
25748c2ecf20Sopenharmony_ci
25758c2ecf20Sopenharmony_ci	ret = mnt_want_write_file(filp);
25768c2ecf20Sopenharmony_ci	if (ret)
25778c2ecf20Sopenharmony_ci		return ret;
25788c2ecf20Sopenharmony_ci
25798c2ecf20Sopenharmony_ci	ret = f2fs_sync_fs(sbi->sb, 1);
25808c2ecf20Sopenharmony_ci
25818c2ecf20Sopenharmony_ci	mnt_drop_write_file(filp);
25828c2ecf20Sopenharmony_ci	return ret;
25838c2ecf20Sopenharmony_ci}
25848c2ecf20Sopenharmony_ci
25858c2ecf20Sopenharmony_cistatic int f2fs_defragment_range(struct f2fs_sb_info *sbi,
25868c2ecf20Sopenharmony_ci					struct file *filp,
25878c2ecf20Sopenharmony_ci					struct f2fs_defragment *range)
25888c2ecf20Sopenharmony_ci{
25898c2ecf20Sopenharmony_ci	struct inode *inode = file_inode(filp);
25908c2ecf20Sopenharmony_ci	struct f2fs_map_blocks map = { .m_next_extent = NULL,
25918c2ecf20Sopenharmony_ci					.m_seg_type = NO_CHECK_TYPE ,
25928c2ecf20Sopenharmony_ci					.m_may_create = false };
25938c2ecf20Sopenharmony_ci	struct extent_info ei = {0, 0, 0};
25948c2ecf20Sopenharmony_ci	pgoff_t pg_start, pg_end, next_pgofs;
25958c2ecf20Sopenharmony_ci	unsigned int blk_per_seg = sbi->blocks_per_seg;
25968c2ecf20Sopenharmony_ci	unsigned int total = 0, sec_num;
25978c2ecf20Sopenharmony_ci	block_t blk_end = 0;
25988c2ecf20Sopenharmony_ci	bool fragmented = false;
25998c2ecf20Sopenharmony_ci	int err;
26008c2ecf20Sopenharmony_ci
26018c2ecf20Sopenharmony_ci	/* if in-place-update policy is enabled, don't waste time here */
26028c2ecf20Sopenharmony_ci	if (f2fs_should_update_inplace(inode, NULL))
26038c2ecf20Sopenharmony_ci		return -EINVAL;
26048c2ecf20Sopenharmony_ci
26058c2ecf20Sopenharmony_ci	pg_start = range->start >> PAGE_SHIFT;
26068c2ecf20Sopenharmony_ci	pg_end = (range->start + range->len) >> PAGE_SHIFT;
26078c2ecf20Sopenharmony_ci
26088c2ecf20Sopenharmony_ci	f2fs_balance_fs(sbi, true);
26098c2ecf20Sopenharmony_ci
26108c2ecf20Sopenharmony_ci	inode_lock(inode);
26118c2ecf20Sopenharmony_ci
26128c2ecf20Sopenharmony_ci	/* writeback all dirty pages in the range */
26138c2ecf20Sopenharmony_ci	err = filemap_write_and_wait_range(inode->i_mapping, range->start,
26148c2ecf20Sopenharmony_ci						range->start + range->len - 1);
26158c2ecf20Sopenharmony_ci	if (err)
26168c2ecf20Sopenharmony_ci		goto out;
26178c2ecf20Sopenharmony_ci
26188c2ecf20Sopenharmony_ci	/*
26198c2ecf20Sopenharmony_ci	 * lookup mapping info in extent cache, skip defragmenting if physical
26208c2ecf20Sopenharmony_ci	 * block addresses are continuous.
26218c2ecf20Sopenharmony_ci	 */
26228c2ecf20Sopenharmony_ci	if (f2fs_lookup_extent_cache(inode, pg_start, &ei)) {
26238c2ecf20Sopenharmony_ci		if (ei.fofs + ei.len >= pg_end)
26248c2ecf20Sopenharmony_ci			goto out;
26258c2ecf20Sopenharmony_ci	}
26268c2ecf20Sopenharmony_ci
26278c2ecf20Sopenharmony_ci	map.m_lblk = pg_start;
26288c2ecf20Sopenharmony_ci	map.m_next_pgofs = &next_pgofs;
26298c2ecf20Sopenharmony_ci
26308c2ecf20Sopenharmony_ci	/*
26318c2ecf20Sopenharmony_ci	 * lookup mapping info in dnode page cache, skip defragmenting if all
26328c2ecf20Sopenharmony_ci	 * physical block addresses are continuous even if there are hole(s)
26338c2ecf20Sopenharmony_ci	 * in logical blocks.
26348c2ecf20Sopenharmony_ci	 */
26358c2ecf20Sopenharmony_ci	while (map.m_lblk < pg_end) {
26368c2ecf20Sopenharmony_ci		map.m_len = pg_end - map.m_lblk;
26378c2ecf20Sopenharmony_ci		err = f2fs_map_blocks(inode, &map, 0, F2FS_GET_BLOCK_DEFAULT);
26388c2ecf20Sopenharmony_ci		if (err)
26398c2ecf20Sopenharmony_ci			goto out;
26408c2ecf20Sopenharmony_ci
26418c2ecf20Sopenharmony_ci		if (!(map.m_flags & F2FS_MAP_FLAGS)) {
26428c2ecf20Sopenharmony_ci			map.m_lblk = next_pgofs;
26438c2ecf20Sopenharmony_ci			continue;
26448c2ecf20Sopenharmony_ci		}
26458c2ecf20Sopenharmony_ci
26468c2ecf20Sopenharmony_ci		if (blk_end && blk_end != map.m_pblk)
26478c2ecf20Sopenharmony_ci			fragmented = true;
26488c2ecf20Sopenharmony_ci
26498c2ecf20Sopenharmony_ci		/* record total count of block that we're going to move */
26508c2ecf20Sopenharmony_ci		total += map.m_len;
26518c2ecf20Sopenharmony_ci
26528c2ecf20Sopenharmony_ci		blk_end = map.m_pblk + map.m_len;
26538c2ecf20Sopenharmony_ci
26548c2ecf20Sopenharmony_ci		map.m_lblk += map.m_len;
26558c2ecf20Sopenharmony_ci	}
26568c2ecf20Sopenharmony_ci
26578c2ecf20Sopenharmony_ci	if (!fragmented) {
26588c2ecf20Sopenharmony_ci		total = 0;
26598c2ecf20Sopenharmony_ci		goto out;
26608c2ecf20Sopenharmony_ci	}
26618c2ecf20Sopenharmony_ci
26628c2ecf20Sopenharmony_ci	sec_num = DIV_ROUND_UP(total, BLKS_PER_SEC(sbi));
26638c2ecf20Sopenharmony_ci
26648c2ecf20Sopenharmony_ci	/*
26658c2ecf20Sopenharmony_ci	 * make sure there are enough free section for LFS allocation, this can
26668c2ecf20Sopenharmony_ci	 * avoid defragment running in SSR mode when free section are allocated
26678c2ecf20Sopenharmony_ci	 * intensively
26688c2ecf20Sopenharmony_ci	 */
26698c2ecf20Sopenharmony_ci	if (has_not_enough_free_secs(sbi, 0, sec_num)) {
26708c2ecf20Sopenharmony_ci		err = -EAGAIN;
26718c2ecf20Sopenharmony_ci		goto out;
26728c2ecf20Sopenharmony_ci	}
26738c2ecf20Sopenharmony_ci
26748c2ecf20Sopenharmony_ci	map.m_lblk = pg_start;
26758c2ecf20Sopenharmony_ci	map.m_len = pg_end - pg_start;
26768c2ecf20Sopenharmony_ci	total = 0;
26778c2ecf20Sopenharmony_ci
26788c2ecf20Sopenharmony_ci	while (map.m_lblk < pg_end) {
26798c2ecf20Sopenharmony_ci		pgoff_t idx;
26808c2ecf20Sopenharmony_ci		int cnt = 0;
26818c2ecf20Sopenharmony_ci
26828c2ecf20Sopenharmony_cido_map:
26838c2ecf20Sopenharmony_ci		map.m_len = pg_end - map.m_lblk;
26848c2ecf20Sopenharmony_ci		err = f2fs_map_blocks(inode, &map, 0, F2FS_GET_BLOCK_DEFAULT);
26858c2ecf20Sopenharmony_ci		if (err)
26868c2ecf20Sopenharmony_ci			goto clear_out;
26878c2ecf20Sopenharmony_ci
26888c2ecf20Sopenharmony_ci		if (!(map.m_flags & F2FS_MAP_FLAGS)) {
26898c2ecf20Sopenharmony_ci			map.m_lblk = next_pgofs;
26908c2ecf20Sopenharmony_ci			goto check;
26918c2ecf20Sopenharmony_ci		}
26928c2ecf20Sopenharmony_ci
26938c2ecf20Sopenharmony_ci		set_inode_flag(inode, FI_DO_DEFRAG);
26948c2ecf20Sopenharmony_ci
26958c2ecf20Sopenharmony_ci		idx = map.m_lblk;
26968c2ecf20Sopenharmony_ci		while (idx < map.m_lblk + map.m_len && cnt < blk_per_seg) {
26978c2ecf20Sopenharmony_ci			struct page *page;
26988c2ecf20Sopenharmony_ci
26998c2ecf20Sopenharmony_ci			page = f2fs_get_lock_data_page(inode, idx, true);
27008c2ecf20Sopenharmony_ci			if (IS_ERR(page)) {
27018c2ecf20Sopenharmony_ci				err = PTR_ERR(page);
27028c2ecf20Sopenharmony_ci				goto clear_out;
27038c2ecf20Sopenharmony_ci			}
27048c2ecf20Sopenharmony_ci
27058c2ecf20Sopenharmony_ci			set_page_dirty(page);
27068c2ecf20Sopenharmony_ci			f2fs_put_page(page, 1);
27078c2ecf20Sopenharmony_ci
27088c2ecf20Sopenharmony_ci			idx++;
27098c2ecf20Sopenharmony_ci			cnt++;
27108c2ecf20Sopenharmony_ci			total++;
27118c2ecf20Sopenharmony_ci		}
27128c2ecf20Sopenharmony_ci
27138c2ecf20Sopenharmony_ci		map.m_lblk = idx;
27148c2ecf20Sopenharmony_cicheck:
27158c2ecf20Sopenharmony_ci		if (map.m_lblk < pg_end && cnt < blk_per_seg)
27168c2ecf20Sopenharmony_ci			goto do_map;
27178c2ecf20Sopenharmony_ci
27188c2ecf20Sopenharmony_ci		clear_inode_flag(inode, FI_DO_DEFRAG);
27198c2ecf20Sopenharmony_ci
27208c2ecf20Sopenharmony_ci		err = filemap_fdatawrite(inode->i_mapping);
27218c2ecf20Sopenharmony_ci		if (err)
27228c2ecf20Sopenharmony_ci			goto out;
27238c2ecf20Sopenharmony_ci	}
27248c2ecf20Sopenharmony_ciclear_out:
27258c2ecf20Sopenharmony_ci	clear_inode_flag(inode, FI_DO_DEFRAG);
27268c2ecf20Sopenharmony_ciout:
27278c2ecf20Sopenharmony_ci	inode_unlock(inode);
27288c2ecf20Sopenharmony_ci	if (!err)
27298c2ecf20Sopenharmony_ci		range->len = (u64)total << PAGE_SHIFT;
27308c2ecf20Sopenharmony_ci	return err;
27318c2ecf20Sopenharmony_ci}
27328c2ecf20Sopenharmony_ci
27338c2ecf20Sopenharmony_cistatic int f2fs_ioc_defragment(struct file *filp, unsigned long arg)
27348c2ecf20Sopenharmony_ci{
27358c2ecf20Sopenharmony_ci	struct inode *inode = file_inode(filp);
27368c2ecf20Sopenharmony_ci	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
27378c2ecf20Sopenharmony_ci	struct f2fs_defragment range;
27388c2ecf20Sopenharmony_ci	int err;
27398c2ecf20Sopenharmony_ci
27408c2ecf20Sopenharmony_ci	if (!capable(CAP_SYS_ADMIN))
27418c2ecf20Sopenharmony_ci		return -EPERM;
27428c2ecf20Sopenharmony_ci
27438c2ecf20Sopenharmony_ci	if (!S_ISREG(inode->i_mode) || f2fs_is_atomic_file(inode))
27448c2ecf20Sopenharmony_ci		return -EINVAL;
27458c2ecf20Sopenharmony_ci
27468c2ecf20Sopenharmony_ci	if (f2fs_readonly(sbi->sb))
27478c2ecf20Sopenharmony_ci		return -EROFS;
27488c2ecf20Sopenharmony_ci
27498c2ecf20Sopenharmony_ci	if (copy_from_user(&range, (struct f2fs_defragment __user *)arg,
27508c2ecf20Sopenharmony_ci							sizeof(range)))
27518c2ecf20Sopenharmony_ci		return -EFAULT;
27528c2ecf20Sopenharmony_ci
27538c2ecf20Sopenharmony_ci	/* verify alignment of offset & size */
27548c2ecf20Sopenharmony_ci	if (range.start & (F2FS_BLKSIZE - 1) || range.len & (F2FS_BLKSIZE - 1))
27558c2ecf20Sopenharmony_ci		return -EINVAL;
27568c2ecf20Sopenharmony_ci
27578c2ecf20Sopenharmony_ci	if (unlikely((range.start + range.len) >> PAGE_SHIFT >
27588c2ecf20Sopenharmony_ci					sbi->max_file_blocks))
27598c2ecf20Sopenharmony_ci		return -EINVAL;
27608c2ecf20Sopenharmony_ci
27618c2ecf20Sopenharmony_ci	err = mnt_want_write_file(filp);
27628c2ecf20Sopenharmony_ci	if (err)
27638c2ecf20Sopenharmony_ci		return err;
27648c2ecf20Sopenharmony_ci
27658c2ecf20Sopenharmony_ci	err = f2fs_defragment_range(sbi, filp, &range);
27668c2ecf20Sopenharmony_ci	mnt_drop_write_file(filp);
27678c2ecf20Sopenharmony_ci
27688c2ecf20Sopenharmony_ci	f2fs_update_time(sbi, REQ_TIME);
27698c2ecf20Sopenharmony_ci	if (err < 0)
27708c2ecf20Sopenharmony_ci		return err;
27718c2ecf20Sopenharmony_ci
27728c2ecf20Sopenharmony_ci	if (copy_to_user((struct f2fs_defragment __user *)arg, &range,
27738c2ecf20Sopenharmony_ci							sizeof(range)))
27748c2ecf20Sopenharmony_ci		return -EFAULT;
27758c2ecf20Sopenharmony_ci
27768c2ecf20Sopenharmony_ci	return 0;
27778c2ecf20Sopenharmony_ci}
27788c2ecf20Sopenharmony_ci
27798c2ecf20Sopenharmony_cistatic int f2fs_move_file_range(struct file *file_in, loff_t pos_in,
27808c2ecf20Sopenharmony_ci			struct file *file_out, loff_t pos_out, size_t len)
27818c2ecf20Sopenharmony_ci{
27828c2ecf20Sopenharmony_ci	struct inode *src = file_inode(file_in);
27838c2ecf20Sopenharmony_ci	struct inode *dst = file_inode(file_out);
27848c2ecf20Sopenharmony_ci	struct f2fs_sb_info *sbi = F2FS_I_SB(src);
27858c2ecf20Sopenharmony_ci	size_t olen = len, dst_max_i_size = 0;
27868c2ecf20Sopenharmony_ci	size_t dst_osize;
27878c2ecf20Sopenharmony_ci	int ret;
27888c2ecf20Sopenharmony_ci
27898c2ecf20Sopenharmony_ci	if (file_in->f_path.mnt != file_out->f_path.mnt ||
27908c2ecf20Sopenharmony_ci				src->i_sb != dst->i_sb)
27918c2ecf20Sopenharmony_ci		return -EXDEV;
27928c2ecf20Sopenharmony_ci
27938c2ecf20Sopenharmony_ci	if (unlikely(f2fs_readonly(src->i_sb)))
27948c2ecf20Sopenharmony_ci		return -EROFS;
27958c2ecf20Sopenharmony_ci
27968c2ecf20Sopenharmony_ci	if (!S_ISREG(src->i_mode) || !S_ISREG(dst->i_mode))
27978c2ecf20Sopenharmony_ci		return -EINVAL;
27988c2ecf20Sopenharmony_ci
27998c2ecf20Sopenharmony_ci	if (IS_ENCRYPTED(src) || IS_ENCRYPTED(dst))
28008c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
28018c2ecf20Sopenharmony_ci
28028c2ecf20Sopenharmony_ci	if (pos_out < 0 || pos_in < 0)
28038c2ecf20Sopenharmony_ci		return -EINVAL;
28048c2ecf20Sopenharmony_ci
28058c2ecf20Sopenharmony_ci	if (src == dst) {
28068c2ecf20Sopenharmony_ci		if (pos_in == pos_out)
28078c2ecf20Sopenharmony_ci			return 0;
28088c2ecf20Sopenharmony_ci		if (pos_out > pos_in && pos_out < pos_in + len)
28098c2ecf20Sopenharmony_ci			return -EINVAL;
28108c2ecf20Sopenharmony_ci	}
28118c2ecf20Sopenharmony_ci
28128c2ecf20Sopenharmony_ci	inode_lock(src);
28138c2ecf20Sopenharmony_ci	if (src != dst) {
28148c2ecf20Sopenharmony_ci		ret = -EBUSY;
28158c2ecf20Sopenharmony_ci		if (!inode_trylock(dst))
28168c2ecf20Sopenharmony_ci			goto out;
28178c2ecf20Sopenharmony_ci	}
28188c2ecf20Sopenharmony_ci
28198c2ecf20Sopenharmony_ci	if (f2fs_compressed_file(src) || f2fs_compressed_file(dst)) {
28208c2ecf20Sopenharmony_ci		ret = -EOPNOTSUPP;
28218c2ecf20Sopenharmony_ci		goto out_unlock;
28228c2ecf20Sopenharmony_ci	}
28238c2ecf20Sopenharmony_ci
28248c2ecf20Sopenharmony_ci	ret = -EINVAL;
28258c2ecf20Sopenharmony_ci	if (pos_in + len > src->i_size || pos_in + len < pos_in)
28268c2ecf20Sopenharmony_ci		goto out_unlock;
28278c2ecf20Sopenharmony_ci	if (len == 0)
28288c2ecf20Sopenharmony_ci		olen = len = src->i_size - pos_in;
28298c2ecf20Sopenharmony_ci	if (pos_in + len == src->i_size)
28308c2ecf20Sopenharmony_ci		len = ALIGN(src->i_size, F2FS_BLKSIZE) - pos_in;
28318c2ecf20Sopenharmony_ci	if (len == 0) {
28328c2ecf20Sopenharmony_ci		ret = 0;
28338c2ecf20Sopenharmony_ci		goto out_unlock;
28348c2ecf20Sopenharmony_ci	}
28358c2ecf20Sopenharmony_ci
28368c2ecf20Sopenharmony_ci	dst_osize = dst->i_size;
28378c2ecf20Sopenharmony_ci	if (pos_out + olen > dst->i_size)
28388c2ecf20Sopenharmony_ci		dst_max_i_size = pos_out + olen;
28398c2ecf20Sopenharmony_ci
28408c2ecf20Sopenharmony_ci	/* verify the end result is block aligned */
28418c2ecf20Sopenharmony_ci	if (!IS_ALIGNED(pos_in, F2FS_BLKSIZE) ||
28428c2ecf20Sopenharmony_ci			!IS_ALIGNED(pos_in + len, F2FS_BLKSIZE) ||
28438c2ecf20Sopenharmony_ci			!IS_ALIGNED(pos_out, F2FS_BLKSIZE))
28448c2ecf20Sopenharmony_ci		goto out_unlock;
28458c2ecf20Sopenharmony_ci
28468c2ecf20Sopenharmony_ci	ret = f2fs_convert_inline_inode(src);
28478c2ecf20Sopenharmony_ci	if (ret)
28488c2ecf20Sopenharmony_ci		goto out_unlock;
28498c2ecf20Sopenharmony_ci
28508c2ecf20Sopenharmony_ci	ret = f2fs_convert_inline_inode(dst);
28518c2ecf20Sopenharmony_ci	if (ret)
28528c2ecf20Sopenharmony_ci		goto out_unlock;
28538c2ecf20Sopenharmony_ci
28548c2ecf20Sopenharmony_ci	/* write out all dirty pages from offset */
28558c2ecf20Sopenharmony_ci	ret = filemap_write_and_wait_range(src->i_mapping,
28568c2ecf20Sopenharmony_ci					pos_in, pos_in + len);
28578c2ecf20Sopenharmony_ci	if (ret)
28588c2ecf20Sopenharmony_ci		goto out_unlock;
28598c2ecf20Sopenharmony_ci
28608c2ecf20Sopenharmony_ci	ret = filemap_write_and_wait_range(dst->i_mapping,
28618c2ecf20Sopenharmony_ci					pos_out, pos_out + len);
28628c2ecf20Sopenharmony_ci	if (ret)
28638c2ecf20Sopenharmony_ci		goto out_unlock;
28648c2ecf20Sopenharmony_ci
28658c2ecf20Sopenharmony_ci	f2fs_balance_fs(sbi, true);
28668c2ecf20Sopenharmony_ci
28678c2ecf20Sopenharmony_ci	down_write(&F2FS_I(src)->i_gc_rwsem[WRITE]);
28688c2ecf20Sopenharmony_ci	if (src != dst) {
28698c2ecf20Sopenharmony_ci		ret = -EBUSY;
28708c2ecf20Sopenharmony_ci		if (!down_write_trylock(&F2FS_I(dst)->i_gc_rwsem[WRITE]))
28718c2ecf20Sopenharmony_ci			goto out_src;
28728c2ecf20Sopenharmony_ci	}
28738c2ecf20Sopenharmony_ci
28748c2ecf20Sopenharmony_ci	f2fs_lock_op(sbi);
28758c2ecf20Sopenharmony_ci	ret = __exchange_data_block(src, dst, pos_in >> F2FS_BLKSIZE_BITS,
28768c2ecf20Sopenharmony_ci				pos_out >> F2FS_BLKSIZE_BITS,
28778c2ecf20Sopenharmony_ci				len >> F2FS_BLKSIZE_BITS, false);
28788c2ecf20Sopenharmony_ci
28798c2ecf20Sopenharmony_ci	if (!ret) {
28808c2ecf20Sopenharmony_ci		if (dst_max_i_size)
28818c2ecf20Sopenharmony_ci			f2fs_i_size_write(dst, dst_max_i_size);
28828c2ecf20Sopenharmony_ci		else if (dst_osize != dst->i_size)
28838c2ecf20Sopenharmony_ci			f2fs_i_size_write(dst, dst_osize);
28848c2ecf20Sopenharmony_ci	}
28858c2ecf20Sopenharmony_ci	f2fs_unlock_op(sbi);
28868c2ecf20Sopenharmony_ci
28878c2ecf20Sopenharmony_ci	if (src != dst)
28888c2ecf20Sopenharmony_ci		up_write(&F2FS_I(dst)->i_gc_rwsem[WRITE]);
28898c2ecf20Sopenharmony_ciout_src:
28908c2ecf20Sopenharmony_ci	up_write(&F2FS_I(src)->i_gc_rwsem[WRITE]);
28918c2ecf20Sopenharmony_ciout_unlock:
28928c2ecf20Sopenharmony_ci	if (src != dst)
28938c2ecf20Sopenharmony_ci		inode_unlock(dst);
28948c2ecf20Sopenharmony_ciout:
28958c2ecf20Sopenharmony_ci	inode_unlock(src);
28968c2ecf20Sopenharmony_ci	return ret;
28978c2ecf20Sopenharmony_ci}
28988c2ecf20Sopenharmony_ci
28998c2ecf20Sopenharmony_cistatic int __f2fs_ioc_move_range(struct file *filp,
29008c2ecf20Sopenharmony_ci				struct f2fs_move_range *range)
29018c2ecf20Sopenharmony_ci{
29028c2ecf20Sopenharmony_ci	struct fd dst;
29038c2ecf20Sopenharmony_ci	int err;
29048c2ecf20Sopenharmony_ci
29058c2ecf20Sopenharmony_ci	if (!(filp->f_mode & FMODE_READ) ||
29068c2ecf20Sopenharmony_ci			!(filp->f_mode & FMODE_WRITE))
29078c2ecf20Sopenharmony_ci		return -EBADF;
29088c2ecf20Sopenharmony_ci
29098c2ecf20Sopenharmony_ci	dst = fdget(range->dst_fd);
29108c2ecf20Sopenharmony_ci	if (!dst.file)
29118c2ecf20Sopenharmony_ci		return -EBADF;
29128c2ecf20Sopenharmony_ci
29138c2ecf20Sopenharmony_ci	if (!(dst.file->f_mode & FMODE_WRITE)) {
29148c2ecf20Sopenharmony_ci		err = -EBADF;
29158c2ecf20Sopenharmony_ci		goto err_out;
29168c2ecf20Sopenharmony_ci	}
29178c2ecf20Sopenharmony_ci
29188c2ecf20Sopenharmony_ci	err = mnt_want_write_file(filp);
29198c2ecf20Sopenharmony_ci	if (err)
29208c2ecf20Sopenharmony_ci		goto err_out;
29218c2ecf20Sopenharmony_ci
29228c2ecf20Sopenharmony_ci	err = f2fs_move_file_range(filp, range->pos_in, dst.file,
29238c2ecf20Sopenharmony_ci					range->pos_out, range->len);
29248c2ecf20Sopenharmony_ci
29258c2ecf20Sopenharmony_ci	mnt_drop_write_file(filp);
29268c2ecf20Sopenharmony_cierr_out:
29278c2ecf20Sopenharmony_ci	fdput(dst);
29288c2ecf20Sopenharmony_ci	return err;
29298c2ecf20Sopenharmony_ci}
29308c2ecf20Sopenharmony_ci
29318c2ecf20Sopenharmony_cistatic int f2fs_ioc_move_range(struct file *filp, unsigned long arg)
29328c2ecf20Sopenharmony_ci{
29338c2ecf20Sopenharmony_ci	struct f2fs_move_range range;
29348c2ecf20Sopenharmony_ci
29358c2ecf20Sopenharmony_ci	if (copy_from_user(&range, (struct f2fs_move_range __user *)arg,
29368c2ecf20Sopenharmony_ci							sizeof(range)))
29378c2ecf20Sopenharmony_ci		return -EFAULT;
29388c2ecf20Sopenharmony_ci	return __f2fs_ioc_move_range(filp, &range);
29398c2ecf20Sopenharmony_ci}
29408c2ecf20Sopenharmony_ci
29418c2ecf20Sopenharmony_cistatic int f2fs_ioc_flush_device(struct file *filp, unsigned long arg)
29428c2ecf20Sopenharmony_ci{
29438c2ecf20Sopenharmony_ci	struct inode *inode = file_inode(filp);
29448c2ecf20Sopenharmony_ci	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
29458c2ecf20Sopenharmony_ci	struct sit_info *sm = SIT_I(sbi);
29468c2ecf20Sopenharmony_ci	unsigned int start_segno = 0, end_segno = 0;
29478c2ecf20Sopenharmony_ci	unsigned int dev_start_segno = 0, dev_end_segno = 0;
29488c2ecf20Sopenharmony_ci	struct f2fs_flush_device range;
29498c2ecf20Sopenharmony_ci	int ret;
29508c2ecf20Sopenharmony_ci
29518c2ecf20Sopenharmony_ci	if (!capable(CAP_SYS_ADMIN))
29528c2ecf20Sopenharmony_ci		return -EPERM;
29538c2ecf20Sopenharmony_ci
29548c2ecf20Sopenharmony_ci	if (f2fs_readonly(sbi->sb))
29558c2ecf20Sopenharmony_ci		return -EROFS;
29568c2ecf20Sopenharmony_ci
29578c2ecf20Sopenharmony_ci	if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED)))
29588c2ecf20Sopenharmony_ci		return -EINVAL;
29598c2ecf20Sopenharmony_ci
29608c2ecf20Sopenharmony_ci	if (copy_from_user(&range, (struct f2fs_flush_device __user *)arg,
29618c2ecf20Sopenharmony_ci							sizeof(range)))
29628c2ecf20Sopenharmony_ci		return -EFAULT;
29638c2ecf20Sopenharmony_ci
29648c2ecf20Sopenharmony_ci	if (!f2fs_is_multi_device(sbi) || sbi->s_ndevs - 1 <= range.dev_num ||
29658c2ecf20Sopenharmony_ci			__is_large_section(sbi)) {
29668c2ecf20Sopenharmony_ci		f2fs_warn(sbi, "Can't flush %u in %d for segs_per_sec %u != 1",
29678c2ecf20Sopenharmony_ci			  range.dev_num, sbi->s_ndevs, sbi->segs_per_sec);
29688c2ecf20Sopenharmony_ci		return -EINVAL;
29698c2ecf20Sopenharmony_ci	}
29708c2ecf20Sopenharmony_ci
29718c2ecf20Sopenharmony_ci	ret = mnt_want_write_file(filp);
29728c2ecf20Sopenharmony_ci	if (ret)
29738c2ecf20Sopenharmony_ci		return ret;
29748c2ecf20Sopenharmony_ci
29758c2ecf20Sopenharmony_ci	if (range.dev_num != 0)
29768c2ecf20Sopenharmony_ci		dev_start_segno = GET_SEGNO(sbi, FDEV(range.dev_num).start_blk);
29778c2ecf20Sopenharmony_ci	dev_end_segno = GET_SEGNO(sbi, FDEV(range.dev_num).end_blk);
29788c2ecf20Sopenharmony_ci
29798c2ecf20Sopenharmony_ci	start_segno = sm->last_victim[FLUSH_DEVICE];
29808c2ecf20Sopenharmony_ci	if (start_segno < dev_start_segno || start_segno >= dev_end_segno)
29818c2ecf20Sopenharmony_ci		start_segno = dev_start_segno;
29828c2ecf20Sopenharmony_ci	end_segno = min(start_segno + range.segments, dev_end_segno);
29838c2ecf20Sopenharmony_ci
29848c2ecf20Sopenharmony_ci	while (start_segno < end_segno) {
29858c2ecf20Sopenharmony_ci		if (!down_write_trylock(&sbi->gc_lock)) {
29868c2ecf20Sopenharmony_ci			ret = -EBUSY;
29878c2ecf20Sopenharmony_ci			goto out;
29888c2ecf20Sopenharmony_ci		}
29898c2ecf20Sopenharmony_ci		sm->last_victim[GC_CB] = end_segno + 1;
29908c2ecf20Sopenharmony_ci		sm->last_victim[GC_GREEDY] = end_segno + 1;
29918c2ecf20Sopenharmony_ci		sm->last_victim[ALLOC_NEXT] = end_segno + 1;
29928c2ecf20Sopenharmony_ci		ret = f2fs_gc(sbi, true, true, true, start_segno);
29938c2ecf20Sopenharmony_ci		if (ret == -EAGAIN)
29948c2ecf20Sopenharmony_ci			ret = 0;
29958c2ecf20Sopenharmony_ci		else if (ret < 0)
29968c2ecf20Sopenharmony_ci			break;
29978c2ecf20Sopenharmony_ci		start_segno++;
29988c2ecf20Sopenharmony_ci	}
29998c2ecf20Sopenharmony_ciout:
30008c2ecf20Sopenharmony_ci	mnt_drop_write_file(filp);
30018c2ecf20Sopenharmony_ci	return ret;
30028c2ecf20Sopenharmony_ci}
30038c2ecf20Sopenharmony_ci
30048c2ecf20Sopenharmony_cistatic int f2fs_ioc_get_features(struct file *filp, unsigned long arg)
30058c2ecf20Sopenharmony_ci{
30068c2ecf20Sopenharmony_ci	struct inode *inode = file_inode(filp);
30078c2ecf20Sopenharmony_ci	u32 sb_feature = le32_to_cpu(F2FS_I_SB(inode)->raw_super->feature);
30088c2ecf20Sopenharmony_ci
30098c2ecf20Sopenharmony_ci	/* Must validate to set it with SQLite behavior in Android. */
30108c2ecf20Sopenharmony_ci	sb_feature |= F2FS_FEATURE_ATOMIC_WRITE;
30118c2ecf20Sopenharmony_ci
30128c2ecf20Sopenharmony_ci	return put_user(sb_feature, (u32 __user *)arg);
30138c2ecf20Sopenharmony_ci}
30148c2ecf20Sopenharmony_ci
30158c2ecf20Sopenharmony_ci#ifdef CONFIG_QUOTA
30168c2ecf20Sopenharmony_ciint f2fs_transfer_project_quota(struct inode *inode, kprojid_t kprojid)
30178c2ecf20Sopenharmony_ci{
30188c2ecf20Sopenharmony_ci	struct dquot *transfer_to[MAXQUOTAS] = {};
30198c2ecf20Sopenharmony_ci	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
30208c2ecf20Sopenharmony_ci	struct super_block *sb = sbi->sb;
30218c2ecf20Sopenharmony_ci	int err;
30228c2ecf20Sopenharmony_ci
30238c2ecf20Sopenharmony_ci	transfer_to[PRJQUOTA] = dqget(sb, make_kqid_projid(kprojid));
30248c2ecf20Sopenharmony_ci	if (IS_ERR(transfer_to[PRJQUOTA]))
30258c2ecf20Sopenharmony_ci		return PTR_ERR(transfer_to[PRJQUOTA]);
30268c2ecf20Sopenharmony_ci
30278c2ecf20Sopenharmony_ci	err = __dquot_transfer(inode, transfer_to);
30288c2ecf20Sopenharmony_ci	if (err)
30298c2ecf20Sopenharmony_ci		set_sbi_flag(sbi, SBI_QUOTA_NEED_REPAIR);
30308c2ecf20Sopenharmony_ci	dqput(transfer_to[PRJQUOTA]);
30318c2ecf20Sopenharmony_ci	return err;
30328c2ecf20Sopenharmony_ci}
30338c2ecf20Sopenharmony_ci
30348c2ecf20Sopenharmony_cistatic int f2fs_ioc_setproject(struct file *filp, __u32 projid)
30358c2ecf20Sopenharmony_ci{
30368c2ecf20Sopenharmony_ci	struct inode *inode = file_inode(filp);
30378c2ecf20Sopenharmony_ci	struct f2fs_inode_info *fi = F2FS_I(inode);
30388c2ecf20Sopenharmony_ci	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
30398c2ecf20Sopenharmony_ci	struct page *ipage;
30408c2ecf20Sopenharmony_ci	kprojid_t kprojid;
30418c2ecf20Sopenharmony_ci	int err;
30428c2ecf20Sopenharmony_ci
30438c2ecf20Sopenharmony_ci	if (!f2fs_sb_has_project_quota(sbi)) {
30448c2ecf20Sopenharmony_ci		if (projid != F2FS_DEF_PROJID)
30458c2ecf20Sopenharmony_ci			return -EOPNOTSUPP;
30468c2ecf20Sopenharmony_ci		else
30478c2ecf20Sopenharmony_ci			return 0;
30488c2ecf20Sopenharmony_ci	}
30498c2ecf20Sopenharmony_ci
30508c2ecf20Sopenharmony_ci	if (!f2fs_has_extra_attr(inode))
30518c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
30528c2ecf20Sopenharmony_ci
30538c2ecf20Sopenharmony_ci	kprojid = make_kprojid(&init_user_ns, (projid_t)projid);
30548c2ecf20Sopenharmony_ci
30558c2ecf20Sopenharmony_ci	if (projid_eq(kprojid, F2FS_I(inode)->i_projid))
30568c2ecf20Sopenharmony_ci		return 0;
30578c2ecf20Sopenharmony_ci
30588c2ecf20Sopenharmony_ci	err = -EPERM;
30598c2ecf20Sopenharmony_ci	/* Is it quota file? Do not allow user to mess with it */
30608c2ecf20Sopenharmony_ci	if (IS_NOQUOTA(inode))
30618c2ecf20Sopenharmony_ci		return err;
30628c2ecf20Sopenharmony_ci
30638c2ecf20Sopenharmony_ci	ipage = f2fs_get_node_page(sbi, inode->i_ino);
30648c2ecf20Sopenharmony_ci	if (IS_ERR(ipage))
30658c2ecf20Sopenharmony_ci		return PTR_ERR(ipage);
30668c2ecf20Sopenharmony_ci
30678c2ecf20Sopenharmony_ci	if (!F2FS_FITS_IN_INODE(F2FS_INODE(ipage), fi->i_extra_isize,
30688c2ecf20Sopenharmony_ci								i_projid)) {
30698c2ecf20Sopenharmony_ci		err = -EOVERFLOW;
30708c2ecf20Sopenharmony_ci		f2fs_put_page(ipage, 1);
30718c2ecf20Sopenharmony_ci		return err;
30728c2ecf20Sopenharmony_ci	}
30738c2ecf20Sopenharmony_ci	f2fs_put_page(ipage, 1);
30748c2ecf20Sopenharmony_ci
30758c2ecf20Sopenharmony_ci	err = dquot_initialize(inode);
30768c2ecf20Sopenharmony_ci	if (err)
30778c2ecf20Sopenharmony_ci		return err;
30788c2ecf20Sopenharmony_ci
30798c2ecf20Sopenharmony_ci	f2fs_lock_op(sbi);
30808c2ecf20Sopenharmony_ci	err = f2fs_transfer_project_quota(inode, kprojid);
30818c2ecf20Sopenharmony_ci	if (err)
30828c2ecf20Sopenharmony_ci		goto out_unlock;
30838c2ecf20Sopenharmony_ci
30848c2ecf20Sopenharmony_ci	F2FS_I(inode)->i_projid = kprojid;
30858c2ecf20Sopenharmony_ci	inode->i_ctime = current_time(inode);
30868c2ecf20Sopenharmony_ci	f2fs_mark_inode_dirty_sync(inode, true);
30878c2ecf20Sopenharmony_ciout_unlock:
30888c2ecf20Sopenharmony_ci	f2fs_unlock_op(sbi);
30898c2ecf20Sopenharmony_ci	return err;
30908c2ecf20Sopenharmony_ci}
30918c2ecf20Sopenharmony_ci#else
30928c2ecf20Sopenharmony_ciint f2fs_transfer_project_quota(struct inode *inode, kprojid_t kprojid)
30938c2ecf20Sopenharmony_ci{
30948c2ecf20Sopenharmony_ci	return 0;
30958c2ecf20Sopenharmony_ci}
30968c2ecf20Sopenharmony_ci
30978c2ecf20Sopenharmony_cistatic int f2fs_ioc_setproject(struct file *filp, __u32 projid)
30988c2ecf20Sopenharmony_ci{
30998c2ecf20Sopenharmony_ci	if (projid != F2FS_DEF_PROJID)
31008c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
31018c2ecf20Sopenharmony_ci	return 0;
31028c2ecf20Sopenharmony_ci}
31038c2ecf20Sopenharmony_ci#endif
31048c2ecf20Sopenharmony_ci
31058c2ecf20Sopenharmony_ci/* FS_IOC_FSGETXATTR and FS_IOC_FSSETXATTR support */
31068c2ecf20Sopenharmony_ci
31078c2ecf20Sopenharmony_ci/*
31088c2ecf20Sopenharmony_ci * To make a new on-disk f2fs i_flag gettable via FS_IOC_FSGETXATTR and settable
31098c2ecf20Sopenharmony_ci * via FS_IOC_FSSETXATTR, add an entry for it to f2fs_xflags_map[], and add its
31108c2ecf20Sopenharmony_ci * FS_XFLAG_* equivalent to F2FS_SUPPORTED_XFLAGS.
31118c2ecf20Sopenharmony_ci */
31128c2ecf20Sopenharmony_ci
31138c2ecf20Sopenharmony_cistatic const struct {
31148c2ecf20Sopenharmony_ci	u32 iflag;
31158c2ecf20Sopenharmony_ci	u32 xflag;
31168c2ecf20Sopenharmony_ci} f2fs_xflags_map[] = {
31178c2ecf20Sopenharmony_ci	{ F2FS_SYNC_FL,		FS_XFLAG_SYNC },
31188c2ecf20Sopenharmony_ci	{ F2FS_IMMUTABLE_FL,	FS_XFLAG_IMMUTABLE },
31198c2ecf20Sopenharmony_ci	{ F2FS_APPEND_FL,	FS_XFLAG_APPEND },
31208c2ecf20Sopenharmony_ci	{ F2FS_NODUMP_FL,	FS_XFLAG_NODUMP },
31218c2ecf20Sopenharmony_ci	{ F2FS_NOATIME_FL,	FS_XFLAG_NOATIME },
31228c2ecf20Sopenharmony_ci	{ F2FS_PROJINHERIT_FL,	FS_XFLAG_PROJINHERIT },
31238c2ecf20Sopenharmony_ci};
31248c2ecf20Sopenharmony_ci
31258c2ecf20Sopenharmony_ci#define F2FS_SUPPORTED_XFLAGS (		\
31268c2ecf20Sopenharmony_ci		FS_XFLAG_SYNC |		\
31278c2ecf20Sopenharmony_ci		FS_XFLAG_IMMUTABLE |	\
31288c2ecf20Sopenharmony_ci		FS_XFLAG_APPEND |	\
31298c2ecf20Sopenharmony_ci		FS_XFLAG_NODUMP |	\
31308c2ecf20Sopenharmony_ci		FS_XFLAG_NOATIME |	\
31318c2ecf20Sopenharmony_ci		FS_XFLAG_PROJINHERIT)
31328c2ecf20Sopenharmony_ci
31338c2ecf20Sopenharmony_ci/* Convert f2fs on-disk i_flags to FS_IOC_FS{GET,SET}XATTR flags */
31348c2ecf20Sopenharmony_cistatic inline u32 f2fs_iflags_to_xflags(u32 iflags)
31358c2ecf20Sopenharmony_ci{
31368c2ecf20Sopenharmony_ci	u32 xflags = 0;
31378c2ecf20Sopenharmony_ci	int i;
31388c2ecf20Sopenharmony_ci
31398c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(f2fs_xflags_map); i++)
31408c2ecf20Sopenharmony_ci		if (iflags & f2fs_xflags_map[i].iflag)
31418c2ecf20Sopenharmony_ci			xflags |= f2fs_xflags_map[i].xflag;
31428c2ecf20Sopenharmony_ci
31438c2ecf20Sopenharmony_ci	return xflags;
31448c2ecf20Sopenharmony_ci}
31458c2ecf20Sopenharmony_ci
31468c2ecf20Sopenharmony_ci/* Convert FS_IOC_FS{GET,SET}XATTR flags to f2fs on-disk i_flags */
31478c2ecf20Sopenharmony_cistatic inline u32 f2fs_xflags_to_iflags(u32 xflags)
31488c2ecf20Sopenharmony_ci{
31498c2ecf20Sopenharmony_ci	u32 iflags = 0;
31508c2ecf20Sopenharmony_ci	int i;
31518c2ecf20Sopenharmony_ci
31528c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(f2fs_xflags_map); i++)
31538c2ecf20Sopenharmony_ci		if (xflags & f2fs_xflags_map[i].xflag)
31548c2ecf20Sopenharmony_ci			iflags |= f2fs_xflags_map[i].iflag;
31558c2ecf20Sopenharmony_ci
31568c2ecf20Sopenharmony_ci	return iflags;
31578c2ecf20Sopenharmony_ci}
31588c2ecf20Sopenharmony_ci
31598c2ecf20Sopenharmony_cistatic void f2fs_fill_fsxattr(struct inode *inode, struct fsxattr *fa)
31608c2ecf20Sopenharmony_ci{
31618c2ecf20Sopenharmony_ci	struct f2fs_inode_info *fi = F2FS_I(inode);
31628c2ecf20Sopenharmony_ci
31638c2ecf20Sopenharmony_ci	simple_fill_fsxattr(fa, f2fs_iflags_to_xflags(fi->i_flags));
31648c2ecf20Sopenharmony_ci
31658c2ecf20Sopenharmony_ci	if (f2fs_sb_has_project_quota(F2FS_I_SB(inode)))
31668c2ecf20Sopenharmony_ci		fa->fsx_projid = from_kprojid(&init_user_ns, fi->i_projid);
31678c2ecf20Sopenharmony_ci}
31688c2ecf20Sopenharmony_ci
31698c2ecf20Sopenharmony_cistatic int f2fs_ioc_fsgetxattr(struct file *filp, unsigned long arg)
31708c2ecf20Sopenharmony_ci{
31718c2ecf20Sopenharmony_ci	struct inode *inode = file_inode(filp);
31728c2ecf20Sopenharmony_ci	struct fsxattr fa;
31738c2ecf20Sopenharmony_ci
31748c2ecf20Sopenharmony_ci	f2fs_fill_fsxattr(inode, &fa);
31758c2ecf20Sopenharmony_ci
31768c2ecf20Sopenharmony_ci	if (copy_to_user((struct fsxattr __user *)arg, &fa, sizeof(fa)))
31778c2ecf20Sopenharmony_ci		return -EFAULT;
31788c2ecf20Sopenharmony_ci	return 0;
31798c2ecf20Sopenharmony_ci}
31808c2ecf20Sopenharmony_ci
31818c2ecf20Sopenharmony_cistatic int f2fs_ioc_fssetxattr(struct file *filp, unsigned long arg)
31828c2ecf20Sopenharmony_ci{
31838c2ecf20Sopenharmony_ci	struct inode *inode = file_inode(filp);
31848c2ecf20Sopenharmony_ci	struct fsxattr fa, old_fa;
31858c2ecf20Sopenharmony_ci	u32 iflags;
31868c2ecf20Sopenharmony_ci	int err;
31878c2ecf20Sopenharmony_ci
31888c2ecf20Sopenharmony_ci	if (copy_from_user(&fa, (struct fsxattr __user *)arg, sizeof(fa)))
31898c2ecf20Sopenharmony_ci		return -EFAULT;
31908c2ecf20Sopenharmony_ci
31918c2ecf20Sopenharmony_ci	/* Make sure caller has proper permission */
31928c2ecf20Sopenharmony_ci	if (!inode_owner_or_capable(inode))
31938c2ecf20Sopenharmony_ci		return -EACCES;
31948c2ecf20Sopenharmony_ci
31958c2ecf20Sopenharmony_ci	if (fa.fsx_xflags & ~F2FS_SUPPORTED_XFLAGS)
31968c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
31978c2ecf20Sopenharmony_ci
31988c2ecf20Sopenharmony_ci	iflags = f2fs_xflags_to_iflags(fa.fsx_xflags);
31998c2ecf20Sopenharmony_ci	if (f2fs_mask_flags(inode->i_mode, iflags) != iflags)
32008c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
32018c2ecf20Sopenharmony_ci
32028c2ecf20Sopenharmony_ci	err = mnt_want_write_file(filp);
32038c2ecf20Sopenharmony_ci	if (err)
32048c2ecf20Sopenharmony_ci		return err;
32058c2ecf20Sopenharmony_ci
32068c2ecf20Sopenharmony_ci	inode_lock(inode);
32078c2ecf20Sopenharmony_ci
32088c2ecf20Sopenharmony_ci	f2fs_fill_fsxattr(inode, &old_fa);
32098c2ecf20Sopenharmony_ci	err = vfs_ioc_fssetxattr_check(inode, &old_fa, &fa);
32108c2ecf20Sopenharmony_ci	if (err)
32118c2ecf20Sopenharmony_ci		goto out;
32128c2ecf20Sopenharmony_ci
32138c2ecf20Sopenharmony_ci	err = f2fs_setflags_common(inode, iflags,
32148c2ecf20Sopenharmony_ci			f2fs_xflags_to_iflags(F2FS_SUPPORTED_XFLAGS));
32158c2ecf20Sopenharmony_ci	if (err)
32168c2ecf20Sopenharmony_ci		goto out;
32178c2ecf20Sopenharmony_ci
32188c2ecf20Sopenharmony_ci	err = f2fs_ioc_setproject(filp, fa.fsx_projid);
32198c2ecf20Sopenharmony_ciout:
32208c2ecf20Sopenharmony_ci	inode_unlock(inode);
32218c2ecf20Sopenharmony_ci	mnt_drop_write_file(filp);
32228c2ecf20Sopenharmony_ci	return err;
32238c2ecf20Sopenharmony_ci}
32248c2ecf20Sopenharmony_ci
32258c2ecf20Sopenharmony_ciint f2fs_pin_file_control(struct inode *inode, bool inc)
32268c2ecf20Sopenharmony_ci{
32278c2ecf20Sopenharmony_ci	struct f2fs_inode_info *fi = F2FS_I(inode);
32288c2ecf20Sopenharmony_ci	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
32298c2ecf20Sopenharmony_ci
32308c2ecf20Sopenharmony_ci	/* Use i_gc_failures for normal file as a risk signal. */
32318c2ecf20Sopenharmony_ci	if (inc)
32328c2ecf20Sopenharmony_ci		f2fs_i_gc_failures_write(inode,
32338c2ecf20Sopenharmony_ci				fi->i_gc_failures[GC_FAILURE_PIN] + 1);
32348c2ecf20Sopenharmony_ci
32358c2ecf20Sopenharmony_ci	if (fi->i_gc_failures[GC_FAILURE_PIN] > sbi->gc_pin_file_threshold) {
32368c2ecf20Sopenharmony_ci		f2fs_warn(sbi, "%s: Enable GC = ino %lx after %x GC trials",
32378c2ecf20Sopenharmony_ci			  __func__, inode->i_ino,
32388c2ecf20Sopenharmony_ci			  fi->i_gc_failures[GC_FAILURE_PIN]);
32398c2ecf20Sopenharmony_ci		clear_inode_flag(inode, FI_PIN_FILE);
32408c2ecf20Sopenharmony_ci		return -EAGAIN;
32418c2ecf20Sopenharmony_ci	}
32428c2ecf20Sopenharmony_ci	return 0;
32438c2ecf20Sopenharmony_ci}
32448c2ecf20Sopenharmony_ci
32458c2ecf20Sopenharmony_cistatic int f2fs_ioc_set_pin_file(struct file *filp, unsigned long arg)
32468c2ecf20Sopenharmony_ci{
32478c2ecf20Sopenharmony_ci	struct inode *inode = file_inode(filp);
32488c2ecf20Sopenharmony_ci	__u32 pin;
32498c2ecf20Sopenharmony_ci	int ret = 0;
32508c2ecf20Sopenharmony_ci
32518c2ecf20Sopenharmony_ci	if (get_user(pin, (__u32 __user *)arg))
32528c2ecf20Sopenharmony_ci		return -EFAULT;
32538c2ecf20Sopenharmony_ci
32548c2ecf20Sopenharmony_ci	if (!S_ISREG(inode->i_mode))
32558c2ecf20Sopenharmony_ci		return -EINVAL;
32568c2ecf20Sopenharmony_ci
32578c2ecf20Sopenharmony_ci	if (f2fs_readonly(F2FS_I_SB(inode)->sb))
32588c2ecf20Sopenharmony_ci		return -EROFS;
32598c2ecf20Sopenharmony_ci
32608c2ecf20Sopenharmony_ci	ret = mnt_want_write_file(filp);
32618c2ecf20Sopenharmony_ci	if (ret)
32628c2ecf20Sopenharmony_ci		return ret;
32638c2ecf20Sopenharmony_ci
32648c2ecf20Sopenharmony_ci	inode_lock(inode);
32658c2ecf20Sopenharmony_ci
32668c2ecf20Sopenharmony_ci	if (f2fs_should_update_outplace(inode, NULL)) {
32678c2ecf20Sopenharmony_ci		ret = -EINVAL;
32688c2ecf20Sopenharmony_ci		goto out;
32698c2ecf20Sopenharmony_ci	}
32708c2ecf20Sopenharmony_ci
32718c2ecf20Sopenharmony_ci	if (!pin) {
32728c2ecf20Sopenharmony_ci		clear_inode_flag(inode, FI_PIN_FILE);
32738c2ecf20Sopenharmony_ci		f2fs_i_gc_failures_write(inode, 0);
32748c2ecf20Sopenharmony_ci		goto done;
32758c2ecf20Sopenharmony_ci	}
32768c2ecf20Sopenharmony_ci
32778c2ecf20Sopenharmony_ci	if (f2fs_pin_file_control(inode, false)) {
32788c2ecf20Sopenharmony_ci		ret = -EAGAIN;
32798c2ecf20Sopenharmony_ci		goto out;
32808c2ecf20Sopenharmony_ci	}
32818c2ecf20Sopenharmony_ci
32828c2ecf20Sopenharmony_ci	ret = f2fs_convert_inline_inode(inode);
32838c2ecf20Sopenharmony_ci	if (ret)
32848c2ecf20Sopenharmony_ci		goto out;
32858c2ecf20Sopenharmony_ci
32868c2ecf20Sopenharmony_ci	if (!f2fs_disable_compressed_file(inode)) {
32878c2ecf20Sopenharmony_ci		ret = -EOPNOTSUPP;
32888c2ecf20Sopenharmony_ci		goto out;
32898c2ecf20Sopenharmony_ci	}
32908c2ecf20Sopenharmony_ci
32918c2ecf20Sopenharmony_ci	set_inode_flag(inode, FI_PIN_FILE);
32928c2ecf20Sopenharmony_ci	ret = F2FS_I(inode)->i_gc_failures[GC_FAILURE_PIN];
32938c2ecf20Sopenharmony_cidone:
32948c2ecf20Sopenharmony_ci	f2fs_update_time(F2FS_I_SB(inode), REQ_TIME);
32958c2ecf20Sopenharmony_ciout:
32968c2ecf20Sopenharmony_ci	inode_unlock(inode);
32978c2ecf20Sopenharmony_ci	mnt_drop_write_file(filp);
32988c2ecf20Sopenharmony_ci	return ret;
32998c2ecf20Sopenharmony_ci}
33008c2ecf20Sopenharmony_ci
33018c2ecf20Sopenharmony_cistatic int f2fs_ioc_get_pin_file(struct file *filp, unsigned long arg)
33028c2ecf20Sopenharmony_ci{
33038c2ecf20Sopenharmony_ci	struct inode *inode = file_inode(filp);
33048c2ecf20Sopenharmony_ci	__u32 pin = 0;
33058c2ecf20Sopenharmony_ci
33068c2ecf20Sopenharmony_ci	if (is_inode_flag_set(inode, FI_PIN_FILE))
33078c2ecf20Sopenharmony_ci		pin = F2FS_I(inode)->i_gc_failures[GC_FAILURE_PIN];
33088c2ecf20Sopenharmony_ci	return put_user(pin, (u32 __user *)arg);
33098c2ecf20Sopenharmony_ci}
33108c2ecf20Sopenharmony_ci
33118c2ecf20Sopenharmony_ciint f2fs_precache_extents(struct inode *inode)
33128c2ecf20Sopenharmony_ci{
33138c2ecf20Sopenharmony_ci	struct f2fs_inode_info *fi = F2FS_I(inode);
33148c2ecf20Sopenharmony_ci	struct f2fs_map_blocks map;
33158c2ecf20Sopenharmony_ci	pgoff_t m_next_extent;
33168c2ecf20Sopenharmony_ci	loff_t end;
33178c2ecf20Sopenharmony_ci	int err;
33188c2ecf20Sopenharmony_ci
33198c2ecf20Sopenharmony_ci	if (is_inode_flag_set(inode, FI_NO_EXTENT))
33208c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
33218c2ecf20Sopenharmony_ci
33228c2ecf20Sopenharmony_ci	map.m_lblk = 0;
33238c2ecf20Sopenharmony_ci	map.m_pblk = 0;
33248c2ecf20Sopenharmony_ci	map.m_next_pgofs = NULL;
33258c2ecf20Sopenharmony_ci	map.m_next_extent = &m_next_extent;
33268c2ecf20Sopenharmony_ci	map.m_seg_type = NO_CHECK_TYPE;
33278c2ecf20Sopenharmony_ci	map.m_may_create = false;
33288c2ecf20Sopenharmony_ci	end = F2FS_I_SB(inode)->max_file_blocks;
33298c2ecf20Sopenharmony_ci
33308c2ecf20Sopenharmony_ci	while (map.m_lblk < end) {
33318c2ecf20Sopenharmony_ci		map.m_len = end - map.m_lblk;
33328c2ecf20Sopenharmony_ci
33338c2ecf20Sopenharmony_ci		down_write(&fi->i_gc_rwsem[WRITE]);
33348c2ecf20Sopenharmony_ci		err = f2fs_map_blocks(inode, &map, 0, F2FS_GET_BLOCK_PRECACHE);
33358c2ecf20Sopenharmony_ci		up_write(&fi->i_gc_rwsem[WRITE]);
33368c2ecf20Sopenharmony_ci		if (err)
33378c2ecf20Sopenharmony_ci			return err;
33388c2ecf20Sopenharmony_ci
33398c2ecf20Sopenharmony_ci		map.m_lblk = m_next_extent;
33408c2ecf20Sopenharmony_ci	}
33418c2ecf20Sopenharmony_ci
33428c2ecf20Sopenharmony_ci	return err;
33438c2ecf20Sopenharmony_ci}
33448c2ecf20Sopenharmony_ci
33458c2ecf20Sopenharmony_cistatic int f2fs_ioc_precache_extents(struct file *filp, unsigned long arg)
33468c2ecf20Sopenharmony_ci{
33478c2ecf20Sopenharmony_ci	return f2fs_precache_extents(file_inode(filp));
33488c2ecf20Sopenharmony_ci}
33498c2ecf20Sopenharmony_ci
33508c2ecf20Sopenharmony_cistatic int f2fs_ioc_resize_fs(struct file *filp, unsigned long arg)
33518c2ecf20Sopenharmony_ci{
33528c2ecf20Sopenharmony_ci	struct f2fs_sb_info *sbi = F2FS_I_SB(file_inode(filp));
33538c2ecf20Sopenharmony_ci	__u64 block_count;
33548c2ecf20Sopenharmony_ci
33558c2ecf20Sopenharmony_ci	if (!capable(CAP_SYS_ADMIN))
33568c2ecf20Sopenharmony_ci		return -EPERM;
33578c2ecf20Sopenharmony_ci
33588c2ecf20Sopenharmony_ci	if (f2fs_readonly(sbi->sb))
33598c2ecf20Sopenharmony_ci		return -EROFS;
33608c2ecf20Sopenharmony_ci
33618c2ecf20Sopenharmony_ci	if (copy_from_user(&block_count, (void __user *)arg,
33628c2ecf20Sopenharmony_ci			   sizeof(block_count)))
33638c2ecf20Sopenharmony_ci		return -EFAULT;
33648c2ecf20Sopenharmony_ci
33658c2ecf20Sopenharmony_ci	return f2fs_resize_fs(filp, block_count);
33668c2ecf20Sopenharmony_ci}
33678c2ecf20Sopenharmony_ci
33688c2ecf20Sopenharmony_cistatic inline int f2fs_has_feature_verity(struct file *filp)
33698c2ecf20Sopenharmony_ci{
33708c2ecf20Sopenharmony_ci	struct inode *inode = file_inode(filp);
33718c2ecf20Sopenharmony_ci
33728c2ecf20Sopenharmony_ci	f2fs_update_time(F2FS_I_SB(inode), REQ_TIME);
33738c2ecf20Sopenharmony_ci
33748c2ecf20Sopenharmony_ci	if (!f2fs_sb_has_verity(F2FS_I_SB(inode))) {
33758c2ecf20Sopenharmony_ci		f2fs_warn(F2FS_I_SB(inode),
33768c2ecf20Sopenharmony_ci			  "Can't enable fs-verity on inode %lu: the verity feature is not enabled on this filesystem.\n",
33778c2ecf20Sopenharmony_ci			  inode->i_ino);
33788c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
33798c2ecf20Sopenharmony_ci	}
33808c2ecf20Sopenharmony_ci	return 0;
33818c2ecf20Sopenharmony_ci}
33828c2ecf20Sopenharmony_ci
33838c2ecf20Sopenharmony_cistatic int f2fs_ioc_enable_verity(struct file *filp, unsigned long arg)
33848c2ecf20Sopenharmony_ci{
33858c2ecf20Sopenharmony_ci	int err = f2fs_has_feature_verity(filp);
33868c2ecf20Sopenharmony_ci
33878c2ecf20Sopenharmony_ci	if (err)
33888c2ecf20Sopenharmony_ci		return err;
33898c2ecf20Sopenharmony_ci
33908c2ecf20Sopenharmony_ci	return fsverity_ioctl_enable(filp, (const void __user *)arg);
33918c2ecf20Sopenharmony_ci}
33928c2ecf20Sopenharmony_ci
33938c2ecf20Sopenharmony_cistatic int f2fs_ioc_enable_code_sign(struct file *filp, unsigned long arg)
33948c2ecf20Sopenharmony_ci{
33958c2ecf20Sopenharmony_ci	int err = f2fs_has_feature_verity(filp);
33968c2ecf20Sopenharmony_ci
33978c2ecf20Sopenharmony_ci	if (err)
33988c2ecf20Sopenharmony_ci		return err;
33998c2ecf20Sopenharmony_ci
34008c2ecf20Sopenharmony_ci	return fsverity_ioctl_enable_code_sign(filp, (const void __user *)arg);
34018c2ecf20Sopenharmony_ci}
34028c2ecf20Sopenharmony_ci
34038c2ecf20Sopenharmony_cistatic int f2fs_ioc_measure_verity(struct file *filp, unsigned long arg)
34048c2ecf20Sopenharmony_ci{
34058c2ecf20Sopenharmony_ci	if (!f2fs_sb_has_verity(F2FS_I_SB(file_inode(filp))))
34068c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
34078c2ecf20Sopenharmony_ci
34088c2ecf20Sopenharmony_ci	return fsverity_ioctl_measure(filp, (void __user *)arg);
34098c2ecf20Sopenharmony_ci}
34108c2ecf20Sopenharmony_ci
34118c2ecf20Sopenharmony_cistatic int f2fs_ioc_getfslabel(struct file *filp, unsigned long arg)
34128c2ecf20Sopenharmony_ci{
34138c2ecf20Sopenharmony_ci	struct inode *inode = file_inode(filp);
34148c2ecf20Sopenharmony_ci	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
34158c2ecf20Sopenharmony_ci	char *vbuf;
34168c2ecf20Sopenharmony_ci	int count;
34178c2ecf20Sopenharmony_ci	int err = 0;
34188c2ecf20Sopenharmony_ci
34198c2ecf20Sopenharmony_ci	vbuf = f2fs_kzalloc(sbi, MAX_VOLUME_NAME, GFP_KERNEL);
34208c2ecf20Sopenharmony_ci	if (!vbuf)
34218c2ecf20Sopenharmony_ci		return -ENOMEM;
34228c2ecf20Sopenharmony_ci
34238c2ecf20Sopenharmony_ci	down_read(&sbi->sb_lock);
34248c2ecf20Sopenharmony_ci	count = utf16s_to_utf8s(sbi->raw_super->volume_name,
34258c2ecf20Sopenharmony_ci			ARRAY_SIZE(sbi->raw_super->volume_name),
34268c2ecf20Sopenharmony_ci			UTF16_LITTLE_ENDIAN, vbuf, MAX_VOLUME_NAME);
34278c2ecf20Sopenharmony_ci	up_read(&sbi->sb_lock);
34288c2ecf20Sopenharmony_ci
34298c2ecf20Sopenharmony_ci	if (copy_to_user((char __user *)arg, vbuf,
34308c2ecf20Sopenharmony_ci				min(FSLABEL_MAX, count)))
34318c2ecf20Sopenharmony_ci		err = -EFAULT;
34328c2ecf20Sopenharmony_ci
34338c2ecf20Sopenharmony_ci	kfree(vbuf);
34348c2ecf20Sopenharmony_ci	return err;
34358c2ecf20Sopenharmony_ci}
34368c2ecf20Sopenharmony_ci
34378c2ecf20Sopenharmony_cistatic int f2fs_ioc_setfslabel(struct file *filp, unsigned long arg)
34388c2ecf20Sopenharmony_ci{
34398c2ecf20Sopenharmony_ci	struct inode *inode = file_inode(filp);
34408c2ecf20Sopenharmony_ci	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
34418c2ecf20Sopenharmony_ci	char *vbuf;
34428c2ecf20Sopenharmony_ci	int err = 0;
34438c2ecf20Sopenharmony_ci
34448c2ecf20Sopenharmony_ci	if (!capable(CAP_SYS_ADMIN))
34458c2ecf20Sopenharmony_ci		return -EPERM;
34468c2ecf20Sopenharmony_ci
34478c2ecf20Sopenharmony_ci	vbuf = strndup_user((const char __user *)arg, FSLABEL_MAX);
34488c2ecf20Sopenharmony_ci	if (IS_ERR(vbuf))
34498c2ecf20Sopenharmony_ci		return PTR_ERR(vbuf);
34508c2ecf20Sopenharmony_ci
34518c2ecf20Sopenharmony_ci	err = mnt_want_write_file(filp);
34528c2ecf20Sopenharmony_ci	if (err)
34538c2ecf20Sopenharmony_ci		goto out;
34548c2ecf20Sopenharmony_ci
34558c2ecf20Sopenharmony_ci	down_write(&sbi->sb_lock);
34568c2ecf20Sopenharmony_ci
34578c2ecf20Sopenharmony_ci	memset(sbi->raw_super->volume_name, 0,
34588c2ecf20Sopenharmony_ci			sizeof(sbi->raw_super->volume_name));
34598c2ecf20Sopenharmony_ci	utf8s_to_utf16s(vbuf, strlen(vbuf), UTF16_LITTLE_ENDIAN,
34608c2ecf20Sopenharmony_ci			sbi->raw_super->volume_name,
34618c2ecf20Sopenharmony_ci			ARRAY_SIZE(sbi->raw_super->volume_name));
34628c2ecf20Sopenharmony_ci
34638c2ecf20Sopenharmony_ci	err = f2fs_commit_super(sbi, false);
34648c2ecf20Sopenharmony_ci
34658c2ecf20Sopenharmony_ci	up_write(&sbi->sb_lock);
34668c2ecf20Sopenharmony_ci
34678c2ecf20Sopenharmony_ci	mnt_drop_write_file(filp);
34688c2ecf20Sopenharmony_ciout:
34698c2ecf20Sopenharmony_ci	kfree(vbuf);
34708c2ecf20Sopenharmony_ci	return err;
34718c2ecf20Sopenharmony_ci}
34728c2ecf20Sopenharmony_ci
34738c2ecf20Sopenharmony_cistatic int f2fs_get_compress_blocks(struct file *filp, unsigned long arg)
34748c2ecf20Sopenharmony_ci{
34758c2ecf20Sopenharmony_ci	struct inode *inode = file_inode(filp);
34768c2ecf20Sopenharmony_ci	__u64 blocks;
34778c2ecf20Sopenharmony_ci
34788c2ecf20Sopenharmony_ci	if (!f2fs_sb_has_compression(F2FS_I_SB(inode)))
34798c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
34808c2ecf20Sopenharmony_ci
34818c2ecf20Sopenharmony_ci	if (!f2fs_compressed_file(inode))
34828c2ecf20Sopenharmony_ci		return -EINVAL;
34838c2ecf20Sopenharmony_ci
34848c2ecf20Sopenharmony_ci	blocks = atomic_read(&F2FS_I(inode)->i_compr_blocks);
34858c2ecf20Sopenharmony_ci	return put_user(blocks, (u64 __user *)arg);
34868c2ecf20Sopenharmony_ci}
34878c2ecf20Sopenharmony_ci
34888c2ecf20Sopenharmony_cistatic int release_compress_blocks(struct dnode_of_data *dn, pgoff_t count)
34898c2ecf20Sopenharmony_ci{
34908c2ecf20Sopenharmony_ci	struct f2fs_sb_info *sbi = F2FS_I_SB(dn->inode);
34918c2ecf20Sopenharmony_ci	unsigned int released_blocks = 0;
34928c2ecf20Sopenharmony_ci	int cluster_size = F2FS_I(dn->inode)->i_cluster_size;
34938c2ecf20Sopenharmony_ci	block_t blkaddr;
34948c2ecf20Sopenharmony_ci	int i;
34958c2ecf20Sopenharmony_ci
34968c2ecf20Sopenharmony_ci	for (i = 0; i < count; i++) {
34978c2ecf20Sopenharmony_ci		blkaddr = data_blkaddr(dn->inode, dn->node_page,
34988c2ecf20Sopenharmony_ci						dn->ofs_in_node + i);
34998c2ecf20Sopenharmony_ci
35008c2ecf20Sopenharmony_ci		if (!__is_valid_data_blkaddr(blkaddr))
35018c2ecf20Sopenharmony_ci			continue;
35028c2ecf20Sopenharmony_ci		if (unlikely(!f2fs_is_valid_blkaddr(sbi, blkaddr,
35038c2ecf20Sopenharmony_ci					DATA_GENERIC_ENHANCE)))
35048c2ecf20Sopenharmony_ci			return -EFSCORRUPTED;
35058c2ecf20Sopenharmony_ci	}
35068c2ecf20Sopenharmony_ci
35078c2ecf20Sopenharmony_ci	while (count) {
35088c2ecf20Sopenharmony_ci		int compr_blocks = 0;
35098c2ecf20Sopenharmony_ci
35108c2ecf20Sopenharmony_ci		for (i = 0; i < cluster_size; i++, dn->ofs_in_node++) {
35118c2ecf20Sopenharmony_ci			blkaddr = f2fs_data_blkaddr(dn);
35128c2ecf20Sopenharmony_ci
35138c2ecf20Sopenharmony_ci			if (i == 0) {
35148c2ecf20Sopenharmony_ci				if (blkaddr == COMPRESS_ADDR)
35158c2ecf20Sopenharmony_ci					continue;
35168c2ecf20Sopenharmony_ci				dn->ofs_in_node += cluster_size;
35178c2ecf20Sopenharmony_ci				goto next;
35188c2ecf20Sopenharmony_ci			}
35198c2ecf20Sopenharmony_ci
35208c2ecf20Sopenharmony_ci			if (__is_valid_data_blkaddr(blkaddr))
35218c2ecf20Sopenharmony_ci				compr_blocks++;
35228c2ecf20Sopenharmony_ci
35238c2ecf20Sopenharmony_ci			if (blkaddr != NEW_ADDR)
35248c2ecf20Sopenharmony_ci				continue;
35258c2ecf20Sopenharmony_ci
35268c2ecf20Sopenharmony_ci			dn->data_blkaddr = NULL_ADDR;
35278c2ecf20Sopenharmony_ci			f2fs_set_data_blkaddr(dn);
35288c2ecf20Sopenharmony_ci		}
35298c2ecf20Sopenharmony_ci
35308c2ecf20Sopenharmony_ci		f2fs_i_compr_blocks_update(dn->inode, compr_blocks, false);
35318c2ecf20Sopenharmony_ci		dec_valid_block_count(sbi, dn->inode,
35328c2ecf20Sopenharmony_ci					cluster_size - compr_blocks);
35338c2ecf20Sopenharmony_ci
35348c2ecf20Sopenharmony_ci		released_blocks += cluster_size - compr_blocks;
35358c2ecf20Sopenharmony_cinext:
35368c2ecf20Sopenharmony_ci		count -= cluster_size;
35378c2ecf20Sopenharmony_ci	}
35388c2ecf20Sopenharmony_ci
35398c2ecf20Sopenharmony_ci	return released_blocks;
35408c2ecf20Sopenharmony_ci}
35418c2ecf20Sopenharmony_ci
35428c2ecf20Sopenharmony_cistatic int f2fs_release_compress_blocks(struct file *filp, unsigned long arg)
35438c2ecf20Sopenharmony_ci{
35448c2ecf20Sopenharmony_ci	struct inode *inode = file_inode(filp);
35458c2ecf20Sopenharmony_ci	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
35468c2ecf20Sopenharmony_ci	pgoff_t page_idx = 0, last_idx;
35478c2ecf20Sopenharmony_ci	unsigned int released_blocks = 0;
35488c2ecf20Sopenharmony_ci	int ret;
35498c2ecf20Sopenharmony_ci	int writecount;
35508c2ecf20Sopenharmony_ci
35518c2ecf20Sopenharmony_ci	if (!f2fs_sb_has_compression(F2FS_I_SB(inode)))
35528c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
35538c2ecf20Sopenharmony_ci
35548c2ecf20Sopenharmony_ci	if (!f2fs_compressed_file(inode))
35558c2ecf20Sopenharmony_ci		return -EINVAL;
35568c2ecf20Sopenharmony_ci
35578c2ecf20Sopenharmony_ci	if (f2fs_readonly(sbi->sb))
35588c2ecf20Sopenharmony_ci		return -EROFS;
35598c2ecf20Sopenharmony_ci
35608c2ecf20Sopenharmony_ci	ret = mnt_want_write_file(filp);
35618c2ecf20Sopenharmony_ci	if (ret)
35628c2ecf20Sopenharmony_ci		return ret;
35638c2ecf20Sopenharmony_ci
35648c2ecf20Sopenharmony_ci	f2fs_balance_fs(F2FS_I_SB(inode), true);
35658c2ecf20Sopenharmony_ci
35668c2ecf20Sopenharmony_ci	inode_lock(inode);
35678c2ecf20Sopenharmony_ci
35688c2ecf20Sopenharmony_ci	writecount = atomic_read(&inode->i_writecount);
35698c2ecf20Sopenharmony_ci	if ((filp->f_mode & FMODE_WRITE && writecount != 1) ||
35708c2ecf20Sopenharmony_ci			(!(filp->f_mode & FMODE_WRITE) && writecount)) {
35718c2ecf20Sopenharmony_ci		ret = -EBUSY;
35728c2ecf20Sopenharmony_ci		goto out;
35738c2ecf20Sopenharmony_ci	}
35748c2ecf20Sopenharmony_ci
35758c2ecf20Sopenharmony_ci	if (IS_IMMUTABLE(inode)) {
35768c2ecf20Sopenharmony_ci		ret = -EINVAL;
35778c2ecf20Sopenharmony_ci		goto out;
35788c2ecf20Sopenharmony_ci	}
35798c2ecf20Sopenharmony_ci
35808c2ecf20Sopenharmony_ci	ret = filemap_write_and_wait_range(inode->i_mapping, 0, LLONG_MAX);
35818c2ecf20Sopenharmony_ci	if (ret)
35828c2ecf20Sopenharmony_ci		goto out;
35838c2ecf20Sopenharmony_ci
35848c2ecf20Sopenharmony_ci	F2FS_I(inode)->i_flags |= F2FS_IMMUTABLE_FL;
35858c2ecf20Sopenharmony_ci	f2fs_set_inode_flags(inode);
35868c2ecf20Sopenharmony_ci	inode->i_ctime = current_time(inode);
35878c2ecf20Sopenharmony_ci	f2fs_mark_inode_dirty_sync(inode, true);
35888c2ecf20Sopenharmony_ci
35898c2ecf20Sopenharmony_ci	if (!atomic_read(&F2FS_I(inode)->i_compr_blocks))
35908c2ecf20Sopenharmony_ci		goto out;
35918c2ecf20Sopenharmony_ci
35928c2ecf20Sopenharmony_ci	down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
35938c2ecf20Sopenharmony_ci	down_write(&F2FS_I(inode)->i_mmap_sem);
35948c2ecf20Sopenharmony_ci
35958c2ecf20Sopenharmony_ci	last_idx = DIV_ROUND_UP(i_size_read(inode), PAGE_SIZE);
35968c2ecf20Sopenharmony_ci
35978c2ecf20Sopenharmony_ci	while (page_idx < last_idx) {
35988c2ecf20Sopenharmony_ci		struct dnode_of_data dn;
35998c2ecf20Sopenharmony_ci		pgoff_t end_offset, count;
36008c2ecf20Sopenharmony_ci
36018c2ecf20Sopenharmony_ci		f2fs_lock_op(sbi);
36028c2ecf20Sopenharmony_ci
36038c2ecf20Sopenharmony_ci		set_new_dnode(&dn, inode, NULL, NULL, 0);
36048c2ecf20Sopenharmony_ci		ret = f2fs_get_dnode_of_data(&dn, page_idx, LOOKUP_NODE);
36058c2ecf20Sopenharmony_ci		if (ret) {
36068c2ecf20Sopenharmony_ci			f2fs_unlock_op(sbi);
36078c2ecf20Sopenharmony_ci			if (ret == -ENOENT) {
36088c2ecf20Sopenharmony_ci				page_idx = f2fs_get_next_page_offset(&dn,
36098c2ecf20Sopenharmony_ci								page_idx);
36108c2ecf20Sopenharmony_ci				ret = 0;
36118c2ecf20Sopenharmony_ci				continue;
36128c2ecf20Sopenharmony_ci			}
36138c2ecf20Sopenharmony_ci			break;
36148c2ecf20Sopenharmony_ci		}
36158c2ecf20Sopenharmony_ci
36168c2ecf20Sopenharmony_ci		end_offset = ADDRS_PER_PAGE(dn.node_page, inode);
36178c2ecf20Sopenharmony_ci		count = min(end_offset - dn.ofs_in_node, last_idx - page_idx);
36188c2ecf20Sopenharmony_ci		count = round_up(count, F2FS_I(inode)->i_cluster_size);
36198c2ecf20Sopenharmony_ci
36208c2ecf20Sopenharmony_ci		ret = release_compress_blocks(&dn, count);
36218c2ecf20Sopenharmony_ci
36228c2ecf20Sopenharmony_ci		f2fs_put_dnode(&dn);
36238c2ecf20Sopenharmony_ci
36248c2ecf20Sopenharmony_ci		f2fs_unlock_op(sbi);
36258c2ecf20Sopenharmony_ci
36268c2ecf20Sopenharmony_ci		if (ret < 0)
36278c2ecf20Sopenharmony_ci			break;
36288c2ecf20Sopenharmony_ci
36298c2ecf20Sopenharmony_ci		page_idx += count;
36308c2ecf20Sopenharmony_ci		released_blocks += ret;
36318c2ecf20Sopenharmony_ci	}
36328c2ecf20Sopenharmony_ci
36338c2ecf20Sopenharmony_ci	up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
36348c2ecf20Sopenharmony_ci	up_write(&F2FS_I(inode)->i_mmap_sem);
36358c2ecf20Sopenharmony_ciout:
36368c2ecf20Sopenharmony_ci	inode_unlock(inode);
36378c2ecf20Sopenharmony_ci
36388c2ecf20Sopenharmony_ci	mnt_drop_write_file(filp);
36398c2ecf20Sopenharmony_ci
36408c2ecf20Sopenharmony_ci	if (ret >= 0) {
36418c2ecf20Sopenharmony_ci		ret = put_user(released_blocks, (u64 __user *)arg);
36428c2ecf20Sopenharmony_ci	} else if (released_blocks &&
36438c2ecf20Sopenharmony_ci			atomic_read(&F2FS_I(inode)->i_compr_blocks)) {
36448c2ecf20Sopenharmony_ci		set_sbi_flag(sbi, SBI_NEED_FSCK);
36458c2ecf20Sopenharmony_ci		f2fs_warn(sbi, "%s: partial blocks were released i_ino=%lx "
36468c2ecf20Sopenharmony_ci			"iblocks=%llu, released=%u, compr_blocks=%u, "
36478c2ecf20Sopenharmony_ci			"run fsck to fix.",
36488c2ecf20Sopenharmony_ci			__func__, inode->i_ino, inode->i_blocks,
36498c2ecf20Sopenharmony_ci			released_blocks,
36508c2ecf20Sopenharmony_ci			atomic_read(&F2FS_I(inode)->i_compr_blocks));
36518c2ecf20Sopenharmony_ci	}
36528c2ecf20Sopenharmony_ci
36538c2ecf20Sopenharmony_ci	return ret;
36548c2ecf20Sopenharmony_ci}
36558c2ecf20Sopenharmony_ci
36568c2ecf20Sopenharmony_cistatic int reserve_compress_blocks(struct dnode_of_data *dn, pgoff_t count,
36578c2ecf20Sopenharmony_ci		unsigned int *reserved_blocks)
36588c2ecf20Sopenharmony_ci{
36598c2ecf20Sopenharmony_ci	struct f2fs_sb_info *sbi = F2FS_I_SB(dn->inode);
36608c2ecf20Sopenharmony_ci	int cluster_size = F2FS_I(dn->inode)->i_cluster_size;
36618c2ecf20Sopenharmony_ci	block_t blkaddr;
36628c2ecf20Sopenharmony_ci	int i;
36638c2ecf20Sopenharmony_ci
36648c2ecf20Sopenharmony_ci	for (i = 0; i < count; i++) {
36658c2ecf20Sopenharmony_ci		blkaddr = data_blkaddr(dn->inode, dn->node_page,
36668c2ecf20Sopenharmony_ci						dn->ofs_in_node + i);
36678c2ecf20Sopenharmony_ci
36688c2ecf20Sopenharmony_ci		if (!__is_valid_data_blkaddr(blkaddr))
36698c2ecf20Sopenharmony_ci			continue;
36708c2ecf20Sopenharmony_ci		if (unlikely(!f2fs_is_valid_blkaddr(sbi, blkaddr,
36718c2ecf20Sopenharmony_ci					DATA_GENERIC_ENHANCE)))
36728c2ecf20Sopenharmony_ci			return -EFSCORRUPTED;
36738c2ecf20Sopenharmony_ci	}
36748c2ecf20Sopenharmony_ci
36758c2ecf20Sopenharmony_ci	while (count) {
36768c2ecf20Sopenharmony_ci		int compr_blocks = 0;
36778c2ecf20Sopenharmony_ci		blkcnt_t reserved;
36788c2ecf20Sopenharmony_ci		int ret;
36798c2ecf20Sopenharmony_ci
36808c2ecf20Sopenharmony_ci		for (i = 0; i < cluster_size; i++, dn->ofs_in_node++) {
36818c2ecf20Sopenharmony_ci			blkaddr = f2fs_data_blkaddr(dn);
36828c2ecf20Sopenharmony_ci
36838c2ecf20Sopenharmony_ci			if (i == 0) {
36848c2ecf20Sopenharmony_ci				if (blkaddr == COMPRESS_ADDR)
36858c2ecf20Sopenharmony_ci					continue;
36868c2ecf20Sopenharmony_ci				dn->ofs_in_node += cluster_size;
36878c2ecf20Sopenharmony_ci				goto next;
36888c2ecf20Sopenharmony_ci			}
36898c2ecf20Sopenharmony_ci
36908c2ecf20Sopenharmony_ci			if (__is_valid_data_blkaddr(blkaddr)) {
36918c2ecf20Sopenharmony_ci				compr_blocks++;
36928c2ecf20Sopenharmony_ci				continue;
36938c2ecf20Sopenharmony_ci			}
36948c2ecf20Sopenharmony_ci
36958c2ecf20Sopenharmony_ci			dn->data_blkaddr = NEW_ADDR;
36968c2ecf20Sopenharmony_ci			f2fs_set_data_blkaddr(dn);
36978c2ecf20Sopenharmony_ci		}
36988c2ecf20Sopenharmony_ci
36998c2ecf20Sopenharmony_ci		reserved = cluster_size - compr_blocks;
37008c2ecf20Sopenharmony_ci		ret = inc_valid_block_count(sbi, dn->inode, &reserved);
37018c2ecf20Sopenharmony_ci		if (ret)
37028c2ecf20Sopenharmony_ci			return ret;
37038c2ecf20Sopenharmony_ci
37048c2ecf20Sopenharmony_ci		if (reserved != cluster_size - compr_blocks)
37058c2ecf20Sopenharmony_ci			return -ENOSPC;
37068c2ecf20Sopenharmony_ci
37078c2ecf20Sopenharmony_ci		f2fs_i_compr_blocks_update(dn->inode, compr_blocks, true);
37088c2ecf20Sopenharmony_ci
37098c2ecf20Sopenharmony_ci		*reserved_blocks += reserved;
37108c2ecf20Sopenharmony_cinext:
37118c2ecf20Sopenharmony_ci		count -= cluster_size;
37128c2ecf20Sopenharmony_ci	}
37138c2ecf20Sopenharmony_ci
37148c2ecf20Sopenharmony_ci	return 0;
37158c2ecf20Sopenharmony_ci}
37168c2ecf20Sopenharmony_ci
37178c2ecf20Sopenharmony_cistatic int f2fs_reserve_compress_blocks(struct file *filp, unsigned long arg)
37188c2ecf20Sopenharmony_ci{
37198c2ecf20Sopenharmony_ci	struct inode *inode = file_inode(filp);
37208c2ecf20Sopenharmony_ci	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
37218c2ecf20Sopenharmony_ci	pgoff_t page_idx = 0, last_idx;
37228c2ecf20Sopenharmony_ci	unsigned int reserved_blocks = 0;
37238c2ecf20Sopenharmony_ci	int ret;
37248c2ecf20Sopenharmony_ci
37258c2ecf20Sopenharmony_ci	if (!f2fs_sb_has_compression(F2FS_I_SB(inode)))
37268c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
37278c2ecf20Sopenharmony_ci
37288c2ecf20Sopenharmony_ci	if (!f2fs_compressed_file(inode))
37298c2ecf20Sopenharmony_ci		return -EINVAL;
37308c2ecf20Sopenharmony_ci
37318c2ecf20Sopenharmony_ci	if (f2fs_readonly(sbi->sb))
37328c2ecf20Sopenharmony_ci		return -EROFS;
37338c2ecf20Sopenharmony_ci
37348c2ecf20Sopenharmony_ci	ret = mnt_want_write_file(filp);
37358c2ecf20Sopenharmony_ci	if (ret)
37368c2ecf20Sopenharmony_ci		return ret;
37378c2ecf20Sopenharmony_ci
37388c2ecf20Sopenharmony_ci	if (atomic_read(&F2FS_I(inode)->i_compr_blocks))
37398c2ecf20Sopenharmony_ci		goto out;
37408c2ecf20Sopenharmony_ci
37418c2ecf20Sopenharmony_ci	f2fs_balance_fs(F2FS_I_SB(inode), true);
37428c2ecf20Sopenharmony_ci
37438c2ecf20Sopenharmony_ci	inode_lock(inode);
37448c2ecf20Sopenharmony_ci
37458c2ecf20Sopenharmony_ci	if (!IS_IMMUTABLE(inode)) {
37468c2ecf20Sopenharmony_ci		ret = -EINVAL;
37478c2ecf20Sopenharmony_ci		goto unlock_inode;
37488c2ecf20Sopenharmony_ci	}
37498c2ecf20Sopenharmony_ci
37508c2ecf20Sopenharmony_ci	down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
37518c2ecf20Sopenharmony_ci	down_write(&F2FS_I(inode)->i_mmap_sem);
37528c2ecf20Sopenharmony_ci
37538c2ecf20Sopenharmony_ci	last_idx = DIV_ROUND_UP(i_size_read(inode), PAGE_SIZE);
37548c2ecf20Sopenharmony_ci
37558c2ecf20Sopenharmony_ci	while (page_idx < last_idx) {
37568c2ecf20Sopenharmony_ci		struct dnode_of_data dn;
37578c2ecf20Sopenharmony_ci		pgoff_t end_offset, count;
37588c2ecf20Sopenharmony_ci
37598c2ecf20Sopenharmony_ci		f2fs_lock_op(sbi);
37608c2ecf20Sopenharmony_ci
37618c2ecf20Sopenharmony_ci		set_new_dnode(&dn, inode, NULL, NULL, 0);
37628c2ecf20Sopenharmony_ci		ret = f2fs_get_dnode_of_data(&dn, page_idx, LOOKUP_NODE);
37638c2ecf20Sopenharmony_ci		if (ret) {
37648c2ecf20Sopenharmony_ci			f2fs_unlock_op(sbi);
37658c2ecf20Sopenharmony_ci			if (ret == -ENOENT) {
37668c2ecf20Sopenharmony_ci				page_idx = f2fs_get_next_page_offset(&dn,
37678c2ecf20Sopenharmony_ci								page_idx);
37688c2ecf20Sopenharmony_ci				ret = 0;
37698c2ecf20Sopenharmony_ci				continue;
37708c2ecf20Sopenharmony_ci			}
37718c2ecf20Sopenharmony_ci			break;
37728c2ecf20Sopenharmony_ci		}
37738c2ecf20Sopenharmony_ci
37748c2ecf20Sopenharmony_ci		end_offset = ADDRS_PER_PAGE(dn.node_page, inode);
37758c2ecf20Sopenharmony_ci		count = min(end_offset - dn.ofs_in_node, last_idx - page_idx);
37768c2ecf20Sopenharmony_ci		count = round_up(count, F2FS_I(inode)->i_cluster_size);
37778c2ecf20Sopenharmony_ci
37788c2ecf20Sopenharmony_ci		ret = reserve_compress_blocks(&dn, count, &reserved_blocks);
37798c2ecf20Sopenharmony_ci
37808c2ecf20Sopenharmony_ci		f2fs_put_dnode(&dn);
37818c2ecf20Sopenharmony_ci
37828c2ecf20Sopenharmony_ci		f2fs_unlock_op(sbi);
37838c2ecf20Sopenharmony_ci
37848c2ecf20Sopenharmony_ci		if (ret < 0)
37858c2ecf20Sopenharmony_ci			break;
37868c2ecf20Sopenharmony_ci
37878c2ecf20Sopenharmony_ci		page_idx += count;
37888c2ecf20Sopenharmony_ci	}
37898c2ecf20Sopenharmony_ci
37908c2ecf20Sopenharmony_ci	up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
37918c2ecf20Sopenharmony_ci	up_write(&F2FS_I(inode)->i_mmap_sem);
37928c2ecf20Sopenharmony_ci
37938c2ecf20Sopenharmony_ci	if (ret >= 0) {
37948c2ecf20Sopenharmony_ci		F2FS_I(inode)->i_flags &= ~F2FS_IMMUTABLE_FL;
37958c2ecf20Sopenharmony_ci		f2fs_set_inode_flags(inode);
37968c2ecf20Sopenharmony_ci		inode->i_ctime = current_time(inode);
37978c2ecf20Sopenharmony_ci		f2fs_mark_inode_dirty_sync(inode, true);
37988c2ecf20Sopenharmony_ci	}
37998c2ecf20Sopenharmony_ciunlock_inode:
38008c2ecf20Sopenharmony_ci	inode_unlock(inode);
38018c2ecf20Sopenharmony_ciout:
38028c2ecf20Sopenharmony_ci	mnt_drop_write_file(filp);
38038c2ecf20Sopenharmony_ci
38048c2ecf20Sopenharmony_ci	if (!ret) {
38058c2ecf20Sopenharmony_ci		ret = put_user(reserved_blocks, (u64 __user *)arg);
38068c2ecf20Sopenharmony_ci	} else if (reserved_blocks &&
38078c2ecf20Sopenharmony_ci			atomic_read(&F2FS_I(inode)->i_compr_blocks)) {
38088c2ecf20Sopenharmony_ci		set_sbi_flag(sbi, SBI_NEED_FSCK);
38098c2ecf20Sopenharmony_ci		f2fs_warn(sbi, "%s: partial blocks were released i_ino=%lx "
38108c2ecf20Sopenharmony_ci			"iblocks=%llu, reserved=%u, compr_blocks=%u, "
38118c2ecf20Sopenharmony_ci			"run fsck to fix.",
38128c2ecf20Sopenharmony_ci			__func__, inode->i_ino, inode->i_blocks,
38138c2ecf20Sopenharmony_ci			reserved_blocks,
38148c2ecf20Sopenharmony_ci			atomic_read(&F2FS_I(inode)->i_compr_blocks));
38158c2ecf20Sopenharmony_ci	}
38168c2ecf20Sopenharmony_ci
38178c2ecf20Sopenharmony_ci	return ret;
38188c2ecf20Sopenharmony_ci}
38198c2ecf20Sopenharmony_ci
38208c2ecf20Sopenharmony_cistatic int f2fs_secure_erase(struct block_device *bdev, struct inode *inode,
38218c2ecf20Sopenharmony_ci		pgoff_t off, block_t block, block_t len, u32 flags)
38228c2ecf20Sopenharmony_ci{
38238c2ecf20Sopenharmony_ci	struct request_queue *q = bdev_get_queue(bdev);
38248c2ecf20Sopenharmony_ci	sector_t sector = SECTOR_FROM_BLOCK(block);
38258c2ecf20Sopenharmony_ci	sector_t nr_sects = SECTOR_FROM_BLOCK(len);
38268c2ecf20Sopenharmony_ci	int ret = 0;
38278c2ecf20Sopenharmony_ci
38288c2ecf20Sopenharmony_ci	if (!q)
38298c2ecf20Sopenharmony_ci		return -ENXIO;
38308c2ecf20Sopenharmony_ci
38318c2ecf20Sopenharmony_ci	if (flags & F2FS_TRIM_FILE_DISCARD)
38328c2ecf20Sopenharmony_ci		ret = blkdev_issue_discard(bdev, sector, nr_sects, GFP_NOFS,
38338c2ecf20Sopenharmony_ci						blk_queue_secure_erase(q) ?
38348c2ecf20Sopenharmony_ci						BLKDEV_DISCARD_SECURE : 0);
38358c2ecf20Sopenharmony_ci
38368c2ecf20Sopenharmony_ci	if (!ret && (flags & F2FS_TRIM_FILE_ZEROOUT)) {
38378c2ecf20Sopenharmony_ci		if (IS_ENCRYPTED(inode))
38388c2ecf20Sopenharmony_ci			ret = fscrypt_zeroout_range(inode, off, block, len);
38398c2ecf20Sopenharmony_ci		else
38408c2ecf20Sopenharmony_ci			ret = blkdev_issue_zeroout(bdev, sector, nr_sects,
38418c2ecf20Sopenharmony_ci					GFP_NOFS, 0);
38428c2ecf20Sopenharmony_ci	}
38438c2ecf20Sopenharmony_ci
38448c2ecf20Sopenharmony_ci	return ret;
38458c2ecf20Sopenharmony_ci}
38468c2ecf20Sopenharmony_ci
38478c2ecf20Sopenharmony_cistatic int f2fs_sec_trim_file(struct file *filp, unsigned long arg)
38488c2ecf20Sopenharmony_ci{
38498c2ecf20Sopenharmony_ci	struct inode *inode = file_inode(filp);
38508c2ecf20Sopenharmony_ci	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
38518c2ecf20Sopenharmony_ci	struct address_space *mapping = inode->i_mapping;
38528c2ecf20Sopenharmony_ci	struct block_device *prev_bdev = NULL;
38538c2ecf20Sopenharmony_ci	struct f2fs_sectrim_range range;
38548c2ecf20Sopenharmony_ci	pgoff_t index, pg_end, prev_index = 0;
38558c2ecf20Sopenharmony_ci	block_t prev_block = 0, len = 0;
38568c2ecf20Sopenharmony_ci	loff_t end_addr;
38578c2ecf20Sopenharmony_ci	bool to_end = false;
38588c2ecf20Sopenharmony_ci	int ret = 0;
38598c2ecf20Sopenharmony_ci
38608c2ecf20Sopenharmony_ci	if (!(filp->f_mode & FMODE_WRITE))
38618c2ecf20Sopenharmony_ci		return -EBADF;
38628c2ecf20Sopenharmony_ci
38638c2ecf20Sopenharmony_ci	if (copy_from_user(&range, (struct f2fs_sectrim_range __user *)arg,
38648c2ecf20Sopenharmony_ci				sizeof(range)))
38658c2ecf20Sopenharmony_ci		return -EFAULT;
38668c2ecf20Sopenharmony_ci
38678c2ecf20Sopenharmony_ci	if (range.flags == 0 || (range.flags & ~F2FS_TRIM_FILE_MASK) ||
38688c2ecf20Sopenharmony_ci			!S_ISREG(inode->i_mode))
38698c2ecf20Sopenharmony_ci		return -EINVAL;
38708c2ecf20Sopenharmony_ci
38718c2ecf20Sopenharmony_ci	if (((range.flags & F2FS_TRIM_FILE_DISCARD) &&
38728c2ecf20Sopenharmony_ci			!f2fs_hw_support_discard(sbi)) ||
38738c2ecf20Sopenharmony_ci			((range.flags & F2FS_TRIM_FILE_ZEROOUT) &&
38748c2ecf20Sopenharmony_ci			 IS_ENCRYPTED(inode) && f2fs_is_multi_device(sbi)))
38758c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
38768c2ecf20Sopenharmony_ci
38778c2ecf20Sopenharmony_ci	file_start_write(filp);
38788c2ecf20Sopenharmony_ci	inode_lock(inode);
38798c2ecf20Sopenharmony_ci
38808c2ecf20Sopenharmony_ci	if (f2fs_is_atomic_file(inode) || f2fs_compressed_file(inode) ||
38818c2ecf20Sopenharmony_ci			range.start >= inode->i_size) {
38828c2ecf20Sopenharmony_ci		ret = -EINVAL;
38838c2ecf20Sopenharmony_ci		goto err;
38848c2ecf20Sopenharmony_ci	}
38858c2ecf20Sopenharmony_ci
38868c2ecf20Sopenharmony_ci	if (range.len == 0)
38878c2ecf20Sopenharmony_ci		goto err;
38888c2ecf20Sopenharmony_ci
38898c2ecf20Sopenharmony_ci	if (inode->i_size - range.start > range.len) {
38908c2ecf20Sopenharmony_ci		end_addr = range.start + range.len;
38918c2ecf20Sopenharmony_ci	} else {
38928c2ecf20Sopenharmony_ci		end_addr = range.len == (u64)-1 ?
38938c2ecf20Sopenharmony_ci			sbi->sb->s_maxbytes : inode->i_size;
38948c2ecf20Sopenharmony_ci		to_end = true;
38958c2ecf20Sopenharmony_ci	}
38968c2ecf20Sopenharmony_ci
38978c2ecf20Sopenharmony_ci	if (!IS_ALIGNED(range.start, F2FS_BLKSIZE) ||
38988c2ecf20Sopenharmony_ci			(!to_end && !IS_ALIGNED(end_addr, F2FS_BLKSIZE))) {
38998c2ecf20Sopenharmony_ci		ret = -EINVAL;
39008c2ecf20Sopenharmony_ci		goto err;
39018c2ecf20Sopenharmony_ci	}
39028c2ecf20Sopenharmony_ci
39038c2ecf20Sopenharmony_ci	index = F2FS_BYTES_TO_BLK(range.start);
39048c2ecf20Sopenharmony_ci	pg_end = DIV_ROUND_UP(end_addr, F2FS_BLKSIZE);
39058c2ecf20Sopenharmony_ci
39068c2ecf20Sopenharmony_ci	ret = f2fs_convert_inline_inode(inode);
39078c2ecf20Sopenharmony_ci	if (ret)
39088c2ecf20Sopenharmony_ci		goto err;
39098c2ecf20Sopenharmony_ci
39108c2ecf20Sopenharmony_ci	down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
39118c2ecf20Sopenharmony_ci	down_write(&F2FS_I(inode)->i_mmap_sem);
39128c2ecf20Sopenharmony_ci
39138c2ecf20Sopenharmony_ci	ret = filemap_write_and_wait_range(mapping, range.start,
39148c2ecf20Sopenharmony_ci			to_end ? LLONG_MAX : end_addr - 1);
39158c2ecf20Sopenharmony_ci	if (ret)
39168c2ecf20Sopenharmony_ci		goto out;
39178c2ecf20Sopenharmony_ci
39188c2ecf20Sopenharmony_ci	truncate_inode_pages_range(mapping, range.start,
39198c2ecf20Sopenharmony_ci			to_end ? -1 : end_addr - 1);
39208c2ecf20Sopenharmony_ci
39218c2ecf20Sopenharmony_ci	while (index < pg_end) {
39228c2ecf20Sopenharmony_ci		struct dnode_of_data dn;
39238c2ecf20Sopenharmony_ci		pgoff_t end_offset, count;
39248c2ecf20Sopenharmony_ci		int i;
39258c2ecf20Sopenharmony_ci
39268c2ecf20Sopenharmony_ci		set_new_dnode(&dn, inode, NULL, NULL, 0);
39278c2ecf20Sopenharmony_ci		ret = f2fs_get_dnode_of_data(&dn, index, LOOKUP_NODE);
39288c2ecf20Sopenharmony_ci		if (ret) {
39298c2ecf20Sopenharmony_ci			if (ret == -ENOENT) {
39308c2ecf20Sopenharmony_ci				index = f2fs_get_next_page_offset(&dn, index);
39318c2ecf20Sopenharmony_ci				continue;
39328c2ecf20Sopenharmony_ci			}
39338c2ecf20Sopenharmony_ci			goto out;
39348c2ecf20Sopenharmony_ci		}
39358c2ecf20Sopenharmony_ci
39368c2ecf20Sopenharmony_ci		end_offset = ADDRS_PER_PAGE(dn.node_page, inode);
39378c2ecf20Sopenharmony_ci		count = min(end_offset - dn.ofs_in_node, pg_end - index);
39388c2ecf20Sopenharmony_ci		for (i = 0; i < count; i++, index++, dn.ofs_in_node++) {
39398c2ecf20Sopenharmony_ci			struct block_device *cur_bdev;
39408c2ecf20Sopenharmony_ci			block_t blkaddr = f2fs_data_blkaddr(&dn);
39418c2ecf20Sopenharmony_ci
39428c2ecf20Sopenharmony_ci			if (!__is_valid_data_blkaddr(blkaddr))
39438c2ecf20Sopenharmony_ci				continue;
39448c2ecf20Sopenharmony_ci
39458c2ecf20Sopenharmony_ci			if (!f2fs_is_valid_blkaddr(sbi, blkaddr,
39468c2ecf20Sopenharmony_ci						DATA_GENERIC_ENHANCE)) {
39478c2ecf20Sopenharmony_ci				ret = -EFSCORRUPTED;
39488c2ecf20Sopenharmony_ci				f2fs_put_dnode(&dn);
39498c2ecf20Sopenharmony_ci				goto out;
39508c2ecf20Sopenharmony_ci			}
39518c2ecf20Sopenharmony_ci
39528c2ecf20Sopenharmony_ci			cur_bdev = f2fs_target_device(sbi, blkaddr, NULL);
39538c2ecf20Sopenharmony_ci			if (f2fs_is_multi_device(sbi)) {
39548c2ecf20Sopenharmony_ci				int di = f2fs_target_device_index(sbi, blkaddr);
39558c2ecf20Sopenharmony_ci
39568c2ecf20Sopenharmony_ci				blkaddr -= FDEV(di).start_blk;
39578c2ecf20Sopenharmony_ci			}
39588c2ecf20Sopenharmony_ci
39598c2ecf20Sopenharmony_ci			if (len) {
39608c2ecf20Sopenharmony_ci				if (prev_bdev == cur_bdev &&
39618c2ecf20Sopenharmony_ci						index == prev_index + len &&
39628c2ecf20Sopenharmony_ci						blkaddr == prev_block + len) {
39638c2ecf20Sopenharmony_ci					len++;
39648c2ecf20Sopenharmony_ci				} else {
39658c2ecf20Sopenharmony_ci					ret = f2fs_secure_erase(prev_bdev,
39668c2ecf20Sopenharmony_ci						inode, prev_index, prev_block,
39678c2ecf20Sopenharmony_ci						len, range.flags);
39688c2ecf20Sopenharmony_ci					if (ret) {
39698c2ecf20Sopenharmony_ci						f2fs_put_dnode(&dn);
39708c2ecf20Sopenharmony_ci						goto out;
39718c2ecf20Sopenharmony_ci					}
39728c2ecf20Sopenharmony_ci
39738c2ecf20Sopenharmony_ci					len = 0;
39748c2ecf20Sopenharmony_ci				}
39758c2ecf20Sopenharmony_ci			}
39768c2ecf20Sopenharmony_ci
39778c2ecf20Sopenharmony_ci			if (!len) {
39788c2ecf20Sopenharmony_ci				prev_bdev = cur_bdev;
39798c2ecf20Sopenharmony_ci				prev_index = index;
39808c2ecf20Sopenharmony_ci				prev_block = blkaddr;
39818c2ecf20Sopenharmony_ci				len = 1;
39828c2ecf20Sopenharmony_ci			}
39838c2ecf20Sopenharmony_ci		}
39848c2ecf20Sopenharmony_ci
39858c2ecf20Sopenharmony_ci		f2fs_put_dnode(&dn);
39868c2ecf20Sopenharmony_ci
39878c2ecf20Sopenharmony_ci		if (fatal_signal_pending(current)) {
39888c2ecf20Sopenharmony_ci			ret = -EINTR;
39898c2ecf20Sopenharmony_ci			goto out;
39908c2ecf20Sopenharmony_ci		}
39918c2ecf20Sopenharmony_ci		cond_resched();
39928c2ecf20Sopenharmony_ci	}
39938c2ecf20Sopenharmony_ci
39948c2ecf20Sopenharmony_ci	if (len)
39958c2ecf20Sopenharmony_ci		ret = f2fs_secure_erase(prev_bdev, inode, prev_index,
39968c2ecf20Sopenharmony_ci				prev_block, len, range.flags);
39978c2ecf20Sopenharmony_ciout:
39988c2ecf20Sopenharmony_ci	up_write(&F2FS_I(inode)->i_mmap_sem);
39998c2ecf20Sopenharmony_ci	up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
40008c2ecf20Sopenharmony_cierr:
40018c2ecf20Sopenharmony_ci	inode_unlock(inode);
40028c2ecf20Sopenharmony_ci	file_end_write(filp);
40038c2ecf20Sopenharmony_ci
40048c2ecf20Sopenharmony_ci	return ret;
40058c2ecf20Sopenharmony_ci}
40068c2ecf20Sopenharmony_ci
40078c2ecf20Sopenharmony_cistatic long __f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
40088c2ecf20Sopenharmony_ci{
40098c2ecf20Sopenharmony_ci	switch (cmd) {
40108c2ecf20Sopenharmony_ci	case FS_IOC_GETFLAGS:
40118c2ecf20Sopenharmony_ci		return f2fs_ioc_getflags(filp, arg);
40128c2ecf20Sopenharmony_ci	case FS_IOC_SETFLAGS:
40138c2ecf20Sopenharmony_ci		return f2fs_ioc_setflags(filp, arg);
40148c2ecf20Sopenharmony_ci	case FS_IOC_GETVERSION:
40158c2ecf20Sopenharmony_ci		return f2fs_ioc_getversion(filp, arg);
40168c2ecf20Sopenharmony_ci	case F2FS_IOC_START_ATOMIC_WRITE:
40178c2ecf20Sopenharmony_ci		return f2fs_ioc_start_atomic_write(filp);
40188c2ecf20Sopenharmony_ci	case F2FS_IOC_COMMIT_ATOMIC_WRITE:
40198c2ecf20Sopenharmony_ci		return f2fs_ioc_commit_atomic_write(filp);
40208c2ecf20Sopenharmony_ci	case F2FS_IOC_START_VOLATILE_WRITE:
40218c2ecf20Sopenharmony_ci		return f2fs_ioc_start_volatile_write(filp);
40228c2ecf20Sopenharmony_ci	case F2FS_IOC_RELEASE_VOLATILE_WRITE:
40238c2ecf20Sopenharmony_ci		return f2fs_ioc_release_volatile_write(filp);
40248c2ecf20Sopenharmony_ci	case F2FS_IOC_ABORT_VOLATILE_WRITE:
40258c2ecf20Sopenharmony_ci		return f2fs_ioc_abort_volatile_write(filp);
40268c2ecf20Sopenharmony_ci	case F2FS_IOC_SHUTDOWN:
40278c2ecf20Sopenharmony_ci		return f2fs_ioc_shutdown(filp, arg);
40288c2ecf20Sopenharmony_ci	case FITRIM:
40298c2ecf20Sopenharmony_ci		return f2fs_ioc_fitrim(filp, arg);
40308c2ecf20Sopenharmony_ci	case FS_IOC_SET_ENCRYPTION_POLICY:
40318c2ecf20Sopenharmony_ci		return f2fs_ioc_set_encryption_policy(filp, arg);
40328c2ecf20Sopenharmony_ci	case FS_IOC_GET_ENCRYPTION_POLICY:
40338c2ecf20Sopenharmony_ci		return f2fs_ioc_get_encryption_policy(filp, arg);
40348c2ecf20Sopenharmony_ci	case FS_IOC_GET_ENCRYPTION_PWSALT:
40358c2ecf20Sopenharmony_ci		return f2fs_ioc_get_encryption_pwsalt(filp, arg);
40368c2ecf20Sopenharmony_ci	case FS_IOC_GET_ENCRYPTION_POLICY_EX:
40378c2ecf20Sopenharmony_ci		return f2fs_ioc_get_encryption_policy_ex(filp, arg);
40388c2ecf20Sopenharmony_ci	case FS_IOC_ADD_ENCRYPTION_KEY:
40398c2ecf20Sopenharmony_ci		return f2fs_ioc_add_encryption_key(filp, arg);
40408c2ecf20Sopenharmony_ci	case FS_IOC_REMOVE_ENCRYPTION_KEY:
40418c2ecf20Sopenharmony_ci		return f2fs_ioc_remove_encryption_key(filp, arg);
40428c2ecf20Sopenharmony_ci	case FS_IOC_REMOVE_ENCRYPTION_KEY_ALL_USERS:
40438c2ecf20Sopenharmony_ci		return f2fs_ioc_remove_encryption_key_all_users(filp, arg);
40448c2ecf20Sopenharmony_ci	case FS_IOC_GET_ENCRYPTION_KEY_STATUS:
40458c2ecf20Sopenharmony_ci		return f2fs_ioc_get_encryption_key_status(filp, arg);
40468c2ecf20Sopenharmony_ci	case FS_IOC_GET_ENCRYPTION_NONCE:
40478c2ecf20Sopenharmony_ci		return f2fs_ioc_get_encryption_nonce(filp, arg);
40488c2ecf20Sopenharmony_ci	case F2FS_IOC_GARBAGE_COLLECT:
40498c2ecf20Sopenharmony_ci		return f2fs_ioc_gc(filp, arg);
40508c2ecf20Sopenharmony_ci	case F2FS_IOC_GARBAGE_COLLECT_RANGE:
40518c2ecf20Sopenharmony_ci		return f2fs_ioc_gc_range(filp, arg);
40528c2ecf20Sopenharmony_ci	case F2FS_IOC_WRITE_CHECKPOINT:
40538c2ecf20Sopenharmony_ci		return f2fs_ioc_write_checkpoint(filp, arg);
40548c2ecf20Sopenharmony_ci	case F2FS_IOC_DEFRAGMENT:
40558c2ecf20Sopenharmony_ci		return f2fs_ioc_defragment(filp, arg);
40568c2ecf20Sopenharmony_ci	case F2FS_IOC_MOVE_RANGE:
40578c2ecf20Sopenharmony_ci		return f2fs_ioc_move_range(filp, arg);
40588c2ecf20Sopenharmony_ci	case F2FS_IOC_FLUSH_DEVICE:
40598c2ecf20Sopenharmony_ci		return f2fs_ioc_flush_device(filp, arg);
40608c2ecf20Sopenharmony_ci	case F2FS_IOC_GET_FEATURES:
40618c2ecf20Sopenharmony_ci		return f2fs_ioc_get_features(filp, arg);
40628c2ecf20Sopenharmony_ci	case FS_IOC_FSGETXATTR:
40638c2ecf20Sopenharmony_ci		return f2fs_ioc_fsgetxattr(filp, arg);
40648c2ecf20Sopenharmony_ci	case FS_IOC_FSSETXATTR:
40658c2ecf20Sopenharmony_ci		return f2fs_ioc_fssetxattr(filp, arg);
40668c2ecf20Sopenharmony_ci	case F2FS_IOC_GET_PIN_FILE:
40678c2ecf20Sopenharmony_ci		return f2fs_ioc_get_pin_file(filp, arg);
40688c2ecf20Sopenharmony_ci	case F2FS_IOC_SET_PIN_FILE:
40698c2ecf20Sopenharmony_ci		return f2fs_ioc_set_pin_file(filp, arg);
40708c2ecf20Sopenharmony_ci	case F2FS_IOC_PRECACHE_EXTENTS:
40718c2ecf20Sopenharmony_ci		return f2fs_ioc_precache_extents(filp, arg);
40728c2ecf20Sopenharmony_ci	case F2FS_IOC_RESIZE_FS:
40738c2ecf20Sopenharmony_ci		return f2fs_ioc_resize_fs(filp, arg);
40748c2ecf20Sopenharmony_ci	case FS_IOC_ENABLE_VERITY:
40758c2ecf20Sopenharmony_ci		return f2fs_ioc_enable_verity(filp, arg);
40768c2ecf20Sopenharmony_ci	case FS_IOC_MEASURE_VERITY:
40778c2ecf20Sopenharmony_ci		return f2fs_ioc_measure_verity(filp, arg);
40788c2ecf20Sopenharmony_ci	case FS_IOC_ENABLE_CODE_SIGN:
40798c2ecf20Sopenharmony_ci		return f2fs_ioc_enable_code_sign(filp, arg);
40808c2ecf20Sopenharmony_ci	case FS_IOC_GETFSLABEL:
40818c2ecf20Sopenharmony_ci		return f2fs_ioc_getfslabel(filp, arg);
40828c2ecf20Sopenharmony_ci	case FS_IOC_SETFSLABEL:
40838c2ecf20Sopenharmony_ci		return f2fs_ioc_setfslabel(filp, arg);
40848c2ecf20Sopenharmony_ci	case F2FS_IOC_GET_COMPRESS_BLOCKS:
40858c2ecf20Sopenharmony_ci		return f2fs_get_compress_blocks(filp, arg);
40868c2ecf20Sopenharmony_ci	case F2FS_IOC_RELEASE_COMPRESS_BLOCKS:
40878c2ecf20Sopenharmony_ci		return f2fs_release_compress_blocks(filp, arg);
40888c2ecf20Sopenharmony_ci	case F2FS_IOC_RESERVE_COMPRESS_BLOCKS:
40898c2ecf20Sopenharmony_ci		return f2fs_reserve_compress_blocks(filp, arg);
40908c2ecf20Sopenharmony_ci	case F2FS_IOC_SEC_TRIM_FILE:
40918c2ecf20Sopenharmony_ci		return f2fs_sec_trim_file(filp, arg);
40928c2ecf20Sopenharmony_ci	default:
40938c2ecf20Sopenharmony_ci		return -ENOTTY;
40948c2ecf20Sopenharmony_ci	}
40958c2ecf20Sopenharmony_ci}
40968c2ecf20Sopenharmony_ci
40978c2ecf20Sopenharmony_cilong f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
40988c2ecf20Sopenharmony_ci{
40998c2ecf20Sopenharmony_ci	if (unlikely(f2fs_cp_error(F2FS_I_SB(file_inode(filp)))))
41008c2ecf20Sopenharmony_ci		return -EIO;
41018c2ecf20Sopenharmony_ci	if (!f2fs_is_checkpoint_ready(F2FS_I_SB(file_inode(filp))))
41028c2ecf20Sopenharmony_ci		return -ENOSPC;
41038c2ecf20Sopenharmony_ci
41048c2ecf20Sopenharmony_ci	return __f2fs_ioctl(filp, cmd, arg);
41058c2ecf20Sopenharmony_ci}
41068c2ecf20Sopenharmony_ci
41078c2ecf20Sopenharmony_cistatic ssize_t f2fs_file_read_iter(struct kiocb *iocb, struct iov_iter *iter)
41088c2ecf20Sopenharmony_ci{
41098c2ecf20Sopenharmony_ci	struct file *file = iocb->ki_filp;
41108c2ecf20Sopenharmony_ci	struct inode *inode = file_inode(file);
41118c2ecf20Sopenharmony_ci	int ret;
41128c2ecf20Sopenharmony_ci
41138c2ecf20Sopenharmony_ci	if (!f2fs_is_compress_backend_ready(inode))
41148c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
41158c2ecf20Sopenharmony_ci
41168c2ecf20Sopenharmony_ci	ret = generic_file_read_iter(iocb, iter);
41178c2ecf20Sopenharmony_ci
41188c2ecf20Sopenharmony_ci	if (ret > 0)
41198c2ecf20Sopenharmony_ci		f2fs_update_iostat(F2FS_I_SB(inode), APP_READ_IO, ret);
41208c2ecf20Sopenharmony_ci
41218c2ecf20Sopenharmony_ci	return ret;
41228c2ecf20Sopenharmony_ci}
41238c2ecf20Sopenharmony_ci
41248c2ecf20Sopenharmony_cistatic ssize_t f2fs_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
41258c2ecf20Sopenharmony_ci{
41268c2ecf20Sopenharmony_ci	struct file *file = iocb->ki_filp;
41278c2ecf20Sopenharmony_ci	struct inode *inode = file_inode(file);
41288c2ecf20Sopenharmony_ci	ssize_t ret;
41298c2ecf20Sopenharmony_ci
41308c2ecf20Sopenharmony_ci	if (unlikely(f2fs_cp_error(F2FS_I_SB(inode)))) {
41318c2ecf20Sopenharmony_ci		ret = -EIO;
41328c2ecf20Sopenharmony_ci		goto out;
41338c2ecf20Sopenharmony_ci	}
41348c2ecf20Sopenharmony_ci
41358c2ecf20Sopenharmony_ci	if (!f2fs_is_compress_backend_ready(inode)) {
41368c2ecf20Sopenharmony_ci		ret = -EOPNOTSUPP;
41378c2ecf20Sopenharmony_ci		goto out;
41388c2ecf20Sopenharmony_ci	}
41398c2ecf20Sopenharmony_ci
41408c2ecf20Sopenharmony_ci	if (iocb->ki_flags & IOCB_NOWAIT) {
41418c2ecf20Sopenharmony_ci		if (!inode_trylock(inode)) {
41428c2ecf20Sopenharmony_ci			ret = -EAGAIN;
41438c2ecf20Sopenharmony_ci			goto out;
41448c2ecf20Sopenharmony_ci		}
41458c2ecf20Sopenharmony_ci	} else {
41468c2ecf20Sopenharmony_ci		inode_lock(inode);
41478c2ecf20Sopenharmony_ci	}
41488c2ecf20Sopenharmony_ci
41498c2ecf20Sopenharmony_ci	if (unlikely(IS_IMMUTABLE(inode))) {
41508c2ecf20Sopenharmony_ci		ret = -EPERM;
41518c2ecf20Sopenharmony_ci		goto unlock;
41528c2ecf20Sopenharmony_ci	}
41538c2ecf20Sopenharmony_ci
41548c2ecf20Sopenharmony_ci	ret = generic_write_checks(iocb, from);
41558c2ecf20Sopenharmony_ci	if (ret > 0) {
41568c2ecf20Sopenharmony_ci		bool preallocated = false;
41578c2ecf20Sopenharmony_ci		size_t target_size = 0;
41588c2ecf20Sopenharmony_ci		int err;
41598c2ecf20Sopenharmony_ci
41608c2ecf20Sopenharmony_ci		if (iov_iter_fault_in_readable(from, iov_iter_count(from)))
41618c2ecf20Sopenharmony_ci			set_inode_flag(inode, FI_NO_PREALLOC);
41628c2ecf20Sopenharmony_ci
41638c2ecf20Sopenharmony_ci		if ((iocb->ki_flags & IOCB_NOWAIT)) {
41648c2ecf20Sopenharmony_ci			if (!f2fs_overwrite_io(inode, iocb->ki_pos,
41658c2ecf20Sopenharmony_ci						iov_iter_count(from)) ||
41668c2ecf20Sopenharmony_ci				f2fs_has_inline_data(inode) ||
41678c2ecf20Sopenharmony_ci				f2fs_force_buffered_io(inode, iocb, from)) {
41688c2ecf20Sopenharmony_ci				clear_inode_flag(inode, FI_NO_PREALLOC);
41698c2ecf20Sopenharmony_ci				inode_unlock(inode);
41708c2ecf20Sopenharmony_ci				ret = -EAGAIN;
41718c2ecf20Sopenharmony_ci				goto out;
41728c2ecf20Sopenharmony_ci			}
41738c2ecf20Sopenharmony_ci			goto write;
41748c2ecf20Sopenharmony_ci		}
41758c2ecf20Sopenharmony_ci
41768c2ecf20Sopenharmony_ci		if (is_inode_flag_set(inode, FI_NO_PREALLOC))
41778c2ecf20Sopenharmony_ci			goto write;
41788c2ecf20Sopenharmony_ci
41798c2ecf20Sopenharmony_ci		if (iocb->ki_flags & IOCB_DIRECT) {
41808c2ecf20Sopenharmony_ci			/*
41818c2ecf20Sopenharmony_ci			 * Convert inline data for Direct I/O before entering
41828c2ecf20Sopenharmony_ci			 * f2fs_direct_IO().
41838c2ecf20Sopenharmony_ci			 */
41848c2ecf20Sopenharmony_ci			err = f2fs_convert_inline_inode(inode);
41858c2ecf20Sopenharmony_ci			if (err)
41868c2ecf20Sopenharmony_ci				goto out_err;
41878c2ecf20Sopenharmony_ci			/*
41888c2ecf20Sopenharmony_ci			 * If force_buffere_io() is true, we have to allocate
41898c2ecf20Sopenharmony_ci			 * blocks all the time, since f2fs_direct_IO will fall
41908c2ecf20Sopenharmony_ci			 * back to buffered IO.
41918c2ecf20Sopenharmony_ci			 */
41928c2ecf20Sopenharmony_ci			if (!f2fs_force_buffered_io(inode, iocb, from) &&
41938c2ecf20Sopenharmony_ci					allow_outplace_dio(inode, iocb, from))
41948c2ecf20Sopenharmony_ci				goto write;
41958c2ecf20Sopenharmony_ci		}
41968c2ecf20Sopenharmony_ci		preallocated = true;
41978c2ecf20Sopenharmony_ci		target_size = iocb->ki_pos + iov_iter_count(from);
41988c2ecf20Sopenharmony_ci
41998c2ecf20Sopenharmony_ci		err = f2fs_preallocate_blocks(iocb, from);
42008c2ecf20Sopenharmony_ci		if (err) {
42018c2ecf20Sopenharmony_ciout_err:
42028c2ecf20Sopenharmony_ci			clear_inode_flag(inode, FI_NO_PREALLOC);
42038c2ecf20Sopenharmony_ci			inode_unlock(inode);
42048c2ecf20Sopenharmony_ci			ret = err;
42058c2ecf20Sopenharmony_ci			goto out;
42068c2ecf20Sopenharmony_ci		}
42078c2ecf20Sopenharmony_ciwrite:
42088c2ecf20Sopenharmony_ci		ret = __generic_file_write_iter(iocb, from);
42098c2ecf20Sopenharmony_ci		clear_inode_flag(inode, FI_NO_PREALLOC);
42108c2ecf20Sopenharmony_ci
42118c2ecf20Sopenharmony_ci		/* if we couldn't write data, we should deallocate blocks. */
42128c2ecf20Sopenharmony_ci		if (preallocated && i_size_read(inode) < target_size)
42138c2ecf20Sopenharmony_ci			f2fs_truncate(inode);
42148c2ecf20Sopenharmony_ci
42158c2ecf20Sopenharmony_ci		if (ret > 0)
42168c2ecf20Sopenharmony_ci			f2fs_update_iostat(F2FS_I_SB(inode), APP_WRITE_IO, ret);
42178c2ecf20Sopenharmony_ci	}
42188c2ecf20Sopenharmony_ciunlock:
42198c2ecf20Sopenharmony_ci	inode_unlock(inode);
42208c2ecf20Sopenharmony_ciout:
42218c2ecf20Sopenharmony_ci	trace_f2fs_file_write_iter(inode, iocb->ki_pos,
42228c2ecf20Sopenharmony_ci					iov_iter_count(from), ret);
42238c2ecf20Sopenharmony_ci	if (ret > 0)
42248c2ecf20Sopenharmony_ci		ret = generic_write_sync(iocb, ret);
42258c2ecf20Sopenharmony_ci	return ret;
42268c2ecf20Sopenharmony_ci}
42278c2ecf20Sopenharmony_ci
42288c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT
42298c2ecf20Sopenharmony_cistruct compat_f2fs_gc_range {
42308c2ecf20Sopenharmony_ci	u32 sync;
42318c2ecf20Sopenharmony_ci	compat_u64 start;
42328c2ecf20Sopenharmony_ci	compat_u64 len;
42338c2ecf20Sopenharmony_ci};
42348c2ecf20Sopenharmony_ci#define F2FS_IOC32_GARBAGE_COLLECT_RANGE	_IOW(F2FS_IOCTL_MAGIC, 11,\
42358c2ecf20Sopenharmony_ci						struct compat_f2fs_gc_range)
42368c2ecf20Sopenharmony_ci
42378c2ecf20Sopenharmony_cistatic int f2fs_compat_ioc_gc_range(struct file *file, unsigned long arg)
42388c2ecf20Sopenharmony_ci{
42398c2ecf20Sopenharmony_ci	struct compat_f2fs_gc_range __user *urange;
42408c2ecf20Sopenharmony_ci	struct f2fs_gc_range range;
42418c2ecf20Sopenharmony_ci	int err;
42428c2ecf20Sopenharmony_ci
42438c2ecf20Sopenharmony_ci	urange = compat_ptr(arg);
42448c2ecf20Sopenharmony_ci	err = get_user(range.sync, &urange->sync);
42458c2ecf20Sopenharmony_ci	err |= get_user(range.start, &urange->start);
42468c2ecf20Sopenharmony_ci	err |= get_user(range.len, &urange->len);
42478c2ecf20Sopenharmony_ci	if (err)
42488c2ecf20Sopenharmony_ci		return -EFAULT;
42498c2ecf20Sopenharmony_ci
42508c2ecf20Sopenharmony_ci	return __f2fs_ioc_gc_range(file, &range);
42518c2ecf20Sopenharmony_ci}
42528c2ecf20Sopenharmony_ci
42538c2ecf20Sopenharmony_cistruct compat_f2fs_move_range {
42548c2ecf20Sopenharmony_ci	u32 dst_fd;
42558c2ecf20Sopenharmony_ci	compat_u64 pos_in;
42568c2ecf20Sopenharmony_ci	compat_u64 pos_out;
42578c2ecf20Sopenharmony_ci	compat_u64 len;
42588c2ecf20Sopenharmony_ci};
42598c2ecf20Sopenharmony_ci#define F2FS_IOC32_MOVE_RANGE		_IOWR(F2FS_IOCTL_MAGIC, 9,	\
42608c2ecf20Sopenharmony_ci					struct compat_f2fs_move_range)
42618c2ecf20Sopenharmony_ci
42628c2ecf20Sopenharmony_cistatic int f2fs_compat_ioc_move_range(struct file *file, unsigned long arg)
42638c2ecf20Sopenharmony_ci{
42648c2ecf20Sopenharmony_ci	struct compat_f2fs_move_range __user *urange;
42658c2ecf20Sopenharmony_ci	struct f2fs_move_range range;
42668c2ecf20Sopenharmony_ci	int err;
42678c2ecf20Sopenharmony_ci
42688c2ecf20Sopenharmony_ci	urange = compat_ptr(arg);
42698c2ecf20Sopenharmony_ci	err = get_user(range.dst_fd, &urange->dst_fd);
42708c2ecf20Sopenharmony_ci	err |= get_user(range.pos_in, &urange->pos_in);
42718c2ecf20Sopenharmony_ci	err |= get_user(range.pos_out, &urange->pos_out);
42728c2ecf20Sopenharmony_ci	err |= get_user(range.len, &urange->len);
42738c2ecf20Sopenharmony_ci	if (err)
42748c2ecf20Sopenharmony_ci		return -EFAULT;
42758c2ecf20Sopenharmony_ci
42768c2ecf20Sopenharmony_ci	return __f2fs_ioc_move_range(file, &range);
42778c2ecf20Sopenharmony_ci}
42788c2ecf20Sopenharmony_ci
42798c2ecf20Sopenharmony_cilong f2fs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
42808c2ecf20Sopenharmony_ci{
42818c2ecf20Sopenharmony_ci	if (unlikely(f2fs_cp_error(F2FS_I_SB(file_inode(file)))))
42828c2ecf20Sopenharmony_ci		return -EIO;
42838c2ecf20Sopenharmony_ci	if (!f2fs_is_checkpoint_ready(F2FS_I_SB(file_inode(file))))
42848c2ecf20Sopenharmony_ci		return -ENOSPC;
42858c2ecf20Sopenharmony_ci
42868c2ecf20Sopenharmony_ci	switch (cmd) {
42878c2ecf20Sopenharmony_ci	case FS_IOC32_GETFLAGS:
42888c2ecf20Sopenharmony_ci		cmd = FS_IOC_GETFLAGS;
42898c2ecf20Sopenharmony_ci		break;
42908c2ecf20Sopenharmony_ci	case FS_IOC32_SETFLAGS:
42918c2ecf20Sopenharmony_ci		cmd = FS_IOC_SETFLAGS;
42928c2ecf20Sopenharmony_ci		break;
42938c2ecf20Sopenharmony_ci	case FS_IOC32_GETVERSION:
42948c2ecf20Sopenharmony_ci		cmd = FS_IOC_GETVERSION;
42958c2ecf20Sopenharmony_ci		break;
42968c2ecf20Sopenharmony_ci	case F2FS_IOC32_GARBAGE_COLLECT_RANGE:
42978c2ecf20Sopenharmony_ci		return f2fs_compat_ioc_gc_range(file, arg);
42988c2ecf20Sopenharmony_ci	case F2FS_IOC32_MOVE_RANGE:
42998c2ecf20Sopenharmony_ci		return f2fs_compat_ioc_move_range(file, arg);
43008c2ecf20Sopenharmony_ci	case F2FS_IOC_START_ATOMIC_WRITE:
43018c2ecf20Sopenharmony_ci	case F2FS_IOC_COMMIT_ATOMIC_WRITE:
43028c2ecf20Sopenharmony_ci	case F2FS_IOC_START_VOLATILE_WRITE:
43038c2ecf20Sopenharmony_ci	case F2FS_IOC_RELEASE_VOLATILE_WRITE:
43048c2ecf20Sopenharmony_ci	case F2FS_IOC_ABORT_VOLATILE_WRITE:
43058c2ecf20Sopenharmony_ci	case F2FS_IOC_SHUTDOWN:
43068c2ecf20Sopenharmony_ci	case FITRIM:
43078c2ecf20Sopenharmony_ci	case FS_IOC_SET_ENCRYPTION_POLICY:
43088c2ecf20Sopenharmony_ci	case FS_IOC_GET_ENCRYPTION_PWSALT:
43098c2ecf20Sopenharmony_ci	case FS_IOC_GET_ENCRYPTION_POLICY:
43108c2ecf20Sopenharmony_ci	case FS_IOC_GET_ENCRYPTION_POLICY_EX:
43118c2ecf20Sopenharmony_ci	case FS_IOC_ADD_ENCRYPTION_KEY:
43128c2ecf20Sopenharmony_ci	case FS_IOC_REMOVE_ENCRYPTION_KEY:
43138c2ecf20Sopenharmony_ci	case FS_IOC_REMOVE_ENCRYPTION_KEY_ALL_USERS:
43148c2ecf20Sopenharmony_ci	case FS_IOC_GET_ENCRYPTION_KEY_STATUS:
43158c2ecf20Sopenharmony_ci	case FS_IOC_GET_ENCRYPTION_NONCE:
43168c2ecf20Sopenharmony_ci	case F2FS_IOC_GARBAGE_COLLECT:
43178c2ecf20Sopenharmony_ci	case F2FS_IOC_WRITE_CHECKPOINT:
43188c2ecf20Sopenharmony_ci	case F2FS_IOC_DEFRAGMENT:
43198c2ecf20Sopenharmony_ci	case F2FS_IOC_FLUSH_DEVICE:
43208c2ecf20Sopenharmony_ci	case F2FS_IOC_GET_FEATURES:
43218c2ecf20Sopenharmony_ci	case FS_IOC_FSGETXATTR:
43228c2ecf20Sopenharmony_ci	case FS_IOC_FSSETXATTR:
43238c2ecf20Sopenharmony_ci	case F2FS_IOC_GET_PIN_FILE:
43248c2ecf20Sopenharmony_ci	case F2FS_IOC_SET_PIN_FILE:
43258c2ecf20Sopenharmony_ci	case F2FS_IOC_PRECACHE_EXTENTS:
43268c2ecf20Sopenharmony_ci	case F2FS_IOC_RESIZE_FS:
43278c2ecf20Sopenharmony_ci	case FS_IOC_ENABLE_VERITY:
43288c2ecf20Sopenharmony_ci	case FS_IOC_MEASURE_VERITY:
43298c2ecf20Sopenharmony_ci	case FS_IOC_ENABLE_CODE_SIGN:
43308c2ecf20Sopenharmony_ci	case FS_IOC_GETFSLABEL:
43318c2ecf20Sopenharmony_ci	case FS_IOC_SETFSLABEL:
43328c2ecf20Sopenharmony_ci	case F2FS_IOC_GET_COMPRESS_BLOCKS:
43338c2ecf20Sopenharmony_ci	case F2FS_IOC_RELEASE_COMPRESS_BLOCKS:
43348c2ecf20Sopenharmony_ci	case F2FS_IOC_RESERVE_COMPRESS_BLOCKS:
43358c2ecf20Sopenharmony_ci	case F2FS_IOC_SEC_TRIM_FILE:
43368c2ecf20Sopenharmony_ci		break;
43378c2ecf20Sopenharmony_ci	default:
43388c2ecf20Sopenharmony_ci		return -ENOIOCTLCMD;
43398c2ecf20Sopenharmony_ci	}
43408c2ecf20Sopenharmony_ci	return __f2fs_ioctl(file, cmd, (unsigned long) compat_ptr(arg));
43418c2ecf20Sopenharmony_ci}
43428c2ecf20Sopenharmony_ci#endif
43438c2ecf20Sopenharmony_ci
43448c2ecf20Sopenharmony_ciconst struct file_operations f2fs_file_operations = {
43458c2ecf20Sopenharmony_ci	.llseek		= f2fs_llseek,
43468c2ecf20Sopenharmony_ci	.read_iter	= f2fs_file_read_iter,
43478c2ecf20Sopenharmony_ci	.write_iter	= f2fs_file_write_iter,
43488c2ecf20Sopenharmony_ci	.open		= f2fs_file_open,
43498c2ecf20Sopenharmony_ci	.release	= f2fs_release_file,
43508c2ecf20Sopenharmony_ci	.mmap		= f2fs_file_mmap,
43518c2ecf20Sopenharmony_ci	.flush		= f2fs_file_flush,
43528c2ecf20Sopenharmony_ci	.fsync		= f2fs_sync_file,
43538c2ecf20Sopenharmony_ci	.fallocate	= f2fs_fallocate,
43548c2ecf20Sopenharmony_ci	.unlocked_ioctl	= f2fs_ioctl,
43558c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT
43568c2ecf20Sopenharmony_ci	.compat_ioctl	= f2fs_compat_ioctl,
43578c2ecf20Sopenharmony_ci#endif
43588c2ecf20Sopenharmony_ci	.splice_read	= generic_file_splice_read,
43598c2ecf20Sopenharmony_ci	.splice_write	= iter_file_splice_write,
43608c2ecf20Sopenharmony_ci};
4361