xref: /openbmc/linux/fs/f2fs/file.c (revision 9144f784f852f9a125cabe9927b986d909bfa439)
17c1a000dSChao Yu // SPDX-License-Identifier: GPL-2.0
20a8165d7SJaegeuk Kim /*
3fbfa2cc5SJaegeuk Kim  * fs/f2fs/file.c
4fbfa2cc5SJaegeuk Kim  *
5fbfa2cc5SJaegeuk Kim  * Copyright (c) 2012 Samsung Electronics Co., Ltd.
6fbfa2cc5SJaegeuk Kim  *             http://www.samsung.com/
7fbfa2cc5SJaegeuk Kim  */
8fbfa2cc5SJaegeuk Kim #include <linux/fs.h>
9fbfa2cc5SJaegeuk Kim #include <linux/f2fs_fs.h>
10fbfa2cc5SJaegeuk Kim #include <linux/stat.h>
11fbfa2cc5SJaegeuk Kim #include <linux/buffer_head.h>
12fbfa2cc5SJaegeuk Kim #include <linux/writeback.h>
13ae51fb31SJaegeuk Kim #include <linux/blkdev.h>
14fbfa2cc5SJaegeuk Kim #include <linux/falloc.h>
15fbfa2cc5SJaegeuk Kim #include <linux/types.h>
16e9750824SNamjae Jeon #include <linux/compat.h>
17fbfa2cc5SJaegeuk Kim #include <linux/uaccess.h>
18fbfa2cc5SJaegeuk Kim #include <linux/mount.h>
197f7670feSJaegeuk Kim #include <linux/pagevec.h>
20dc91de78SJaegeuk Kim #include <linux/uio.h>
218da4b8c4SAndy Shevchenko #include <linux/uuid.h>
224dd6f977SJaegeuk Kim #include <linux/file.h>
234507847cSChao Yu #include <linux/nls.h>
249af84648SDaeho Jeong #include <linux/sched/signal.h>
259b1bb01cSMiklos Szeredi #include <linux/fileattr.h>
260f6b56ecSDaeho Jeong #include <linux/fadvise.h>
27a1e09b03SEric Biggers #include <linux/iomap.h>
28fbfa2cc5SJaegeuk Kim 
29fbfa2cc5SJaegeuk Kim #include "f2fs.h"
30fbfa2cc5SJaegeuk Kim #include "node.h"
31fbfa2cc5SJaegeuk Kim #include "segment.h"
32fbfa2cc5SJaegeuk Kim #include "xattr.h"
33fbfa2cc5SJaegeuk Kim #include "acl.h"
34c1c1b583SChao Yu #include "gc.h"
3552118743SDaeho Jeong #include "iostat.h"
36a2a4a7e4SNamjae Jeon #include <trace/events/f2fs.h>
37fa4320ceSChao Yu #include <uapi/linux/f2fs.h>
38fbfa2cc5SJaegeuk Kim 
f2fs_filemap_fault(struct vm_fault * vmf)39ea4d479bSSouptick Joarder static vm_fault_t f2fs_filemap_fault(struct vm_fault *vmf)
405a3a2d83SQiuyang Sun {
415a3a2d83SQiuyang Sun 	struct inode *inode = file_inode(vmf->vma->vm_file);
42ea4d479bSSouptick Joarder 	vm_fault_t ret;
435a3a2d83SQiuyang Sun 
44ea4d479bSSouptick Joarder 	ret = filemap_fault(vmf);
457bf0cba7SChao Yu 	if (ret & VM_FAULT_LOCKED)
4634a23525SChao Yu 		f2fs_update_iostat(F2FS_I_SB(inode), inode,
4734a23525SChao Yu 					APP_MAPPED_READ_IO, F2FS_BLKSIZE);
488b83ac81SChao Yu 
49d7648343SChao Yu 	trace_f2fs_filemap_fault(inode, vmf->pgoff, (unsigned long)ret);
50d7648343SChao Yu 
51ea4d479bSSouptick Joarder 	return ret;
525a3a2d83SQiuyang Sun }
535a3a2d83SQiuyang Sun 
f2fs_vm_page_mkwrite(struct vm_fault * vmf)54ea4d479bSSouptick Joarder static vm_fault_t f2fs_vm_page_mkwrite(struct vm_fault *vmf)
55fbfa2cc5SJaegeuk Kim {
56fbfa2cc5SJaegeuk Kim 	struct page *page = vmf->page;
5711bac800SDave Jiang 	struct inode *inode = file_inode(vmf->vma->vm_file);
584081363fSJaegeuk Kim 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
59bdf03299SJaegeuk Kim 	struct dnode_of_data dn;
604c8ff709SChao Yu 	bool need_alloc = true;
614c8ff709SChao Yu 	int err = 0;
62fbfa2cc5SJaegeuk Kim 
63e0fcd015SChao Yu 	if (unlikely(IS_IMMUTABLE(inode)))
64e0fcd015SChao Yu 		return VM_FAULT_SIGBUS;
65e0fcd015SChao Yu 
66c6140415SJaegeuk Kim 	if (is_inode_flag_set(inode, FI_COMPRESS_RELEASED))
67c6140415SJaegeuk Kim 		return VM_FAULT_SIGBUS;
68c6140415SJaegeuk Kim 
691f227a3eSJaegeuk Kim 	if (unlikely(f2fs_cp_error(sbi))) {
701f227a3eSJaegeuk Kim 		err = -EIO;
711f227a3eSJaegeuk Kim 		goto err;
721f227a3eSJaegeuk Kim 	}
731f227a3eSJaegeuk Kim 
7400e09c0bSChao Yu 	if (!f2fs_is_checkpoint_ready(sbi)) {
7500e09c0bSChao Yu 		err = -ENOSPC;
76955ebcd3SChao Yu 		goto err;
7700e09c0bSChao Yu 	}
78fbfa2cc5SJaegeuk Kim 
79c8e43d55SChao Yu 	err = f2fs_convert_inline_inode(inode);
80c8e43d55SChao Yu 	if (err)
81c8e43d55SChao Yu 		goto err;
82c8e43d55SChao Yu 
834c8ff709SChao Yu #ifdef CONFIG_F2FS_FS_COMPRESSION
844c8ff709SChao Yu 	if (f2fs_compressed_file(inode)) {
854c8ff709SChao Yu 		int ret = f2fs_is_compressed_cluster(inode, page->index);
864c8ff709SChao Yu 
874c8ff709SChao Yu 		if (ret < 0) {
884c8ff709SChao Yu 			err = ret;
894c8ff709SChao Yu 			goto err;
904c8ff709SChao Yu 		} else if (ret) {
914c8ff709SChao Yu 			need_alloc = false;
924c8ff709SChao Yu 		}
934c8ff709SChao Yu 	}
944c8ff709SChao Yu #endif
95bdf03299SJaegeuk Kim 	/* should do out of any locked page */
964c8ff709SChao Yu 	if (need_alloc)
97bdf03299SJaegeuk Kim 		f2fs_balance_fs(sbi, true);
98bdf03299SJaegeuk Kim 
99fbfa2cc5SJaegeuk Kim 	sb_start_pagefault(inode->i_sb);
100b3d208f9SJaegeuk Kim 
101b3d208f9SJaegeuk Kim 	f2fs_bug_on(sbi, f2fs_has_inline_data(inode));
102b067ba1fSJaegeuk Kim 
10311bac800SDave Jiang 	file_update_time(vmf->vma->vm_file);
104edc6d01bSJan Kara 	filemap_invalidate_lock_shared(inode->i_mapping);
105fbfa2cc5SJaegeuk Kim 	lock_page(page);
1066bacf52fSJaegeuk Kim 	if (unlikely(page->mapping != inode->i_mapping ||
1079851e6e1SNamjae Jeon 			page_offset(page) > i_size_read(inode) ||
1086bacf52fSJaegeuk Kim 			!PageUptodate(page))) {
109fbfa2cc5SJaegeuk Kim 		unlock_page(page);
110fbfa2cc5SJaegeuk Kim 		err = -EFAULT;
1115a3a2d83SQiuyang Sun 		goto out_sem;
112fbfa2cc5SJaegeuk Kim 	}
113fbfa2cc5SJaegeuk Kim 
1144c8ff709SChao Yu 	if (need_alloc) {
11539a86958SChao Yu 		/* block allocation */
11639a86958SChao Yu 		set_new_dnode(&dn, inode, NULL, NULL, 0);
117cf342d3bSChristoph Hellwig 		err = f2fs_get_block_locked(&dn, page->index);
11806c7540fSChao Yu 	}
11906c7540fSChao Yu 
12006c7540fSChao Yu #ifdef CONFIG_F2FS_FS_COMPRESSION
12106c7540fSChao Yu 	if (!need_alloc) {
12206c7540fSChao Yu 		set_new_dnode(&dn, inode, NULL, NULL, 0);
12306c7540fSChao Yu 		err = f2fs_get_dnode_of_data(&dn, page->index, LOOKUP_NODE);
12406c7540fSChao Yu 		f2fs_put_dnode(&dn);
12506c7540fSChao Yu 	}
12606c7540fSChao Yu #endif
12739a86958SChao Yu 	if (err) {
12839a86958SChao Yu 		unlock_page(page);
12939a86958SChao Yu 		goto out_sem;
13039a86958SChao Yu 	}
13139a86958SChao Yu 
132bae0ee7aSChao Yu 	f2fs_wait_on_page_writeback(page, DATA, false, true);
13339a86958SChao Yu 
13439a86958SChao Yu 	/* wait for GCed page writeback via META_MAPPING */
13539a86958SChao Yu 	f2fs_wait_on_block_writeback(inode, dn.data_blkaddr);
13639a86958SChao Yu 
137fbfa2cc5SJaegeuk Kim 	/*
138fbfa2cc5SJaegeuk Kim 	 * check to see if the page is mapped already (no holes)
139fbfa2cc5SJaegeuk Kim 	 */
140fbfa2cc5SJaegeuk Kim 	if (PageMappedToDisk(page))
14139a86958SChao Yu 		goto out_sem;
142fbfa2cc5SJaegeuk Kim 
143fbfa2cc5SJaegeuk Kim 	/* page is wholly or partially inside EOF */
14409cbfeafSKirill A. Shutemov 	if (((loff_t)(page->index + 1) << PAGE_SHIFT) >
1459edcdabfSChao Yu 						i_size_read(inode)) {
146193bea1dSyoungjun yoo 		loff_t offset;
147f11e98bdSyoungjun yoo 
14809cbfeafSKirill A. Shutemov 		offset = i_size_read(inode) & ~PAGE_MASK;
14909cbfeafSKirill A. Shutemov 		zero_user_segment(page, offset, PAGE_SIZE);
150fbfa2cc5SJaegeuk Kim 	}
151fbfa2cc5SJaegeuk Kim 	set_page_dirty(page);
152fbfa2cc5SJaegeuk Kim 
15334a23525SChao Yu 	f2fs_update_iostat(sbi, inode, APP_MAPPED_IO, F2FS_BLKSIZE);
154c75f2febSSahitya Tummala 	f2fs_update_time(sbi, REQ_TIME);
155b0af6d49SChao Yu 
156e943a10dSJaegeuk Kim 	trace_f2fs_vm_page_mkwrite(page, DATA);
1575a3a2d83SQiuyang Sun out_sem:
158edc6d01bSJan Kara 	filemap_invalidate_unlock_shared(inode->i_mapping);
15939a86958SChao Yu 
160fbfa2cc5SJaegeuk Kim 	sb_end_pagefault(inode->i_sb);
1611f227a3eSJaegeuk Kim err:
1622ba39cc4SChristoph Hellwig 	return vmf_fs_error(err);
163fbfa2cc5SJaegeuk Kim }
164fbfa2cc5SJaegeuk Kim 
165fbfa2cc5SJaegeuk Kim static const struct vm_operations_struct f2fs_file_vm_ops = {
1665a3a2d83SQiuyang Sun 	.fault		= f2fs_filemap_fault,
167f1820361SKirill A. Shutemov 	.map_pages	= filemap_map_pages,
168fbfa2cc5SJaegeuk Kim 	.page_mkwrite	= f2fs_vm_page_mkwrite,
169fbfa2cc5SJaegeuk Kim };
170fbfa2cc5SJaegeuk Kim 
get_parent_ino(struct inode * inode,nid_t * pino)171354a3399SJaegeuk Kim static int get_parent_ino(struct inode *inode, nid_t *pino)
172354a3399SJaegeuk Kim {
173354a3399SJaegeuk Kim 	struct dentry *dentry;
174354a3399SJaegeuk Kim 
17584c9c2deSEric Biggers 	/*
17684c9c2deSEric Biggers 	 * Make sure to get the non-deleted alias.  The alias associated with
17784c9c2deSEric Biggers 	 * the open file descriptor being fsync()'ed may be deleted already.
17884c9c2deSEric Biggers 	 */
17984c9c2deSEric Biggers 	dentry = d_find_alias(inode);
180354a3399SJaegeuk Kim 	if (!dentry)
181354a3399SJaegeuk Kim 		return 0;
182354a3399SJaegeuk Kim 
183f0947e5cSJaegeuk Kim 	*pino = parent_ino(dentry);
184f0947e5cSJaegeuk Kim 	dput(dentry);
185354a3399SJaegeuk Kim 	return 1;
186354a3399SJaegeuk Kim }
187354a3399SJaegeuk Kim 
need_do_checkpoint(struct inode * inode)188a5fd5050SChao Yu static inline enum cp_reason_type need_do_checkpoint(struct inode *inode)
1899d1589efSChao Yu {
1904081363fSJaegeuk Kim 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
191a5fd5050SChao Yu 	enum cp_reason_type cp_reason = CP_NO_NEEDED;
1929d1589efSChao Yu 
193a5fd5050SChao Yu 	if (!S_ISREG(inode->i_mode))
194a5fd5050SChao Yu 		cp_reason = CP_NON_REGULAR;
1954c8ff709SChao Yu 	else if (f2fs_compressed_file(inode))
1964c8ff709SChao Yu 		cp_reason = CP_COMPRESSED;
197a5fd5050SChao Yu 	else if (inode->i_nlink != 1)
198a5fd5050SChao Yu 		cp_reason = CP_HARDLINK;
199bbf156f7SJaegeuk Kim 	else if (is_sbi_flag_set(sbi, SBI_NEED_CP))
200a5fd5050SChao Yu 		cp_reason = CP_SB_NEED_CP;
2019d1589efSChao Yu 	else if (file_wrong_pino(inode))
202a5fd5050SChao Yu 		cp_reason = CP_WRONG_PINO;
2034d57b86dSChao Yu 	else if (!f2fs_space_for_roll_forward(sbi))
204a5fd5050SChao Yu 		cp_reason = CP_NO_SPC_ROLL;
2054d57b86dSChao Yu 	else if (!f2fs_is_checkpointed_node(sbi, F2FS_I(inode)->i_pino))
206a5fd5050SChao Yu 		cp_reason = CP_NODE_NEED_CP;
207d5053a34SJaegeuk Kim 	else if (test_opt(sbi, FASTBOOT))
208a5fd5050SChao Yu 		cp_reason = CP_FASTBOOT_MODE;
20963189b78SChao Yu 	else if (F2FS_OPTION(sbi).active_logs == 2)
210a5fd5050SChao Yu 		cp_reason = CP_SPEC_LOG_NUM;
21163189b78SChao Yu 	else if (F2FS_OPTION(sbi).fsync_mode == FSYNC_MODE_STRICT &&
2124d57b86dSChao Yu 		f2fs_need_dentry_mark(sbi, inode->i_ino) &&
2134d57b86dSChao Yu 		f2fs_exist_written_data(sbi, F2FS_I(inode)->i_pino,
2144d57b86dSChao Yu 							TRANS_DIR_INO))
2150a007b97SJaegeuk Kim 		cp_reason = CP_RECOVER_DIR;
2166c59f87eSChao Yu 	else if (f2fs_exist_written_data(sbi, F2FS_I(inode)->i_pino,
2176c59f87eSChao Yu 							XATTR_DIR_INO))
2186c59f87eSChao Yu 		cp_reason = CP_XATTR_DIR;
2199d1589efSChao Yu 
220a5fd5050SChao Yu 	return cp_reason;
2219d1589efSChao Yu }
2229d1589efSChao Yu 
need_inode_page_update(struct f2fs_sb_info * sbi,nid_t ino)2239c7bb702SChangman Lee static bool need_inode_page_update(struct f2fs_sb_info *sbi, nid_t ino)
2249c7bb702SChangman Lee {
2259c7bb702SChangman Lee 	struct page *i = find_get_page(NODE_MAPPING(sbi), ino);
2269c7bb702SChangman Lee 	bool ret = false;
2279c7bb702SChangman Lee 	/* But we need to avoid that there are some inode updates */
2284d57b86dSChao Yu 	if ((i && PageDirty(i)) || f2fs_need_inode_block_update(sbi, ino))
2299c7bb702SChangman Lee 		ret = true;
2309c7bb702SChangman Lee 	f2fs_put_page(i, 0);
2319c7bb702SChangman Lee 	return ret;
2329c7bb702SChangman Lee }
2339c7bb702SChangman Lee 
try_to_fix_pino(struct inode * inode)23451455b19SChangman Lee static void try_to_fix_pino(struct inode *inode)
23551455b19SChangman Lee {
23651455b19SChangman Lee 	struct f2fs_inode_info *fi = F2FS_I(inode);
23751455b19SChangman Lee 	nid_t pino;
23851455b19SChangman Lee 
239e4544b63STim Murray 	f2fs_down_write(&fi->i_sem);
24051455b19SChangman Lee 	if (file_wrong_pino(inode) && inode->i_nlink == 1 &&
24151455b19SChangman Lee 			get_parent_ino(inode, &pino)) {
242205b9822SJaegeuk Kim 		f2fs_i_pino_write(inode, pino);
24351455b19SChangman Lee 		file_got_pino(inode);
24451455b19SChangman Lee 	}
245e4544b63STim Murray 	f2fs_up_write(&fi->i_sem);
24651455b19SChangman Lee }
24751455b19SChangman Lee 
f2fs_do_sync_file(struct file * file,loff_t start,loff_t end,int datasync,bool atomic)248608514deSJaegeuk Kim static int f2fs_do_sync_file(struct file *file, loff_t start, loff_t end,
249608514deSJaegeuk Kim 						int datasync, bool atomic)
250fbfa2cc5SJaegeuk Kim {
251fbfa2cc5SJaegeuk Kim 	struct inode *inode = file->f_mapping->host;
2524081363fSJaegeuk Kim 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
2532403c155SJaegeuk Kim 	nid_t ino = inode->i_ino;
254fbfa2cc5SJaegeuk Kim 	int ret = 0;
255a5fd5050SChao Yu 	enum cp_reason_type cp_reason = 0;
256fbfa2cc5SJaegeuk Kim 	struct writeback_control wbc = {
257c81bf1c8SJaegeuk Kim 		.sync_mode = WB_SYNC_ALL,
258fbfa2cc5SJaegeuk Kim 		.nr_to_write = LONG_MAX,
259fbfa2cc5SJaegeuk Kim 		.for_reclaim = 0,
260fbfa2cc5SJaegeuk Kim 	};
26150fa53ecSChao Yu 	unsigned int seq_id = 0;
262fbfa2cc5SJaegeuk Kim 
263dddd3d65SJaegeuk Kim 	if (unlikely(f2fs_readonly(inode->i_sb)))
2641fa95b0bSNamjae Jeon 		return 0;
2651fa95b0bSNamjae Jeon 
266a2a4a7e4SNamjae Jeon 	trace_f2fs_sync_file_enter(inode);
267ea1aa12cSJaegeuk Kim 
268b61ac5b7SYunlei He 	if (S_ISDIR(inode->i_mode))
269b61ac5b7SYunlei He 		goto go_write;
270b61ac5b7SYunlei He 
271ea1aa12cSJaegeuk Kim 	/* if fdatasync is triggered, let's do in-place-update */
272c46a155bSJaegeuk Kim 	if (datasync || get_dirty_pages(inode) <= SM_I(sbi)->min_fsync_blocks)
27391942321SJaegeuk Kim 		set_inode_flag(inode, FI_NEED_IPU);
2743b49c9a1SJeff Layton 	ret = file_write_and_wait_range(file, start, end);
27591942321SJaegeuk Kim 	clear_inode_flag(inode, FI_NEED_IPU);
276c1ce1b02SJaegeuk Kim 
277dddd3d65SJaegeuk Kim 	if (ret || is_sbi_flag_set(sbi, SBI_CP_DISABLED)) {
278a5fd5050SChao Yu 		trace_f2fs_sync_file_exit(inode, cp_reason, datasync, ret);
279fbfa2cc5SJaegeuk Kim 		return ret;
280a2a4a7e4SNamjae Jeon 	}
281fbfa2cc5SJaegeuk Kim 
2829c7bb702SChangman Lee 	/* if the inode is dirty, let's recover all the time */
283281518c6SChao Yu 	if (!f2fs_skip_inode_update(inode, datasync)) {
2842286c020SJaegeuk Kim 		f2fs_write_inode(inode, NULL);
2859c7bb702SChangman Lee 		goto go_write;
2869c7bb702SChangman Lee 	}
2879c7bb702SChangman Lee 
2886d99ba41SJaegeuk Kim 	/*
2896d99ba41SJaegeuk Kim 	 * if there is no written data, don't waste time to write recovery info.
2906d99ba41SJaegeuk Kim 	 */
29191942321SJaegeuk Kim 	if (!is_inode_flag_set(inode, FI_APPEND_WRITE) &&
2924d57b86dSChao Yu 			!f2fs_exist_written_data(sbi, ino, APPEND_INO)) {
29319c9c466SJaegeuk Kim 
2949c7bb702SChangman Lee 		/* it may call write_inode just prior to fsync */
2959c7bb702SChangman Lee 		if (need_inode_page_update(sbi, ino))
29619c9c466SJaegeuk Kim 			goto go_write;
29719c9c466SJaegeuk Kim 
29891942321SJaegeuk Kim 		if (is_inode_flag_set(inode, FI_UPDATE_WRITE) ||
2994d57b86dSChao Yu 				f2fs_exist_written_data(sbi, ino, UPDATE_INO))
3006d99ba41SJaegeuk Kim 			goto flush_out;
3016d99ba41SJaegeuk Kim 		goto out;
30227879915SChao Yu 	} else {
30327879915SChao Yu 		/*
30427879915SChao Yu 		 * for OPU case, during fsync(), node can be persisted before
30527879915SChao Yu 		 * data when lower device doesn't support write barrier, result
30627879915SChao Yu 		 * in data corruption after SPO.
307146949deSJinyoung CHOI 		 * So for strict fsync mode, force to use atomic write semantics
30827879915SChao Yu 		 * to keep write order in between data/node and last node to
30927879915SChao Yu 		 * avoid potential data corruption.
31027879915SChao Yu 		 */
31127879915SChao Yu 		if (F2FS_OPTION(sbi).fsync_mode ==
31227879915SChao Yu 				FSYNC_MODE_STRICT && !atomic)
31327879915SChao Yu 			atomic = true;
3146d99ba41SJaegeuk Kim 	}
31519c9c466SJaegeuk Kim go_write:
316e5d2385eSJaegeuk Kim 	/*
317e5d2385eSJaegeuk Kim 	 * Both of fdatasync() and fsync() are able to be recovered from
318e5d2385eSJaegeuk Kim 	 * sudden-power-off.
319e5d2385eSJaegeuk Kim 	 */
320e4544b63STim Murray 	f2fs_down_read(&F2FS_I(inode)->i_sem);
321a5fd5050SChao Yu 	cp_reason = need_do_checkpoint(inode);
322e4544b63STim Murray 	f2fs_up_read(&F2FS_I(inode)->i_sem);
323d928bfbfSJaegeuk Kim 
324a5fd5050SChao Yu 	if (cp_reason) {
325fbfa2cc5SJaegeuk Kim 		/* all the dirty node pages should be flushed for POR */
326fbfa2cc5SJaegeuk Kim 		ret = f2fs_sync_fs(inode->i_sb, 1);
327d928bfbfSJaegeuk Kim 
32851455b19SChangman Lee 		/*
32951455b19SChangman Lee 		 * We've secured consistency through sync_fs. Following pino
33051455b19SChangman Lee 		 * will be used only for fsynced inodes after checkpoint.
33151455b19SChangman Lee 		 */
33251455b19SChangman Lee 		try_to_fix_pino(inode);
33391942321SJaegeuk Kim 		clear_inode_flag(inode, FI_APPEND_WRITE);
33491942321SJaegeuk Kim 		clear_inode_flag(inode, FI_UPDATE_WRITE);
335354a3399SJaegeuk Kim 		goto out;
336354a3399SJaegeuk Kim 	}
33788bd02c9SJaegeuk Kim sync_nodes:
338c29fd0c0SChao Yu 	atomic_inc(&sbi->wb_sync_req[NODE]);
33950fa53ecSChao Yu 	ret = f2fs_fsync_node_pages(sbi, inode, &wbc, atomic, &seq_id);
340c29fd0c0SChao Yu 	atomic_dec(&sbi->wb_sync_req[NODE]);
341c267ec15SJaegeuk Kim 	if (ret)
342c267ec15SJaegeuk Kim 		goto out;
34388bd02c9SJaegeuk Kim 
344871f599fSJaegeuk Kim 	/* if cp_error was enabled, we should avoid infinite loop */
3456d5a1495SChao Yu 	if (unlikely(f2fs_cp_error(sbi))) {
3466d5a1495SChao Yu 		ret = -EIO;
347871f599fSJaegeuk Kim 		goto out;
3486d5a1495SChao Yu 	}
349871f599fSJaegeuk Kim 
3504d57b86dSChao Yu 	if (f2fs_need_inode_block_update(sbi, ino)) {
3517c45729aSJaegeuk Kim 		f2fs_mark_inode_dirty_sync(inode, true);
35251455b19SChangman Lee 		f2fs_write_inode(inode, NULL);
35388bd02c9SJaegeuk Kim 		goto sync_nodes;
354398b1ac5SJaegeuk Kim 	}
35588bd02c9SJaegeuk Kim 
356b6a245ebSJaegeuk Kim 	/*
357b6a245ebSJaegeuk Kim 	 * If it's atomic_write, it's just fine to keep write ordering. So
358b6a245ebSJaegeuk Kim 	 * here we don't need to wait for node write completion, since we use
359b6a245ebSJaegeuk Kim 	 * node chain which serializes node blocks. If one of node writes are
360b6a245ebSJaegeuk Kim 	 * reordered, we can see simply broken chain, resulting in stopping
361b6a245ebSJaegeuk Kim 	 * roll-forward recovery. It means we'll recover all or none node blocks
362b6a245ebSJaegeuk Kim 	 * given fsync mark.
363b6a245ebSJaegeuk Kim 	 */
364b6a245ebSJaegeuk Kim 	if (!atomic) {
36550fa53ecSChao Yu 		ret = f2fs_wait_on_node_pages_writeback(sbi, seq_id);
366cfe58f9dSJaegeuk Kim 		if (ret)
367cfe58f9dSJaegeuk Kim 			goto out;
368b6a245ebSJaegeuk Kim 	}
3696d99ba41SJaegeuk Kim 
3706d99ba41SJaegeuk Kim 	/* once recovery info is written, don't need to tack this */
3714d57b86dSChao Yu 	f2fs_remove_ino_entry(sbi, ino, APPEND_INO);
37291942321SJaegeuk Kim 	clear_inode_flag(inode, FI_APPEND_WRITE);
3736d99ba41SJaegeuk Kim flush_out:
374c550e25bSJaegeuk Kim 	if ((!atomic && F2FS_OPTION(sbi).fsync_mode != FSYNC_MODE_NOBARRIER) ||
375c550e25bSJaegeuk Kim 	    (atomic && !test_opt(sbi, NOBARRIER) && f2fs_sb_has_blkzoned(sbi)))
37639d787beSChao Yu 		ret = f2fs_issue_flush(sbi, inode->i_ino);
3773f06252fSChao Yu 	if (!ret) {
3784d57b86dSChao Yu 		f2fs_remove_ino_entry(sbi, ino, UPDATE_INO);
37991942321SJaegeuk Kim 		clear_inode_flag(inode, FI_UPDATE_WRITE);
3804d57b86dSChao Yu 		f2fs_remove_ino_entry(sbi, ino, FLUSH_INO);
3813f06252fSChao Yu 	}
382d0239e1bSJaegeuk Kim 	f2fs_update_time(sbi, REQ_TIME);
383fbfa2cc5SJaegeuk Kim out:
384a5fd5050SChao Yu 	trace_f2fs_sync_file_exit(inode, cp_reason, datasync, ret);
385fbfa2cc5SJaegeuk Kim 	return ret;
386fbfa2cc5SJaegeuk Kim }
387fbfa2cc5SJaegeuk Kim 
f2fs_sync_file(struct file * file,loff_t start,loff_t end,int datasync)388608514deSJaegeuk Kim int f2fs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
389608514deSJaegeuk Kim {
3901f227a3eSJaegeuk Kim 	if (unlikely(f2fs_cp_error(F2FS_I_SB(file_inode(file)))))
3911f227a3eSJaegeuk Kim 		return -EIO;
392608514deSJaegeuk Kim 	return f2fs_do_sync_file(file, start, end, datasync, false);
393608514deSJaegeuk Kim }
394608514deSJaegeuk Kim 
__found_offset(struct address_space * mapping,block_t blkaddr,pgoff_t index,int whence)3954cb03fecSMatthew Wilcox (Oracle) static bool __found_offset(struct address_space *mapping, block_t blkaddr,
3964cb03fecSMatthew Wilcox (Oracle) 				pgoff_t index, int whence)
3977f7670feSJaegeuk Kim {
3987f7670feSJaegeuk Kim 	switch (whence) {
3997f7670feSJaegeuk Kim 	case SEEK_DATA:
4004cb03fecSMatthew Wilcox (Oracle) 		if (__is_valid_data_blkaddr(blkaddr))
4014cb03fecSMatthew Wilcox (Oracle) 			return true;
4024cb03fecSMatthew Wilcox (Oracle) 		if (blkaddr == NEW_ADDR &&
4034cb03fecSMatthew Wilcox (Oracle) 		    xa_get_mark(&mapping->i_pages, index, PAGECACHE_TAG_DIRTY))
4047f7670feSJaegeuk Kim 			return true;
4057f7670feSJaegeuk Kim 		break;
4067f7670feSJaegeuk Kim 	case SEEK_HOLE:
4077f7670feSJaegeuk Kim 		if (blkaddr == NULL_ADDR)
4087f7670feSJaegeuk Kim 			return true;
4097f7670feSJaegeuk Kim 		break;
4107f7670feSJaegeuk Kim 	}
4117f7670feSJaegeuk Kim 	return false;
4127f7670feSJaegeuk Kim }
4137f7670feSJaegeuk Kim 
f2fs_seek_block(struct file * file,loff_t offset,int whence)414267378d4SChao Yu static loff_t f2fs_seek_block(struct file *file, loff_t offset, int whence)
415267378d4SChao Yu {
416267378d4SChao Yu 	struct inode *inode = file->f_mapping->host;
417267378d4SChao Yu 	loff_t maxbytes = inode->i_sb->s_maxbytes;
418267378d4SChao Yu 	struct dnode_of_data dn;
4194cb03fecSMatthew Wilcox (Oracle) 	pgoff_t pgofs, end_offset;
4207f7670feSJaegeuk Kim 	loff_t data_ofs = offset;
4217f7670feSJaegeuk Kim 	loff_t isize;
422267378d4SChao Yu 	int err = 0;
423267378d4SChao Yu 
4245955102cSAl Viro 	inode_lock(inode);
425267378d4SChao Yu 
426267378d4SChao Yu 	isize = i_size_read(inode);
427267378d4SChao Yu 	if (offset >= isize)
428267378d4SChao Yu 		goto fail;
429267378d4SChao Yu 
430267378d4SChao Yu 	/* handle inline data case */
4317a6e59d7SChao Yu 	if (f2fs_has_inline_data(inode)) {
4327a6e59d7SChao Yu 		if (whence == SEEK_HOLE) {
433267378d4SChao Yu 			data_ofs = isize;
434267378d4SChao Yu 			goto found;
4357a6e59d7SChao Yu 		} else if (whence == SEEK_DATA) {
4367a6e59d7SChao Yu 			data_ofs = offset;
4377a6e59d7SChao Yu 			goto found;
4387a6e59d7SChao Yu 		}
439267378d4SChao Yu 	}
440267378d4SChao Yu 
44109cbfeafSKirill A. Shutemov 	pgofs = (pgoff_t)(offset >> PAGE_SHIFT);
442267378d4SChao Yu 
44309cbfeafSKirill A. Shutemov 	for (; data_ofs < isize; data_ofs = (loff_t)pgofs << PAGE_SHIFT) {
444267378d4SChao Yu 		set_new_dnode(&dn, inode, NULL, NULL, 0);
4454d57b86dSChao Yu 		err = f2fs_get_dnode_of_data(&dn, pgofs, LOOKUP_NODE);
446267378d4SChao Yu 		if (err && err != -ENOENT) {
447267378d4SChao Yu 			goto fail;
448267378d4SChao Yu 		} else if (err == -ENOENT) {
449e1c42045Sarter97 			/* direct node does not exists */
450267378d4SChao Yu 			if (whence == SEEK_DATA) {
4514d57b86dSChao Yu 				pgofs = f2fs_get_next_page_offset(&dn, pgofs);
452267378d4SChao Yu 				continue;
453267378d4SChao Yu 			} else {
454267378d4SChao Yu 				goto found;
455267378d4SChao Yu 			}
456267378d4SChao Yu 		}
457267378d4SChao Yu 
45881ca7350SChao Yu 		end_offset = ADDRS_PER_PAGE(dn.node_page, inode);
459267378d4SChao Yu 
460267378d4SChao Yu 		/* find data/hole in dnode block */
461267378d4SChao Yu 		for (; dn.ofs_in_node < end_offset;
462267378d4SChao Yu 				dn.ofs_in_node++, pgofs++,
46309cbfeafSKirill A. Shutemov 				data_ofs = (loff_t)pgofs << PAGE_SHIFT) {
464267378d4SChao Yu 			block_t blkaddr;
465f11e98bdSyoungjun yoo 
466a2ced1ceSChao Yu 			blkaddr = f2fs_data_blkaddr(&dn);
467267378d4SChao Yu 
468c9b60788SChao Yu 			if (__is_valid_data_blkaddr(blkaddr) &&
469c9b60788SChao Yu 				!f2fs_is_valid_blkaddr(F2FS_I_SB(inode),
47093770ab7SChao Yu 					blkaddr, DATA_GENERIC_ENHANCE)) {
471c9b60788SChao Yu 				f2fs_put_dnode(&dn);
472c9b60788SChao Yu 				goto fail;
473c9b60788SChao Yu 			}
474c9b60788SChao Yu 
4754cb03fecSMatthew Wilcox (Oracle) 			if (__found_offset(file->f_mapping, blkaddr,
476e1da7872SChao Yu 							pgofs, whence)) {
477267378d4SChao Yu 				f2fs_put_dnode(&dn);
478267378d4SChao Yu 				goto found;
479267378d4SChao Yu 			}
480267378d4SChao Yu 		}
481267378d4SChao Yu 		f2fs_put_dnode(&dn);
482267378d4SChao Yu 	}
483267378d4SChao Yu 
484267378d4SChao Yu 	if (whence == SEEK_DATA)
485267378d4SChao Yu 		goto fail;
486267378d4SChao Yu found:
487fe369bc8SJaegeuk Kim 	if (whence == SEEK_HOLE && data_ofs > isize)
488fe369bc8SJaegeuk Kim 		data_ofs = isize;
4895955102cSAl Viro 	inode_unlock(inode);
490267378d4SChao Yu 	return vfs_setpos(file, data_ofs, maxbytes);
491267378d4SChao Yu fail:
4925955102cSAl Viro 	inode_unlock(inode);
493267378d4SChao Yu 	return -ENXIO;
494267378d4SChao Yu }
495267378d4SChao Yu 
f2fs_llseek(struct file * file,loff_t offset,int whence)496267378d4SChao Yu static loff_t f2fs_llseek(struct file *file, loff_t offset, int whence)
497267378d4SChao Yu {
498267378d4SChao Yu 	struct inode *inode = file->f_mapping->host;
499267378d4SChao Yu 	loff_t maxbytes = inode->i_sb->s_maxbytes;
500267378d4SChao Yu 
5016d1451bfSChengguang Xu 	if (f2fs_compressed_file(inode))
5026d1451bfSChengguang Xu 		maxbytes = max_file_blocks(inode) << F2FS_BLKSIZE_BITS;
5036d1451bfSChengguang Xu 
504267378d4SChao Yu 	switch (whence) {
505267378d4SChao Yu 	case SEEK_SET:
506267378d4SChao Yu 	case SEEK_CUR:
507267378d4SChao Yu 	case SEEK_END:
508267378d4SChao Yu 		return generic_file_llseek_size(file, offset, whence,
509267378d4SChao Yu 						maxbytes, i_size_read(inode));
510267378d4SChao Yu 	case SEEK_DATA:
511267378d4SChao Yu 	case SEEK_HOLE:
5120b4c5afdSJaegeuk Kim 		if (offset < 0)
5130b4c5afdSJaegeuk Kim 			return -ENXIO;
514267378d4SChao Yu 		return f2fs_seek_block(file, offset, whence);
515267378d4SChao Yu 	}
516267378d4SChao Yu 
517267378d4SChao Yu 	return -EINVAL;
518267378d4SChao Yu }
519267378d4SChao Yu 
f2fs_file_mmap(struct file * file,struct vm_area_struct * vma)520fbfa2cc5SJaegeuk Kim static int f2fs_file_mmap(struct file *file, struct vm_area_struct *vma)
521fbfa2cc5SJaegeuk Kim {
522b3d208f9SJaegeuk Kim 	struct inode *inode = file_inode(file);
523b3d208f9SJaegeuk Kim 
5241f227a3eSJaegeuk Kim 	if (unlikely(f2fs_cp_error(F2FS_I_SB(inode))))
5251f227a3eSJaegeuk Kim 		return -EIO;
5261f227a3eSJaegeuk Kim 
5274c8ff709SChao Yu 	if (!f2fs_is_compress_backend_ready(inode))
5284c8ff709SChao Yu 		return -EOPNOTSUPP;
5294c8ff709SChao Yu 
530fbfa2cc5SJaegeuk Kim 	file_accessed(file);
531fbfa2cc5SJaegeuk Kim 	vma->vm_ops = &f2fs_file_vm_ops;
532b5ab3276SChao Yu 
533b5ab3276SChao Yu 	f2fs_down_read(&F2FS_I(inode)->i_sem);
5344c8ff709SChao Yu 	set_inode_flag(inode, FI_MMAP_FILE);
535b5ab3276SChao Yu 	f2fs_up_read(&F2FS_I(inode)->i_sem);
536b5ab3276SChao Yu 
537fbfa2cc5SJaegeuk Kim 	return 0;
538fbfa2cc5SJaegeuk Kim }
539fbfa2cc5SJaegeuk Kim 
finish_preallocate_blocks(struct inode * inode)540f44a25a8SChao Yu static int finish_preallocate_blocks(struct inode *inode)
541f44a25a8SChao Yu {
542f44a25a8SChao Yu 	int ret;
543f44a25a8SChao Yu 
544f44a25a8SChao Yu 	inode_lock(inode);
545f44a25a8SChao Yu 	if (is_inode_flag_set(inode, FI_OPENED_FILE)) {
546f44a25a8SChao Yu 		inode_unlock(inode);
547f44a25a8SChao Yu 		return 0;
548f44a25a8SChao Yu 	}
549f44a25a8SChao Yu 
550f44a25a8SChao Yu 	if (!file_should_truncate(inode)) {
551f44a25a8SChao Yu 		set_inode_flag(inode, FI_OPENED_FILE);
552f44a25a8SChao Yu 		inode_unlock(inode);
553f44a25a8SChao Yu 		return 0;
554f44a25a8SChao Yu 	}
555f44a25a8SChao Yu 
556f44a25a8SChao Yu 	f2fs_down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
557f44a25a8SChao Yu 	filemap_invalidate_lock(inode->i_mapping);
558f44a25a8SChao Yu 
559f44a25a8SChao Yu 	truncate_setsize(inode, i_size_read(inode));
560f44a25a8SChao Yu 	ret = f2fs_truncate(inode);
561f44a25a8SChao Yu 
562f44a25a8SChao Yu 	filemap_invalidate_unlock(inode->i_mapping);
563f44a25a8SChao Yu 	f2fs_up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
564f44a25a8SChao Yu 
565f44a25a8SChao Yu 	if (!ret)
566f44a25a8SChao Yu 		set_inode_flag(inode, FI_OPENED_FILE);
567f44a25a8SChao Yu 
568f44a25a8SChao Yu 	inode_unlock(inode);
569f44a25a8SChao Yu 	if (ret)
570f44a25a8SChao Yu 		return ret;
571f44a25a8SChao Yu 
572f44a25a8SChao Yu 	file_dont_truncate(inode);
573f44a25a8SChao Yu 	return 0;
574f44a25a8SChao Yu }
575f44a25a8SChao Yu 
f2fs_file_open(struct inode * inode,struct file * filp)576fcc85a4dSJaegeuk Kim static int f2fs_file_open(struct inode *inode, struct file *filp)
577fcc85a4dSJaegeuk Kim {
5782e168c82SEric Biggers 	int err = fscrypt_file_open(inode, filp);
579fcc85a4dSJaegeuk Kim 
5802e168c82SEric Biggers 	if (err)
5812e168c82SEric Biggers 		return err;
582b91050a8SHyunchul Lee 
5834c8ff709SChao Yu 	if (!f2fs_is_compress_backend_ready(inode))
5844c8ff709SChao Yu 		return -EOPNOTSUPP;
5854c8ff709SChao Yu 
58695ae251fSEric Biggers 	err = fsverity_file_open(inode, filp);
58795ae251fSEric Biggers 	if (err)
58895ae251fSEric Biggers 		return err;
58995ae251fSEric Biggers 
59038b57833SYangtao Li 	filp->f_mode |= FMODE_NOWAIT | FMODE_BUF_RASYNC;
59194c8431fSChristoph Hellwig 	filp->f_mode |= FMODE_CAN_ODIRECT;
592b91050a8SHyunchul Lee 
593f44a25a8SChao Yu 	err = dquot_file_open(inode, filp);
594f44a25a8SChao Yu 	if (err)
595f44a25a8SChao Yu 		return err;
596f44a25a8SChao Yu 
597f44a25a8SChao Yu 	return finish_preallocate_blocks(inode);
598fcc85a4dSJaegeuk Kim }
599fcc85a4dSJaegeuk Kim 
f2fs_truncate_data_blocks_range(struct dnode_of_data * dn,int count)6004d57b86dSChao Yu void f2fs_truncate_data_blocks_range(struct dnode_of_data *dn, int count)
601fbfa2cc5SJaegeuk Kim {
6024081363fSJaegeuk Kim 	struct f2fs_sb_info *sbi = F2FS_I_SB(dn->inode);
60319b2c30dSChao Yu 	int nr_free = 0, ofs = dn->ofs_in_node, len = count;
604fbfa2cc5SJaegeuk Kim 	__le32 *addr;
6054c8ff709SChao Yu 	bool compressed_cluster = false;
6064c8ff709SChao Yu 	int cluster_index = 0, valid_blocks = 0;
6074c8ff709SChao Yu 	int cluster_size = F2FS_I(dn->inode)->i_cluster_size;
608c2759ebaSDaeho Jeong 	bool released = !atomic_read(&F2FS_I(dn->inode)->i_compr_blocks);
6097a2af766SChao Yu 
610dcd6b38bSChao Yu 	addr = get_dnode_addr(dn->inode, dn->node_page) + ofs;
611fbfa2cc5SJaegeuk Kim 
612a5029a57SKeoseong Park 	/* Assumption: truncation starts with cluster */
6134c8ff709SChao Yu 	for (; count > 0; count--, addr++, dn->ofs_in_node++, cluster_index++) {
614fbfa2cc5SJaegeuk Kim 		block_t blkaddr = le32_to_cpu(*addr);
615f11e98bdSyoungjun yoo 
6164c8ff709SChao Yu 		if (f2fs_compressed_file(dn->inode) &&
6174c8ff709SChao Yu 					!(cluster_index & (cluster_size - 1))) {
6184c8ff709SChao Yu 			if (compressed_cluster)
6194c8ff709SChao Yu 				f2fs_i_compr_blocks_update(dn->inode,
6204c8ff709SChao Yu 							valid_blocks, false);
6214c8ff709SChao Yu 			compressed_cluster = (blkaddr == COMPRESS_ADDR);
6224c8ff709SChao Yu 			valid_blocks = 0;
6234c8ff709SChao Yu 		}
6244c8ff709SChao Yu 
625fbfa2cc5SJaegeuk Kim 		if (blkaddr == NULL_ADDR)
626fbfa2cc5SJaegeuk Kim 			continue;
627fbfa2cc5SJaegeuk Kim 
628eb6d30bcSChao Yu 		f2fs_set_data_blkaddr(dn, NULL_ADDR);
629c9b60788SChao Yu 
6304c8ff709SChao Yu 		if (__is_valid_data_blkaddr(blkaddr)) {
6314c8ff709SChao Yu 			if (!f2fs_is_valid_blkaddr(sbi, blkaddr,
63293770ab7SChao Yu 					DATA_GENERIC_ENHANCE))
633c9b60788SChao Yu 				continue;
6344c8ff709SChao Yu 			if (compressed_cluster)
6354c8ff709SChao Yu 				valid_blocks++;
6364c8ff709SChao Yu 		}
637c9b60788SChao Yu 
6384c8ff709SChao Yu 		f2fs_invalidate_blocks(sbi, blkaddr);
639ef8d563fSChao Yu 
640ef8d563fSChao Yu 		if (!released || blkaddr != COMPRESS_ADDR)
641fbfa2cc5SJaegeuk Kim 			nr_free++;
642fbfa2cc5SJaegeuk Kim 	}
64319b2c30dSChao Yu 
6444c8ff709SChao Yu 	if (compressed_cluster)
6454c8ff709SChao Yu 		f2fs_i_compr_blocks_update(dn->inode, valid_blocks, false);
6464c8ff709SChao Yu 
647fbfa2cc5SJaegeuk Kim 	if (nr_free) {
64819b2c30dSChao Yu 		pgoff_t fofs;
64919b2c30dSChao Yu 		/*
65019b2c30dSChao Yu 		 * once we invalidate valid blkaddr in range [ofs, ofs + count],
65119b2c30dSChao Yu 		 * we will invalidate all blkaddr in the whole range.
65219b2c30dSChao Yu 		 */
6534d57b86dSChao Yu 		fofs = f2fs_start_bidx_of_node(ofs_of_node(dn->node_page),
65481ca7350SChao Yu 							dn->inode) + ofs;
655e7547dacSJaegeuk Kim 		f2fs_update_read_extent_cache_range(dn, fofs, 0, len);
6568c0ed062SChao Yu 		f2fs_update_age_extent_cache_range(dn, fofs, len);
657d7cc950bSNamjae Jeon 		dec_valid_block_count(sbi, dn->inode, nr_free);
658fbfa2cc5SJaegeuk Kim 	}
659fbfa2cc5SJaegeuk Kim 	dn->ofs_in_node = ofs;
66051dd6249SNamjae Jeon 
661d0239e1bSJaegeuk Kim 	f2fs_update_time(sbi, REQ_TIME);
66251dd6249SNamjae Jeon 	trace_f2fs_truncate_data_blocks_range(dn->inode, dn->nid,
66351dd6249SNamjae Jeon 					 dn->ofs_in_node, nr_free);
664fbfa2cc5SJaegeuk Kim }
665fbfa2cc5SJaegeuk Kim 
truncate_partial_data_page(struct inode * inode,u64 from,bool cache_only)6660bfcfccaSChao Yu static int truncate_partial_data_page(struct inode *inode, u64 from,
66743f3eae1SJaegeuk Kim 								bool cache_only)
668fbfa2cc5SJaegeuk Kim {
669193bea1dSyoungjun yoo 	loff_t offset = from & (PAGE_SIZE - 1);
67009cbfeafSKirill A. Shutemov 	pgoff_t index = from >> PAGE_SHIFT;
67143f3eae1SJaegeuk Kim 	struct address_space *mapping = inode->i_mapping;
672fbfa2cc5SJaegeuk Kim 	struct page *page;
673fbfa2cc5SJaegeuk Kim 
67443f3eae1SJaegeuk Kim 	if (!offset && !cache_only)
675b3d208f9SJaegeuk Kim 		return 0;
676fbfa2cc5SJaegeuk Kim 
67743f3eae1SJaegeuk Kim 	if (cache_only) {
67834b5d5c2SJaegeuk Kim 		page = find_lock_page(mapping, index);
67943f3eae1SJaegeuk Kim 		if (page && PageUptodate(page))
68043f3eae1SJaegeuk Kim 			goto truncate_out;
68143f3eae1SJaegeuk Kim 		f2fs_put_page(page, 1);
68243f3eae1SJaegeuk Kim 		return 0;
68343f3eae1SJaegeuk Kim 	}
68443f3eae1SJaegeuk Kim 
6854d57b86dSChao Yu 	page = f2fs_get_lock_data_page(inode, index, true);
686fbfa2cc5SJaegeuk Kim 	if (IS_ERR(page))
687a78aaa2cSYunlei He 		return PTR_ERR(page) == -ENOENT ? 0 : PTR_ERR(page);
68843f3eae1SJaegeuk Kim truncate_out:
689bae0ee7aSChao Yu 	f2fs_wait_on_page_writeback(page, DATA, true, true);
69009cbfeafSKirill A. Shutemov 	zero_user(page, offset, PAGE_SIZE - offset);
691a9bcf9bcSJaegeuk Kim 
692a9bcf9bcSJaegeuk Kim 	/* An encrypted inode should have a key and truncate the last page. */
69362230e0dSChandan Rajendra 	f2fs_bug_on(F2FS_I_SB(inode), cache_only && IS_ENCRYPTED(inode));
694a9bcf9bcSJaegeuk Kim 	if (!cache_only)
695fbfa2cc5SJaegeuk Kim 		set_page_dirty(page);
696fbfa2cc5SJaegeuk Kim 	f2fs_put_page(page, 1);
697b3d208f9SJaegeuk Kim 	return 0;
698fbfa2cc5SJaegeuk Kim }
699fbfa2cc5SJaegeuk Kim 
f2fs_do_truncate_blocks(struct inode * inode,u64 from,bool lock)7003265d3dbSChao Yu int f2fs_do_truncate_blocks(struct inode *inode, u64 from, bool lock)
701fbfa2cc5SJaegeuk Kim {
7024081363fSJaegeuk Kim 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
703fbfa2cc5SJaegeuk Kim 	struct dnode_of_data dn;
704fbfa2cc5SJaegeuk Kim 	pgoff_t free_from;
7059ffe0fb5SHuajun Li 	int count = 0, err = 0;
706b3d208f9SJaegeuk Kim 	struct page *ipage;
7070bfcfccaSChao Yu 	bool truncate_page = false;
708fbfa2cc5SJaegeuk Kim 
70951dd6249SNamjae Jeon 	trace_f2fs_truncate_blocks_enter(inode, from);
71051dd6249SNamjae Jeon 
711df033cafSChao Yu 	free_from = (pgoff_t)F2FS_BLK_ALIGN(from);
712fbfa2cc5SJaegeuk Kim 
7136d1451bfSChengguang Xu 	if (free_from >= max_file_blocks(inode))
71409210c97SChao Yu 		goto free_partial;
71509210c97SChao Yu 
716764aa3e9SJaegeuk Kim 	if (lock)
717c42d28ceSChao Yu 		f2fs_lock_op(sbi);
7189ffe0fb5SHuajun Li 
7194d57b86dSChao Yu 	ipage = f2fs_get_node_page(sbi, inode->i_ino);
720b3d208f9SJaegeuk Kim 	if (IS_ERR(ipage)) {
721b3d208f9SJaegeuk Kim 		err = PTR_ERR(ipage);
722b3d208f9SJaegeuk Kim 		goto out;
723b3d208f9SJaegeuk Kim 	}
724b3d208f9SJaegeuk Kim 
725b3d208f9SJaegeuk Kim 	if (f2fs_has_inline_data(inode)) {
7264d57b86dSChao Yu 		f2fs_truncate_inline_inode(inode, ipage, from);
727b3d208f9SJaegeuk Kim 		f2fs_put_page(ipage, 1);
7280bfcfccaSChao Yu 		truncate_page = true;
729b3d208f9SJaegeuk Kim 		goto out;
730b3d208f9SJaegeuk Kim 	}
731b3d208f9SJaegeuk Kim 
732b3d208f9SJaegeuk Kim 	set_new_dnode(&dn, inode, ipage, NULL, 0);
7334d57b86dSChao Yu 	err = f2fs_get_dnode_of_data(&dn, free_from, LOOKUP_NODE_RA);
734fbfa2cc5SJaegeuk Kim 	if (err) {
735fbfa2cc5SJaegeuk Kim 		if (err == -ENOENT)
736fbfa2cc5SJaegeuk Kim 			goto free_next;
737b3d208f9SJaegeuk Kim 		goto out;
7381ce86bf6SJaegeuk Kim 	}
7391ce86bf6SJaegeuk Kim 
74081ca7350SChao Yu 	count = ADDRS_PER_PAGE(dn.node_page, inode);
741fbfa2cc5SJaegeuk Kim 
742fbfa2cc5SJaegeuk Kim 	count -= dn.ofs_in_node;
7439850cf4aSJaegeuk Kim 	f2fs_bug_on(sbi, count < 0);
74439936837SJaegeuk Kim 
745fbfa2cc5SJaegeuk Kim 	if (dn.ofs_in_node || IS_INODE(dn.node_page)) {
7464d57b86dSChao Yu 		f2fs_truncate_data_blocks_range(&dn, count);
747fbfa2cc5SJaegeuk Kim 		free_from += count;
748fbfa2cc5SJaegeuk Kim 	}
749fbfa2cc5SJaegeuk Kim 
750fbfa2cc5SJaegeuk Kim 	f2fs_put_dnode(&dn);
751fbfa2cc5SJaegeuk Kim free_next:
7524d57b86dSChao Yu 	err = f2fs_truncate_inode_blocks(inode, free_from);
753764d2c80SJaegeuk Kim out:
754764d2c80SJaegeuk Kim 	if (lock)
755c42d28ceSChao Yu 		f2fs_unlock_op(sbi);
75609210c97SChao Yu free_partial:
757b3d208f9SJaegeuk Kim 	/* lastly zero out the first data page */
758b3d208f9SJaegeuk Kim 	if (!err)
7590bfcfccaSChao Yu 		err = truncate_partial_data_page(inode, from, truncate_page);
760fbfa2cc5SJaegeuk Kim 
76151dd6249SNamjae Jeon 	trace_f2fs_truncate_blocks_exit(inode, err);
762fbfa2cc5SJaegeuk Kim 	return err;
763fbfa2cc5SJaegeuk Kim }
764fbfa2cc5SJaegeuk Kim 
f2fs_truncate_blocks(struct inode * inode,u64 from,bool lock)7654c8ff709SChao Yu int f2fs_truncate_blocks(struct inode *inode, u64 from, bool lock)
7664c8ff709SChao Yu {
7674c8ff709SChao Yu 	u64 free_from = from;
7683265d3dbSChao Yu 	int err;
7694c8ff709SChao Yu 
7703265d3dbSChao Yu #ifdef CONFIG_F2FS_FS_COMPRESSION
7714c8ff709SChao Yu 	/*
7724c8ff709SChao Yu 	 * for compressed file, only support cluster size
7734c8ff709SChao Yu 	 * aligned truncation.
7744c8ff709SChao Yu 	 */
7754fec3fc0SChao Yu 	if (f2fs_compressed_file(inode))
7764fec3fc0SChao Yu 		free_from = round_up(from,
7774fec3fc0SChao Yu 				F2FS_I(inode)->i_cluster_size << PAGE_SHIFT);
7783265d3dbSChao Yu #endif
7794c8ff709SChao Yu 
7803265d3dbSChao Yu 	err = f2fs_do_truncate_blocks(inode, free_from, lock);
7813265d3dbSChao Yu 	if (err)
7823265d3dbSChao Yu 		return err;
7833265d3dbSChao Yu 
7843265d3dbSChao Yu #ifdef CONFIG_F2FS_FS_COMPRESSION
7854a4fc043SFengnan Chang 	/*
7864a4fc043SFengnan Chang 	 * For compressed file, after release compress blocks, don't allow write
7874a4fc043SFengnan Chang 	 * direct, but we should allow write direct after truncate to zero.
7884a4fc043SFengnan Chang 	 */
7894a4fc043SFengnan Chang 	if (f2fs_compressed_file(inode) && !free_from
7904a4fc043SFengnan Chang 			&& is_inode_flag_set(inode, FI_COMPRESS_RELEASED))
7914a4fc043SFengnan Chang 		clear_inode_flag(inode, FI_COMPRESS_RELEASED);
7924a4fc043SFengnan Chang 
79317d7648dSChao Yu 	if (from != free_from) {
7943265d3dbSChao Yu 		err = f2fs_truncate_partial_cluster(inode, from, lock);
79517d7648dSChao Yu 		if (err)
79617d7648dSChao Yu 			return err;
79717d7648dSChao Yu 	}
7983265d3dbSChao Yu #endif
7993265d3dbSChao Yu 
80017d7648dSChao Yu 	return 0;
8014c8ff709SChao Yu }
8024c8ff709SChao Yu 
f2fs_truncate(struct inode * inode)8039a449e9cSJaegeuk Kim int f2fs_truncate(struct inode *inode)
804fbfa2cc5SJaegeuk Kim {
805b0154891SChao Yu 	int err;
806b0154891SChao Yu 
8071f227a3eSJaegeuk Kim 	if (unlikely(f2fs_cp_error(F2FS_I_SB(inode))))
8081f227a3eSJaegeuk Kim 		return -EIO;
8091f227a3eSJaegeuk Kim 
810fbfa2cc5SJaegeuk Kim 	if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
811fbfa2cc5SJaegeuk Kim 				S_ISLNK(inode->i_mode)))
812b0154891SChao Yu 		return 0;
813fbfa2cc5SJaegeuk Kim 
81451dd6249SNamjae Jeon 	trace_f2fs_truncate(inode);
81551dd6249SNamjae Jeon 
816c40e15a9SYangtao Li 	if (time_to_inject(F2FS_I_SB(inode), FAULT_TRUNCATE))
81714b44d23SJaegeuk Kim 		return -EIO;
8187fa750a1SArnd Bergmann 
81910a26878SChao Yu 	err = f2fs_dquot_initialize(inode);
82025fb04dbSYi Chen 	if (err)
82125fb04dbSYi Chen 		return err;
82225fb04dbSYi Chen 
82392dffd01SJaegeuk Kim 	/* we should check inline_data size */
824b9d777b8SJaegeuk Kim 	if (!f2fs_may_inline_data(inode)) {
825b0154891SChao Yu 		err = f2fs_convert_inline_inode(inode);
826b0154891SChao Yu 		if (err)
827b0154891SChao Yu 			return err;
82892dffd01SJaegeuk Kim 	}
82992dffd01SJaegeuk Kim 
830c42d28ceSChao Yu 	err = f2fs_truncate_blocks(inode, i_size_read(inode), true);
831b0154891SChao Yu 	if (err)
832b0154891SChao Yu 		return err;
833b0154891SChao Yu 
834c62ebd35SJeff Layton 	inode->i_mtime = inode_set_ctime_current(inode);
8357c45729aSJaegeuk Kim 	f2fs_mark_inode_dirty_sync(inode, false);
836b0154891SChao Yu 	return 0;
837fbfa2cc5SJaegeuk Kim }
838fbfa2cc5SJaegeuk Kim 
f2fs_force_buffered_io(struct inode * inode,int rw)839bd367329SEric Biggers static bool f2fs_force_buffered_io(struct inode *inode, int rw)
8402db0487fSEric Biggers {
8412db0487fSEric Biggers 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
8422db0487fSEric Biggers 
8432db0487fSEric Biggers 	if (!fscrypt_dio_supported(inode))
8442db0487fSEric Biggers 		return true;
8452db0487fSEric Biggers 	if (fsverity_active(inode))
8462db0487fSEric Biggers 		return true;
8472db0487fSEric Biggers 	if (f2fs_compressed_file(inode))
8482db0487fSEric Biggers 		return true;
84916784362SChao Yu 	/*
85016784362SChao Yu 	 * only force direct read to use buffered IO, for direct write,
85116784362SChao Yu 	 * it expects inline data conversion before committing IO.
85216784362SChao Yu 	 */
85316784362SChao Yu 	if (f2fs_has_inline_data(inode) && rw == READ)
8541789db62SChao Yu 		return true;
8552db0487fSEric Biggers 
8562db0487fSEric Biggers 	/* disallow direct IO if any of devices has unaligned blksize */
8572db0487fSEric Biggers 	if (f2fs_is_multi_device(sbi) && !sbi->aligned_blksize)
8582db0487fSEric Biggers 		return true;
8595d170fe4SLinus Torvalds 	/*
8605d170fe4SLinus Torvalds 	 * for blkzoned device, fallback direct IO to buffered IO, so
8615d170fe4SLinus Torvalds 	 * all IOs can be serialized by log-structured write.
8625d170fe4SLinus Torvalds 	 */
8635d170fe4SLinus Torvalds 	if (f2fs_sb_has_blkzoned(sbi) && (rw == WRITE))
8645d170fe4SLinus Torvalds 		return true;
865bd367329SEric Biggers 	if (is_sbi_flag_set(sbi, SBI_CP_DISABLED))
8662db0487fSEric Biggers 		return true;
8672db0487fSEric Biggers 
8682db0487fSEric Biggers 	return false;
8692db0487fSEric Biggers }
8702db0487fSEric Biggers 
f2fs_getattr(struct mnt_idmap * idmap,const struct path * path,struct kstat * stat,u32 request_mask,unsigned int query_flags)871b74d24f7SChristian Brauner int f2fs_getattr(struct mnt_idmap *idmap, const struct path *path,
872549c7297SChristian Brauner 		 struct kstat *stat, u32 request_mask, unsigned int query_flags)
873fbfa2cc5SJaegeuk Kim {
874a528d35eSDavid Howells 	struct inode *inode = d_inode(path->dentry);
8751c6d8ee4SChao Yu 	struct f2fs_inode_info *fi = F2FS_I(inode);
876d13732ccSJia Yang 	struct f2fs_inode *ri = NULL;
8771c6d8ee4SChao Yu 	unsigned int flags;
8781c6d8ee4SChao Yu 
8791c1d35dfSChao Yu 	if (f2fs_has_extra_attr(inode) &&
8807beb01f7SChao Yu 			f2fs_sb_has_inode_crtime(F2FS_I_SB(inode)) &&
8811c1d35dfSChao Yu 			F2FS_FITS_IN_INODE(ri, fi->i_extra_isize, i_crtime)) {
8821c1d35dfSChao Yu 		stat->result_mask |= STATX_BTIME;
8831c1d35dfSChao Yu 		stat->btime.tv_sec = fi->i_crtime.tv_sec;
8841c1d35dfSChao Yu 		stat->btime.tv_nsec = fi->i_crtime.tv_nsec;
8851c1d35dfSChao Yu 	}
8861c1d35dfSChao Yu 
887c8c02272SEric Biggers 	/*
888c8c02272SEric Biggers 	 * Return the DIO alignment restrictions if requested.  We only return
889c8c02272SEric Biggers 	 * this information when requested, since on encrypted files it might
890c8c02272SEric Biggers 	 * take a fair bit of work to get if the file wasn't opened recently.
891c8c02272SEric Biggers 	 *
892c8c02272SEric Biggers 	 * f2fs sometimes supports DIO reads but not DIO writes.  STATX_DIOALIGN
893c8c02272SEric Biggers 	 * cannot represent that, so in that case we report no DIO support.
894c8c02272SEric Biggers 	 */
895c8c02272SEric Biggers 	if ((request_mask & STATX_DIOALIGN) && S_ISREG(inode->i_mode)) {
896c8c02272SEric Biggers 		unsigned int bsize = i_blocksize(inode);
897c8c02272SEric Biggers 
898c8c02272SEric Biggers 		stat->result_mask |= STATX_DIOALIGN;
899c8c02272SEric Biggers 		if (!f2fs_force_buffered_io(inode, WRITE)) {
900c8c02272SEric Biggers 			stat->dio_mem_align = bsize;
901c8c02272SEric Biggers 			stat->dio_offset_align = bsize;
902c8c02272SEric Biggers 		}
903c8c02272SEric Biggers 	}
904c8c02272SEric Biggers 
90536098557SEric Biggers 	flags = fi->i_flags;
906fd26725fSChao Yu 	if (flags & F2FS_COMPR_FL)
907fd26725fSChao Yu 		stat->attributes |= STATX_ATTR_COMPRESSED;
90859c84408SChao Yu 	if (flags & F2FS_APPEND_FL)
9091c6d8ee4SChao Yu 		stat->attributes |= STATX_ATTR_APPEND;
91062230e0dSChandan Rajendra 	if (IS_ENCRYPTED(inode))
9111c6d8ee4SChao Yu 		stat->attributes |= STATX_ATTR_ENCRYPTED;
91259c84408SChao Yu 	if (flags & F2FS_IMMUTABLE_FL)
9131c6d8ee4SChao Yu 		stat->attributes |= STATX_ATTR_IMMUTABLE;
91459c84408SChao Yu 	if (flags & F2FS_NODUMP_FL)
9151c6d8ee4SChao Yu 		stat->attributes |= STATX_ATTR_NODUMP;
916924e3194SEric Biggers 	if (IS_VERITY(inode))
917924e3194SEric Biggers 		stat->attributes |= STATX_ATTR_VERITY;
9181c6d8ee4SChao Yu 
919fd26725fSChao Yu 	stat->attributes_mask |= (STATX_ATTR_COMPRESSED |
920fd26725fSChao Yu 				  STATX_ATTR_APPEND |
9211c6d8ee4SChao Yu 				  STATX_ATTR_ENCRYPTED |
9221c6d8ee4SChao Yu 				  STATX_ATTR_IMMUTABLE |
923924e3194SEric Biggers 				  STATX_ATTR_NODUMP |
924924e3194SEric Biggers 				  STATX_ATTR_VERITY);
9251c6d8ee4SChao Yu 
9260d72b928SJeff Layton 	generic_fillattr(idmap, request_mask, inode, stat);
9275b4267d1SJaegeuk Kim 
9285b4267d1SJaegeuk Kim 	/* we need to show initial sectors used for inline_data/dentries */
9295b4267d1SJaegeuk Kim 	if ((S_ISREG(inode->i_mode) && f2fs_has_inline_data(inode)) ||
9305b4267d1SJaegeuk Kim 					f2fs_has_inline_dentry(inode))
9315b4267d1SJaegeuk Kim 		stat->blocks += (stat->size + 511) >> 9;
9325b4267d1SJaegeuk Kim 
933fbfa2cc5SJaegeuk Kim 	return 0;
934fbfa2cc5SJaegeuk Kim }
935fbfa2cc5SJaegeuk Kim 
936fbfa2cc5SJaegeuk Kim #ifdef CONFIG_F2FS_FS_POSIX_ACL
__setattr_copy(struct mnt_idmap * idmap,struct inode * inode,const struct iattr * attr)937c1632a0fSChristian Brauner static void __setattr_copy(struct mnt_idmap *idmap,
938e65ce2a5SChristian Brauner 			   struct inode *inode, const struct iattr *attr)
939fbfa2cc5SJaegeuk Kim {
940fbfa2cc5SJaegeuk Kim 	unsigned int ia_valid = attr->ia_valid;
941fbfa2cc5SJaegeuk Kim 
9420dbe12f2SChristian Brauner 	i_uid_update(idmap, attr, inode);
9430dbe12f2SChristian Brauner 	i_gid_update(idmap, attr, inode);
944eb31e2f6SAmir Goldstein 	if (ia_valid & ATTR_ATIME)
945eb31e2f6SAmir Goldstein 		inode->i_atime = attr->ia_atime;
946eb31e2f6SAmir Goldstein 	if (ia_valid & ATTR_MTIME)
947eb31e2f6SAmir Goldstein 		inode->i_mtime = attr->ia_mtime;
948eb31e2f6SAmir Goldstein 	if (ia_valid & ATTR_CTIME)
949c62ebd35SJeff Layton 		inode_set_ctime_to_ts(inode, attr->ia_ctime);
950fbfa2cc5SJaegeuk Kim 	if (ia_valid & ATTR_MODE) {
951fbfa2cc5SJaegeuk Kim 		umode_t mode = attr->ia_mode;
952e67fe633SChristian Brauner 		vfsgid_t vfsgid = i_gid_into_vfsgid(idmap, inode);
953fbfa2cc5SJaegeuk Kim 
9541e8a9191SChristian Brauner 		if (!vfsgid_in_group_p(vfsgid) &&
9559452e93eSChristian Brauner 		    !capable_wrt_inode_uidgid(idmap, inode, CAP_FSETID))
956fbfa2cc5SJaegeuk Kim 			mode &= ~S_ISGID;
95791942321SJaegeuk Kim 		set_acl_inode(inode, mode);
958fbfa2cc5SJaegeuk Kim 	}
959fbfa2cc5SJaegeuk Kim }
960fbfa2cc5SJaegeuk Kim #else
961fbfa2cc5SJaegeuk Kim #define __setattr_copy setattr_copy
962fbfa2cc5SJaegeuk Kim #endif
963fbfa2cc5SJaegeuk Kim 
f2fs_setattr(struct mnt_idmap * idmap,struct dentry * dentry,struct iattr * attr)964c1632a0fSChristian Brauner int f2fs_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
965549c7297SChristian Brauner 		 struct iattr *attr)
966fbfa2cc5SJaegeuk Kim {
9672b0143b5SDavid Howells 	struct inode *inode = d_inode(dentry);
968fbfa2cc5SJaegeuk Kim 	int err;
969fbfa2cc5SJaegeuk Kim 
9701f227a3eSJaegeuk Kim 	if (unlikely(f2fs_cp_error(F2FS_I_SB(inode))))
9711f227a3eSJaegeuk Kim 		return -EIO;
9721f227a3eSJaegeuk Kim 
973e0fcd015SChao Yu 	if (unlikely(IS_IMMUTABLE(inode)))
974e0fcd015SChao Yu 		return -EPERM;
975e0fcd015SChao Yu 
976e0fcd015SChao Yu 	if (unlikely(IS_APPEND(inode) &&
977e0fcd015SChao Yu 			(attr->ia_valid & (ATTR_MODE | ATTR_UID |
978e0fcd015SChao Yu 				  ATTR_GID | ATTR_TIMES_SET))))
979e0fcd015SChao Yu 		return -EPERM;
980e0fcd015SChao Yu 
9819f934106SChao Yu 	if ((attr->ia_valid & ATTR_SIZE)) {
9829f934106SChao Yu 		if (!f2fs_is_compress_backend_ready(inode))
9834c8ff709SChao Yu 			return -EOPNOTSUPP;
9849f934106SChao Yu 		if (is_inode_flag_set(inode, FI_COMPRESS_RELEASED) &&
9859f934106SChao Yu 			!IS_ALIGNED(attr->ia_size,
9869f934106SChao Yu 			F2FS_BLK_TO_BYTES(F2FS_I(inode)->i_cluster_size)))
9879f934106SChao Yu 			return -EINVAL;
9889f934106SChao Yu 	}
9894c8ff709SChao Yu 
990c1632a0fSChristian Brauner 	err = setattr_prepare(idmap, dentry, attr);
991fbfa2cc5SJaegeuk Kim 	if (err)
992fbfa2cc5SJaegeuk Kim 		return err;
993fbfa2cc5SJaegeuk Kim 
99420bb2479SEric Biggers 	err = fscrypt_prepare_setattr(dentry, attr);
99520bb2479SEric Biggers 	if (err)
99620bb2479SEric Biggers 		return err;
99720bb2479SEric Biggers 
99895ae251fSEric Biggers 	err = fsverity_prepare_setattr(dentry, attr);
99995ae251fSEric Biggers 	if (err)
100095ae251fSEric Biggers 		return err;
100195ae251fSEric Biggers 
1002f861646aSChristian Brauner 	if (is_quota_modification(idmap, inode, attr)) {
100310a26878SChao Yu 		err = f2fs_dquot_initialize(inode);
10040abd675eSChao Yu 		if (err)
10050abd675eSChao Yu 			return err;
10060abd675eSChao Yu 	}
10070dbe12f2SChristian Brauner 	if (i_uid_needs_update(idmap, attr, inode) ||
10080dbe12f2SChristian Brauner 	    i_gid_needs_update(idmap, attr, inode)) {
1009af033b2aSChao Yu 		f2fs_lock_op(F2FS_I_SB(inode));
1010f861646aSChristian Brauner 		err = dquot_transfer(idmap, inode, attr);
1011af033b2aSChao Yu 		if (err) {
1012af033b2aSChao Yu 			set_sbi_flag(F2FS_I_SB(inode),
1013af033b2aSChao Yu 					SBI_QUOTA_NEED_REPAIR);
1014af033b2aSChao Yu 			f2fs_unlock_op(F2FS_I_SB(inode));
10150abd675eSChao Yu 			return err;
10160abd675eSChao Yu 		}
1017af033b2aSChao Yu 		/*
1018af033b2aSChao Yu 		 * update uid/gid under lock_op(), so that dquot and inode can
1019af033b2aSChao Yu 		 * be updated atomically.
1020af033b2aSChao Yu 		 */
10210dbe12f2SChristian Brauner 		i_uid_update(idmap, attr, inode);
10220dbe12f2SChristian Brauner 		i_gid_update(idmap, attr, inode);
1023af033b2aSChao Yu 		f2fs_mark_inode_dirty_sync(inode, true);
1024af033b2aSChao Yu 		f2fs_unlock_op(F2FS_I_SB(inode));
1025af033b2aSChao Yu 	}
10260abd675eSChao Yu 
102709db6a2eSChao Yu 	if (attr->ia_valid & ATTR_SIZE) {
1028cfb9a34dSJaegeuk Kim 		loff_t old_size = i_size_read(inode);
1029cfb9a34dSJaegeuk Kim 
1030cfb9a34dSJaegeuk Kim 		if (attr->ia_size > MAX_INLINE_DATA(inode)) {
1031cfb9a34dSJaegeuk Kim 			/*
1032cfb9a34dSJaegeuk Kim 			 * should convert inline inode before i_size_write to
1033cfb9a34dSJaegeuk Kim 			 * keep smaller than inline_data size with inline flag.
1034cfb9a34dSJaegeuk Kim 			 */
1035cfb9a34dSJaegeuk Kim 			err = f2fs_convert_inline_inode(inode);
1036cfb9a34dSJaegeuk Kim 			if (err)
1037cfb9a34dSJaegeuk Kim 				return err;
1038cfb9a34dSJaegeuk Kim 		}
1039a33c1502SChao Yu 
1040*c2a7fc51SChao Yu 		/*
1041*c2a7fc51SChao Yu 		 * wait for inflight dio, blocks should be removed after
1042*c2a7fc51SChao Yu 		 * IO completion.
1043*c2a7fc51SChao Yu 		 */
1044*c2a7fc51SChao Yu 		if (attr->ia_size < old_size)
1045*c2a7fc51SChao Yu 			inode_dio_wait(inode);
1046*c2a7fc51SChao Yu 
1047e4544b63STim Murray 		f2fs_down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
1048edc6d01bSJan Kara 		filemap_invalidate_lock(inode->i_mapping);
1049a33c1502SChao Yu 
1050fbfa2cc5SJaegeuk Kim 		truncate_setsize(inode, attr->ia_size);
1051a33c1502SChao Yu 
1052cfb9a34dSJaegeuk Kim 		if (attr->ia_size <= old_size)
10539a449e9cSJaegeuk Kim 			err = f2fs_truncate(inode);
105409db6a2eSChao Yu 		/*
10553c454145SChao Yu 		 * do not trim all blocks after i_size if target size is
10563c454145SChao Yu 		 * larger than i_size.
105709db6a2eSChao Yu 		 */
1058edc6d01bSJan Kara 		filemap_invalidate_unlock(inode->i_mapping);
1059e4544b63STim Murray 		f2fs_up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
1060a33c1502SChao Yu 		if (err)
1061a33c1502SChao Yu 			return err;
1062a33c1502SChao Yu 
1063c10c9820SChao Yu 		spin_lock(&F2FS_I(inode)->i_size_lock);
1064c62ebd35SJeff Layton 		inode->i_mtime = inode_set_ctime_current(inode);
1065a0d00fadSChao Yu 		F2FS_I(inode)->last_disk_size = i_size_read(inode);
1066c10c9820SChao Yu 		spin_unlock(&F2FS_I(inode)->i_size_lock);
1067fbfa2cc5SJaegeuk Kim 	}
1068fbfa2cc5SJaegeuk Kim 
1069c1632a0fSChristian Brauner 	__setattr_copy(idmap, inode, attr);
1070fbfa2cc5SJaegeuk Kim 
1071fbfa2cc5SJaegeuk Kim 	if (attr->ia_valid & ATTR_MODE) {
107213e83a49SChristian Brauner 		err = posix_acl_chmod(idmap, dentry, f2fs_get_inode_mode(inode));
107317232e83SChao Yu 
107417232e83SChao Yu 		if (is_inode_flag_set(inode, FI_ACL_MODE)) {
107517232e83SChao Yu 			if (!err)
107691942321SJaegeuk Kim 				inode->i_mode = F2FS_I(inode)->i_acl_mode;
107791942321SJaegeuk Kim 			clear_inode_flag(inode, FI_ACL_MODE);
1078fbfa2cc5SJaegeuk Kim 		}
1079fbfa2cc5SJaegeuk Kim 	}
1080fbfa2cc5SJaegeuk Kim 
1081c0ed4405SYunlei He 	/* file size may changed here */
1082ca597bddSChao Yu 	f2fs_mark_inode_dirty_sync(inode, true);
108315d04354SJaegeuk Kim 
108415d04354SJaegeuk Kim 	/* inode change will produce dirty node pages flushed by checkpoint */
108515d04354SJaegeuk Kim 	f2fs_balance_fs(F2FS_I_SB(inode), true);
108615d04354SJaegeuk Kim 
1087fbfa2cc5SJaegeuk Kim 	return err;
1088fbfa2cc5SJaegeuk Kim }
1089fbfa2cc5SJaegeuk Kim 
1090fbfa2cc5SJaegeuk Kim const struct inode_operations f2fs_file_inode_operations = {
1091fbfa2cc5SJaegeuk Kim 	.getattr	= f2fs_getattr,
1092fbfa2cc5SJaegeuk Kim 	.setattr	= f2fs_setattr,
1093cac2f8b8SChristian Brauner 	.get_inode_acl	= f2fs_get_acl,
1094a6dda0e6SChristoph Hellwig 	.set_acl	= f2fs_set_acl,
1095fbfa2cc5SJaegeuk Kim 	.listxattr	= f2fs_listxattr,
10969ab70134SJaegeuk Kim 	.fiemap		= f2fs_fiemap,
10979b1bb01cSMiklos Szeredi 	.fileattr_get	= f2fs_fileattr_get,
10989b1bb01cSMiklos Szeredi 	.fileattr_set	= f2fs_fileattr_set,
1099fbfa2cc5SJaegeuk Kim };
1100fbfa2cc5SJaegeuk Kim 
fill_zero(struct inode * inode,pgoff_t index,loff_t start,loff_t len)11016394328aSChao Yu static int fill_zero(struct inode *inode, pgoff_t index,
1102fbfa2cc5SJaegeuk Kim 					loff_t start, loff_t len)
1103fbfa2cc5SJaegeuk Kim {
11044081363fSJaegeuk Kim 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
1105fbfa2cc5SJaegeuk Kim 	struct page *page;
1106fbfa2cc5SJaegeuk Kim 
1107fbfa2cc5SJaegeuk Kim 	if (!len)
11086394328aSChao Yu 		return 0;
1109fbfa2cc5SJaegeuk Kim 
11102c4db1a6SJaegeuk Kim 	f2fs_balance_fs(sbi, true);
1111bd43df02SJaegeuk Kim 
1112e479556bSGu Zheng 	f2fs_lock_op(sbi);
11134d57b86dSChao Yu 	page = f2fs_get_new_data_page(inode, NULL, index, false);
1114e479556bSGu Zheng 	f2fs_unlock_op(sbi);
1115fbfa2cc5SJaegeuk Kim 
11166394328aSChao Yu 	if (IS_ERR(page))
11176394328aSChao Yu 		return PTR_ERR(page);
11186394328aSChao Yu 
1119bae0ee7aSChao Yu 	f2fs_wait_on_page_writeback(page, DATA, true, true);
1120fbfa2cc5SJaegeuk Kim 	zero_user(page, start, len);
1121fbfa2cc5SJaegeuk Kim 	set_page_dirty(page);
1122fbfa2cc5SJaegeuk Kim 	f2fs_put_page(page, 1);
11236394328aSChao Yu 	return 0;
1124fbfa2cc5SJaegeuk Kim }
1125fbfa2cc5SJaegeuk Kim 
f2fs_truncate_hole(struct inode * inode,pgoff_t pg_start,pgoff_t pg_end)11264d57b86dSChao Yu int f2fs_truncate_hole(struct inode *inode, pgoff_t pg_start, pgoff_t pg_end)
1127fbfa2cc5SJaegeuk Kim {
1128fbfa2cc5SJaegeuk Kim 	int err;
1129fbfa2cc5SJaegeuk Kim 
1130ea58711eSChao Yu 	while (pg_start < pg_end) {
1131fbfa2cc5SJaegeuk Kim 		struct dnode_of_data dn;
1132ea58711eSChao Yu 		pgoff_t end_offset, count;
1133fbfa2cc5SJaegeuk Kim 
1134fbfa2cc5SJaegeuk Kim 		set_new_dnode(&dn, inode, NULL, NULL, 0);
11354d57b86dSChao Yu 		err = f2fs_get_dnode_of_data(&dn, pg_start, LOOKUP_NODE);
1136fbfa2cc5SJaegeuk Kim 		if (err) {
1137ea58711eSChao Yu 			if (err == -ENOENT) {
11384d57b86dSChao Yu 				pg_start = f2fs_get_next_page_offset(&dn,
11394d57b86dSChao Yu 								pg_start);
1140fbfa2cc5SJaegeuk Kim 				continue;
1141ea58711eSChao Yu 			}
1142fbfa2cc5SJaegeuk Kim 			return err;
1143fbfa2cc5SJaegeuk Kim 		}
1144fbfa2cc5SJaegeuk Kim 
114581ca7350SChao Yu 		end_offset = ADDRS_PER_PAGE(dn.node_page, inode);
1146ea58711eSChao Yu 		count = min(end_offset - dn.ofs_in_node, pg_end - pg_start);
1147ea58711eSChao Yu 
1148ea58711eSChao Yu 		f2fs_bug_on(F2FS_I_SB(inode), count == 0 || count > end_offset);
1149ea58711eSChao Yu 
11504d57b86dSChao Yu 		f2fs_truncate_data_blocks_range(&dn, count);
1151fbfa2cc5SJaegeuk Kim 		f2fs_put_dnode(&dn);
1152ea58711eSChao Yu 
1153ea58711eSChao Yu 		pg_start += count;
1154fbfa2cc5SJaegeuk Kim 	}
1155fbfa2cc5SJaegeuk Kim 	return 0;
1156fbfa2cc5SJaegeuk Kim }
1157fbfa2cc5SJaegeuk Kim 
f2fs_punch_hole(struct inode * inode,loff_t offset,loff_t len)11581cd75654SYangtao Li static int f2fs_punch_hole(struct inode *inode, loff_t offset, loff_t len)
1159fbfa2cc5SJaegeuk Kim {
1160fbfa2cc5SJaegeuk Kim 	pgoff_t pg_start, pg_end;
1161fbfa2cc5SJaegeuk Kim 	loff_t off_start, off_end;
1162b9d777b8SJaegeuk Kim 	int ret;
1163fbfa2cc5SJaegeuk Kim 
1164b3d208f9SJaegeuk Kim 	ret = f2fs_convert_inline_inode(inode);
11659ffe0fb5SHuajun Li 	if (ret)
11669ffe0fb5SHuajun Li 		return ret;
11679ffe0fb5SHuajun Li 
116809cbfeafSKirill A. Shutemov 	pg_start = ((unsigned long long) offset) >> PAGE_SHIFT;
116909cbfeafSKirill A. Shutemov 	pg_end = ((unsigned long long) offset + len) >> PAGE_SHIFT;
1170fbfa2cc5SJaegeuk Kim 
117109cbfeafSKirill A. Shutemov 	off_start = offset & (PAGE_SIZE - 1);
117209cbfeafSKirill A. Shutemov 	off_end = (offset + len) & (PAGE_SIZE - 1);
1173fbfa2cc5SJaegeuk Kim 
1174fbfa2cc5SJaegeuk Kim 	if (pg_start == pg_end) {
11756394328aSChao Yu 		ret = fill_zero(inode, pg_start, off_start,
1176fbfa2cc5SJaegeuk Kim 						off_end - off_start);
11776394328aSChao Yu 		if (ret)
11786394328aSChao Yu 			return ret;
1179fbfa2cc5SJaegeuk Kim 	} else {
11806394328aSChao Yu 		if (off_start) {
11816394328aSChao Yu 			ret = fill_zero(inode, pg_start++, off_start,
118209cbfeafSKirill A. Shutemov 						PAGE_SIZE - off_start);
11836394328aSChao Yu 			if (ret)
11846394328aSChao Yu 				return ret;
11856394328aSChao Yu 		}
11866394328aSChao Yu 		if (off_end) {
11876394328aSChao Yu 			ret = fill_zero(inode, pg_end, 0, off_end);
11886394328aSChao Yu 			if (ret)
11896394328aSChao Yu 				return ret;
11906394328aSChao Yu 		}
1191fbfa2cc5SJaegeuk Kim 
1192fbfa2cc5SJaegeuk Kim 		if (pg_start < pg_end) {
1193fbfa2cc5SJaegeuk Kim 			loff_t blk_start, blk_end;
11944081363fSJaegeuk Kim 			struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
11951127a3d4SJason Hrycay 
11962c4db1a6SJaegeuk Kim 			f2fs_balance_fs(sbi, true);
1197fbfa2cc5SJaegeuk Kim 
119809cbfeafSKirill A. Shutemov 			blk_start = (loff_t)pg_start << PAGE_SHIFT;
119909cbfeafSKirill A. Shutemov 			blk_end = (loff_t)pg_end << PAGE_SHIFT;
1200a33c1502SChao Yu 
1201e4544b63STim Murray 			f2fs_down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
12026abaa83cSLinus Torvalds 			filemap_invalidate_lock(inode->i_mapping);
1203a33c1502SChao Yu 
1204c8dc3047SChao Yu 			truncate_pagecache_range(inode, blk_start, blk_end - 1);
120539936837SJaegeuk Kim 
1206e479556bSGu Zheng 			f2fs_lock_op(sbi);
12074d57b86dSChao Yu 			ret = f2fs_truncate_hole(inode, pg_start, pg_end);
1208e479556bSGu Zheng 			f2fs_unlock_op(sbi);
1209a33c1502SChao Yu 
12106abaa83cSLinus Torvalds 			filemap_invalidate_unlock(inode->i_mapping);
1211e4544b63STim Murray 			f2fs_up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
1212fbfa2cc5SJaegeuk Kim 		}
1213fbfa2cc5SJaegeuk Kim 	}
1214fbfa2cc5SJaegeuk Kim 
1215fbfa2cc5SJaegeuk Kim 	return ret;
1216fbfa2cc5SJaegeuk Kim }
1217fbfa2cc5SJaegeuk Kim 
__read_out_blkaddrs(struct inode * inode,block_t * blkaddr,int * do_replace,pgoff_t off,pgoff_t len)12180a2aa8fbSJaegeuk Kim static int __read_out_blkaddrs(struct inode *inode, block_t *blkaddr,
12190a2aa8fbSJaegeuk Kim 				int *do_replace, pgoff_t off, pgoff_t len)
1220b4ace337SChao Yu {
1221b4ace337SChao Yu 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
1222b4ace337SChao Yu 	struct dnode_of_data dn;
12230a2aa8fbSJaegeuk Kim 	int ret, done, i;
1224ecbaa406SChao Yu 
12250a2aa8fbSJaegeuk Kim next_dnode:
1226b4ace337SChao Yu 	set_new_dnode(&dn, inode, NULL, NULL, 0);
12274d57b86dSChao Yu 	ret = f2fs_get_dnode_of_data(&dn, off, LOOKUP_NODE_RA);
1228b4ace337SChao Yu 	if (ret && ret != -ENOENT) {
12296e2c64adSJaegeuk Kim 		return ret;
1230b4ace337SChao Yu 	} else if (ret == -ENOENT) {
12310a2aa8fbSJaegeuk Kim 		if (dn.max_level == 0)
12320a2aa8fbSJaegeuk Kim 			return -ENOENT;
12334c8ff709SChao Yu 		done = min((pgoff_t)ADDRS_PER_BLOCK(inode) -
12344c8ff709SChao Yu 						dn.ofs_in_node, len);
12350a2aa8fbSJaegeuk Kim 		blkaddr += done;
12360a2aa8fbSJaegeuk Kim 		do_replace += done;
12370a2aa8fbSJaegeuk Kim 		goto next;
12380a2aa8fbSJaegeuk Kim 	}
12390a2aa8fbSJaegeuk Kim 
12400a2aa8fbSJaegeuk Kim 	done = min((pgoff_t)ADDRS_PER_PAGE(dn.node_page, inode) -
12410a2aa8fbSJaegeuk Kim 							dn.ofs_in_node, len);
12420a2aa8fbSJaegeuk Kim 	for (i = 0; i < done; i++, blkaddr++, do_replace++, dn.ofs_in_node++) {
1243a2ced1ceSChao Yu 		*blkaddr = f2fs_data_blkaddr(&dn);
124493770ab7SChao Yu 
124593770ab7SChao Yu 		if (__is_valid_data_blkaddr(*blkaddr) &&
124693770ab7SChao Yu 			!f2fs_is_valid_blkaddr(sbi, *blkaddr,
124793770ab7SChao Yu 					DATA_GENERIC_ENHANCE)) {
124893770ab7SChao Yu 			f2fs_put_dnode(&dn);
124995fa90c9SChao Yu 			f2fs_handle_error(sbi, ERROR_INVALID_BLKADDR);
125010f966bbSChao Yu 			return -EFSCORRUPTED;
125193770ab7SChao Yu 		}
125293770ab7SChao Yu 
12534d57b86dSChao Yu 		if (!f2fs_is_checkpointed_data(sbi, *blkaddr)) {
12540a2aa8fbSJaegeuk Kim 
1255b0332a0fSChao Yu 			if (f2fs_lfs_mode(sbi)) {
12560a2aa8fbSJaegeuk Kim 				f2fs_put_dnode(&dn);
1257fd114ab2SChao Yu 				return -EOPNOTSUPP;
12580a2aa8fbSJaegeuk Kim 			}
12590a2aa8fbSJaegeuk Kim 
12606e2c64adSJaegeuk Kim 			/* do not invalidate this block address */
1261f28b3434SChao Yu 			f2fs_update_data_blkaddr(&dn, NULL_ADDR);
12620a2aa8fbSJaegeuk Kim 			*do_replace = 1;
12630a2aa8fbSJaegeuk Kim 		}
12640a2aa8fbSJaegeuk Kim 	}
12650a2aa8fbSJaegeuk Kim 	f2fs_put_dnode(&dn);
12660a2aa8fbSJaegeuk Kim next:
12670a2aa8fbSJaegeuk Kim 	len -= done;
12680a2aa8fbSJaegeuk Kim 	off += done;
12690a2aa8fbSJaegeuk Kim 	if (len)
12700a2aa8fbSJaegeuk Kim 		goto next_dnode;
12710a2aa8fbSJaegeuk Kim 	return 0;
12720a2aa8fbSJaegeuk Kim }
12730a2aa8fbSJaegeuk Kim 
__roll_back_blkaddrs(struct inode * inode,block_t * blkaddr,int * do_replace,pgoff_t off,int len)12740a2aa8fbSJaegeuk Kim static int __roll_back_blkaddrs(struct inode *inode, block_t *blkaddr,
12750a2aa8fbSJaegeuk Kim 				int *do_replace, pgoff_t off, int len)
12760a2aa8fbSJaegeuk Kim {
12770a2aa8fbSJaegeuk Kim 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
12780a2aa8fbSJaegeuk Kim 	struct dnode_of_data dn;
12790a2aa8fbSJaegeuk Kim 	int ret, i;
12800a2aa8fbSJaegeuk Kim 
12810a2aa8fbSJaegeuk Kim 	for (i = 0; i < len; i++, do_replace++, blkaddr++) {
12820a2aa8fbSJaegeuk Kim 		if (*do_replace == 0)
12830a2aa8fbSJaegeuk Kim 			continue;
12840a2aa8fbSJaegeuk Kim 
12850a2aa8fbSJaegeuk Kim 		set_new_dnode(&dn, inode, NULL, NULL, 0);
12864d57b86dSChao Yu 		ret = f2fs_get_dnode_of_data(&dn, off + i, LOOKUP_NODE_RA);
12870a2aa8fbSJaegeuk Kim 		if (ret) {
12880a2aa8fbSJaegeuk Kim 			dec_valid_block_count(sbi, inode, 1);
12894d57b86dSChao Yu 			f2fs_invalidate_blocks(sbi, *blkaddr);
12900a2aa8fbSJaegeuk Kim 		} else {
12910a2aa8fbSJaegeuk Kim 			f2fs_update_data_blkaddr(&dn, *blkaddr);
12926e2c64adSJaegeuk Kim 		}
1293b4ace337SChao Yu 		f2fs_put_dnode(&dn);
1294b4ace337SChao Yu 	}
12950a2aa8fbSJaegeuk Kim 	return 0;
12960a2aa8fbSJaegeuk Kim }
1297b4ace337SChao Yu 
__clone_blkaddrs(struct inode * src_inode,struct inode * dst_inode,block_t * blkaddr,int * do_replace,pgoff_t src,pgoff_t dst,pgoff_t len,bool full)12980a2aa8fbSJaegeuk Kim static int __clone_blkaddrs(struct inode *src_inode, struct inode *dst_inode,
12990a2aa8fbSJaegeuk Kim 			block_t *blkaddr, int *do_replace,
13000a2aa8fbSJaegeuk Kim 			pgoff_t src, pgoff_t dst, pgoff_t len, bool full)
13010a2aa8fbSJaegeuk Kim {
13020a2aa8fbSJaegeuk Kim 	struct f2fs_sb_info *sbi = F2FS_I_SB(src_inode);
13030a2aa8fbSJaegeuk Kim 	pgoff_t i = 0;
13040a2aa8fbSJaegeuk Kim 	int ret;
1305b4ace337SChao Yu 
13060a2aa8fbSJaegeuk Kim 	while (i < len) {
13070a2aa8fbSJaegeuk Kim 		if (blkaddr[i] == NULL_ADDR && !full) {
13080a2aa8fbSJaegeuk Kim 			i++;
13090a2aa8fbSJaegeuk Kim 			continue;
13100a2aa8fbSJaegeuk Kim 		}
13110a2aa8fbSJaegeuk Kim 
13120a2aa8fbSJaegeuk Kim 		if (do_replace[i] || blkaddr[i] == NULL_ADDR) {
13130a2aa8fbSJaegeuk Kim 			struct dnode_of_data dn;
13146e2c64adSJaegeuk Kim 			struct node_info ni;
13150a2aa8fbSJaegeuk Kim 			size_t new_size;
13160a2aa8fbSJaegeuk Kim 			pgoff_t ilen;
1317b4ace337SChao Yu 
13180a2aa8fbSJaegeuk Kim 			set_new_dnode(&dn, dst_inode, NULL, NULL, 0);
13194d57b86dSChao Yu 			ret = f2fs_get_dnode_of_data(&dn, dst + i, ALLOC_NODE);
1320b4ace337SChao Yu 			if (ret)
13210a2aa8fbSJaegeuk Kim 				return ret;
1322b4ace337SChao Yu 
1323a9419b63SJaegeuk Kim 			ret = f2fs_get_node_info(sbi, dn.nid, &ni, false);
13247735730dSChao Yu 			if (ret) {
13257735730dSChao Yu 				f2fs_put_dnode(&dn);
13267735730dSChao Yu 				return ret;
13277735730dSChao Yu 			}
13287735730dSChao Yu 
13290a2aa8fbSJaegeuk Kim 			ilen = min((pgoff_t)
13300a2aa8fbSJaegeuk Kim 				ADDRS_PER_PAGE(dn.node_page, dst_inode) -
13310a2aa8fbSJaegeuk Kim 						dn.ofs_in_node, len - i);
13320a2aa8fbSJaegeuk Kim 			do {
1333a2ced1ceSChao Yu 				dn.data_blkaddr = f2fs_data_blkaddr(&dn);
13344d57b86dSChao Yu 				f2fs_truncate_data_blocks_range(&dn, 1);
13350a2aa8fbSJaegeuk Kim 
13360a2aa8fbSJaegeuk Kim 				if (do_replace[i]) {
13370a2aa8fbSJaegeuk Kim 					f2fs_i_blocks_write(src_inode,
13380abd675eSChao Yu 							1, false, false);
13390a2aa8fbSJaegeuk Kim 					f2fs_i_blocks_write(dst_inode,
13400abd675eSChao Yu 							1, true, false);
13410a2aa8fbSJaegeuk Kim 					f2fs_replace_block(sbi, &dn, dn.data_blkaddr,
13420a2aa8fbSJaegeuk Kim 					blkaddr[i], ni.version, true, false);
13430a2aa8fbSJaegeuk Kim 
13440a2aa8fbSJaegeuk Kim 					do_replace[i] = 0;
13450a2aa8fbSJaegeuk Kim 				}
13460a2aa8fbSJaegeuk Kim 				dn.ofs_in_node++;
13470a2aa8fbSJaegeuk Kim 				i++;
13481f0d5c91SChao Yu 				new_size = (loff_t)(dst + i) << PAGE_SHIFT;
13490a2aa8fbSJaegeuk Kim 				if (dst_inode->i_size < new_size)
13500a2aa8fbSJaegeuk Kim 					f2fs_i_size_write(dst_inode, new_size);
1351e87f7329SJaegeuk Kim 			} while (--ilen && (do_replace[i] || blkaddr[i] == NULL_ADDR));
13520a2aa8fbSJaegeuk Kim 
1353b4ace337SChao Yu 			f2fs_put_dnode(&dn);
13546e2c64adSJaegeuk Kim 		} else {
13556e2c64adSJaegeuk Kim 			struct page *psrc, *pdst;
13566e2c64adSJaegeuk Kim 
13574d57b86dSChao Yu 			psrc = f2fs_get_lock_data_page(src_inode,
13584d57b86dSChao Yu 							src + i, true);
13596e2c64adSJaegeuk Kim 			if (IS_ERR(psrc))
13606e2c64adSJaegeuk Kim 				return PTR_ERR(psrc);
13614d57b86dSChao Yu 			pdst = f2fs_get_new_data_page(dst_inode, NULL, dst + i,
13620a2aa8fbSJaegeuk Kim 								true);
13636e2c64adSJaegeuk Kim 			if (IS_ERR(pdst)) {
13646e2c64adSJaegeuk Kim 				f2fs_put_page(psrc, 1);
13656e2c64adSJaegeuk Kim 				return PTR_ERR(pdst);
1366b4ace337SChao Yu 			}
13674b3609e6SChao Yu 
13684b3609e6SChao Yu 			f2fs_wait_on_page_writeback(pdst, DATA, true, true);
13694b3609e6SChao Yu 
13701dd55358SFabio M. De Francesco 			memcpy_page(pdst, 0, psrc, 0, PAGE_SIZE);
13716e2c64adSJaegeuk Kim 			set_page_dirty(pdst);
1372417b8a91SChao Yu 			set_page_private_gcing(pdst);
13736e2c64adSJaegeuk Kim 			f2fs_put_page(pdst, 1);
13746e2c64adSJaegeuk Kim 			f2fs_put_page(psrc, 1);
13756e2c64adSJaegeuk Kim 
13764d57b86dSChao Yu 			ret = f2fs_truncate_hole(src_inode,
13774d57b86dSChao Yu 						src + i, src + i + 1);
13780a2aa8fbSJaegeuk Kim 			if (ret)
13790a2aa8fbSJaegeuk Kim 				return ret;
13800a2aa8fbSJaegeuk Kim 			i++;
13810a2aa8fbSJaegeuk Kim 		}
1382b4ace337SChao Yu 	}
1383ecbaa406SChao Yu 	return 0;
13846e2c64adSJaegeuk Kim }
13850a2aa8fbSJaegeuk Kim 
__exchange_data_block(struct inode * src_inode,struct inode * dst_inode,pgoff_t src,pgoff_t dst,pgoff_t len,bool full)13860a2aa8fbSJaegeuk Kim static int __exchange_data_block(struct inode *src_inode,
13870a2aa8fbSJaegeuk Kim 			struct inode *dst_inode, pgoff_t src, pgoff_t dst,
1388363cad7fSJaegeuk Kim 			pgoff_t len, bool full)
13890a2aa8fbSJaegeuk Kim {
13900a2aa8fbSJaegeuk Kim 	block_t *src_blkaddr;
13910a2aa8fbSJaegeuk Kim 	int *do_replace;
1392363cad7fSJaegeuk Kim 	pgoff_t olen;
13930a2aa8fbSJaegeuk Kim 	int ret;
13940a2aa8fbSJaegeuk Kim 
1395363cad7fSJaegeuk Kim 	while (len) {
1396d02a6e61SChao Yu 		olen = min((pgoff_t)4 * ADDRS_PER_BLOCK(src_inode), len);
1397363cad7fSJaegeuk Kim 
1398628b3d14SChao Yu 		src_blkaddr = f2fs_kvzalloc(F2FS_I_SB(src_inode),
13999d2a789cSKees Cook 					array_size(olen, sizeof(block_t)),
14004f4460c0SJaegeuk Kim 					GFP_NOFS);
14010a2aa8fbSJaegeuk Kim 		if (!src_blkaddr)
14020a2aa8fbSJaegeuk Kim 			return -ENOMEM;
14030a2aa8fbSJaegeuk Kim 
1404628b3d14SChao Yu 		do_replace = f2fs_kvzalloc(F2FS_I_SB(src_inode),
14059d2a789cSKees Cook 					array_size(olen, sizeof(int)),
14064f4460c0SJaegeuk Kim 					GFP_NOFS);
14070a2aa8fbSJaegeuk Kim 		if (!do_replace) {
14080a2aa8fbSJaegeuk Kim 			kvfree(src_blkaddr);
14090a2aa8fbSJaegeuk Kim 			return -ENOMEM;
14100a2aa8fbSJaegeuk Kim 		}
14110a2aa8fbSJaegeuk Kim 
1412363cad7fSJaegeuk Kim 		ret = __read_out_blkaddrs(src_inode, src_blkaddr,
1413363cad7fSJaegeuk Kim 					do_replace, src, olen);
14140a2aa8fbSJaegeuk Kim 		if (ret)
14150a2aa8fbSJaegeuk Kim 			goto roll_back;
14160a2aa8fbSJaegeuk Kim 
14170a2aa8fbSJaegeuk Kim 		ret = __clone_blkaddrs(src_inode, dst_inode, src_blkaddr,
1418363cad7fSJaegeuk Kim 					do_replace, src, dst, olen, full);
14190a2aa8fbSJaegeuk Kim 		if (ret)
14200a2aa8fbSJaegeuk Kim 			goto roll_back;
14210a2aa8fbSJaegeuk Kim 
1422363cad7fSJaegeuk Kim 		src += olen;
1423363cad7fSJaegeuk Kim 		dst += olen;
1424363cad7fSJaegeuk Kim 		len -= olen;
1425363cad7fSJaegeuk Kim 
14260a2aa8fbSJaegeuk Kim 		kvfree(src_blkaddr);
14270a2aa8fbSJaegeuk Kim 		kvfree(do_replace);
1428363cad7fSJaegeuk Kim 	}
14290a2aa8fbSJaegeuk Kim 	return 0;
14300a2aa8fbSJaegeuk Kim 
14310a2aa8fbSJaegeuk Kim roll_back:
14329fd62605SChao Yu 	__roll_back_blkaddrs(src_inode, src_blkaddr, do_replace, src, olen);
14330a2aa8fbSJaegeuk Kim 	kvfree(src_blkaddr);
14340a2aa8fbSJaegeuk Kim 	kvfree(do_replace);
14356e2c64adSJaegeuk Kim 	return ret;
14366e2c64adSJaegeuk Kim }
14376e2c64adSJaegeuk Kim 
f2fs_do_collapse(struct inode * inode,loff_t offset,loff_t len)14386f8d4455SJaegeuk Kim static int f2fs_do_collapse(struct inode *inode, loff_t offset, loff_t len)
14396e2c64adSJaegeuk Kim {
14406e2c64adSJaegeuk Kim 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
1441f91108b8SGeert Uytterhoeven 	pgoff_t nrpages = DIV_ROUND_UP(i_size_read(inode), PAGE_SIZE);
14426f8d4455SJaegeuk Kim 	pgoff_t start = offset >> PAGE_SHIFT;
14436f8d4455SJaegeuk Kim 	pgoff_t end = (offset + len) >> PAGE_SHIFT;
14440a2aa8fbSJaegeuk Kim 	int ret;
14456e2c64adSJaegeuk Kim 
14462c4db1a6SJaegeuk Kim 	f2fs_balance_fs(sbi, true);
14476f8d4455SJaegeuk Kim 
14486f8d4455SJaegeuk Kim 	/* avoid gc operation during block exchange */
1449e4544b63STim Murray 	f2fs_down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
1450edc6d01bSJan Kara 	filemap_invalidate_lock(inode->i_mapping);
14516f8d4455SJaegeuk Kim 
14526e2c64adSJaegeuk Kim 	f2fs_lock_op(sbi);
14535f281fabSJaegeuk Kim 	f2fs_drop_extent_tree(inode);
14546f8d4455SJaegeuk Kim 	truncate_pagecache(inode, offset);
14550a2aa8fbSJaegeuk Kim 	ret = __exchange_data_block(inode, inode, end, start, nrpages - end, true);
1456b4ace337SChao Yu 	f2fs_unlock_op(sbi);
14576f8d4455SJaegeuk Kim 
1458edc6d01bSJan Kara 	filemap_invalidate_unlock(inode->i_mapping);
1459e4544b63STim Murray 	f2fs_up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
1460b4ace337SChao Yu 	return ret;
1461b4ace337SChao Yu }
1462b4ace337SChao Yu 
f2fs_collapse_range(struct inode * inode,loff_t offset,loff_t len)1463b4ace337SChao Yu static int f2fs_collapse_range(struct inode *inode, loff_t offset, loff_t len)
1464b4ace337SChao Yu {
1465b4ace337SChao Yu 	loff_t new_size;
1466b4ace337SChao Yu 	int ret;
1467b4ace337SChao Yu 
1468b4ace337SChao Yu 	if (offset + len >= i_size_read(inode))
1469b4ace337SChao Yu 		return -EINVAL;
1470b4ace337SChao Yu 
1471b4ace337SChao Yu 	/* collapse range should be aligned to block size of f2fs. */
1472b4ace337SChao Yu 	if (offset & (F2FS_BLKSIZE - 1) || len & (F2FS_BLKSIZE - 1))
1473b4ace337SChao Yu 		return -EINVAL;
1474b4ace337SChao Yu 
147597a7b2c2SJaegeuk Kim 	ret = f2fs_convert_inline_inode(inode);
147697a7b2c2SJaegeuk Kim 	if (ret)
147797a7b2c2SJaegeuk Kim 		return ret;
147897a7b2c2SJaegeuk Kim 
1479b4ace337SChao Yu 	/* write out all dirty pages from offset */
1480b4ace337SChao Yu 	ret = filemap_write_and_wait_range(inode->i_mapping, offset, LLONG_MAX);
1481b4ace337SChao Yu 	if (ret)
14826f8d4455SJaegeuk Kim 		return ret;
1483bb06664aSChao Yu 
14846f8d4455SJaegeuk Kim 	ret = f2fs_do_collapse(inode, offset, len);
1485b4ace337SChao Yu 	if (ret)
14866f8d4455SJaegeuk Kim 		return ret;
1487b4ace337SChao Yu 
14886e2c64adSJaegeuk Kim 	/* write out all moved pages, if possible */
1489edc6d01bSJan Kara 	filemap_invalidate_lock(inode->i_mapping);
14906e2c64adSJaegeuk Kim 	filemap_write_and_wait_range(inode->i_mapping, offset, LLONG_MAX);
14916e2c64adSJaegeuk Kim 	truncate_pagecache(inode, offset);
14926e2c64adSJaegeuk Kim 
1493b4ace337SChao Yu 	new_size = i_size_read(inode) - len;
1494c42d28ceSChao Yu 	ret = f2fs_truncate_blocks(inode, new_size, true);
1495edc6d01bSJan Kara 	filemap_invalidate_unlock(inode->i_mapping);
1496b4ace337SChao Yu 	if (!ret)
1497fc9581c8SJaegeuk Kim 		f2fs_i_size_write(inode, new_size);
1498b4ace337SChao Yu 	return ret;
1499b4ace337SChao Yu }
1500b4ace337SChao Yu 
f2fs_do_zero_range(struct dnode_of_data * dn,pgoff_t start,pgoff_t end)15016e961949SChao Yu static int f2fs_do_zero_range(struct dnode_of_data *dn, pgoff_t start,
15026e961949SChao Yu 								pgoff_t end)
15036e961949SChao Yu {
15046e961949SChao Yu 	struct f2fs_sb_info *sbi = F2FS_I_SB(dn->inode);
15056e961949SChao Yu 	pgoff_t index = start;
15066e961949SChao Yu 	unsigned int ofs_in_node = dn->ofs_in_node;
15076e961949SChao Yu 	blkcnt_t count = 0;
15086e961949SChao Yu 	int ret;
15096e961949SChao Yu 
15106e961949SChao Yu 	for (; index < end; index++, dn->ofs_in_node++) {
1511a2ced1ceSChao Yu 		if (f2fs_data_blkaddr(dn) == NULL_ADDR)
15126e961949SChao Yu 			count++;
15136e961949SChao Yu 	}
15146e961949SChao Yu 
15156e961949SChao Yu 	dn->ofs_in_node = ofs_in_node;
15164d57b86dSChao Yu 	ret = f2fs_reserve_new_blocks(dn, count);
15176e961949SChao Yu 	if (ret)
15186e961949SChao Yu 		return ret;
15196e961949SChao Yu 
15206e961949SChao Yu 	dn->ofs_in_node = ofs_in_node;
15216e961949SChao Yu 	for (index = start; index < end; index++, dn->ofs_in_node++) {
1522a2ced1ceSChao Yu 		dn->data_blkaddr = f2fs_data_blkaddr(dn);
15236e961949SChao Yu 		/*
15244d57b86dSChao Yu 		 * f2fs_reserve_new_blocks will not guarantee entire block
15256e961949SChao Yu 		 * allocation.
15266e961949SChao Yu 		 */
15276e961949SChao Yu 		if (dn->data_blkaddr == NULL_ADDR) {
15286e961949SChao Yu 			ret = -ENOSPC;
15296e961949SChao Yu 			break;
15306e961949SChao Yu 		}
153125f82362SChao Yu 
153225f82362SChao Yu 		if (dn->data_blkaddr == NEW_ADDR)
153325f82362SChao Yu 			continue;
153425f82362SChao Yu 
153525f82362SChao Yu 		if (!f2fs_is_valid_blkaddr(sbi, dn->data_blkaddr,
153625f82362SChao Yu 					DATA_GENERIC_ENHANCE)) {
153725f82362SChao Yu 			ret = -EFSCORRUPTED;
153895fa90c9SChao Yu 			f2fs_handle_error(sbi, ERROR_INVALID_BLKADDR);
153925f82362SChao Yu 			break;
154025f82362SChao Yu 		}
154125f82362SChao Yu 
15424d57b86dSChao Yu 		f2fs_invalidate_blocks(sbi, dn->data_blkaddr);
1543eb6d30bcSChao Yu 		f2fs_set_data_blkaddr(dn, NEW_ADDR);
15446e961949SChao Yu 	}
15456e961949SChao Yu 
1546e7547dacSJaegeuk Kim 	f2fs_update_read_extent_cache_range(dn, start, 0, index - start);
1547a84153f9SChao Yu 	f2fs_update_age_extent_cache_range(dn, start, index - start);
15486e961949SChao Yu 
15496e961949SChao Yu 	return ret;
15506e961949SChao Yu }
15516e961949SChao Yu 
f2fs_zero_range(struct inode * inode,loff_t offset,loff_t len,int mode)155275cd4e09SChao Yu static int f2fs_zero_range(struct inode *inode, loff_t offset, loff_t len,
155375cd4e09SChao Yu 								int mode)
155475cd4e09SChao Yu {
155575cd4e09SChao Yu 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
155675cd4e09SChao Yu 	struct address_space *mapping = inode->i_mapping;
155775cd4e09SChao Yu 	pgoff_t index, pg_start, pg_end;
155875cd4e09SChao Yu 	loff_t new_size = i_size_read(inode);
155975cd4e09SChao Yu 	loff_t off_start, off_end;
156075cd4e09SChao Yu 	int ret = 0;
156175cd4e09SChao Yu 
156275cd4e09SChao Yu 	ret = inode_newsize_ok(inode, (len + offset));
156375cd4e09SChao Yu 	if (ret)
156475cd4e09SChao Yu 		return ret;
156575cd4e09SChao Yu 
156675cd4e09SChao Yu 	ret = f2fs_convert_inline_inode(inode);
156775cd4e09SChao Yu 	if (ret)
156875cd4e09SChao Yu 		return ret;
156975cd4e09SChao Yu 
157075cd4e09SChao Yu 	ret = filemap_write_and_wait_range(mapping, offset, offset + len - 1);
157175cd4e09SChao Yu 	if (ret)
15726f8d4455SJaegeuk Kim 		return ret;
157375cd4e09SChao Yu 
157409cbfeafSKirill A. Shutemov 	pg_start = ((unsigned long long) offset) >> PAGE_SHIFT;
157509cbfeafSKirill A. Shutemov 	pg_end = ((unsigned long long) offset + len) >> PAGE_SHIFT;
157675cd4e09SChao Yu 
157709cbfeafSKirill A. Shutemov 	off_start = offset & (PAGE_SIZE - 1);
157809cbfeafSKirill A. Shutemov 	off_end = (offset + len) & (PAGE_SIZE - 1);
157975cd4e09SChao Yu 
158075cd4e09SChao Yu 	if (pg_start == pg_end) {
15816394328aSChao Yu 		ret = fill_zero(inode, pg_start, off_start,
15826394328aSChao Yu 						off_end - off_start);
15836394328aSChao Yu 		if (ret)
15846f8d4455SJaegeuk Kim 			return ret;
15856394328aSChao Yu 
158675cd4e09SChao Yu 		new_size = max_t(loff_t, new_size, offset + len);
158775cd4e09SChao Yu 	} else {
158875cd4e09SChao Yu 		if (off_start) {
15896394328aSChao Yu 			ret = fill_zero(inode, pg_start++, off_start,
159009cbfeafSKirill A. Shutemov 						PAGE_SIZE - off_start);
15916394328aSChao Yu 			if (ret)
15926f8d4455SJaegeuk Kim 				return ret;
15936394328aSChao Yu 
159475cd4e09SChao Yu 			new_size = max_t(loff_t, new_size,
159509cbfeafSKirill A. Shutemov 					(loff_t)pg_start << PAGE_SHIFT);
159675cd4e09SChao Yu 		}
159775cd4e09SChao Yu 
15986e961949SChao Yu 		for (index = pg_start; index < pg_end;) {
159975cd4e09SChao Yu 			struct dnode_of_data dn;
16006e961949SChao Yu 			unsigned int end_offset;
16016e961949SChao Yu 			pgoff_t end;
160275cd4e09SChao Yu 
1603e4544b63STim Murray 			f2fs_down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
1604edc6d01bSJan Kara 			filemap_invalidate_lock(mapping);
1605c7079853SChao Yu 
1606c7079853SChao Yu 			truncate_pagecache_range(inode,
1607c7079853SChao Yu 				(loff_t)index << PAGE_SHIFT,
1608c7079853SChao Yu 				((loff_t)pg_end << PAGE_SHIFT) - 1);
1609c7079853SChao Yu 
161075cd4e09SChao Yu 			f2fs_lock_op(sbi);
161175cd4e09SChao Yu 
16126e961949SChao Yu 			set_new_dnode(&dn, inode, NULL, NULL, 0);
16134d57b86dSChao Yu 			ret = f2fs_get_dnode_of_data(&dn, index, ALLOC_NODE);
161475cd4e09SChao Yu 			if (ret) {
161575cd4e09SChao Yu 				f2fs_unlock_op(sbi);
1616edc6d01bSJan Kara 				filemap_invalidate_unlock(mapping);
1617e4544b63STim Murray 				f2fs_up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
161875cd4e09SChao Yu 				goto out;
161975cd4e09SChao Yu 			}
162075cd4e09SChao Yu 
16216e961949SChao Yu 			end_offset = ADDRS_PER_PAGE(dn.node_page, inode);
16226e961949SChao Yu 			end = min(pg_end, end_offset - dn.ofs_in_node + index);
16236e961949SChao Yu 
16246e961949SChao Yu 			ret = f2fs_do_zero_range(&dn, index, end);
162575cd4e09SChao Yu 			f2fs_put_dnode(&dn);
1626c7079853SChao Yu 
162775cd4e09SChao Yu 			f2fs_unlock_op(sbi);
1628edc6d01bSJan Kara 			filemap_invalidate_unlock(mapping);
1629e4544b63STim Murray 			f2fs_up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
16309434fcdeSChao Yu 
16319434fcdeSChao Yu 			f2fs_balance_fs(sbi, dn.node_changed);
16329434fcdeSChao Yu 
16336e961949SChao Yu 			if (ret)
16346e961949SChao Yu 				goto out;
163575cd4e09SChao Yu 
16366e961949SChao Yu 			index = end;
163775cd4e09SChao Yu 			new_size = max_t(loff_t, new_size,
16386e961949SChao Yu 					(loff_t)index << PAGE_SHIFT);
163975cd4e09SChao Yu 		}
164075cd4e09SChao Yu 
164175cd4e09SChao Yu 		if (off_end) {
16426394328aSChao Yu 			ret = fill_zero(inode, pg_end, 0, off_end);
16436394328aSChao Yu 			if (ret)
16446394328aSChao Yu 				goto out;
16456394328aSChao Yu 
164675cd4e09SChao Yu 			new_size = max_t(loff_t, new_size, offset + len);
164775cd4e09SChao Yu 		}
164875cd4e09SChao Yu 	}
164975cd4e09SChao Yu 
165075cd4e09SChao Yu out:
165117cd07aeSChao Yu 	if (new_size > i_size_read(inode)) {
165217cd07aeSChao Yu 		if (mode & FALLOC_FL_KEEP_SIZE)
165317cd07aeSChao Yu 			file_set_keep_isize(inode);
165417cd07aeSChao Yu 		else
1655fc9581c8SJaegeuk Kim 			f2fs_i_size_write(inode, new_size);
165617cd07aeSChao Yu 	}
165775cd4e09SChao Yu 	return ret;
165875cd4e09SChao Yu }
165975cd4e09SChao Yu 
f2fs_insert_range(struct inode * inode,loff_t offset,loff_t len)1660f62185d0SChao Yu static int f2fs_insert_range(struct inode *inode, loff_t offset, loff_t len)
1661f62185d0SChao Yu {
1662f62185d0SChao Yu 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
1663edc6d01bSJan Kara 	struct address_space *mapping = inode->i_mapping;
16640a2aa8fbSJaegeuk Kim 	pgoff_t nr, pg_start, pg_end, delta, idx;
1665f62185d0SChao Yu 	loff_t new_size;
16666e2c64adSJaegeuk Kim 	int ret = 0;
1667f62185d0SChao Yu 
1668f62185d0SChao Yu 	new_size = i_size_read(inode) + len;
166946e82fb1SKinglong Mee 	ret = inode_newsize_ok(inode, new_size);
167046e82fb1SKinglong Mee 	if (ret)
167146e82fb1SKinglong Mee 		return ret;
1672f62185d0SChao Yu 
1673f62185d0SChao Yu 	if (offset >= i_size_read(inode))
1674f62185d0SChao Yu 		return -EINVAL;
1675f62185d0SChao Yu 
1676f62185d0SChao Yu 	/* insert range should be aligned to block size of f2fs. */
1677f62185d0SChao Yu 	if (offset & (F2FS_BLKSIZE - 1) || len & (F2FS_BLKSIZE - 1))
1678f62185d0SChao Yu 		return -EINVAL;
1679f62185d0SChao Yu 
168097a7b2c2SJaegeuk Kim 	ret = f2fs_convert_inline_inode(inode);
168197a7b2c2SJaegeuk Kim 	if (ret)
168297a7b2c2SJaegeuk Kim 		return ret;
168397a7b2c2SJaegeuk Kim 
16842c4db1a6SJaegeuk Kim 	f2fs_balance_fs(sbi, true);
16852a340760SJaegeuk Kim 
1686edc6d01bSJan Kara 	filemap_invalidate_lock(mapping);
1687c42d28ceSChao Yu 	ret = f2fs_truncate_blocks(inode, i_size_read(inode), true);
1688edc6d01bSJan Kara 	filemap_invalidate_unlock(mapping);
1689f62185d0SChao Yu 	if (ret)
16906f8d4455SJaegeuk Kim 		return ret;
1691f62185d0SChao Yu 
1692f62185d0SChao Yu 	/* write out all dirty pages from offset */
1693edc6d01bSJan Kara 	ret = filemap_write_and_wait_range(mapping, offset, LLONG_MAX);
1694f62185d0SChao Yu 	if (ret)
16956f8d4455SJaegeuk Kim 		return ret;
1696f62185d0SChao Yu 
169709cbfeafSKirill A. Shutemov 	pg_start = offset >> PAGE_SHIFT;
169809cbfeafSKirill A. Shutemov 	pg_end = (offset + len) >> PAGE_SHIFT;
1699f62185d0SChao Yu 	delta = pg_end - pg_start;
1700f91108b8SGeert Uytterhoeven 	idx = DIV_ROUND_UP(i_size_read(inode), PAGE_SIZE);
1701f62185d0SChao Yu 
17026f8d4455SJaegeuk Kim 	/* avoid gc operation during block exchange */
1703e4544b63STim Murray 	f2fs_down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
1704edc6d01bSJan Kara 	filemap_invalidate_lock(mapping);
17056f8d4455SJaegeuk Kim 	truncate_pagecache(inode, offset);
17066f8d4455SJaegeuk Kim 
17070a2aa8fbSJaegeuk Kim 	while (!ret && idx > pg_start) {
17080a2aa8fbSJaegeuk Kim 		nr = idx - pg_start;
17090a2aa8fbSJaegeuk Kim 		if (nr > delta)
17100a2aa8fbSJaegeuk Kim 			nr = delta;
17110a2aa8fbSJaegeuk Kim 		idx -= nr;
17120a2aa8fbSJaegeuk Kim 
1713f62185d0SChao Yu 		f2fs_lock_op(sbi);
17145f281fabSJaegeuk Kim 		f2fs_drop_extent_tree(inode);
17155f281fabSJaegeuk Kim 
17160a2aa8fbSJaegeuk Kim 		ret = __exchange_data_block(inode, inode, idx,
17170a2aa8fbSJaegeuk Kim 					idx + delta, nr, false);
17186e2c64adSJaegeuk Kim 		f2fs_unlock_op(sbi);
1719f62185d0SChao Yu 	}
1720edc6d01bSJan Kara 	filemap_invalidate_unlock(mapping);
1721e4544b63STim Murray 	f2fs_up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
1722f62185d0SChao Yu 
17236e2c64adSJaegeuk Kim 	/* write out all moved pages, if possible */
1724edc6d01bSJan Kara 	filemap_invalidate_lock(mapping);
1725edc6d01bSJan Kara 	filemap_write_and_wait_range(mapping, offset, LLONG_MAX);
17266e2c64adSJaegeuk Kim 	truncate_pagecache(inode, offset);
1727edc6d01bSJan Kara 	filemap_invalidate_unlock(mapping);
17286e2c64adSJaegeuk Kim 
17296e2c64adSJaegeuk Kim 	if (!ret)
1730fc9581c8SJaegeuk Kim 		f2fs_i_size_write(inode, new_size);
1731f62185d0SChao Yu 	return ret;
1732f62185d0SChao Yu }
1733f62185d0SChao Yu 
f2fs_expand_inode_data(struct inode * inode,loff_t offset,loff_t len,int mode)17341cd75654SYangtao Li static int f2fs_expand_inode_data(struct inode *inode, loff_t offset,
1735fbfa2cc5SJaegeuk Kim 					loff_t len, int mode)
1736fbfa2cc5SJaegeuk Kim {
17374081363fSJaegeuk Kim 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
1738d5097be5SHyunchul Lee 	struct f2fs_map_blocks map = { .m_next_pgofs = NULL,
1739f9d6d059SChao Yu 			.m_next_extent = NULL, .m_seg_type = NO_CHECK_TYPE,
1740f9d6d059SChao Yu 			.m_may_create = true };
1741d147ea4aSJaegeuk Kim 	struct f2fs_gc_control gc_control = { .victim_segno = NULL_SEGNO,
1742d147ea4aSJaegeuk Kim 			.init_gc_type = FG_GC,
1743d147ea4aSJaegeuk Kim 			.should_migrate_blocks = false,
1744c81d5baeSJaegeuk Kim 			.err_gc_skipped = true,
1745c81d5baeSJaegeuk Kim 			.nr_free_secs = 0 };
174688f2cfc5SChao Yu 	pgoff_t pg_start, pg_end;
174739bee2e6SSergey Shtylyov 	loff_t new_size;
1748e12dd7bdSJaegeuk Kim 	loff_t off_end;
174988f2cfc5SChao Yu 	block_t expanded = 0;
1750a7de6086SJaegeuk Kim 	int err;
1751fbfa2cc5SJaegeuk Kim 
1752a7de6086SJaegeuk Kim 	err = inode_newsize_ok(inode, (len + offset));
1753a7de6086SJaegeuk Kim 	if (err)
1754a7de6086SJaegeuk Kim 		return err;
17559ffe0fb5SHuajun Li 
1756a7de6086SJaegeuk Kim 	err = f2fs_convert_inline_inode(inode);
1757a7de6086SJaegeuk Kim 	if (err)
1758a7de6086SJaegeuk Kim 		return err;
1759fbfa2cc5SJaegeuk Kim 
17602c4db1a6SJaegeuk Kim 	f2fs_balance_fs(sbi, true);
17612a340760SJaegeuk Kim 
176288f2cfc5SChao Yu 	pg_start = ((unsigned long long)offset) >> PAGE_SHIFT;
176309cbfeafSKirill A. Shutemov 	pg_end = ((unsigned long long)offset + len) >> PAGE_SHIFT;
176409cbfeafSKirill A. Shutemov 	off_end = (offset + len) & (PAGE_SIZE - 1);
1765fbfa2cc5SJaegeuk Kim 
176688f2cfc5SChao Yu 	map.m_lblk = pg_start;
176788f2cfc5SChao Yu 	map.m_len = pg_end - pg_start;
1768e12dd7bdSJaegeuk Kim 	if (off_end)
1769e12dd7bdSJaegeuk Kim 		map.m_len++;
1770ead43275SJaegeuk Kim 
1771f5a53edcSJaegeuk Kim 	if (!map.m_len)
1772f5a53edcSJaegeuk Kim 		return 0;
1773cad3836fSJaegeuk Kim 
1774f5a53edcSJaegeuk Kim 	if (f2fs_is_pinned_file(inode)) {
1775074b5ea2SJaegeuk Kim 		block_t sec_blks = CAP_BLKS_PER_SEC(sbi);
1776e1175f02SChao Yu 		block_t sec_len = roundup(map.m_len, sec_blks);
1777f5a53edcSJaegeuk Kim 
1778e1175f02SChao Yu 		map.m_len = sec_blks;
1779f5a53edcSJaegeuk Kim next_alloc:
1780f5a53edcSJaegeuk Kim 		if (has_not_enough_free_secs(sbi, 0,
1781f5a53edcSJaegeuk Kim 			GET_SEC_FROM_SEG(sbi, overprovision_segments(sbi)))) {
1782e4544b63STim Murray 			f2fs_down_write(&sbi->gc_lock);
17839bf1dcbdSChao Yu 			stat_inc_gc_call_count(sbi, FOREGROUND);
1784d147ea4aSJaegeuk Kim 			err = f2fs_gc(sbi, &gc_control);
17852e42b7f8SJaegeuk Kim 			if (err && err != -ENODATA)
1786f5a53edcSJaegeuk Kim 				goto out_err;
1787f5a53edcSJaegeuk Kim 		}
1788f5a53edcSJaegeuk Kim 
1789e4544b63STim Murray 		f2fs_down_write(&sbi->pin_sem);
1790fd612648SDaeho Jeong 
179140d76c39SDaeho Jeong 		err = f2fs_allocate_pinning_section(sbi);
179240d76c39SDaeho Jeong 		if (err) {
179340d76c39SDaeho Jeong 			f2fs_up_write(&sbi->pin_sem);
179440d76c39SDaeho Jeong 			goto out_err;
179540d76c39SDaeho Jeong 		}
1796fd612648SDaeho Jeong 
1797d0b9e42aSChao Yu 		map.m_seg_type = CURSEG_COLD_DATA_PINNED;
1798cd8fc522SChristoph Hellwig 		err = f2fs_map_blocks(inode, &map, F2FS_GET_BLOCK_PRE_DIO);
1799d4dd19ecSJaegeuk Kim 		file_dont_truncate(inode);
1800d0b9e42aSChao Yu 
1801e4544b63STim Murray 		f2fs_up_write(&sbi->pin_sem);
1802f5a53edcSJaegeuk Kim 
180388f2cfc5SChao Yu 		expanded += map.m_len;
1804e1175f02SChao Yu 		sec_len -= map.m_len;
1805f5a53edcSJaegeuk Kim 		map.m_lblk += map.m_len;
1806e1175f02SChao Yu 		if (!err && sec_len)
1807f5a53edcSJaegeuk Kim 			goto next_alloc;
1808f5a53edcSJaegeuk Kim 
180988f2cfc5SChao Yu 		map.m_len = expanded;
1810f5a53edcSJaegeuk Kim 	} else {
1811cd8fc522SChristoph Hellwig 		err = f2fs_map_blocks(inode, &map, F2FS_GET_BLOCK_PRE_AIO);
181288f2cfc5SChao Yu 		expanded = map.m_len;
1813f5a53edcSJaegeuk Kim 	}
1814f5a53edcSJaegeuk Kim out_err:
1815a7de6086SJaegeuk Kim 	if (err) {
1816e12dd7bdSJaegeuk Kim 		pgoff_t last_off;
1817fbfa2cc5SJaegeuk Kim 
181888f2cfc5SChao Yu 		if (!expanded)
1819a7de6086SJaegeuk Kim 			return err;
182098397ff3SJaegeuk Kim 
182188f2cfc5SChao Yu 		last_off = pg_start + expanded - 1;
1822e12dd7bdSJaegeuk Kim 
1823e12dd7bdSJaegeuk Kim 		/* update new size to the failed position */
1824e12dd7bdSJaegeuk Kim 		new_size = (last_off == pg_end) ? offset + len :
1825e12dd7bdSJaegeuk Kim 					(loff_t)(last_off + 1) << PAGE_SHIFT;
1826e12dd7bdSJaegeuk Kim 	} else {
1827e12dd7bdSJaegeuk Kim 		new_size = ((loff_t)pg_end << PAGE_SHIFT) + off_end;
1828fbfa2cc5SJaegeuk Kim 	}
1829fbfa2cc5SJaegeuk Kim 
1830e8ed90a6SChao Yu 	if (new_size > i_size_read(inode)) {
1831e8ed90a6SChao Yu 		if (mode & FALLOC_FL_KEEP_SIZE)
1832e8ed90a6SChao Yu 			file_set_keep_isize(inode);
1833e8ed90a6SChao Yu 		else
1834fc9581c8SJaegeuk Kim 			f2fs_i_size_write(inode, new_size);
1835e8ed90a6SChao Yu 	}
1836fbfa2cc5SJaegeuk Kim 
1837a7de6086SJaegeuk Kim 	return err;
1838fbfa2cc5SJaegeuk Kim }
1839fbfa2cc5SJaegeuk Kim 
f2fs_fallocate(struct file * file,int mode,loff_t offset,loff_t len)1840fbfa2cc5SJaegeuk Kim static long f2fs_fallocate(struct file *file, int mode,
1841fbfa2cc5SJaegeuk Kim 				loff_t offset, loff_t len)
1842fbfa2cc5SJaegeuk Kim {
18436131ffaaSAl Viro 	struct inode *inode = file_inode(file);
1844587c0a42STaehee Yoo 	long ret = 0;
1845fbfa2cc5SJaegeuk Kim 
18461f227a3eSJaegeuk Kim 	if (unlikely(f2fs_cp_error(F2FS_I_SB(inode))))
18471f227a3eSJaegeuk Kim 		return -EIO;
184800e09c0bSChao Yu 	if (!f2fs_is_checkpoint_ready(F2FS_I_SB(inode)))
184900e09c0bSChao Yu 		return -ENOSPC;
18504c8ff709SChao Yu 	if (!f2fs_is_compress_backend_ready(inode))
18514c8ff709SChao Yu 		return -EOPNOTSUPP;
18521f227a3eSJaegeuk Kim 
1853c998012bSChao Yu 	/* f2fs only support ->fallocate for regular file */
1854c998012bSChao Yu 	if (!S_ISREG(inode->i_mode))
1855c998012bSChao Yu 		return -EINVAL;
1856c998012bSChao Yu 
185762230e0dSChandan Rajendra 	if (IS_ENCRYPTED(inode) &&
1858f62185d0SChao Yu 		(mode & (FALLOC_FL_COLLAPSE_RANGE | FALLOC_FL_INSERT_RANGE)))
1859fcc85a4dSJaegeuk Kim 		return -EOPNOTSUPP;
1860fcc85a4dSJaegeuk Kim 
1861b4ace337SChao Yu 	if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE |
1862f62185d0SChao Yu 			FALLOC_FL_COLLAPSE_RANGE | FALLOC_FL_ZERO_RANGE |
1863f62185d0SChao Yu 			FALLOC_FL_INSERT_RANGE))
1864fbfa2cc5SJaegeuk Kim 		return -EOPNOTSUPP;
1865fbfa2cc5SJaegeuk Kim 
18665955102cSAl Viro 	inode_lock(inode);
18673375f696SChao Yu 
18685632bdb4SChao Yu 	/*
18695632bdb4SChao Yu 	 * Pinned file should not support partial truncation since the block
18705632bdb4SChao Yu 	 * can be used by applications.
18715632bdb4SChao Yu 	 */
18725632bdb4SChao Yu 	if ((f2fs_compressed_file(inode) || f2fs_is_pinned_file(inode)) &&
18735632bdb4SChao Yu 		(mode & (FALLOC_FL_PUNCH_HOLE | FALLOC_FL_COLLAPSE_RANGE |
18745632bdb4SChao Yu 			FALLOC_FL_ZERO_RANGE | FALLOC_FL_INSERT_RANGE))) {
18755632bdb4SChao Yu 		ret = -EOPNOTSUPP;
18765632bdb4SChao Yu 		goto out;
18775632bdb4SChao Yu 	}
18785632bdb4SChao Yu 
1879958ed929SChao Yu 	ret = file_modified(file);
1880958ed929SChao Yu 	if (ret)
1881958ed929SChao Yu 		goto out;
1882958ed929SChao Yu 
1883*c2a7fc51SChao Yu 	/*
1884*c2a7fc51SChao Yu 	 * wait for inflight dio, blocks should be removed after IO
1885*c2a7fc51SChao Yu 	 * completion.
1886*c2a7fc51SChao Yu 	 */
1887*c2a7fc51SChao Yu 	inode_dio_wait(inode);
1888*c2a7fc51SChao Yu 
1889587c0a42STaehee Yoo 	if (mode & FALLOC_FL_PUNCH_HOLE) {
1890587c0a42STaehee Yoo 		if (offset >= inode->i_size)
1891587c0a42STaehee Yoo 			goto out;
1892587c0a42STaehee Yoo 
18931cd75654SYangtao Li 		ret = f2fs_punch_hole(inode, offset, len);
1894b4ace337SChao Yu 	} else if (mode & FALLOC_FL_COLLAPSE_RANGE) {
1895b4ace337SChao Yu 		ret = f2fs_collapse_range(inode, offset, len);
189675cd4e09SChao Yu 	} else if (mode & FALLOC_FL_ZERO_RANGE) {
189775cd4e09SChao Yu 		ret = f2fs_zero_range(inode, offset, len, mode);
1898f62185d0SChao Yu 	} else if (mode & FALLOC_FL_INSERT_RANGE) {
1899f62185d0SChao Yu 		ret = f2fs_insert_range(inode, offset, len);
1900b4ace337SChao Yu 	} else {
19011cd75654SYangtao Li 		ret = f2fs_expand_inode_data(inode, offset, len, mode);
1902b4ace337SChao Yu 	}
1903fbfa2cc5SJaegeuk Kim 
19043af60a49SNamjae Jeon 	if (!ret) {
1905c62ebd35SJeff Layton 		inode->i_mtime = inode_set_ctime_current(inode);
19067c45729aSJaegeuk Kim 		f2fs_mark_inode_dirty_sync(inode, false);
1907d0239e1bSJaegeuk Kim 		f2fs_update_time(F2FS_I_SB(inode), REQ_TIME);
19083af60a49SNamjae Jeon 	}
19093375f696SChao Yu 
1910587c0a42STaehee Yoo out:
19115955102cSAl Viro 	inode_unlock(inode);
19123375f696SChao Yu 
1913c01e2853SNamjae Jeon 	trace_f2fs_fallocate(inode, mode, offset, len, ret);
1914fbfa2cc5SJaegeuk Kim 	return ret;
1915fbfa2cc5SJaegeuk Kim }
1916fbfa2cc5SJaegeuk Kim 
f2fs_release_file(struct inode * inode,struct file * filp)19171e84371fSJaegeuk Kim static int f2fs_release_file(struct inode *inode, struct file *filp)
19181e84371fSJaegeuk Kim {
1919de5307e4SJaegeuk Kim 	/*
1920146949deSJinyoung CHOI 	 * f2fs_release_file is called at every close calls. So we should
1921de5307e4SJaegeuk Kim 	 * not drop any inmemory pages by close called by other process.
1922de5307e4SJaegeuk Kim 	 */
1923de5307e4SJaegeuk Kim 	if (!(filp->f_mode & FMODE_WRITE) ||
1924de5307e4SJaegeuk Kim 			atomic_read(&inode->i_writecount) != 1)
1925de5307e4SJaegeuk Kim 		return 0;
1926de5307e4SJaegeuk Kim 
1927a46bebd5SDaeho Jeong 	inode_lock(inode);
19283db1de0eSDaeho Jeong 	f2fs_abort_atomic_write(inode, true);
1929a46bebd5SDaeho Jeong 	inode_unlock(inode);
1930a46bebd5SDaeho Jeong 
19311e84371fSJaegeuk Kim 	return 0;
19321e84371fSJaegeuk Kim }
19331e84371fSJaegeuk Kim 
f2fs_file_flush(struct file * file,fl_owner_t id)19347a10f017SJaegeuk Kim static int f2fs_file_flush(struct file *file, fl_owner_t id)
1935fbfa2cc5SJaegeuk Kim {
19367a10f017SJaegeuk Kim 	struct inode *inode = file_inode(file);
19377a10f017SJaegeuk Kim 
19387a10f017SJaegeuk Kim 	/*
19397a10f017SJaegeuk Kim 	 * If the process doing a transaction is crashed, we should do
19407a10f017SJaegeuk Kim 	 * roll-back. Otherwise, other reader/write can see corrupted database
19417a10f017SJaegeuk Kim 	 * until all the writers close its file. Since this should be done
19427a10f017SJaegeuk Kim 	 * before dropping file lock, it needs to do in ->flush.
19437a10f017SJaegeuk Kim 	 */
1944ae267fc1SChao Yu 	if (F2FS_I(inode)->atomic_write_task == current &&
1945a46bebd5SDaeho Jeong 				(current->flags & PF_EXITING)) {
1946a46bebd5SDaeho Jeong 		inode_lock(inode);
19473db1de0eSDaeho Jeong 		f2fs_abort_atomic_write(inode, true);
1948a46bebd5SDaeho Jeong 		inode_unlock(inode);
1949a46bebd5SDaeho Jeong 	}
1950a46bebd5SDaeho Jeong 
19517a10f017SJaegeuk Kim 	return 0;
1952fbfa2cc5SJaegeuk Kim }
1953fbfa2cc5SJaegeuk Kim 
f2fs_setflags_common(struct inode * inode,u32 iflags,u32 mask)195436098557SEric Biggers static int f2fs_setflags_common(struct inode *inode, u32 iflags, u32 mask)
19552c1d0305SChao Yu {
19562c1d0305SChao Yu 	struct f2fs_inode_info *fi = F2FS_I(inode);
195799eabb91SJaegeuk Kim 	u32 masked_flags = fi->i_flags & mask;
195899eabb91SJaegeuk Kim 
1959a7531039SJaegeuk Kim 	/* mask can be shrunk by flags_valid selector */
1960a7531039SJaegeuk Kim 	iflags &= mask;
19612c1d0305SChao Yu 
19622c1d0305SChao Yu 	/* Is it quota file? Do not allow user to mess with it */
19632c1d0305SChao Yu 	if (IS_NOQUOTA(inode))
19642c1d0305SChao Yu 		return -EPERM;
19652c1d0305SChao Yu 
196699eabb91SJaegeuk Kim 	if ((iflags ^ masked_flags) & F2FS_CASEFOLD_FL) {
19672c2eb7a3SDaniel Rosenberg 		if (!f2fs_sb_has_casefold(F2FS_I_SB(inode)))
19682c2eb7a3SDaniel Rosenberg 			return -EOPNOTSUPP;
19692c2eb7a3SDaniel Rosenberg 		if (!f2fs_empty_dir(inode))
19702c2eb7a3SDaniel Rosenberg 			return -ENOTEMPTY;
19712c2eb7a3SDaniel Rosenberg 	}
19722c2eb7a3SDaniel Rosenberg 
19734c8ff709SChao Yu 	if (iflags & (F2FS_COMPR_FL | F2FS_NOCOMP_FL)) {
19744c8ff709SChao Yu 		if (!f2fs_sb_has_compression(F2FS_I_SB(inode)))
19754c8ff709SChao Yu 			return -EOPNOTSUPP;
19764c8ff709SChao Yu 		if ((iflags & F2FS_COMPR_FL) && (iflags & F2FS_NOCOMP_FL))
19774c8ff709SChao Yu 			return -EINVAL;
19784c8ff709SChao Yu 	}
19794c8ff709SChao Yu 
198099eabb91SJaegeuk Kim 	if ((iflags ^ masked_flags) & F2FS_COMPR_FL) {
1981aa576970SChao Yu 		if (masked_flags & F2FS_COMPR_FL) {
198278134d03SDaeho Jeong 			if (!f2fs_disable_compressed_file(inode))
19834c8ff709SChao Yu 				return -EINVAL;
19848ee236dcSChao Liu 		} else {
1985a995627eSJaegeuk Kim 			/* try to convert inline_data to support compression */
1986a995627eSJaegeuk Kim 			int err = f2fs_convert_inline_inode(inode);
1987a995627eSJaegeuk Kim 			if (err)
1988a995627eSJaegeuk Kim 				return err;
1989b5ab3276SChao Yu 
1990b5ab3276SChao Yu 			f2fs_down_write(&F2FS_I(inode)->i_sem);
1991b5ab3276SChao Yu 			if (!f2fs_may_compress(inode) ||
1992b5ab3276SChao Yu 					(S_ISREG(inode->i_mode) &&
1993b5ab3276SChao Yu 					F2FS_HAS_BLOCKS(inode))) {
1994b5ab3276SChao Yu 				f2fs_up_write(&F2FS_I(inode)->i_sem);
19954c8ff709SChao Yu 				return -EINVAL;
1996b5ab3276SChao Yu 			}
1997b5ab3276SChao Yu 			err = set_compress_context(inode);
1998b5ab3276SChao Yu 			f2fs_up_write(&F2FS_I(inode)->i_sem);
1999b5ab3276SChao Yu 
2000b5ab3276SChao Yu 			if (err)
2001b5ab3276SChao Yu 				return err;
20024c8ff709SChao Yu 		}
20034c8ff709SChao Yu 	}
20044c8ff709SChao Yu 
2005d5e5efa2SEric Biggers 	fi->i_flags = iflags | (fi->i_flags & ~mask);
20064c8ff709SChao Yu 	f2fs_bug_on(F2FS_I_SB(inode), (fi->i_flags & F2FS_COMPR_FL) &&
20074c8ff709SChao Yu 					(fi->i_flags & F2FS_NOCOMP_FL));
20082c1d0305SChao Yu 
200959c84408SChao Yu 	if (fi->i_flags & F2FS_PROJINHERIT_FL)
20102c1d0305SChao Yu 		set_inode_flag(inode, FI_PROJ_INHERIT);
20112c1d0305SChao Yu 	else
20122c1d0305SChao Yu 		clear_inode_flag(inode, FI_PROJ_INHERIT);
20132c1d0305SChao Yu 
2014c62ebd35SJeff Layton 	inode_set_ctime_current(inode);
20152c1d0305SChao Yu 	f2fs_set_inode_flags(inode);
2016b32e0190SChao Yu 	f2fs_mark_inode_dirty_sync(inode, true);
20172c1d0305SChao Yu 	return 0;
20182c1d0305SChao Yu }
20192c1d0305SChao Yu 
20209b1bb01cSMiklos Szeredi /* FS_IOC_[GS]ETFLAGS and FS_IOC_FS[GS]ETXATTR support */
202136098557SEric Biggers 
202236098557SEric Biggers /*
202336098557SEric Biggers  * To make a new on-disk f2fs i_flag gettable via FS_IOC_GETFLAGS, add an entry
202436098557SEric Biggers  * for it to f2fs_fsflags_map[], and add its FS_*_FL equivalent to
202536098557SEric Biggers  * F2FS_GETTABLE_FS_FL.  To also make it settable via FS_IOC_SETFLAGS, also add
202636098557SEric Biggers  * its FS_*_FL equivalent to F2FS_SETTABLE_FS_FL.
20279b1bb01cSMiklos Szeredi  *
20289b1bb01cSMiklos Szeredi  * Translating flags to fsx_flags value used by FS_IOC_FSGETXATTR and
20299b1bb01cSMiklos Szeredi  * FS_IOC_FSSETXATTR is done by the VFS.
203036098557SEric Biggers  */
203136098557SEric Biggers 
203236098557SEric Biggers static const struct {
203336098557SEric Biggers 	u32 iflag;
203436098557SEric Biggers 	u32 fsflag;
203536098557SEric Biggers } f2fs_fsflags_map[] = {
20364c8ff709SChao Yu 	{ F2FS_COMPR_FL,	FS_COMPR_FL },
203736098557SEric Biggers 	{ F2FS_SYNC_FL,		FS_SYNC_FL },
203836098557SEric Biggers 	{ F2FS_IMMUTABLE_FL,	FS_IMMUTABLE_FL },
203936098557SEric Biggers 	{ F2FS_APPEND_FL,	FS_APPEND_FL },
204036098557SEric Biggers 	{ F2FS_NODUMP_FL,	FS_NODUMP_FL },
204136098557SEric Biggers 	{ F2FS_NOATIME_FL,	FS_NOATIME_FL },
20424c8ff709SChao Yu 	{ F2FS_NOCOMP_FL,	FS_NOCOMP_FL },
204336098557SEric Biggers 	{ F2FS_INDEX_FL,	FS_INDEX_FL },
204436098557SEric Biggers 	{ F2FS_DIRSYNC_FL,	FS_DIRSYNC_FL },
204536098557SEric Biggers 	{ F2FS_PROJINHERIT_FL,	FS_PROJINHERIT_FL },
20462c2eb7a3SDaniel Rosenberg 	{ F2FS_CASEFOLD_FL,	FS_CASEFOLD_FL },
204736098557SEric Biggers };
204836098557SEric Biggers 
204936098557SEric Biggers #define F2FS_GETTABLE_FS_FL (		\
20504c8ff709SChao Yu 		FS_COMPR_FL |		\
205136098557SEric Biggers 		FS_SYNC_FL |		\
205236098557SEric Biggers 		FS_IMMUTABLE_FL |	\
205336098557SEric Biggers 		FS_APPEND_FL |		\
205436098557SEric Biggers 		FS_NODUMP_FL |		\
205536098557SEric Biggers 		FS_NOATIME_FL |		\
20564c8ff709SChao Yu 		FS_NOCOMP_FL |		\
205736098557SEric Biggers 		FS_INDEX_FL |		\
205836098557SEric Biggers 		FS_DIRSYNC_FL |		\
205936098557SEric Biggers 		FS_PROJINHERIT_FL |	\
206036098557SEric Biggers 		FS_ENCRYPT_FL |		\
206136098557SEric Biggers 		FS_INLINE_DATA_FL |	\
206295ae251fSEric Biggers 		FS_NOCOW_FL |		\
2063fbc246a1SLinus Torvalds 		FS_VERITY_FL |		\
20642c2eb7a3SDaniel Rosenberg 		FS_CASEFOLD_FL)
206536098557SEric Biggers 
206636098557SEric Biggers #define F2FS_SETTABLE_FS_FL (		\
20674c8ff709SChao Yu 		FS_COMPR_FL |		\
206836098557SEric Biggers 		FS_SYNC_FL |		\
206936098557SEric Biggers 		FS_IMMUTABLE_FL |	\
207036098557SEric Biggers 		FS_APPEND_FL |		\
207136098557SEric Biggers 		FS_NODUMP_FL |		\
207236098557SEric Biggers 		FS_NOATIME_FL |		\
20734c8ff709SChao Yu 		FS_NOCOMP_FL |		\
207436098557SEric Biggers 		FS_DIRSYNC_FL |		\
20752c2eb7a3SDaniel Rosenberg 		FS_PROJINHERIT_FL |	\
20762c2eb7a3SDaniel Rosenberg 		FS_CASEFOLD_FL)
207736098557SEric Biggers 
207836098557SEric Biggers /* Convert f2fs on-disk i_flags to FS_IOC_{GET,SET}FLAGS flags */
f2fs_iflags_to_fsflags(u32 iflags)207936098557SEric Biggers static inline u32 f2fs_iflags_to_fsflags(u32 iflags)
208036098557SEric Biggers {
208136098557SEric Biggers 	u32 fsflags = 0;
208236098557SEric Biggers 	int i;
208336098557SEric Biggers 
208436098557SEric Biggers 	for (i = 0; i < ARRAY_SIZE(f2fs_fsflags_map); i++)
208536098557SEric Biggers 		if (iflags & f2fs_fsflags_map[i].iflag)
208636098557SEric Biggers 			fsflags |= f2fs_fsflags_map[i].fsflag;
208736098557SEric Biggers 
208836098557SEric Biggers 	return fsflags;
208936098557SEric Biggers }
209036098557SEric Biggers 
209136098557SEric Biggers /* Convert FS_IOC_{GET,SET}FLAGS flags to f2fs on-disk i_flags */
f2fs_fsflags_to_iflags(u32 fsflags)209236098557SEric Biggers static inline u32 f2fs_fsflags_to_iflags(u32 fsflags)
209336098557SEric Biggers {
209436098557SEric Biggers 	u32 iflags = 0;
209536098557SEric Biggers 	int i;
209636098557SEric Biggers 
209736098557SEric Biggers 	for (i = 0; i < ARRAY_SIZE(f2fs_fsflags_map); i++)
209836098557SEric Biggers 		if (fsflags & f2fs_fsflags_map[i].fsflag)
209936098557SEric Biggers 			iflags |= f2fs_fsflags_map[i].iflag;
210036098557SEric Biggers 
210136098557SEric Biggers 	return iflags;
210236098557SEric Biggers }
210336098557SEric Biggers 
f2fs_ioc_getversion(struct file * filp,unsigned long arg)2104d49f3e89SChao Yu static int f2fs_ioc_getversion(struct file *filp, unsigned long arg)
2105d49f3e89SChao Yu {
2106d49f3e89SChao Yu 	struct inode *inode = file_inode(filp);
2107d49f3e89SChao Yu 
2108d49f3e89SChao Yu 	return put_user(inode->i_generation, (int __user *)arg);
2109d49f3e89SChao Yu }
2110d49f3e89SChao Yu 
f2fs_ioc_start_atomic_write(struct file * filp,bool truncate)211141e8f85aSDaeho Jeong static int f2fs_ioc_start_atomic_write(struct file *filp, bool truncate)
211288b88a66SJaegeuk Kim {
211388b88a66SJaegeuk Kim 	struct inode *inode = file_inode(filp);
2114f2d40141SChristian Brauner 	struct mnt_idmap *idmap = file_mnt_idmap(filp);
2115743b620cSJaegeuk Kim 	struct f2fs_inode_info *fi = F2FS_I(inode);
2116743b620cSJaegeuk Kim 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
21174d8d45dfSDaeho Jeong 	loff_t isize;
2118f4c9c743SChao Yu 	int ret;
211988b88a66SJaegeuk Kim 
21205e0de753SJann Horn 	if (!(filp->f_mode & FMODE_WRITE))
21215e0de753SJann Horn 		return -EBADF;
21225e0de753SJann Horn 
212301beba79SChristian Brauner 	if (!inode_owner_or_capable(idmap, inode))
212488b88a66SJaegeuk Kim 		return -EACCES;
212588b88a66SJaegeuk Kim 
2126e811898cSJaegeuk Kim 	if (!S_ISREG(inode->i_mode))
2127e811898cSJaegeuk Kim 		return -EINVAL;
2128e811898cSJaegeuk Kim 
2129038d0698SChao Yu 	if (filp->f_flags & O_DIRECT)
2130038d0698SChao Yu 		return -EINVAL;
2131038d0698SChao Yu 
21327fb17fe4SChao Yu 	ret = mnt_want_write_file(filp);
21337fb17fe4SChao Yu 	if (ret)
21347fb17fe4SChao Yu 		return ret;
21357fb17fe4SChao Yu 
21360fac558bSChao Yu 	inode_lock(inode);
21370fac558bSChao Yu 
21389b56adcfSFengnan Chang 	if (!f2fs_disable_compressed_file(inode)) {
21399b56adcfSFengnan Chang 		ret = -EINVAL;
21409b56adcfSFengnan Chang 		goto out;
21419b56adcfSFengnan Chang 	}
21424c8ff709SChao Yu 
21433db1de0eSDaeho Jeong 	if (f2fs_is_atomic_file(inode))
21447fb17fe4SChao Yu 		goto out;
214588b88a66SJaegeuk Kim 
2146f4c9c743SChao Yu 	ret = f2fs_convert_inline_inode(inode);
2147f4c9c743SChao Yu 	if (ret)
21487fb17fe4SChao Yu 		goto out;
214988b88a66SJaegeuk Kim 
2150054cb289SYufen Yu 	f2fs_down_write(&fi->i_gc_rwsem[WRITE]);
21516f8d4455SJaegeuk Kim 
215231867b23SJaegeuk Kim 	/*
215331867b23SJaegeuk Kim 	 * Should wait end_io to count F2FS_WB_CP_DATA correctly by
215431867b23SJaegeuk Kim 	 * f2fs_is_atomic_file.
215531867b23SJaegeuk Kim 	 */
215631867b23SJaegeuk Kim 	if (get_dirty_pages(inode))
2157054cb289SYufen Yu 		f2fs_warn(sbi, "Unexpected flush for atomic writes: ino=%lu, npages=%u",
2158c27753d6SJaegeuk Kim 			  inode->i_ino, get_dirty_pages(inode));
2159c27753d6SJaegeuk Kim 	ret = filemap_write_and_wait_range(inode->i_mapping, 0, LLONG_MAX);
21606f8d4455SJaegeuk Kim 	if (ret) {
2161054cb289SYufen Yu 		f2fs_up_write(&fi->i_gc_rwsem[WRITE]);
2162684ca7e5SKinglong Mee 		goto out;
21636f8d4455SJaegeuk Kim 	}
216431867b23SJaegeuk Kim 
2165a46bebd5SDaeho Jeong 	/* Check if the inode already has a COW inode */
2166a46bebd5SDaeho Jeong 	if (fi->cow_inode == NULL) {
21673db1de0eSDaeho Jeong 		/* Create a COW inode for atomic write */
216887f9d26fSYeongjin Gil 		struct dentry *dentry = file_dentry(filp);
216987f9d26fSYeongjin Gil 		struct inode *dir = d_inode(dentry->d_parent);
21703db1de0eSDaeho Jeong 
217187f9d26fSYeongjin Gil 		ret = f2fs_get_tmpfile(idmap, dir, &fi->cow_inode);
21723db1de0eSDaeho Jeong 		if (ret) {
2173054cb289SYufen Yu 			f2fs_up_write(&fi->i_gc_rwsem[WRITE]);
21743db1de0eSDaeho Jeong 			goto out;
21753db1de0eSDaeho Jeong 		}
21764d8d45dfSDaeho Jeong 
2177a46bebd5SDaeho Jeong 		set_inode_flag(fi->cow_inode, FI_COW_FILE);
2178a46bebd5SDaeho Jeong 		clear_inode_flag(fi->cow_inode, FI_INLINE_DATA);
2179b82d4300SSunmin Jeong 
2180b82d4300SSunmin Jeong 		/* Set the COW inode's atomic_inode to the atomic inode */
2181b82d4300SSunmin Jeong 		F2FS_I(fi->cow_inode)->atomic_inode = inode;
2182a46bebd5SDaeho Jeong 	} else {
2183a46bebd5SDaeho Jeong 		/* Reuse the already created COW inode */
2184783b6ca3SChao Yu 		f2fs_bug_on(sbi, get_dirty_pages(fi->cow_inode));
2185783b6ca3SChao Yu 
2186783b6ca3SChao Yu 		invalidate_mapping_pages(fi->cow_inode->i_mapping, 0, -1);
2187783b6ca3SChao Yu 
2188b851ee6bSChao Yu 		ret = f2fs_do_truncate_blocks(fi->cow_inode, 0, true);
2189b851ee6bSChao Yu 		if (ret) {
2190b851ee6bSChao Yu 			f2fs_up_write(&fi->i_gc_rwsem[WRITE]);
2191b851ee6bSChao Yu 			goto out;
2192b851ee6bSChao Yu 		}
2193a46bebd5SDaeho Jeong 	}
2194a46bebd5SDaeho Jeong 
21954d8d45dfSDaeho Jeong 	f2fs_write_inode(inode, NULL);
21963db1de0eSDaeho Jeong 
2197b4dac120SChao Yu 	stat_inc_atomic_inode(inode);
2198743b620cSJaegeuk Kim 
2199054afda9SYunlei He 	set_inode_flag(inode, FI_ATOMIC_FILE);
220041e8f85aSDaeho Jeong 
220141e8f85aSDaeho Jeong 	isize = i_size_read(inode);
220241e8f85aSDaeho Jeong 	fi->original_i_size = isize;
220341e8f85aSDaeho Jeong 	if (truncate) {
220441e8f85aSDaeho Jeong 		set_inode_flag(inode, FI_ATOMIC_REPLACE);
220541e8f85aSDaeho Jeong 		truncate_inode_pages_final(inode->i_mapping);
220641e8f85aSDaeho Jeong 		f2fs_i_size_write(inode, 0);
220741e8f85aSDaeho Jeong 		isize = 0;
220841e8f85aSDaeho Jeong 	}
220941e8f85aSDaeho Jeong 	f2fs_i_size_write(fi->cow_inode, isize);
221041e8f85aSDaeho Jeong 
2211054cb289SYufen Yu 	f2fs_up_write(&fi->i_gc_rwsem[WRITE]);
2212684ca7e5SKinglong Mee 
2213054cb289SYufen Yu 	f2fs_update_time(sbi, REQ_TIME);
2214054cb289SYufen Yu 	fi->atomic_write_task = current;
221526a28a0cSJaegeuk Kim 	stat_update_max_atomic_write(inode);
2216f8e2f32bSDaeho Jeong 	fi->atomic_write_cnt = 0;
2217684ca7e5SKinglong Mee out:
22180fac558bSChao Yu 	inode_unlock(inode);
22197fb17fe4SChao Yu 	mnt_drop_write_file(filp);
2220c27753d6SJaegeuk Kim 	return ret;
222188b88a66SJaegeuk Kim }
222288b88a66SJaegeuk Kim 
f2fs_ioc_commit_atomic_write(struct file * filp)222388b88a66SJaegeuk Kim static int f2fs_ioc_commit_atomic_write(struct file *filp)
222488b88a66SJaegeuk Kim {
222588b88a66SJaegeuk Kim 	struct inode *inode = file_inode(filp);
222601beba79SChristian Brauner 	struct mnt_idmap *idmap = file_mnt_idmap(filp);
222788b88a66SJaegeuk Kim 	int ret;
222888b88a66SJaegeuk Kim 
22295e0de753SJann Horn 	if (!(filp->f_mode & FMODE_WRITE))
22305e0de753SJann Horn 		return -EBADF;
22315e0de753SJann Horn 
223201beba79SChristian Brauner 	if (!inode_owner_or_capable(idmap, inode))
223388b88a66SJaegeuk Kim 		return -EACCES;
223488b88a66SJaegeuk Kim 
223588b88a66SJaegeuk Kim 	ret = mnt_want_write_file(filp);
223688b88a66SJaegeuk Kim 	if (ret)
223788b88a66SJaegeuk Kim 		return ret;
223888b88a66SJaegeuk Kim 
22396f8d4455SJaegeuk Kim 	f2fs_balance_fs(F2FS_I_SB(inode), true);
22400fac558bSChao Yu 
22416f8d4455SJaegeuk Kim 	inode_lock(inode);
22421dc0f899SChao Yu 
22436282adbfSJaegeuk Kim 	if (f2fs_is_atomic_file(inode)) {
22443db1de0eSDaeho Jeong 		ret = f2fs_commit_atomic_write(inode);
2245743b620cSJaegeuk Kim 		if (!ret)
22464d8d45dfSDaeho Jeong 			ret = f2fs_do_sync_file(filp, 0, LLONG_MAX, 0, true);
22474d8d45dfSDaeho Jeong 
22484d8d45dfSDaeho Jeong 		f2fs_abort_atomic_write(inode, ret);
224926a28a0cSJaegeuk Kim 	} else {
2250774e1b78SChao Yu 		ret = f2fs_do_sync_file(filp, 0, LLONG_MAX, 1, false);
225126a28a0cSJaegeuk Kim 	}
22524d8d45dfSDaeho Jeong 
22530fac558bSChao Yu 	inode_unlock(inode);
225488b88a66SJaegeuk Kim 	mnt_drop_write_file(filp);
225588b88a66SJaegeuk Kim 	return ret;
225688b88a66SJaegeuk Kim }
225788b88a66SJaegeuk Kim 
f2fs_ioc_abort_atomic_write(struct file * filp)225823339e57SDaeho Jeong static int f2fs_ioc_abort_atomic_write(struct file *filp)
225923339e57SDaeho Jeong {
226023339e57SDaeho Jeong 	struct inode *inode = file_inode(filp);
226101beba79SChristian Brauner 	struct mnt_idmap *idmap = file_mnt_idmap(filp);
226223339e57SDaeho Jeong 	int ret;
226323339e57SDaeho Jeong 
22645e0de753SJann Horn 	if (!(filp->f_mode & FMODE_WRITE))
22655e0de753SJann Horn 		return -EBADF;
22665e0de753SJann Horn 
226701beba79SChristian Brauner 	if (!inode_owner_or_capable(idmap, inode))
226823339e57SDaeho Jeong 		return -EACCES;
226923339e57SDaeho Jeong 
227023339e57SDaeho Jeong 	ret = mnt_want_write_file(filp);
227123339e57SDaeho Jeong 	if (ret)
227223339e57SDaeho Jeong 		return ret;
227323339e57SDaeho Jeong 
227423339e57SDaeho Jeong 	inode_lock(inode);
227523339e57SDaeho Jeong 
227623339e57SDaeho Jeong 	f2fs_abort_atomic_write(inode, true);
227723339e57SDaeho Jeong 
227823339e57SDaeho Jeong 	inode_unlock(inode);
227923339e57SDaeho Jeong 
228023339e57SDaeho Jeong 	mnt_drop_write_file(filp);
228123339e57SDaeho Jeong 	f2fs_update_time(F2FS_I_SB(inode), REQ_TIME);
228223339e57SDaeho Jeong 	return ret;
228323339e57SDaeho Jeong }
228423339e57SDaeho Jeong 
f2fs_do_shutdown(struct f2fs_sb_info * sbi,unsigned int flag,bool readonly,bool need_lock)2285f2971778SChao Yu int f2fs_do_shutdown(struct f2fs_sb_info *sbi, unsigned int flag,
2286fc18e655SChao Yu 						bool readonly, bool need_lock)
22871abff93dSJaegeuk Kim {
22881abff93dSJaegeuk Kim 	struct super_block *sb = sbi->sb;
22892a96d8adSDan Carpenter 	int ret = 0;
22901abff93dSJaegeuk Kim 
2291f2971778SChao Yu 	switch (flag) {
22921abff93dSJaegeuk Kim 	case F2FS_GOING_DOWN_FULLSYNC:
2293040f04bdSChristoph Hellwig 		ret = freeze_bdev(sb->s_bdev);
2294040f04bdSChristoph Hellwig 		if (ret)
2295d027c484SChao Yu 			goto out;
2296a9cfee0eSChao Yu 		f2fs_stop_checkpoint(sbi, false, STOP_CP_REASON_SHUTDOWN);
2297040f04bdSChristoph Hellwig 		thaw_bdev(sb->s_bdev);
22981abff93dSJaegeuk Kim 		break;
22991abff93dSJaegeuk Kim 	case F2FS_GOING_DOWN_METASYNC:
23001abff93dSJaegeuk Kim 		/* do checkpoint only */
2301d027c484SChao Yu 		ret = f2fs_sync_fs(sb, 1);
2302d027c484SChao Yu 		if (ret)
2303d027c484SChao Yu 			goto out;
2304a9cfee0eSChao Yu 		f2fs_stop_checkpoint(sbi, false, STOP_CP_REASON_SHUTDOWN);
23051abff93dSJaegeuk Kim 		break;
23061abff93dSJaegeuk Kim 	case F2FS_GOING_DOWN_NOSYNC:
2307a9cfee0eSChao Yu 		f2fs_stop_checkpoint(sbi, false, STOP_CP_REASON_SHUTDOWN);
23081abff93dSJaegeuk Kim 		break;
2309c912a829SJaegeuk Kim 	case F2FS_GOING_DOWN_METAFLUSH:
23104d57b86dSChao Yu 		f2fs_sync_meta_pages(sbi, META, LONG_MAX, FS_META_IO);
2311a9cfee0eSChao Yu 		f2fs_stop_checkpoint(sbi, false, STOP_CP_REASON_SHUTDOWN);
2312c912a829SJaegeuk Kim 		break;
23130cd6d9b0SJaegeuk Kim 	case F2FS_GOING_DOWN_NEED_FSCK:
23140cd6d9b0SJaegeuk Kim 		set_sbi_flag(sbi, SBI_NEED_FSCK);
2315db610a64SJaegeuk Kim 		set_sbi_flag(sbi, SBI_CP_DISABLED_QUICK);
2316db610a64SJaegeuk Kim 		set_sbi_flag(sbi, SBI_IS_DIRTY);
23170cd6d9b0SJaegeuk Kim 		/* do checkpoint only */
23180cd6d9b0SJaegeuk Kim 		ret = f2fs_sync_fs(sb, 1);
23190cd6d9b0SJaegeuk Kim 		goto out;
23201abff93dSJaegeuk Kim 	default:
23217fb17fe4SChao Yu 		ret = -EINVAL;
23227fb17fe4SChao Yu 		goto out;
23231abff93dSJaegeuk Kim 	}
23247950e9acSChao Yu 
2325f2971778SChao Yu 	if (readonly)
2326f2971778SChao Yu 		goto out;
2327f2971778SChao Yu 
2328794fa879SLong Li 	/*
2329794fa879SLong Li 	 * grab sb->s_umount to avoid racing w/ remount() and other shutdown
2330794fa879SLong Li 	 * paths.
2331794fa879SLong Li 	 */
2332fc18e655SChao Yu 	if (need_lock)
2333794fa879SLong Li 		down_write(&sbi->sb->s_umount);
2334fc18e655SChao Yu 
23354d57b86dSChao Yu 	f2fs_stop_gc_thread(sbi);
23364d57b86dSChao Yu 	f2fs_stop_discard_thread(sbi);
23377950e9acSChao Yu 
23384d57b86dSChao Yu 	f2fs_drop_discard_cmd(sbi);
23397950e9acSChao Yu 	clear_opt(sbi, DISCARD);
23407950e9acSChao Yu 
2341fc18e655SChao Yu 	if (need_lock)
2342794fa879SLong Li 		up_write(&sbi->sb->s_umount);
2343fc18e655SChao Yu 
2344d0239e1bSJaegeuk Kim 	f2fs_update_time(sbi, REQ_TIME);
23457fb17fe4SChao Yu out:
2346559e87c4SChao Yu 
2347f2971778SChao Yu 	trace_f2fs_shutdown(sbi, flag, ret);
2348f2971778SChao Yu 
2349f2971778SChao Yu 	return ret;
2350f2971778SChao Yu }
2351f2971778SChao Yu 
f2fs_ioc_shutdown(struct file * filp,unsigned long arg)2352f2971778SChao Yu static int f2fs_ioc_shutdown(struct file *filp, unsigned long arg)
2353f2971778SChao Yu {
2354f2971778SChao Yu 	struct inode *inode = file_inode(filp);
2355f2971778SChao Yu 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
2356f2971778SChao Yu 	__u32 in;
2357f2971778SChao Yu 	int ret;
2358f2971778SChao Yu 	bool need_drop = false, readonly = false;
2359f2971778SChao Yu 
2360f2971778SChao Yu 	if (!capable(CAP_SYS_ADMIN))
2361f2971778SChao Yu 		return -EPERM;
2362f2971778SChao Yu 
2363f2971778SChao Yu 	if (get_user(in, (__u32 __user *)arg))
2364f2971778SChao Yu 		return -EFAULT;
2365f2971778SChao Yu 
2366f2971778SChao Yu 	if (in != F2FS_GOING_DOWN_FULLSYNC) {
2367f2971778SChao Yu 		ret = mnt_want_write_file(filp);
2368f2971778SChao Yu 		if (ret) {
2369f2971778SChao Yu 			if (ret != -EROFS)
2370f2971778SChao Yu 				return ret;
2371f2971778SChao Yu 
2372f2971778SChao Yu 			/* fallback to nosync shutdown for readonly fs */
2373f2971778SChao Yu 			in = F2FS_GOING_DOWN_NOSYNC;
2374f2971778SChao Yu 			readonly = true;
2375f2971778SChao Yu 		} else {
2376f2971778SChao Yu 			need_drop = true;
2377f2971778SChao Yu 		}
2378f2971778SChao Yu 	}
2379f2971778SChao Yu 
2380fc18e655SChao Yu 	ret = f2fs_do_shutdown(sbi, in, readonly, true);
2381f2971778SChao Yu 
2382f2971778SChao Yu 	if (need_drop)
2383f2971778SChao Yu 		mnt_drop_write_file(filp);
2384559e87c4SChao Yu 
23857fb17fe4SChao Yu 	return ret;
23861abff93dSJaegeuk Kim }
23871abff93dSJaegeuk Kim 
f2fs_ioc_fitrim(struct file * filp,unsigned long arg)238852656e6cSJaegeuk Kim static int f2fs_ioc_fitrim(struct file *filp, unsigned long arg)
23894b2fecc8SJaegeuk Kim {
239052656e6cSJaegeuk Kim 	struct inode *inode = file_inode(filp);
23914b2fecc8SJaegeuk Kim 	struct super_block *sb = inode->i_sb;
23924b2fecc8SJaegeuk Kim 	struct fstrim_range range;
239352656e6cSJaegeuk Kim 	int ret;
23944b2fecc8SJaegeuk Kim 
23954b2fecc8SJaegeuk Kim 	if (!capable(CAP_SYS_ADMIN))
23964b2fecc8SJaegeuk Kim 		return -EPERM;
23974b2fecc8SJaegeuk Kim 
23987d20c8abSChao Yu 	if (!f2fs_hw_support_discard(F2FS_SB(sb)))
23994b2fecc8SJaegeuk Kim 		return -EOPNOTSUPP;
24004b2fecc8SJaegeuk Kim 
24014b2fecc8SJaegeuk Kim 	if (copy_from_user(&range, (struct fstrim_range __user *)arg,
24024b2fecc8SJaegeuk Kim 				sizeof(range)))
24034b2fecc8SJaegeuk Kim 		return -EFAULT;
24044b2fecc8SJaegeuk Kim 
24057fb17fe4SChao Yu 	ret = mnt_want_write_file(filp);
24067fb17fe4SChao Yu 	if (ret)
24077fb17fe4SChao Yu 		return ret;
24087fb17fe4SChao Yu 
24094b2fecc8SJaegeuk Kim 	range.minlen = max((unsigned int)range.minlen,
24107b47ef52SChristoph Hellwig 			   bdev_discard_granularity(sb->s_bdev));
24114b2fecc8SJaegeuk Kim 	ret = f2fs_trim_fs(F2FS_SB(sb), &range);
24127fb17fe4SChao Yu 	mnt_drop_write_file(filp);
24134b2fecc8SJaegeuk Kim 	if (ret < 0)
24144b2fecc8SJaegeuk Kim 		return ret;
24154b2fecc8SJaegeuk Kim 
24164b2fecc8SJaegeuk Kim 	if (copy_to_user((struct fstrim_range __user *)arg, &range,
24174b2fecc8SJaegeuk Kim 				sizeof(range)))
24184b2fecc8SJaegeuk Kim 		return -EFAULT;
2419d0239e1bSJaegeuk Kim 	f2fs_update_time(F2FS_I_SB(inode), REQ_TIME);
24204b2fecc8SJaegeuk Kim 	return 0;
24214b2fecc8SJaegeuk Kim }
242252656e6cSJaegeuk Kim 
uuid_is_nonzero(__u8 u[16])2423f424f664SJaegeuk Kim static bool uuid_is_nonzero(__u8 u[16])
2424f424f664SJaegeuk Kim {
2425f424f664SJaegeuk Kim 	int i;
2426f424f664SJaegeuk Kim 
2427f424f664SJaegeuk Kim 	for (i = 0; i < 16; i++)
2428f424f664SJaegeuk Kim 		if (u[i])
2429f424f664SJaegeuk Kim 			return true;
2430f424f664SJaegeuk Kim 	return false;
2431f424f664SJaegeuk Kim }
2432f424f664SJaegeuk Kim 
f2fs_ioc_set_encryption_policy(struct file * filp,unsigned long arg)2433f424f664SJaegeuk Kim static int f2fs_ioc_set_encryption_policy(struct file *filp, unsigned long arg)
2434f424f664SJaegeuk Kim {
2435f424f664SJaegeuk Kim 	struct inode *inode = file_inode(filp);
2436f424f664SJaegeuk Kim 
24377beb01f7SChao Yu 	if (!f2fs_sb_has_encrypt(F2FS_I_SB(inode)))
2438ead710b7SChao Yu 		return -EOPNOTSUPP;
2439ead710b7SChao Yu 
2440d0239e1bSJaegeuk Kim 	f2fs_update_time(F2FS_I_SB(inode), REQ_TIME);
24417fb17fe4SChao Yu 
2442db717d8eSEric Biggers 	return fscrypt_ioctl_set_policy(filp, (const void __user *)arg);
2443f424f664SJaegeuk Kim }
2444f424f664SJaegeuk Kim 
f2fs_ioc_get_encryption_policy(struct file * filp,unsigned long arg)2445f424f664SJaegeuk Kim static int f2fs_ioc_get_encryption_policy(struct file *filp, unsigned long arg)
2446f424f664SJaegeuk Kim {
24477beb01f7SChao Yu 	if (!f2fs_sb_has_encrypt(F2FS_I_SB(file_inode(filp))))
2448ead710b7SChao Yu 		return -EOPNOTSUPP;
2449db717d8eSEric Biggers 	return fscrypt_ioctl_get_policy(filp, (void __user *)arg);
2450f424f664SJaegeuk Kim }
2451f424f664SJaegeuk Kim 
f2fs_ioc_get_encryption_pwsalt(struct file * filp,unsigned long arg)2452f424f664SJaegeuk Kim static int f2fs_ioc_get_encryption_pwsalt(struct file *filp, unsigned long arg)
2453f424f664SJaegeuk Kim {
2454f424f664SJaegeuk Kim 	struct inode *inode = file_inode(filp);
2455f424f664SJaegeuk Kim 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
24565eaac835SChao Yu 	u8 encrypt_pw_salt[16];
2457f424f664SJaegeuk Kim 	int err;
2458f424f664SJaegeuk Kim 
24597beb01f7SChao Yu 	if (!f2fs_sb_has_encrypt(sbi))
2460f424f664SJaegeuk Kim 		return -EOPNOTSUPP;
2461f424f664SJaegeuk Kim 
2462f424f664SJaegeuk Kim 	err = mnt_want_write_file(filp);
2463f424f664SJaegeuk Kim 	if (err)
2464f424f664SJaegeuk Kim 		return err;
2465f424f664SJaegeuk Kim 
2466e4544b63STim Murray 	f2fs_down_write(&sbi->sb_lock);
2467d0d3f1b3SChao Yu 
2468d0d3f1b3SChao Yu 	if (uuid_is_nonzero(sbi->raw_super->encrypt_pw_salt))
2469d0d3f1b3SChao Yu 		goto got_it;
2470d0d3f1b3SChao Yu 
2471f424f664SJaegeuk Kim 	/* update superblock with uuid */
2472f424f664SJaegeuk Kim 	generate_random_uuid(sbi->raw_super->encrypt_pw_salt);
2473f424f664SJaegeuk Kim 
2474c5bda1c8SChao Yu 	err = f2fs_commit_super(sbi, false);
2475f424f664SJaegeuk Kim 	if (err) {
2476f424f664SJaegeuk Kim 		/* undo new data */
2477f424f664SJaegeuk Kim 		memset(sbi->raw_super->encrypt_pw_salt, 0, 16);
2478d0d3f1b3SChao Yu 		goto out_err;
2479f424f664SJaegeuk Kim 	}
2480f424f664SJaegeuk Kim got_it:
24815eaac835SChao Yu 	memcpy(encrypt_pw_salt, sbi->raw_super->encrypt_pw_salt, 16);
2482d0d3f1b3SChao Yu out_err:
2483e4544b63STim Murray 	f2fs_up_write(&sbi->sb_lock);
2484d0d3f1b3SChao Yu 	mnt_drop_write_file(filp);
24855eaac835SChao Yu 
24865eaac835SChao Yu 	if (!err && copy_to_user((__u8 __user *)arg, encrypt_pw_salt, 16))
24875eaac835SChao Yu 		err = -EFAULT;
24885eaac835SChao Yu 
2489d0d3f1b3SChao Yu 	return err;
2490f424f664SJaegeuk Kim }
2491f424f664SJaegeuk Kim 
f2fs_ioc_get_encryption_policy_ex(struct file * filp,unsigned long arg)24928ce589c7SEric Biggers static int f2fs_ioc_get_encryption_policy_ex(struct file *filp,
24938ce589c7SEric Biggers 					     unsigned long arg)
24948ce589c7SEric Biggers {
24958ce589c7SEric Biggers 	if (!f2fs_sb_has_encrypt(F2FS_I_SB(file_inode(filp))))
24968ce589c7SEric Biggers 		return -EOPNOTSUPP;
24978ce589c7SEric Biggers 
24988ce589c7SEric Biggers 	return fscrypt_ioctl_get_policy_ex(filp, (void __user *)arg);
24998ce589c7SEric Biggers }
25008ce589c7SEric Biggers 
f2fs_ioc_add_encryption_key(struct file * filp,unsigned long arg)25018ce589c7SEric Biggers static int f2fs_ioc_add_encryption_key(struct file *filp, unsigned long arg)
25028ce589c7SEric Biggers {
25038ce589c7SEric Biggers 	if (!f2fs_sb_has_encrypt(F2FS_I_SB(file_inode(filp))))
25048ce589c7SEric Biggers 		return -EOPNOTSUPP;
25058ce589c7SEric Biggers 
25068ce589c7SEric Biggers 	return fscrypt_ioctl_add_key(filp, (void __user *)arg);
25078ce589c7SEric Biggers }
25088ce589c7SEric Biggers 
f2fs_ioc_remove_encryption_key(struct file * filp,unsigned long arg)25098ce589c7SEric Biggers static int f2fs_ioc_remove_encryption_key(struct file *filp, unsigned long arg)
25108ce589c7SEric Biggers {
25118ce589c7SEric Biggers 	if (!f2fs_sb_has_encrypt(F2FS_I_SB(file_inode(filp))))
25128ce589c7SEric Biggers 		return -EOPNOTSUPP;
25138ce589c7SEric Biggers 
25148ce589c7SEric Biggers 	return fscrypt_ioctl_remove_key(filp, (void __user *)arg);
25158ce589c7SEric Biggers }
25168ce589c7SEric Biggers 
f2fs_ioc_remove_encryption_key_all_users(struct file * filp,unsigned long arg)25178ce589c7SEric Biggers static int f2fs_ioc_remove_encryption_key_all_users(struct file *filp,
25188ce589c7SEric Biggers 						    unsigned long arg)
25198ce589c7SEric Biggers {
25208ce589c7SEric Biggers 	if (!f2fs_sb_has_encrypt(F2FS_I_SB(file_inode(filp))))
25218ce589c7SEric Biggers 		return -EOPNOTSUPP;
25228ce589c7SEric Biggers 
25238ce589c7SEric Biggers 	return fscrypt_ioctl_remove_key_all_users(filp, (void __user *)arg);
25248ce589c7SEric Biggers }
25258ce589c7SEric Biggers 
f2fs_ioc_get_encryption_key_status(struct file * filp,unsigned long arg)25268ce589c7SEric Biggers static int f2fs_ioc_get_encryption_key_status(struct file *filp,
25278ce589c7SEric Biggers 					      unsigned long arg)
25288ce589c7SEric Biggers {
25298ce589c7SEric Biggers 	if (!f2fs_sb_has_encrypt(F2FS_I_SB(file_inode(filp))))
25308ce589c7SEric Biggers 		return -EOPNOTSUPP;
25318ce589c7SEric Biggers 
25328ce589c7SEric Biggers 	return fscrypt_ioctl_get_key_status(filp, (void __user *)arg);
25338ce589c7SEric Biggers }
25348ce589c7SEric Biggers 
f2fs_ioc_get_encryption_nonce(struct file * filp,unsigned long arg)2535ee446e1aSEric Biggers static int f2fs_ioc_get_encryption_nonce(struct file *filp, unsigned long arg)
2536ee446e1aSEric Biggers {
2537ee446e1aSEric Biggers 	if (!f2fs_sb_has_encrypt(F2FS_I_SB(file_inode(filp))))
2538ee446e1aSEric Biggers 		return -EOPNOTSUPP;
2539ee446e1aSEric Biggers 
2540ee446e1aSEric Biggers 	return fscrypt_ioctl_get_nonce(filp, (void __user *)arg);
2541ee446e1aSEric Biggers }
2542ee446e1aSEric Biggers 
f2fs_ioc_gc(struct file * filp,unsigned long arg)2543c1c1b583SChao Yu static int f2fs_ioc_gc(struct file *filp, unsigned long arg)
2544c1c1b583SChao Yu {
2545c1c1b583SChao Yu 	struct inode *inode = file_inode(filp);
2546c1c1b583SChao Yu 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
2547d147ea4aSJaegeuk Kim 	struct f2fs_gc_control gc_control = { .victim_segno = NULL_SEGNO,
2548d147ea4aSJaegeuk Kim 			.no_bg_gc = false,
2549c81d5baeSJaegeuk Kim 			.should_migrate_blocks = false,
2550c81d5baeSJaegeuk Kim 			.nr_free_secs = 0 };
2551d530d4d8SChao Yu 	__u32 sync;
25527fb17fe4SChao Yu 	int ret;
2553c1c1b583SChao Yu 
2554c1c1b583SChao Yu 	if (!capable(CAP_SYS_ADMIN))
2555c1c1b583SChao Yu 		return -EPERM;
2556c1c1b583SChao Yu 
2557d530d4d8SChao Yu 	if (get_user(sync, (__u32 __user *)arg))
2558c1c1b583SChao Yu 		return -EFAULT;
2559c1c1b583SChao Yu 
2560d530d4d8SChao Yu 	if (f2fs_readonly(sbi->sb))
2561d530d4d8SChao Yu 		return -EROFS;
2562c1c1b583SChao Yu 
25637fb17fe4SChao Yu 	ret = mnt_want_write_file(filp);
25647fb17fe4SChao Yu 	if (ret)
25657fb17fe4SChao Yu 		return ret;
25667fb17fe4SChao Yu 
2567d530d4d8SChao Yu 	if (!sync) {
2568e4544b63STim Murray 		if (!f2fs_down_write_trylock(&sbi->gc_lock)) {
25697fb17fe4SChao Yu 			ret = -EBUSY;
25707fb17fe4SChao Yu 			goto out;
25717fb17fe4SChao Yu 		}
2572d530d4d8SChao Yu 	} else {
2573e4544b63STim Murray 		f2fs_down_write(&sbi->gc_lock);
2574c1c1b583SChao Yu 	}
2575c1c1b583SChao Yu 
2576d147ea4aSJaegeuk Kim 	gc_control.init_gc_type = sync ? FG_GC : BG_GC;
2577d147ea4aSJaegeuk Kim 	gc_control.err_gc_skipped = sync;
25789bf1dcbdSChao Yu 	stat_inc_gc_call_count(sbi, FOREGROUND);
2579d147ea4aSJaegeuk Kim 	ret = f2fs_gc(sbi, &gc_control);
25807fb17fe4SChao Yu out:
25817fb17fe4SChao Yu 	mnt_drop_write_file(filp);
25827fb17fe4SChao Yu 	return ret;
2583c1c1b583SChao Yu }
2584c1c1b583SChao Yu 
__f2fs_ioc_gc_range(struct file * filp,struct f2fs_gc_range * range)258534178b1bSChao Yu static int __f2fs_ioc_gc_range(struct file *filp, struct f2fs_gc_range *range)
258634dc77adSJaegeuk Kim {
258734178b1bSChao Yu 	struct f2fs_sb_info *sbi = F2FS_I_SB(file_inode(filp));
2588d147ea4aSJaegeuk Kim 	struct f2fs_gc_control gc_control = {
2589d147ea4aSJaegeuk Kim 			.init_gc_type = range->sync ? FG_GC : BG_GC,
2590d147ea4aSJaegeuk Kim 			.no_bg_gc = false,
2591d147ea4aSJaegeuk Kim 			.should_migrate_blocks = false,
2592c81d5baeSJaegeuk Kim 			.err_gc_skipped = range->sync,
2593c81d5baeSJaegeuk Kim 			.nr_free_secs = 0 };
259434dc77adSJaegeuk Kim 	u64 end;
259534dc77adSJaegeuk Kim 	int ret;
259634dc77adSJaegeuk Kim 
259734dc77adSJaegeuk Kim 	if (!capable(CAP_SYS_ADMIN))
259834dc77adSJaegeuk Kim 		return -EPERM;
259934dc77adSJaegeuk Kim 	if (f2fs_readonly(sbi->sb))
260034dc77adSJaegeuk Kim 		return -EROFS;
260134dc77adSJaegeuk Kim 
260234178b1bSChao Yu 	end = range->start + range->len;
260334178b1bSChao Yu 	if (end < range->start || range->start < MAIN_BLKADDR(sbi) ||
2604fbbf7799SSahitya Tummala 					end >= MAX_BLKADDR(sbi))
2605b82f6e34SYunlei He 		return -EINVAL;
2606b82f6e34SYunlei He 
260734dc77adSJaegeuk Kim 	ret = mnt_want_write_file(filp);
260834dc77adSJaegeuk Kim 	if (ret)
260934dc77adSJaegeuk Kim 		return ret;
261034dc77adSJaegeuk Kim 
261134dc77adSJaegeuk Kim do_more:
261234178b1bSChao Yu 	if (!range->sync) {
2613e4544b63STim Murray 		if (!f2fs_down_write_trylock(&sbi->gc_lock)) {
261434dc77adSJaegeuk Kim 			ret = -EBUSY;
261534dc77adSJaegeuk Kim 			goto out;
261634dc77adSJaegeuk Kim 		}
261734dc77adSJaegeuk Kim 	} else {
2618e4544b63STim Murray 		f2fs_down_write(&sbi->gc_lock);
261934dc77adSJaegeuk Kim 	}
262034dc77adSJaegeuk Kim 
2621d147ea4aSJaegeuk Kim 	gc_control.victim_segno = GET_SEGNO(sbi, range->start);
26229bf1dcbdSChao Yu 	stat_inc_gc_call_count(sbi, FOREGROUND);
2623d147ea4aSJaegeuk Kim 	ret = f2fs_gc(sbi, &gc_control);
262497767500SQilong Zhang 	if (ret) {
262597767500SQilong Zhang 		if (ret == -EBUSY)
262697767500SQilong Zhang 			ret = -EAGAIN;
262797767500SQilong Zhang 		goto out;
262897767500SQilong Zhang 	}
2629074b5ea2SJaegeuk Kim 	range->start += CAP_BLKS_PER_SEC(sbi);
263034178b1bSChao Yu 	if (range->start <= end)
263134dc77adSJaegeuk Kim 		goto do_more;
263234dc77adSJaegeuk Kim out:
263334dc77adSJaegeuk Kim 	mnt_drop_write_file(filp);
263434dc77adSJaegeuk Kim 	return ret;
263534dc77adSJaegeuk Kim }
263634dc77adSJaegeuk Kim 
f2fs_ioc_gc_range(struct file * filp,unsigned long arg)263734178b1bSChao Yu static int f2fs_ioc_gc_range(struct file *filp, unsigned long arg)
263834178b1bSChao Yu {
263934178b1bSChao Yu 	struct f2fs_gc_range range;
264034178b1bSChao Yu 
264134178b1bSChao Yu 	if (copy_from_user(&range, (struct f2fs_gc_range __user *)arg,
264234178b1bSChao Yu 							sizeof(range)))
264334178b1bSChao Yu 		return -EFAULT;
264434178b1bSChao Yu 	return __f2fs_ioc_gc_range(filp, &range);
264534178b1bSChao Yu }
264634178b1bSChao Yu 
f2fs_ioc_write_checkpoint(struct file * filp)2647ddf1eca4SYangtao Li static int f2fs_ioc_write_checkpoint(struct file *filp)
2648456b88e4SChao Yu {
2649456b88e4SChao Yu 	struct inode *inode = file_inode(filp);
2650456b88e4SChao Yu 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
26517fb17fe4SChao Yu 	int ret;
2652456b88e4SChao Yu 
2653456b88e4SChao Yu 	if (!capable(CAP_SYS_ADMIN))
2654456b88e4SChao Yu 		return -EPERM;
2655456b88e4SChao Yu 
2656456b88e4SChao Yu 	if (f2fs_readonly(sbi->sb))
2657456b88e4SChao Yu 		return -EROFS;
2658456b88e4SChao Yu 
26594354994fSDaniel Rosenberg 	if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED))) {
2660dcbb4c10SJoe Perches 		f2fs_info(sbi, "Skipping Checkpoint. Checkpoints currently disabled.");
26614354994fSDaniel Rosenberg 		return -EINVAL;
26624354994fSDaniel Rosenberg 	}
26634354994fSDaniel Rosenberg 
26647fb17fe4SChao Yu 	ret = mnt_want_write_file(filp);
26657fb17fe4SChao Yu 	if (ret)
26667fb17fe4SChao Yu 		return ret;
26677fb17fe4SChao Yu 
26687fb17fe4SChao Yu 	ret = f2fs_sync_fs(sbi->sb, 1);
26697fb17fe4SChao Yu 
26707fb17fe4SChao Yu 	mnt_drop_write_file(filp);
26717fb17fe4SChao Yu 	return ret;
2672456b88e4SChao Yu }
2673456b88e4SChao Yu 
f2fs_defragment_range(struct f2fs_sb_info * sbi,struct file * filp,struct f2fs_defragment * range)2674d323d005SChao Yu static int f2fs_defragment_range(struct f2fs_sb_info *sbi,
2675d323d005SChao Yu 					struct file *filp,
2676d323d005SChao Yu 					struct f2fs_defragment *range)
2677d323d005SChao Yu {
2678d323d005SChao Yu 	struct inode *inode = file_inode(filp);
2679f3d98e74SChao Yu 	struct f2fs_map_blocks map = { .m_next_extent = NULL,
2680f4f0b677SJia Zhu 					.m_seg_type = NO_CHECK_TYPE,
2681f4f0b677SJia Zhu 					.m_may_create = false };
2682fe59109aSJaegeuk Kim 	struct extent_info ei = {};
2683f3d98e74SChao Yu 	pgoff_t pg_start, pg_end, next_pgofs;
2684d323d005SChao Yu 	unsigned int total = 0, sec_num;
2685d323d005SChao Yu 	block_t blk_end = 0;
2686d323d005SChao Yu 	bool fragmented = false;
2687d323d005SChao Yu 	int err;
2688d323d005SChao Yu 
268909cbfeafSKirill A. Shutemov 	pg_start = range->start >> PAGE_SHIFT;
269009cbfeafSKirill A. Shutemov 	pg_end = (range->start + range->len) >> PAGE_SHIFT;
2691d323d005SChao Yu 
26922c4db1a6SJaegeuk Kim 	f2fs_balance_fs(sbi, true);
2693d323d005SChao Yu 
26945955102cSAl Viro 	inode_lock(inode);
2695d323d005SChao Yu 
26967cb51731SChao Yu 	if (is_inode_flag_set(inode, FI_COMPRESS_RELEASED) ||
26977cb51731SChao Yu 		f2fs_is_atomic_file(inode)) {
26987cd2e5f7SYangtao Li 		err = -EINVAL;
26997cd2e5f7SYangtao Li 		goto unlock_out;
27007cd2e5f7SYangtao Li 	}
27017cd2e5f7SYangtao Li 
27021018a546SChao Yu 	/* if in-place-update policy is enabled, don't waste time here */
27031018a546SChao Yu 	set_inode_flag(inode, FI_OPU_WRITE);
27041018a546SChao Yu 	if (f2fs_should_update_inplace(inode, NULL)) {
27051018a546SChao Yu 		err = -EINVAL;
27061018a546SChao Yu 		goto out;
27071018a546SChao Yu 	}
27081018a546SChao Yu 
2709d323d005SChao Yu 	/* writeback all dirty pages in the range */
2710d323d005SChao Yu 	err = filemap_write_and_wait_range(inode->i_mapping, range->start,
2711d8fe4f0eSFan Li 						range->start + range->len - 1);
2712d323d005SChao Yu 	if (err)
2713d323d005SChao Yu 		goto out;
2714d323d005SChao Yu 
2715d323d005SChao Yu 	/*
2716d323d005SChao Yu 	 * lookup mapping info in extent cache, skip defragmenting if physical
2717d323d005SChao Yu 	 * block addresses are continuous.
2718d323d005SChao Yu 	 */
2719e7547dacSJaegeuk Kim 	if (f2fs_lookup_read_extent_cache(inode, pg_start, &ei)) {
2720b18a5c83SNikita Zhandarovich 		if ((pgoff_t)ei.fofs + ei.len >= pg_end)
2721d323d005SChao Yu 			goto out;
2722d323d005SChao Yu 	}
2723d323d005SChao Yu 
2724d323d005SChao Yu 	map.m_lblk = pg_start;
2725f3d98e74SChao Yu 	map.m_next_pgofs = &next_pgofs;
2726d323d005SChao Yu 
2727d323d005SChao Yu 	/*
2728d323d005SChao Yu 	 * lookup mapping info in dnode page cache, skip defragmenting if all
2729d323d005SChao Yu 	 * physical block addresses are continuous even if there are hole(s)
2730d323d005SChao Yu 	 * in logical blocks.
2731d323d005SChao Yu 	 */
2732d323d005SChao Yu 	while (map.m_lblk < pg_end) {
2733a1c1e9b7SFan Li 		map.m_len = pg_end - map.m_lblk;
2734cd8fc522SChristoph Hellwig 		err = f2fs_map_blocks(inode, &map, F2FS_GET_BLOCK_DEFAULT);
2735d323d005SChao Yu 		if (err)
2736d323d005SChao Yu 			goto out;
2737d323d005SChao Yu 
2738d323d005SChao Yu 		if (!(map.m_flags & F2FS_MAP_FLAGS)) {
2739f3d98e74SChao Yu 			map.m_lblk = next_pgofs;
2740d323d005SChao Yu 			continue;
2741d323d005SChao Yu 		}
2742d323d005SChao Yu 
274325a912e5SChao Yu 		if (blk_end && blk_end != map.m_pblk)
2744d323d005SChao Yu 			fragmented = true;
274525a912e5SChao Yu 
274625a912e5SChao Yu 		/* record total count of block that we're going to move */
274725a912e5SChao Yu 		total += map.m_len;
274825a912e5SChao Yu 
2749d323d005SChao Yu 		blk_end = map.m_pblk + map.m_len;
2750d323d005SChao Yu 
2751d323d005SChao Yu 		map.m_lblk += map.m_len;
2752d323d005SChao Yu 	}
2753d323d005SChao Yu 
2754d3a1a0e1SChao Yu 	if (!fragmented) {
2755d3a1a0e1SChao Yu 		total = 0;
2756d323d005SChao Yu 		goto out;
2757d3a1a0e1SChao Yu 	}
2758d323d005SChao Yu 
2759074b5ea2SJaegeuk Kim 	sec_num = DIV_ROUND_UP(total, CAP_BLKS_PER_SEC(sbi));
2760d323d005SChao Yu 
2761d323d005SChao Yu 	/*
2762d323d005SChao Yu 	 * make sure there are enough free section for LFS allocation, this can
2763d323d005SChao Yu 	 * avoid defragment running in SSR mode when free section are allocated
2764d323d005SChao Yu 	 * intensively
2765d323d005SChao Yu 	 */
27667f3037a5SJaegeuk Kim 	if (has_not_enough_free_secs(sbi, 0, sec_num)) {
2767d323d005SChao Yu 		err = -EAGAIN;
2768d323d005SChao Yu 		goto out;
2769d323d005SChao Yu 	}
2770d323d005SChao Yu 
277125a912e5SChao Yu 	map.m_lblk = pg_start;
277225a912e5SChao Yu 	map.m_len = pg_end - pg_start;
277325a912e5SChao Yu 	total = 0;
277425a912e5SChao Yu 
2775d323d005SChao Yu 	while (map.m_lblk < pg_end) {
2776d323d005SChao Yu 		pgoff_t idx;
2777d323d005SChao Yu 		int cnt = 0;
2778d323d005SChao Yu 
2779d323d005SChao Yu do_map:
2780a1c1e9b7SFan Li 		map.m_len = pg_end - map.m_lblk;
2781cd8fc522SChristoph Hellwig 		err = f2fs_map_blocks(inode, &map, F2FS_GET_BLOCK_DEFAULT);
2782d323d005SChao Yu 		if (err)
2783d323d005SChao Yu 			goto clear_out;
2784d323d005SChao Yu 
2785d323d005SChao Yu 		if (!(map.m_flags & F2FS_MAP_FLAGS)) {
2786f3d98e74SChao Yu 			map.m_lblk = next_pgofs;
2787d3a1a0e1SChao Yu 			goto check;
2788d323d005SChao Yu 		}
2789d323d005SChao Yu 
27901018a546SChao Yu 		set_inode_flag(inode, FI_SKIP_WRITES);
2791d323d005SChao Yu 
2792d323d005SChao Yu 		idx = map.m_lblk;
2793f0248ba6SJaegeuk Kim 		while (idx < map.m_lblk + map.m_len &&
2794f0248ba6SJaegeuk Kim 						cnt < BLKS_PER_SEG(sbi)) {
2795d323d005SChao Yu 			struct page *page;
2796d323d005SChao Yu 
27974d57b86dSChao Yu 			page = f2fs_get_lock_data_page(inode, idx, true);
2798d323d005SChao Yu 			if (IS_ERR(page)) {
2799d323d005SChao Yu 				err = PTR_ERR(page);
2800d323d005SChao Yu 				goto clear_out;
2801d323d005SChao Yu 			}
2802d323d005SChao Yu 
28031bb0686aSChao Yu 			f2fs_wait_on_page_writeback(page, DATA, true, true);
28041bb0686aSChao Yu 
2805d323d005SChao Yu 			set_page_dirty(page);
28062d1fe8a8SChao Yu 			set_page_private_gcing(page);
2807d323d005SChao Yu 			f2fs_put_page(page, 1);
2808d323d005SChao Yu 
2809d323d005SChao Yu 			idx++;
2810d323d005SChao Yu 			cnt++;
2811d323d005SChao Yu 			total++;
2812d323d005SChao Yu 		}
2813d323d005SChao Yu 
2814d323d005SChao Yu 		map.m_lblk = idx;
2815d3a1a0e1SChao Yu check:
2816f0248ba6SJaegeuk Kim 		if (map.m_lblk < pg_end && cnt < BLKS_PER_SEG(sbi))
2817d323d005SChao Yu 			goto do_map;
2818d323d005SChao Yu 
28191018a546SChao Yu 		clear_inode_flag(inode, FI_SKIP_WRITES);
2820d323d005SChao Yu 
2821d323d005SChao Yu 		err = filemap_fdatawrite(inode->i_mapping);
2822d323d005SChao Yu 		if (err)
2823d323d005SChao Yu 			goto out;
2824d323d005SChao Yu 	}
2825d323d005SChao Yu clear_out:
28261018a546SChao Yu 	clear_inode_flag(inode, FI_SKIP_WRITES);
2827d323d005SChao Yu out:
28281018a546SChao Yu 	clear_inode_flag(inode, FI_OPU_WRITE);
28297cd2e5f7SYangtao Li unlock_out:
28305955102cSAl Viro 	inode_unlock(inode);
2831d323d005SChao Yu 	if (!err)
283209cbfeafSKirill A. Shutemov 		range->len = (u64)total << PAGE_SHIFT;
2833d323d005SChao Yu 	return err;
2834d323d005SChao Yu }
2835d323d005SChao Yu 
f2fs_ioc_defragment(struct file * filp,unsigned long arg)2836d323d005SChao Yu static int f2fs_ioc_defragment(struct file *filp, unsigned long arg)
2837d323d005SChao Yu {
2838d323d005SChao Yu 	struct inode *inode = file_inode(filp);
2839d323d005SChao Yu 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
2840d323d005SChao Yu 	struct f2fs_defragment range;
2841d323d005SChao Yu 	int err;
2842d323d005SChao Yu 
2843d323d005SChao Yu 	if (!capable(CAP_SYS_ADMIN))
2844d323d005SChao Yu 		return -EPERM;
2845d323d005SChao Yu 
28467eab0c0dSHou Pengyang 	if (!S_ISREG(inode->i_mode) || f2fs_is_atomic_file(inode))
2847d323d005SChao Yu 		return -EINVAL;
2848d323d005SChao Yu 
2849d7563861SKinglong Mee 	if (f2fs_readonly(sbi->sb))
2850d7563861SKinglong Mee 		return -EROFS;
2851d7563861SKinglong Mee 
2852d7563861SKinglong Mee 	if (copy_from_user(&range, (struct f2fs_defragment __user *)arg,
2853d7563861SKinglong Mee 							sizeof(range)))
2854d7563861SKinglong Mee 		return -EFAULT;
2855d7563861SKinglong Mee 
2856d7563861SKinglong Mee 	/* verify alignment of offset & size */
2857d7563861SKinglong Mee 	if (range.start & (F2FS_BLKSIZE - 1) || range.len & (F2FS_BLKSIZE - 1))
2858d7563861SKinglong Mee 		return -EINVAL;
2859d7563861SKinglong Mee 
2860d7563861SKinglong Mee 	if (unlikely((range.start + range.len) >> PAGE_SHIFT >
28616d1451bfSChengguang Xu 					max_file_blocks(inode)))
2862d7563861SKinglong Mee 		return -EINVAL;
2863d7563861SKinglong Mee 
2864d323d005SChao Yu 	err = mnt_want_write_file(filp);
2865d323d005SChao Yu 	if (err)
2866d323d005SChao Yu 		return err;
2867d323d005SChao Yu 
2868d323d005SChao Yu 	err = f2fs_defragment_range(sbi, filp, &range);
2869d7563861SKinglong Mee 	mnt_drop_write_file(filp);
2870d7563861SKinglong Mee 
2871d0239e1bSJaegeuk Kim 	f2fs_update_time(sbi, REQ_TIME);
2872d323d005SChao Yu 	if (err < 0)
2873d7563861SKinglong Mee 		return err;
2874d323d005SChao Yu 
2875d323d005SChao Yu 	if (copy_to_user((struct f2fs_defragment __user *)arg, &range,
2876d323d005SChao Yu 							sizeof(range)))
2877d7563861SKinglong Mee 		return -EFAULT;
2878d7563861SKinglong Mee 
2879d7563861SKinglong Mee 	return 0;
2880d323d005SChao Yu }
2881d323d005SChao Yu 
f2fs_move_file_range(struct file * file_in,loff_t pos_in,struct file * file_out,loff_t pos_out,size_t len)28824dd6f977SJaegeuk Kim static int f2fs_move_file_range(struct file *file_in, loff_t pos_in,
28834dd6f977SJaegeuk Kim 			struct file *file_out, loff_t pos_out, size_t len)
28844dd6f977SJaegeuk Kim {
28854dd6f977SJaegeuk Kim 	struct inode *src = file_inode(file_in);
28864dd6f977SJaegeuk Kim 	struct inode *dst = file_inode(file_out);
28874dd6f977SJaegeuk Kim 	struct f2fs_sb_info *sbi = F2FS_I_SB(src);
28884dd6f977SJaegeuk Kim 	size_t olen = len, dst_max_i_size = 0;
28894dd6f977SJaegeuk Kim 	size_t dst_osize;
28904dd6f977SJaegeuk Kim 	int ret;
28914dd6f977SJaegeuk Kim 
28924dd6f977SJaegeuk Kim 	if (file_in->f_path.mnt != file_out->f_path.mnt ||
28934dd6f977SJaegeuk Kim 				src->i_sb != dst->i_sb)
28944dd6f977SJaegeuk Kim 		return -EXDEV;
28954dd6f977SJaegeuk Kim 
28964dd6f977SJaegeuk Kim 	if (unlikely(f2fs_readonly(src->i_sb)))
28974dd6f977SJaegeuk Kim 		return -EROFS;
28984dd6f977SJaegeuk Kim 
2899fe8494bfSChao Yu 	if (!S_ISREG(src->i_mode) || !S_ISREG(dst->i_mode))
2900fe8494bfSChao Yu 		return -EINVAL;
29014dd6f977SJaegeuk Kim 
290262230e0dSChandan Rajendra 	if (IS_ENCRYPTED(src) || IS_ENCRYPTED(dst))
29034dd6f977SJaegeuk Kim 		return -EOPNOTSUPP;
29044dd6f977SJaegeuk Kim 
2905aad1383cSDan Robertson 	if (pos_out < 0 || pos_in < 0)
2906aad1383cSDan Robertson 		return -EINVAL;
2907aad1383cSDan Robertson 
2908d95fd91cSFan Li 	if (src == dst) {
2909d95fd91cSFan Li 		if (pos_in == pos_out)
2910d95fd91cSFan Li 			return 0;
2911d95fd91cSFan Li 		if (pos_out > pos_in && pos_out < pos_in + len)
2912d95fd91cSFan Li 			return -EINVAL;
2913d95fd91cSFan Li 	}
2914d95fd91cSFan Li 
29154dd6f977SJaegeuk Kim 	inode_lock(src);
291620a3d61dSChao Yu 	if (src != dst) {
291720a3d61dSChao Yu 		ret = -EBUSY;
2918bb06664aSChao Yu 		if (!inode_trylock(dst))
2919bb06664aSChao Yu 			goto out;
292020a3d61dSChao Yu 	}
29214dd6f977SJaegeuk Kim 
2922f8412268SChao Yu 	if (f2fs_compressed_file(src) || f2fs_compressed_file(dst) ||
2923f8412268SChao Yu 		f2fs_is_pinned_file(src) || f2fs_is_pinned_file(dst)) {
2924412eee2cSChao Yu 		ret = -EOPNOTSUPP;
2925412eee2cSChao Yu 		goto out_unlock;
2926412eee2cSChao Yu 	}
2927412eee2cSChao Yu 
29287cb51731SChao Yu 	if (f2fs_is_atomic_file(src) || f2fs_is_atomic_file(dst)) {
29297cb51731SChao Yu 		ret = -EINVAL;
29307cb51731SChao Yu 		goto out_unlock;
29317cb51731SChao Yu 	}
29327cb51731SChao Yu 
29334dd6f977SJaegeuk Kim 	ret = -EINVAL;
29344dd6f977SJaegeuk Kim 	if (pos_in + len > src->i_size || pos_in + len < pos_in)
29354dd6f977SJaegeuk Kim 		goto out_unlock;
29364dd6f977SJaegeuk Kim 	if (len == 0)
29374dd6f977SJaegeuk Kim 		olen = len = src->i_size - pos_in;
29384dd6f977SJaegeuk Kim 	if (pos_in + len == src->i_size)
29394dd6f977SJaegeuk Kim 		len = ALIGN(src->i_size, F2FS_BLKSIZE) - pos_in;
29404dd6f977SJaegeuk Kim 	if (len == 0) {
29414dd6f977SJaegeuk Kim 		ret = 0;
29424dd6f977SJaegeuk Kim 		goto out_unlock;
29434dd6f977SJaegeuk Kim 	}
29444dd6f977SJaegeuk Kim 
29454dd6f977SJaegeuk Kim 	dst_osize = dst->i_size;
29464dd6f977SJaegeuk Kim 	if (pos_out + olen > dst->i_size)
29474dd6f977SJaegeuk Kim 		dst_max_i_size = pos_out + olen;
29484dd6f977SJaegeuk Kim 
29494dd6f977SJaegeuk Kim 	/* verify the end result is block aligned */
29504dd6f977SJaegeuk Kim 	if (!IS_ALIGNED(pos_in, F2FS_BLKSIZE) ||
29514dd6f977SJaegeuk Kim 			!IS_ALIGNED(pos_in + len, F2FS_BLKSIZE) ||
29524dd6f977SJaegeuk Kim 			!IS_ALIGNED(pos_out, F2FS_BLKSIZE))
29534dd6f977SJaegeuk Kim 		goto out_unlock;
29544dd6f977SJaegeuk Kim 
29554dd6f977SJaegeuk Kim 	ret = f2fs_convert_inline_inode(src);
29564dd6f977SJaegeuk Kim 	if (ret)
29574dd6f977SJaegeuk Kim 		goto out_unlock;
29584dd6f977SJaegeuk Kim 
29594dd6f977SJaegeuk Kim 	ret = f2fs_convert_inline_inode(dst);
29604dd6f977SJaegeuk Kim 	if (ret)
29614dd6f977SJaegeuk Kim 		goto out_unlock;
29624dd6f977SJaegeuk Kim 
29634dd6f977SJaegeuk Kim 	/* write out all dirty pages from offset */
29644dd6f977SJaegeuk Kim 	ret = filemap_write_and_wait_range(src->i_mapping,
29654dd6f977SJaegeuk Kim 					pos_in, pos_in + len);
29664dd6f977SJaegeuk Kim 	if (ret)
29674dd6f977SJaegeuk Kim 		goto out_unlock;
29684dd6f977SJaegeuk Kim 
29694dd6f977SJaegeuk Kim 	ret = filemap_write_and_wait_range(dst->i_mapping,
29704dd6f977SJaegeuk Kim 					pos_out, pos_out + len);
29714dd6f977SJaegeuk Kim 	if (ret)
29724dd6f977SJaegeuk Kim 		goto out_unlock;
29734dd6f977SJaegeuk Kim 
29744dd6f977SJaegeuk Kim 	f2fs_balance_fs(sbi, true);
29756f8d4455SJaegeuk Kim 
2976e4544b63STim Murray 	f2fs_down_write(&F2FS_I(src)->i_gc_rwsem[WRITE]);
29776f8d4455SJaegeuk Kim 	if (src != dst) {
29786f8d4455SJaegeuk Kim 		ret = -EBUSY;
2979e4544b63STim Murray 		if (!f2fs_down_write_trylock(&F2FS_I(dst)->i_gc_rwsem[WRITE]))
29806f8d4455SJaegeuk Kim 			goto out_src;
29816f8d4455SJaegeuk Kim 	}
29826f8d4455SJaegeuk Kim 
29834dd6f977SJaegeuk Kim 	f2fs_lock_op(sbi);
298461e4da11SFan Li 	ret = __exchange_data_block(src, dst, pos_in >> F2FS_BLKSIZE_BITS,
298561e4da11SFan Li 				pos_out >> F2FS_BLKSIZE_BITS,
298661e4da11SFan Li 				len >> F2FS_BLKSIZE_BITS, false);
29874dd6f977SJaegeuk Kim 
29884dd6f977SJaegeuk Kim 	if (!ret) {
29894dd6f977SJaegeuk Kim 		if (dst_max_i_size)
29904dd6f977SJaegeuk Kim 			f2fs_i_size_write(dst, dst_max_i_size);
29914dd6f977SJaegeuk Kim 		else if (dst_osize != dst->i_size)
29924dd6f977SJaegeuk Kim 			f2fs_i_size_write(dst, dst_osize);
29934dd6f977SJaegeuk Kim 	}
29944dd6f977SJaegeuk Kim 	f2fs_unlock_op(sbi);
29956f8d4455SJaegeuk Kim 
29966f8d4455SJaegeuk Kim 	if (src != dst)
2997e4544b63STim Murray 		f2fs_up_write(&F2FS_I(dst)->i_gc_rwsem[WRITE]);
29986f8d4455SJaegeuk Kim out_src:
2999e4544b63STim Murray 	f2fs_up_write(&F2FS_I(src)->i_gc_rwsem[WRITE]);
3000396d0a28SYunlei He 	if (ret)
3001396d0a28SYunlei He 		goto out_unlock;
3002396d0a28SYunlei He 
3003c62ebd35SJeff Layton 	src->i_mtime = inode_set_ctime_current(src);
3004396d0a28SYunlei He 	f2fs_mark_inode_dirty_sync(src, false);
3005396d0a28SYunlei He 	if (src != dst) {
3006c62ebd35SJeff Layton 		dst->i_mtime = inode_set_ctime_current(dst);
3007396d0a28SYunlei He 		f2fs_mark_inode_dirty_sync(dst, false);
3008396d0a28SYunlei He 	}
3009396d0a28SYunlei He 	f2fs_update_time(sbi, REQ_TIME);
3010396d0a28SYunlei He 
30116f8d4455SJaegeuk Kim out_unlock:
30126f8d4455SJaegeuk Kim 	if (src != dst)
30136f8d4455SJaegeuk Kim 		inode_unlock(dst);
30146f8d4455SJaegeuk Kim out:
30154dd6f977SJaegeuk Kim 	inode_unlock(src);
30164dd6f977SJaegeuk Kim 	return ret;
30174dd6f977SJaegeuk Kim }
30184dd6f977SJaegeuk Kim 
__f2fs_ioc_move_range(struct file * filp,struct f2fs_move_range * range)301934178b1bSChao Yu static int __f2fs_ioc_move_range(struct file *filp,
302034178b1bSChao Yu 				struct f2fs_move_range *range)
30214dd6f977SJaegeuk Kim {
30224dd6f977SJaegeuk Kim 	struct fd dst;
30234dd6f977SJaegeuk Kim 	int err;
30244dd6f977SJaegeuk Kim 
30254dd6f977SJaegeuk Kim 	if (!(filp->f_mode & FMODE_READ) ||
30264dd6f977SJaegeuk Kim 			!(filp->f_mode & FMODE_WRITE))
30274dd6f977SJaegeuk Kim 		return -EBADF;
30284dd6f977SJaegeuk Kim 
302934178b1bSChao Yu 	dst = fdget(range->dst_fd);
30304dd6f977SJaegeuk Kim 	if (!dst.file)
30314dd6f977SJaegeuk Kim 		return -EBADF;
30324dd6f977SJaegeuk Kim 
30334dd6f977SJaegeuk Kim 	if (!(dst.file->f_mode & FMODE_WRITE)) {
30344dd6f977SJaegeuk Kim 		err = -EBADF;
30354dd6f977SJaegeuk Kim 		goto err_out;
30364dd6f977SJaegeuk Kim 	}
30374dd6f977SJaegeuk Kim 
30384dd6f977SJaegeuk Kim 	err = mnt_want_write_file(filp);
30394dd6f977SJaegeuk Kim 	if (err)
30404dd6f977SJaegeuk Kim 		goto err_out;
30414dd6f977SJaegeuk Kim 
304234178b1bSChao Yu 	err = f2fs_move_file_range(filp, range->pos_in, dst.file,
304334178b1bSChao Yu 					range->pos_out, range->len);
30444dd6f977SJaegeuk Kim 
30454dd6f977SJaegeuk Kim 	mnt_drop_write_file(filp);
30464dd6f977SJaegeuk Kim err_out:
30474dd6f977SJaegeuk Kim 	fdput(dst);
30484dd6f977SJaegeuk Kim 	return err;
30494dd6f977SJaegeuk Kim }
30504dd6f977SJaegeuk Kim 
f2fs_ioc_move_range(struct file * filp,unsigned long arg)305134178b1bSChao Yu static int f2fs_ioc_move_range(struct file *filp, unsigned long arg)
305234178b1bSChao Yu {
305334178b1bSChao Yu 	struct f2fs_move_range range;
305434178b1bSChao Yu 
305534178b1bSChao Yu 	if (copy_from_user(&range, (struct f2fs_move_range __user *)arg,
305634178b1bSChao Yu 							sizeof(range)))
305734178b1bSChao Yu 		return -EFAULT;
305834178b1bSChao Yu 	return __f2fs_ioc_move_range(filp, &range);
305934178b1bSChao Yu }
306034178b1bSChao Yu 
f2fs_ioc_flush_device(struct file * filp,unsigned long arg)3061e066b83cSJaegeuk Kim static int f2fs_ioc_flush_device(struct file *filp, unsigned long arg)
3062e066b83cSJaegeuk Kim {
3063e066b83cSJaegeuk Kim 	struct inode *inode = file_inode(filp);
3064e066b83cSJaegeuk Kim 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
3065e066b83cSJaegeuk Kim 	struct sit_info *sm = SIT_I(sbi);
3066e066b83cSJaegeuk Kim 	unsigned int start_segno = 0, end_segno = 0;
3067e066b83cSJaegeuk Kim 	unsigned int dev_start_segno = 0, dev_end_segno = 0;
3068e066b83cSJaegeuk Kim 	struct f2fs_flush_device range;
3069d147ea4aSJaegeuk Kim 	struct f2fs_gc_control gc_control = {
3070d147ea4aSJaegeuk Kim 			.init_gc_type = FG_GC,
3071d147ea4aSJaegeuk Kim 			.should_migrate_blocks = true,
3072c81d5baeSJaegeuk Kim 			.err_gc_skipped = true,
3073c81d5baeSJaegeuk Kim 			.nr_free_secs = 0 };
3074e066b83cSJaegeuk Kim 	int ret;
3075e066b83cSJaegeuk Kim 
3076e066b83cSJaegeuk Kim 	if (!capable(CAP_SYS_ADMIN))
3077e066b83cSJaegeuk Kim 		return -EPERM;
3078e066b83cSJaegeuk Kim 
3079e066b83cSJaegeuk Kim 	if (f2fs_readonly(sbi->sb))
3080e066b83cSJaegeuk Kim 		return -EROFS;
3081e066b83cSJaegeuk Kim 
30824354994fSDaniel Rosenberg 	if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED)))
30834354994fSDaniel Rosenberg 		return -EINVAL;
30844354994fSDaniel Rosenberg 
3085e066b83cSJaegeuk Kim 	if (copy_from_user(&range, (struct f2fs_flush_device __user *)arg,
3086e066b83cSJaegeuk Kim 							sizeof(range)))
3087e066b83cSJaegeuk Kim 		return -EFAULT;
3088e066b83cSJaegeuk Kim 
30890916878dSDamien Le Moal 	if (!f2fs_is_multi_device(sbi) || sbi->s_ndevs - 1 <= range.dev_num ||
30902c70c5e3SChao Yu 			__is_large_section(sbi)) {
3091f0248ba6SJaegeuk Kim 		f2fs_warn(sbi, "Can't flush %u in %d for SEGS_PER_SEC %u != 1",
3092f0248ba6SJaegeuk Kim 			  range.dev_num, sbi->s_ndevs, SEGS_PER_SEC(sbi));
3093e066b83cSJaegeuk Kim 		return -EINVAL;
3094e066b83cSJaegeuk Kim 	}
3095e066b83cSJaegeuk Kim 
3096e066b83cSJaegeuk Kim 	ret = mnt_want_write_file(filp);
3097e066b83cSJaegeuk Kim 	if (ret)
3098e066b83cSJaegeuk Kim 		return ret;
3099e066b83cSJaegeuk Kim 
3100e066b83cSJaegeuk Kim 	if (range.dev_num != 0)
3101e066b83cSJaegeuk Kim 		dev_start_segno = GET_SEGNO(sbi, FDEV(range.dev_num).start_blk);
3102e066b83cSJaegeuk Kim 	dev_end_segno = GET_SEGNO(sbi, FDEV(range.dev_num).end_blk);
3103e066b83cSJaegeuk Kim 
3104e066b83cSJaegeuk Kim 	start_segno = sm->last_victim[FLUSH_DEVICE];
3105e066b83cSJaegeuk Kim 	if (start_segno < dev_start_segno || start_segno >= dev_end_segno)
3106e066b83cSJaegeuk Kim 		start_segno = dev_start_segno;
3107e066b83cSJaegeuk Kim 	end_segno = min(start_segno + range.segments, dev_end_segno);
3108e066b83cSJaegeuk Kim 
3109e066b83cSJaegeuk Kim 	while (start_segno < end_segno) {
3110e4544b63STim Murray 		if (!f2fs_down_write_trylock(&sbi->gc_lock)) {
3111e066b83cSJaegeuk Kim 			ret = -EBUSY;
3112e066b83cSJaegeuk Kim 			goto out;
3113e066b83cSJaegeuk Kim 		}
3114e066b83cSJaegeuk Kim 		sm->last_victim[GC_CB] = end_segno + 1;
3115e066b83cSJaegeuk Kim 		sm->last_victim[GC_GREEDY] = end_segno + 1;
3116e066b83cSJaegeuk Kim 		sm->last_victim[ALLOC_NEXT] = end_segno + 1;
3117d147ea4aSJaegeuk Kim 
3118d147ea4aSJaegeuk Kim 		gc_control.victim_segno = start_segno;
31199bf1dcbdSChao Yu 		stat_inc_gc_call_count(sbi, FOREGROUND);
3120d147ea4aSJaegeuk Kim 		ret = f2fs_gc(sbi, &gc_control);
3121e066b83cSJaegeuk Kim 		if (ret == -EAGAIN)
3122e066b83cSJaegeuk Kim 			ret = 0;
3123e066b83cSJaegeuk Kim 		else if (ret < 0)
3124e066b83cSJaegeuk Kim 			break;
3125e066b83cSJaegeuk Kim 		start_segno++;
3126e066b83cSJaegeuk Kim 	}
3127e066b83cSJaegeuk Kim out:
3128e066b83cSJaegeuk Kim 	mnt_drop_write_file(filp);
3129e066b83cSJaegeuk Kim 	return ret;
3130e066b83cSJaegeuk Kim }
3131e066b83cSJaegeuk Kim 
f2fs_ioc_get_features(struct file * filp,unsigned long arg)3132e65ef207SJaegeuk Kim static int f2fs_ioc_get_features(struct file *filp, unsigned long arg)
3133e65ef207SJaegeuk Kim {
3134e65ef207SJaegeuk Kim 	struct inode *inode = file_inode(filp);
3135e65ef207SJaegeuk Kim 	u32 sb_feature = le32_to_cpu(F2FS_I_SB(inode)->raw_super->feature);
3136e65ef207SJaegeuk Kim 
3137e65ef207SJaegeuk Kim 	/* Must validate to set it with SQLite behavior in Android. */
3138e65ef207SJaegeuk Kim 	sb_feature |= F2FS_FEATURE_ATOMIC_WRITE;
3139e65ef207SJaegeuk Kim 
3140e65ef207SJaegeuk Kim 	return put_user(sb_feature, (u32 __user *)arg);
3141e65ef207SJaegeuk Kim }
3142e066b83cSJaegeuk Kim 
31432c1d0305SChao Yu #ifdef CONFIG_QUOTA
f2fs_transfer_project_quota(struct inode * inode,kprojid_t kprojid)314478130819SChao Yu int f2fs_transfer_project_quota(struct inode *inode, kprojid_t kprojid)
314578130819SChao Yu {
314678130819SChao Yu 	struct dquot *transfer_to[MAXQUOTAS] = {};
314778130819SChao Yu 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
314878130819SChao Yu 	struct super_block *sb = sbi->sb;
31498051692fSYangtao Li 	int err;
315078130819SChao Yu 
315178130819SChao Yu 	transfer_to[PRJQUOTA] = dqget(sb, make_kqid_projid(kprojid));
31528051692fSYangtao Li 	if (IS_ERR(transfer_to[PRJQUOTA]))
31538051692fSYangtao Li 		return PTR_ERR(transfer_to[PRJQUOTA]);
31548051692fSYangtao Li 
315578130819SChao Yu 	err = __dquot_transfer(inode, transfer_to);
315678130819SChao Yu 	if (err)
315778130819SChao Yu 		set_sbi_flag(sbi, SBI_QUOTA_NEED_REPAIR);
315878130819SChao Yu 	dqput(transfer_to[PRJQUOTA]);
315978130819SChao Yu 	return err;
316078130819SChao Yu }
316178130819SChao Yu 
f2fs_ioc_setproject(struct inode * inode,__u32 projid)31629b1bb01cSMiklos Szeredi static int f2fs_ioc_setproject(struct inode *inode, __u32 projid)
31632c1d0305SChao Yu {
31642c1d0305SChao Yu 	struct f2fs_inode_info *fi = F2FS_I(inode);
31652c1d0305SChao Yu 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
3166d13732ccSJia Yang 	struct f2fs_inode *ri = NULL;
31672c1d0305SChao Yu 	kprojid_t kprojid;
31682c1d0305SChao Yu 	int err;
31692c1d0305SChao Yu 
31707beb01f7SChao Yu 	if (!f2fs_sb_has_project_quota(sbi)) {
31712c1d0305SChao Yu 		if (projid != F2FS_DEF_PROJID)
31722c1d0305SChao Yu 			return -EOPNOTSUPP;
31732c1d0305SChao Yu 		else
31742c1d0305SChao Yu 			return 0;
31752c1d0305SChao Yu 	}
31762c1d0305SChao Yu 
31772c1d0305SChao Yu 	if (!f2fs_has_extra_attr(inode))
31782c1d0305SChao Yu 		return -EOPNOTSUPP;
31792c1d0305SChao Yu 
31802c1d0305SChao Yu 	kprojid = make_kprojid(&init_user_ns, (projid_t)projid);
31812c1d0305SChao Yu 
3182054cb289SYufen Yu 	if (projid_eq(kprojid, fi->i_projid))
31832c1d0305SChao Yu 		return 0;
31842c1d0305SChao Yu 
31852c1d0305SChao Yu 	err = -EPERM;
31862c1d0305SChao Yu 	/* Is it quota file? Do not allow user to mess with it */
31872c1d0305SChao Yu 	if (IS_NOQUOTA(inode))
3188c8e92757SWang Shilong 		return err;
31892c1d0305SChao Yu 
3190d13732ccSJia Yang 	if (!F2FS_FITS_IN_INODE(ri, fi->i_extra_isize, i_projid))
3191d13732ccSJia Yang 		return -EOVERFLOW;
31922c1d0305SChao Yu 
319310a26878SChao Yu 	err = f2fs_dquot_initialize(inode);
3194c22aecd7SChao Yu 	if (err)
3195c8e92757SWang Shilong 		return err;
31962c1d0305SChao Yu 
319778130819SChao Yu 	f2fs_lock_op(sbi);
319878130819SChao Yu 	err = f2fs_transfer_project_quota(inode, kprojid);
31992c1d0305SChao Yu 	if (err)
320078130819SChao Yu 		goto out_unlock;
32012c1d0305SChao Yu 
3202054cb289SYufen Yu 	fi->i_projid = kprojid;
3203c62ebd35SJeff Layton 	inode_set_ctime_current(inode);
32042c1d0305SChao Yu 	f2fs_mark_inode_dirty_sync(inode, true);
320578130819SChao Yu out_unlock:
320678130819SChao Yu 	f2fs_unlock_op(sbi);
32072c1d0305SChao Yu 	return err;
32082c1d0305SChao Yu }
32092c1d0305SChao Yu #else
f2fs_transfer_project_quota(struct inode * inode,kprojid_t kprojid)321078130819SChao Yu int f2fs_transfer_project_quota(struct inode *inode, kprojid_t kprojid)
321178130819SChao Yu {
321278130819SChao Yu 	return 0;
321378130819SChao Yu }
321478130819SChao Yu 
f2fs_ioc_setproject(struct inode * inode,__u32 projid)32159b1bb01cSMiklos Szeredi static int f2fs_ioc_setproject(struct inode *inode, __u32 projid)
32162c1d0305SChao Yu {
32172c1d0305SChao Yu 	if (projid != F2FS_DEF_PROJID)
32182c1d0305SChao Yu 		return -EOPNOTSUPP;
32192c1d0305SChao Yu 	return 0;
32202c1d0305SChao Yu }
32212c1d0305SChao Yu #endif
32222c1d0305SChao Yu 
f2fs_fileattr_get(struct dentry * dentry,struct fileattr * fa)32239b1bb01cSMiklos Szeredi int f2fs_fileattr_get(struct dentry *dentry, struct fileattr *fa)
322436098557SEric Biggers {
32259b1bb01cSMiklos Szeredi 	struct inode *inode = d_inode(dentry);
32266fc93c4eSEric Biggers 	struct f2fs_inode_info *fi = F2FS_I(inode);
32279b1bb01cSMiklos Szeredi 	u32 fsflags = f2fs_iflags_to_fsflags(fi->i_flags);
32286fc93c4eSEric Biggers 
32299b1bb01cSMiklos Szeredi 	if (IS_ENCRYPTED(inode))
32309b1bb01cSMiklos Szeredi 		fsflags |= FS_ENCRYPT_FL;
32319b1bb01cSMiklos Szeredi 	if (IS_VERITY(inode))
32329b1bb01cSMiklos Szeredi 		fsflags |= FS_VERITY_FL;
32339b1bb01cSMiklos Szeredi 	if (f2fs_has_inline_data(inode) || f2fs_has_inline_dentry(inode))
32349b1bb01cSMiklos Szeredi 		fsflags |= FS_INLINE_DATA_FL;
32359b1bb01cSMiklos Szeredi 	if (is_inode_flag_set(inode, FI_PIN_FILE))
32369b1bb01cSMiklos Szeredi 		fsflags |= FS_NOCOW_FL;
32379b1bb01cSMiklos Szeredi 
32389b1bb01cSMiklos Szeredi 	fileattr_fill_flags(fa, fsflags & F2FS_GETTABLE_FS_FL);
32396fc93c4eSEric Biggers 
32406fc93c4eSEric Biggers 	if (f2fs_sb_has_project_quota(F2FS_I_SB(inode)))
32416fc93c4eSEric Biggers 		fa->fsx_projid = from_kprojid(&init_user_ns, fi->i_projid);
32426fc93c4eSEric Biggers 
32432c1d0305SChao Yu 	return 0;
32442c1d0305SChao Yu }
32452c1d0305SChao Yu 
f2fs_fileattr_set(struct mnt_idmap * idmap,struct dentry * dentry,struct fileattr * fa)32468782a9aeSChristian Brauner int f2fs_fileattr_set(struct mnt_idmap *idmap,
32479b1bb01cSMiklos Szeredi 		      struct dentry *dentry, struct fileattr *fa)
32482c1d0305SChao Yu {
32499b1bb01cSMiklos Szeredi 	struct inode *inode = d_inode(dentry);
32509b1bb01cSMiklos Szeredi 	u32 fsflags = fa->flags, mask = F2FS_SETTABLE_FS_FL;
325136098557SEric Biggers 	u32 iflags;
32522c1d0305SChao Yu 	int err;
32532c1d0305SChao Yu 
32549b1bb01cSMiklos Szeredi 	if (unlikely(f2fs_cp_error(F2FS_I_SB(inode))))
32559b1bb01cSMiklos Szeredi 		return -EIO;
32569b1bb01cSMiklos Szeredi 	if (!f2fs_is_checkpoint_ready(F2FS_I_SB(inode)))
32579b1bb01cSMiklos Szeredi 		return -ENOSPC;
32589b1bb01cSMiklos Szeredi 	if (fsflags & ~F2FS_GETTABLE_FS_FL)
32592c1d0305SChao Yu 		return -EOPNOTSUPP;
32609b1bb01cSMiklos Szeredi 	fsflags &= F2FS_SETTABLE_FS_FL;
32619b1bb01cSMiklos Szeredi 	if (!fa->flags_valid)
32629b1bb01cSMiklos Szeredi 		mask &= FS_COMMON_FL;
32632c1d0305SChao Yu 
32649b1bb01cSMiklos Szeredi 	iflags = f2fs_fsflags_to_iflags(fsflags);
326536098557SEric Biggers 	if (f2fs_mask_flags(inode->i_mode, iflags) != iflags)
32662c1d0305SChao Yu 		return -EOPNOTSUPP;
32672c1d0305SChao Yu 
32689b1bb01cSMiklos Szeredi 	err = f2fs_setflags_common(inode, iflags, f2fs_fsflags_to_iflags(mask));
32699b1bb01cSMiklos Szeredi 	if (!err)
32709b1bb01cSMiklos Szeredi 		err = f2fs_ioc_setproject(inode, fa->fsx_projid);
32712c1d0305SChao Yu 
32722c1d0305SChao Yu 	return err;
32732c1d0305SChao Yu }
327452656e6cSJaegeuk Kim 
f2fs_pin_file_control(struct inode * inode,bool inc)32751ad71a27SJaegeuk Kim int f2fs_pin_file_control(struct inode *inode, bool inc)
32761ad71a27SJaegeuk Kim {
32771ad71a27SJaegeuk Kim 	struct f2fs_inode_info *fi = F2FS_I(inode);
32781ad71a27SJaegeuk Kim 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
32791ad71a27SJaegeuk Kim 
32801ad71a27SJaegeuk Kim 	/* Use i_gc_failures for normal file as a risk signal. */
32811ad71a27SJaegeuk Kim 	if (inc)
32822ef79ecbSChao Yu 		f2fs_i_gc_failures_write(inode,
32832ef79ecbSChao Yu 				fi->i_gc_failures[GC_FAILURE_PIN] + 1);
32841ad71a27SJaegeuk Kim 
32852ef79ecbSChao Yu 	if (fi->i_gc_failures[GC_FAILURE_PIN] > sbi->gc_pin_file_threshold) {
3286dcbb4c10SJoe Perches 		f2fs_warn(sbi, "%s: Enable GC = ino %lx after %x GC trials",
32872ef79ecbSChao Yu 			  __func__, inode->i_ino,
32882ef79ecbSChao Yu 			  fi->i_gc_failures[GC_FAILURE_PIN]);
32891ad71a27SJaegeuk Kim 		clear_inode_flag(inode, FI_PIN_FILE);
32901ad71a27SJaegeuk Kim 		return -EAGAIN;
32911ad71a27SJaegeuk Kim 	}
32921ad71a27SJaegeuk Kim 	return 0;
32931ad71a27SJaegeuk Kim }
32941ad71a27SJaegeuk Kim 
f2fs_ioc_set_pin_file(struct file * filp,unsigned long arg)32951ad71a27SJaegeuk Kim static int f2fs_ioc_set_pin_file(struct file *filp, unsigned long arg)
32961ad71a27SJaegeuk Kim {
32971ad71a27SJaegeuk Kim 	struct inode *inode = file_inode(filp);
329840d76c39SDaeho Jeong 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
32991ad71a27SJaegeuk Kim 	__u32 pin;
33001ad71a27SJaegeuk Kim 	int ret = 0;
33011ad71a27SJaegeuk Kim 
33021ad71a27SJaegeuk Kim 	if (get_user(pin, (__u32 __user *)arg))
33031ad71a27SJaegeuk Kim 		return -EFAULT;
33041ad71a27SJaegeuk Kim 
33051ad71a27SJaegeuk Kim 	if (!S_ISREG(inode->i_mode))
33061ad71a27SJaegeuk Kim 		return -EINVAL;
33071ad71a27SJaegeuk Kim 
330840d76c39SDaeho Jeong 	if (f2fs_readonly(sbi->sb))
33091ad71a27SJaegeuk Kim 		return -EROFS;
33101ad71a27SJaegeuk Kim 
33111ad71a27SJaegeuk Kim 	ret = mnt_want_write_file(filp);
33121ad71a27SJaegeuk Kim 	if (ret)
33131ad71a27SJaegeuk Kim 		return ret;
33141ad71a27SJaegeuk Kim 
33151ad71a27SJaegeuk Kim 	inode_lock(inode);
33161ad71a27SJaegeuk Kim 
33177cb51731SChao Yu 	if (f2fs_is_atomic_file(inode)) {
33187cb51731SChao Yu 		ret = -EINVAL;
33197cb51731SChao Yu 		goto out;
33207cb51731SChao Yu 	}
33217cb51731SChao Yu 
33221ad71a27SJaegeuk Kim 	if (!pin) {
33231ad71a27SJaegeuk Kim 		clear_inode_flag(inode, FI_PIN_FILE);
332430933364SChao Yu 		f2fs_i_gc_failures_write(inode, 0);
33251ad71a27SJaegeuk Kim 		goto done;
332640d76c39SDaeho Jeong 	} else if (f2fs_is_pinned_file(inode)) {
332740d76c39SDaeho Jeong 		goto done;
33281ad71a27SJaegeuk Kim 	}
33291ad71a27SJaegeuk Kim 
333040d76c39SDaeho Jeong 	if (f2fs_sb_has_blkzoned(sbi) && F2FS_HAS_BLOCKS(inode)) {
333140d76c39SDaeho Jeong 		ret = -EFBIG;
333240d76c39SDaeho Jeong 		goto out;
333340d76c39SDaeho Jeong 	}
333440d76c39SDaeho Jeong 
333540d76c39SDaeho Jeong 	/* Let's allow file pinning on zoned device. */
333640d76c39SDaeho Jeong 	if (!f2fs_sb_has_blkzoned(sbi) &&
333740d76c39SDaeho Jeong 	    f2fs_should_update_outplace(inode, NULL)) {
333819bdba52SJaegeuk Kim 		ret = -EINVAL;
333919bdba52SJaegeuk Kim 		goto out;
334019bdba52SJaegeuk Kim 	}
334119bdba52SJaegeuk Kim 
33421ad71a27SJaegeuk Kim 	if (f2fs_pin_file_control(inode, false)) {
33431ad71a27SJaegeuk Kim 		ret = -EAGAIN;
33441ad71a27SJaegeuk Kim 		goto out;
33451ad71a27SJaegeuk Kim 	}
33464c8ff709SChao Yu 
33471ad71a27SJaegeuk Kim 	ret = f2fs_convert_inline_inode(inode);
33481ad71a27SJaegeuk Kim 	if (ret)
33491ad71a27SJaegeuk Kim 		goto out;
33501ad71a27SJaegeuk Kim 
335178134d03SDaeho Jeong 	if (!f2fs_disable_compressed_file(inode)) {
33524c8ff709SChao Yu 		ret = -EOPNOTSUPP;
33534c8ff709SChao Yu 		goto out;
33544c8ff709SChao Yu 	}
33554c8ff709SChao Yu 
33561ad71a27SJaegeuk Kim 	set_inode_flag(inode, FI_PIN_FILE);
33572ef79ecbSChao Yu 	ret = F2FS_I(inode)->i_gc_failures[GC_FAILURE_PIN];
33581ad71a27SJaegeuk Kim done:
335940d76c39SDaeho Jeong 	f2fs_update_time(sbi, REQ_TIME);
33601ad71a27SJaegeuk Kim out:
33611ad71a27SJaegeuk Kim 	inode_unlock(inode);
33621ad71a27SJaegeuk Kim 	mnt_drop_write_file(filp);
33631ad71a27SJaegeuk Kim 	return ret;
33641ad71a27SJaegeuk Kim }
33651ad71a27SJaegeuk Kim 
f2fs_ioc_get_pin_file(struct file * filp,unsigned long arg)33661ad71a27SJaegeuk Kim static int f2fs_ioc_get_pin_file(struct file *filp, unsigned long arg)
33671ad71a27SJaegeuk Kim {
33681ad71a27SJaegeuk Kim 	struct inode *inode = file_inode(filp);
33691ad71a27SJaegeuk Kim 	__u32 pin = 0;
33701ad71a27SJaegeuk Kim 
33711ad71a27SJaegeuk Kim 	if (is_inode_flag_set(inode, FI_PIN_FILE))
33722ef79ecbSChao Yu 		pin = F2FS_I(inode)->i_gc_failures[GC_FAILURE_PIN];
33731ad71a27SJaegeuk Kim 	return put_user(pin, (u32 __user *)arg);
33741ad71a27SJaegeuk Kim }
33751ad71a27SJaegeuk Kim 
f2fs_precache_extents(struct inode * inode)3376c4020b2dSChao Yu int f2fs_precache_extents(struct inode *inode)
3377c4020b2dSChao Yu {
3378c4020b2dSChao Yu 	struct f2fs_inode_info *fi = F2FS_I(inode);
3379c4020b2dSChao Yu 	struct f2fs_map_blocks map;
3380c4020b2dSChao Yu 	pgoff_t m_next_extent;
3381c4020b2dSChao Yu 	loff_t end;
3382c4020b2dSChao Yu 	int err;
3383c4020b2dSChao Yu 
3384c4020b2dSChao Yu 	if (is_inode_flag_set(inode, FI_NO_EXTENT))
3385c4020b2dSChao Yu 		return -EOPNOTSUPP;
3386c4020b2dSChao Yu 
3387c4020b2dSChao Yu 	map.m_lblk = 0;
3388f1aeaf3cSChao Yu 	map.m_pblk = 0;
3389c4020b2dSChao Yu 	map.m_next_pgofs = NULL;
3390c4020b2dSChao Yu 	map.m_next_extent = &m_next_extent;
3391c4020b2dSChao Yu 	map.m_seg_type = NO_CHECK_TYPE;
3392f4f0b677SJia Zhu 	map.m_may_create = false;
33936d1451bfSChengguang Xu 	end = max_file_blocks(inode);
3394c4020b2dSChao Yu 
3395c4020b2dSChao Yu 	while (map.m_lblk < end) {
3396c4020b2dSChao Yu 		map.m_len = end - map.m_lblk;
3397c4020b2dSChao Yu 
3398e4544b63STim Murray 		f2fs_down_write(&fi->i_gc_rwsem[WRITE]);
3399cd8fc522SChristoph Hellwig 		err = f2fs_map_blocks(inode, &map, F2FS_GET_BLOCK_PRECACHE);
3400e4544b63STim Murray 		f2fs_up_write(&fi->i_gc_rwsem[WRITE]);
3401c4020b2dSChao Yu 		if (err)
3402c4020b2dSChao Yu 			return err;
3403c4020b2dSChao Yu 
3404c4020b2dSChao Yu 		map.m_lblk = m_next_extent;
3405c4020b2dSChao Yu 	}
3406c4020b2dSChao Yu 
34074f55dc2aSTom Rix 	return 0;
3408c4020b2dSChao Yu }
3409c4020b2dSChao Yu 
f2fs_ioc_precache_extents(struct file * filp)3410ddf1eca4SYangtao Li static int f2fs_ioc_precache_extents(struct file *filp)
3411c4020b2dSChao Yu {
3412c4020b2dSChao Yu 	return f2fs_precache_extents(file_inode(filp));
3413c4020b2dSChao Yu }
3414c4020b2dSChao Yu 
f2fs_ioc_resize_fs(struct file * filp,unsigned long arg)341504f0b2eaSQiuyang Sun static int f2fs_ioc_resize_fs(struct file *filp, unsigned long arg)
341604f0b2eaSQiuyang Sun {
341704f0b2eaSQiuyang Sun 	struct f2fs_sb_info *sbi = F2FS_I_SB(file_inode(filp));
341804f0b2eaSQiuyang Sun 	__u64 block_count;
341904f0b2eaSQiuyang Sun 
342004f0b2eaSQiuyang Sun 	if (!capable(CAP_SYS_ADMIN))
342104f0b2eaSQiuyang Sun 		return -EPERM;
342204f0b2eaSQiuyang Sun 
342304f0b2eaSQiuyang Sun 	if (f2fs_readonly(sbi->sb))
342404f0b2eaSQiuyang Sun 		return -EROFS;
342504f0b2eaSQiuyang Sun 
342604f0b2eaSQiuyang Sun 	if (copy_from_user(&block_count, (void __user *)arg,
342704f0b2eaSQiuyang Sun 			   sizeof(block_count)))
342804f0b2eaSQiuyang Sun 		return -EFAULT;
342904f0b2eaSQiuyang Sun 
3430d8189834SChao Yu 	return f2fs_resize_fs(filp, block_count);
343104f0b2eaSQiuyang Sun }
343204f0b2eaSQiuyang Sun 
f2fs_ioc_enable_verity(struct file * filp,unsigned long arg)343395ae251fSEric Biggers static int f2fs_ioc_enable_verity(struct file *filp, unsigned long arg)
343495ae251fSEric Biggers {
343595ae251fSEric Biggers 	struct inode *inode = file_inode(filp);
343695ae251fSEric Biggers 
343795ae251fSEric Biggers 	f2fs_update_time(F2FS_I_SB(inode), REQ_TIME);
343895ae251fSEric Biggers 
343995ae251fSEric Biggers 	if (!f2fs_sb_has_verity(F2FS_I_SB(inode))) {
344095ae251fSEric Biggers 		f2fs_warn(F2FS_I_SB(inode),
3441833dcd35SJoe Perches 			  "Can't enable fs-verity on inode %lu: the verity feature is not enabled on this filesystem",
344295ae251fSEric Biggers 			  inode->i_ino);
344395ae251fSEric Biggers 		return -EOPNOTSUPP;
344495ae251fSEric Biggers 	}
344595ae251fSEric Biggers 
344695ae251fSEric Biggers 	return fsverity_ioctl_enable(filp, (const void __user *)arg);
344795ae251fSEric Biggers }
344895ae251fSEric Biggers 
f2fs_ioc_measure_verity(struct file * filp,unsigned long arg)344995ae251fSEric Biggers static int f2fs_ioc_measure_verity(struct file *filp, unsigned long arg)
345095ae251fSEric Biggers {
345195ae251fSEric Biggers 	if (!f2fs_sb_has_verity(F2FS_I_SB(file_inode(filp))))
345295ae251fSEric Biggers 		return -EOPNOTSUPP;
345395ae251fSEric Biggers 
345495ae251fSEric Biggers 	return fsverity_ioctl_measure(filp, (void __user *)arg);
345595ae251fSEric Biggers }
345695ae251fSEric Biggers 
f2fs_ioc_read_verity_metadata(struct file * filp,unsigned long arg)3457e17fe657SEric Biggers static int f2fs_ioc_read_verity_metadata(struct file *filp, unsigned long arg)
3458e17fe657SEric Biggers {
3459e17fe657SEric Biggers 	if (!f2fs_sb_has_verity(F2FS_I_SB(file_inode(filp))))
3460e17fe657SEric Biggers 		return -EOPNOTSUPP;
3461e17fe657SEric Biggers 
3462e17fe657SEric Biggers 	return fsverity_ioctl_read_metadata(filp, (const void __user *)arg);
3463e17fe657SEric Biggers }
3464e17fe657SEric Biggers 
f2fs_ioc_getfslabel(struct file * filp,unsigned long arg)34653357af8fSEric Biggers static int f2fs_ioc_getfslabel(struct file *filp, unsigned long arg)
34664507847cSChao Yu {
34674507847cSChao Yu 	struct inode *inode = file_inode(filp);
34684507847cSChao Yu 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
34694507847cSChao Yu 	char *vbuf;
34704507847cSChao Yu 	int count;
34714507847cSChao Yu 	int err = 0;
34724507847cSChao Yu 
34734507847cSChao Yu 	vbuf = f2fs_kzalloc(sbi, MAX_VOLUME_NAME, GFP_KERNEL);
34744507847cSChao Yu 	if (!vbuf)
34754507847cSChao Yu 		return -ENOMEM;
34764507847cSChao Yu 
3477e4544b63STim Murray 	f2fs_down_read(&sbi->sb_lock);
34784507847cSChao Yu 	count = utf16s_to_utf8s(sbi->raw_super->volume_name,
34794507847cSChao Yu 			ARRAY_SIZE(sbi->raw_super->volume_name),
34804507847cSChao Yu 			UTF16_LITTLE_ENDIAN, vbuf, MAX_VOLUME_NAME);
3481e4544b63STim Murray 	f2fs_up_read(&sbi->sb_lock);
34824507847cSChao Yu 
34834507847cSChao Yu 	if (copy_to_user((char __user *)arg, vbuf,
34844507847cSChao Yu 				min(FSLABEL_MAX, count)))
34854507847cSChao Yu 		err = -EFAULT;
34864507847cSChao Yu 
3487c8eb7024SChao Yu 	kfree(vbuf);
34884507847cSChao Yu 	return err;
34894507847cSChao Yu }
34904507847cSChao Yu 
f2fs_ioc_setfslabel(struct file * filp,unsigned long arg)34913357af8fSEric Biggers static int f2fs_ioc_setfslabel(struct file *filp, unsigned long arg)
34924507847cSChao Yu {
34934507847cSChao Yu 	struct inode *inode = file_inode(filp);
34944507847cSChao Yu 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
34954507847cSChao Yu 	char *vbuf;
34964507847cSChao Yu 	int err = 0;
34974507847cSChao Yu 
34984507847cSChao Yu 	if (!capable(CAP_SYS_ADMIN))
34994507847cSChao Yu 		return -EPERM;
35004507847cSChao Yu 
35014507847cSChao Yu 	vbuf = strndup_user((const char __user *)arg, FSLABEL_MAX);
35024507847cSChao Yu 	if (IS_ERR(vbuf))
35034507847cSChao Yu 		return PTR_ERR(vbuf);
35044507847cSChao Yu 
35054507847cSChao Yu 	err = mnt_want_write_file(filp);
35064507847cSChao Yu 	if (err)
35074507847cSChao Yu 		goto out;
35084507847cSChao Yu 
3509e4544b63STim Murray 	f2fs_down_write(&sbi->sb_lock);
35104507847cSChao Yu 
35114507847cSChao Yu 	memset(sbi->raw_super->volume_name, 0,
35124507847cSChao Yu 			sizeof(sbi->raw_super->volume_name));
35134507847cSChao Yu 	utf8s_to_utf16s(vbuf, strlen(vbuf), UTF16_LITTLE_ENDIAN,
35144507847cSChao Yu 			sbi->raw_super->volume_name,
35154507847cSChao Yu 			ARRAY_SIZE(sbi->raw_super->volume_name));
35164507847cSChao Yu 
35174507847cSChao Yu 	err = f2fs_commit_super(sbi, false);
35184507847cSChao Yu 
3519e4544b63STim Murray 	f2fs_up_write(&sbi->sb_lock);
35204507847cSChao Yu 
35214507847cSChao Yu 	mnt_drop_write_file(filp);
35224507847cSChao Yu out:
35234507847cSChao Yu 	kfree(vbuf);
35244507847cSChao Yu 	return err;
35254507847cSChao Yu }
35264507847cSChao Yu 
f2fs_get_compress_blocks(struct inode * inode,__u64 * blocks)3527ac1ee161SSheng Yong static int f2fs_get_compress_blocks(struct inode *inode, __u64 *blocks)
3528439dfb10SChao Yu {
3529439dfb10SChao Yu 	if (!f2fs_sb_has_compression(F2FS_I_SB(inode)))
3530439dfb10SChao Yu 		return -EOPNOTSUPP;
3531439dfb10SChao Yu 
3532439dfb10SChao Yu 	if (!f2fs_compressed_file(inode))
3533439dfb10SChao Yu 		return -EINVAL;
3534439dfb10SChao Yu 
3535ac1ee161SSheng Yong 	*blocks = atomic_read(&F2FS_I(inode)->i_compr_blocks);
3536ac1ee161SSheng Yong 
3537ac1ee161SSheng Yong 	return 0;
3538ac1ee161SSheng Yong }
3539ac1ee161SSheng Yong 
f2fs_ioc_get_compress_blocks(struct file * filp,unsigned long arg)3540ac1ee161SSheng Yong static int f2fs_ioc_get_compress_blocks(struct file *filp, unsigned long arg)
3541ac1ee161SSheng Yong {
3542ac1ee161SSheng Yong 	struct inode *inode = file_inode(filp);
3543ac1ee161SSheng Yong 	__u64 blocks;
3544ac1ee161SSheng Yong 	int ret;
3545ac1ee161SSheng Yong 
3546ac1ee161SSheng Yong 	ret = f2fs_get_compress_blocks(inode, &blocks);
3547ac1ee161SSheng Yong 	if (ret < 0)
3548ac1ee161SSheng Yong 		return ret;
3549ac1ee161SSheng Yong 
3550439dfb10SChao Yu 	return put_user(blocks, (u64 __user *)arg);
3551439dfb10SChao Yu }
3552439dfb10SChao Yu 
release_compress_blocks(struct dnode_of_data * dn,pgoff_t count)3553ef8d563fSChao Yu static int release_compress_blocks(struct dnode_of_data *dn, pgoff_t count)
3554ef8d563fSChao Yu {
3555ef8d563fSChao Yu 	struct f2fs_sb_info *sbi = F2FS_I_SB(dn->inode);
3556ef8d563fSChao Yu 	unsigned int released_blocks = 0;
3557ef8d563fSChao Yu 	int cluster_size = F2FS_I(dn->inode)->i_cluster_size;
3558ef8d563fSChao Yu 	block_t blkaddr;
3559ef8d563fSChao Yu 	int i;
3560ef8d563fSChao Yu 
3561ef8d563fSChao Yu 	for (i = 0; i < count; i++) {
3562ef8d563fSChao Yu 		blkaddr = data_blkaddr(dn->inode, dn->node_page,
3563ef8d563fSChao Yu 						dn->ofs_in_node + i);
3564ef8d563fSChao Yu 
3565ef8d563fSChao Yu 		if (!__is_valid_data_blkaddr(blkaddr))
3566ef8d563fSChao Yu 			continue;
3567ef8d563fSChao Yu 		if (unlikely(!f2fs_is_valid_blkaddr(sbi, blkaddr,
356895fa90c9SChao Yu 					DATA_GENERIC_ENHANCE))) {
356995fa90c9SChao Yu 			f2fs_handle_error(sbi, ERROR_INVALID_BLKADDR);
3570ef8d563fSChao Yu 			return -EFSCORRUPTED;
3571ef8d563fSChao Yu 		}
357295fa90c9SChao Yu 	}
3573ef8d563fSChao Yu 
3574ef8d563fSChao Yu 	while (count) {
3575ef8d563fSChao Yu 		int compr_blocks = 0;
3576ef8d563fSChao Yu 
3577ef8d563fSChao Yu 		for (i = 0; i < cluster_size; i++, dn->ofs_in_node++) {
3578ef8d563fSChao Yu 			blkaddr = f2fs_data_blkaddr(dn);
3579ef8d563fSChao Yu 
3580ef8d563fSChao Yu 			if (i == 0) {
3581ef8d563fSChao Yu 				if (blkaddr == COMPRESS_ADDR)
3582ef8d563fSChao Yu 					continue;
3583ef8d563fSChao Yu 				dn->ofs_in_node += cluster_size;
3584ef8d563fSChao Yu 				goto next;
3585ef8d563fSChao Yu 			}
3586ef8d563fSChao Yu 
3587ef8d563fSChao Yu 			if (__is_valid_data_blkaddr(blkaddr))
3588ef8d563fSChao Yu 				compr_blocks++;
3589ef8d563fSChao Yu 
3590ef8d563fSChao Yu 			if (blkaddr != NEW_ADDR)
3591ef8d563fSChao Yu 				continue;
3592ef8d563fSChao Yu 
3593eb6d30bcSChao Yu 			f2fs_set_data_blkaddr(dn, NULL_ADDR);
3594ef8d563fSChao Yu 		}
3595ef8d563fSChao Yu 
3596ef8d563fSChao Yu 		f2fs_i_compr_blocks_update(dn->inode, compr_blocks, false);
3597ef8d563fSChao Yu 		dec_valid_block_count(sbi, dn->inode,
3598ef8d563fSChao Yu 					cluster_size - compr_blocks);
3599ef8d563fSChao Yu 
3600ef8d563fSChao Yu 		released_blocks += cluster_size - compr_blocks;
3601ef8d563fSChao Yu next:
3602ef8d563fSChao Yu 		count -= cluster_size;
3603ef8d563fSChao Yu 	}
3604ef8d563fSChao Yu 
3605ef8d563fSChao Yu 	return released_blocks;
3606ef8d563fSChao Yu }
3607ef8d563fSChao Yu 
f2fs_release_compress_blocks(struct file * filp,unsigned long arg)3608ef8d563fSChao Yu static int f2fs_release_compress_blocks(struct file *filp, unsigned long arg)
3609ef8d563fSChao Yu {
3610ef8d563fSChao Yu 	struct inode *inode = file_inode(filp);
3611ef8d563fSChao Yu 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
3612ef8d563fSChao Yu 	pgoff_t page_idx = 0, last_idx;
3613ef8d563fSChao Yu 	unsigned int released_blocks = 0;
3614ef8d563fSChao Yu 	int ret;
3615ef8d563fSChao Yu 	int writecount;
3616ef8d563fSChao Yu 
3617c3355ea9SYangtao Li 	if (!f2fs_sb_has_compression(sbi))
3618ef8d563fSChao Yu 		return -EOPNOTSUPP;
3619ef8d563fSChao Yu 
3620ef8d563fSChao Yu 	if (f2fs_readonly(sbi->sb))
3621ef8d563fSChao Yu 		return -EROFS;
3622ef8d563fSChao Yu 
3623ef8d563fSChao Yu 	ret = mnt_want_write_file(filp);
3624ef8d563fSChao Yu 	if (ret)
3625ef8d563fSChao Yu 		return ret;
3626ef8d563fSChao Yu 
3627c3355ea9SYangtao Li 	f2fs_balance_fs(sbi, true);
3628ef8d563fSChao Yu 
3629ef8d563fSChao Yu 	inode_lock(inode);
3630ef8d563fSChao Yu 
3631ef8d563fSChao Yu 	writecount = atomic_read(&inode->i_writecount);
36328c8cf26aSDaeho Jeong 	if ((filp->f_mode & FMODE_WRITE && writecount != 1) ||
36338c8cf26aSDaeho Jeong 			(!(filp->f_mode & FMODE_WRITE) && writecount)) {
3634ef8d563fSChao Yu 		ret = -EBUSY;
3635ef8d563fSChao Yu 		goto out;
3636ef8d563fSChao Yu 	}
3637ef8d563fSChao Yu 
36381d59aa23SChao Yu 	if (!f2fs_compressed_file(inode) ||
36391d59aa23SChao Yu 		is_inode_flag_set(inode, FI_COMPRESS_RELEASED)) {
3640ef8d563fSChao Yu 		ret = -EINVAL;
3641ef8d563fSChao Yu 		goto out;
3642ef8d563fSChao Yu 	}
3643ef8d563fSChao Yu 
3644ef8d563fSChao Yu 	ret = filemap_write_and_wait_range(inode->i_mapping, 0, LLONG_MAX);
3645ef8d563fSChao Yu 	if (ret)
3646ef8d563fSChao Yu 		goto out;
3647ef8d563fSChao Yu 
364887a91a15SSheng Yong 	if (!atomic_read(&F2FS_I(inode)->i_compr_blocks)) {
364987a91a15SSheng Yong 		ret = -EPERM;
365087a91a15SSheng Yong 		goto out;
365187a91a15SSheng Yong 	}
365287a91a15SSheng Yong 
3653c6140415SJaegeuk Kim 	set_inode_flag(inode, FI_COMPRESS_RELEASED);
3654c62ebd35SJeff Layton 	inode_set_ctime_current(inode);
3655ef8d563fSChao Yu 	f2fs_mark_inode_dirty_sync(inode, true);
3656ef8d563fSChao Yu 
3657e4544b63STim Murray 	f2fs_down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
3658edc6d01bSJan Kara 	filemap_invalidate_lock(inode->i_mapping);
3659ef8d563fSChao Yu 
3660ef8d563fSChao Yu 	last_idx = DIV_ROUND_UP(i_size_read(inode), PAGE_SIZE);
3661ef8d563fSChao Yu 
3662ef8d563fSChao Yu 	while (page_idx < last_idx) {
3663ef8d563fSChao Yu 		struct dnode_of_data dn;
3664ef8d563fSChao Yu 		pgoff_t end_offset, count;
3665ef8d563fSChao Yu 
3666329edb7cSChao Yu 		f2fs_lock_op(sbi);
3667329edb7cSChao Yu 
3668ef8d563fSChao Yu 		set_new_dnode(&dn, inode, NULL, NULL, 0);
3669ef8d563fSChao Yu 		ret = f2fs_get_dnode_of_data(&dn, page_idx, LOOKUP_NODE);
3670ef8d563fSChao Yu 		if (ret) {
3671329edb7cSChao Yu 			f2fs_unlock_op(sbi);
3672ef8d563fSChao Yu 			if (ret == -ENOENT) {
3673ef8d563fSChao Yu 				page_idx = f2fs_get_next_page_offset(&dn,
3674ef8d563fSChao Yu 								page_idx);
3675ef8d563fSChao Yu 				ret = 0;
3676ef8d563fSChao Yu 				continue;
3677ef8d563fSChao Yu 			}
3678ef8d563fSChao Yu 			break;
3679ef8d563fSChao Yu 		}
3680ef8d563fSChao Yu 
3681ef8d563fSChao Yu 		end_offset = ADDRS_PER_PAGE(dn.node_page, inode);
3682ef8d563fSChao Yu 		count = min(end_offset - dn.ofs_in_node, last_idx - page_idx);
36834fec3fc0SChao Yu 		count = round_up(count, F2FS_I(inode)->i_cluster_size);
3684ef8d563fSChao Yu 
3685ef8d563fSChao Yu 		ret = release_compress_blocks(&dn, count);
3686ef8d563fSChao Yu 
3687ef8d563fSChao Yu 		f2fs_put_dnode(&dn);
3688ef8d563fSChao Yu 
3689329edb7cSChao Yu 		f2fs_unlock_op(sbi);
3690329edb7cSChao Yu 
3691ef8d563fSChao Yu 		if (ret < 0)
3692ef8d563fSChao Yu 			break;
3693ef8d563fSChao Yu 
3694ef8d563fSChao Yu 		page_idx += count;
3695ef8d563fSChao Yu 		released_blocks += ret;
3696ef8d563fSChao Yu 	}
3697ef8d563fSChao Yu 
3698edc6d01bSJan Kara 	filemap_invalidate_unlock(inode->i_mapping);
3699e4544b63STim Murray 	f2fs_up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
3700ef8d563fSChao Yu out:
3701ef8d563fSChao Yu 	inode_unlock(inode);
3702ef8d563fSChao Yu 
3703ef8d563fSChao Yu 	mnt_drop_write_file(filp);
3704ef8d563fSChao Yu 
3705ef8d563fSChao Yu 	if (ret >= 0) {
3706ef8d563fSChao Yu 		ret = put_user(released_blocks, (u64 __user *)arg);
3707c2759ebaSDaeho Jeong 	} else if (released_blocks &&
3708c2759ebaSDaeho Jeong 			atomic_read(&F2FS_I(inode)->i_compr_blocks)) {
3709ef8d563fSChao Yu 		set_sbi_flag(sbi, SBI_NEED_FSCK);
3710ef8d563fSChao Yu 		f2fs_warn(sbi, "%s: partial blocks were released i_ino=%lx "
3711c2759ebaSDaeho Jeong 			"iblocks=%llu, released=%u, compr_blocks=%u, "
3712ef8d563fSChao Yu 			"run fsck to fix.",
3713ef8d563fSChao Yu 			__func__, inode->i_ino, inode->i_blocks,
3714ef8d563fSChao Yu 			released_blocks,
3715c2759ebaSDaeho Jeong 			atomic_read(&F2FS_I(inode)->i_compr_blocks));
3716ef8d563fSChao Yu 	}
3717ef8d563fSChao Yu 
3718ef8d563fSChao Yu 	return ret;
3719ef8d563fSChao Yu }
3720ef8d563fSChao Yu 
reserve_compress_blocks(struct dnode_of_data * dn,pgoff_t count,unsigned int * reserved_blocks)3721f0bf89e8SXiuhong Wang static int reserve_compress_blocks(struct dnode_of_data *dn, pgoff_t count,
3722f0bf89e8SXiuhong Wang 		unsigned int *reserved_blocks)
3723c75488fbSChao Yu {
3724c75488fbSChao Yu 	struct f2fs_sb_info *sbi = F2FS_I_SB(dn->inode);
3725c75488fbSChao Yu 	int cluster_size = F2FS_I(dn->inode)->i_cluster_size;
3726c75488fbSChao Yu 	block_t blkaddr;
3727c75488fbSChao Yu 	int i;
3728c75488fbSChao Yu 
3729c75488fbSChao Yu 	for (i = 0; i < count; i++) {
3730c75488fbSChao Yu 		blkaddr = data_blkaddr(dn->inode, dn->node_page,
3731c75488fbSChao Yu 						dn->ofs_in_node + i);
3732c75488fbSChao Yu 
3733c75488fbSChao Yu 		if (!__is_valid_data_blkaddr(blkaddr))
3734c75488fbSChao Yu 			continue;
3735c75488fbSChao Yu 		if (unlikely(!f2fs_is_valid_blkaddr(sbi, blkaddr,
373695fa90c9SChao Yu 					DATA_GENERIC_ENHANCE))) {
373795fa90c9SChao Yu 			f2fs_handle_error(sbi, ERROR_INVALID_BLKADDR);
3738c75488fbSChao Yu 			return -EFSCORRUPTED;
3739c75488fbSChao Yu 		}
374095fa90c9SChao Yu 	}
3741c75488fbSChao Yu 
3742c75488fbSChao Yu 	while (count) {
3743c75488fbSChao Yu 		int compr_blocks = 0;
374492b24f04SChao Yu 		blkcnt_t reserved = 0;
374592b24f04SChao Yu 		blkcnt_t to_reserved;
3746c75488fbSChao Yu 		int ret;
3747c75488fbSChao Yu 
3748bc1e3992SChao Yu 		for (i = 0; i < cluster_size; i++) {
3749bc1e3992SChao Yu 			blkaddr = data_blkaddr(dn->inode, dn->node_page,
3750bc1e3992SChao Yu 						dn->ofs_in_node + i);
3751c75488fbSChao Yu 
3752c75488fbSChao Yu 			if (i == 0) {
3753bc1e3992SChao Yu 				if (blkaddr != COMPRESS_ADDR) {
3754c75488fbSChao Yu 					dn->ofs_in_node += cluster_size;
3755c75488fbSChao Yu 					goto next;
3756c75488fbSChao Yu 				}
3757bc1e3992SChao Yu 				continue;
3758bc1e3992SChao Yu 			}
3759c75488fbSChao Yu 
3760d415e1c9SSheng Yong 			/*
3761d415e1c9SSheng Yong 			 * compressed cluster was not released due to it
3762d415e1c9SSheng Yong 			 * fails in release_compress_blocks(), so NEW_ADDR
3763d415e1c9SSheng Yong 			 * is a possible case.
3764d415e1c9SSheng Yong 			 */
376592b24f04SChao Yu 			if (blkaddr == NEW_ADDR) {
376692b24f04SChao Yu 				reserved++;
376792b24f04SChao Yu 				continue;
376892b24f04SChao Yu 			}
376992b24f04SChao Yu 			if (__is_valid_data_blkaddr(blkaddr)) {
3770c75488fbSChao Yu 				compr_blocks++;
3771c75488fbSChao Yu 				continue;
3772c75488fbSChao Yu 			}
3773c75488fbSChao Yu 		}
3774c75488fbSChao Yu 
377592b24f04SChao Yu 		to_reserved = cluster_size - compr_blocks - reserved;
3776d415e1c9SSheng Yong 
3777d415e1c9SSheng Yong 		/* for the case all blocks in cluster were reserved */
37786b0ed65cSQi Han 		if (reserved && to_reserved == 1) {
377992b24f04SChao Yu 			dn->ofs_in_node += cluster_size;
3780d415e1c9SSheng Yong 			goto next;
378192b24f04SChao Yu 		}
3782d415e1c9SSheng Yong 
378392b24f04SChao Yu 		ret = inc_valid_block_count(sbi, dn->inode,
378492b24f04SChao Yu 						&to_reserved, false);
3785bc1e3992SChao Yu 		if (unlikely(ret))
3786c75488fbSChao Yu 			return ret;
3787c75488fbSChao Yu 
3788bc1e3992SChao Yu 		for (i = 0; i < cluster_size; i++, dn->ofs_in_node++) {
3789bc1e3992SChao Yu 			if (f2fs_data_blkaddr(dn) == NULL_ADDR)
3790bc1e3992SChao Yu 				f2fs_set_data_blkaddr(dn, NEW_ADDR);
3791bc1e3992SChao Yu 		}
3792c75488fbSChao Yu 
3793c75488fbSChao Yu 		f2fs_i_compr_blocks_update(dn->inode, compr_blocks, true);
3794c75488fbSChao Yu 
379592b24f04SChao Yu 		*reserved_blocks += to_reserved;
3796c75488fbSChao Yu next:
3797c75488fbSChao Yu 		count -= cluster_size;
3798c75488fbSChao Yu 	}
3799c75488fbSChao Yu 
3800f0bf89e8SXiuhong Wang 	return 0;
3801c75488fbSChao Yu }
3802c75488fbSChao Yu 
f2fs_reserve_compress_blocks(struct file * filp,unsigned long arg)3803c75488fbSChao Yu static int f2fs_reserve_compress_blocks(struct file *filp, unsigned long arg)
3804c75488fbSChao Yu {
3805c75488fbSChao Yu 	struct inode *inode = file_inode(filp);
3806c75488fbSChao Yu 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
3807c75488fbSChao Yu 	pgoff_t page_idx = 0, last_idx;
3808c75488fbSChao Yu 	unsigned int reserved_blocks = 0;
3809c75488fbSChao Yu 	int ret;
3810c75488fbSChao Yu 
3811c3355ea9SYangtao Li 	if (!f2fs_sb_has_compression(sbi))
3812c75488fbSChao Yu 		return -EOPNOTSUPP;
3813c75488fbSChao Yu 
3814c75488fbSChao Yu 	if (f2fs_readonly(sbi->sb))
3815c75488fbSChao Yu 		return -EROFS;
3816c75488fbSChao Yu 
3817c75488fbSChao Yu 	ret = mnt_want_write_file(filp);
3818c75488fbSChao Yu 	if (ret)
3819c75488fbSChao Yu 		return ret;
3820c75488fbSChao Yu 
3821c3355ea9SYangtao Li 	f2fs_balance_fs(sbi, true);
3822c75488fbSChao Yu 
3823c75488fbSChao Yu 	inode_lock(inode);
3824c75488fbSChao Yu 
38251d59aa23SChao Yu 	if (!f2fs_compressed_file(inode) ||
38261d59aa23SChao Yu 		!is_inode_flag_set(inode, FI_COMPRESS_RELEASED)) {
3827c75488fbSChao Yu 		ret = -EINVAL;
3828c75488fbSChao Yu 		goto unlock_inode;
3829c75488fbSChao Yu 	}
3830c75488fbSChao Yu 
38314d1a3b79SXiuhong Wang 	if (atomic_read(&F2FS_I(inode)->i_compr_blocks))
38324d1a3b79SXiuhong Wang 		goto unlock_inode;
38334d1a3b79SXiuhong Wang 
3834e4544b63STim Murray 	f2fs_down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
3835edc6d01bSJan Kara 	filemap_invalidate_lock(inode->i_mapping);
3836c75488fbSChao Yu 
3837c75488fbSChao Yu 	last_idx = DIV_ROUND_UP(i_size_read(inode), PAGE_SIZE);
3838c75488fbSChao Yu 
3839c75488fbSChao Yu 	while (page_idx < last_idx) {
3840c75488fbSChao Yu 		struct dnode_of_data dn;
3841c75488fbSChao Yu 		pgoff_t end_offset, count;
3842c75488fbSChao Yu 
3843329edb7cSChao Yu 		f2fs_lock_op(sbi);
3844329edb7cSChao Yu 
3845c75488fbSChao Yu 		set_new_dnode(&dn, inode, NULL, NULL, 0);
3846c75488fbSChao Yu 		ret = f2fs_get_dnode_of_data(&dn, page_idx, LOOKUP_NODE);
3847c75488fbSChao Yu 		if (ret) {
3848329edb7cSChao Yu 			f2fs_unlock_op(sbi);
3849c75488fbSChao Yu 			if (ret == -ENOENT) {
3850c75488fbSChao Yu 				page_idx = f2fs_get_next_page_offset(&dn,
3851c75488fbSChao Yu 								page_idx);
3852c75488fbSChao Yu 				ret = 0;
3853c75488fbSChao Yu 				continue;
3854c75488fbSChao Yu 			}
3855c75488fbSChao Yu 			break;
3856c75488fbSChao Yu 		}
3857c75488fbSChao Yu 
3858c75488fbSChao Yu 		end_offset = ADDRS_PER_PAGE(dn.node_page, inode);
3859c75488fbSChao Yu 		count = min(end_offset - dn.ofs_in_node, last_idx - page_idx);
38604fec3fc0SChao Yu 		count = round_up(count, F2FS_I(inode)->i_cluster_size);
3861c75488fbSChao Yu 
3862f0bf89e8SXiuhong Wang 		ret = reserve_compress_blocks(&dn, count, &reserved_blocks);
3863c75488fbSChao Yu 
3864c75488fbSChao Yu 		f2fs_put_dnode(&dn);
3865c75488fbSChao Yu 
3866329edb7cSChao Yu 		f2fs_unlock_op(sbi);
3867329edb7cSChao Yu 
3868c75488fbSChao Yu 		if (ret < 0)
3869c75488fbSChao Yu 			break;
3870c75488fbSChao Yu 
3871c75488fbSChao Yu 		page_idx += count;
3872c75488fbSChao Yu 	}
3873c75488fbSChao Yu 
3874edc6d01bSJan Kara 	filemap_invalidate_unlock(inode->i_mapping);
3875e4544b63STim Murray 	f2fs_up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
3876c75488fbSChao Yu 
3877f0bf89e8SXiuhong Wang 	if (!ret) {
3878c6140415SJaegeuk Kim 		clear_inode_flag(inode, FI_COMPRESS_RELEASED);
3879c62ebd35SJeff Layton 		inode_set_ctime_current(inode);
3880c75488fbSChao Yu 		f2fs_mark_inode_dirty_sync(inode, true);
3881c75488fbSChao Yu 	}
3882c75488fbSChao Yu unlock_inode:
3883c75488fbSChao Yu 	inode_unlock(inode);
3884c75488fbSChao Yu 	mnt_drop_write_file(filp);
3885c75488fbSChao Yu 
3886f0bf89e8SXiuhong Wang 	if (!ret) {
3887c75488fbSChao Yu 		ret = put_user(reserved_blocks, (u64 __user *)arg);
3888c2759ebaSDaeho Jeong 	} else if (reserved_blocks &&
3889c2759ebaSDaeho Jeong 			atomic_read(&F2FS_I(inode)->i_compr_blocks)) {
3890c75488fbSChao Yu 		set_sbi_flag(sbi, SBI_NEED_FSCK);
3891c75488fbSChao Yu 		f2fs_warn(sbi, "%s: partial blocks were released i_ino=%lx "
3892c2759ebaSDaeho Jeong 			"iblocks=%llu, reserved=%u, compr_blocks=%u, "
3893c75488fbSChao Yu 			"run fsck to fix.",
3894c75488fbSChao Yu 			__func__, inode->i_ino, inode->i_blocks,
3895c75488fbSChao Yu 			reserved_blocks,
3896c2759ebaSDaeho Jeong 			atomic_read(&F2FS_I(inode)->i_compr_blocks));
3897c75488fbSChao Yu 	}
3898c75488fbSChao Yu 
3899c75488fbSChao Yu 	return ret;
3900c75488fbSChao Yu }
3901c75488fbSChao Yu 
f2fs_secure_erase(struct block_device * bdev,struct inode * inode,pgoff_t off,block_t block,block_t len,u32 flags)39029af84648SDaeho Jeong static int f2fs_secure_erase(struct block_device *bdev, struct inode *inode,
39039af84648SDaeho Jeong 		pgoff_t off, block_t block, block_t len, u32 flags)
39049af84648SDaeho Jeong {
39059af84648SDaeho Jeong 	sector_t sector = SECTOR_FROM_BLOCK(block);
39069af84648SDaeho Jeong 	sector_t nr_sects = SECTOR_FROM_BLOCK(len);
39079af84648SDaeho Jeong 	int ret = 0;
39089af84648SDaeho Jeong 
390944abff2cSChristoph Hellwig 	if (flags & F2FS_TRIM_FILE_DISCARD) {
391044abff2cSChristoph Hellwig 		if (bdev_max_secure_erase_sectors(bdev))
391144abff2cSChristoph Hellwig 			ret = blkdev_issue_secure_erase(bdev, sector, nr_sects,
391244abff2cSChristoph Hellwig 					GFP_NOFS);
391344abff2cSChristoph Hellwig 		else
391444abff2cSChristoph Hellwig 			ret = blkdev_issue_discard(bdev, sector, nr_sects,
391544abff2cSChristoph Hellwig 					GFP_NOFS);
391644abff2cSChristoph Hellwig 	}
39179af84648SDaeho Jeong 
39189af84648SDaeho Jeong 	if (!ret && (flags & F2FS_TRIM_FILE_ZEROOUT)) {
39199af84648SDaeho Jeong 		if (IS_ENCRYPTED(inode))
39209af84648SDaeho Jeong 			ret = fscrypt_zeroout_range(inode, off, block, len);
39219af84648SDaeho Jeong 		else
39229af84648SDaeho Jeong 			ret = blkdev_issue_zeroout(bdev, sector, nr_sects,
39239af84648SDaeho Jeong 					GFP_NOFS, 0);
39249af84648SDaeho Jeong 	}
39259af84648SDaeho Jeong 
39269af84648SDaeho Jeong 	return ret;
39279af84648SDaeho Jeong }
39289af84648SDaeho Jeong 
f2fs_sec_trim_file(struct file * filp,unsigned long arg)39299af84648SDaeho Jeong static int f2fs_sec_trim_file(struct file *filp, unsigned long arg)
39309af84648SDaeho Jeong {
39319af84648SDaeho Jeong 	struct inode *inode = file_inode(filp);
39329af84648SDaeho Jeong 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
39339af84648SDaeho Jeong 	struct address_space *mapping = inode->i_mapping;
39349af84648SDaeho Jeong 	struct block_device *prev_bdev = NULL;
39359af84648SDaeho Jeong 	struct f2fs_sectrim_range range;
39369af84648SDaeho Jeong 	pgoff_t index, pg_end, prev_index = 0;
39379af84648SDaeho Jeong 	block_t prev_block = 0, len = 0;
39389af84648SDaeho Jeong 	loff_t end_addr;
39399af84648SDaeho Jeong 	bool to_end = false;
39409af84648SDaeho Jeong 	int ret = 0;
39419af84648SDaeho Jeong 
39429af84648SDaeho Jeong 	if (!(filp->f_mode & FMODE_WRITE))
39439af84648SDaeho Jeong 		return -EBADF;
39449af84648SDaeho Jeong 
39459af84648SDaeho Jeong 	if (copy_from_user(&range, (struct f2fs_sectrim_range __user *)arg,
39469af84648SDaeho Jeong 				sizeof(range)))
39479af84648SDaeho Jeong 		return -EFAULT;
39489af84648SDaeho Jeong 
39499af84648SDaeho Jeong 	if (range.flags == 0 || (range.flags & ~F2FS_TRIM_FILE_MASK) ||
39509af84648SDaeho Jeong 			!S_ISREG(inode->i_mode))
39519af84648SDaeho Jeong 		return -EINVAL;
39529af84648SDaeho Jeong 
39539af84648SDaeho Jeong 	if (((range.flags & F2FS_TRIM_FILE_DISCARD) &&
39549af84648SDaeho Jeong 			!f2fs_hw_support_discard(sbi)) ||
39559af84648SDaeho Jeong 			((range.flags & F2FS_TRIM_FILE_ZEROOUT) &&
39569af84648SDaeho Jeong 			 IS_ENCRYPTED(inode) && f2fs_is_multi_device(sbi)))
39579af84648SDaeho Jeong 		return -EOPNOTSUPP;
39589af84648SDaeho Jeong 
39599af84648SDaeho Jeong 	file_start_write(filp);
39609af84648SDaeho Jeong 	inode_lock(inode);
39619af84648SDaeho Jeong 
39629af84648SDaeho Jeong 	if (f2fs_is_atomic_file(inode) || f2fs_compressed_file(inode) ||
39639af84648SDaeho Jeong 			range.start >= inode->i_size) {
39649af84648SDaeho Jeong 		ret = -EINVAL;
39659af84648SDaeho Jeong 		goto err;
39669af84648SDaeho Jeong 	}
39679af84648SDaeho Jeong 
39689af84648SDaeho Jeong 	if (range.len == 0)
39699af84648SDaeho Jeong 		goto err;
39709af84648SDaeho Jeong 
39719af84648SDaeho Jeong 	if (inode->i_size - range.start > range.len) {
39729af84648SDaeho Jeong 		end_addr = range.start + range.len;
39739af84648SDaeho Jeong 	} else {
39749af84648SDaeho Jeong 		end_addr = range.len == (u64)-1 ?
39759af84648SDaeho Jeong 			sbi->sb->s_maxbytes : inode->i_size;
39769af84648SDaeho Jeong 		to_end = true;
39779af84648SDaeho Jeong 	}
39789af84648SDaeho Jeong 
39799af84648SDaeho Jeong 	if (!IS_ALIGNED(range.start, F2FS_BLKSIZE) ||
39809af84648SDaeho Jeong 			(!to_end && !IS_ALIGNED(end_addr, F2FS_BLKSIZE))) {
39819af84648SDaeho Jeong 		ret = -EINVAL;
39829af84648SDaeho Jeong 		goto err;
39839af84648SDaeho Jeong 	}
39849af84648SDaeho Jeong 
39859af84648SDaeho Jeong 	index = F2FS_BYTES_TO_BLK(range.start);
39869af84648SDaeho Jeong 	pg_end = DIV_ROUND_UP(end_addr, F2FS_BLKSIZE);
39879af84648SDaeho Jeong 
39889af84648SDaeho Jeong 	ret = f2fs_convert_inline_inode(inode);
39899af84648SDaeho Jeong 	if (ret)
39909af84648SDaeho Jeong 		goto err;
39919af84648SDaeho Jeong 
3992e4544b63STim Murray 	f2fs_down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
3993edc6d01bSJan Kara 	filemap_invalidate_lock(mapping);
39949af84648SDaeho Jeong 
39959af84648SDaeho Jeong 	ret = filemap_write_and_wait_range(mapping, range.start,
39969af84648SDaeho Jeong 			to_end ? LLONG_MAX : end_addr - 1);
39979af84648SDaeho Jeong 	if (ret)
39989af84648SDaeho Jeong 		goto out;
39999af84648SDaeho Jeong 
40009af84648SDaeho Jeong 	truncate_inode_pages_range(mapping, range.start,
40019af84648SDaeho Jeong 			to_end ? -1 : end_addr - 1);
40029af84648SDaeho Jeong 
40039af84648SDaeho Jeong 	while (index < pg_end) {
40049af84648SDaeho Jeong 		struct dnode_of_data dn;
40059af84648SDaeho Jeong 		pgoff_t end_offset, count;
40069af84648SDaeho Jeong 		int i;
40079af84648SDaeho Jeong 
40089af84648SDaeho Jeong 		set_new_dnode(&dn, inode, NULL, NULL, 0);
40099af84648SDaeho Jeong 		ret = f2fs_get_dnode_of_data(&dn, index, LOOKUP_NODE);
40109af84648SDaeho Jeong 		if (ret) {
40119af84648SDaeho Jeong 			if (ret == -ENOENT) {
40129af84648SDaeho Jeong 				index = f2fs_get_next_page_offset(&dn, index);
40139af84648SDaeho Jeong 				continue;
40149af84648SDaeho Jeong 			}
40159af84648SDaeho Jeong 			goto out;
40169af84648SDaeho Jeong 		}
40179af84648SDaeho Jeong 
40189af84648SDaeho Jeong 		end_offset = ADDRS_PER_PAGE(dn.node_page, inode);
40199af84648SDaeho Jeong 		count = min(end_offset - dn.ofs_in_node, pg_end - index);
40209af84648SDaeho Jeong 		for (i = 0; i < count; i++, index++, dn.ofs_in_node++) {
40219af84648SDaeho Jeong 			struct block_device *cur_bdev;
40229af84648SDaeho Jeong 			block_t blkaddr = f2fs_data_blkaddr(&dn);
40239af84648SDaeho Jeong 
40249af84648SDaeho Jeong 			if (!__is_valid_data_blkaddr(blkaddr))
40259af84648SDaeho Jeong 				continue;
40269af84648SDaeho Jeong 
40279af84648SDaeho Jeong 			if (!f2fs_is_valid_blkaddr(sbi, blkaddr,
40289af84648SDaeho Jeong 						DATA_GENERIC_ENHANCE)) {
40299af84648SDaeho Jeong 				ret = -EFSCORRUPTED;
40309af84648SDaeho Jeong 				f2fs_put_dnode(&dn);
403195fa90c9SChao Yu 				f2fs_handle_error(sbi,
403295fa90c9SChao Yu 						ERROR_INVALID_BLKADDR);
40339af84648SDaeho Jeong 				goto out;
40349af84648SDaeho Jeong 			}
40359af84648SDaeho Jeong 
40369af84648SDaeho Jeong 			cur_bdev = f2fs_target_device(sbi, blkaddr, NULL);
40379af84648SDaeho Jeong 			if (f2fs_is_multi_device(sbi)) {
40389af84648SDaeho Jeong 				int di = f2fs_target_device_index(sbi, blkaddr);
40399af84648SDaeho Jeong 
40409af84648SDaeho Jeong 				blkaddr -= FDEV(di).start_blk;
40419af84648SDaeho Jeong 			}
40429af84648SDaeho Jeong 
40439af84648SDaeho Jeong 			if (len) {
40449af84648SDaeho Jeong 				if (prev_bdev == cur_bdev &&
40459af84648SDaeho Jeong 						index == prev_index + len &&
40469af84648SDaeho Jeong 						blkaddr == prev_block + len) {
40479af84648SDaeho Jeong 					len++;
40489af84648SDaeho Jeong 				} else {
40499af84648SDaeho Jeong 					ret = f2fs_secure_erase(prev_bdev,
40509af84648SDaeho Jeong 						inode, prev_index, prev_block,
40519af84648SDaeho Jeong 						len, range.flags);
40529af84648SDaeho Jeong 					if (ret) {
40539af84648SDaeho Jeong 						f2fs_put_dnode(&dn);
40549af84648SDaeho Jeong 						goto out;
40559af84648SDaeho Jeong 					}
40569af84648SDaeho Jeong 
40579af84648SDaeho Jeong 					len = 0;
40589af84648SDaeho Jeong 				}
40599af84648SDaeho Jeong 			}
40609af84648SDaeho Jeong 
40619af84648SDaeho Jeong 			if (!len) {
40629af84648SDaeho Jeong 				prev_bdev = cur_bdev;
40639af84648SDaeho Jeong 				prev_index = index;
40649af84648SDaeho Jeong 				prev_block = blkaddr;
40659af84648SDaeho Jeong 				len = 1;
40669af84648SDaeho Jeong 			}
40679af84648SDaeho Jeong 		}
40689af84648SDaeho Jeong 
40699af84648SDaeho Jeong 		f2fs_put_dnode(&dn);
40709af84648SDaeho Jeong 
40719af84648SDaeho Jeong 		if (fatal_signal_pending(current)) {
40729af84648SDaeho Jeong 			ret = -EINTR;
40739af84648SDaeho Jeong 			goto out;
40749af84648SDaeho Jeong 		}
40759af84648SDaeho Jeong 		cond_resched();
40769af84648SDaeho Jeong 	}
40779af84648SDaeho Jeong 
40789af84648SDaeho Jeong 	if (len)
40799af84648SDaeho Jeong 		ret = f2fs_secure_erase(prev_bdev, inode, prev_index,
40809af84648SDaeho Jeong 				prev_block, len, range.flags);
40819af84648SDaeho Jeong out:
4082edc6d01bSJan Kara 	filemap_invalidate_unlock(mapping);
4083e4544b63STim Murray 	f2fs_up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
40849af84648SDaeho Jeong err:
40859af84648SDaeho Jeong 	inode_unlock(inode);
40869af84648SDaeho Jeong 	file_end_write(filp);
40879af84648SDaeho Jeong 
40889af84648SDaeho Jeong 	return ret;
40899af84648SDaeho Jeong }
40909af84648SDaeho Jeong 
f2fs_ioc_get_compress_option(struct file * filp,unsigned long arg)40919e2a5f8cSDaeho Jeong static int f2fs_ioc_get_compress_option(struct file *filp, unsigned long arg)
409252656e6cSJaegeuk Kim {
40939e2a5f8cSDaeho Jeong 	struct inode *inode = file_inode(filp);
40949e2a5f8cSDaeho Jeong 	struct f2fs_comp_option option;
40951f227a3eSJaegeuk Kim 
40969e2a5f8cSDaeho Jeong 	if (!f2fs_sb_has_compression(F2FS_I_SB(inode)))
40979e2a5f8cSDaeho Jeong 		return -EOPNOTSUPP;
40989e2a5f8cSDaeho Jeong 
40999e2a5f8cSDaeho Jeong 	inode_lock_shared(inode);
41009e2a5f8cSDaeho Jeong 
41019e2a5f8cSDaeho Jeong 	if (!f2fs_compressed_file(inode)) {
41029e2a5f8cSDaeho Jeong 		inode_unlock_shared(inode);
41039e2a5f8cSDaeho Jeong 		return -ENODATA;
41049e2a5f8cSDaeho Jeong 	}
41059e2a5f8cSDaeho Jeong 
41069e2a5f8cSDaeho Jeong 	option.algorithm = F2FS_I(inode)->i_compress_algorithm;
41079e2a5f8cSDaeho Jeong 	option.log_cluster_size = F2FS_I(inode)->i_log_cluster_size;
41089e2a5f8cSDaeho Jeong 
41099e2a5f8cSDaeho Jeong 	inode_unlock_shared(inode);
41109e2a5f8cSDaeho Jeong 
41119e2a5f8cSDaeho Jeong 	if (copy_to_user((struct f2fs_comp_option __user *)arg, &option,
41129e2a5f8cSDaeho Jeong 				sizeof(option)))
41139e2a5f8cSDaeho Jeong 		return -EFAULT;
41149e2a5f8cSDaeho Jeong 
41159e2a5f8cSDaeho Jeong 	return 0;
41169e2a5f8cSDaeho Jeong }
41179e2a5f8cSDaeho Jeong 
f2fs_ioc_set_compress_option(struct file * filp,unsigned long arg)4118e1e8debeSDaeho Jeong static int f2fs_ioc_set_compress_option(struct file *filp, unsigned long arg)
4119e1e8debeSDaeho Jeong {
4120e1e8debeSDaeho Jeong 	struct inode *inode = file_inode(filp);
4121e1e8debeSDaeho Jeong 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
4122e1e8debeSDaeho Jeong 	struct f2fs_comp_option option;
4123e1e8debeSDaeho Jeong 	int ret = 0;
4124e1e8debeSDaeho Jeong 
4125e1e8debeSDaeho Jeong 	if (!f2fs_sb_has_compression(sbi))
4126e1e8debeSDaeho Jeong 		return -EOPNOTSUPP;
4127e1e8debeSDaeho Jeong 
4128e1e8debeSDaeho Jeong 	if (!(filp->f_mode & FMODE_WRITE))
4129e1e8debeSDaeho Jeong 		return -EBADF;
4130e1e8debeSDaeho Jeong 
4131e1e8debeSDaeho Jeong 	if (copy_from_user(&option, (struct f2fs_comp_option __user *)arg,
4132e1e8debeSDaeho Jeong 				sizeof(option)))
4133e1e8debeSDaeho Jeong 		return -EFAULT;
4134e1e8debeSDaeho Jeong 
413541e8018bSChao Yu 	if (option.log_cluster_size < MIN_COMPRESS_LOG_SIZE ||
4136e1e8debeSDaeho Jeong 		option.log_cluster_size > MAX_COMPRESS_LOG_SIZE ||
4137e1e8debeSDaeho Jeong 		option.algorithm >= COMPRESS_MAX)
4138e1e8debeSDaeho Jeong 		return -EINVAL;
4139e1e8debeSDaeho Jeong 
4140e1e8debeSDaeho Jeong 	file_start_write(filp);
4141e1e8debeSDaeho Jeong 	inode_lock(inode);
4142e1e8debeSDaeho Jeong 
4143b5ab3276SChao Yu 	f2fs_down_write(&F2FS_I(inode)->i_sem);
414441e8018bSChao Yu 	if (!f2fs_compressed_file(inode)) {
414541e8018bSChao Yu 		ret = -EINVAL;
414641e8018bSChao Yu 		goto out;
414741e8018bSChao Yu 	}
414841e8018bSChao Yu 
4149e1e8debeSDaeho Jeong 	if (f2fs_is_mmap_file(inode) || get_dirty_pages(inode)) {
4150e1e8debeSDaeho Jeong 		ret = -EBUSY;
4151e1e8debeSDaeho Jeong 		goto out;
4152e1e8debeSDaeho Jeong 	}
4153e1e8debeSDaeho Jeong 
4154e6261bebSYangtao Li 	if (F2FS_HAS_BLOCKS(inode)) {
4155e1e8debeSDaeho Jeong 		ret = -EFBIG;
4156e1e8debeSDaeho Jeong 		goto out;
4157e1e8debeSDaeho Jeong 	}
4158e1e8debeSDaeho Jeong 
4159e1e8debeSDaeho Jeong 	F2FS_I(inode)->i_compress_algorithm = option.algorithm;
4160e1e8debeSDaeho Jeong 	F2FS_I(inode)->i_log_cluster_size = option.log_cluster_size;
4161447286ebSYangtao Li 	F2FS_I(inode)->i_cluster_size = BIT(option.log_cluster_size);
416200de7280SJaegeuk Kim 	/* Set default level */
416300de7280SJaegeuk Kim 	if (F2FS_I(inode)->i_compress_algorithm == COMPRESS_ZSTD)
416400de7280SJaegeuk Kim 		F2FS_I(inode)->i_compress_level = F2FS_ZSTD_DEFAULT_CLEVEL;
416500de7280SJaegeuk Kim 	else
416600de7280SJaegeuk Kim 		F2FS_I(inode)->i_compress_level = 0;
416700de7280SJaegeuk Kim 	/* Adjust mount option level */
416800de7280SJaegeuk Kim 	if (option.algorithm == F2FS_OPTION(sbi).compress_algorithm &&
416900de7280SJaegeuk Kim 	    F2FS_OPTION(sbi).compress_level)
417000de7280SJaegeuk Kim 		F2FS_I(inode)->i_compress_level = F2FS_OPTION(sbi).compress_level;
4171e1e8debeSDaeho Jeong 	f2fs_mark_inode_dirty_sync(inode, true);
4172e1e8debeSDaeho Jeong 
4173e1e8debeSDaeho Jeong 	if (!f2fs_is_compress_backend_ready(inode))
4174e1e8debeSDaeho Jeong 		f2fs_warn(sbi, "compression algorithm is successfully set, "
4175e1e8debeSDaeho Jeong 			"but current kernel doesn't support this algorithm.");
4176e1e8debeSDaeho Jeong out:
4177b5ab3276SChao Yu 	f2fs_up_write(&F2FS_I(inode)->i_sem);
4178e1e8debeSDaeho Jeong 	inode_unlock(inode);
4179e1e8debeSDaeho Jeong 	file_end_write(filp);
4180e1e8debeSDaeho Jeong 
4181e1e8debeSDaeho Jeong 	return ret;
4182e1e8debeSDaeho Jeong }
4183e1e8debeSDaeho Jeong 
redirty_blocks(struct inode * inode,pgoff_t page_idx,int len)41845fdb322fSDaeho Jeong static int redirty_blocks(struct inode *inode, pgoff_t page_idx, int len)
41855fdb322fSDaeho Jeong {
4186fcd9ae4fSMatthew Wilcox (Oracle) 	DEFINE_READAHEAD(ractl, NULL, NULL, inode->i_mapping, page_idx);
41875fdb322fSDaeho Jeong 	struct address_space *mapping = inode->i_mapping;
41885fdb322fSDaeho Jeong 	struct page *page;
41895fdb322fSDaeho Jeong 	pgoff_t redirty_idx = page_idx;
41905fdb322fSDaeho Jeong 	int i, page_len = 0, ret = 0;
41915fdb322fSDaeho Jeong 
41925fdb322fSDaeho Jeong 	page_cache_ra_unbounded(&ractl, len, 0);
41935fdb322fSDaeho Jeong 
41945fdb322fSDaeho Jeong 	for (i = 0; i < len; i++, page_idx++) {
41955fdb322fSDaeho Jeong 		page = read_cache_page(mapping, page_idx, NULL, NULL);
41965fdb322fSDaeho Jeong 		if (IS_ERR(page)) {
41975fdb322fSDaeho Jeong 			ret = PTR_ERR(page);
41985fdb322fSDaeho Jeong 			break;
41995fdb322fSDaeho Jeong 		}
42005fdb322fSDaeho Jeong 		page_len++;
42015fdb322fSDaeho Jeong 	}
42025fdb322fSDaeho Jeong 
42035fdb322fSDaeho Jeong 	for (i = 0; i < page_len; i++, redirty_idx++) {
42045fdb322fSDaeho Jeong 		page = find_lock_page(mapping, redirty_idx);
4205a4a0e16dSJack Qiu 
4206a4a0e16dSJack Qiu 		/* It will never fail, when page has pinned above */
4207a4a0e16dSJack Qiu 		f2fs_bug_on(F2FS_I_SB(inode), !page);
4208a4a0e16dSJack Qiu 
42091bb0686aSChao Yu 		f2fs_wait_on_page_writeback(page, DATA, true, true);
42101bb0686aSChao Yu 
42115fdb322fSDaeho Jeong 		set_page_dirty(page);
4212417b8a91SChao Yu 		set_page_private_gcing(page);
42135fdb322fSDaeho Jeong 		f2fs_put_page(page, 1);
42145fdb322fSDaeho Jeong 		f2fs_put_page(page, 0);
42155fdb322fSDaeho Jeong 	}
42165fdb322fSDaeho Jeong 
42175fdb322fSDaeho Jeong 	return ret;
42185fdb322fSDaeho Jeong }
42195fdb322fSDaeho Jeong 
f2fs_ioc_decompress_file(struct file * filp)4220ddf1eca4SYangtao Li static int f2fs_ioc_decompress_file(struct file *filp)
42215fdb322fSDaeho Jeong {
42225fdb322fSDaeho Jeong 	struct inode *inode = file_inode(filp);
42235fdb322fSDaeho Jeong 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
42245fdb322fSDaeho Jeong 	struct f2fs_inode_info *fi = F2FS_I(inode);
4225b6f186bdSYeongjin Gil 	pgoff_t page_idx = 0, last_idx, cluster_idx;
4226b6f186bdSYeongjin Gil 	int ret;
42275fdb322fSDaeho Jeong 
42285fdb322fSDaeho Jeong 	if (!f2fs_sb_has_compression(sbi) ||
42295fdb322fSDaeho Jeong 			F2FS_OPTION(sbi).compress_mode != COMPR_MODE_USER)
42305fdb322fSDaeho Jeong 		return -EOPNOTSUPP;
42315fdb322fSDaeho Jeong 
42325fdb322fSDaeho Jeong 	if (!(filp->f_mode & FMODE_WRITE))
42335fdb322fSDaeho Jeong 		return -EBADF;
42345fdb322fSDaeho Jeong 
4235c3355ea9SYangtao Li 	f2fs_balance_fs(sbi, true);
42365fdb322fSDaeho Jeong 
42375fdb322fSDaeho Jeong 	file_start_write(filp);
42385fdb322fSDaeho Jeong 	inode_lock(inode);
42395fdb322fSDaeho Jeong 
42405fdb322fSDaeho Jeong 	if (!f2fs_is_compress_backend_ready(inode)) {
42415fdb322fSDaeho Jeong 		ret = -EOPNOTSUPP;
42425fdb322fSDaeho Jeong 		goto out;
42435fdb322fSDaeho Jeong 	}
42445fdb322fSDaeho Jeong 
4245116d824fSChao Yu 	if (!f2fs_compressed_file(inode) ||
4246116d824fSChao Yu 		is_inode_flag_set(inode, FI_COMPRESS_RELEASED)) {
424790be48bdSJaewook Kim 		ret = -EINVAL;
424890be48bdSJaewook Kim 		goto out;
424990be48bdSJaewook Kim 	}
425090be48bdSJaewook Kim 
42515fdb322fSDaeho Jeong 	ret = filemap_write_and_wait_range(inode->i_mapping, 0, LLONG_MAX);
42525fdb322fSDaeho Jeong 	if (ret)
42535fdb322fSDaeho Jeong 		goto out;
42545fdb322fSDaeho Jeong 
42555fdb322fSDaeho Jeong 	if (!atomic_read(&fi->i_compr_blocks))
42565fdb322fSDaeho Jeong 		goto out;
42575fdb322fSDaeho Jeong 
42585fdb322fSDaeho Jeong 	last_idx = DIV_ROUND_UP(i_size_read(inode), PAGE_SIZE);
4259b6f186bdSYeongjin Gil 	last_idx >>= fi->i_log_cluster_size;
42605fdb322fSDaeho Jeong 
4261b6f186bdSYeongjin Gil 	for (cluster_idx = 0; cluster_idx < last_idx; cluster_idx++) {
4262b6f186bdSYeongjin Gil 		page_idx = cluster_idx << fi->i_log_cluster_size;
4263b6f186bdSYeongjin Gil 
4264b6f186bdSYeongjin Gil 		if (!f2fs_is_compressed_cluster(inode, page_idx))
4265b6f186bdSYeongjin Gil 			continue;
4266b6f186bdSYeongjin Gil 
4267b6f186bdSYeongjin Gil 		ret = redirty_blocks(inode, page_idx, fi->i_cluster_size);
42685fdb322fSDaeho Jeong 		if (ret < 0)
42695fdb322fSDaeho Jeong 			break;
42705fdb322fSDaeho Jeong 
4271f0248ba6SJaegeuk Kim 		if (get_dirty_pages(inode) >= BLKS_PER_SEG(sbi)) {
4272b822dc91SYangtao Li 			ret = filemap_fdatawrite(inode->i_mapping);
4273b822dc91SYangtao Li 			if (ret < 0)
4274b822dc91SYangtao Li 				break;
4275b822dc91SYangtao Li 		}
42765fdb322fSDaeho Jeong 
42773a2c0e55SChao Yu 		cond_resched();
42783a2c0e55SChao Yu 		if (fatal_signal_pending(current)) {
42793a2c0e55SChao Yu 			ret = -EINTR;
42803a2c0e55SChao Yu 			break;
42813a2c0e55SChao Yu 		}
42825fdb322fSDaeho Jeong 	}
42835fdb322fSDaeho Jeong 
42845fdb322fSDaeho Jeong 	if (!ret)
42855fdb322fSDaeho Jeong 		ret = filemap_write_and_wait_range(inode->i_mapping, 0,
42865fdb322fSDaeho Jeong 							LLONG_MAX);
42875fdb322fSDaeho Jeong 
42885fdb322fSDaeho Jeong 	if (ret)
4289833dcd35SJoe Perches 		f2fs_warn(sbi, "%s: The file might be partially decompressed (errno=%d). Please delete the file.",
42905fdb322fSDaeho Jeong 			  __func__, ret);
42915fdb322fSDaeho Jeong out:
42925fdb322fSDaeho Jeong 	inode_unlock(inode);
42935fdb322fSDaeho Jeong 	file_end_write(filp);
42945fdb322fSDaeho Jeong 
42955fdb322fSDaeho Jeong 	return ret;
42965fdb322fSDaeho Jeong }
42975fdb322fSDaeho Jeong 
f2fs_ioc_compress_file(struct file * filp)4298ddf1eca4SYangtao Li static int f2fs_ioc_compress_file(struct file *filp)
42995fdb322fSDaeho Jeong {
43005fdb322fSDaeho Jeong 	struct inode *inode = file_inode(filp);
43015fdb322fSDaeho Jeong 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
4302b6f186bdSYeongjin Gil 	struct f2fs_inode_info *fi = F2FS_I(inode);
4303b6f186bdSYeongjin Gil 	pgoff_t page_idx = 0, last_idx, cluster_idx;
4304b6f186bdSYeongjin Gil 	int ret;
43055fdb322fSDaeho Jeong 
43065fdb322fSDaeho Jeong 	if (!f2fs_sb_has_compression(sbi) ||
43075fdb322fSDaeho Jeong 			F2FS_OPTION(sbi).compress_mode != COMPR_MODE_USER)
43085fdb322fSDaeho Jeong 		return -EOPNOTSUPP;
43095fdb322fSDaeho Jeong 
43105fdb322fSDaeho Jeong 	if (!(filp->f_mode & FMODE_WRITE))
43115fdb322fSDaeho Jeong 		return -EBADF;
43125fdb322fSDaeho Jeong 
4313c3355ea9SYangtao Li 	f2fs_balance_fs(sbi, true);
43145fdb322fSDaeho Jeong 
43155fdb322fSDaeho Jeong 	file_start_write(filp);
43165fdb322fSDaeho Jeong 	inode_lock(inode);
43175fdb322fSDaeho Jeong 
43185fdb322fSDaeho Jeong 	if (!f2fs_is_compress_backend_ready(inode)) {
43195fdb322fSDaeho Jeong 		ret = -EOPNOTSUPP;
43205fdb322fSDaeho Jeong 		goto out;
43215fdb322fSDaeho Jeong 	}
43225fdb322fSDaeho Jeong 
4323116d824fSChao Yu 	if (!f2fs_compressed_file(inode) ||
4324116d824fSChao Yu 		is_inode_flag_set(inode, FI_COMPRESS_RELEASED)) {
432590be48bdSJaewook Kim 		ret = -EINVAL;
432690be48bdSJaewook Kim 		goto out;
432790be48bdSJaewook Kim 	}
432890be48bdSJaewook Kim 
43295fdb322fSDaeho Jeong 	ret = filemap_write_and_wait_range(inode->i_mapping, 0, LLONG_MAX);
43305fdb322fSDaeho Jeong 	if (ret)
43315fdb322fSDaeho Jeong 		goto out;
43325fdb322fSDaeho Jeong 
43335fdb322fSDaeho Jeong 	set_inode_flag(inode, FI_ENABLE_COMPRESS);
43345fdb322fSDaeho Jeong 
43355fdb322fSDaeho Jeong 	last_idx = DIV_ROUND_UP(i_size_read(inode), PAGE_SIZE);
4336b6f186bdSYeongjin Gil 	last_idx >>= fi->i_log_cluster_size;
43375fdb322fSDaeho Jeong 
4338b6f186bdSYeongjin Gil 	for (cluster_idx = 0; cluster_idx < last_idx; cluster_idx++) {
4339b6f186bdSYeongjin Gil 		page_idx = cluster_idx << fi->i_log_cluster_size;
4340b6f186bdSYeongjin Gil 
4341b6f186bdSYeongjin Gil 		if (f2fs_is_sparse_cluster(inode, page_idx))
4342b6f186bdSYeongjin Gil 			continue;
4343b6f186bdSYeongjin Gil 
4344b6f186bdSYeongjin Gil 		ret = redirty_blocks(inode, page_idx, fi->i_cluster_size);
43455fdb322fSDaeho Jeong 		if (ret < 0)
43465fdb322fSDaeho Jeong 			break;
43475fdb322fSDaeho Jeong 
4348f0248ba6SJaegeuk Kim 		if (get_dirty_pages(inode) >= BLKS_PER_SEG(sbi)) {
4349b822dc91SYangtao Li 			ret = filemap_fdatawrite(inode->i_mapping);
4350b822dc91SYangtao Li 			if (ret < 0)
4351b822dc91SYangtao Li 				break;
4352b822dc91SYangtao Li 		}
43535fdb322fSDaeho Jeong 
43543a2c0e55SChao Yu 		cond_resched();
43553a2c0e55SChao Yu 		if (fatal_signal_pending(current)) {
43563a2c0e55SChao Yu 			ret = -EINTR;
43573a2c0e55SChao Yu 			break;
43583a2c0e55SChao Yu 		}
43595fdb322fSDaeho Jeong 	}
43605fdb322fSDaeho Jeong 
43615fdb322fSDaeho Jeong 	if (!ret)
43625fdb322fSDaeho Jeong 		ret = filemap_write_and_wait_range(inode->i_mapping, 0,
43635fdb322fSDaeho Jeong 							LLONG_MAX);
43645fdb322fSDaeho Jeong 
43655fdb322fSDaeho Jeong 	clear_inode_flag(inode, FI_ENABLE_COMPRESS);
43665fdb322fSDaeho Jeong 
43675fdb322fSDaeho Jeong 	if (ret)
4368833dcd35SJoe Perches 		f2fs_warn(sbi, "%s: The file might be partially compressed (errno=%d). Please delete the file.",
43695fdb322fSDaeho Jeong 			  __func__, ret);
43705fdb322fSDaeho Jeong out:
43715fdb322fSDaeho Jeong 	inode_unlock(inode);
43725fdb322fSDaeho Jeong 	file_end_write(filp);
43735fdb322fSDaeho Jeong 
43745fdb322fSDaeho Jeong 	return ret;
43755fdb322fSDaeho Jeong }
43765fdb322fSDaeho Jeong 
__f2fs_ioctl(struct file * filp,unsigned int cmd,unsigned long arg)437734178b1bSChao Yu static long __f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
4378fbfa2cc5SJaegeuk Kim {
437952656e6cSJaegeuk Kim 	switch (cmd) {
43803357af8fSEric Biggers 	case FS_IOC_GETVERSION:
4381d49f3e89SChao Yu 		return f2fs_ioc_getversion(filp, arg);
438288b88a66SJaegeuk Kim 	case F2FS_IOC_START_ATOMIC_WRITE:
438341e8f85aSDaeho Jeong 		return f2fs_ioc_start_atomic_write(filp, false);
438441e8f85aSDaeho Jeong 	case F2FS_IOC_START_ATOMIC_REPLACE:
438541e8f85aSDaeho Jeong 		return f2fs_ioc_start_atomic_write(filp, true);
438688b88a66SJaegeuk Kim 	case F2FS_IOC_COMMIT_ATOMIC_WRITE:
438788b88a66SJaegeuk Kim 		return f2fs_ioc_commit_atomic_write(filp);
438823339e57SDaeho Jeong 	case F2FS_IOC_ABORT_ATOMIC_WRITE:
438923339e57SDaeho Jeong 		return f2fs_ioc_abort_atomic_write(filp);
439002a1335fSJaegeuk Kim 	case F2FS_IOC_START_VOLATILE_WRITE:
43911e84371fSJaegeuk Kim 	case F2FS_IOC_RELEASE_VOLATILE_WRITE:
43927bc155feSJaegeuk Kim 		return -EOPNOTSUPP;
43931abff93dSJaegeuk Kim 	case F2FS_IOC_SHUTDOWN:
43941abff93dSJaegeuk Kim 		return f2fs_ioc_shutdown(filp, arg);
439552656e6cSJaegeuk Kim 	case FITRIM:
439652656e6cSJaegeuk Kim 		return f2fs_ioc_fitrim(filp, arg);
43973357af8fSEric Biggers 	case FS_IOC_SET_ENCRYPTION_POLICY:
4398f424f664SJaegeuk Kim 		return f2fs_ioc_set_encryption_policy(filp, arg);
43993357af8fSEric Biggers 	case FS_IOC_GET_ENCRYPTION_POLICY:
4400f424f664SJaegeuk Kim 		return f2fs_ioc_get_encryption_policy(filp, arg);
44013357af8fSEric Biggers 	case FS_IOC_GET_ENCRYPTION_PWSALT:
4402f424f664SJaegeuk Kim 		return f2fs_ioc_get_encryption_pwsalt(filp, arg);
44038ce589c7SEric Biggers 	case FS_IOC_GET_ENCRYPTION_POLICY_EX:
44048ce589c7SEric Biggers 		return f2fs_ioc_get_encryption_policy_ex(filp, arg);
44058ce589c7SEric Biggers 	case FS_IOC_ADD_ENCRYPTION_KEY:
44068ce589c7SEric Biggers 		return f2fs_ioc_add_encryption_key(filp, arg);
44078ce589c7SEric Biggers 	case FS_IOC_REMOVE_ENCRYPTION_KEY:
44088ce589c7SEric Biggers 		return f2fs_ioc_remove_encryption_key(filp, arg);
44098ce589c7SEric Biggers 	case FS_IOC_REMOVE_ENCRYPTION_KEY_ALL_USERS:
44108ce589c7SEric Biggers 		return f2fs_ioc_remove_encryption_key_all_users(filp, arg);
44118ce589c7SEric Biggers 	case FS_IOC_GET_ENCRYPTION_KEY_STATUS:
44128ce589c7SEric Biggers 		return f2fs_ioc_get_encryption_key_status(filp, arg);
4413ee446e1aSEric Biggers 	case FS_IOC_GET_ENCRYPTION_NONCE:
4414ee446e1aSEric Biggers 		return f2fs_ioc_get_encryption_nonce(filp, arg);
4415c1c1b583SChao Yu 	case F2FS_IOC_GARBAGE_COLLECT:
4416c1c1b583SChao Yu 		return f2fs_ioc_gc(filp, arg);
441734dc77adSJaegeuk Kim 	case F2FS_IOC_GARBAGE_COLLECT_RANGE:
441834dc77adSJaegeuk Kim 		return f2fs_ioc_gc_range(filp, arg);
4419456b88e4SChao Yu 	case F2FS_IOC_WRITE_CHECKPOINT:
4420ddf1eca4SYangtao Li 		return f2fs_ioc_write_checkpoint(filp);
4421d323d005SChao Yu 	case F2FS_IOC_DEFRAGMENT:
4422d323d005SChao Yu 		return f2fs_ioc_defragment(filp, arg);
44234dd6f977SJaegeuk Kim 	case F2FS_IOC_MOVE_RANGE:
44244dd6f977SJaegeuk Kim 		return f2fs_ioc_move_range(filp, arg);
4425e066b83cSJaegeuk Kim 	case F2FS_IOC_FLUSH_DEVICE:
4426e066b83cSJaegeuk Kim 		return f2fs_ioc_flush_device(filp, arg);
4427e65ef207SJaegeuk Kim 	case F2FS_IOC_GET_FEATURES:
4428e65ef207SJaegeuk Kim 		return f2fs_ioc_get_features(filp, arg);
44291ad71a27SJaegeuk Kim 	case F2FS_IOC_GET_PIN_FILE:
44301ad71a27SJaegeuk Kim 		return f2fs_ioc_get_pin_file(filp, arg);
44311ad71a27SJaegeuk Kim 	case F2FS_IOC_SET_PIN_FILE:
44321ad71a27SJaegeuk Kim 		return f2fs_ioc_set_pin_file(filp, arg);
4433c4020b2dSChao Yu 	case F2FS_IOC_PRECACHE_EXTENTS:
4434ddf1eca4SYangtao Li 		return f2fs_ioc_precache_extents(filp);
443504f0b2eaSQiuyang Sun 	case F2FS_IOC_RESIZE_FS:
443604f0b2eaSQiuyang Sun 		return f2fs_ioc_resize_fs(filp, arg);
443795ae251fSEric Biggers 	case FS_IOC_ENABLE_VERITY:
443895ae251fSEric Biggers 		return f2fs_ioc_enable_verity(filp, arg);
443995ae251fSEric Biggers 	case FS_IOC_MEASURE_VERITY:
444095ae251fSEric Biggers 		return f2fs_ioc_measure_verity(filp, arg);
4441e17fe657SEric Biggers 	case FS_IOC_READ_VERITY_METADATA:
4442e17fe657SEric Biggers 		return f2fs_ioc_read_verity_metadata(filp, arg);
44433357af8fSEric Biggers 	case FS_IOC_GETFSLABEL:
44443357af8fSEric Biggers 		return f2fs_ioc_getfslabel(filp, arg);
44453357af8fSEric Biggers 	case FS_IOC_SETFSLABEL:
44463357af8fSEric Biggers 		return f2fs_ioc_setfslabel(filp, arg);
4447439dfb10SChao Yu 	case F2FS_IOC_GET_COMPRESS_BLOCKS:
4448ac1ee161SSheng Yong 		return f2fs_ioc_get_compress_blocks(filp, arg);
4449ef8d563fSChao Yu 	case F2FS_IOC_RELEASE_COMPRESS_BLOCKS:
4450ef8d563fSChao Yu 		return f2fs_release_compress_blocks(filp, arg);
4451c75488fbSChao Yu 	case F2FS_IOC_RESERVE_COMPRESS_BLOCKS:
4452c75488fbSChao Yu 		return f2fs_reserve_compress_blocks(filp, arg);
44539af84648SDaeho Jeong 	case F2FS_IOC_SEC_TRIM_FILE:
44549af84648SDaeho Jeong 		return f2fs_sec_trim_file(filp, arg);
44559e2a5f8cSDaeho Jeong 	case F2FS_IOC_GET_COMPRESS_OPTION:
44569e2a5f8cSDaeho Jeong 		return f2fs_ioc_get_compress_option(filp, arg);
4457e1e8debeSDaeho Jeong 	case F2FS_IOC_SET_COMPRESS_OPTION:
4458e1e8debeSDaeho Jeong 		return f2fs_ioc_set_compress_option(filp, arg);
44595fdb322fSDaeho Jeong 	case F2FS_IOC_DECOMPRESS_FILE:
4460ddf1eca4SYangtao Li 		return f2fs_ioc_decompress_file(filp);
44615fdb322fSDaeho Jeong 	case F2FS_IOC_COMPRESS_FILE:
4462ddf1eca4SYangtao Li 		return f2fs_ioc_compress_file(filp);
4463fbfa2cc5SJaegeuk Kim 	default:
4464fbfa2cc5SJaegeuk Kim 		return -ENOTTY;
4465fbfa2cc5SJaegeuk Kim 	}
4466fbfa2cc5SJaegeuk Kim }
4467fbfa2cc5SJaegeuk Kim 
f2fs_ioctl(struct file * filp,unsigned int cmd,unsigned long arg)446834178b1bSChao Yu long f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
446934178b1bSChao Yu {
447034178b1bSChao Yu 	if (unlikely(f2fs_cp_error(F2FS_I_SB(file_inode(filp)))))
447134178b1bSChao Yu 		return -EIO;
447234178b1bSChao Yu 	if (!f2fs_is_checkpoint_ready(F2FS_I_SB(file_inode(filp))))
447334178b1bSChao Yu 		return -ENOSPC;
447434178b1bSChao Yu 
447534178b1bSChao Yu 	return __f2fs_ioctl(filp, cmd, arg);
447634178b1bSChao Yu }
447734178b1bSChao Yu 
4478a1e09b03SEric Biggers /*
4479a1e09b03SEric Biggers  * Return %true if the given read or write request should use direct I/O, or
4480a1e09b03SEric Biggers  * %false if it should use buffered I/O.
4481a1e09b03SEric Biggers  */
f2fs_should_use_dio(struct inode * inode,struct kiocb * iocb,struct iov_iter * iter)4482a1e09b03SEric Biggers static bool f2fs_should_use_dio(struct inode *inode, struct kiocb *iocb,
4483a1e09b03SEric Biggers 				struct iov_iter *iter)
4484a1e09b03SEric Biggers {
4485a1e09b03SEric Biggers 	unsigned int align;
4486a1e09b03SEric Biggers 
4487a1e09b03SEric Biggers 	if (!(iocb->ki_flags & IOCB_DIRECT))
4488a1e09b03SEric Biggers 		return false;
4489a1e09b03SEric Biggers 
4490bd367329SEric Biggers 	if (f2fs_force_buffered_io(inode, iov_iter_rw(iter)))
4491a1e09b03SEric Biggers 		return false;
4492a1e09b03SEric Biggers 
4493a1e09b03SEric Biggers 	/*
4494a1e09b03SEric Biggers 	 * Direct I/O not aligned to the disk's logical_block_size will be
4495a1e09b03SEric Biggers 	 * attempted, but will fail with -EINVAL.
4496a1e09b03SEric Biggers 	 *
4497a1e09b03SEric Biggers 	 * f2fs additionally requires that direct I/O be aligned to the
4498a1e09b03SEric Biggers 	 * filesystem block size, which is often a stricter requirement.
4499a1e09b03SEric Biggers 	 * However, f2fs traditionally falls back to buffered I/O on requests
4500a1e09b03SEric Biggers 	 * that are logical_block_size-aligned but not fs-block aligned.
4501a1e09b03SEric Biggers 	 *
4502a1e09b03SEric Biggers 	 * The below logic implements this behavior.
4503a1e09b03SEric Biggers 	 */
4504a1e09b03SEric Biggers 	align = iocb->ki_pos | iov_iter_alignment(iter);
4505a1e09b03SEric Biggers 	if (!IS_ALIGNED(align, i_blocksize(inode)) &&
4506a1e09b03SEric Biggers 	    IS_ALIGNED(align, bdev_logical_block_size(inode->i_sb->s_bdev)))
4507a1e09b03SEric Biggers 		return false;
4508a1e09b03SEric Biggers 
4509a1e09b03SEric Biggers 	return true;
4510a1e09b03SEric Biggers }
4511a1e09b03SEric Biggers 
f2fs_dio_read_end_io(struct kiocb * iocb,ssize_t size,int error,unsigned int flags)4512a1e09b03SEric Biggers static int f2fs_dio_read_end_io(struct kiocb *iocb, ssize_t size, int error,
4513a1e09b03SEric Biggers 				unsigned int flags)
4514a1e09b03SEric Biggers {
4515a1e09b03SEric Biggers 	struct f2fs_sb_info *sbi = F2FS_I_SB(file_inode(iocb->ki_filp));
4516a1e09b03SEric Biggers 
4517a1e09b03SEric Biggers 	dec_page_count(sbi, F2FS_DIO_READ);
4518a1e09b03SEric Biggers 	if (error)
4519a1e09b03SEric Biggers 		return error;
452034a23525SChao Yu 	f2fs_update_iostat(sbi, NULL, APP_DIRECT_READ_IO, size);
4521a1e09b03SEric Biggers 	return 0;
4522a1e09b03SEric Biggers }
4523a1e09b03SEric Biggers 
4524a1e09b03SEric Biggers static const struct iomap_dio_ops f2fs_iomap_dio_read_ops = {
4525a1e09b03SEric Biggers 	.end_io = f2fs_dio_read_end_io,
4526a1e09b03SEric Biggers };
4527a1e09b03SEric Biggers 
f2fs_dio_read_iter(struct kiocb * iocb,struct iov_iter * to)4528a1e09b03SEric Biggers static ssize_t f2fs_dio_read_iter(struct kiocb *iocb, struct iov_iter *to)
45294c8ff709SChao Yu {
45304c8ff709SChao Yu 	struct file *file = iocb->ki_filp;
45314c8ff709SChao Yu 	struct inode *inode = file_inode(file);
4532a1e09b03SEric Biggers 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
4533a1e09b03SEric Biggers 	struct f2fs_inode_info *fi = F2FS_I(inode);
4534a1e09b03SEric Biggers 	const loff_t pos = iocb->ki_pos;
4535a1e09b03SEric Biggers 	const size_t count = iov_iter_count(to);
4536a1e09b03SEric Biggers 	struct iomap_dio *dio;
4537a1e09b03SEric Biggers 	ssize_t ret;
4538a1e09b03SEric Biggers 
4539a1e09b03SEric Biggers 	if (count == 0)
4540a1e09b03SEric Biggers 		return 0; /* skip atime update */
4541a1e09b03SEric Biggers 
4542bd984c03SJaegeuk Kim 	trace_f2fs_direct_IO_enter(inode, iocb, count, READ);
4543a1e09b03SEric Biggers 
4544a1e09b03SEric Biggers 	if (iocb->ki_flags & IOCB_NOWAIT) {
4545e4544b63STim Murray 		if (!f2fs_down_read_trylock(&fi->i_gc_rwsem[READ])) {
4546a1e09b03SEric Biggers 			ret = -EAGAIN;
4547a1e09b03SEric Biggers 			goto out;
4548a1e09b03SEric Biggers 		}
4549a1e09b03SEric Biggers 	} else {
4550e4544b63STim Murray 		f2fs_down_read(&fi->i_gc_rwsem[READ]);
4551a1e09b03SEric Biggers 	}
4552a1e09b03SEric Biggers 
4553a1e09b03SEric Biggers 	/*
4554a1e09b03SEric Biggers 	 * We have to use __iomap_dio_rw() and iomap_dio_complete() instead of
4555a1e09b03SEric Biggers 	 * the higher-level function iomap_dio_rw() in order to ensure that the
4556a1e09b03SEric Biggers 	 * F2FS_DIO_READ counter will be decremented correctly in all cases.
4557a1e09b03SEric Biggers 	 */
4558a1e09b03SEric Biggers 	inc_page_count(sbi, F2FS_DIO_READ);
4559a1e09b03SEric Biggers 	dio = __iomap_dio_rw(iocb, to, &f2fs_iomap_ops,
4560786f847fSChristoph Hellwig 			     &f2fs_iomap_dio_read_ops, 0, NULL, 0);
4561a1e09b03SEric Biggers 	if (IS_ERR_OR_NULL(dio)) {
4562a1e09b03SEric Biggers 		ret = PTR_ERR_OR_ZERO(dio);
4563a1e09b03SEric Biggers 		if (ret != -EIOCBQUEUED)
4564a1e09b03SEric Biggers 			dec_page_count(sbi, F2FS_DIO_READ);
4565a1e09b03SEric Biggers 	} else {
4566a1e09b03SEric Biggers 		ret = iomap_dio_complete(dio);
4567a1e09b03SEric Biggers 	}
4568a1e09b03SEric Biggers 
4569e4544b63STim Murray 	f2fs_up_read(&fi->i_gc_rwsem[READ]);
4570a1e09b03SEric Biggers 
4571a1e09b03SEric Biggers 	file_accessed(file);
4572a1e09b03SEric Biggers out:
4573a1e09b03SEric Biggers 	trace_f2fs_direct_IO_exit(inode, pos, count, READ, ret);
4574a1e09b03SEric Biggers 	return ret;
4575a1e09b03SEric Biggers }
4576a1e09b03SEric Biggers 
f2fs_trace_rw_file_path(struct file * file,loff_t pos,size_t count,int rw)4577ceb11d0eSDavid Howells static void f2fs_trace_rw_file_path(struct file *file, loff_t pos, size_t count,
4578ceb11d0eSDavid Howells 				    int rw)
4579a28bca0fSChristoph Hellwig {
4580ceb11d0eSDavid Howells 	struct inode *inode = file_inode(file);
4581a28bca0fSChristoph Hellwig 	char *buf, *path;
4582a28bca0fSChristoph Hellwig 
458355847850SWu Bo 	buf = f2fs_getname(F2FS_I_SB(inode));
4584a28bca0fSChristoph Hellwig 	if (!buf)
4585a28bca0fSChristoph Hellwig 		return;
4586ceb11d0eSDavid Howells 	path = dentry_path_raw(file_dentry(file), buf, PATH_MAX);
4587a28bca0fSChristoph Hellwig 	if (IS_ERR(path))
4588a28bca0fSChristoph Hellwig 		goto free_buf;
4589a28bca0fSChristoph Hellwig 	if (rw == WRITE)
4590ceb11d0eSDavid Howells 		trace_f2fs_datawrite_start(inode, pos, count,
4591a28bca0fSChristoph Hellwig 				current->pid, path, current->comm);
4592a28bca0fSChristoph Hellwig 	else
4593ceb11d0eSDavid Howells 		trace_f2fs_dataread_start(inode, pos, count,
4594a28bca0fSChristoph Hellwig 				current->pid, path, current->comm);
4595a28bca0fSChristoph Hellwig free_buf:
459655847850SWu Bo 	f2fs_putname(buf);
4597a28bca0fSChristoph Hellwig }
4598a28bca0fSChristoph Hellwig 
f2fs_file_read_iter(struct kiocb * iocb,struct iov_iter * to)4599a1e09b03SEric Biggers static ssize_t f2fs_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
4600a1e09b03SEric Biggers {
4601a1e09b03SEric Biggers 	struct inode *inode = file_inode(iocb->ki_filp);
4602c277f141SJaegeuk Kim 	const loff_t pos = iocb->ki_pos;
4603a1e09b03SEric Biggers 	ssize_t ret;
46044c8ff709SChao Yu 
46054c8ff709SChao Yu 	if (!f2fs_is_compress_backend_ready(inode))
46064c8ff709SChao Yu 		return -EOPNOTSUPP;
46074c8ff709SChao Yu 
4608a28bca0fSChristoph Hellwig 	if (trace_f2fs_dataread_start_enabled())
4609ceb11d0eSDavid Howells 		f2fs_trace_rw_file_path(iocb->ki_filp, iocb->ki_pos,
4610ceb11d0eSDavid Howells 					iov_iter_count(to), READ);
46118b83ac81SChao Yu 
461267c3c463SChao Yu 	/* In LFS mode, if there is inflight dio, wait for its completion */
461367c3c463SChao Yu 	if (f2fs_lfs_mode(F2FS_I_SB(inode)))
461467c3c463SChao Yu 		inode_dio_wait(inode);
461567c3c463SChao Yu 
4616c277f141SJaegeuk Kim 	if (f2fs_should_use_dio(inode, iocb, to)) {
4617c277f141SJaegeuk Kim 		ret = f2fs_dio_read_iter(iocb, to);
4618c277f141SJaegeuk Kim 	} else {
4619a1e09b03SEric Biggers 		ret = filemap_read(iocb, to, 0);
46208b83ac81SChao Yu 		if (ret > 0)
462134a23525SChao Yu 			f2fs_update_iostat(F2FS_I_SB(inode), inode,
462234a23525SChao Yu 						APP_BUFFERED_READ_IO, ret);
4623c277f141SJaegeuk Kim 	}
4624c277f141SJaegeuk Kim 	if (trace_f2fs_dataread_end_enabled())
4625c277f141SJaegeuk Kim 		trace_f2fs_dataread_end(inode, pos, ret);
46268b83ac81SChao Yu 	return ret;
46274c8ff709SChao Yu }
46284c8ff709SChao Yu 
f2fs_file_splice_read(struct file * in,loff_t * ppos,struct pipe_inode_info * pipe,size_t len,unsigned int flags)4629ceb11d0eSDavid Howells static ssize_t f2fs_file_splice_read(struct file *in, loff_t *ppos,
4630ceb11d0eSDavid Howells 				     struct pipe_inode_info *pipe,
4631ceb11d0eSDavid Howells 				     size_t len, unsigned int flags)
4632ceb11d0eSDavid Howells {
4633ceb11d0eSDavid Howells 	struct inode *inode = file_inode(in);
4634ceb11d0eSDavid Howells 	const loff_t pos = *ppos;
4635ceb11d0eSDavid Howells 	ssize_t ret;
4636ceb11d0eSDavid Howells 
4637ceb11d0eSDavid Howells 	if (!f2fs_is_compress_backend_ready(inode))
4638ceb11d0eSDavid Howells 		return -EOPNOTSUPP;
4639ceb11d0eSDavid Howells 
4640ceb11d0eSDavid Howells 	if (trace_f2fs_dataread_start_enabled())
4641ceb11d0eSDavid Howells 		f2fs_trace_rw_file_path(in, pos, len, READ);
4642ceb11d0eSDavid Howells 
4643ceb11d0eSDavid Howells 	ret = filemap_splice_read(in, ppos, pipe, len, flags);
4644ceb11d0eSDavid Howells 	if (ret > 0)
4645ceb11d0eSDavid Howells 		f2fs_update_iostat(F2FS_I_SB(inode), inode,
4646ceb11d0eSDavid Howells 				   APP_BUFFERED_READ_IO, ret);
4647ceb11d0eSDavid Howells 
4648ceb11d0eSDavid Howells 	if (trace_f2fs_dataread_end_enabled())
4649ceb11d0eSDavid Howells 		trace_f2fs_dataread_end(inode, pos, ret);
4650ceb11d0eSDavid Howells 	return ret;
4651ceb11d0eSDavid Howells }
4652ceb11d0eSDavid Howells 
f2fs_write_checks(struct kiocb * iocb,struct iov_iter * from)4653a1e09b03SEric Biggers static ssize_t f2fs_write_checks(struct kiocb *iocb, struct iov_iter *from)
4654a1e09b03SEric Biggers {
4655a1e09b03SEric Biggers 	struct file *file = iocb->ki_filp;
4656a1e09b03SEric Biggers 	struct inode *inode = file_inode(file);
4657a1e09b03SEric Biggers 	ssize_t count;
4658a1e09b03SEric Biggers 	int err;
4659a1e09b03SEric Biggers 
4660a1e09b03SEric Biggers 	if (IS_IMMUTABLE(inode))
4661a1e09b03SEric Biggers 		return -EPERM;
4662a1e09b03SEric Biggers 
4663a1e09b03SEric Biggers 	if (is_inode_flag_set(inode, FI_COMPRESS_RELEASED))
4664a1e09b03SEric Biggers 		return -EPERM;
4665a1e09b03SEric Biggers 
4666a1e09b03SEric Biggers 	count = generic_write_checks(iocb, from);
4667a1e09b03SEric Biggers 	if (count <= 0)
4668a1e09b03SEric Biggers 		return count;
4669a1e09b03SEric Biggers 
4670a1e09b03SEric Biggers 	err = file_modified(file);
4671a1e09b03SEric Biggers 	if (err)
4672a1e09b03SEric Biggers 		return err;
4673a1e09b03SEric Biggers 	return count;
4674a1e09b03SEric Biggers }
4675a1e09b03SEric Biggers 
46763d697a4aSEric Biggers /*
46773d697a4aSEric Biggers  * Preallocate blocks for a write request, if it is possible and helpful to do
46783d697a4aSEric Biggers  * so.  Returns a positive number if blocks may have been preallocated, 0 if no
46793d697a4aSEric Biggers  * blocks were preallocated, or a negative errno value if something went
46803d697a4aSEric Biggers  * seriously wrong.  Also sets FI_PREALLOCATED_ALL on the inode if *all* the
46813d697a4aSEric Biggers  * requested blocks (not just some of them) have been allocated.
46823d697a4aSEric Biggers  */
f2fs_preallocate_blocks(struct kiocb * iocb,struct iov_iter * iter,bool dio)4683a1e09b03SEric Biggers static int f2fs_preallocate_blocks(struct kiocb *iocb, struct iov_iter *iter,
4684a1e09b03SEric Biggers 				   bool dio)
46853d697a4aSEric Biggers {
46863d697a4aSEric Biggers 	struct inode *inode = file_inode(iocb->ki_filp);
46873d697a4aSEric Biggers 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
46883d697a4aSEric Biggers 	const loff_t pos = iocb->ki_pos;
46893d697a4aSEric Biggers 	const size_t count = iov_iter_count(iter);
46903d697a4aSEric Biggers 	struct f2fs_map_blocks map = {};
46913d697a4aSEric Biggers 	int flag;
46923d697a4aSEric Biggers 	int ret;
46933d697a4aSEric Biggers 
46943d697a4aSEric Biggers 	/* If it will be an out-of-place direct write, don't bother. */
46953d697a4aSEric Biggers 	if (dio && f2fs_lfs_mode(sbi))
46963d697a4aSEric Biggers 		return 0;
4697d4dd19ecSJaegeuk Kim 	/*
4698d4dd19ecSJaegeuk Kim 	 * Don't preallocate holes aligned to DIO_SKIP_HOLES which turns into
4699d4dd19ecSJaegeuk Kim 	 * buffered IO, if DIO meets any holes.
4700d4dd19ecSJaegeuk Kim 	 */
4701d4dd19ecSJaegeuk Kim 	if (dio && i_size_read(inode) &&
4702d4dd19ecSJaegeuk Kim 		(F2FS_BYTES_TO_BLK(pos) < F2FS_BLK_ALIGN(i_size_read(inode))))
4703d4dd19ecSJaegeuk Kim 		return 0;
47043d697a4aSEric Biggers 
47053d697a4aSEric Biggers 	/* No-wait I/O can't allocate blocks. */
47063d697a4aSEric Biggers 	if (iocb->ki_flags & IOCB_NOWAIT)
47073d697a4aSEric Biggers 		return 0;
47083d697a4aSEric Biggers 
47093d697a4aSEric Biggers 	/* If it will be a short write, don't bother. */
47103d697a4aSEric Biggers 	if (fault_in_iov_iter_readable(iter, count))
47113d697a4aSEric Biggers 		return 0;
47123d697a4aSEric Biggers 
47133d697a4aSEric Biggers 	if (f2fs_has_inline_data(inode)) {
47143d697a4aSEric Biggers 		/* If the data will fit inline, don't bother. */
47153d697a4aSEric Biggers 		if (pos + count <= MAX_INLINE_DATA(inode))
47163d697a4aSEric Biggers 			return 0;
47173d697a4aSEric Biggers 		ret = f2fs_convert_inline_inode(inode);
47183d697a4aSEric Biggers 		if (ret)
47193d697a4aSEric Biggers 			return ret;
47203d697a4aSEric Biggers 	}
47213d697a4aSEric Biggers 
47223d697a4aSEric Biggers 	/* Do not preallocate blocks that will be written partially in 4KB. */
47233d697a4aSEric Biggers 	map.m_lblk = F2FS_BLK_ALIGN(pos);
47243d697a4aSEric Biggers 	map.m_len = F2FS_BYTES_TO_BLK(pos + count);
47253d697a4aSEric Biggers 	if (map.m_len > map.m_lblk)
47263d697a4aSEric Biggers 		map.m_len -= map.m_lblk;
47273d697a4aSEric Biggers 	else
47283d697a4aSEric Biggers 		map.m_len = 0;
47293d697a4aSEric Biggers 	map.m_may_create = true;
47303d697a4aSEric Biggers 	if (dio) {
47313d697a4aSEric Biggers 		map.m_seg_type = f2fs_rw_hint_to_seg_type(inode->i_write_hint);
47323d697a4aSEric Biggers 		flag = F2FS_GET_BLOCK_PRE_DIO;
47333d697a4aSEric Biggers 	} else {
47343d697a4aSEric Biggers 		map.m_seg_type = NO_CHECK_TYPE;
47353d697a4aSEric Biggers 		flag = F2FS_GET_BLOCK_PRE_AIO;
47363d697a4aSEric Biggers 	}
47373d697a4aSEric Biggers 
4738cd8fc522SChristoph Hellwig 	ret = f2fs_map_blocks(inode, &map, flag);
4739d4dd19ecSJaegeuk Kim 	/* -ENOSPC|-EDQUOT are fine to report the number of allocated blocks. */
4740d4dd19ecSJaegeuk Kim 	if (ret < 0 && !((ret == -ENOSPC || ret == -EDQUOT) && map.m_len > 0))
47413d697a4aSEric Biggers 		return ret;
47423d697a4aSEric Biggers 	if (ret == 0)
47433d697a4aSEric Biggers 		set_inode_flag(inode, FI_PREALLOCATED_ALL);
47443d697a4aSEric Biggers 	return map.m_len;
47453d697a4aSEric Biggers }
47463d697a4aSEric Biggers 
f2fs_buffered_write_iter(struct kiocb * iocb,struct iov_iter * from)4747a1e09b03SEric Biggers static ssize_t f2fs_buffered_write_iter(struct kiocb *iocb,
4748a1e09b03SEric Biggers 					struct iov_iter *from)
4749fcc85a4dSJaegeuk Kim {
4750b439b103SJaegeuk Kim 	struct file *file = iocb->ki_filp;
4751b439b103SJaegeuk Kim 	struct inode *inode = file_inode(file);
4752a1e09b03SEric Biggers 	ssize_t ret;
4753a1e09b03SEric Biggers 
4754a1e09b03SEric Biggers 	if (iocb->ki_flags & IOCB_NOWAIT)
4755a1e09b03SEric Biggers 		return -EOPNOTSUPP;
4756a1e09b03SEric Biggers 
4757800ba295SMatthew Wilcox (Oracle) 	ret = generic_perform_write(iocb, from);
4758a1e09b03SEric Biggers 
4759a1e09b03SEric Biggers 	if (ret > 0) {
476034a23525SChao Yu 		f2fs_update_iostat(F2FS_I_SB(inode), inode,
476134a23525SChao Yu 						APP_BUFFERED_IO, ret);
4762a1e09b03SEric Biggers 	}
4763a1e09b03SEric Biggers 	return ret;
4764a1e09b03SEric Biggers }
4765a1e09b03SEric Biggers 
f2fs_dio_write_end_io(struct kiocb * iocb,ssize_t size,int error,unsigned int flags)4766a1e09b03SEric Biggers static int f2fs_dio_write_end_io(struct kiocb *iocb, ssize_t size, int error,
4767a1e09b03SEric Biggers 				 unsigned int flags)
4768a1e09b03SEric Biggers {
4769a1e09b03SEric Biggers 	struct f2fs_sb_info *sbi = F2FS_I_SB(file_inode(iocb->ki_filp));
4770a1e09b03SEric Biggers 
4771a1e09b03SEric Biggers 	dec_page_count(sbi, F2FS_DIO_WRITE);
4772a1e09b03SEric Biggers 	if (error)
4773a1e09b03SEric Biggers 		return error;
47740cc81b1aSZhiguo Niu 	f2fs_update_time(sbi, REQ_TIME);
477534a23525SChao Yu 	f2fs_update_iostat(sbi, NULL, APP_DIRECT_IO, size);
4776a1e09b03SEric Biggers 	return 0;
4777a1e09b03SEric Biggers }
4778a1e09b03SEric Biggers 
4779a1e09b03SEric Biggers static const struct iomap_dio_ops f2fs_iomap_dio_write_ops = {
4780a1e09b03SEric Biggers 	.end_io = f2fs_dio_write_end_io,
4781a1e09b03SEric Biggers };
4782a1e09b03SEric Biggers 
f2fs_flush_buffered_write(struct address_space * mapping,loff_t start_pos,loff_t end_pos)478392318f20SHans Holmberg static void f2fs_flush_buffered_write(struct address_space *mapping,
478492318f20SHans Holmberg 				      loff_t start_pos, loff_t end_pos)
478592318f20SHans Holmberg {
478692318f20SHans Holmberg 	int ret;
478792318f20SHans Holmberg 
478892318f20SHans Holmberg 	ret = filemap_write_and_wait_range(mapping, start_pos, end_pos);
478992318f20SHans Holmberg 	if (ret < 0)
479092318f20SHans Holmberg 		return;
479192318f20SHans Holmberg 	invalidate_mapping_pages(mapping,
479292318f20SHans Holmberg 				 start_pos >> PAGE_SHIFT,
479392318f20SHans Holmberg 				 end_pos >> PAGE_SHIFT);
479492318f20SHans Holmberg }
479592318f20SHans Holmberg 
f2fs_dio_write_iter(struct kiocb * iocb,struct iov_iter * from,bool * may_need_sync)4796a1e09b03SEric Biggers static ssize_t f2fs_dio_write_iter(struct kiocb *iocb, struct iov_iter *from,
4797a1e09b03SEric Biggers 				   bool *may_need_sync)
4798a1e09b03SEric Biggers {
4799a1e09b03SEric Biggers 	struct file *file = iocb->ki_filp;
4800a1e09b03SEric Biggers 	struct inode *inode = file_inode(file);
4801a1e09b03SEric Biggers 	struct f2fs_inode_info *fi = F2FS_I(inode);
4802a1e09b03SEric Biggers 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
4803a1e09b03SEric Biggers 	const bool do_opu = f2fs_lfs_mode(sbi);
4804a1e09b03SEric Biggers 	const loff_t pos = iocb->ki_pos;
4805a1e09b03SEric Biggers 	const ssize_t count = iov_iter_count(from);
4806a1e09b03SEric Biggers 	unsigned int dio_flags;
4807a1e09b03SEric Biggers 	struct iomap_dio *dio;
4808a1e09b03SEric Biggers 	ssize_t ret;
4809a1e09b03SEric Biggers 
4810bd984c03SJaegeuk Kim 	trace_f2fs_direct_IO_enter(inode, iocb, count, WRITE);
4811a1e09b03SEric Biggers 
4812a1e09b03SEric Biggers 	if (iocb->ki_flags & IOCB_NOWAIT) {
4813a1e09b03SEric Biggers 		/* f2fs_convert_inline_inode() and block allocation can block */
4814a1e09b03SEric Biggers 		if (f2fs_has_inline_data(inode) ||
4815a1e09b03SEric Biggers 		    !f2fs_overwrite_io(inode, pos, count)) {
4816a1e09b03SEric Biggers 			ret = -EAGAIN;
4817a1e09b03SEric Biggers 			goto out;
4818a1e09b03SEric Biggers 		}
4819a1e09b03SEric Biggers 
4820e4544b63STim Murray 		if (!f2fs_down_read_trylock(&fi->i_gc_rwsem[WRITE])) {
4821a1e09b03SEric Biggers 			ret = -EAGAIN;
4822a1e09b03SEric Biggers 			goto out;
4823a1e09b03SEric Biggers 		}
4824e4544b63STim Murray 		if (do_opu && !f2fs_down_read_trylock(&fi->i_gc_rwsem[READ])) {
4825e4544b63STim Murray 			f2fs_up_read(&fi->i_gc_rwsem[WRITE]);
4826a1e09b03SEric Biggers 			ret = -EAGAIN;
4827a1e09b03SEric Biggers 			goto out;
4828a1e09b03SEric Biggers 		}
4829a1e09b03SEric Biggers 	} else {
4830a1e09b03SEric Biggers 		ret = f2fs_convert_inline_inode(inode);
4831a1e09b03SEric Biggers 		if (ret)
4832a1e09b03SEric Biggers 			goto out;
4833a1e09b03SEric Biggers 
4834e4544b63STim Murray 		f2fs_down_read(&fi->i_gc_rwsem[WRITE]);
4835a1e09b03SEric Biggers 		if (do_opu)
4836e4544b63STim Murray 			f2fs_down_read(&fi->i_gc_rwsem[READ]);
4837a1e09b03SEric Biggers 	}
4838a1e09b03SEric Biggers 
4839a1e09b03SEric Biggers 	/*
4840a1e09b03SEric Biggers 	 * We have to use __iomap_dio_rw() and iomap_dio_complete() instead of
4841a1e09b03SEric Biggers 	 * the higher-level function iomap_dio_rw() in order to ensure that the
4842a1e09b03SEric Biggers 	 * F2FS_DIO_WRITE counter will be decremented correctly in all cases.
4843a1e09b03SEric Biggers 	 */
4844a1e09b03SEric Biggers 	inc_page_count(sbi, F2FS_DIO_WRITE);
4845a1e09b03SEric Biggers 	dio_flags = 0;
4846a1e09b03SEric Biggers 	if (pos + count > inode->i_size)
4847a1e09b03SEric Biggers 		dio_flags |= IOMAP_DIO_FORCE_WAIT;
4848a1e09b03SEric Biggers 	dio = __iomap_dio_rw(iocb, from, &f2fs_iomap_ops,
4849786f847fSChristoph Hellwig 			     &f2fs_iomap_dio_write_ops, dio_flags, NULL, 0);
4850a1e09b03SEric Biggers 	if (IS_ERR_OR_NULL(dio)) {
4851a1e09b03SEric Biggers 		ret = PTR_ERR_OR_ZERO(dio);
4852a1e09b03SEric Biggers 		if (ret == -ENOTBLK)
4853a1e09b03SEric Biggers 			ret = 0;
4854a1e09b03SEric Biggers 		if (ret != -EIOCBQUEUED)
4855a1e09b03SEric Biggers 			dec_page_count(sbi, F2FS_DIO_WRITE);
4856a1e09b03SEric Biggers 	} else {
4857a1e09b03SEric Biggers 		ret = iomap_dio_complete(dio);
4858a1e09b03SEric Biggers 	}
4859a1e09b03SEric Biggers 
4860a1e09b03SEric Biggers 	if (do_opu)
4861e4544b63STim Murray 		f2fs_up_read(&fi->i_gc_rwsem[READ]);
4862e4544b63STim Murray 	f2fs_up_read(&fi->i_gc_rwsem[WRITE]);
4863a1e09b03SEric Biggers 
4864a1e09b03SEric Biggers 	if (ret < 0)
4865a1e09b03SEric Biggers 		goto out;
4866a1e09b03SEric Biggers 	if (pos + ret > inode->i_size)
4867a1e09b03SEric Biggers 		f2fs_i_size_write(inode, pos + ret);
4868a1e09b03SEric Biggers 	if (!do_opu)
4869a1e09b03SEric Biggers 		set_inode_flag(inode, FI_UPDATE_WRITE);
4870a1e09b03SEric Biggers 
4871a1e09b03SEric Biggers 	if (iov_iter_count(from)) {
4872a1e09b03SEric Biggers 		ssize_t ret2;
4873a1e09b03SEric Biggers 		loff_t bufio_start_pos = iocb->ki_pos;
4874a1e09b03SEric Biggers 
4875a1e09b03SEric Biggers 		/*
4876a1e09b03SEric Biggers 		 * The direct write was partial, so we need to fall back to a
4877a1e09b03SEric Biggers 		 * buffered write for the remainder.
4878a1e09b03SEric Biggers 		 */
4879a1e09b03SEric Biggers 
4880a1e09b03SEric Biggers 		ret2 = f2fs_buffered_write_iter(iocb, from);
4881a1e09b03SEric Biggers 		if (iov_iter_count(from))
4882a1e09b03SEric Biggers 			f2fs_write_failed(inode, iocb->ki_pos);
4883a1e09b03SEric Biggers 		if (ret2 < 0)
4884a1e09b03SEric Biggers 			goto out;
4885a1e09b03SEric Biggers 
4886a1e09b03SEric Biggers 		/*
4887a1e09b03SEric Biggers 		 * Ensure that the pagecache pages are written to disk and
4888a1e09b03SEric Biggers 		 * invalidated to preserve the expected O_DIRECT semantics.
4889a1e09b03SEric Biggers 		 */
4890a1e09b03SEric Biggers 		if (ret2 > 0) {
4891a1e09b03SEric Biggers 			loff_t bufio_end_pos = bufio_start_pos + ret2 - 1;
4892a1e09b03SEric Biggers 
4893a1e09b03SEric Biggers 			ret += ret2;
4894a1e09b03SEric Biggers 
489592318f20SHans Holmberg 			f2fs_flush_buffered_write(file->f_mapping,
4896a1e09b03SEric Biggers 						  bufio_start_pos,
4897a1e09b03SEric Biggers 						  bufio_end_pos);
4898a1e09b03SEric Biggers 		}
4899a1e09b03SEric Biggers 	} else {
4900a1e09b03SEric Biggers 		/* iomap_dio_rw() already handled the generic_write_sync(). */
4901a1e09b03SEric Biggers 		*may_need_sync = false;
4902a1e09b03SEric Biggers 	}
4903a1e09b03SEric Biggers out:
4904a1e09b03SEric Biggers 	trace_f2fs_direct_IO_exit(inode, pos, count, WRITE, ret);
4905a1e09b03SEric Biggers 	return ret;
4906a1e09b03SEric Biggers }
4907a1e09b03SEric Biggers 
f2fs_file_write_iter(struct kiocb * iocb,struct iov_iter * from)4908a1e09b03SEric Biggers static ssize_t f2fs_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
4909a1e09b03SEric Biggers {
4910a1e09b03SEric Biggers 	struct inode *inode = file_inode(iocb->ki_filp);
4911ccf7cf92SEric Biggers 	const loff_t orig_pos = iocb->ki_pos;
4912ccf7cf92SEric Biggers 	const size_t orig_count = iov_iter_count(from);
49133d697a4aSEric Biggers 	loff_t target_size;
4914a1e09b03SEric Biggers 	bool dio;
4915a1e09b03SEric Biggers 	bool may_need_sync = true;
49163d697a4aSEric Biggers 	int preallocated;
4917b439b103SJaegeuk Kim 	ssize_t ret;
4918fcc85a4dSJaegeuk Kim 
4919126ce721SChao Yu 	if (unlikely(f2fs_cp_error(F2FS_I_SB(inode)))) {
4920126ce721SChao Yu 		ret = -EIO;
4921126ce721SChao Yu 		goto out;
4922126ce721SChao Yu 	}
49231f227a3eSJaegeuk Kim 
49247bd29358SChao Yu 	if (!f2fs_is_compress_backend_ready(inode)) {
49257bd29358SChao Yu 		ret = -EOPNOTSUPP;
49267bd29358SChao Yu 		goto out;
49277bd29358SChao Yu 	}
49284c8ff709SChao Yu 
4929126ce721SChao Yu 	if (iocb->ki_flags & IOCB_NOWAIT) {
4930cb8434f1SGoldwyn Rodrigues 		if (!inode_trylock(inode)) {
4931126ce721SChao Yu 			ret = -EAGAIN;
4932126ce721SChao Yu 			goto out;
4933126ce721SChao Yu 		}
4934cb8434f1SGoldwyn Rodrigues 	} else {
4935b439b103SJaegeuk Kim 		inode_lock(inode);
4936b91050a8SHyunchul Lee 	}
4937b91050a8SHyunchul Lee 
4938a1e09b03SEric Biggers 	ret = f2fs_write_checks(iocb, from);
4939b31bf0f9SEric Biggers 	if (ret <= 0)
4940b31bf0f9SEric Biggers 		goto out_unlock;
4941b31bf0f9SEric Biggers 
4942a1e09b03SEric Biggers 	/* Determine whether we will do a direct write or a buffered write. */
4943a1e09b03SEric Biggers 	dio = f2fs_should_use_dio(inode, iocb, from);
4944b31bf0f9SEric Biggers 
49453d697a4aSEric Biggers 	/* Possibly preallocate the blocks for the write. */
4946dc7a10ddSJaegeuk Kim 	target_size = iocb->ki_pos + iov_iter_count(from);
4947a1e09b03SEric Biggers 	preallocated = f2fs_preallocate_blocks(iocb, from, dio);
4948c277f141SJaegeuk Kim 	if (preallocated < 0) {
49493d697a4aSEric Biggers 		ret = preallocated;
4950c277f141SJaegeuk Kim 	} else {
4951a28bca0fSChristoph Hellwig 		if (trace_f2fs_datawrite_start_enabled())
4952ceb11d0eSDavid Howells 			f2fs_trace_rw_file_path(iocb->ki_filp, iocb->ki_pos,
4953ceb11d0eSDavid Howells 						orig_count, WRITE);
4954c277f141SJaegeuk Kim 
4955a1e09b03SEric Biggers 		/* Do the actual write. */
4956a1e09b03SEric Biggers 		ret = dio ?
4957a1e09b03SEric Biggers 			f2fs_dio_write_iter(iocb, from, &may_need_sync) :
4958a1e09b03SEric Biggers 			f2fs_buffered_write_iter(iocb, from);
49593d697a4aSEric Biggers 
4960c277f141SJaegeuk Kim 		if (trace_f2fs_datawrite_end_enabled())
4961c277f141SJaegeuk Kim 			trace_f2fs_datawrite_end(inode, orig_pos, ret);
4962c277f141SJaegeuk Kim 	}
4963c277f141SJaegeuk Kim 
49643d697a4aSEric Biggers 	/* Don't leave any preallocated blocks around past i_size. */
4965d4dd19ecSJaegeuk Kim 	if (preallocated && i_size_read(inode) < target_size) {
4966e4544b63STim Murray 		f2fs_down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
4967edc6d01bSJan Kara 		filemap_invalidate_lock(inode->i_mapping);
4968d4dd19ecSJaegeuk Kim 		if (!f2fs_truncate(inode))
4969d4dd19ecSJaegeuk Kim 			file_dont_truncate(inode);
4970edc6d01bSJan Kara 		filemap_invalidate_unlock(inode->i_mapping);
4971e4544b63STim Murray 		f2fs_up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
4972d4dd19ecSJaegeuk Kim 	} else {
4973d4dd19ecSJaegeuk Kim 		file_dont_truncate(inode);
4974a303b0acSChao Yu 	}
4975b31bf0f9SEric Biggers 
49763d697a4aSEric Biggers 	clear_inode_flag(inode, FI_PREALLOCATED_ALL);
49773d697a4aSEric Biggers out_unlock:
4978b439b103SJaegeuk Kim 	inode_unlock(inode);
4979126ce721SChao Yu out:
4980ccf7cf92SEric Biggers 	trace_f2fs_file_write_iter(inode, orig_pos, orig_count, ret);
498192318f20SHans Holmberg 
4982a1e09b03SEric Biggers 	if (ret > 0 && may_need_sync)
4983e2592217SChristoph Hellwig 		ret = generic_write_sync(iocb, ret);
498492318f20SHans Holmberg 
498592318f20SHans Holmberg 	/* If buffered IO was forced, flush and drop the data from
498692318f20SHans Holmberg 	 * the page cache to preserve O_DIRECT semantics
498792318f20SHans Holmberg 	 */
498892318f20SHans Holmberg 	if (ret > 0 && !dio && (iocb->ki_flags & IOCB_DIRECT))
498992318f20SHans Holmberg 		f2fs_flush_buffered_write(iocb->ki_filp->f_mapping,
499092318f20SHans Holmberg 					  orig_pos,
499192318f20SHans Holmberg 					  orig_pos + ret - 1);
499292318f20SHans Holmberg 
4993b439b103SJaegeuk Kim 	return ret;
4994fcc85a4dSJaegeuk Kim }
4995fcc85a4dSJaegeuk Kim 
f2fs_file_fadvise(struct file * filp,loff_t offset,loff_t len,int advice)49960f6b56ecSDaeho Jeong static int f2fs_file_fadvise(struct file *filp, loff_t offset, loff_t len,
49970f6b56ecSDaeho Jeong 		int advice)
49980f6b56ecSDaeho Jeong {
49990f6b56ecSDaeho Jeong 	struct address_space *mapping;
50000f6b56ecSDaeho Jeong 	struct backing_dev_info *bdi;
5001e64347aeSFengnan Chang 	struct inode *inode = file_inode(filp);
5002e64347aeSFengnan Chang 	int err;
50030f6b56ecSDaeho Jeong 
50040f6b56ecSDaeho Jeong 	if (advice == POSIX_FADV_SEQUENTIAL) {
50050f6b56ecSDaeho Jeong 		if (S_ISFIFO(inode->i_mode))
50060f6b56ecSDaeho Jeong 			return -ESPIPE;
50070f6b56ecSDaeho Jeong 
50080f6b56ecSDaeho Jeong 		mapping = filp->f_mapping;
50090f6b56ecSDaeho Jeong 		if (!mapping || len < 0)
50100f6b56ecSDaeho Jeong 			return -EINVAL;
50110f6b56ecSDaeho Jeong 
50120f6b56ecSDaeho Jeong 		bdi = inode_to_bdi(mapping->host);
50130f6b56ecSDaeho Jeong 		filp->f_ra.ra_pages = bdi->ra_pages *
50140f6b56ecSDaeho Jeong 			F2FS_I_SB(inode)->seq_file_ra_mul;
50150f6b56ecSDaeho Jeong 		spin_lock(&filp->f_lock);
50160f6b56ecSDaeho Jeong 		filp->f_mode &= ~FMODE_RANDOM;
50170f6b56ecSDaeho Jeong 		spin_unlock(&filp->f_lock);
50180f6b56ecSDaeho Jeong 		return 0;
50190f6b56ecSDaeho Jeong 	}
50200f6b56ecSDaeho Jeong 
5021e64347aeSFengnan Chang 	err = generic_fadvise(filp, offset, len, advice);
5022e64347aeSFengnan Chang 	if (!err && advice == POSIX_FADV_DONTNEED &&
5023e64347aeSFengnan Chang 		test_opt(F2FS_I_SB(inode), COMPRESS_CACHE) &&
5024e64347aeSFengnan Chang 		f2fs_compressed_file(inode))
5025e64347aeSFengnan Chang 		f2fs_invalidate_compress_pages(F2FS_I_SB(inode), inode->i_ino);
5026e64347aeSFengnan Chang 
5027e64347aeSFengnan Chang 	return err;
50280f6b56ecSDaeho Jeong }
50290f6b56ecSDaeho Jeong 
5030fbfa2cc5SJaegeuk Kim #ifdef CONFIG_COMPAT
503134178b1bSChao Yu struct compat_f2fs_gc_range {
503234178b1bSChao Yu 	u32 sync;
503334178b1bSChao Yu 	compat_u64 start;
503434178b1bSChao Yu 	compat_u64 len;
503534178b1bSChao Yu };
503634178b1bSChao Yu #define F2FS_IOC32_GARBAGE_COLLECT_RANGE	_IOW(F2FS_IOCTL_MAGIC, 11,\
503734178b1bSChao Yu 						struct compat_f2fs_gc_range)
503834178b1bSChao Yu 
f2fs_compat_ioc_gc_range(struct file * file,unsigned long arg)503934178b1bSChao Yu static int f2fs_compat_ioc_gc_range(struct file *file, unsigned long arg)
504034178b1bSChao Yu {
504134178b1bSChao Yu 	struct compat_f2fs_gc_range __user *urange;
504234178b1bSChao Yu 	struct f2fs_gc_range range;
504334178b1bSChao Yu 	int err;
504434178b1bSChao Yu 
504534178b1bSChao Yu 	urange = compat_ptr(arg);
504634178b1bSChao Yu 	err = get_user(range.sync, &urange->sync);
504734178b1bSChao Yu 	err |= get_user(range.start, &urange->start);
504834178b1bSChao Yu 	err |= get_user(range.len, &urange->len);
504934178b1bSChao Yu 	if (err)
505034178b1bSChao Yu 		return -EFAULT;
505134178b1bSChao Yu 
505234178b1bSChao Yu 	return __f2fs_ioc_gc_range(file, &range);
505334178b1bSChao Yu }
505434178b1bSChao Yu 
505534178b1bSChao Yu struct compat_f2fs_move_range {
505634178b1bSChao Yu 	u32 dst_fd;
505734178b1bSChao Yu 	compat_u64 pos_in;
505834178b1bSChao Yu 	compat_u64 pos_out;
505934178b1bSChao Yu 	compat_u64 len;
506034178b1bSChao Yu };
506134178b1bSChao Yu #define F2FS_IOC32_MOVE_RANGE		_IOWR(F2FS_IOCTL_MAGIC, 9,	\
506234178b1bSChao Yu 					struct compat_f2fs_move_range)
506334178b1bSChao Yu 
f2fs_compat_ioc_move_range(struct file * file,unsigned long arg)506434178b1bSChao Yu static int f2fs_compat_ioc_move_range(struct file *file, unsigned long arg)
506534178b1bSChao Yu {
506634178b1bSChao Yu 	struct compat_f2fs_move_range __user *urange;
506734178b1bSChao Yu 	struct f2fs_move_range range;
506834178b1bSChao Yu 	int err;
506934178b1bSChao Yu 
507034178b1bSChao Yu 	urange = compat_ptr(arg);
507134178b1bSChao Yu 	err = get_user(range.dst_fd, &urange->dst_fd);
507234178b1bSChao Yu 	err |= get_user(range.pos_in, &urange->pos_in);
507334178b1bSChao Yu 	err |= get_user(range.pos_out, &urange->pos_out);
507434178b1bSChao Yu 	err |= get_user(range.len, &urange->len);
507534178b1bSChao Yu 	if (err)
507634178b1bSChao Yu 		return -EFAULT;
507734178b1bSChao Yu 
507834178b1bSChao Yu 	return __f2fs_ioc_move_range(file, &range);
507934178b1bSChao Yu }
508034178b1bSChao Yu 
f2fs_compat_ioctl(struct file * file,unsigned int cmd,unsigned long arg)5081fbfa2cc5SJaegeuk Kim long f2fs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
5082fbfa2cc5SJaegeuk Kim {
508334178b1bSChao Yu 	if (unlikely(f2fs_cp_error(F2FS_I_SB(file_inode(file)))))
508434178b1bSChao Yu 		return -EIO;
508534178b1bSChao Yu 	if (!f2fs_is_checkpoint_ready(F2FS_I_SB(file_inode(file))))
508634178b1bSChao Yu 		return -ENOSPC;
508734178b1bSChao Yu 
5088fbfa2cc5SJaegeuk Kim 	switch (cmd) {
50893357af8fSEric Biggers 	case FS_IOC32_GETVERSION:
50903357af8fSEric Biggers 		cmd = FS_IOC_GETVERSION;
509104ef4b62SChao Yu 		break;
509234178b1bSChao Yu 	case F2FS_IOC32_GARBAGE_COLLECT_RANGE:
509334178b1bSChao Yu 		return f2fs_compat_ioc_gc_range(file, arg);
509434178b1bSChao Yu 	case F2FS_IOC32_MOVE_RANGE:
509534178b1bSChao Yu 		return f2fs_compat_ioc_move_range(file, arg);
509604ef4b62SChao Yu 	case F2FS_IOC_START_ATOMIC_WRITE:
5097933141e4SChao Yu 	case F2FS_IOC_START_ATOMIC_REPLACE:
509804ef4b62SChao Yu 	case F2FS_IOC_COMMIT_ATOMIC_WRITE:
509904ef4b62SChao Yu 	case F2FS_IOC_START_VOLATILE_WRITE:
510004ef4b62SChao Yu 	case F2FS_IOC_RELEASE_VOLATILE_WRITE:
510123339e57SDaeho Jeong 	case F2FS_IOC_ABORT_ATOMIC_WRITE:
510204ef4b62SChao Yu 	case F2FS_IOC_SHUTDOWN:
5103314999dcSArnd Bergmann 	case FITRIM:
51043357af8fSEric Biggers 	case FS_IOC_SET_ENCRYPTION_POLICY:
51053357af8fSEric Biggers 	case FS_IOC_GET_ENCRYPTION_PWSALT:
51063357af8fSEric Biggers 	case FS_IOC_GET_ENCRYPTION_POLICY:
51078ce589c7SEric Biggers 	case FS_IOC_GET_ENCRYPTION_POLICY_EX:
51088ce589c7SEric Biggers 	case FS_IOC_ADD_ENCRYPTION_KEY:
51098ce589c7SEric Biggers 	case FS_IOC_REMOVE_ENCRYPTION_KEY:
51108ce589c7SEric Biggers 	case FS_IOC_REMOVE_ENCRYPTION_KEY_ALL_USERS:
51118ce589c7SEric Biggers 	case FS_IOC_GET_ENCRYPTION_KEY_STATUS:
5112ee446e1aSEric Biggers 	case FS_IOC_GET_ENCRYPTION_NONCE:
511304ef4b62SChao Yu 	case F2FS_IOC_GARBAGE_COLLECT:
511404ef4b62SChao Yu 	case F2FS_IOC_WRITE_CHECKPOINT:
511504ef4b62SChao Yu 	case F2FS_IOC_DEFRAGMENT:
5116e066b83cSJaegeuk Kim 	case F2FS_IOC_FLUSH_DEVICE:
5117e65ef207SJaegeuk Kim 	case F2FS_IOC_GET_FEATURES:
51181ad71a27SJaegeuk Kim 	case F2FS_IOC_GET_PIN_FILE:
51191ad71a27SJaegeuk Kim 	case F2FS_IOC_SET_PIN_FILE:
5120c4020b2dSChao Yu 	case F2FS_IOC_PRECACHE_EXTENTS:
512104f0b2eaSQiuyang Sun 	case F2FS_IOC_RESIZE_FS:
512295ae251fSEric Biggers 	case FS_IOC_ENABLE_VERITY:
512395ae251fSEric Biggers 	case FS_IOC_MEASURE_VERITY:
5124e17fe657SEric Biggers 	case FS_IOC_READ_VERITY_METADATA:
51253357af8fSEric Biggers 	case FS_IOC_GETFSLABEL:
51263357af8fSEric Biggers 	case FS_IOC_SETFSLABEL:
5127439dfb10SChao Yu 	case F2FS_IOC_GET_COMPRESS_BLOCKS:
5128ef8d563fSChao Yu 	case F2FS_IOC_RELEASE_COMPRESS_BLOCKS:
5129c75488fbSChao Yu 	case F2FS_IOC_RESERVE_COMPRESS_BLOCKS:
51309af84648SDaeho Jeong 	case F2FS_IOC_SEC_TRIM_FILE:
51319e2a5f8cSDaeho Jeong 	case F2FS_IOC_GET_COMPRESS_OPTION:
5132e1e8debeSDaeho Jeong 	case F2FS_IOC_SET_COMPRESS_OPTION:
51335fdb322fSDaeho Jeong 	case F2FS_IOC_DECOMPRESS_FILE:
51345fdb322fSDaeho Jeong 	case F2FS_IOC_COMPRESS_FILE:
51354dd6f977SJaegeuk Kim 		break;
5136fbfa2cc5SJaegeuk Kim 	default:
5137fbfa2cc5SJaegeuk Kim 		return -ENOIOCTLCMD;
5138fbfa2cc5SJaegeuk Kim 	}
513934178b1bSChao Yu 	return __f2fs_ioctl(file, cmd, (unsigned long) compat_ptr(arg));
5140fbfa2cc5SJaegeuk Kim }
5141fbfa2cc5SJaegeuk Kim #endif
5142fbfa2cc5SJaegeuk Kim 
5143fbfa2cc5SJaegeuk Kim const struct file_operations f2fs_file_operations = {
5144267378d4SChao Yu 	.llseek		= f2fs_llseek,
51454c8ff709SChao Yu 	.read_iter	= f2fs_file_read_iter,
5146fcc85a4dSJaegeuk Kim 	.write_iter	= f2fs_file_write_iter,
514750aa6f44SWu Bo 	.iopoll		= iocb_bio_iopoll,
5148fcc85a4dSJaegeuk Kim 	.open		= f2fs_file_open,
514912662234SJaegeuk Kim 	.release	= f2fs_release_file,
5150fbfa2cc5SJaegeuk Kim 	.mmap		= f2fs_file_mmap,
51517a10f017SJaegeuk Kim 	.flush		= f2fs_file_flush,
5152fbfa2cc5SJaegeuk Kim 	.fsync		= f2fs_sync_file,
5153fbfa2cc5SJaegeuk Kim 	.fallocate	= f2fs_fallocate,
5154fbfa2cc5SJaegeuk Kim 	.unlocked_ioctl	= f2fs_ioctl,
5155e9750824SNamjae Jeon #ifdef CONFIG_COMPAT
5156e9750824SNamjae Jeon 	.compat_ioctl	= f2fs_compat_ioctl,
5157e9750824SNamjae Jeon #endif
5158ceb11d0eSDavid Howells 	.splice_read	= f2fs_file_splice_read,
51598d020765SAl Viro 	.splice_write	= iter_file_splice_write,
51600f6b56ecSDaeho Jeong 	.fadvise	= f2fs_file_fadvise,
5161fbfa2cc5SJaegeuk Kim };
5162