xref: /openbmc/linux/fs/f2fs/file.c (revision f0bf89e8)
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;
2169d1589efSChao Yu 
217a5fd5050SChao Yu 	return cp_reason;
2189d1589efSChao Yu }
2199d1589efSChao Yu 
need_inode_page_update(struct f2fs_sb_info * sbi,nid_t ino)2209c7bb702SChangman Lee static bool need_inode_page_update(struct f2fs_sb_info *sbi, nid_t ino)
2219c7bb702SChangman Lee {
2229c7bb702SChangman Lee 	struct page *i = find_get_page(NODE_MAPPING(sbi), ino);
2239c7bb702SChangman Lee 	bool ret = false;
2249c7bb702SChangman Lee 	/* But we need to avoid that there are some inode updates */
2254d57b86dSChao Yu 	if ((i && PageDirty(i)) || f2fs_need_inode_block_update(sbi, ino))
2269c7bb702SChangman Lee 		ret = true;
2279c7bb702SChangman Lee 	f2fs_put_page(i, 0);
2289c7bb702SChangman Lee 	return ret;
2299c7bb702SChangman Lee }
2309c7bb702SChangman Lee 
try_to_fix_pino(struct inode * inode)23151455b19SChangman Lee static void try_to_fix_pino(struct inode *inode)
23251455b19SChangman Lee {
23351455b19SChangman Lee 	struct f2fs_inode_info *fi = F2FS_I(inode);
23451455b19SChangman Lee 	nid_t pino;
23551455b19SChangman Lee 
236e4544b63STim Murray 	f2fs_down_write(&fi->i_sem);
23751455b19SChangman Lee 	if (file_wrong_pino(inode) && inode->i_nlink == 1 &&
23851455b19SChangman Lee 			get_parent_ino(inode, &pino)) {
239205b9822SJaegeuk Kim 		f2fs_i_pino_write(inode, pino);
24051455b19SChangman Lee 		file_got_pino(inode);
24151455b19SChangman Lee 	}
242e4544b63STim Murray 	f2fs_up_write(&fi->i_sem);
24351455b19SChangman Lee }
24451455b19SChangman Lee 
f2fs_do_sync_file(struct file * file,loff_t start,loff_t end,int datasync,bool atomic)245608514deSJaegeuk Kim static int f2fs_do_sync_file(struct file *file, loff_t start, loff_t end,
246608514deSJaegeuk Kim 						int datasync, bool atomic)
247fbfa2cc5SJaegeuk Kim {
248fbfa2cc5SJaegeuk Kim 	struct inode *inode = file->f_mapping->host;
2494081363fSJaegeuk Kim 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
2502403c155SJaegeuk Kim 	nid_t ino = inode->i_ino;
251fbfa2cc5SJaegeuk Kim 	int ret = 0;
252a5fd5050SChao Yu 	enum cp_reason_type cp_reason = 0;
253fbfa2cc5SJaegeuk Kim 	struct writeback_control wbc = {
254c81bf1c8SJaegeuk Kim 		.sync_mode = WB_SYNC_ALL,
255fbfa2cc5SJaegeuk Kim 		.nr_to_write = LONG_MAX,
256fbfa2cc5SJaegeuk Kim 		.for_reclaim = 0,
257fbfa2cc5SJaegeuk Kim 	};
25850fa53ecSChao Yu 	unsigned int seq_id = 0;
259fbfa2cc5SJaegeuk Kim 
260dddd3d65SJaegeuk Kim 	if (unlikely(f2fs_readonly(inode->i_sb)))
2611fa95b0bSNamjae Jeon 		return 0;
2621fa95b0bSNamjae Jeon 
263a2a4a7e4SNamjae Jeon 	trace_f2fs_sync_file_enter(inode);
264ea1aa12cSJaegeuk Kim 
265b61ac5b7SYunlei He 	if (S_ISDIR(inode->i_mode))
266b61ac5b7SYunlei He 		goto go_write;
267b61ac5b7SYunlei He 
268ea1aa12cSJaegeuk Kim 	/* if fdatasync is triggered, let's do in-place-update */
269c46a155bSJaegeuk Kim 	if (datasync || get_dirty_pages(inode) <= SM_I(sbi)->min_fsync_blocks)
27091942321SJaegeuk Kim 		set_inode_flag(inode, FI_NEED_IPU);
2713b49c9a1SJeff Layton 	ret = file_write_and_wait_range(file, start, end);
27291942321SJaegeuk Kim 	clear_inode_flag(inode, FI_NEED_IPU);
273c1ce1b02SJaegeuk Kim 
274dddd3d65SJaegeuk Kim 	if (ret || is_sbi_flag_set(sbi, SBI_CP_DISABLED)) {
275a5fd5050SChao Yu 		trace_f2fs_sync_file_exit(inode, cp_reason, datasync, ret);
276fbfa2cc5SJaegeuk Kim 		return ret;
277a2a4a7e4SNamjae Jeon 	}
278fbfa2cc5SJaegeuk Kim 
2799c7bb702SChangman Lee 	/* if the inode is dirty, let's recover all the time */
280281518c6SChao Yu 	if (!f2fs_skip_inode_update(inode, datasync)) {
2812286c020SJaegeuk Kim 		f2fs_write_inode(inode, NULL);
2829c7bb702SChangman Lee 		goto go_write;
2839c7bb702SChangman Lee 	}
2849c7bb702SChangman Lee 
2856d99ba41SJaegeuk Kim 	/*
2866d99ba41SJaegeuk Kim 	 * if there is no written data, don't waste time to write recovery info.
2876d99ba41SJaegeuk Kim 	 */
28891942321SJaegeuk Kim 	if (!is_inode_flag_set(inode, FI_APPEND_WRITE) &&
2894d57b86dSChao Yu 			!f2fs_exist_written_data(sbi, ino, APPEND_INO)) {
29019c9c466SJaegeuk Kim 
2919c7bb702SChangman Lee 		/* it may call write_inode just prior to fsync */
2929c7bb702SChangman Lee 		if (need_inode_page_update(sbi, ino))
29319c9c466SJaegeuk Kim 			goto go_write;
29419c9c466SJaegeuk Kim 
29591942321SJaegeuk Kim 		if (is_inode_flag_set(inode, FI_UPDATE_WRITE) ||
2964d57b86dSChao Yu 				f2fs_exist_written_data(sbi, ino, UPDATE_INO))
2976d99ba41SJaegeuk Kim 			goto flush_out;
2986d99ba41SJaegeuk Kim 		goto out;
29927879915SChao Yu 	} else {
30027879915SChao Yu 		/*
30127879915SChao Yu 		 * for OPU case, during fsync(), node can be persisted before
30227879915SChao Yu 		 * data when lower device doesn't support write barrier, result
30327879915SChao Yu 		 * in data corruption after SPO.
304146949deSJinyoung CHOI 		 * So for strict fsync mode, force to use atomic write semantics
30527879915SChao Yu 		 * to keep write order in between data/node and last node to
30627879915SChao Yu 		 * avoid potential data corruption.
30727879915SChao Yu 		 */
30827879915SChao Yu 		if (F2FS_OPTION(sbi).fsync_mode ==
30927879915SChao Yu 				FSYNC_MODE_STRICT && !atomic)
31027879915SChao Yu 			atomic = true;
3116d99ba41SJaegeuk Kim 	}
31219c9c466SJaegeuk Kim go_write:
313e5d2385eSJaegeuk Kim 	/*
314e5d2385eSJaegeuk Kim 	 * Both of fdatasync() and fsync() are able to be recovered from
315e5d2385eSJaegeuk Kim 	 * sudden-power-off.
316e5d2385eSJaegeuk Kim 	 */
317e4544b63STim Murray 	f2fs_down_read(&F2FS_I(inode)->i_sem);
318a5fd5050SChao Yu 	cp_reason = need_do_checkpoint(inode);
319e4544b63STim Murray 	f2fs_up_read(&F2FS_I(inode)->i_sem);
320d928bfbfSJaegeuk Kim 
321a5fd5050SChao Yu 	if (cp_reason) {
322fbfa2cc5SJaegeuk Kim 		/* all the dirty node pages should be flushed for POR */
323fbfa2cc5SJaegeuk Kim 		ret = f2fs_sync_fs(inode->i_sb, 1);
324d928bfbfSJaegeuk Kim 
32551455b19SChangman Lee 		/*
32651455b19SChangman Lee 		 * We've secured consistency through sync_fs. Following pino
32751455b19SChangman Lee 		 * will be used only for fsynced inodes after checkpoint.
32851455b19SChangman Lee 		 */
32951455b19SChangman Lee 		try_to_fix_pino(inode);
33091942321SJaegeuk Kim 		clear_inode_flag(inode, FI_APPEND_WRITE);
33191942321SJaegeuk Kim 		clear_inode_flag(inode, FI_UPDATE_WRITE);
332354a3399SJaegeuk Kim 		goto out;
333354a3399SJaegeuk Kim 	}
33488bd02c9SJaegeuk Kim sync_nodes:
335c29fd0c0SChao Yu 	atomic_inc(&sbi->wb_sync_req[NODE]);
33650fa53ecSChao Yu 	ret = f2fs_fsync_node_pages(sbi, inode, &wbc, atomic, &seq_id);
337c29fd0c0SChao Yu 	atomic_dec(&sbi->wb_sync_req[NODE]);
338c267ec15SJaegeuk Kim 	if (ret)
339c267ec15SJaegeuk Kim 		goto out;
34088bd02c9SJaegeuk Kim 
341871f599fSJaegeuk Kim 	/* if cp_error was enabled, we should avoid infinite loop */
3426d5a1495SChao Yu 	if (unlikely(f2fs_cp_error(sbi))) {
3436d5a1495SChao Yu 		ret = -EIO;
344871f599fSJaegeuk Kim 		goto out;
3456d5a1495SChao Yu 	}
346871f599fSJaegeuk Kim 
3474d57b86dSChao Yu 	if (f2fs_need_inode_block_update(sbi, ino)) {
3487c45729aSJaegeuk Kim 		f2fs_mark_inode_dirty_sync(inode, true);
34951455b19SChangman Lee 		f2fs_write_inode(inode, NULL);
35088bd02c9SJaegeuk Kim 		goto sync_nodes;
351398b1ac5SJaegeuk Kim 	}
35288bd02c9SJaegeuk Kim 
353b6a245ebSJaegeuk Kim 	/*
354b6a245ebSJaegeuk Kim 	 * If it's atomic_write, it's just fine to keep write ordering. So
355b6a245ebSJaegeuk Kim 	 * here we don't need to wait for node write completion, since we use
356b6a245ebSJaegeuk Kim 	 * node chain which serializes node blocks. If one of node writes are
357b6a245ebSJaegeuk Kim 	 * reordered, we can see simply broken chain, resulting in stopping
358b6a245ebSJaegeuk Kim 	 * roll-forward recovery. It means we'll recover all or none node blocks
359b6a245ebSJaegeuk Kim 	 * given fsync mark.
360b6a245ebSJaegeuk Kim 	 */
361b6a245ebSJaegeuk Kim 	if (!atomic) {
36250fa53ecSChao Yu 		ret = f2fs_wait_on_node_pages_writeback(sbi, seq_id);
363cfe58f9dSJaegeuk Kim 		if (ret)
364cfe58f9dSJaegeuk Kim 			goto out;
365b6a245ebSJaegeuk Kim 	}
3666d99ba41SJaegeuk Kim 
3676d99ba41SJaegeuk Kim 	/* once recovery info is written, don't need to tack this */
3684d57b86dSChao Yu 	f2fs_remove_ino_entry(sbi, ino, APPEND_INO);
36991942321SJaegeuk Kim 	clear_inode_flag(inode, FI_APPEND_WRITE);
3706d99ba41SJaegeuk Kim flush_out:
371c550e25bSJaegeuk Kim 	if ((!atomic && F2FS_OPTION(sbi).fsync_mode != FSYNC_MODE_NOBARRIER) ||
372c550e25bSJaegeuk Kim 	    (atomic && !test_opt(sbi, NOBARRIER) && f2fs_sb_has_blkzoned(sbi)))
37339d787beSChao Yu 		ret = f2fs_issue_flush(sbi, inode->i_ino);
3743f06252fSChao Yu 	if (!ret) {
3754d57b86dSChao Yu 		f2fs_remove_ino_entry(sbi, ino, UPDATE_INO);
37691942321SJaegeuk Kim 		clear_inode_flag(inode, FI_UPDATE_WRITE);
3774d57b86dSChao Yu 		f2fs_remove_ino_entry(sbi, ino, FLUSH_INO);
3783f06252fSChao Yu 	}
379d0239e1bSJaegeuk Kim 	f2fs_update_time(sbi, REQ_TIME);
380fbfa2cc5SJaegeuk Kim out:
381a5fd5050SChao Yu 	trace_f2fs_sync_file_exit(inode, cp_reason, datasync, ret);
382fbfa2cc5SJaegeuk Kim 	return ret;
383fbfa2cc5SJaegeuk Kim }
384fbfa2cc5SJaegeuk Kim 
f2fs_sync_file(struct file * file,loff_t start,loff_t end,int datasync)385608514deSJaegeuk Kim int f2fs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
386608514deSJaegeuk Kim {
3871f227a3eSJaegeuk Kim 	if (unlikely(f2fs_cp_error(F2FS_I_SB(file_inode(file)))))
3881f227a3eSJaegeuk Kim 		return -EIO;
389608514deSJaegeuk Kim 	return f2fs_do_sync_file(file, start, end, datasync, false);
390608514deSJaegeuk Kim }
391608514deSJaegeuk Kim 
__found_offset(struct address_space * mapping,block_t blkaddr,pgoff_t index,int whence)3924cb03fecSMatthew Wilcox (Oracle) static bool __found_offset(struct address_space *mapping, block_t blkaddr,
3934cb03fecSMatthew Wilcox (Oracle) 				pgoff_t index, int whence)
3947f7670feSJaegeuk Kim {
3957f7670feSJaegeuk Kim 	switch (whence) {
3967f7670feSJaegeuk Kim 	case SEEK_DATA:
3974cb03fecSMatthew Wilcox (Oracle) 		if (__is_valid_data_blkaddr(blkaddr))
3984cb03fecSMatthew Wilcox (Oracle) 			return true;
3994cb03fecSMatthew Wilcox (Oracle) 		if (blkaddr == NEW_ADDR &&
4004cb03fecSMatthew Wilcox (Oracle) 		    xa_get_mark(&mapping->i_pages, index, PAGECACHE_TAG_DIRTY))
4017f7670feSJaegeuk Kim 			return true;
4027f7670feSJaegeuk Kim 		break;
4037f7670feSJaegeuk Kim 	case SEEK_HOLE:
4047f7670feSJaegeuk Kim 		if (blkaddr == NULL_ADDR)
4057f7670feSJaegeuk Kim 			return true;
4067f7670feSJaegeuk Kim 		break;
4077f7670feSJaegeuk Kim 	}
4087f7670feSJaegeuk Kim 	return false;
4097f7670feSJaegeuk Kim }
4107f7670feSJaegeuk Kim 
f2fs_seek_block(struct file * file,loff_t offset,int whence)411267378d4SChao Yu static loff_t f2fs_seek_block(struct file *file, loff_t offset, int whence)
412267378d4SChao Yu {
413267378d4SChao Yu 	struct inode *inode = file->f_mapping->host;
414267378d4SChao Yu 	loff_t maxbytes = inode->i_sb->s_maxbytes;
415267378d4SChao Yu 	struct dnode_of_data dn;
4164cb03fecSMatthew Wilcox (Oracle) 	pgoff_t pgofs, end_offset;
4177f7670feSJaegeuk Kim 	loff_t data_ofs = offset;
4187f7670feSJaegeuk Kim 	loff_t isize;
419267378d4SChao Yu 	int err = 0;
420267378d4SChao Yu 
4215955102cSAl Viro 	inode_lock(inode);
422267378d4SChao Yu 
423267378d4SChao Yu 	isize = i_size_read(inode);
424267378d4SChao Yu 	if (offset >= isize)
425267378d4SChao Yu 		goto fail;
426267378d4SChao Yu 
427267378d4SChao Yu 	/* handle inline data case */
4287a6e59d7SChao Yu 	if (f2fs_has_inline_data(inode)) {
4297a6e59d7SChao Yu 		if (whence == SEEK_HOLE) {
430267378d4SChao Yu 			data_ofs = isize;
431267378d4SChao Yu 			goto found;
4327a6e59d7SChao Yu 		} else if (whence == SEEK_DATA) {
4337a6e59d7SChao Yu 			data_ofs = offset;
4347a6e59d7SChao Yu 			goto found;
4357a6e59d7SChao Yu 		}
436267378d4SChao Yu 	}
437267378d4SChao Yu 
43809cbfeafSKirill A. Shutemov 	pgofs = (pgoff_t)(offset >> PAGE_SHIFT);
439267378d4SChao Yu 
44009cbfeafSKirill A. Shutemov 	for (; data_ofs < isize; data_ofs = (loff_t)pgofs << PAGE_SHIFT) {
441267378d4SChao Yu 		set_new_dnode(&dn, inode, NULL, NULL, 0);
4424d57b86dSChao Yu 		err = f2fs_get_dnode_of_data(&dn, pgofs, LOOKUP_NODE);
443267378d4SChao Yu 		if (err && err != -ENOENT) {
444267378d4SChao Yu 			goto fail;
445267378d4SChao Yu 		} else if (err == -ENOENT) {
446e1c42045Sarter97 			/* direct node does not exists */
447267378d4SChao Yu 			if (whence == SEEK_DATA) {
4484d57b86dSChao Yu 				pgofs = f2fs_get_next_page_offset(&dn, pgofs);
449267378d4SChao Yu 				continue;
450267378d4SChao Yu 			} else {
451267378d4SChao Yu 				goto found;
452267378d4SChao Yu 			}
453267378d4SChao Yu 		}
454267378d4SChao Yu 
45581ca7350SChao Yu 		end_offset = ADDRS_PER_PAGE(dn.node_page, inode);
456267378d4SChao Yu 
457267378d4SChao Yu 		/* find data/hole in dnode block */
458267378d4SChao Yu 		for (; dn.ofs_in_node < end_offset;
459267378d4SChao Yu 				dn.ofs_in_node++, pgofs++,
46009cbfeafSKirill A. Shutemov 				data_ofs = (loff_t)pgofs << PAGE_SHIFT) {
461267378d4SChao Yu 			block_t blkaddr;
462f11e98bdSyoungjun yoo 
463a2ced1ceSChao Yu 			blkaddr = f2fs_data_blkaddr(&dn);
464267378d4SChao Yu 
465c9b60788SChao Yu 			if (__is_valid_data_blkaddr(blkaddr) &&
466c9b60788SChao Yu 				!f2fs_is_valid_blkaddr(F2FS_I_SB(inode),
46793770ab7SChao Yu 					blkaddr, DATA_GENERIC_ENHANCE)) {
468c9b60788SChao Yu 				f2fs_put_dnode(&dn);
469c9b60788SChao Yu 				goto fail;
470c9b60788SChao Yu 			}
471c9b60788SChao Yu 
4724cb03fecSMatthew Wilcox (Oracle) 			if (__found_offset(file->f_mapping, blkaddr,
473e1da7872SChao Yu 							pgofs, whence)) {
474267378d4SChao Yu 				f2fs_put_dnode(&dn);
475267378d4SChao Yu 				goto found;
476267378d4SChao Yu 			}
477267378d4SChao Yu 		}
478267378d4SChao Yu 		f2fs_put_dnode(&dn);
479267378d4SChao Yu 	}
480267378d4SChao Yu 
481267378d4SChao Yu 	if (whence == SEEK_DATA)
482267378d4SChao Yu 		goto fail;
483267378d4SChao Yu found:
484fe369bc8SJaegeuk Kim 	if (whence == SEEK_HOLE && data_ofs > isize)
485fe369bc8SJaegeuk Kim 		data_ofs = isize;
4865955102cSAl Viro 	inode_unlock(inode);
487267378d4SChao Yu 	return vfs_setpos(file, data_ofs, maxbytes);
488267378d4SChao Yu fail:
4895955102cSAl Viro 	inode_unlock(inode);
490267378d4SChao Yu 	return -ENXIO;
491267378d4SChao Yu }
492267378d4SChao Yu 
f2fs_llseek(struct file * file,loff_t offset,int whence)493267378d4SChao Yu static loff_t f2fs_llseek(struct file *file, loff_t offset, int whence)
494267378d4SChao Yu {
495267378d4SChao Yu 	struct inode *inode = file->f_mapping->host;
496267378d4SChao Yu 	loff_t maxbytes = inode->i_sb->s_maxbytes;
497267378d4SChao Yu 
4986d1451bfSChengguang Xu 	if (f2fs_compressed_file(inode))
4996d1451bfSChengguang Xu 		maxbytes = max_file_blocks(inode) << F2FS_BLKSIZE_BITS;
5006d1451bfSChengguang Xu 
501267378d4SChao Yu 	switch (whence) {
502267378d4SChao Yu 	case SEEK_SET:
503267378d4SChao Yu 	case SEEK_CUR:
504267378d4SChao Yu 	case SEEK_END:
505267378d4SChao Yu 		return generic_file_llseek_size(file, offset, whence,
506267378d4SChao Yu 						maxbytes, i_size_read(inode));
507267378d4SChao Yu 	case SEEK_DATA:
508267378d4SChao Yu 	case SEEK_HOLE:
5090b4c5afdSJaegeuk Kim 		if (offset < 0)
5100b4c5afdSJaegeuk Kim 			return -ENXIO;
511267378d4SChao Yu 		return f2fs_seek_block(file, offset, whence);
512267378d4SChao Yu 	}
513267378d4SChao Yu 
514267378d4SChao Yu 	return -EINVAL;
515267378d4SChao Yu }
516267378d4SChao Yu 
f2fs_file_mmap(struct file * file,struct vm_area_struct * vma)517fbfa2cc5SJaegeuk Kim static int f2fs_file_mmap(struct file *file, struct vm_area_struct *vma)
518fbfa2cc5SJaegeuk Kim {
519b3d208f9SJaegeuk Kim 	struct inode *inode = file_inode(file);
520b3d208f9SJaegeuk Kim 
5211f227a3eSJaegeuk Kim 	if (unlikely(f2fs_cp_error(F2FS_I_SB(inode))))
5221f227a3eSJaegeuk Kim 		return -EIO;
5231f227a3eSJaegeuk Kim 
5244c8ff709SChao Yu 	if (!f2fs_is_compress_backend_ready(inode))
5254c8ff709SChao Yu 		return -EOPNOTSUPP;
5264c8ff709SChao Yu 
527fbfa2cc5SJaegeuk Kim 	file_accessed(file);
528fbfa2cc5SJaegeuk Kim 	vma->vm_ops = &f2fs_file_vm_ops;
529b5ab3276SChao Yu 
530b5ab3276SChao Yu 	f2fs_down_read(&F2FS_I(inode)->i_sem);
5314c8ff709SChao Yu 	set_inode_flag(inode, FI_MMAP_FILE);
532b5ab3276SChao Yu 	f2fs_up_read(&F2FS_I(inode)->i_sem);
533b5ab3276SChao Yu 
534fbfa2cc5SJaegeuk Kim 	return 0;
535fbfa2cc5SJaegeuk Kim }
536fbfa2cc5SJaegeuk Kim 
f2fs_file_open(struct inode * inode,struct file * filp)537fcc85a4dSJaegeuk Kim static int f2fs_file_open(struct inode *inode, struct file *filp)
538fcc85a4dSJaegeuk Kim {
5392e168c82SEric Biggers 	int err = fscrypt_file_open(inode, filp);
540fcc85a4dSJaegeuk Kim 
5412e168c82SEric Biggers 	if (err)
5422e168c82SEric Biggers 		return err;
543b91050a8SHyunchul Lee 
5444c8ff709SChao Yu 	if (!f2fs_is_compress_backend_ready(inode))
5454c8ff709SChao Yu 		return -EOPNOTSUPP;
5464c8ff709SChao Yu 
54795ae251fSEric Biggers 	err = fsverity_file_open(inode, filp);
54895ae251fSEric Biggers 	if (err)
54995ae251fSEric Biggers 		return err;
55095ae251fSEric Biggers 
55138b57833SYangtao Li 	filp->f_mode |= FMODE_NOWAIT | FMODE_BUF_RASYNC;
55294c8431fSChristoph Hellwig 	filp->f_mode |= FMODE_CAN_ODIRECT;
553b91050a8SHyunchul Lee 
5540abd675eSChao Yu 	return dquot_file_open(inode, filp);
555fcc85a4dSJaegeuk Kim }
556fcc85a4dSJaegeuk Kim 
f2fs_truncate_data_blocks_range(struct dnode_of_data * dn,int count)5574d57b86dSChao Yu void f2fs_truncate_data_blocks_range(struct dnode_of_data *dn, int count)
558fbfa2cc5SJaegeuk Kim {
5594081363fSJaegeuk Kim 	struct f2fs_sb_info *sbi = F2FS_I_SB(dn->inode);
56019b2c30dSChao Yu 	int nr_free = 0, ofs = dn->ofs_in_node, len = count;
561fbfa2cc5SJaegeuk Kim 	__le32 *addr;
5624c8ff709SChao Yu 	bool compressed_cluster = false;
5634c8ff709SChao Yu 	int cluster_index = 0, valid_blocks = 0;
5644c8ff709SChao Yu 	int cluster_size = F2FS_I(dn->inode)->i_cluster_size;
565c2759ebaSDaeho Jeong 	bool released = !atomic_read(&F2FS_I(dn->inode)->i_compr_blocks);
5667a2af766SChao Yu 
567dcd6b38bSChao Yu 	addr = get_dnode_addr(dn->inode, dn->node_page) + ofs;
568fbfa2cc5SJaegeuk Kim 
569a5029a57SKeoseong Park 	/* Assumption: truncation starts with cluster */
5704c8ff709SChao Yu 	for (; count > 0; count--, addr++, dn->ofs_in_node++, cluster_index++) {
571fbfa2cc5SJaegeuk Kim 		block_t blkaddr = le32_to_cpu(*addr);
572f11e98bdSyoungjun yoo 
5734c8ff709SChao Yu 		if (f2fs_compressed_file(dn->inode) &&
5744c8ff709SChao Yu 					!(cluster_index & (cluster_size - 1))) {
5754c8ff709SChao Yu 			if (compressed_cluster)
5764c8ff709SChao Yu 				f2fs_i_compr_blocks_update(dn->inode,
5774c8ff709SChao Yu 							valid_blocks, false);
5784c8ff709SChao Yu 			compressed_cluster = (blkaddr == COMPRESS_ADDR);
5794c8ff709SChao Yu 			valid_blocks = 0;
5804c8ff709SChao Yu 		}
5814c8ff709SChao Yu 
582fbfa2cc5SJaegeuk Kim 		if (blkaddr == NULL_ADDR)
583fbfa2cc5SJaegeuk Kim 			continue;
584fbfa2cc5SJaegeuk Kim 
585eb6d30bcSChao Yu 		f2fs_set_data_blkaddr(dn, NULL_ADDR);
586c9b60788SChao Yu 
5874c8ff709SChao Yu 		if (__is_valid_data_blkaddr(blkaddr)) {
5884c8ff709SChao Yu 			if (!f2fs_is_valid_blkaddr(sbi, blkaddr,
58993770ab7SChao Yu 					DATA_GENERIC_ENHANCE))
590c9b60788SChao Yu 				continue;
5914c8ff709SChao Yu 			if (compressed_cluster)
5924c8ff709SChao Yu 				valid_blocks++;
5934c8ff709SChao Yu 		}
594c9b60788SChao Yu 
5954c8ff709SChao Yu 		f2fs_invalidate_blocks(sbi, blkaddr);
596ef8d563fSChao Yu 
597ef8d563fSChao Yu 		if (!released || blkaddr != COMPRESS_ADDR)
598fbfa2cc5SJaegeuk Kim 			nr_free++;
599fbfa2cc5SJaegeuk Kim 	}
60019b2c30dSChao Yu 
6014c8ff709SChao Yu 	if (compressed_cluster)
6024c8ff709SChao Yu 		f2fs_i_compr_blocks_update(dn->inode, valid_blocks, false);
6034c8ff709SChao Yu 
604fbfa2cc5SJaegeuk Kim 	if (nr_free) {
60519b2c30dSChao Yu 		pgoff_t fofs;
60619b2c30dSChao Yu 		/*
60719b2c30dSChao Yu 		 * once we invalidate valid blkaddr in range [ofs, ofs + count],
60819b2c30dSChao Yu 		 * we will invalidate all blkaddr in the whole range.
60919b2c30dSChao Yu 		 */
6104d57b86dSChao Yu 		fofs = f2fs_start_bidx_of_node(ofs_of_node(dn->node_page),
61181ca7350SChao Yu 							dn->inode) + ofs;
612e7547dacSJaegeuk Kim 		f2fs_update_read_extent_cache_range(dn, fofs, 0, len);
6138c0ed062SChao Yu 		f2fs_update_age_extent_cache_range(dn, fofs, len);
614d7cc950bSNamjae Jeon 		dec_valid_block_count(sbi, dn->inode, nr_free);
615fbfa2cc5SJaegeuk Kim 	}
616fbfa2cc5SJaegeuk Kim 	dn->ofs_in_node = ofs;
61751dd6249SNamjae Jeon 
618d0239e1bSJaegeuk Kim 	f2fs_update_time(sbi, REQ_TIME);
61951dd6249SNamjae Jeon 	trace_f2fs_truncate_data_blocks_range(dn->inode, dn->nid,
62051dd6249SNamjae Jeon 					 dn->ofs_in_node, nr_free);
621fbfa2cc5SJaegeuk Kim }
622fbfa2cc5SJaegeuk Kim 
truncate_partial_data_page(struct inode * inode,u64 from,bool cache_only)6230bfcfccaSChao Yu static int truncate_partial_data_page(struct inode *inode, u64 from,
62443f3eae1SJaegeuk Kim 								bool cache_only)
625fbfa2cc5SJaegeuk Kim {
626193bea1dSyoungjun yoo 	loff_t offset = from & (PAGE_SIZE - 1);
62709cbfeafSKirill A. Shutemov 	pgoff_t index = from >> PAGE_SHIFT;
62843f3eae1SJaegeuk Kim 	struct address_space *mapping = inode->i_mapping;
629fbfa2cc5SJaegeuk Kim 	struct page *page;
630fbfa2cc5SJaegeuk Kim 
63143f3eae1SJaegeuk Kim 	if (!offset && !cache_only)
632b3d208f9SJaegeuk Kim 		return 0;
633fbfa2cc5SJaegeuk Kim 
63443f3eae1SJaegeuk Kim 	if (cache_only) {
63534b5d5c2SJaegeuk Kim 		page = find_lock_page(mapping, index);
63643f3eae1SJaegeuk Kim 		if (page && PageUptodate(page))
63743f3eae1SJaegeuk Kim 			goto truncate_out;
63843f3eae1SJaegeuk Kim 		f2fs_put_page(page, 1);
63943f3eae1SJaegeuk Kim 		return 0;
64043f3eae1SJaegeuk Kim 	}
64143f3eae1SJaegeuk Kim 
6424d57b86dSChao Yu 	page = f2fs_get_lock_data_page(inode, index, true);
643fbfa2cc5SJaegeuk Kim 	if (IS_ERR(page))
644a78aaa2cSYunlei He 		return PTR_ERR(page) == -ENOENT ? 0 : PTR_ERR(page);
64543f3eae1SJaegeuk Kim truncate_out:
646bae0ee7aSChao Yu 	f2fs_wait_on_page_writeback(page, DATA, true, true);
64709cbfeafSKirill A. Shutemov 	zero_user(page, offset, PAGE_SIZE - offset);
648a9bcf9bcSJaegeuk Kim 
649a9bcf9bcSJaegeuk Kim 	/* An encrypted inode should have a key and truncate the last page. */
65062230e0dSChandan Rajendra 	f2fs_bug_on(F2FS_I_SB(inode), cache_only && IS_ENCRYPTED(inode));
651a9bcf9bcSJaegeuk Kim 	if (!cache_only)
652fbfa2cc5SJaegeuk Kim 		set_page_dirty(page);
653fbfa2cc5SJaegeuk Kim 	f2fs_put_page(page, 1);
654b3d208f9SJaegeuk Kim 	return 0;
655fbfa2cc5SJaegeuk Kim }
656fbfa2cc5SJaegeuk Kim 
f2fs_do_truncate_blocks(struct inode * inode,u64 from,bool lock)6573265d3dbSChao Yu int f2fs_do_truncate_blocks(struct inode *inode, u64 from, bool lock)
658fbfa2cc5SJaegeuk Kim {
6594081363fSJaegeuk Kim 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
660fbfa2cc5SJaegeuk Kim 	struct dnode_of_data dn;
661fbfa2cc5SJaegeuk Kim 	pgoff_t free_from;
6629ffe0fb5SHuajun Li 	int count = 0, err = 0;
663b3d208f9SJaegeuk Kim 	struct page *ipage;
6640bfcfccaSChao Yu 	bool truncate_page = false;
665fbfa2cc5SJaegeuk Kim 
66651dd6249SNamjae Jeon 	trace_f2fs_truncate_blocks_enter(inode, from);
66751dd6249SNamjae Jeon 
668df033cafSChao Yu 	free_from = (pgoff_t)F2FS_BLK_ALIGN(from);
669fbfa2cc5SJaegeuk Kim 
6706d1451bfSChengguang Xu 	if (free_from >= max_file_blocks(inode))
67109210c97SChao Yu 		goto free_partial;
67209210c97SChao Yu 
673764aa3e9SJaegeuk Kim 	if (lock)
674c42d28ceSChao Yu 		f2fs_lock_op(sbi);
6759ffe0fb5SHuajun Li 
6764d57b86dSChao Yu 	ipage = f2fs_get_node_page(sbi, inode->i_ino);
677b3d208f9SJaegeuk Kim 	if (IS_ERR(ipage)) {
678b3d208f9SJaegeuk Kim 		err = PTR_ERR(ipage);
679b3d208f9SJaegeuk Kim 		goto out;
680b3d208f9SJaegeuk Kim 	}
681b3d208f9SJaegeuk Kim 
682b3d208f9SJaegeuk Kim 	if (f2fs_has_inline_data(inode)) {
6834d57b86dSChao Yu 		f2fs_truncate_inline_inode(inode, ipage, from);
684b3d208f9SJaegeuk Kim 		f2fs_put_page(ipage, 1);
6850bfcfccaSChao Yu 		truncate_page = true;
686b3d208f9SJaegeuk Kim 		goto out;
687b3d208f9SJaegeuk Kim 	}
688b3d208f9SJaegeuk Kim 
689b3d208f9SJaegeuk Kim 	set_new_dnode(&dn, inode, ipage, NULL, 0);
6904d57b86dSChao Yu 	err = f2fs_get_dnode_of_data(&dn, free_from, LOOKUP_NODE_RA);
691fbfa2cc5SJaegeuk Kim 	if (err) {
692fbfa2cc5SJaegeuk Kim 		if (err == -ENOENT)
693fbfa2cc5SJaegeuk Kim 			goto free_next;
694b3d208f9SJaegeuk Kim 		goto out;
6951ce86bf6SJaegeuk Kim 	}
6961ce86bf6SJaegeuk Kim 
69781ca7350SChao Yu 	count = ADDRS_PER_PAGE(dn.node_page, inode);
698fbfa2cc5SJaegeuk Kim 
699fbfa2cc5SJaegeuk Kim 	count -= dn.ofs_in_node;
7009850cf4aSJaegeuk Kim 	f2fs_bug_on(sbi, count < 0);
70139936837SJaegeuk Kim 
702fbfa2cc5SJaegeuk Kim 	if (dn.ofs_in_node || IS_INODE(dn.node_page)) {
7034d57b86dSChao Yu 		f2fs_truncate_data_blocks_range(&dn, count);
704fbfa2cc5SJaegeuk Kim 		free_from += count;
705fbfa2cc5SJaegeuk Kim 	}
706fbfa2cc5SJaegeuk Kim 
707fbfa2cc5SJaegeuk Kim 	f2fs_put_dnode(&dn);
708fbfa2cc5SJaegeuk Kim free_next:
7094d57b86dSChao Yu 	err = f2fs_truncate_inode_blocks(inode, free_from);
710764d2c80SJaegeuk Kim out:
711764d2c80SJaegeuk Kim 	if (lock)
712c42d28ceSChao Yu 		f2fs_unlock_op(sbi);
71309210c97SChao Yu free_partial:
714b3d208f9SJaegeuk Kim 	/* lastly zero out the first data page */
715b3d208f9SJaegeuk Kim 	if (!err)
7160bfcfccaSChao Yu 		err = truncate_partial_data_page(inode, from, truncate_page);
717fbfa2cc5SJaegeuk Kim 
71851dd6249SNamjae Jeon 	trace_f2fs_truncate_blocks_exit(inode, err);
719fbfa2cc5SJaegeuk Kim 	return err;
720fbfa2cc5SJaegeuk Kim }
721fbfa2cc5SJaegeuk Kim 
f2fs_truncate_blocks(struct inode * inode,u64 from,bool lock)7224c8ff709SChao Yu int f2fs_truncate_blocks(struct inode *inode, u64 from, bool lock)
7234c8ff709SChao Yu {
7244c8ff709SChao Yu 	u64 free_from = from;
7253265d3dbSChao Yu 	int err;
7264c8ff709SChao Yu 
7273265d3dbSChao Yu #ifdef CONFIG_F2FS_FS_COMPRESSION
7284c8ff709SChao Yu 	/*
7294c8ff709SChao Yu 	 * for compressed file, only support cluster size
7304c8ff709SChao Yu 	 * aligned truncation.
7314c8ff709SChao Yu 	 */
7324fec3fc0SChao Yu 	if (f2fs_compressed_file(inode))
7334fec3fc0SChao Yu 		free_from = round_up(from,
7344fec3fc0SChao Yu 				F2FS_I(inode)->i_cluster_size << PAGE_SHIFT);
7353265d3dbSChao Yu #endif
7364c8ff709SChao Yu 
7373265d3dbSChao Yu 	err = f2fs_do_truncate_blocks(inode, free_from, lock);
7383265d3dbSChao Yu 	if (err)
7393265d3dbSChao Yu 		return err;
7403265d3dbSChao Yu 
7413265d3dbSChao Yu #ifdef CONFIG_F2FS_FS_COMPRESSION
7424a4fc043SFengnan Chang 	/*
7434a4fc043SFengnan Chang 	 * For compressed file, after release compress blocks, don't allow write
7444a4fc043SFengnan Chang 	 * direct, but we should allow write direct after truncate to zero.
7454a4fc043SFengnan Chang 	 */
7464a4fc043SFengnan Chang 	if (f2fs_compressed_file(inode) && !free_from
7474a4fc043SFengnan Chang 			&& is_inode_flag_set(inode, FI_COMPRESS_RELEASED))
7484a4fc043SFengnan Chang 		clear_inode_flag(inode, FI_COMPRESS_RELEASED);
7494a4fc043SFengnan Chang 
75017d7648dSChao Yu 	if (from != free_from) {
7513265d3dbSChao Yu 		err = f2fs_truncate_partial_cluster(inode, from, lock);
75217d7648dSChao Yu 		if (err)
75317d7648dSChao Yu 			return err;
75417d7648dSChao Yu 	}
7553265d3dbSChao Yu #endif
7563265d3dbSChao Yu 
75717d7648dSChao Yu 	return 0;
7584c8ff709SChao Yu }
7594c8ff709SChao Yu 
f2fs_truncate(struct inode * inode)7609a449e9cSJaegeuk Kim int f2fs_truncate(struct inode *inode)
761fbfa2cc5SJaegeuk Kim {
762b0154891SChao Yu 	int err;
763b0154891SChao Yu 
7641f227a3eSJaegeuk Kim 	if (unlikely(f2fs_cp_error(F2FS_I_SB(inode))))
7651f227a3eSJaegeuk Kim 		return -EIO;
7661f227a3eSJaegeuk Kim 
767fbfa2cc5SJaegeuk Kim 	if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
768fbfa2cc5SJaegeuk Kim 				S_ISLNK(inode->i_mode)))
769b0154891SChao Yu 		return 0;
770fbfa2cc5SJaegeuk Kim 
77151dd6249SNamjae Jeon 	trace_f2fs_truncate(inode);
77251dd6249SNamjae Jeon 
773c40e15a9SYangtao Li 	if (time_to_inject(F2FS_I_SB(inode), FAULT_TRUNCATE))
77414b44d23SJaegeuk Kim 		return -EIO;
7757fa750a1SArnd Bergmann 
77610a26878SChao Yu 	err = f2fs_dquot_initialize(inode);
77725fb04dbSYi Chen 	if (err)
77825fb04dbSYi Chen 		return err;
77925fb04dbSYi Chen 
78092dffd01SJaegeuk Kim 	/* we should check inline_data size */
781b9d777b8SJaegeuk Kim 	if (!f2fs_may_inline_data(inode)) {
782b0154891SChao Yu 		err = f2fs_convert_inline_inode(inode);
783b0154891SChao Yu 		if (err)
784b0154891SChao Yu 			return err;
78592dffd01SJaegeuk Kim 	}
78692dffd01SJaegeuk Kim 
787c42d28ceSChao Yu 	err = f2fs_truncate_blocks(inode, i_size_read(inode), true);
788b0154891SChao Yu 	if (err)
789b0154891SChao Yu 		return err;
790b0154891SChao Yu 
791c62ebd35SJeff Layton 	inode->i_mtime = inode_set_ctime_current(inode);
7927c45729aSJaegeuk Kim 	f2fs_mark_inode_dirty_sync(inode, false);
793b0154891SChao Yu 	return 0;
794fbfa2cc5SJaegeuk Kim }
795fbfa2cc5SJaegeuk Kim 
f2fs_force_buffered_io(struct inode * inode,int rw)796bd367329SEric Biggers static bool f2fs_force_buffered_io(struct inode *inode, int rw)
7972db0487fSEric Biggers {
7982db0487fSEric Biggers 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
7992db0487fSEric Biggers 
8002db0487fSEric Biggers 	if (!fscrypt_dio_supported(inode))
8012db0487fSEric Biggers 		return true;
8022db0487fSEric Biggers 	if (fsverity_active(inode))
8032db0487fSEric Biggers 		return true;
8042db0487fSEric Biggers 	if (f2fs_compressed_file(inode))
8052db0487fSEric Biggers 		return true;
8062db0487fSEric Biggers 
8072db0487fSEric Biggers 	/* disallow direct IO if any of devices has unaligned blksize */
8082db0487fSEric Biggers 	if (f2fs_is_multi_device(sbi) && !sbi->aligned_blksize)
8092db0487fSEric Biggers 		return true;
8105d170fe4SLinus Torvalds 	/*
8115d170fe4SLinus Torvalds 	 * for blkzoned device, fallback direct IO to buffered IO, so
8125d170fe4SLinus Torvalds 	 * all IOs can be serialized by log-structured write.
8135d170fe4SLinus Torvalds 	 */
8145d170fe4SLinus Torvalds 	if (f2fs_sb_has_blkzoned(sbi) && (rw == WRITE))
8155d170fe4SLinus Torvalds 		return true;
816bd367329SEric Biggers 	if (f2fs_lfs_mode(sbi) && rw == WRITE && F2FS_IO_ALIGNED(sbi))
8172db0487fSEric Biggers 		return true;
818bd367329SEric Biggers 	if (is_sbi_flag_set(sbi, SBI_CP_DISABLED))
8192db0487fSEric Biggers 		return true;
8202db0487fSEric Biggers 
8212db0487fSEric Biggers 	return false;
8222db0487fSEric Biggers }
8232db0487fSEric Biggers 
f2fs_getattr(struct mnt_idmap * idmap,const struct path * path,struct kstat * stat,u32 request_mask,unsigned int query_flags)824b74d24f7SChristian Brauner int f2fs_getattr(struct mnt_idmap *idmap, const struct path *path,
825549c7297SChristian Brauner 		 struct kstat *stat, u32 request_mask, unsigned int query_flags)
826fbfa2cc5SJaegeuk Kim {
827a528d35eSDavid Howells 	struct inode *inode = d_inode(path->dentry);
8281c6d8ee4SChao Yu 	struct f2fs_inode_info *fi = F2FS_I(inode);
829d13732ccSJia Yang 	struct f2fs_inode *ri = NULL;
8301c6d8ee4SChao Yu 	unsigned int flags;
8311c6d8ee4SChao Yu 
8321c1d35dfSChao Yu 	if (f2fs_has_extra_attr(inode) &&
8337beb01f7SChao Yu 			f2fs_sb_has_inode_crtime(F2FS_I_SB(inode)) &&
8341c1d35dfSChao Yu 			F2FS_FITS_IN_INODE(ri, fi->i_extra_isize, i_crtime)) {
8351c1d35dfSChao Yu 		stat->result_mask |= STATX_BTIME;
8361c1d35dfSChao Yu 		stat->btime.tv_sec = fi->i_crtime.tv_sec;
8371c1d35dfSChao Yu 		stat->btime.tv_nsec = fi->i_crtime.tv_nsec;
8381c1d35dfSChao Yu 	}
8391c1d35dfSChao Yu 
840c8c02272SEric Biggers 	/*
841c8c02272SEric Biggers 	 * Return the DIO alignment restrictions if requested.  We only return
842c8c02272SEric Biggers 	 * this information when requested, since on encrypted files it might
843c8c02272SEric Biggers 	 * take a fair bit of work to get if the file wasn't opened recently.
844c8c02272SEric Biggers 	 *
845c8c02272SEric Biggers 	 * f2fs sometimes supports DIO reads but not DIO writes.  STATX_DIOALIGN
846c8c02272SEric Biggers 	 * cannot represent that, so in that case we report no DIO support.
847c8c02272SEric Biggers 	 */
848c8c02272SEric Biggers 	if ((request_mask & STATX_DIOALIGN) && S_ISREG(inode->i_mode)) {
849c8c02272SEric Biggers 		unsigned int bsize = i_blocksize(inode);
850c8c02272SEric Biggers 
851c8c02272SEric Biggers 		stat->result_mask |= STATX_DIOALIGN;
852c8c02272SEric Biggers 		if (!f2fs_force_buffered_io(inode, WRITE)) {
853c8c02272SEric Biggers 			stat->dio_mem_align = bsize;
854c8c02272SEric Biggers 			stat->dio_offset_align = bsize;
855c8c02272SEric Biggers 		}
856c8c02272SEric Biggers 	}
857c8c02272SEric Biggers 
85836098557SEric Biggers 	flags = fi->i_flags;
859fd26725fSChao Yu 	if (flags & F2FS_COMPR_FL)
860fd26725fSChao Yu 		stat->attributes |= STATX_ATTR_COMPRESSED;
86159c84408SChao Yu 	if (flags & F2FS_APPEND_FL)
8621c6d8ee4SChao Yu 		stat->attributes |= STATX_ATTR_APPEND;
86362230e0dSChandan Rajendra 	if (IS_ENCRYPTED(inode))
8641c6d8ee4SChao Yu 		stat->attributes |= STATX_ATTR_ENCRYPTED;
86559c84408SChao Yu 	if (flags & F2FS_IMMUTABLE_FL)
8661c6d8ee4SChao Yu 		stat->attributes |= STATX_ATTR_IMMUTABLE;
86759c84408SChao Yu 	if (flags & F2FS_NODUMP_FL)
8681c6d8ee4SChao Yu 		stat->attributes |= STATX_ATTR_NODUMP;
869924e3194SEric Biggers 	if (IS_VERITY(inode))
870924e3194SEric Biggers 		stat->attributes |= STATX_ATTR_VERITY;
8711c6d8ee4SChao Yu 
872fd26725fSChao Yu 	stat->attributes_mask |= (STATX_ATTR_COMPRESSED |
873fd26725fSChao Yu 				  STATX_ATTR_APPEND |
8741c6d8ee4SChao Yu 				  STATX_ATTR_ENCRYPTED |
8751c6d8ee4SChao Yu 				  STATX_ATTR_IMMUTABLE |
876924e3194SEric Biggers 				  STATX_ATTR_NODUMP |
877924e3194SEric Biggers 				  STATX_ATTR_VERITY);
8781c6d8ee4SChao Yu 
8790d72b928SJeff Layton 	generic_fillattr(idmap, request_mask, inode, stat);
8805b4267d1SJaegeuk Kim 
8815b4267d1SJaegeuk Kim 	/* we need to show initial sectors used for inline_data/dentries */
8825b4267d1SJaegeuk Kim 	if ((S_ISREG(inode->i_mode) && f2fs_has_inline_data(inode)) ||
8835b4267d1SJaegeuk Kim 					f2fs_has_inline_dentry(inode))
8845b4267d1SJaegeuk Kim 		stat->blocks += (stat->size + 511) >> 9;
8855b4267d1SJaegeuk Kim 
886fbfa2cc5SJaegeuk Kim 	return 0;
887fbfa2cc5SJaegeuk Kim }
888fbfa2cc5SJaegeuk Kim 
889fbfa2cc5SJaegeuk Kim #ifdef CONFIG_F2FS_FS_POSIX_ACL
__setattr_copy(struct mnt_idmap * idmap,struct inode * inode,const struct iattr * attr)890c1632a0fSChristian Brauner static void __setattr_copy(struct mnt_idmap *idmap,
891e65ce2a5SChristian Brauner 			   struct inode *inode, const struct iattr *attr)
892fbfa2cc5SJaegeuk Kim {
893fbfa2cc5SJaegeuk Kim 	unsigned int ia_valid = attr->ia_valid;
894fbfa2cc5SJaegeuk Kim 
8950dbe12f2SChristian Brauner 	i_uid_update(idmap, attr, inode);
8960dbe12f2SChristian Brauner 	i_gid_update(idmap, attr, inode);
897eb31e2f6SAmir Goldstein 	if (ia_valid & ATTR_ATIME)
898eb31e2f6SAmir Goldstein 		inode->i_atime = attr->ia_atime;
899eb31e2f6SAmir Goldstein 	if (ia_valid & ATTR_MTIME)
900eb31e2f6SAmir Goldstein 		inode->i_mtime = attr->ia_mtime;
901eb31e2f6SAmir Goldstein 	if (ia_valid & ATTR_CTIME)
902c62ebd35SJeff Layton 		inode_set_ctime_to_ts(inode, attr->ia_ctime);
903fbfa2cc5SJaegeuk Kim 	if (ia_valid & ATTR_MODE) {
904fbfa2cc5SJaegeuk Kim 		umode_t mode = attr->ia_mode;
905e67fe633SChristian Brauner 		vfsgid_t vfsgid = i_gid_into_vfsgid(idmap, inode);
906fbfa2cc5SJaegeuk Kim 
9071e8a9191SChristian Brauner 		if (!vfsgid_in_group_p(vfsgid) &&
9089452e93eSChristian Brauner 		    !capable_wrt_inode_uidgid(idmap, inode, CAP_FSETID))
909fbfa2cc5SJaegeuk Kim 			mode &= ~S_ISGID;
91091942321SJaegeuk Kim 		set_acl_inode(inode, mode);
911fbfa2cc5SJaegeuk Kim 	}
912fbfa2cc5SJaegeuk Kim }
913fbfa2cc5SJaegeuk Kim #else
914fbfa2cc5SJaegeuk Kim #define __setattr_copy setattr_copy
915fbfa2cc5SJaegeuk Kim #endif
916fbfa2cc5SJaegeuk Kim 
f2fs_setattr(struct mnt_idmap * idmap,struct dentry * dentry,struct iattr * attr)917c1632a0fSChristian Brauner int f2fs_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
918549c7297SChristian Brauner 		 struct iattr *attr)
919fbfa2cc5SJaegeuk Kim {
9202b0143b5SDavid Howells 	struct inode *inode = d_inode(dentry);
921fbfa2cc5SJaegeuk Kim 	int err;
922fbfa2cc5SJaegeuk Kim 
9231f227a3eSJaegeuk Kim 	if (unlikely(f2fs_cp_error(F2FS_I_SB(inode))))
9241f227a3eSJaegeuk Kim 		return -EIO;
9251f227a3eSJaegeuk Kim 
926e0fcd015SChao Yu 	if (unlikely(IS_IMMUTABLE(inode)))
927e0fcd015SChao Yu 		return -EPERM;
928e0fcd015SChao Yu 
929e0fcd015SChao Yu 	if (unlikely(IS_APPEND(inode) &&
930e0fcd015SChao Yu 			(attr->ia_valid & (ATTR_MODE | ATTR_UID |
931e0fcd015SChao Yu 				  ATTR_GID | ATTR_TIMES_SET))))
932e0fcd015SChao Yu 		return -EPERM;
933e0fcd015SChao Yu 
9344c8ff709SChao Yu 	if ((attr->ia_valid & ATTR_SIZE) &&
9354c8ff709SChao Yu 		!f2fs_is_compress_backend_ready(inode))
9364c8ff709SChao Yu 		return -EOPNOTSUPP;
9374c8ff709SChao Yu 
938c1632a0fSChristian Brauner 	err = setattr_prepare(idmap, dentry, attr);
939fbfa2cc5SJaegeuk Kim 	if (err)
940fbfa2cc5SJaegeuk Kim 		return err;
941fbfa2cc5SJaegeuk Kim 
94220bb2479SEric Biggers 	err = fscrypt_prepare_setattr(dentry, attr);
94320bb2479SEric Biggers 	if (err)
94420bb2479SEric Biggers 		return err;
94520bb2479SEric Biggers 
94695ae251fSEric Biggers 	err = fsverity_prepare_setattr(dentry, attr);
94795ae251fSEric Biggers 	if (err)
94895ae251fSEric Biggers 		return err;
94995ae251fSEric Biggers 
950f861646aSChristian Brauner 	if (is_quota_modification(idmap, inode, attr)) {
95110a26878SChao Yu 		err = f2fs_dquot_initialize(inode);
9520abd675eSChao Yu 		if (err)
9530abd675eSChao Yu 			return err;
9540abd675eSChao Yu 	}
9550dbe12f2SChristian Brauner 	if (i_uid_needs_update(idmap, attr, inode) ||
9560dbe12f2SChristian Brauner 	    i_gid_needs_update(idmap, attr, inode)) {
957af033b2aSChao Yu 		f2fs_lock_op(F2FS_I_SB(inode));
958f861646aSChristian Brauner 		err = dquot_transfer(idmap, inode, attr);
959af033b2aSChao Yu 		if (err) {
960af033b2aSChao Yu 			set_sbi_flag(F2FS_I_SB(inode),
961af033b2aSChao Yu 					SBI_QUOTA_NEED_REPAIR);
962af033b2aSChao Yu 			f2fs_unlock_op(F2FS_I_SB(inode));
9630abd675eSChao Yu 			return err;
9640abd675eSChao Yu 		}
965af033b2aSChao Yu 		/*
966af033b2aSChao Yu 		 * update uid/gid under lock_op(), so that dquot and inode can
967af033b2aSChao Yu 		 * be updated atomically.
968af033b2aSChao Yu 		 */
9690dbe12f2SChristian Brauner 		i_uid_update(idmap, attr, inode);
9700dbe12f2SChristian Brauner 		i_gid_update(idmap, attr, inode);
971af033b2aSChao Yu 		f2fs_mark_inode_dirty_sync(inode, true);
972af033b2aSChao Yu 		f2fs_unlock_op(F2FS_I_SB(inode));
973af033b2aSChao Yu 	}
9740abd675eSChao Yu 
97509db6a2eSChao Yu 	if (attr->ia_valid & ATTR_SIZE) {
976cfb9a34dSJaegeuk Kim 		loff_t old_size = i_size_read(inode);
977cfb9a34dSJaegeuk Kim 
978cfb9a34dSJaegeuk Kim 		if (attr->ia_size > MAX_INLINE_DATA(inode)) {
979cfb9a34dSJaegeuk Kim 			/*
980cfb9a34dSJaegeuk Kim 			 * should convert inline inode before i_size_write to
981cfb9a34dSJaegeuk Kim 			 * keep smaller than inline_data size with inline flag.
982cfb9a34dSJaegeuk Kim 			 */
983cfb9a34dSJaegeuk Kim 			err = f2fs_convert_inline_inode(inode);
984cfb9a34dSJaegeuk Kim 			if (err)
985cfb9a34dSJaegeuk Kim 				return err;
986cfb9a34dSJaegeuk Kim 		}
987a33c1502SChao Yu 
988e4544b63STim Murray 		f2fs_down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
989edc6d01bSJan Kara 		filemap_invalidate_lock(inode->i_mapping);
990a33c1502SChao Yu 
991fbfa2cc5SJaegeuk Kim 		truncate_setsize(inode, attr->ia_size);
992a33c1502SChao Yu 
993cfb9a34dSJaegeuk Kim 		if (attr->ia_size <= old_size)
9949a449e9cSJaegeuk Kim 			err = f2fs_truncate(inode);
99509db6a2eSChao Yu 		/*
9963c454145SChao Yu 		 * do not trim all blocks after i_size if target size is
9973c454145SChao Yu 		 * larger than i_size.
99809db6a2eSChao Yu 		 */
999edc6d01bSJan Kara 		filemap_invalidate_unlock(inode->i_mapping);
1000e4544b63STim Murray 		f2fs_up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
1001a33c1502SChao Yu 		if (err)
1002a33c1502SChao Yu 			return err;
1003a33c1502SChao Yu 
1004c10c9820SChao Yu 		spin_lock(&F2FS_I(inode)->i_size_lock);
1005c62ebd35SJeff Layton 		inode->i_mtime = inode_set_ctime_current(inode);
1006a0d00fadSChao Yu 		F2FS_I(inode)->last_disk_size = i_size_read(inode);
1007c10c9820SChao Yu 		spin_unlock(&F2FS_I(inode)->i_size_lock);
1008fbfa2cc5SJaegeuk Kim 	}
1009fbfa2cc5SJaegeuk Kim 
1010c1632a0fSChristian Brauner 	__setattr_copy(idmap, inode, attr);
1011fbfa2cc5SJaegeuk Kim 
1012fbfa2cc5SJaegeuk Kim 	if (attr->ia_valid & ATTR_MODE) {
101313e83a49SChristian Brauner 		err = posix_acl_chmod(idmap, dentry, f2fs_get_inode_mode(inode));
101417232e83SChao Yu 
101517232e83SChao Yu 		if (is_inode_flag_set(inode, FI_ACL_MODE)) {
101617232e83SChao Yu 			if (!err)
101791942321SJaegeuk Kim 				inode->i_mode = F2FS_I(inode)->i_acl_mode;
101891942321SJaegeuk Kim 			clear_inode_flag(inode, FI_ACL_MODE);
1019fbfa2cc5SJaegeuk Kim 		}
1020fbfa2cc5SJaegeuk Kim 	}
1021fbfa2cc5SJaegeuk Kim 
1022c0ed4405SYunlei He 	/* file size may changed here */
1023ca597bddSChao Yu 	f2fs_mark_inode_dirty_sync(inode, true);
102415d04354SJaegeuk Kim 
102515d04354SJaegeuk Kim 	/* inode change will produce dirty node pages flushed by checkpoint */
102615d04354SJaegeuk Kim 	f2fs_balance_fs(F2FS_I_SB(inode), true);
102715d04354SJaegeuk Kim 
1028fbfa2cc5SJaegeuk Kim 	return err;
1029fbfa2cc5SJaegeuk Kim }
1030fbfa2cc5SJaegeuk Kim 
1031fbfa2cc5SJaegeuk Kim const struct inode_operations f2fs_file_inode_operations = {
1032fbfa2cc5SJaegeuk Kim 	.getattr	= f2fs_getattr,
1033fbfa2cc5SJaegeuk Kim 	.setattr	= f2fs_setattr,
1034cac2f8b8SChristian Brauner 	.get_inode_acl	= f2fs_get_acl,
1035a6dda0e6SChristoph Hellwig 	.set_acl	= f2fs_set_acl,
1036fbfa2cc5SJaegeuk Kim 	.listxattr	= f2fs_listxattr,
10379ab70134SJaegeuk Kim 	.fiemap		= f2fs_fiemap,
10389b1bb01cSMiklos Szeredi 	.fileattr_get	= f2fs_fileattr_get,
10399b1bb01cSMiklos Szeredi 	.fileattr_set	= f2fs_fileattr_set,
1040fbfa2cc5SJaegeuk Kim };
1041fbfa2cc5SJaegeuk Kim 
fill_zero(struct inode * inode,pgoff_t index,loff_t start,loff_t len)10426394328aSChao Yu static int fill_zero(struct inode *inode, pgoff_t index,
1043fbfa2cc5SJaegeuk Kim 					loff_t start, loff_t len)
1044fbfa2cc5SJaegeuk Kim {
10454081363fSJaegeuk Kim 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
1046fbfa2cc5SJaegeuk Kim 	struct page *page;
1047fbfa2cc5SJaegeuk Kim 
1048fbfa2cc5SJaegeuk Kim 	if (!len)
10496394328aSChao Yu 		return 0;
1050fbfa2cc5SJaegeuk Kim 
10512c4db1a6SJaegeuk Kim 	f2fs_balance_fs(sbi, true);
1052bd43df02SJaegeuk Kim 
1053e479556bSGu Zheng 	f2fs_lock_op(sbi);
10544d57b86dSChao Yu 	page = f2fs_get_new_data_page(inode, NULL, index, false);
1055e479556bSGu Zheng 	f2fs_unlock_op(sbi);
1056fbfa2cc5SJaegeuk Kim 
10576394328aSChao Yu 	if (IS_ERR(page))
10586394328aSChao Yu 		return PTR_ERR(page);
10596394328aSChao Yu 
1060bae0ee7aSChao Yu 	f2fs_wait_on_page_writeback(page, DATA, true, true);
1061fbfa2cc5SJaegeuk Kim 	zero_user(page, start, len);
1062fbfa2cc5SJaegeuk Kim 	set_page_dirty(page);
1063fbfa2cc5SJaegeuk Kim 	f2fs_put_page(page, 1);
10646394328aSChao Yu 	return 0;
1065fbfa2cc5SJaegeuk Kim }
1066fbfa2cc5SJaegeuk Kim 
f2fs_truncate_hole(struct inode * inode,pgoff_t pg_start,pgoff_t pg_end)10674d57b86dSChao Yu int f2fs_truncate_hole(struct inode *inode, pgoff_t pg_start, pgoff_t pg_end)
1068fbfa2cc5SJaegeuk Kim {
1069fbfa2cc5SJaegeuk Kim 	int err;
1070fbfa2cc5SJaegeuk Kim 
1071ea58711eSChao Yu 	while (pg_start < pg_end) {
1072fbfa2cc5SJaegeuk Kim 		struct dnode_of_data dn;
1073ea58711eSChao Yu 		pgoff_t end_offset, count;
1074fbfa2cc5SJaegeuk Kim 
1075fbfa2cc5SJaegeuk Kim 		set_new_dnode(&dn, inode, NULL, NULL, 0);
10764d57b86dSChao Yu 		err = f2fs_get_dnode_of_data(&dn, pg_start, LOOKUP_NODE);
1077fbfa2cc5SJaegeuk Kim 		if (err) {
1078ea58711eSChao Yu 			if (err == -ENOENT) {
10794d57b86dSChao Yu 				pg_start = f2fs_get_next_page_offset(&dn,
10804d57b86dSChao Yu 								pg_start);
1081fbfa2cc5SJaegeuk Kim 				continue;
1082ea58711eSChao Yu 			}
1083fbfa2cc5SJaegeuk Kim 			return err;
1084fbfa2cc5SJaegeuk Kim 		}
1085fbfa2cc5SJaegeuk Kim 
108681ca7350SChao Yu 		end_offset = ADDRS_PER_PAGE(dn.node_page, inode);
1087ea58711eSChao Yu 		count = min(end_offset - dn.ofs_in_node, pg_end - pg_start);
1088ea58711eSChao Yu 
1089ea58711eSChao Yu 		f2fs_bug_on(F2FS_I_SB(inode), count == 0 || count > end_offset);
1090ea58711eSChao Yu 
10914d57b86dSChao Yu 		f2fs_truncate_data_blocks_range(&dn, count);
1092fbfa2cc5SJaegeuk Kim 		f2fs_put_dnode(&dn);
1093ea58711eSChao Yu 
1094ea58711eSChao Yu 		pg_start += count;
1095fbfa2cc5SJaegeuk Kim 	}
1096fbfa2cc5SJaegeuk Kim 	return 0;
1097fbfa2cc5SJaegeuk Kim }
1098fbfa2cc5SJaegeuk Kim 
f2fs_punch_hole(struct inode * inode,loff_t offset,loff_t len)10991cd75654SYangtao Li static int f2fs_punch_hole(struct inode *inode, loff_t offset, loff_t len)
1100fbfa2cc5SJaegeuk Kim {
1101fbfa2cc5SJaegeuk Kim 	pgoff_t pg_start, pg_end;
1102fbfa2cc5SJaegeuk Kim 	loff_t off_start, off_end;
1103b9d777b8SJaegeuk Kim 	int ret;
1104fbfa2cc5SJaegeuk Kim 
1105b3d208f9SJaegeuk Kim 	ret = f2fs_convert_inline_inode(inode);
11069ffe0fb5SHuajun Li 	if (ret)
11079ffe0fb5SHuajun Li 		return ret;
11089ffe0fb5SHuajun Li 
110909cbfeafSKirill A. Shutemov 	pg_start = ((unsigned long long) offset) >> PAGE_SHIFT;
111009cbfeafSKirill A. Shutemov 	pg_end = ((unsigned long long) offset + len) >> PAGE_SHIFT;
1111fbfa2cc5SJaegeuk Kim 
111209cbfeafSKirill A. Shutemov 	off_start = offset & (PAGE_SIZE - 1);
111309cbfeafSKirill A. Shutemov 	off_end = (offset + len) & (PAGE_SIZE - 1);
1114fbfa2cc5SJaegeuk Kim 
1115fbfa2cc5SJaegeuk Kim 	if (pg_start == pg_end) {
11166394328aSChao Yu 		ret = fill_zero(inode, pg_start, off_start,
1117fbfa2cc5SJaegeuk Kim 						off_end - off_start);
11186394328aSChao Yu 		if (ret)
11196394328aSChao Yu 			return ret;
1120fbfa2cc5SJaegeuk Kim 	} else {
11216394328aSChao Yu 		if (off_start) {
11226394328aSChao Yu 			ret = fill_zero(inode, pg_start++, off_start,
112309cbfeafSKirill A. Shutemov 						PAGE_SIZE - off_start);
11246394328aSChao Yu 			if (ret)
11256394328aSChao Yu 				return ret;
11266394328aSChao Yu 		}
11276394328aSChao Yu 		if (off_end) {
11286394328aSChao Yu 			ret = fill_zero(inode, pg_end, 0, off_end);
11296394328aSChao Yu 			if (ret)
11306394328aSChao Yu 				return ret;
11316394328aSChao Yu 		}
1132fbfa2cc5SJaegeuk Kim 
1133fbfa2cc5SJaegeuk Kim 		if (pg_start < pg_end) {
1134fbfa2cc5SJaegeuk Kim 			loff_t blk_start, blk_end;
11354081363fSJaegeuk Kim 			struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
11361127a3d4SJason Hrycay 
11372c4db1a6SJaegeuk Kim 			f2fs_balance_fs(sbi, true);
1138fbfa2cc5SJaegeuk Kim 
113909cbfeafSKirill A. Shutemov 			blk_start = (loff_t)pg_start << PAGE_SHIFT;
114009cbfeafSKirill A. Shutemov 			blk_end = (loff_t)pg_end << PAGE_SHIFT;
1141a33c1502SChao Yu 
1142e4544b63STim Murray 			f2fs_down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
11436abaa83cSLinus Torvalds 			filemap_invalidate_lock(inode->i_mapping);
1144a33c1502SChao Yu 
1145c8dc3047SChao Yu 			truncate_pagecache_range(inode, blk_start, blk_end - 1);
114639936837SJaegeuk Kim 
1147e479556bSGu Zheng 			f2fs_lock_op(sbi);
11484d57b86dSChao Yu 			ret = f2fs_truncate_hole(inode, pg_start, pg_end);
1149e479556bSGu Zheng 			f2fs_unlock_op(sbi);
1150a33c1502SChao Yu 
11516abaa83cSLinus Torvalds 			filemap_invalidate_unlock(inode->i_mapping);
1152e4544b63STim Murray 			f2fs_up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
1153fbfa2cc5SJaegeuk Kim 		}
1154fbfa2cc5SJaegeuk Kim 	}
1155fbfa2cc5SJaegeuk Kim 
1156fbfa2cc5SJaegeuk Kim 	return ret;
1157fbfa2cc5SJaegeuk Kim }
1158fbfa2cc5SJaegeuk Kim 
__read_out_blkaddrs(struct inode * inode,block_t * blkaddr,int * do_replace,pgoff_t off,pgoff_t len)11590a2aa8fbSJaegeuk Kim static int __read_out_blkaddrs(struct inode *inode, block_t *blkaddr,
11600a2aa8fbSJaegeuk Kim 				int *do_replace, pgoff_t off, pgoff_t len)
1161b4ace337SChao Yu {
1162b4ace337SChao Yu 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
1163b4ace337SChao Yu 	struct dnode_of_data dn;
11640a2aa8fbSJaegeuk Kim 	int ret, done, i;
1165ecbaa406SChao Yu 
11660a2aa8fbSJaegeuk Kim next_dnode:
1167b4ace337SChao Yu 	set_new_dnode(&dn, inode, NULL, NULL, 0);
11684d57b86dSChao Yu 	ret = f2fs_get_dnode_of_data(&dn, off, LOOKUP_NODE_RA);
1169b4ace337SChao Yu 	if (ret && ret != -ENOENT) {
11706e2c64adSJaegeuk Kim 		return ret;
1171b4ace337SChao Yu 	} else if (ret == -ENOENT) {
11720a2aa8fbSJaegeuk Kim 		if (dn.max_level == 0)
11730a2aa8fbSJaegeuk Kim 			return -ENOENT;
11744c8ff709SChao Yu 		done = min((pgoff_t)ADDRS_PER_BLOCK(inode) -
11754c8ff709SChao Yu 						dn.ofs_in_node, len);
11760a2aa8fbSJaegeuk Kim 		blkaddr += done;
11770a2aa8fbSJaegeuk Kim 		do_replace += done;
11780a2aa8fbSJaegeuk Kim 		goto next;
11790a2aa8fbSJaegeuk Kim 	}
11800a2aa8fbSJaegeuk Kim 
11810a2aa8fbSJaegeuk Kim 	done = min((pgoff_t)ADDRS_PER_PAGE(dn.node_page, inode) -
11820a2aa8fbSJaegeuk Kim 							dn.ofs_in_node, len);
11830a2aa8fbSJaegeuk Kim 	for (i = 0; i < done; i++, blkaddr++, do_replace++, dn.ofs_in_node++) {
1184a2ced1ceSChao Yu 		*blkaddr = f2fs_data_blkaddr(&dn);
118593770ab7SChao Yu 
118693770ab7SChao Yu 		if (__is_valid_data_blkaddr(*blkaddr) &&
118793770ab7SChao Yu 			!f2fs_is_valid_blkaddr(sbi, *blkaddr,
118893770ab7SChao Yu 					DATA_GENERIC_ENHANCE)) {
118993770ab7SChao Yu 			f2fs_put_dnode(&dn);
119095fa90c9SChao Yu 			f2fs_handle_error(sbi, ERROR_INVALID_BLKADDR);
119110f966bbSChao Yu 			return -EFSCORRUPTED;
119293770ab7SChao Yu 		}
119393770ab7SChao Yu 
11944d57b86dSChao Yu 		if (!f2fs_is_checkpointed_data(sbi, *blkaddr)) {
11950a2aa8fbSJaegeuk Kim 
1196b0332a0fSChao Yu 			if (f2fs_lfs_mode(sbi)) {
11970a2aa8fbSJaegeuk Kim 				f2fs_put_dnode(&dn);
1198fd114ab2SChao Yu 				return -EOPNOTSUPP;
11990a2aa8fbSJaegeuk Kim 			}
12000a2aa8fbSJaegeuk Kim 
12016e2c64adSJaegeuk Kim 			/* do not invalidate this block address */
1202f28b3434SChao Yu 			f2fs_update_data_blkaddr(&dn, NULL_ADDR);
12030a2aa8fbSJaegeuk Kim 			*do_replace = 1;
12040a2aa8fbSJaegeuk Kim 		}
12050a2aa8fbSJaegeuk Kim 	}
12060a2aa8fbSJaegeuk Kim 	f2fs_put_dnode(&dn);
12070a2aa8fbSJaegeuk Kim next:
12080a2aa8fbSJaegeuk Kim 	len -= done;
12090a2aa8fbSJaegeuk Kim 	off += done;
12100a2aa8fbSJaegeuk Kim 	if (len)
12110a2aa8fbSJaegeuk Kim 		goto next_dnode;
12120a2aa8fbSJaegeuk Kim 	return 0;
12130a2aa8fbSJaegeuk Kim }
12140a2aa8fbSJaegeuk Kim 
__roll_back_blkaddrs(struct inode * inode,block_t * blkaddr,int * do_replace,pgoff_t off,int len)12150a2aa8fbSJaegeuk Kim static int __roll_back_blkaddrs(struct inode *inode, block_t *blkaddr,
12160a2aa8fbSJaegeuk Kim 				int *do_replace, pgoff_t off, int len)
12170a2aa8fbSJaegeuk Kim {
12180a2aa8fbSJaegeuk Kim 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
12190a2aa8fbSJaegeuk Kim 	struct dnode_of_data dn;
12200a2aa8fbSJaegeuk Kim 	int ret, i;
12210a2aa8fbSJaegeuk Kim 
12220a2aa8fbSJaegeuk Kim 	for (i = 0; i < len; i++, do_replace++, blkaddr++) {
12230a2aa8fbSJaegeuk Kim 		if (*do_replace == 0)
12240a2aa8fbSJaegeuk Kim 			continue;
12250a2aa8fbSJaegeuk Kim 
12260a2aa8fbSJaegeuk Kim 		set_new_dnode(&dn, inode, NULL, NULL, 0);
12274d57b86dSChao Yu 		ret = f2fs_get_dnode_of_data(&dn, off + i, LOOKUP_NODE_RA);
12280a2aa8fbSJaegeuk Kim 		if (ret) {
12290a2aa8fbSJaegeuk Kim 			dec_valid_block_count(sbi, inode, 1);
12304d57b86dSChao Yu 			f2fs_invalidate_blocks(sbi, *blkaddr);
12310a2aa8fbSJaegeuk Kim 		} else {
12320a2aa8fbSJaegeuk Kim 			f2fs_update_data_blkaddr(&dn, *blkaddr);
12336e2c64adSJaegeuk Kim 		}
1234b4ace337SChao Yu 		f2fs_put_dnode(&dn);
1235b4ace337SChao Yu 	}
12360a2aa8fbSJaegeuk Kim 	return 0;
12370a2aa8fbSJaegeuk Kim }
1238b4ace337SChao 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)12390a2aa8fbSJaegeuk Kim static int __clone_blkaddrs(struct inode *src_inode, struct inode *dst_inode,
12400a2aa8fbSJaegeuk Kim 			block_t *blkaddr, int *do_replace,
12410a2aa8fbSJaegeuk Kim 			pgoff_t src, pgoff_t dst, pgoff_t len, bool full)
12420a2aa8fbSJaegeuk Kim {
12430a2aa8fbSJaegeuk Kim 	struct f2fs_sb_info *sbi = F2FS_I_SB(src_inode);
12440a2aa8fbSJaegeuk Kim 	pgoff_t i = 0;
12450a2aa8fbSJaegeuk Kim 	int ret;
1246b4ace337SChao Yu 
12470a2aa8fbSJaegeuk Kim 	while (i < len) {
12480a2aa8fbSJaegeuk Kim 		if (blkaddr[i] == NULL_ADDR && !full) {
12490a2aa8fbSJaegeuk Kim 			i++;
12500a2aa8fbSJaegeuk Kim 			continue;
12510a2aa8fbSJaegeuk Kim 		}
12520a2aa8fbSJaegeuk Kim 
12530a2aa8fbSJaegeuk Kim 		if (do_replace[i] || blkaddr[i] == NULL_ADDR) {
12540a2aa8fbSJaegeuk Kim 			struct dnode_of_data dn;
12556e2c64adSJaegeuk Kim 			struct node_info ni;
12560a2aa8fbSJaegeuk Kim 			size_t new_size;
12570a2aa8fbSJaegeuk Kim 			pgoff_t ilen;
1258b4ace337SChao Yu 
12590a2aa8fbSJaegeuk Kim 			set_new_dnode(&dn, dst_inode, NULL, NULL, 0);
12604d57b86dSChao Yu 			ret = f2fs_get_dnode_of_data(&dn, dst + i, ALLOC_NODE);
1261b4ace337SChao Yu 			if (ret)
12620a2aa8fbSJaegeuk Kim 				return ret;
1263b4ace337SChao Yu 
1264a9419b63SJaegeuk Kim 			ret = f2fs_get_node_info(sbi, dn.nid, &ni, false);
12657735730dSChao Yu 			if (ret) {
12667735730dSChao Yu 				f2fs_put_dnode(&dn);
12677735730dSChao Yu 				return ret;
12687735730dSChao Yu 			}
12697735730dSChao Yu 
12700a2aa8fbSJaegeuk Kim 			ilen = min((pgoff_t)
12710a2aa8fbSJaegeuk Kim 				ADDRS_PER_PAGE(dn.node_page, dst_inode) -
12720a2aa8fbSJaegeuk Kim 						dn.ofs_in_node, len - i);
12730a2aa8fbSJaegeuk Kim 			do {
1274a2ced1ceSChao Yu 				dn.data_blkaddr = f2fs_data_blkaddr(&dn);
12754d57b86dSChao Yu 				f2fs_truncate_data_blocks_range(&dn, 1);
12760a2aa8fbSJaegeuk Kim 
12770a2aa8fbSJaegeuk Kim 				if (do_replace[i]) {
12780a2aa8fbSJaegeuk Kim 					f2fs_i_blocks_write(src_inode,
12790abd675eSChao Yu 							1, false, false);
12800a2aa8fbSJaegeuk Kim 					f2fs_i_blocks_write(dst_inode,
12810abd675eSChao Yu 							1, true, false);
12820a2aa8fbSJaegeuk Kim 					f2fs_replace_block(sbi, &dn, dn.data_blkaddr,
12830a2aa8fbSJaegeuk Kim 					blkaddr[i], ni.version, true, false);
12840a2aa8fbSJaegeuk Kim 
12850a2aa8fbSJaegeuk Kim 					do_replace[i] = 0;
12860a2aa8fbSJaegeuk Kim 				}
12870a2aa8fbSJaegeuk Kim 				dn.ofs_in_node++;
12880a2aa8fbSJaegeuk Kim 				i++;
12891f0d5c91SChao Yu 				new_size = (loff_t)(dst + i) << PAGE_SHIFT;
12900a2aa8fbSJaegeuk Kim 				if (dst_inode->i_size < new_size)
12910a2aa8fbSJaegeuk Kim 					f2fs_i_size_write(dst_inode, new_size);
1292e87f7329SJaegeuk Kim 			} while (--ilen && (do_replace[i] || blkaddr[i] == NULL_ADDR));
12930a2aa8fbSJaegeuk Kim 
1294b4ace337SChao Yu 			f2fs_put_dnode(&dn);
12956e2c64adSJaegeuk Kim 		} else {
12966e2c64adSJaegeuk Kim 			struct page *psrc, *pdst;
12976e2c64adSJaegeuk Kim 
12984d57b86dSChao Yu 			psrc = f2fs_get_lock_data_page(src_inode,
12994d57b86dSChao Yu 							src + i, true);
13006e2c64adSJaegeuk Kim 			if (IS_ERR(psrc))
13016e2c64adSJaegeuk Kim 				return PTR_ERR(psrc);
13024d57b86dSChao Yu 			pdst = f2fs_get_new_data_page(dst_inode, NULL, dst + i,
13030a2aa8fbSJaegeuk Kim 								true);
13046e2c64adSJaegeuk Kim 			if (IS_ERR(pdst)) {
13056e2c64adSJaegeuk Kim 				f2fs_put_page(psrc, 1);
13066e2c64adSJaegeuk Kim 				return PTR_ERR(pdst);
1307b4ace337SChao Yu 			}
13081dd55358SFabio M. De Francesco 			memcpy_page(pdst, 0, psrc, 0, PAGE_SIZE);
13096e2c64adSJaegeuk Kim 			set_page_dirty(pdst);
1310417b8a91SChao Yu 			set_page_private_gcing(pdst);
13116e2c64adSJaegeuk Kim 			f2fs_put_page(pdst, 1);
13126e2c64adSJaegeuk Kim 			f2fs_put_page(psrc, 1);
13136e2c64adSJaegeuk Kim 
13144d57b86dSChao Yu 			ret = f2fs_truncate_hole(src_inode,
13154d57b86dSChao Yu 						src + i, src + i + 1);
13160a2aa8fbSJaegeuk Kim 			if (ret)
13170a2aa8fbSJaegeuk Kim 				return ret;
13180a2aa8fbSJaegeuk Kim 			i++;
13190a2aa8fbSJaegeuk Kim 		}
1320b4ace337SChao Yu 	}
1321ecbaa406SChao Yu 	return 0;
13226e2c64adSJaegeuk Kim }
13230a2aa8fbSJaegeuk Kim 
__exchange_data_block(struct inode * src_inode,struct inode * dst_inode,pgoff_t src,pgoff_t dst,pgoff_t len,bool full)13240a2aa8fbSJaegeuk Kim static int __exchange_data_block(struct inode *src_inode,
13250a2aa8fbSJaegeuk Kim 			struct inode *dst_inode, pgoff_t src, pgoff_t dst,
1326363cad7fSJaegeuk Kim 			pgoff_t len, bool full)
13270a2aa8fbSJaegeuk Kim {
13280a2aa8fbSJaegeuk Kim 	block_t *src_blkaddr;
13290a2aa8fbSJaegeuk Kim 	int *do_replace;
1330363cad7fSJaegeuk Kim 	pgoff_t olen;
13310a2aa8fbSJaegeuk Kim 	int ret;
13320a2aa8fbSJaegeuk Kim 
1333363cad7fSJaegeuk Kim 	while (len) {
1334d02a6e61SChao Yu 		olen = min((pgoff_t)4 * ADDRS_PER_BLOCK(src_inode), len);
1335363cad7fSJaegeuk Kim 
1336628b3d14SChao Yu 		src_blkaddr = f2fs_kvzalloc(F2FS_I_SB(src_inode),
13379d2a789cSKees Cook 					array_size(olen, sizeof(block_t)),
13384f4460c0SJaegeuk Kim 					GFP_NOFS);
13390a2aa8fbSJaegeuk Kim 		if (!src_blkaddr)
13400a2aa8fbSJaegeuk Kim 			return -ENOMEM;
13410a2aa8fbSJaegeuk Kim 
1342628b3d14SChao Yu 		do_replace = f2fs_kvzalloc(F2FS_I_SB(src_inode),
13439d2a789cSKees Cook 					array_size(olen, sizeof(int)),
13444f4460c0SJaegeuk Kim 					GFP_NOFS);
13450a2aa8fbSJaegeuk Kim 		if (!do_replace) {
13460a2aa8fbSJaegeuk Kim 			kvfree(src_blkaddr);
13470a2aa8fbSJaegeuk Kim 			return -ENOMEM;
13480a2aa8fbSJaegeuk Kim 		}
13490a2aa8fbSJaegeuk Kim 
1350363cad7fSJaegeuk Kim 		ret = __read_out_blkaddrs(src_inode, src_blkaddr,
1351363cad7fSJaegeuk Kim 					do_replace, src, olen);
13520a2aa8fbSJaegeuk Kim 		if (ret)
13530a2aa8fbSJaegeuk Kim 			goto roll_back;
13540a2aa8fbSJaegeuk Kim 
13550a2aa8fbSJaegeuk Kim 		ret = __clone_blkaddrs(src_inode, dst_inode, src_blkaddr,
1356363cad7fSJaegeuk Kim 					do_replace, src, dst, olen, full);
13570a2aa8fbSJaegeuk Kim 		if (ret)
13580a2aa8fbSJaegeuk Kim 			goto roll_back;
13590a2aa8fbSJaegeuk Kim 
1360363cad7fSJaegeuk Kim 		src += olen;
1361363cad7fSJaegeuk Kim 		dst += olen;
1362363cad7fSJaegeuk Kim 		len -= olen;
1363363cad7fSJaegeuk Kim 
13640a2aa8fbSJaegeuk Kim 		kvfree(src_blkaddr);
13650a2aa8fbSJaegeuk Kim 		kvfree(do_replace);
1366363cad7fSJaegeuk Kim 	}
13670a2aa8fbSJaegeuk Kim 	return 0;
13680a2aa8fbSJaegeuk Kim 
13690a2aa8fbSJaegeuk Kim roll_back:
13709fd62605SChao Yu 	__roll_back_blkaddrs(src_inode, src_blkaddr, do_replace, src, olen);
13710a2aa8fbSJaegeuk Kim 	kvfree(src_blkaddr);
13720a2aa8fbSJaegeuk Kim 	kvfree(do_replace);
13736e2c64adSJaegeuk Kim 	return ret;
13746e2c64adSJaegeuk Kim }
13756e2c64adSJaegeuk Kim 
f2fs_do_collapse(struct inode * inode,loff_t offset,loff_t len)13766f8d4455SJaegeuk Kim static int f2fs_do_collapse(struct inode *inode, loff_t offset, loff_t len)
13776e2c64adSJaegeuk Kim {
13786e2c64adSJaegeuk Kim 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
1379f91108b8SGeert Uytterhoeven 	pgoff_t nrpages = DIV_ROUND_UP(i_size_read(inode), PAGE_SIZE);
13806f8d4455SJaegeuk Kim 	pgoff_t start = offset >> PAGE_SHIFT;
13816f8d4455SJaegeuk Kim 	pgoff_t end = (offset + len) >> PAGE_SHIFT;
13820a2aa8fbSJaegeuk Kim 	int ret;
13836e2c64adSJaegeuk Kim 
13842c4db1a6SJaegeuk Kim 	f2fs_balance_fs(sbi, true);
13856f8d4455SJaegeuk Kim 
13866f8d4455SJaegeuk Kim 	/* avoid gc operation during block exchange */
1387e4544b63STim Murray 	f2fs_down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
1388edc6d01bSJan Kara 	filemap_invalidate_lock(inode->i_mapping);
13896f8d4455SJaegeuk Kim 
13906e2c64adSJaegeuk Kim 	f2fs_lock_op(sbi);
13915f281fabSJaegeuk Kim 	f2fs_drop_extent_tree(inode);
13926f8d4455SJaegeuk Kim 	truncate_pagecache(inode, offset);
13930a2aa8fbSJaegeuk Kim 	ret = __exchange_data_block(inode, inode, end, start, nrpages - end, true);
1394b4ace337SChao Yu 	f2fs_unlock_op(sbi);
13956f8d4455SJaegeuk Kim 
1396edc6d01bSJan Kara 	filemap_invalidate_unlock(inode->i_mapping);
1397e4544b63STim Murray 	f2fs_up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
1398b4ace337SChao Yu 	return ret;
1399b4ace337SChao Yu }
1400b4ace337SChao Yu 
f2fs_collapse_range(struct inode * inode,loff_t offset,loff_t len)1401b4ace337SChao Yu static int f2fs_collapse_range(struct inode *inode, loff_t offset, loff_t len)
1402b4ace337SChao Yu {
1403b4ace337SChao Yu 	loff_t new_size;
1404b4ace337SChao Yu 	int ret;
1405b4ace337SChao Yu 
1406b4ace337SChao Yu 	if (offset + len >= i_size_read(inode))
1407b4ace337SChao Yu 		return -EINVAL;
1408b4ace337SChao Yu 
1409b4ace337SChao Yu 	/* collapse range should be aligned to block size of f2fs. */
1410b4ace337SChao Yu 	if (offset & (F2FS_BLKSIZE - 1) || len & (F2FS_BLKSIZE - 1))
1411b4ace337SChao Yu 		return -EINVAL;
1412b4ace337SChao Yu 
141397a7b2c2SJaegeuk Kim 	ret = f2fs_convert_inline_inode(inode);
141497a7b2c2SJaegeuk Kim 	if (ret)
141597a7b2c2SJaegeuk Kim 		return ret;
141697a7b2c2SJaegeuk Kim 
1417b4ace337SChao Yu 	/* write out all dirty pages from offset */
1418b4ace337SChao Yu 	ret = filemap_write_and_wait_range(inode->i_mapping, offset, LLONG_MAX);
1419b4ace337SChao Yu 	if (ret)
14206f8d4455SJaegeuk Kim 		return ret;
1421bb06664aSChao Yu 
14226f8d4455SJaegeuk Kim 	ret = f2fs_do_collapse(inode, offset, len);
1423b4ace337SChao Yu 	if (ret)
14246f8d4455SJaegeuk Kim 		return ret;
1425b4ace337SChao Yu 
14266e2c64adSJaegeuk Kim 	/* write out all moved pages, if possible */
1427edc6d01bSJan Kara 	filemap_invalidate_lock(inode->i_mapping);
14286e2c64adSJaegeuk Kim 	filemap_write_and_wait_range(inode->i_mapping, offset, LLONG_MAX);
14296e2c64adSJaegeuk Kim 	truncate_pagecache(inode, offset);
14306e2c64adSJaegeuk Kim 
1431b4ace337SChao Yu 	new_size = i_size_read(inode) - len;
1432c42d28ceSChao Yu 	ret = f2fs_truncate_blocks(inode, new_size, true);
1433edc6d01bSJan Kara 	filemap_invalidate_unlock(inode->i_mapping);
1434b4ace337SChao Yu 	if (!ret)
1435fc9581c8SJaegeuk Kim 		f2fs_i_size_write(inode, new_size);
1436b4ace337SChao Yu 	return ret;
1437b4ace337SChao Yu }
1438b4ace337SChao Yu 
f2fs_do_zero_range(struct dnode_of_data * dn,pgoff_t start,pgoff_t end)14396e961949SChao Yu static int f2fs_do_zero_range(struct dnode_of_data *dn, pgoff_t start,
14406e961949SChao Yu 								pgoff_t end)
14416e961949SChao Yu {
14426e961949SChao Yu 	struct f2fs_sb_info *sbi = F2FS_I_SB(dn->inode);
14436e961949SChao Yu 	pgoff_t index = start;
14446e961949SChao Yu 	unsigned int ofs_in_node = dn->ofs_in_node;
14456e961949SChao Yu 	blkcnt_t count = 0;
14466e961949SChao Yu 	int ret;
14476e961949SChao Yu 
14486e961949SChao Yu 	for (; index < end; index++, dn->ofs_in_node++) {
1449a2ced1ceSChao Yu 		if (f2fs_data_blkaddr(dn) == NULL_ADDR)
14506e961949SChao Yu 			count++;
14516e961949SChao Yu 	}
14526e961949SChao Yu 
14536e961949SChao Yu 	dn->ofs_in_node = ofs_in_node;
14544d57b86dSChao Yu 	ret = f2fs_reserve_new_blocks(dn, count);
14556e961949SChao Yu 	if (ret)
14566e961949SChao Yu 		return ret;
14576e961949SChao Yu 
14586e961949SChao Yu 	dn->ofs_in_node = ofs_in_node;
14596e961949SChao Yu 	for (index = start; index < end; index++, dn->ofs_in_node++) {
1460a2ced1ceSChao Yu 		dn->data_blkaddr = f2fs_data_blkaddr(dn);
14616e961949SChao Yu 		/*
14624d57b86dSChao Yu 		 * f2fs_reserve_new_blocks will not guarantee entire block
14636e961949SChao Yu 		 * allocation.
14646e961949SChao Yu 		 */
14656e961949SChao Yu 		if (dn->data_blkaddr == NULL_ADDR) {
14666e961949SChao Yu 			ret = -ENOSPC;
14676e961949SChao Yu 			break;
14686e961949SChao Yu 		}
146925f82362SChao Yu 
147025f82362SChao Yu 		if (dn->data_blkaddr == NEW_ADDR)
147125f82362SChao Yu 			continue;
147225f82362SChao Yu 
147325f82362SChao Yu 		if (!f2fs_is_valid_blkaddr(sbi, dn->data_blkaddr,
147425f82362SChao Yu 					DATA_GENERIC_ENHANCE)) {
147525f82362SChao Yu 			ret = -EFSCORRUPTED;
147695fa90c9SChao Yu 			f2fs_handle_error(sbi, ERROR_INVALID_BLKADDR);
147725f82362SChao Yu 			break;
147825f82362SChao Yu 		}
147925f82362SChao Yu 
14804d57b86dSChao Yu 		f2fs_invalidate_blocks(sbi, dn->data_blkaddr);
1481eb6d30bcSChao Yu 		f2fs_set_data_blkaddr(dn, NEW_ADDR);
14826e961949SChao Yu 	}
14836e961949SChao Yu 
1484e7547dacSJaegeuk Kim 	f2fs_update_read_extent_cache_range(dn, start, 0, index - start);
1485a84153f9SChao Yu 	f2fs_update_age_extent_cache_range(dn, start, index - start);
14866e961949SChao Yu 
14876e961949SChao Yu 	return ret;
14886e961949SChao Yu }
14896e961949SChao Yu 
f2fs_zero_range(struct inode * inode,loff_t offset,loff_t len,int mode)149075cd4e09SChao Yu static int f2fs_zero_range(struct inode *inode, loff_t offset, loff_t len,
149175cd4e09SChao Yu 								int mode)
149275cd4e09SChao Yu {
149375cd4e09SChao Yu 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
149475cd4e09SChao Yu 	struct address_space *mapping = inode->i_mapping;
149575cd4e09SChao Yu 	pgoff_t index, pg_start, pg_end;
149675cd4e09SChao Yu 	loff_t new_size = i_size_read(inode);
149775cd4e09SChao Yu 	loff_t off_start, off_end;
149875cd4e09SChao Yu 	int ret = 0;
149975cd4e09SChao Yu 
150075cd4e09SChao Yu 	ret = inode_newsize_ok(inode, (len + offset));
150175cd4e09SChao Yu 	if (ret)
150275cd4e09SChao Yu 		return ret;
150375cd4e09SChao Yu 
150475cd4e09SChao Yu 	ret = f2fs_convert_inline_inode(inode);
150575cd4e09SChao Yu 	if (ret)
150675cd4e09SChao Yu 		return ret;
150775cd4e09SChao Yu 
150875cd4e09SChao Yu 	ret = filemap_write_and_wait_range(mapping, offset, offset + len - 1);
150975cd4e09SChao Yu 	if (ret)
15106f8d4455SJaegeuk Kim 		return ret;
151175cd4e09SChao Yu 
151209cbfeafSKirill A. Shutemov 	pg_start = ((unsigned long long) offset) >> PAGE_SHIFT;
151309cbfeafSKirill A. Shutemov 	pg_end = ((unsigned long long) offset + len) >> PAGE_SHIFT;
151475cd4e09SChao Yu 
151509cbfeafSKirill A. Shutemov 	off_start = offset & (PAGE_SIZE - 1);
151609cbfeafSKirill A. Shutemov 	off_end = (offset + len) & (PAGE_SIZE - 1);
151775cd4e09SChao Yu 
151875cd4e09SChao Yu 	if (pg_start == pg_end) {
15196394328aSChao Yu 		ret = fill_zero(inode, pg_start, off_start,
15206394328aSChao Yu 						off_end - off_start);
15216394328aSChao Yu 		if (ret)
15226f8d4455SJaegeuk Kim 			return ret;
15236394328aSChao Yu 
152475cd4e09SChao Yu 		new_size = max_t(loff_t, new_size, offset + len);
152575cd4e09SChao Yu 	} else {
152675cd4e09SChao Yu 		if (off_start) {
15276394328aSChao Yu 			ret = fill_zero(inode, pg_start++, off_start,
152809cbfeafSKirill A. Shutemov 						PAGE_SIZE - off_start);
15296394328aSChao Yu 			if (ret)
15306f8d4455SJaegeuk Kim 				return ret;
15316394328aSChao Yu 
153275cd4e09SChao Yu 			new_size = max_t(loff_t, new_size,
153309cbfeafSKirill A. Shutemov 					(loff_t)pg_start << PAGE_SHIFT);
153475cd4e09SChao Yu 		}
153575cd4e09SChao Yu 
15366e961949SChao Yu 		for (index = pg_start; index < pg_end;) {
153775cd4e09SChao Yu 			struct dnode_of_data dn;
15386e961949SChao Yu 			unsigned int end_offset;
15396e961949SChao Yu 			pgoff_t end;
154075cd4e09SChao Yu 
1541e4544b63STim Murray 			f2fs_down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
1542edc6d01bSJan Kara 			filemap_invalidate_lock(mapping);
1543c7079853SChao Yu 
1544c7079853SChao Yu 			truncate_pagecache_range(inode,
1545c7079853SChao Yu 				(loff_t)index << PAGE_SHIFT,
1546c7079853SChao Yu 				((loff_t)pg_end << PAGE_SHIFT) - 1);
1547c7079853SChao Yu 
154875cd4e09SChao Yu 			f2fs_lock_op(sbi);
154975cd4e09SChao Yu 
15506e961949SChao Yu 			set_new_dnode(&dn, inode, NULL, NULL, 0);
15514d57b86dSChao Yu 			ret = f2fs_get_dnode_of_data(&dn, index, ALLOC_NODE);
155275cd4e09SChao Yu 			if (ret) {
155375cd4e09SChao Yu 				f2fs_unlock_op(sbi);
1554edc6d01bSJan Kara 				filemap_invalidate_unlock(mapping);
1555e4544b63STim Murray 				f2fs_up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
155675cd4e09SChao Yu 				goto out;
155775cd4e09SChao Yu 			}
155875cd4e09SChao Yu 
15596e961949SChao Yu 			end_offset = ADDRS_PER_PAGE(dn.node_page, inode);
15606e961949SChao Yu 			end = min(pg_end, end_offset - dn.ofs_in_node + index);
15616e961949SChao Yu 
15626e961949SChao Yu 			ret = f2fs_do_zero_range(&dn, index, end);
156375cd4e09SChao Yu 			f2fs_put_dnode(&dn);
1564c7079853SChao Yu 
156575cd4e09SChao Yu 			f2fs_unlock_op(sbi);
1566edc6d01bSJan Kara 			filemap_invalidate_unlock(mapping);
1567e4544b63STim Murray 			f2fs_up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
15689434fcdeSChao Yu 
15699434fcdeSChao Yu 			f2fs_balance_fs(sbi, dn.node_changed);
15709434fcdeSChao Yu 
15716e961949SChao Yu 			if (ret)
15726e961949SChao Yu 				goto out;
157375cd4e09SChao Yu 
15746e961949SChao Yu 			index = end;
157575cd4e09SChao Yu 			new_size = max_t(loff_t, new_size,
15766e961949SChao Yu 					(loff_t)index << PAGE_SHIFT);
157775cd4e09SChao Yu 		}
157875cd4e09SChao Yu 
157975cd4e09SChao Yu 		if (off_end) {
15806394328aSChao Yu 			ret = fill_zero(inode, pg_end, 0, off_end);
15816394328aSChao Yu 			if (ret)
15826394328aSChao Yu 				goto out;
15836394328aSChao Yu 
158475cd4e09SChao Yu 			new_size = max_t(loff_t, new_size, offset + len);
158575cd4e09SChao Yu 		}
158675cd4e09SChao Yu 	}
158775cd4e09SChao Yu 
158875cd4e09SChao Yu out:
158917cd07aeSChao Yu 	if (new_size > i_size_read(inode)) {
159017cd07aeSChao Yu 		if (mode & FALLOC_FL_KEEP_SIZE)
159117cd07aeSChao Yu 			file_set_keep_isize(inode);
159217cd07aeSChao Yu 		else
1593fc9581c8SJaegeuk Kim 			f2fs_i_size_write(inode, new_size);
159417cd07aeSChao Yu 	}
159575cd4e09SChao Yu 	return ret;
159675cd4e09SChao Yu }
159775cd4e09SChao Yu 
f2fs_insert_range(struct inode * inode,loff_t offset,loff_t len)1598f62185d0SChao Yu static int f2fs_insert_range(struct inode *inode, loff_t offset, loff_t len)
1599f62185d0SChao Yu {
1600f62185d0SChao Yu 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
1601edc6d01bSJan Kara 	struct address_space *mapping = inode->i_mapping;
16020a2aa8fbSJaegeuk Kim 	pgoff_t nr, pg_start, pg_end, delta, idx;
1603f62185d0SChao Yu 	loff_t new_size;
16046e2c64adSJaegeuk Kim 	int ret = 0;
1605f62185d0SChao Yu 
1606f62185d0SChao Yu 	new_size = i_size_read(inode) + len;
160746e82fb1SKinglong Mee 	ret = inode_newsize_ok(inode, new_size);
160846e82fb1SKinglong Mee 	if (ret)
160946e82fb1SKinglong Mee 		return ret;
1610f62185d0SChao Yu 
1611f62185d0SChao Yu 	if (offset >= i_size_read(inode))
1612f62185d0SChao Yu 		return -EINVAL;
1613f62185d0SChao Yu 
1614f62185d0SChao Yu 	/* insert range should be aligned to block size of f2fs. */
1615f62185d0SChao Yu 	if (offset & (F2FS_BLKSIZE - 1) || len & (F2FS_BLKSIZE - 1))
1616f62185d0SChao Yu 		return -EINVAL;
1617f62185d0SChao Yu 
161897a7b2c2SJaegeuk Kim 	ret = f2fs_convert_inline_inode(inode);
161997a7b2c2SJaegeuk Kim 	if (ret)
162097a7b2c2SJaegeuk Kim 		return ret;
162197a7b2c2SJaegeuk Kim 
16222c4db1a6SJaegeuk Kim 	f2fs_balance_fs(sbi, true);
16232a340760SJaegeuk Kim 
1624edc6d01bSJan Kara 	filemap_invalidate_lock(mapping);
1625c42d28ceSChao Yu 	ret = f2fs_truncate_blocks(inode, i_size_read(inode), true);
1626edc6d01bSJan Kara 	filemap_invalidate_unlock(mapping);
1627f62185d0SChao Yu 	if (ret)
16286f8d4455SJaegeuk Kim 		return ret;
1629f62185d0SChao Yu 
1630f62185d0SChao Yu 	/* write out all dirty pages from offset */
1631edc6d01bSJan Kara 	ret = filemap_write_and_wait_range(mapping, offset, LLONG_MAX);
1632f62185d0SChao Yu 	if (ret)
16336f8d4455SJaegeuk Kim 		return ret;
1634f62185d0SChao Yu 
163509cbfeafSKirill A. Shutemov 	pg_start = offset >> PAGE_SHIFT;
163609cbfeafSKirill A. Shutemov 	pg_end = (offset + len) >> PAGE_SHIFT;
1637f62185d0SChao Yu 	delta = pg_end - pg_start;
1638f91108b8SGeert Uytterhoeven 	idx = DIV_ROUND_UP(i_size_read(inode), PAGE_SIZE);
1639f62185d0SChao Yu 
16406f8d4455SJaegeuk Kim 	/* avoid gc operation during block exchange */
1641e4544b63STim Murray 	f2fs_down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
1642edc6d01bSJan Kara 	filemap_invalidate_lock(mapping);
16436f8d4455SJaegeuk Kim 	truncate_pagecache(inode, offset);
16446f8d4455SJaegeuk Kim 
16450a2aa8fbSJaegeuk Kim 	while (!ret && idx > pg_start) {
16460a2aa8fbSJaegeuk Kim 		nr = idx - pg_start;
16470a2aa8fbSJaegeuk Kim 		if (nr > delta)
16480a2aa8fbSJaegeuk Kim 			nr = delta;
16490a2aa8fbSJaegeuk Kim 		idx -= nr;
16500a2aa8fbSJaegeuk Kim 
1651f62185d0SChao Yu 		f2fs_lock_op(sbi);
16525f281fabSJaegeuk Kim 		f2fs_drop_extent_tree(inode);
16535f281fabSJaegeuk Kim 
16540a2aa8fbSJaegeuk Kim 		ret = __exchange_data_block(inode, inode, idx,
16550a2aa8fbSJaegeuk Kim 					idx + delta, nr, false);
16566e2c64adSJaegeuk Kim 		f2fs_unlock_op(sbi);
1657f62185d0SChao Yu 	}
1658edc6d01bSJan Kara 	filemap_invalidate_unlock(mapping);
1659e4544b63STim Murray 	f2fs_up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
1660f62185d0SChao Yu 
16616e2c64adSJaegeuk Kim 	/* write out all moved pages, if possible */
1662edc6d01bSJan Kara 	filemap_invalidate_lock(mapping);
1663edc6d01bSJan Kara 	filemap_write_and_wait_range(mapping, offset, LLONG_MAX);
16646e2c64adSJaegeuk Kim 	truncate_pagecache(inode, offset);
1665edc6d01bSJan Kara 	filemap_invalidate_unlock(mapping);
16666e2c64adSJaegeuk Kim 
16676e2c64adSJaegeuk Kim 	if (!ret)
1668fc9581c8SJaegeuk Kim 		f2fs_i_size_write(inode, new_size);
1669f62185d0SChao Yu 	return ret;
1670f62185d0SChao Yu }
1671f62185d0SChao Yu 
f2fs_expand_inode_data(struct inode * inode,loff_t offset,loff_t len,int mode)16721cd75654SYangtao Li static int f2fs_expand_inode_data(struct inode *inode, loff_t offset,
1673fbfa2cc5SJaegeuk Kim 					loff_t len, int mode)
1674fbfa2cc5SJaegeuk Kim {
16754081363fSJaegeuk Kim 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
1676d5097be5SHyunchul Lee 	struct f2fs_map_blocks map = { .m_next_pgofs = NULL,
1677f9d6d059SChao Yu 			.m_next_extent = NULL, .m_seg_type = NO_CHECK_TYPE,
1678f9d6d059SChao Yu 			.m_may_create = true };
1679d147ea4aSJaegeuk Kim 	struct f2fs_gc_control gc_control = { .victim_segno = NULL_SEGNO,
1680d147ea4aSJaegeuk Kim 			.init_gc_type = FG_GC,
1681d147ea4aSJaegeuk Kim 			.should_migrate_blocks = false,
1682c81d5baeSJaegeuk Kim 			.err_gc_skipped = true,
1683c81d5baeSJaegeuk Kim 			.nr_free_secs = 0 };
168488f2cfc5SChao Yu 	pgoff_t pg_start, pg_end;
168539bee2e6SSergey Shtylyov 	loff_t new_size;
1686e12dd7bdSJaegeuk Kim 	loff_t off_end;
168788f2cfc5SChao Yu 	block_t expanded = 0;
1688a7de6086SJaegeuk Kim 	int err;
1689fbfa2cc5SJaegeuk Kim 
1690a7de6086SJaegeuk Kim 	err = inode_newsize_ok(inode, (len + offset));
1691a7de6086SJaegeuk Kim 	if (err)
1692a7de6086SJaegeuk Kim 		return err;
16939ffe0fb5SHuajun Li 
1694a7de6086SJaegeuk Kim 	err = f2fs_convert_inline_inode(inode);
1695a7de6086SJaegeuk Kim 	if (err)
1696a7de6086SJaegeuk Kim 		return err;
1697fbfa2cc5SJaegeuk Kim 
16982c4db1a6SJaegeuk Kim 	f2fs_balance_fs(sbi, true);
16992a340760SJaegeuk Kim 
170088f2cfc5SChao Yu 	pg_start = ((unsigned long long)offset) >> PAGE_SHIFT;
170109cbfeafSKirill A. Shutemov 	pg_end = ((unsigned long long)offset + len) >> PAGE_SHIFT;
170209cbfeafSKirill A. Shutemov 	off_end = (offset + len) & (PAGE_SIZE - 1);
1703fbfa2cc5SJaegeuk Kim 
170488f2cfc5SChao Yu 	map.m_lblk = pg_start;
170588f2cfc5SChao Yu 	map.m_len = pg_end - pg_start;
1706e12dd7bdSJaegeuk Kim 	if (off_end)
1707e12dd7bdSJaegeuk Kim 		map.m_len++;
1708ead43275SJaegeuk Kim 
1709f5a53edcSJaegeuk Kim 	if (!map.m_len)
1710f5a53edcSJaegeuk Kim 		return 0;
1711cad3836fSJaegeuk Kim 
1712f5a53edcSJaegeuk Kim 	if (f2fs_is_pinned_file(inode)) {
1713074b5ea2SJaegeuk Kim 		block_t sec_blks = CAP_BLKS_PER_SEC(sbi);
1714e1175f02SChao Yu 		block_t sec_len = roundup(map.m_len, sec_blks);
1715f5a53edcSJaegeuk Kim 
1716e1175f02SChao Yu 		map.m_len = sec_blks;
1717f5a53edcSJaegeuk Kim next_alloc:
1718f5a53edcSJaegeuk Kim 		if (has_not_enough_free_secs(sbi, 0,
1719f5a53edcSJaegeuk Kim 			GET_SEC_FROM_SEG(sbi, overprovision_segments(sbi)))) {
1720e4544b63STim Murray 			f2fs_down_write(&sbi->gc_lock);
17219bf1dcbdSChao Yu 			stat_inc_gc_call_count(sbi, FOREGROUND);
1722d147ea4aSJaegeuk Kim 			err = f2fs_gc(sbi, &gc_control);
17232e42b7f8SJaegeuk Kim 			if (err && err != -ENODATA)
1724f5a53edcSJaegeuk Kim 				goto out_err;
1725f5a53edcSJaegeuk Kim 		}
1726f5a53edcSJaegeuk Kim 
1727e4544b63STim Murray 		f2fs_down_write(&sbi->pin_sem);
1728fd612648SDaeho Jeong 
1729fd612648SDaeho Jeong 		f2fs_lock_op(sbi);
1730509f1010SChao Yu 		f2fs_allocate_new_section(sbi, CURSEG_COLD_DATA_PINNED, false);
1731fd612648SDaeho Jeong 		f2fs_unlock_op(sbi);
1732fd612648SDaeho Jeong 
1733d0b9e42aSChao Yu 		map.m_seg_type = CURSEG_COLD_DATA_PINNED;
1734cd8fc522SChristoph Hellwig 		err = f2fs_map_blocks(inode, &map, F2FS_GET_BLOCK_PRE_DIO);
1735d4dd19ecSJaegeuk Kim 		file_dont_truncate(inode);
1736d0b9e42aSChao Yu 
1737e4544b63STim Murray 		f2fs_up_write(&sbi->pin_sem);
1738f5a53edcSJaegeuk Kim 
173988f2cfc5SChao Yu 		expanded += map.m_len;
1740e1175f02SChao Yu 		sec_len -= map.m_len;
1741f5a53edcSJaegeuk Kim 		map.m_lblk += map.m_len;
1742e1175f02SChao Yu 		if (!err && sec_len)
1743f5a53edcSJaegeuk Kim 			goto next_alloc;
1744f5a53edcSJaegeuk Kim 
174588f2cfc5SChao Yu 		map.m_len = expanded;
1746f5a53edcSJaegeuk Kim 	} else {
1747cd8fc522SChristoph Hellwig 		err = f2fs_map_blocks(inode, &map, F2FS_GET_BLOCK_PRE_AIO);
174888f2cfc5SChao Yu 		expanded = map.m_len;
1749f5a53edcSJaegeuk Kim 	}
1750f5a53edcSJaegeuk Kim out_err:
1751a7de6086SJaegeuk Kim 	if (err) {
1752e12dd7bdSJaegeuk Kim 		pgoff_t last_off;
1753fbfa2cc5SJaegeuk Kim 
175488f2cfc5SChao Yu 		if (!expanded)
1755a7de6086SJaegeuk Kim 			return err;
175698397ff3SJaegeuk Kim 
175788f2cfc5SChao Yu 		last_off = pg_start + expanded - 1;
1758e12dd7bdSJaegeuk Kim 
1759e12dd7bdSJaegeuk Kim 		/* update new size to the failed position */
1760e12dd7bdSJaegeuk Kim 		new_size = (last_off == pg_end) ? offset + len :
1761e12dd7bdSJaegeuk Kim 					(loff_t)(last_off + 1) << PAGE_SHIFT;
1762e12dd7bdSJaegeuk Kim 	} else {
1763e12dd7bdSJaegeuk Kim 		new_size = ((loff_t)pg_end << PAGE_SHIFT) + off_end;
1764fbfa2cc5SJaegeuk Kim 	}
1765fbfa2cc5SJaegeuk Kim 
1766e8ed90a6SChao Yu 	if (new_size > i_size_read(inode)) {
1767e8ed90a6SChao Yu 		if (mode & FALLOC_FL_KEEP_SIZE)
1768e8ed90a6SChao Yu 			file_set_keep_isize(inode);
1769e8ed90a6SChao Yu 		else
1770fc9581c8SJaegeuk Kim 			f2fs_i_size_write(inode, new_size);
1771e8ed90a6SChao Yu 	}
1772fbfa2cc5SJaegeuk Kim 
1773a7de6086SJaegeuk Kim 	return err;
1774fbfa2cc5SJaegeuk Kim }
1775fbfa2cc5SJaegeuk Kim 
f2fs_fallocate(struct file * file,int mode,loff_t offset,loff_t len)1776fbfa2cc5SJaegeuk Kim static long f2fs_fallocate(struct file *file, int mode,
1777fbfa2cc5SJaegeuk Kim 				loff_t offset, loff_t len)
1778fbfa2cc5SJaegeuk Kim {
17796131ffaaSAl Viro 	struct inode *inode = file_inode(file);
1780587c0a42STaehee Yoo 	long ret = 0;
1781fbfa2cc5SJaegeuk Kim 
17821f227a3eSJaegeuk Kim 	if (unlikely(f2fs_cp_error(F2FS_I_SB(inode))))
17831f227a3eSJaegeuk Kim 		return -EIO;
178400e09c0bSChao Yu 	if (!f2fs_is_checkpoint_ready(F2FS_I_SB(inode)))
178500e09c0bSChao Yu 		return -ENOSPC;
17864c8ff709SChao Yu 	if (!f2fs_is_compress_backend_ready(inode))
17874c8ff709SChao Yu 		return -EOPNOTSUPP;
17881f227a3eSJaegeuk Kim 
1789c998012bSChao Yu 	/* f2fs only support ->fallocate for regular file */
1790c998012bSChao Yu 	if (!S_ISREG(inode->i_mode))
1791c998012bSChao Yu 		return -EINVAL;
1792c998012bSChao Yu 
179362230e0dSChandan Rajendra 	if (IS_ENCRYPTED(inode) &&
1794f62185d0SChao Yu 		(mode & (FALLOC_FL_COLLAPSE_RANGE | FALLOC_FL_INSERT_RANGE)))
1795fcc85a4dSJaegeuk Kim 		return -EOPNOTSUPP;
1796fcc85a4dSJaegeuk Kim 
17975fed0be8SJaegeuk Kim 	/*
1798146949deSJinyoung CHOI 	 * Pinned file should not support partial truncation since the block
17995fed0be8SJaegeuk Kim 	 * can be used by applications.
18005fed0be8SJaegeuk Kim 	 */
18015fed0be8SJaegeuk Kim 	if ((f2fs_compressed_file(inode) || f2fs_is_pinned_file(inode)) &&
18024c8ff709SChao Yu 		(mode & (FALLOC_FL_PUNCH_HOLE | FALLOC_FL_COLLAPSE_RANGE |
18034c8ff709SChao Yu 			FALLOC_FL_ZERO_RANGE | FALLOC_FL_INSERT_RANGE)))
18044c8ff709SChao Yu 		return -EOPNOTSUPP;
18054c8ff709SChao Yu 
1806b4ace337SChao Yu 	if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE |
1807f62185d0SChao Yu 			FALLOC_FL_COLLAPSE_RANGE | FALLOC_FL_ZERO_RANGE |
1808f62185d0SChao Yu 			FALLOC_FL_INSERT_RANGE))
1809fbfa2cc5SJaegeuk Kim 		return -EOPNOTSUPP;
1810fbfa2cc5SJaegeuk Kim 
18115955102cSAl Viro 	inode_lock(inode);
18123375f696SChao Yu 
1813958ed929SChao Yu 	ret = file_modified(file);
1814958ed929SChao Yu 	if (ret)
1815958ed929SChao Yu 		goto out;
1816958ed929SChao Yu 
1817587c0a42STaehee Yoo 	if (mode & FALLOC_FL_PUNCH_HOLE) {
1818587c0a42STaehee Yoo 		if (offset >= inode->i_size)
1819587c0a42STaehee Yoo 			goto out;
1820587c0a42STaehee Yoo 
18211cd75654SYangtao Li 		ret = f2fs_punch_hole(inode, offset, len);
1822b4ace337SChao Yu 	} else if (mode & FALLOC_FL_COLLAPSE_RANGE) {
1823b4ace337SChao Yu 		ret = f2fs_collapse_range(inode, offset, len);
182475cd4e09SChao Yu 	} else if (mode & FALLOC_FL_ZERO_RANGE) {
182575cd4e09SChao Yu 		ret = f2fs_zero_range(inode, offset, len, mode);
1826f62185d0SChao Yu 	} else if (mode & FALLOC_FL_INSERT_RANGE) {
1827f62185d0SChao Yu 		ret = f2fs_insert_range(inode, offset, len);
1828b4ace337SChao Yu 	} else {
18291cd75654SYangtao Li 		ret = f2fs_expand_inode_data(inode, offset, len, mode);
1830b4ace337SChao Yu 	}
1831fbfa2cc5SJaegeuk Kim 
18323af60a49SNamjae Jeon 	if (!ret) {
1833c62ebd35SJeff Layton 		inode->i_mtime = inode_set_ctime_current(inode);
18347c45729aSJaegeuk Kim 		f2fs_mark_inode_dirty_sync(inode, false);
1835d0239e1bSJaegeuk Kim 		f2fs_update_time(F2FS_I_SB(inode), REQ_TIME);
18363af60a49SNamjae Jeon 	}
18373375f696SChao Yu 
1838587c0a42STaehee Yoo out:
18395955102cSAl Viro 	inode_unlock(inode);
18403375f696SChao Yu 
1841c01e2853SNamjae Jeon 	trace_f2fs_fallocate(inode, mode, offset, len, ret);
1842fbfa2cc5SJaegeuk Kim 	return ret;
1843fbfa2cc5SJaegeuk Kim }
1844fbfa2cc5SJaegeuk Kim 
f2fs_release_file(struct inode * inode,struct file * filp)18451e84371fSJaegeuk Kim static int f2fs_release_file(struct inode *inode, struct file *filp)
18461e84371fSJaegeuk Kim {
1847de5307e4SJaegeuk Kim 	/*
1848146949deSJinyoung CHOI 	 * f2fs_release_file is called at every close calls. So we should
1849de5307e4SJaegeuk Kim 	 * not drop any inmemory pages by close called by other process.
1850de5307e4SJaegeuk Kim 	 */
1851de5307e4SJaegeuk Kim 	if (!(filp->f_mode & FMODE_WRITE) ||
1852de5307e4SJaegeuk Kim 			atomic_read(&inode->i_writecount) != 1)
1853de5307e4SJaegeuk Kim 		return 0;
1854de5307e4SJaegeuk Kim 
1855a46bebd5SDaeho Jeong 	inode_lock(inode);
18563db1de0eSDaeho Jeong 	f2fs_abort_atomic_write(inode, true);
1857a46bebd5SDaeho Jeong 	inode_unlock(inode);
1858a46bebd5SDaeho Jeong 
18591e84371fSJaegeuk Kim 	return 0;
18601e84371fSJaegeuk Kim }
18611e84371fSJaegeuk Kim 
f2fs_file_flush(struct file * file,fl_owner_t id)18627a10f017SJaegeuk Kim static int f2fs_file_flush(struct file *file, fl_owner_t id)
1863fbfa2cc5SJaegeuk Kim {
18647a10f017SJaegeuk Kim 	struct inode *inode = file_inode(file);
18657a10f017SJaegeuk Kim 
18667a10f017SJaegeuk Kim 	/*
18677a10f017SJaegeuk Kim 	 * If the process doing a transaction is crashed, we should do
18687a10f017SJaegeuk Kim 	 * roll-back. Otherwise, other reader/write can see corrupted database
18697a10f017SJaegeuk Kim 	 * until all the writers close its file. Since this should be done
18707a10f017SJaegeuk Kim 	 * before dropping file lock, it needs to do in ->flush.
18717a10f017SJaegeuk Kim 	 */
1872ae267fc1SChao Yu 	if (F2FS_I(inode)->atomic_write_task == current &&
1873a46bebd5SDaeho Jeong 				(current->flags & PF_EXITING)) {
1874a46bebd5SDaeho Jeong 		inode_lock(inode);
18753db1de0eSDaeho Jeong 		f2fs_abort_atomic_write(inode, true);
1876a46bebd5SDaeho Jeong 		inode_unlock(inode);
1877a46bebd5SDaeho Jeong 	}
1878a46bebd5SDaeho Jeong 
18797a10f017SJaegeuk Kim 	return 0;
1880fbfa2cc5SJaegeuk Kim }
1881fbfa2cc5SJaegeuk Kim 
f2fs_setflags_common(struct inode * inode,u32 iflags,u32 mask)188236098557SEric Biggers static int f2fs_setflags_common(struct inode *inode, u32 iflags, u32 mask)
18832c1d0305SChao Yu {
18842c1d0305SChao Yu 	struct f2fs_inode_info *fi = F2FS_I(inode);
188599eabb91SJaegeuk Kim 	u32 masked_flags = fi->i_flags & mask;
188699eabb91SJaegeuk Kim 
1887a7531039SJaegeuk Kim 	/* mask can be shrunk by flags_valid selector */
1888a7531039SJaegeuk Kim 	iflags &= mask;
18892c1d0305SChao Yu 
18902c1d0305SChao Yu 	/* Is it quota file? Do not allow user to mess with it */
18912c1d0305SChao Yu 	if (IS_NOQUOTA(inode))
18922c1d0305SChao Yu 		return -EPERM;
18932c1d0305SChao Yu 
189499eabb91SJaegeuk Kim 	if ((iflags ^ masked_flags) & F2FS_CASEFOLD_FL) {
18952c2eb7a3SDaniel Rosenberg 		if (!f2fs_sb_has_casefold(F2FS_I_SB(inode)))
18962c2eb7a3SDaniel Rosenberg 			return -EOPNOTSUPP;
18972c2eb7a3SDaniel Rosenberg 		if (!f2fs_empty_dir(inode))
18982c2eb7a3SDaniel Rosenberg 			return -ENOTEMPTY;
18992c2eb7a3SDaniel Rosenberg 	}
19002c2eb7a3SDaniel Rosenberg 
19014c8ff709SChao Yu 	if (iflags & (F2FS_COMPR_FL | F2FS_NOCOMP_FL)) {
19024c8ff709SChao Yu 		if (!f2fs_sb_has_compression(F2FS_I_SB(inode)))
19034c8ff709SChao Yu 			return -EOPNOTSUPP;
19044c8ff709SChao Yu 		if ((iflags & F2FS_COMPR_FL) && (iflags & F2FS_NOCOMP_FL))
19054c8ff709SChao Yu 			return -EINVAL;
19064c8ff709SChao Yu 	}
19074c8ff709SChao Yu 
190899eabb91SJaegeuk Kim 	if ((iflags ^ masked_flags) & F2FS_COMPR_FL) {
1909aa576970SChao Yu 		if (masked_flags & F2FS_COMPR_FL) {
191078134d03SDaeho Jeong 			if (!f2fs_disable_compressed_file(inode))
19114c8ff709SChao Yu 				return -EINVAL;
19128ee236dcSChao Liu 		} else {
1913a995627eSJaegeuk Kim 			/* try to convert inline_data to support compression */
1914a995627eSJaegeuk Kim 			int err = f2fs_convert_inline_inode(inode);
1915a995627eSJaegeuk Kim 			if (err)
1916a995627eSJaegeuk Kim 				return err;
1917b5ab3276SChao Yu 
1918b5ab3276SChao Yu 			f2fs_down_write(&F2FS_I(inode)->i_sem);
1919b5ab3276SChao Yu 			if (!f2fs_may_compress(inode) ||
1920b5ab3276SChao Yu 					(S_ISREG(inode->i_mode) &&
1921b5ab3276SChao Yu 					F2FS_HAS_BLOCKS(inode))) {
1922b5ab3276SChao Yu 				f2fs_up_write(&F2FS_I(inode)->i_sem);
19234c8ff709SChao Yu 				return -EINVAL;
1924b5ab3276SChao Yu 			}
1925b5ab3276SChao Yu 			err = set_compress_context(inode);
1926b5ab3276SChao Yu 			f2fs_up_write(&F2FS_I(inode)->i_sem);
1927b5ab3276SChao Yu 
1928b5ab3276SChao Yu 			if (err)
1929b5ab3276SChao Yu 				return err;
19304c8ff709SChao Yu 		}
19314c8ff709SChao Yu 	}
19324c8ff709SChao Yu 
1933d5e5efa2SEric Biggers 	fi->i_flags = iflags | (fi->i_flags & ~mask);
19344c8ff709SChao Yu 	f2fs_bug_on(F2FS_I_SB(inode), (fi->i_flags & F2FS_COMPR_FL) &&
19354c8ff709SChao Yu 					(fi->i_flags & F2FS_NOCOMP_FL));
19362c1d0305SChao Yu 
193759c84408SChao Yu 	if (fi->i_flags & F2FS_PROJINHERIT_FL)
19382c1d0305SChao Yu 		set_inode_flag(inode, FI_PROJ_INHERIT);
19392c1d0305SChao Yu 	else
19402c1d0305SChao Yu 		clear_inode_flag(inode, FI_PROJ_INHERIT);
19412c1d0305SChao Yu 
1942c62ebd35SJeff Layton 	inode_set_ctime_current(inode);
19432c1d0305SChao Yu 	f2fs_set_inode_flags(inode);
1944b32e0190SChao Yu 	f2fs_mark_inode_dirty_sync(inode, true);
19452c1d0305SChao Yu 	return 0;
19462c1d0305SChao Yu }
19472c1d0305SChao Yu 
19489b1bb01cSMiklos Szeredi /* FS_IOC_[GS]ETFLAGS and FS_IOC_FS[GS]ETXATTR support */
194936098557SEric Biggers 
195036098557SEric Biggers /*
195136098557SEric Biggers  * To make a new on-disk f2fs i_flag gettable via FS_IOC_GETFLAGS, add an entry
195236098557SEric Biggers  * for it to f2fs_fsflags_map[], and add its FS_*_FL equivalent to
195336098557SEric Biggers  * F2FS_GETTABLE_FS_FL.  To also make it settable via FS_IOC_SETFLAGS, also add
195436098557SEric Biggers  * its FS_*_FL equivalent to F2FS_SETTABLE_FS_FL.
19559b1bb01cSMiklos Szeredi  *
19569b1bb01cSMiklos Szeredi  * Translating flags to fsx_flags value used by FS_IOC_FSGETXATTR and
19579b1bb01cSMiklos Szeredi  * FS_IOC_FSSETXATTR is done by the VFS.
195836098557SEric Biggers  */
195936098557SEric Biggers 
196036098557SEric Biggers static const struct {
196136098557SEric Biggers 	u32 iflag;
196236098557SEric Biggers 	u32 fsflag;
196336098557SEric Biggers } f2fs_fsflags_map[] = {
19644c8ff709SChao Yu 	{ F2FS_COMPR_FL,	FS_COMPR_FL },
196536098557SEric Biggers 	{ F2FS_SYNC_FL,		FS_SYNC_FL },
196636098557SEric Biggers 	{ F2FS_IMMUTABLE_FL,	FS_IMMUTABLE_FL },
196736098557SEric Biggers 	{ F2FS_APPEND_FL,	FS_APPEND_FL },
196836098557SEric Biggers 	{ F2FS_NODUMP_FL,	FS_NODUMP_FL },
196936098557SEric Biggers 	{ F2FS_NOATIME_FL,	FS_NOATIME_FL },
19704c8ff709SChao Yu 	{ F2FS_NOCOMP_FL,	FS_NOCOMP_FL },
197136098557SEric Biggers 	{ F2FS_INDEX_FL,	FS_INDEX_FL },
197236098557SEric Biggers 	{ F2FS_DIRSYNC_FL,	FS_DIRSYNC_FL },
197336098557SEric Biggers 	{ F2FS_PROJINHERIT_FL,	FS_PROJINHERIT_FL },
19742c2eb7a3SDaniel Rosenberg 	{ F2FS_CASEFOLD_FL,	FS_CASEFOLD_FL },
197536098557SEric Biggers };
197636098557SEric Biggers 
197736098557SEric Biggers #define F2FS_GETTABLE_FS_FL (		\
19784c8ff709SChao Yu 		FS_COMPR_FL |		\
197936098557SEric Biggers 		FS_SYNC_FL |		\
198036098557SEric Biggers 		FS_IMMUTABLE_FL |	\
198136098557SEric Biggers 		FS_APPEND_FL |		\
198236098557SEric Biggers 		FS_NODUMP_FL |		\
198336098557SEric Biggers 		FS_NOATIME_FL |		\
19844c8ff709SChao Yu 		FS_NOCOMP_FL |		\
198536098557SEric Biggers 		FS_INDEX_FL |		\
198636098557SEric Biggers 		FS_DIRSYNC_FL |		\
198736098557SEric Biggers 		FS_PROJINHERIT_FL |	\
198836098557SEric Biggers 		FS_ENCRYPT_FL |		\
198936098557SEric Biggers 		FS_INLINE_DATA_FL |	\
199095ae251fSEric Biggers 		FS_NOCOW_FL |		\
1991fbc246a1SLinus Torvalds 		FS_VERITY_FL |		\
19922c2eb7a3SDaniel Rosenberg 		FS_CASEFOLD_FL)
199336098557SEric Biggers 
199436098557SEric Biggers #define F2FS_SETTABLE_FS_FL (		\
19954c8ff709SChao Yu 		FS_COMPR_FL |		\
199636098557SEric Biggers 		FS_SYNC_FL |		\
199736098557SEric Biggers 		FS_IMMUTABLE_FL |	\
199836098557SEric Biggers 		FS_APPEND_FL |		\
199936098557SEric Biggers 		FS_NODUMP_FL |		\
200036098557SEric Biggers 		FS_NOATIME_FL |		\
20014c8ff709SChao Yu 		FS_NOCOMP_FL |		\
200236098557SEric Biggers 		FS_DIRSYNC_FL |		\
20032c2eb7a3SDaniel Rosenberg 		FS_PROJINHERIT_FL |	\
20042c2eb7a3SDaniel Rosenberg 		FS_CASEFOLD_FL)
200536098557SEric Biggers 
200636098557SEric Biggers /* Convert f2fs on-disk i_flags to FS_IOC_{GET,SET}FLAGS flags */
f2fs_iflags_to_fsflags(u32 iflags)200736098557SEric Biggers static inline u32 f2fs_iflags_to_fsflags(u32 iflags)
200836098557SEric Biggers {
200936098557SEric Biggers 	u32 fsflags = 0;
201036098557SEric Biggers 	int i;
201136098557SEric Biggers 
201236098557SEric Biggers 	for (i = 0; i < ARRAY_SIZE(f2fs_fsflags_map); i++)
201336098557SEric Biggers 		if (iflags & f2fs_fsflags_map[i].iflag)
201436098557SEric Biggers 			fsflags |= f2fs_fsflags_map[i].fsflag;
201536098557SEric Biggers 
201636098557SEric Biggers 	return fsflags;
201736098557SEric Biggers }
201836098557SEric Biggers 
201936098557SEric Biggers /* Convert FS_IOC_{GET,SET}FLAGS flags to f2fs on-disk i_flags */
f2fs_fsflags_to_iflags(u32 fsflags)202036098557SEric Biggers static inline u32 f2fs_fsflags_to_iflags(u32 fsflags)
202136098557SEric Biggers {
202236098557SEric Biggers 	u32 iflags = 0;
202336098557SEric Biggers 	int i;
202436098557SEric Biggers 
202536098557SEric Biggers 	for (i = 0; i < ARRAY_SIZE(f2fs_fsflags_map); i++)
202636098557SEric Biggers 		if (fsflags & f2fs_fsflags_map[i].fsflag)
202736098557SEric Biggers 			iflags |= f2fs_fsflags_map[i].iflag;
202836098557SEric Biggers 
202936098557SEric Biggers 	return iflags;
203036098557SEric Biggers }
203136098557SEric Biggers 
f2fs_ioc_getversion(struct file * filp,unsigned long arg)2032d49f3e89SChao Yu static int f2fs_ioc_getversion(struct file *filp, unsigned long arg)
2033d49f3e89SChao Yu {
2034d49f3e89SChao Yu 	struct inode *inode = file_inode(filp);
2035d49f3e89SChao Yu 
2036d49f3e89SChao Yu 	return put_user(inode->i_generation, (int __user *)arg);
2037d49f3e89SChao Yu }
2038d49f3e89SChao Yu 
f2fs_ioc_start_atomic_write(struct file * filp,bool truncate)203941e8f85aSDaeho Jeong static int f2fs_ioc_start_atomic_write(struct file *filp, bool truncate)
204088b88a66SJaegeuk Kim {
204188b88a66SJaegeuk Kim 	struct inode *inode = file_inode(filp);
2042f2d40141SChristian Brauner 	struct mnt_idmap *idmap = file_mnt_idmap(filp);
2043743b620cSJaegeuk Kim 	struct f2fs_inode_info *fi = F2FS_I(inode);
2044743b620cSJaegeuk Kim 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
20453db1de0eSDaeho Jeong 	struct inode *pinode;
20464d8d45dfSDaeho Jeong 	loff_t isize;
2047f4c9c743SChao Yu 	int ret;
204888b88a66SJaegeuk Kim 
204901beba79SChristian Brauner 	if (!inode_owner_or_capable(idmap, inode))
205088b88a66SJaegeuk Kim 		return -EACCES;
205188b88a66SJaegeuk Kim 
2052e811898cSJaegeuk Kim 	if (!S_ISREG(inode->i_mode))
2053e811898cSJaegeuk Kim 		return -EINVAL;
2054e811898cSJaegeuk Kim 
2055038d0698SChao Yu 	if (filp->f_flags & O_DIRECT)
2056038d0698SChao Yu 		return -EINVAL;
2057038d0698SChao Yu 
20587fb17fe4SChao Yu 	ret = mnt_want_write_file(filp);
20597fb17fe4SChao Yu 	if (ret)
20607fb17fe4SChao Yu 		return ret;
20617fb17fe4SChao Yu 
20620fac558bSChao Yu 	inode_lock(inode);
20630fac558bSChao Yu 
20649b56adcfSFengnan Chang 	if (!f2fs_disable_compressed_file(inode)) {
20659b56adcfSFengnan Chang 		ret = -EINVAL;
20669b56adcfSFengnan Chang 		goto out;
20679b56adcfSFengnan Chang 	}
20684c8ff709SChao Yu 
20693db1de0eSDaeho Jeong 	if (f2fs_is_atomic_file(inode))
20707fb17fe4SChao Yu 		goto out;
207188b88a66SJaegeuk Kim 
2072f4c9c743SChao Yu 	ret = f2fs_convert_inline_inode(inode);
2073f4c9c743SChao Yu 	if (ret)
20747fb17fe4SChao Yu 		goto out;
207588b88a66SJaegeuk Kim 
2076054cb289SYufen Yu 	f2fs_down_write(&fi->i_gc_rwsem[WRITE]);
20776f8d4455SJaegeuk Kim 
207831867b23SJaegeuk Kim 	/*
207931867b23SJaegeuk Kim 	 * Should wait end_io to count F2FS_WB_CP_DATA correctly by
208031867b23SJaegeuk Kim 	 * f2fs_is_atomic_file.
208131867b23SJaegeuk Kim 	 */
208231867b23SJaegeuk Kim 	if (get_dirty_pages(inode))
2083054cb289SYufen Yu 		f2fs_warn(sbi, "Unexpected flush for atomic writes: ino=%lu, npages=%u",
2084c27753d6SJaegeuk Kim 			  inode->i_ino, get_dirty_pages(inode));
2085c27753d6SJaegeuk Kim 	ret = filemap_write_and_wait_range(inode->i_mapping, 0, LLONG_MAX);
20866f8d4455SJaegeuk Kim 	if (ret) {
2087054cb289SYufen Yu 		f2fs_up_write(&fi->i_gc_rwsem[WRITE]);
2088684ca7e5SKinglong Mee 		goto out;
20896f8d4455SJaegeuk Kim 	}
209031867b23SJaegeuk Kim 
2091a46bebd5SDaeho Jeong 	/* Check if the inode already has a COW inode */
2092a46bebd5SDaeho Jeong 	if (fi->cow_inode == NULL) {
20933db1de0eSDaeho Jeong 		/* Create a COW inode for atomic write */
20943db1de0eSDaeho Jeong 		pinode = f2fs_iget(inode->i_sb, fi->i_pino);
20953db1de0eSDaeho Jeong 		if (IS_ERR(pinode)) {
2096054cb289SYufen Yu 			f2fs_up_write(&fi->i_gc_rwsem[WRITE]);
20973db1de0eSDaeho Jeong 			ret = PTR_ERR(pinode);
20983db1de0eSDaeho Jeong 			goto out;
20993db1de0eSDaeho Jeong 		}
21003db1de0eSDaeho Jeong 
2101f2d40141SChristian Brauner 		ret = f2fs_get_tmpfile(idmap, pinode, &fi->cow_inode);
21023db1de0eSDaeho Jeong 		iput(pinode);
21033db1de0eSDaeho Jeong 		if (ret) {
2104054cb289SYufen Yu 			f2fs_up_write(&fi->i_gc_rwsem[WRITE]);
21053db1de0eSDaeho Jeong 			goto out;
21063db1de0eSDaeho Jeong 		}
21074d8d45dfSDaeho Jeong 
2108a46bebd5SDaeho Jeong 		set_inode_flag(fi->cow_inode, FI_COW_FILE);
2109a46bebd5SDaeho Jeong 		clear_inode_flag(fi->cow_inode, FI_INLINE_DATA);
2110a46bebd5SDaeho Jeong 	} else {
2111a46bebd5SDaeho Jeong 		/* Reuse the already created COW inode */
2112b851ee6bSChao Yu 		ret = f2fs_do_truncate_blocks(fi->cow_inode, 0, true);
2113b851ee6bSChao Yu 		if (ret) {
2114b851ee6bSChao Yu 			f2fs_up_write(&fi->i_gc_rwsem[WRITE]);
2115b851ee6bSChao Yu 			goto out;
2116b851ee6bSChao Yu 		}
2117a46bebd5SDaeho Jeong 	}
2118a46bebd5SDaeho Jeong 
21194d8d45dfSDaeho Jeong 	f2fs_write_inode(inode, NULL);
21203db1de0eSDaeho Jeong 
2121b4dac120SChao Yu 	stat_inc_atomic_inode(inode);
2122743b620cSJaegeuk Kim 
2123054afda9SYunlei He 	set_inode_flag(inode, FI_ATOMIC_FILE);
212441e8f85aSDaeho Jeong 
212541e8f85aSDaeho Jeong 	isize = i_size_read(inode);
212641e8f85aSDaeho Jeong 	fi->original_i_size = isize;
212741e8f85aSDaeho Jeong 	if (truncate) {
212841e8f85aSDaeho Jeong 		set_inode_flag(inode, FI_ATOMIC_REPLACE);
212941e8f85aSDaeho Jeong 		truncate_inode_pages_final(inode->i_mapping);
213041e8f85aSDaeho Jeong 		f2fs_i_size_write(inode, 0);
213141e8f85aSDaeho Jeong 		isize = 0;
213241e8f85aSDaeho Jeong 	}
213341e8f85aSDaeho Jeong 	f2fs_i_size_write(fi->cow_inode, isize);
213441e8f85aSDaeho Jeong 
2135054cb289SYufen Yu 	f2fs_up_write(&fi->i_gc_rwsem[WRITE]);
2136684ca7e5SKinglong Mee 
2137054cb289SYufen Yu 	f2fs_update_time(sbi, REQ_TIME);
2138054cb289SYufen Yu 	fi->atomic_write_task = current;
213926a28a0cSJaegeuk Kim 	stat_update_max_atomic_write(inode);
2140f8e2f32bSDaeho Jeong 	fi->atomic_write_cnt = 0;
2141684ca7e5SKinglong Mee out:
21420fac558bSChao Yu 	inode_unlock(inode);
21437fb17fe4SChao Yu 	mnt_drop_write_file(filp);
2144c27753d6SJaegeuk Kim 	return ret;
214588b88a66SJaegeuk Kim }
214688b88a66SJaegeuk Kim 
f2fs_ioc_commit_atomic_write(struct file * filp)214788b88a66SJaegeuk Kim static int f2fs_ioc_commit_atomic_write(struct file *filp)
214888b88a66SJaegeuk Kim {
214988b88a66SJaegeuk Kim 	struct inode *inode = file_inode(filp);
215001beba79SChristian Brauner 	struct mnt_idmap *idmap = file_mnt_idmap(filp);
215188b88a66SJaegeuk Kim 	int ret;
215288b88a66SJaegeuk Kim 
215301beba79SChristian Brauner 	if (!inode_owner_or_capable(idmap, inode))
215488b88a66SJaegeuk Kim 		return -EACCES;
215588b88a66SJaegeuk Kim 
215688b88a66SJaegeuk Kim 	ret = mnt_want_write_file(filp);
215788b88a66SJaegeuk Kim 	if (ret)
215888b88a66SJaegeuk Kim 		return ret;
215988b88a66SJaegeuk Kim 
21606f8d4455SJaegeuk Kim 	f2fs_balance_fs(F2FS_I_SB(inode), true);
21610fac558bSChao Yu 
21626f8d4455SJaegeuk Kim 	inode_lock(inode);
21631dc0f899SChao Yu 
21646282adbfSJaegeuk Kim 	if (f2fs_is_atomic_file(inode)) {
21653db1de0eSDaeho Jeong 		ret = f2fs_commit_atomic_write(inode);
2166743b620cSJaegeuk Kim 		if (!ret)
21674d8d45dfSDaeho Jeong 			ret = f2fs_do_sync_file(filp, 0, LLONG_MAX, 0, true);
21684d8d45dfSDaeho Jeong 
21694d8d45dfSDaeho Jeong 		f2fs_abort_atomic_write(inode, ret);
217026a28a0cSJaegeuk Kim 	} else {
2171774e1b78SChao Yu 		ret = f2fs_do_sync_file(filp, 0, LLONG_MAX, 1, false);
217226a28a0cSJaegeuk Kim 	}
21734d8d45dfSDaeho Jeong 
21740fac558bSChao Yu 	inode_unlock(inode);
217588b88a66SJaegeuk Kim 	mnt_drop_write_file(filp);
217688b88a66SJaegeuk Kim 	return ret;
217788b88a66SJaegeuk Kim }
217888b88a66SJaegeuk Kim 
f2fs_ioc_abort_atomic_write(struct file * filp)217923339e57SDaeho Jeong static int f2fs_ioc_abort_atomic_write(struct file *filp)
218023339e57SDaeho Jeong {
218123339e57SDaeho Jeong 	struct inode *inode = file_inode(filp);
218201beba79SChristian Brauner 	struct mnt_idmap *idmap = file_mnt_idmap(filp);
218323339e57SDaeho Jeong 	int ret;
218423339e57SDaeho Jeong 
218501beba79SChristian Brauner 	if (!inode_owner_or_capable(idmap, inode))
218623339e57SDaeho Jeong 		return -EACCES;
218723339e57SDaeho Jeong 
218823339e57SDaeho Jeong 	ret = mnt_want_write_file(filp);
218923339e57SDaeho Jeong 	if (ret)
219023339e57SDaeho Jeong 		return ret;
219123339e57SDaeho Jeong 
219223339e57SDaeho Jeong 	inode_lock(inode);
219323339e57SDaeho Jeong 
219423339e57SDaeho Jeong 	f2fs_abort_atomic_write(inode, true);
219523339e57SDaeho Jeong 
219623339e57SDaeho Jeong 	inode_unlock(inode);
219723339e57SDaeho Jeong 
219823339e57SDaeho Jeong 	mnt_drop_write_file(filp);
219923339e57SDaeho Jeong 	f2fs_update_time(F2FS_I_SB(inode), REQ_TIME);
220023339e57SDaeho Jeong 	return ret;
220123339e57SDaeho Jeong }
220223339e57SDaeho Jeong 
f2fs_ioc_shutdown(struct file * filp,unsigned long arg)22031abff93dSJaegeuk Kim static int f2fs_ioc_shutdown(struct file *filp, unsigned long arg)
22041abff93dSJaegeuk Kim {
22051abff93dSJaegeuk Kim 	struct inode *inode = file_inode(filp);
22061abff93dSJaegeuk Kim 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
22071abff93dSJaegeuk Kim 	struct super_block *sb = sbi->sb;
22081abff93dSJaegeuk Kim 	__u32 in;
22092a96d8adSDan Carpenter 	int ret = 0;
22101abff93dSJaegeuk Kim 
22111abff93dSJaegeuk Kim 	if (!capable(CAP_SYS_ADMIN))
22121abff93dSJaegeuk Kim 		return -EPERM;
22131abff93dSJaegeuk Kim 
22141abff93dSJaegeuk Kim 	if (get_user(in, (__u32 __user *)arg))
22151abff93dSJaegeuk Kim 		return -EFAULT;
22161abff93dSJaegeuk Kim 
221760b2b4eeSSahitya Tummala 	if (in != F2FS_GOING_DOWN_FULLSYNC) {
22187fb17fe4SChao Yu 		ret = mnt_want_write_file(filp);
22198626441fSChao Yu 		if (ret) {
22208626441fSChao Yu 			if (ret == -EROFS) {
22218626441fSChao Yu 				ret = 0;
2222a9cfee0eSChao Yu 				f2fs_stop_checkpoint(sbi, false,
2223a9cfee0eSChao Yu 						STOP_CP_REASON_SHUTDOWN);
22248626441fSChao Yu 				trace_f2fs_shutdown(sbi, in, ret);
22258626441fSChao Yu 			}
22267fb17fe4SChao Yu 			return ret;
222760b2b4eeSSahitya Tummala 		}
22288626441fSChao Yu 	}
22297fb17fe4SChao Yu 
22301abff93dSJaegeuk Kim 	switch (in) {
22311abff93dSJaegeuk Kim 	case F2FS_GOING_DOWN_FULLSYNC:
2232040f04bdSChristoph Hellwig 		ret = freeze_bdev(sb->s_bdev);
2233040f04bdSChristoph Hellwig 		if (ret)
2234d027c484SChao Yu 			goto out;
2235a9cfee0eSChao Yu 		f2fs_stop_checkpoint(sbi, false, STOP_CP_REASON_SHUTDOWN);
2236040f04bdSChristoph Hellwig 		thaw_bdev(sb->s_bdev);
22371abff93dSJaegeuk Kim 		break;
22381abff93dSJaegeuk Kim 	case F2FS_GOING_DOWN_METASYNC:
22391abff93dSJaegeuk Kim 		/* do checkpoint only */
2240d027c484SChao Yu 		ret = f2fs_sync_fs(sb, 1);
2241d027c484SChao Yu 		if (ret)
2242d027c484SChao Yu 			goto out;
2243a9cfee0eSChao Yu 		f2fs_stop_checkpoint(sbi, false, STOP_CP_REASON_SHUTDOWN);
22441abff93dSJaegeuk Kim 		break;
22451abff93dSJaegeuk Kim 	case F2FS_GOING_DOWN_NOSYNC:
2246a9cfee0eSChao Yu 		f2fs_stop_checkpoint(sbi, false, STOP_CP_REASON_SHUTDOWN);
22471abff93dSJaegeuk Kim 		break;
2248c912a829SJaegeuk Kim 	case F2FS_GOING_DOWN_METAFLUSH:
22494d57b86dSChao Yu 		f2fs_sync_meta_pages(sbi, META, LONG_MAX, FS_META_IO);
2250a9cfee0eSChao Yu 		f2fs_stop_checkpoint(sbi, false, STOP_CP_REASON_SHUTDOWN);
2251c912a829SJaegeuk Kim 		break;
22520cd6d9b0SJaegeuk Kim 	case F2FS_GOING_DOWN_NEED_FSCK:
22530cd6d9b0SJaegeuk Kim 		set_sbi_flag(sbi, SBI_NEED_FSCK);
2254db610a64SJaegeuk Kim 		set_sbi_flag(sbi, SBI_CP_DISABLED_QUICK);
2255db610a64SJaegeuk Kim 		set_sbi_flag(sbi, SBI_IS_DIRTY);
22560cd6d9b0SJaegeuk Kim 		/* do checkpoint only */
22570cd6d9b0SJaegeuk Kim 		ret = f2fs_sync_fs(sb, 1);
22580cd6d9b0SJaegeuk Kim 		goto out;
22591abff93dSJaegeuk Kim 	default:
22607fb17fe4SChao Yu 		ret = -EINVAL;
22617fb17fe4SChao Yu 		goto out;
22621abff93dSJaegeuk Kim 	}
22637950e9acSChao Yu 
22644d57b86dSChao Yu 	f2fs_stop_gc_thread(sbi);
22654d57b86dSChao Yu 	f2fs_stop_discard_thread(sbi);
22667950e9acSChao Yu 
22674d57b86dSChao Yu 	f2fs_drop_discard_cmd(sbi);
22687950e9acSChao Yu 	clear_opt(sbi, DISCARD);
22697950e9acSChao Yu 
2270d0239e1bSJaegeuk Kim 	f2fs_update_time(sbi, REQ_TIME);
22717fb17fe4SChao Yu out:
227260b2b4eeSSahitya Tummala 	if (in != F2FS_GOING_DOWN_FULLSYNC)
22737fb17fe4SChao Yu 		mnt_drop_write_file(filp);
2274559e87c4SChao Yu 
2275559e87c4SChao Yu 	trace_f2fs_shutdown(sbi, in, ret);
2276559e87c4SChao Yu 
22777fb17fe4SChao Yu 	return ret;
22781abff93dSJaegeuk Kim }
22791abff93dSJaegeuk Kim 
f2fs_ioc_fitrim(struct file * filp,unsigned long arg)228052656e6cSJaegeuk Kim static int f2fs_ioc_fitrim(struct file *filp, unsigned long arg)
22814b2fecc8SJaegeuk Kim {
228252656e6cSJaegeuk Kim 	struct inode *inode = file_inode(filp);
22834b2fecc8SJaegeuk Kim 	struct super_block *sb = inode->i_sb;
22844b2fecc8SJaegeuk Kim 	struct fstrim_range range;
228552656e6cSJaegeuk Kim 	int ret;
22864b2fecc8SJaegeuk Kim 
22874b2fecc8SJaegeuk Kim 	if (!capable(CAP_SYS_ADMIN))
22884b2fecc8SJaegeuk Kim 		return -EPERM;
22894b2fecc8SJaegeuk Kim 
22907d20c8abSChao Yu 	if (!f2fs_hw_support_discard(F2FS_SB(sb)))
22914b2fecc8SJaegeuk Kim 		return -EOPNOTSUPP;
22924b2fecc8SJaegeuk Kim 
22934b2fecc8SJaegeuk Kim 	if (copy_from_user(&range, (struct fstrim_range __user *)arg,
22944b2fecc8SJaegeuk Kim 				sizeof(range)))
22954b2fecc8SJaegeuk Kim 		return -EFAULT;
22964b2fecc8SJaegeuk Kim 
22977fb17fe4SChao Yu 	ret = mnt_want_write_file(filp);
22987fb17fe4SChao Yu 	if (ret)
22997fb17fe4SChao Yu 		return ret;
23007fb17fe4SChao Yu 
23014b2fecc8SJaegeuk Kim 	range.minlen = max((unsigned int)range.minlen,
23027b47ef52SChristoph Hellwig 			   bdev_discard_granularity(sb->s_bdev));
23034b2fecc8SJaegeuk Kim 	ret = f2fs_trim_fs(F2FS_SB(sb), &range);
23047fb17fe4SChao Yu 	mnt_drop_write_file(filp);
23054b2fecc8SJaegeuk Kim 	if (ret < 0)
23064b2fecc8SJaegeuk Kim 		return ret;
23074b2fecc8SJaegeuk Kim 
23084b2fecc8SJaegeuk Kim 	if (copy_to_user((struct fstrim_range __user *)arg, &range,
23094b2fecc8SJaegeuk Kim 				sizeof(range)))
23104b2fecc8SJaegeuk Kim 		return -EFAULT;
2311d0239e1bSJaegeuk Kim 	f2fs_update_time(F2FS_I_SB(inode), REQ_TIME);
23124b2fecc8SJaegeuk Kim 	return 0;
23134b2fecc8SJaegeuk Kim }
231452656e6cSJaegeuk Kim 
uuid_is_nonzero(__u8 u[16])2315f424f664SJaegeuk Kim static bool uuid_is_nonzero(__u8 u[16])
2316f424f664SJaegeuk Kim {
2317f424f664SJaegeuk Kim 	int i;
2318f424f664SJaegeuk Kim 
2319f424f664SJaegeuk Kim 	for (i = 0; i < 16; i++)
2320f424f664SJaegeuk Kim 		if (u[i])
2321f424f664SJaegeuk Kim 			return true;
2322f424f664SJaegeuk Kim 	return false;
2323f424f664SJaegeuk Kim }
2324f424f664SJaegeuk Kim 
f2fs_ioc_set_encryption_policy(struct file * filp,unsigned long arg)2325f424f664SJaegeuk Kim static int f2fs_ioc_set_encryption_policy(struct file *filp, unsigned long arg)
2326f424f664SJaegeuk Kim {
2327f424f664SJaegeuk Kim 	struct inode *inode = file_inode(filp);
2328f424f664SJaegeuk Kim 
23297beb01f7SChao Yu 	if (!f2fs_sb_has_encrypt(F2FS_I_SB(inode)))
2330ead710b7SChao Yu 		return -EOPNOTSUPP;
2331ead710b7SChao Yu 
2332d0239e1bSJaegeuk Kim 	f2fs_update_time(F2FS_I_SB(inode), REQ_TIME);
23337fb17fe4SChao Yu 
2334db717d8eSEric Biggers 	return fscrypt_ioctl_set_policy(filp, (const void __user *)arg);
2335f424f664SJaegeuk Kim }
2336f424f664SJaegeuk Kim 
f2fs_ioc_get_encryption_policy(struct file * filp,unsigned long arg)2337f424f664SJaegeuk Kim static int f2fs_ioc_get_encryption_policy(struct file *filp, unsigned long arg)
2338f424f664SJaegeuk Kim {
23397beb01f7SChao Yu 	if (!f2fs_sb_has_encrypt(F2FS_I_SB(file_inode(filp))))
2340ead710b7SChao Yu 		return -EOPNOTSUPP;
2341db717d8eSEric Biggers 	return fscrypt_ioctl_get_policy(filp, (void __user *)arg);
2342f424f664SJaegeuk Kim }
2343f424f664SJaegeuk Kim 
f2fs_ioc_get_encryption_pwsalt(struct file * filp,unsigned long arg)2344f424f664SJaegeuk Kim static int f2fs_ioc_get_encryption_pwsalt(struct file *filp, unsigned long arg)
2345f424f664SJaegeuk Kim {
2346f424f664SJaegeuk Kim 	struct inode *inode = file_inode(filp);
2347f424f664SJaegeuk Kim 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
23485eaac835SChao Yu 	u8 encrypt_pw_salt[16];
2349f424f664SJaegeuk Kim 	int err;
2350f424f664SJaegeuk Kim 
23517beb01f7SChao Yu 	if (!f2fs_sb_has_encrypt(sbi))
2352f424f664SJaegeuk Kim 		return -EOPNOTSUPP;
2353f424f664SJaegeuk Kim 
2354f424f664SJaegeuk Kim 	err = mnt_want_write_file(filp);
2355f424f664SJaegeuk Kim 	if (err)
2356f424f664SJaegeuk Kim 		return err;
2357f424f664SJaegeuk Kim 
2358e4544b63STim Murray 	f2fs_down_write(&sbi->sb_lock);
2359d0d3f1b3SChao Yu 
2360d0d3f1b3SChao Yu 	if (uuid_is_nonzero(sbi->raw_super->encrypt_pw_salt))
2361d0d3f1b3SChao Yu 		goto got_it;
2362d0d3f1b3SChao Yu 
2363f424f664SJaegeuk Kim 	/* update superblock with uuid */
2364f424f664SJaegeuk Kim 	generate_random_uuid(sbi->raw_super->encrypt_pw_salt);
2365f424f664SJaegeuk Kim 
2366c5bda1c8SChao Yu 	err = f2fs_commit_super(sbi, false);
2367f424f664SJaegeuk Kim 	if (err) {
2368f424f664SJaegeuk Kim 		/* undo new data */
2369f424f664SJaegeuk Kim 		memset(sbi->raw_super->encrypt_pw_salt, 0, 16);
2370d0d3f1b3SChao Yu 		goto out_err;
2371f424f664SJaegeuk Kim 	}
2372f424f664SJaegeuk Kim got_it:
23735eaac835SChao Yu 	memcpy(encrypt_pw_salt, sbi->raw_super->encrypt_pw_salt, 16);
2374d0d3f1b3SChao Yu out_err:
2375e4544b63STim Murray 	f2fs_up_write(&sbi->sb_lock);
2376d0d3f1b3SChao Yu 	mnt_drop_write_file(filp);
23775eaac835SChao Yu 
23785eaac835SChao Yu 	if (!err && copy_to_user((__u8 __user *)arg, encrypt_pw_salt, 16))
23795eaac835SChao Yu 		err = -EFAULT;
23805eaac835SChao Yu 
2381d0d3f1b3SChao Yu 	return err;
2382f424f664SJaegeuk Kim }
2383f424f664SJaegeuk Kim 
f2fs_ioc_get_encryption_policy_ex(struct file * filp,unsigned long arg)23848ce589c7SEric Biggers static int f2fs_ioc_get_encryption_policy_ex(struct file *filp,
23858ce589c7SEric Biggers 					     unsigned long arg)
23868ce589c7SEric Biggers {
23878ce589c7SEric Biggers 	if (!f2fs_sb_has_encrypt(F2FS_I_SB(file_inode(filp))))
23888ce589c7SEric Biggers 		return -EOPNOTSUPP;
23898ce589c7SEric Biggers 
23908ce589c7SEric Biggers 	return fscrypt_ioctl_get_policy_ex(filp, (void __user *)arg);
23918ce589c7SEric Biggers }
23928ce589c7SEric Biggers 
f2fs_ioc_add_encryption_key(struct file * filp,unsigned long arg)23938ce589c7SEric Biggers static int f2fs_ioc_add_encryption_key(struct file *filp, unsigned long arg)
23948ce589c7SEric Biggers {
23958ce589c7SEric Biggers 	if (!f2fs_sb_has_encrypt(F2FS_I_SB(file_inode(filp))))
23968ce589c7SEric Biggers 		return -EOPNOTSUPP;
23978ce589c7SEric Biggers 
23988ce589c7SEric Biggers 	return fscrypt_ioctl_add_key(filp, (void __user *)arg);
23998ce589c7SEric Biggers }
24008ce589c7SEric Biggers 
f2fs_ioc_remove_encryption_key(struct file * filp,unsigned long arg)24018ce589c7SEric Biggers static int f2fs_ioc_remove_encryption_key(struct file *filp, unsigned long arg)
24028ce589c7SEric Biggers {
24038ce589c7SEric Biggers 	if (!f2fs_sb_has_encrypt(F2FS_I_SB(file_inode(filp))))
24048ce589c7SEric Biggers 		return -EOPNOTSUPP;
24058ce589c7SEric Biggers 
24068ce589c7SEric Biggers 	return fscrypt_ioctl_remove_key(filp, (void __user *)arg);
24078ce589c7SEric Biggers }
24088ce589c7SEric Biggers 
f2fs_ioc_remove_encryption_key_all_users(struct file * filp,unsigned long arg)24098ce589c7SEric Biggers static int f2fs_ioc_remove_encryption_key_all_users(struct file *filp,
24108ce589c7SEric Biggers 						    unsigned long arg)
24118ce589c7SEric Biggers {
24128ce589c7SEric Biggers 	if (!f2fs_sb_has_encrypt(F2FS_I_SB(file_inode(filp))))
24138ce589c7SEric Biggers 		return -EOPNOTSUPP;
24148ce589c7SEric Biggers 
24158ce589c7SEric Biggers 	return fscrypt_ioctl_remove_key_all_users(filp, (void __user *)arg);
24168ce589c7SEric Biggers }
24178ce589c7SEric Biggers 
f2fs_ioc_get_encryption_key_status(struct file * filp,unsigned long arg)24188ce589c7SEric Biggers static int f2fs_ioc_get_encryption_key_status(struct file *filp,
24198ce589c7SEric Biggers 					      unsigned long arg)
24208ce589c7SEric Biggers {
24218ce589c7SEric Biggers 	if (!f2fs_sb_has_encrypt(F2FS_I_SB(file_inode(filp))))
24228ce589c7SEric Biggers 		return -EOPNOTSUPP;
24238ce589c7SEric Biggers 
24248ce589c7SEric Biggers 	return fscrypt_ioctl_get_key_status(filp, (void __user *)arg);
24258ce589c7SEric Biggers }
24268ce589c7SEric Biggers 
f2fs_ioc_get_encryption_nonce(struct file * filp,unsigned long arg)2427ee446e1aSEric Biggers static int f2fs_ioc_get_encryption_nonce(struct file *filp, unsigned long arg)
2428ee446e1aSEric Biggers {
2429ee446e1aSEric Biggers 	if (!f2fs_sb_has_encrypt(F2FS_I_SB(file_inode(filp))))
2430ee446e1aSEric Biggers 		return -EOPNOTSUPP;
2431ee446e1aSEric Biggers 
2432ee446e1aSEric Biggers 	return fscrypt_ioctl_get_nonce(filp, (void __user *)arg);
2433ee446e1aSEric Biggers }
2434ee446e1aSEric Biggers 
f2fs_ioc_gc(struct file * filp,unsigned long arg)2435c1c1b583SChao Yu static int f2fs_ioc_gc(struct file *filp, unsigned long arg)
2436c1c1b583SChao Yu {
2437c1c1b583SChao Yu 	struct inode *inode = file_inode(filp);
2438c1c1b583SChao Yu 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
2439d147ea4aSJaegeuk Kim 	struct f2fs_gc_control gc_control = { .victim_segno = NULL_SEGNO,
2440d147ea4aSJaegeuk Kim 			.no_bg_gc = false,
2441c81d5baeSJaegeuk Kim 			.should_migrate_blocks = false,
2442c81d5baeSJaegeuk Kim 			.nr_free_secs = 0 };
2443d530d4d8SChao Yu 	__u32 sync;
24447fb17fe4SChao Yu 	int ret;
2445c1c1b583SChao Yu 
2446c1c1b583SChao Yu 	if (!capable(CAP_SYS_ADMIN))
2447c1c1b583SChao Yu 		return -EPERM;
2448c1c1b583SChao Yu 
2449d530d4d8SChao Yu 	if (get_user(sync, (__u32 __user *)arg))
2450c1c1b583SChao Yu 		return -EFAULT;
2451c1c1b583SChao Yu 
2452d530d4d8SChao Yu 	if (f2fs_readonly(sbi->sb))
2453d530d4d8SChao Yu 		return -EROFS;
2454c1c1b583SChao Yu 
24557fb17fe4SChao Yu 	ret = mnt_want_write_file(filp);
24567fb17fe4SChao Yu 	if (ret)
24577fb17fe4SChao Yu 		return ret;
24587fb17fe4SChao Yu 
2459d530d4d8SChao Yu 	if (!sync) {
2460e4544b63STim Murray 		if (!f2fs_down_write_trylock(&sbi->gc_lock)) {
24617fb17fe4SChao Yu 			ret = -EBUSY;
24627fb17fe4SChao Yu 			goto out;
24637fb17fe4SChao Yu 		}
2464d530d4d8SChao Yu 	} else {
2465e4544b63STim Murray 		f2fs_down_write(&sbi->gc_lock);
2466c1c1b583SChao Yu 	}
2467c1c1b583SChao Yu 
2468d147ea4aSJaegeuk Kim 	gc_control.init_gc_type = sync ? FG_GC : BG_GC;
2469d147ea4aSJaegeuk Kim 	gc_control.err_gc_skipped = sync;
24709bf1dcbdSChao Yu 	stat_inc_gc_call_count(sbi, FOREGROUND);
2471d147ea4aSJaegeuk Kim 	ret = f2fs_gc(sbi, &gc_control);
24727fb17fe4SChao Yu out:
24737fb17fe4SChao Yu 	mnt_drop_write_file(filp);
24747fb17fe4SChao Yu 	return ret;
2475c1c1b583SChao Yu }
2476c1c1b583SChao Yu 
__f2fs_ioc_gc_range(struct file * filp,struct f2fs_gc_range * range)247734178b1bSChao Yu static int __f2fs_ioc_gc_range(struct file *filp, struct f2fs_gc_range *range)
247834dc77adSJaegeuk Kim {
247934178b1bSChao Yu 	struct f2fs_sb_info *sbi = F2FS_I_SB(file_inode(filp));
2480d147ea4aSJaegeuk Kim 	struct f2fs_gc_control gc_control = {
2481d147ea4aSJaegeuk Kim 			.init_gc_type = range->sync ? FG_GC : BG_GC,
2482d147ea4aSJaegeuk Kim 			.no_bg_gc = false,
2483d147ea4aSJaegeuk Kim 			.should_migrate_blocks = false,
2484c81d5baeSJaegeuk Kim 			.err_gc_skipped = range->sync,
2485c81d5baeSJaegeuk Kim 			.nr_free_secs = 0 };
248634dc77adSJaegeuk Kim 	u64 end;
248734dc77adSJaegeuk Kim 	int ret;
248834dc77adSJaegeuk Kim 
248934dc77adSJaegeuk Kim 	if (!capable(CAP_SYS_ADMIN))
249034dc77adSJaegeuk Kim 		return -EPERM;
249134dc77adSJaegeuk Kim 	if (f2fs_readonly(sbi->sb))
249234dc77adSJaegeuk Kim 		return -EROFS;
249334dc77adSJaegeuk Kim 
249434178b1bSChao Yu 	end = range->start + range->len;
249534178b1bSChao Yu 	if (end < range->start || range->start < MAIN_BLKADDR(sbi) ||
2496fbbf7799SSahitya Tummala 					end >= MAX_BLKADDR(sbi))
2497b82f6e34SYunlei He 		return -EINVAL;
2498b82f6e34SYunlei He 
249934dc77adSJaegeuk Kim 	ret = mnt_want_write_file(filp);
250034dc77adSJaegeuk Kim 	if (ret)
250134dc77adSJaegeuk Kim 		return ret;
250234dc77adSJaegeuk Kim 
250334dc77adSJaegeuk Kim do_more:
250434178b1bSChao Yu 	if (!range->sync) {
2505e4544b63STim Murray 		if (!f2fs_down_write_trylock(&sbi->gc_lock)) {
250634dc77adSJaegeuk Kim 			ret = -EBUSY;
250734dc77adSJaegeuk Kim 			goto out;
250834dc77adSJaegeuk Kim 		}
250934dc77adSJaegeuk Kim 	} else {
2510e4544b63STim Murray 		f2fs_down_write(&sbi->gc_lock);
251134dc77adSJaegeuk Kim 	}
251234dc77adSJaegeuk Kim 
2513d147ea4aSJaegeuk Kim 	gc_control.victim_segno = GET_SEGNO(sbi, range->start);
25149bf1dcbdSChao Yu 	stat_inc_gc_call_count(sbi, FOREGROUND);
2515d147ea4aSJaegeuk Kim 	ret = f2fs_gc(sbi, &gc_control);
251697767500SQilong Zhang 	if (ret) {
251797767500SQilong Zhang 		if (ret == -EBUSY)
251897767500SQilong Zhang 			ret = -EAGAIN;
251997767500SQilong Zhang 		goto out;
252097767500SQilong Zhang 	}
2521074b5ea2SJaegeuk Kim 	range->start += CAP_BLKS_PER_SEC(sbi);
252234178b1bSChao Yu 	if (range->start <= end)
252334dc77adSJaegeuk Kim 		goto do_more;
252434dc77adSJaegeuk Kim out:
252534dc77adSJaegeuk Kim 	mnt_drop_write_file(filp);
252634dc77adSJaegeuk Kim 	return ret;
252734dc77adSJaegeuk Kim }
252834dc77adSJaegeuk Kim 
f2fs_ioc_gc_range(struct file * filp,unsigned long arg)252934178b1bSChao Yu static int f2fs_ioc_gc_range(struct file *filp, unsigned long arg)
253034178b1bSChao Yu {
253134178b1bSChao Yu 	struct f2fs_gc_range range;
253234178b1bSChao Yu 
253334178b1bSChao Yu 	if (copy_from_user(&range, (struct f2fs_gc_range __user *)arg,
253434178b1bSChao Yu 							sizeof(range)))
253534178b1bSChao Yu 		return -EFAULT;
253634178b1bSChao Yu 	return __f2fs_ioc_gc_range(filp, &range);
253734178b1bSChao Yu }
253834178b1bSChao Yu 
f2fs_ioc_write_checkpoint(struct file * filp)2539ddf1eca4SYangtao Li static int f2fs_ioc_write_checkpoint(struct file *filp)
2540456b88e4SChao Yu {
2541456b88e4SChao Yu 	struct inode *inode = file_inode(filp);
2542456b88e4SChao Yu 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
25437fb17fe4SChao Yu 	int ret;
2544456b88e4SChao Yu 
2545456b88e4SChao Yu 	if (!capable(CAP_SYS_ADMIN))
2546456b88e4SChao Yu 		return -EPERM;
2547456b88e4SChao Yu 
2548456b88e4SChao Yu 	if (f2fs_readonly(sbi->sb))
2549456b88e4SChao Yu 		return -EROFS;
2550456b88e4SChao Yu 
25514354994fSDaniel Rosenberg 	if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED))) {
2552dcbb4c10SJoe Perches 		f2fs_info(sbi, "Skipping Checkpoint. Checkpoints currently disabled.");
25534354994fSDaniel Rosenberg 		return -EINVAL;
25544354994fSDaniel Rosenberg 	}
25554354994fSDaniel Rosenberg 
25567fb17fe4SChao Yu 	ret = mnt_want_write_file(filp);
25577fb17fe4SChao Yu 	if (ret)
25587fb17fe4SChao Yu 		return ret;
25597fb17fe4SChao Yu 
25607fb17fe4SChao Yu 	ret = f2fs_sync_fs(sbi->sb, 1);
25617fb17fe4SChao Yu 
25627fb17fe4SChao Yu 	mnt_drop_write_file(filp);
25637fb17fe4SChao Yu 	return ret;
2564456b88e4SChao Yu }
2565456b88e4SChao Yu 
f2fs_defragment_range(struct f2fs_sb_info * sbi,struct file * filp,struct f2fs_defragment * range)2566d323d005SChao Yu static int f2fs_defragment_range(struct f2fs_sb_info *sbi,
2567d323d005SChao Yu 					struct file *filp,
2568d323d005SChao Yu 					struct f2fs_defragment *range)
2569d323d005SChao Yu {
2570d323d005SChao Yu 	struct inode *inode = file_inode(filp);
2571f3d98e74SChao Yu 	struct f2fs_map_blocks map = { .m_next_extent = NULL,
2572f4f0b677SJia Zhu 					.m_seg_type = NO_CHECK_TYPE,
2573f4f0b677SJia Zhu 					.m_may_create = false };
2574fe59109aSJaegeuk Kim 	struct extent_info ei = {};
2575f3d98e74SChao Yu 	pgoff_t pg_start, pg_end, next_pgofs;
25763519e3f9SChao Yu 	unsigned int blk_per_seg = sbi->blocks_per_seg;
2577d323d005SChao Yu 	unsigned int total = 0, sec_num;
2578d323d005SChao Yu 	block_t blk_end = 0;
2579d323d005SChao Yu 	bool fragmented = false;
2580d323d005SChao Yu 	int err;
2581d323d005SChao Yu 
258209cbfeafSKirill A. Shutemov 	pg_start = range->start >> PAGE_SHIFT;
258309cbfeafSKirill A. Shutemov 	pg_end = (range->start + range->len) >> PAGE_SHIFT;
2584d323d005SChao Yu 
25852c4db1a6SJaegeuk Kim 	f2fs_balance_fs(sbi, true);
2586d323d005SChao Yu 
25875955102cSAl Viro 	inode_lock(inode);
2588d323d005SChao Yu 
25897cd2e5f7SYangtao Li 	if (is_inode_flag_set(inode, FI_COMPRESS_RELEASED)) {
25907cd2e5f7SYangtao Li 		err = -EINVAL;
25917cd2e5f7SYangtao Li 		goto unlock_out;
25927cd2e5f7SYangtao Li 	}
25937cd2e5f7SYangtao Li 
25941018a546SChao Yu 	/* if in-place-update policy is enabled, don't waste time here */
25951018a546SChao Yu 	set_inode_flag(inode, FI_OPU_WRITE);
25961018a546SChao Yu 	if (f2fs_should_update_inplace(inode, NULL)) {
25971018a546SChao Yu 		err = -EINVAL;
25981018a546SChao Yu 		goto out;
25991018a546SChao Yu 	}
26001018a546SChao Yu 
2601d323d005SChao Yu 	/* writeback all dirty pages in the range */
2602d323d005SChao Yu 	err = filemap_write_and_wait_range(inode->i_mapping, range->start,
2603d8fe4f0eSFan Li 						range->start + range->len - 1);
2604d323d005SChao Yu 	if (err)
2605d323d005SChao Yu 		goto out;
2606d323d005SChao Yu 
2607d323d005SChao Yu 	/*
2608d323d005SChao Yu 	 * lookup mapping info in extent cache, skip defragmenting if physical
2609d323d005SChao Yu 	 * block addresses are continuous.
2610d323d005SChao Yu 	 */
2611e7547dacSJaegeuk Kim 	if (f2fs_lookup_read_extent_cache(inode, pg_start, &ei)) {
2612d323d005SChao Yu 		if (ei.fofs + ei.len >= pg_end)
2613d323d005SChao Yu 			goto out;
2614d323d005SChao Yu 	}
2615d323d005SChao Yu 
2616d323d005SChao Yu 	map.m_lblk = pg_start;
2617f3d98e74SChao Yu 	map.m_next_pgofs = &next_pgofs;
2618d323d005SChao Yu 
2619d323d005SChao Yu 	/*
2620d323d005SChao Yu 	 * lookup mapping info in dnode page cache, skip defragmenting if all
2621d323d005SChao Yu 	 * physical block addresses are continuous even if there are hole(s)
2622d323d005SChao Yu 	 * in logical blocks.
2623d323d005SChao Yu 	 */
2624d323d005SChao Yu 	while (map.m_lblk < pg_end) {
2625a1c1e9b7SFan Li 		map.m_len = pg_end - map.m_lblk;
2626cd8fc522SChristoph Hellwig 		err = f2fs_map_blocks(inode, &map, F2FS_GET_BLOCK_DEFAULT);
2627d323d005SChao Yu 		if (err)
2628d323d005SChao Yu 			goto out;
2629d323d005SChao Yu 
2630d323d005SChao Yu 		if (!(map.m_flags & F2FS_MAP_FLAGS)) {
2631f3d98e74SChao Yu 			map.m_lblk = next_pgofs;
2632d323d005SChao Yu 			continue;
2633d323d005SChao Yu 		}
2634d323d005SChao Yu 
263525a912e5SChao Yu 		if (blk_end && blk_end != map.m_pblk)
2636d323d005SChao Yu 			fragmented = true;
263725a912e5SChao Yu 
263825a912e5SChao Yu 		/* record total count of block that we're going to move */
263925a912e5SChao Yu 		total += map.m_len;
264025a912e5SChao Yu 
2641d323d005SChao Yu 		blk_end = map.m_pblk + map.m_len;
2642d323d005SChao Yu 
2643d323d005SChao Yu 		map.m_lblk += map.m_len;
2644d323d005SChao Yu 	}
2645d323d005SChao Yu 
2646d3a1a0e1SChao Yu 	if (!fragmented) {
2647d3a1a0e1SChao Yu 		total = 0;
2648d323d005SChao Yu 		goto out;
2649d3a1a0e1SChao Yu 	}
2650d323d005SChao Yu 
2651074b5ea2SJaegeuk Kim 	sec_num = DIV_ROUND_UP(total, CAP_BLKS_PER_SEC(sbi));
2652d323d005SChao Yu 
2653d323d005SChao Yu 	/*
2654d323d005SChao Yu 	 * make sure there are enough free section for LFS allocation, this can
2655d323d005SChao Yu 	 * avoid defragment running in SSR mode when free section are allocated
2656d323d005SChao Yu 	 * intensively
2657d323d005SChao Yu 	 */
26587f3037a5SJaegeuk Kim 	if (has_not_enough_free_secs(sbi, 0, sec_num)) {
2659d323d005SChao Yu 		err = -EAGAIN;
2660d323d005SChao Yu 		goto out;
2661d323d005SChao Yu 	}
2662d323d005SChao Yu 
266325a912e5SChao Yu 	map.m_lblk = pg_start;
266425a912e5SChao Yu 	map.m_len = pg_end - pg_start;
266525a912e5SChao Yu 	total = 0;
266625a912e5SChao Yu 
2667d323d005SChao Yu 	while (map.m_lblk < pg_end) {
2668d323d005SChao Yu 		pgoff_t idx;
2669d323d005SChao Yu 		int cnt = 0;
2670d323d005SChao Yu 
2671d323d005SChao Yu do_map:
2672a1c1e9b7SFan Li 		map.m_len = pg_end - map.m_lblk;
2673cd8fc522SChristoph Hellwig 		err = f2fs_map_blocks(inode, &map, F2FS_GET_BLOCK_DEFAULT);
2674d323d005SChao Yu 		if (err)
2675d323d005SChao Yu 			goto clear_out;
2676d323d005SChao Yu 
2677d323d005SChao Yu 		if (!(map.m_flags & F2FS_MAP_FLAGS)) {
2678f3d98e74SChao Yu 			map.m_lblk = next_pgofs;
2679d3a1a0e1SChao Yu 			goto check;
2680d323d005SChao Yu 		}
2681d323d005SChao Yu 
26821018a546SChao Yu 		set_inode_flag(inode, FI_SKIP_WRITES);
2683d323d005SChao Yu 
2684d323d005SChao Yu 		idx = map.m_lblk;
2685d323d005SChao Yu 		while (idx < map.m_lblk + map.m_len && cnt < blk_per_seg) {
2686d323d005SChao Yu 			struct page *page;
2687d323d005SChao Yu 
26884d57b86dSChao Yu 			page = f2fs_get_lock_data_page(inode, idx, true);
2689d323d005SChao Yu 			if (IS_ERR(page)) {
2690d323d005SChao Yu 				err = PTR_ERR(page);
2691d323d005SChao Yu 				goto clear_out;
2692d323d005SChao Yu 			}
2693d323d005SChao Yu 
2694d323d005SChao Yu 			set_page_dirty(page);
26952d1fe8a8SChao Yu 			set_page_private_gcing(page);
2696d323d005SChao Yu 			f2fs_put_page(page, 1);
2697d323d005SChao Yu 
2698d323d005SChao Yu 			idx++;
2699d323d005SChao Yu 			cnt++;
2700d323d005SChao Yu 			total++;
2701d323d005SChao Yu 		}
2702d323d005SChao Yu 
2703d323d005SChao Yu 		map.m_lblk = idx;
2704d3a1a0e1SChao Yu check:
2705d3a1a0e1SChao Yu 		if (map.m_lblk < pg_end && cnt < blk_per_seg)
2706d323d005SChao Yu 			goto do_map;
2707d323d005SChao Yu 
27081018a546SChao Yu 		clear_inode_flag(inode, FI_SKIP_WRITES);
2709d323d005SChao Yu 
2710d323d005SChao Yu 		err = filemap_fdatawrite(inode->i_mapping);
2711d323d005SChao Yu 		if (err)
2712d323d005SChao Yu 			goto out;
2713d323d005SChao Yu 	}
2714d323d005SChao Yu clear_out:
27151018a546SChao Yu 	clear_inode_flag(inode, FI_SKIP_WRITES);
2716d323d005SChao Yu out:
27171018a546SChao Yu 	clear_inode_flag(inode, FI_OPU_WRITE);
27187cd2e5f7SYangtao Li unlock_out:
27195955102cSAl Viro 	inode_unlock(inode);
2720d323d005SChao Yu 	if (!err)
272109cbfeafSKirill A. Shutemov 		range->len = (u64)total << PAGE_SHIFT;
2722d323d005SChao Yu 	return err;
2723d323d005SChao Yu }
2724d323d005SChao Yu 
f2fs_ioc_defragment(struct file * filp,unsigned long arg)2725d323d005SChao Yu static int f2fs_ioc_defragment(struct file *filp, unsigned long arg)
2726d323d005SChao Yu {
2727d323d005SChao Yu 	struct inode *inode = file_inode(filp);
2728d323d005SChao Yu 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
2729d323d005SChao Yu 	struct f2fs_defragment range;
2730d323d005SChao Yu 	int err;
2731d323d005SChao Yu 
2732d323d005SChao Yu 	if (!capable(CAP_SYS_ADMIN))
2733d323d005SChao Yu 		return -EPERM;
2734d323d005SChao Yu 
27357eab0c0dSHou Pengyang 	if (!S_ISREG(inode->i_mode) || f2fs_is_atomic_file(inode))
2736d323d005SChao Yu 		return -EINVAL;
2737d323d005SChao Yu 
2738d7563861SKinglong Mee 	if (f2fs_readonly(sbi->sb))
2739d7563861SKinglong Mee 		return -EROFS;
2740d7563861SKinglong Mee 
2741d7563861SKinglong Mee 	if (copy_from_user(&range, (struct f2fs_defragment __user *)arg,
2742d7563861SKinglong Mee 							sizeof(range)))
2743d7563861SKinglong Mee 		return -EFAULT;
2744d7563861SKinglong Mee 
2745d7563861SKinglong Mee 	/* verify alignment of offset & size */
2746d7563861SKinglong Mee 	if (range.start & (F2FS_BLKSIZE - 1) || range.len & (F2FS_BLKSIZE - 1))
2747d7563861SKinglong Mee 		return -EINVAL;
2748d7563861SKinglong Mee 
2749d7563861SKinglong Mee 	if (unlikely((range.start + range.len) >> PAGE_SHIFT >
27506d1451bfSChengguang Xu 					max_file_blocks(inode)))
2751d7563861SKinglong Mee 		return -EINVAL;
2752d7563861SKinglong Mee 
2753d323d005SChao Yu 	err = mnt_want_write_file(filp);
2754d323d005SChao Yu 	if (err)
2755d323d005SChao Yu 		return err;
2756d323d005SChao Yu 
2757d323d005SChao Yu 	err = f2fs_defragment_range(sbi, filp, &range);
2758d7563861SKinglong Mee 	mnt_drop_write_file(filp);
2759d7563861SKinglong Mee 
2760d0239e1bSJaegeuk Kim 	f2fs_update_time(sbi, REQ_TIME);
2761d323d005SChao Yu 	if (err < 0)
2762d7563861SKinglong Mee 		return err;
2763d323d005SChao Yu 
2764d323d005SChao Yu 	if (copy_to_user((struct f2fs_defragment __user *)arg, &range,
2765d323d005SChao Yu 							sizeof(range)))
2766d7563861SKinglong Mee 		return -EFAULT;
2767d7563861SKinglong Mee 
2768d7563861SKinglong Mee 	return 0;
2769d323d005SChao Yu }
2770d323d005SChao Yu 
f2fs_move_file_range(struct file * file_in,loff_t pos_in,struct file * file_out,loff_t pos_out,size_t len)27714dd6f977SJaegeuk Kim static int f2fs_move_file_range(struct file *file_in, loff_t pos_in,
27724dd6f977SJaegeuk Kim 			struct file *file_out, loff_t pos_out, size_t len)
27734dd6f977SJaegeuk Kim {
27744dd6f977SJaegeuk Kim 	struct inode *src = file_inode(file_in);
27754dd6f977SJaegeuk Kim 	struct inode *dst = file_inode(file_out);
27764dd6f977SJaegeuk Kim 	struct f2fs_sb_info *sbi = F2FS_I_SB(src);
27774dd6f977SJaegeuk Kim 	size_t olen = len, dst_max_i_size = 0;
27784dd6f977SJaegeuk Kim 	size_t dst_osize;
27794dd6f977SJaegeuk Kim 	int ret;
27804dd6f977SJaegeuk Kim 
27814dd6f977SJaegeuk Kim 	if (file_in->f_path.mnt != file_out->f_path.mnt ||
27824dd6f977SJaegeuk Kim 				src->i_sb != dst->i_sb)
27834dd6f977SJaegeuk Kim 		return -EXDEV;
27844dd6f977SJaegeuk Kim 
27854dd6f977SJaegeuk Kim 	if (unlikely(f2fs_readonly(src->i_sb)))
27864dd6f977SJaegeuk Kim 		return -EROFS;
27874dd6f977SJaegeuk Kim 
2788fe8494bfSChao Yu 	if (!S_ISREG(src->i_mode) || !S_ISREG(dst->i_mode))
2789fe8494bfSChao Yu 		return -EINVAL;
27904dd6f977SJaegeuk Kim 
279162230e0dSChandan Rajendra 	if (IS_ENCRYPTED(src) || IS_ENCRYPTED(dst))
27924dd6f977SJaegeuk Kim 		return -EOPNOTSUPP;
27934dd6f977SJaegeuk Kim 
2794aad1383cSDan Robertson 	if (pos_out < 0 || pos_in < 0)
2795aad1383cSDan Robertson 		return -EINVAL;
2796aad1383cSDan Robertson 
2797d95fd91cSFan Li 	if (src == dst) {
2798d95fd91cSFan Li 		if (pos_in == pos_out)
2799d95fd91cSFan Li 			return 0;
2800d95fd91cSFan Li 		if (pos_out > pos_in && pos_out < pos_in + len)
2801d95fd91cSFan Li 			return -EINVAL;
2802d95fd91cSFan Li 	}
2803d95fd91cSFan Li 
28044dd6f977SJaegeuk Kim 	inode_lock(src);
280520a3d61dSChao Yu 	if (src != dst) {
280620a3d61dSChao Yu 		ret = -EBUSY;
2807bb06664aSChao Yu 		if (!inode_trylock(dst))
2808bb06664aSChao Yu 			goto out;
280920a3d61dSChao Yu 	}
28104dd6f977SJaegeuk Kim 
2811412eee2cSChao Yu 	if (f2fs_compressed_file(src) || f2fs_compressed_file(dst)) {
2812412eee2cSChao Yu 		ret = -EOPNOTSUPP;
2813412eee2cSChao Yu 		goto out_unlock;
2814412eee2cSChao Yu 	}
2815412eee2cSChao Yu 
28164dd6f977SJaegeuk Kim 	ret = -EINVAL;
28174dd6f977SJaegeuk Kim 	if (pos_in + len > src->i_size || pos_in + len < pos_in)
28184dd6f977SJaegeuk Kim 		goto out_unlock;
28194dd6f977SJaegeuk Kim 	if (len == 0)
28204dd6f977SJaegeuk Kim 		olen = len = src->i_size - pos_in;
28214dd6f977SJaegeuk Kim 	if (pos_in + len == src->i_size)
28224dd6f977SJaegeuk Kim 		len = ALIGN(src->i_size, F2FS_BLKSIZE) - pos_in;
28234dd6f977SJaegeuk Kim 	if (len == 0) {
28244dd6f977SJaegeuk Kim 		ret = 0;
28254dd6f977SJaegeuk Kim 		goto out_unlock;
28264dd6f977SJaegeuk Kim 	}
28274dd6f977SJaegeuk Kim 
28284dd6f977SJaegeuk Kim 	dst_osize = dst->i_size;
28294dd6f977SJaegeuk Kim 	if (pos_out + olen > dst->i_size)
28304dd6f977SJaegeuk Kim 		dst_max_i_size = pos_out + olen;
28314dd6f977SJaegeuk Kim 
28324dd6f977SJaegeuk Kim 	/* verify the end result is block aligned */
28334dd6f977SJaegeuk Kim 	if (!IS_ALIGNED(pos_in, F2FS_BLKSIZE) ||
28344dd6f977SJaegeuk Kim 			!IS_ALIGNED(pos_in + len, F2FS_BLKSIZE) ||
28354dd6f977SJaegeuk Kim 			!IS_ALIGNED(pos_out, F2FS_BLKSIZE))
28364dd6f977SJaegeuk Kim 		goto out_unlock;
28374dd6f977SJaegeuk Kim 
28384dd6f977SJaegeuk Kim 	ret = f2fs_convert_inline_inode(src);
28394dd6f977SJaegeuk Kim 	if (ret)
28404dd6f977SJaegeuk Kim 		goto out_unlock;
28414dd6f977SJaegeuk Kim 
28424dd6f977SJaegeuk Kim 	ret = f2fs_convert_inline_inode(dst);
28434dd6f977SJaegeuk Kim 	if (ret)
28444dd6f977SJaegeuk Kim 		goto out_unlock;
28454dd6f977SJaegeuk Kim 
28464dd6f977SJaegeuk Kim 	/* write out all dirty pages from offset */
28474dd6f977SJaegeuk Kim 	ret = filemap_write_and_wait_range(src->i_mapping,
28484dd6f977SJaegeuk Kim 					pos_in, pos_in + len);
28494dd6f977SJaegeuk Kim 	if (ret)
28504dd6f977SJaegeuk Kim 		goto out_unlock;
28514dd6f977SJaegeuk Kim 
28524dd6f977SJaegeuk Kim 	ret = filemap_write_and_wait_range(dst->i_mapping,
28534dd6f977SJaegeuk Kim 					pos_out, pos_out + len);
28544dd6f977SJaegeuk Kim 	if (ret)
28554dd6f977SJaegeuk Kim 		goto out_unlock;
28564dd6f977SJaegeuk Kim 
28574dd6f977SJaegeuk Kim 	f2fs_balance_fs(sbi, true);
28586f8d4455SJaegeuk Kim 
2859e4544b63STim Murray 	f2fs_down_write(&F2FS_I(src)->i_gc_rwsem[WRITE]);
28606f8d4455SJaegeuk Kim 	if (src != dst) {
28616f8d4455SJaegeuk Kim 		ret = -EBUSY;
2862e4544b63STim Murray 		if (!f2fs_down_write_trylock(&F2FS_I(dst)->i_gc_rwsem[WRITE]))
28636f8d4455SJaegeuk Kim 			goto out_src;
28646f8d4455SJaegeuk Kim 	}
28656f8d4455SJaegeuk Kim 
28664dd6f977SJaegeuk Kim 	f2fs_lock_op(sbi);
286761e4da11SFan Li 	ret = __exchange_data_block(src, dst, pos_in >> F2FS_BLKSIZE_BITS,
286861e4da11SFan Li 				pos_out >> F2FS_BLKSIZE_BITS,
286961e4da11SFan Li 				len >> F2FS_BLKSIZE_BITS, false);
28704dd6f977SJaegeuk Kim 
28714dd6f977SJaegeuk Kim 	if (!ret) {
28724dd6f977SJaegeuk Kim 		if (dst_max_i_size)
28734dd6f977SJaegeuk Kim 			f2fs_i_size_write(dst, dst_max_i_size);
28744dd6f977SJaegeuk Kim 		else if (dst_osize != dst->i_size)
28754dd6f977SJaegeuk Kim 			f2fs_i_size_write(dst, dst_osize);
28764dd6f977SJaegeuk Kim 	}
28774dd6f977SJaegeuk Kim 	f2fs_unlock_op(sbi);
28786f8d4455SJaegeuk Kim 
28796f8d4455SJaegeuk Kim 	if (src != dst)
2880e4544b63STim Murray 		f2fs_up_write(&F2FS_I(dst)->i_gc_rwsem[WRITE]);
28816f8d4455SJaegeuk Kim out_src:
2882e4544b63STim Murray 	f2fs_up_write(&F2FS_I(src)->i_gc_rwsem[WRITE]);
2883396d0a28SYunlei He 	if (ret)
2884396d0a28SYunlei He 		goto out_unlock;
2885396d0a28SYunlei He 
2886c62ebd35SJeff Layton 	src->i_mtime = inode_set_ctime_current(src);
2887396d0a28SYunlei He 	f2fs_mark_inode_dirty_sync(src, false);
2888396d0a28SYunlei He 	if (src != dst) {
2889c62ebd35SJeff Layton 		dst->i_mtime = inode_set_ctime_current(dst);
2890396d0a28SYunlei He 		f2fs_mark_inode_dirty_sync(dst, false);
2891396d0a28SYunlei He 	}
2892396d0a28SYunlei He 	f2fs_update_time(sbi, REQ_TIME);
2893396d0a28SYunlei He 
28946f8d4455SJaegeuk Kim out_unlock:
28956f8d4455SJaegeuk Kim 	if (src != dst)
28966f8d4455SJaegeuk Kim 		inode_unlock(dst);
28976f8d4455SJaegeuk Kim out:
28984dd6f977SJaegeuk Kim 	inode_unlock(src);
28994dd6f977SJaegeuk Kim 	return ret;
29004dd6f977SJaegeuk Kim }
29014dd6f977SJaegeuk Kim 
__f2fs_ioc_move_range(struct file * filp,struct f2fs_move_range * range)290234178b1bSChao Yu static int __f2fs_ioc_move_range(struct file *filp,
290334178b1bSChao Yu 				struct f2fs_move_range *range)
29044dd6f977SJaegeuk Kim {
29054dd6f977SJaegeuk Kim 	struct fd dst;
29064dd6f977SJaegeuk Kim 	int err;
29074dd6f977SJaegeuk Kim 
29084dd6f977SJaegeuk Kim 	if (!(filp->f_mode & FMODE_READ) ||
29094dd6f977SJaegeuk Kim 			!(filp->f_mode & FMODE_WRITE))
29104dd6f977SJaegeuk Kim 		return -EBADF;
29114dd6f977SJaegeuk Kim 
291234178b1bSChao Yu 	dst = fdget(range->dst_fd);
29134dd6f977SJaegeuk Kim 	if (!dst.file)
29144dd6f977SJaegeuk Kim 		return -EBADF;
29154dd6f977SJaegeuk Kim 
29164dd6f977SJaegeuk Kim 	if (!(dst.file->f_mode & FMODE_WRITE)) {
29174dd6f977SJaegeuk Kim 		err = -EBADF;
29184dd6f977SJaegeuk Kim 		goto err_out;
29194dd6f977SJaegeuk Kim 	}
29204dd6f977SJaegeuk Kim 
29214dd6f977SJaegeuk Kim 	err = mnt_want_write_file(filp);
29224dd6f977SJaegeuk Kim 	if (err)
29234dd6f977SJaegeuk Kim 		goto err_out;
29244dd6f977SJaegeuk Kim 
292534178b1bSChao Yu 	err = f2fs_move_file_range(filp, range->pos_in, dst.file,
292634178b1bSChao Yu 					range->pos_out, range->len);
29274dd6f977SJaegeuk Kim 
29284dd6f977SJaegeuk Kim 	mnt_drop_write_file(filp);
29294dd6f977SJaegeuk Kim err_out:
29304dd6f977SJaegeuk Kim 	fdput(dst);
29314dd6f977SJaegeuk Kim 	return err;
29324dd6f977SJaegeuk Kim }
29334dd6f977SJaegeuk Kim 
f2fs_ioc_move_range(struct file * filp,unsigned long arg)293434178b1bSChao Yu static int f2fs_ioc_move_range(struct file *filp, unsigned long arg)
293534178b1bSChao Yu {
293634178b1bSChao Yu 	struct f2fs_move_range range;
293734178b1bSChao Yu 
293834178b1bSChao Yu 	if (copy_from_user(&range, (struct f2fs_move_range __user *)arg,
293934178b1bSChao Yu 							sizeof(range)))
294034178b1bSChao Yu 		return -EFAULT;
294134178b1bSChao Yu 	return __f2fs_ioc_move_range(filp, &range);
294234178b1bSChao Yu }
294334178b1bSChao Yu 
f2fs_ioc_flush_device(struct file * filp,unsigned long arg)2944e066b83cSJaegeuk Kim static int f2fs_ioc_flush_device(struct file *filp, unsigned long arg)
2945e066b83cSJaegeuk Kim {
2946e066b83cSJaegeuk Kim 	struct inode *inode = file_inode(filp);
2947e066b83cSJaegeuk Kim 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
2948e066b83cSJaegeuk Kim 	struct sit_info *sm = SIT_I(sbi);
2949e066b83cSJaegeuk Kim 	unsigned int start_segno = 0, end_segno = 0;
2950e066b83cSJaegeuk Kim 	unsigned int dev_start_segno = 0, dev_end_segno = 0;
2951e066b83cSJaegeuk Kim 	struct f2fs_flush_device range;
2952d147ea4aSJaegeuk Kim 	struct f2fs_gc_control gc_control = {
2953d147ea4aSJaegeuk Kim 			.init_gc_type = FG_GC,
2954d147ea4aSJaegeuk Kim 			.should_migrate_blocks = true,
2955c81d5baeSJaegeuk Kim 			.err_gc_skipped = true,
2956c81d5baeSJaegeuk Kim 			.nr_free_secs = 0 };
2957e066b83cSJaegeuk Kim 	int ret;
2958e066b83cSJaegeuk Kim 
2959e066b83cSJaegeuk Kim 	if (!capable(CAP_SYS_ADMIN))
2960e066b83cSJaegeuk Kim 		return -EPERM;
2961e066b83cSJaegeuk Kim 
2962e066b83cSJaegeuk Kim 	if (f2fs_readonly(sbi->sb))
2963e066b83cSJaegeuk Kim 		return -EROFS;
2964e066b83cSJaegeuk Kim 
29654354994fSDaniel Rosenberg 	if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED)))
29664354994fSDaniel Rosenberg 		return -EINVAL;
29674354994fSDaniel Rosenberg 
2968e066b83cSJaegeuk Kim 	if (copy_from_user(&range, (struct f2fs_flush_device __user *)arg,
2969e066b83cSJaegeuk Kim 							sizeof(range)))
2970e066b83cSJaegeuk Kim 		return -EFAULT;
2971e066b83cSJaegeuk Kim 
29720916878dSDamien Le Moal 	if (!f2fs_is_multi_device(sbi) || sbi->s_ndevs - 1 <= range.dev_num ||
29732c70c5e3SChao Yu 			__is_large_section(sbi)) {
2974dcbb4c10SJoe Perches 		f2fs_warn(sbi, "Can't flush %u in %d for segs_per_sec %u != 1",
2975dcbb4c10SJoe Perches 			  range.dev_num, sbi->s_ndevs, sbi->segs_per_sec);
2976e066b83cSJaegeuk Kim 		return -EINVAL;
2977e066b83cSJaegeuk Kim 	}
2978e066b83cSJaegeuk Kim 
2979e066b83cSJaegeuk Kim 	ret = mnt_want_write_file(filp);
2980e066b83cSJaegeuk Kim 	if (ret)
2981e066b83cSJaegeuk Kim 		return ret;
2982e066b83cSJaegeuk Kim 
2983e066b83cSJaegeuk Kim 	if (range.dev_num != 0)
2984e066b83cSJaegeuk Kim 		dev_start_segno = GET_SEGNO(sbi, FDEV(range.dev_num).start_blk);
2985e066b83cSJaegeuk Kim 	dev_end_segno = GET_SEGNO(sbi, FDEV(range.dev_num).end_blk);
2986e066b83cSJaegeuk Kim 
2987e066b83cSJaegeuk Kim 	start_segno = sm->last_victim[FLUSH_DEVICE];
2988e066b83cSJaegeuk Kim 	if (start_segno < dev_start_segno || start_segno >= dev_end_segno)
2989e066b83cSJaegeuk Kim 		start_segno = dev_start_segno;
2990e066b83cSJaegeuk Kim 	end_segno = min(start_segno + range.segments, dev_end_segno);
2991e066b83cSJaegeuk Kim 
2992e066b83cSJaegeuk Kim 	while (start_segno < end_segno) {
2993e4544b63STim Murray 		if (!f2fs_down_write_trylock(&sbi->gc_lock)) {
2994e066b83cSJaegeuk Kim 			ret = -EBUSY;
2995e066b83cSJaegeuk Kim 			goto out;
2996e066b83cSJaegeuk Kim 		}
2997e066b83cSJaegeuk Kim 		sm->last_victim[GC_CB] = end_segno + 1;
2998e066b83cSJaegeuk Kim 		sm->last_victim[GC_GREEDY] = end_segno + 1;
2999e066b83cSJaegeuk Kim 		sm->last_victim[ALLOC_NEXT] = end_segno + 1;
3000d147ea4aSJaegeuk Kim 
3001d147ea4aSJaegeuk Kim 		gc_control.victim_segno = start_segno;
30029bf1dcbdSChao Yu 		stat_inc_gc_call_count(sbi, FOREGROUND);
3003d147ea4aSJaegeuk Kim 		ret = f2fs_gc(sbi, &gc_control);
3004e066b83cSJaegeuk Kim 		if (ret == -EAGAIN)
3005e066b83cSJaegeuk Kim 			ret = 0;
3006e066b83cSJaegeuk Kim 		else if (ret < 0)
3007e066b83cSJaegeuk Kim 			break;
3008e066b83cSJaegeuk Kim 		start_segno++;
3009e066b83cSJaegeuk Kim 	}
3010e066b83cSJaegeuk Kim out:
3011e066b83cSJaegeuk Kim 	mnt_drop_write_file(filp);
3012e066b83cSJaegeuk Kim 	return ret;
3013e066b83cSJaegeuk Kim }
3014e066b83cSJaegeuk Kim 
f2fs_ioc_get_features(struct file * filp,unsigned long arg)3015e65ef207SJaegeuk Kim static int f2fs_ioc_get_features(struct file *filp, unsigned long arg)
3016e65ef207SJaegeuk Kim {
3017e65ef207SJaegeuk Kim 	struct inode *inode = file_inode(filp);
3018e65ef207SJaegeuk Kim 	u32 sb_feature = le32_to_cpu(F2FS_I_SB(inode)->raw_super->feature);
3019e65ef207SJaegeuk Kim 
3020e65ef207SJaegeuk Kim 	/* Must validate to set it with SQLite behavior in Android. */
3021e65ef207SJaegeuk Kim 	sb_feature |= F2FS_FEATURE_ATOMIC_WRITE;
3022e65ef207SJaegeuk Kim 
3023e65ef207SJaegeuk Kim 	return put_user(sb_feature, (u32 __user *)arg);
3024e65ef207SJaegeuk Kim }
3025e066b83cSJaegeuk Kim 
30262c1d0305SChao Yu #ifdef CONFIG_QUOTA
f2fs_transfer_project_quota(struct inode * inode,kprojid_t kprojid)302778130819SChao Yu int f2fs_transfer_project_quota(struct inode *inode, kprojid_t kprojid)
302878130819SChao Yu {
302978130819SChao Yu 	struct dquot *transfer_to[MAXQUOTAS] = {};
303078130819SChao Yu 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
303178130819SChao Yu 	struct super_block *sb = sbi->sb;
30328051692fSYangtao Li 	int err;
303378130819SChao Yu 
303478130819SChao Yu 	transfer_to[PRJQUOTA] = dqget(sb, make_kqid_projid(kprojid));
30358051692fSYangtao Li 	if (IS_ERR(transfer_to[PRJQUOTA]))
30368051692fSYangtao Li 		return PTR_ERR(transfer_to[PRJQUOTA]);
30378051692fSYangtao Li 
303878130819SChao Yu 	err = __dquot_transfer(inode, transfer_to);
303978130819SChao Yu 	if (err)
304078130819SChao Yu 		set_sbi_flag(sbi, SBI_QUOTA_NEED_REPAIR);
304178130819SChao Yu 	dqput(transfer_to[PRJQUOTA]);
304278130819SChao Yu 	return err;
304378130819SChao Yu }
304478130819SChao Yu 
f2fs_ioc_setproject(struct inode * inode,__u32 projid)30459b1bb01cSMiklos Szeredi static int f2fs_ioc_setproject(struct inode *inode, __u32 projid)
30462c1d0305SChao Yu {
30472c1d0305SChao Yu 	struct f2fs_inode_info *fi = F2FS_I(inode);
30482c1d0305SChao Yu 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
3049d13732ccSJia Yang 	struct f2fs_inode *ri = NULL;
30502c1d0305SChao Yu 	kprojid_t kprojid;
30512c1d0305SChao Yu 	int err;
30522c1d0305SChao Yu 
30537beb01f7SChao Yu 	if (!f2fs_sb_has_project_quota(sbi)) {
30542c1d0305SChao Yu 		if (projid != F2FS_DEF_PROJID)
30552c1d0305SChao Yu 			return -EOPNOTSUPP;
30562c1d0305SChao Yu 		else
30572c1d0305SChao Yu 			return 0;
30582c1d0305SChao Yu 	}
30592c1d0305SChao Yu 
30602c1d0305SChao Yu 	if (!f2fs_has_extra_attr(inode))
30612c1d0305SChao Yu 		return -EOPNOTSUPP;
30622c1d0305SChao Yu 
30632c1d0305SChao Yu 	kprojid = make_kprojid(&init_user_ns, (projid_t)projid);
30642c1d0305SChao Yu 
3065054cb289SYufen Yu 	if (projid_eq(kprojid, fi->i_projid))
30662c1d0305SChao Yu 		return 0;
30672c1d0305SChao Yu 
30682c1d0305SChao Yu 	err = -EPERM;
30692c1d0305SChao Yu 	/* Is it quota file? Do not allow user to mess with it */
30702c1d0305SChao Yu 	if (IS_NOQUOTA(inode))
3071c8e92757SWang Shilong 		return err;
30722c1d0305SChao Yu 
3073d13732ccSJia Yang 	if (!F2FS_FITS_IN_INODE(ri, fi->i_extra_isize, i_projid))
3074d13732ccSJia Yang 		return -EOVERFLOW;
30752c1d0305SChao Yu 
307610a26878SChao Yu 	err = f2fs_dquot_initialize(inode);
3077c22aecd7SChao Yu 	if (err)
3078c8e92757SWang Shilong 		return err;
30792c1d0305SChao Yu 
308078130819SChao Yu 	f2fs_lock_op(sbi);
308178130819SChao Yu 	err = f2fs_transfer_project_quota(inode, kprojid);
30822c1d0305SChao Yu 	if (err)
308378130819SChao Yu 		goto out_unlock;
30842c1d0305SChao Yu 
3085054cb289SYufen Yu 	fi->i_projid = kprojid;
3086c62ebd35SJeff Layton 	inode_set_ctime_current(inode);
30872c1d0305SChao Yu 	f2fs_mark_inode_dirty_sync(inode, true);
308878130819SChao Yu out_unlock:
308978130819SChao Yu 	f2fs_unlock_op(sbi);
30902c1d0305SChao Yu 	return err;
30912c1d0305SChao Yu }
30922c1d0305SChao Yu #else
f2fs_transfer_project_quota(struct inode * inode,kprojid_t kprojid)309378130819SChao Yu int f2fs_transfer_project_quota(struct inode *inode, kprojid_t kprojid)
309478130819SChao Yu {
309578130819SChao Yu 	return 0;
309678130819SChao Yu }
309778130819SChao Yu 
f2fs_ioc_setproject(struct inode * inode,__u32 projid)30989b1bb01cSMiklos Szeredi static int f2fs_ioc_setproject(struct inode *inode, __u32 projid)
30992c1d0305SChao Yu {
31002c1d0305SChao Yu 	if (projid != F2FS_DEF_PROJID)
31012c1d0305SChao Yu 		return -EOPNOTSUPP;
31022c1d0305SChao Yu 	return 0;
31032c1d0305SChao Yu }
31042c1d0305SChao Yu #endif
31052c1d0305SChao Yu 
f2fs_fileattr_get(struct dentry * dentry,struct fileattr * fa)31069b1bb01cSMiklos Szeredi int f2fs_fileattr_get(struct dentry *dentry, struct fileattr *fa)
310736098557SEric Biggers {
31089b1bb01cSMiklos Szeredi 	struct inode *inode = d_inode(dentry);
31096fc93c4eSEric Biggers 	struct f2fs_inode_info *fi = F2FS_I(inode);
31109b1bb01cSMiklos Szeredi 	u32 fsflags = f2fs_iflags_to_fsflags(fi->i_flags);
31116fc93c4eSEric Biggers 
31129b1bb01cSMiklos Szeredi 	if (IS_ENCRYPTED(inode))
31139b1bb01cSMiklos Szeredi 		fsflags |= FS_ENCRYPT_FL;
31149b1bb01cSMiklos Szeredi 	if (IS_VERITY(inode))
31159b1bb01cSMiklos Szeredi 		fsflags |= FS_VERITY_FL;
31169b1bb01cSMiklos Szeredi 	if (f2fs_has_inline_data(inode) || f2fs_has_inline_dentry(inode))
31179b1bb01cSMiklos Szeredi 		fsflags |= FS_INLINE_DATA_FL;
31189b1bb01cSMiklos Szeredi 	if (is_inode_flag_set(inode, FI_PIN_FILE))
31199b1bb01cSMiklos Szeredi 		fsflags |= FS_NOCOW_FL;
31209b1bb01cSMiklos Szeredi 
31219b1bb01cSMiklos Szeredi 	fileattr_fill_flags(fa, fsflags & F2FS_GETTABLE_FS_FL);
31226fc93c4eSEric Biggers 
31236fc93c4eSEric Biggers 	if (f2fs_sb_has_project_quota(F2FS_I_SB(inode)))
31246fc93c4eSEric Biggers 		fa->fsx_projid = from_kprojid(&init_user_ns, fi->i_projid);
31256fc93c4eSEric Biggers 
31262c1d0305SChao Yu 	return 0;
31272c1d0305SChao Yu }
31282c1d0305SChao Yu 
f2fs_fileattr_set(struct mnt_idmap * idmap,struct dentry * dentry,struct fileattr * fa)31298782a9aeSChristian Brauner int f2fs_fileattr_set(struct mnt_idmap *idmap,
31309b1bb01cSMiklos Szeredi 		      struct dentry *dentry, struct fileattr *fa)
31312c1d0305SChao Yu {
31329b1bb01cSMiklos Szeredi 	struct inode *inode = d_inode(dentry);
31339b1bb01cSMiklos Szeredi 	u32 fsflags = fa->flags, mask = F2FS_SETTABLE_FS_FL;
313436098557SEric Biggers 	u32 iflags;
31352c1d0305SChao Yu 	int err;
31362c1d0305SChao Yu 
31379b1bb01cSMiklos Szeredi 	if (unlikely(f2fs_cp_error(F2FS_I_SB(inode))))
31389b1bb01cSMiklos Szeredi 		return -EIO;
31399b1bb01cSMiklos Szeredi 	if (!f2fs_is_checkpoint_ready(F2FS_I_SB(inode)))
31409b1bb01cSMiklos Szeredi 		return -ENOSPC;
31419b1bb01cSMiklos Szeredi 	if (fsflags & ~F2FS_GETTABLE_FS_FL)
31422c1d0305SChao Yu 		return -EOPNOTSUPP;
31439b1bb01cSMiklos Szeredi 	fsflags &= F2FS_SETTABLE_FS_FL;
31449b1bb01cSMiklos Szeredi 	if (!fa->flags_valid)
31459b1bb01cSMiklos Szeredi 		mask &= FS_COMMON_FL;
31462c1d0305SChao Yu 
31479b1bb01cSMiklos Szeredi 	iflags = f2fs_fsflags_to_iflags(fsflags);
314836098557SEric Biggers 	if (f2fs_mask_flags(inode->i_mode, iflags) != iflags)
31492c1d0305SChao Yu 		return -EOPNOTSUPP;
31502c1d0305SChao Yu 
31519b1bb01cSMiklos Szeredi 	err = f2fs_setflags_common(inode, iflags, f2fs_fsflags_to_iflags(mask));
31529b1bb01cSMiklos Szeredi 	if (!err)
31539b1bb01cSMiklos Szeredi 		err = f2fs_ioc_setproject(inode, fa->fsx_projid);
31542c1d0305SChao Yu 
31552c1d0305SChao Yu 	return err;
31562c1d0305SChao Yu }
315752656e6cSJaegeuk Kim 
f2fs_pin_file_control(struct inode * inode,bool inc)31581ad71a27SJaegeuk Kim int f2fs_pin_file_control(struct inode *inode, bool inc)
31591ad71a27SJaegeuk Kim {
31601ad71a27SJaegeuk Kim 	struct f2fs_inode_info *fi = F2FS_I(inode);
31611ad71a27SJaegeuk Kim 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
31621ad71a27SJaegeuk Kim 
31631ad71a27SJaegeuk Kim 	/* Use i_gc_failures for normal file as a risk signal. */
31641ad71a27SJaegeuk Kim 	if (inc)
31652ef79ecbSChao Yu 		f2fs_i_gc_failures_write(inode,
31662ef79ecbSChao Yu 				fi->i_gc_failures[GC_FAILURE_PIN] + 1);
31671ad71a27SJaegeuk Kim 
31682ef79ecbSChao Yu 	if (fi->i_gc_failures[GC_FAILURE_PIN] > sbi->gc_pin_file_threshold) {
3169dcbb4c10SJoe Perches 		f2fs_warn(sbi, "%s: Enable GC = ino %lx after %x GC trials",
31702ef79ecbSChao Yu 			  __func__, inode->i_ino,
31712ef79ecbSChao Yu 			  fi->i_gc_failures[GC_FAILURE_PIN]);
31721ad71a27SJaegeuk Kim 		clear_inode_flag(inode, FI_PIN_FILE);
31731ad71a27SJaegeuk Kim 		return -EAGAIN;
31741ad71a27SJaegeuk Kim 	}
31751ad71a27SJaegeuk Kim 	return 0;
31761ad71a27SJaegeuk Kim }
31771ad71a27SJaegeuk Kim 
f2fs_ioc_set_pin_file(struct file * filp,unsigned long arg)31781ad71a27SJaegeuk Kim static int f2fs_ioc_set_pin_file(struct file *filp, unsigned long arg)
31791ad71a27SJaegeuk Kim {
31801ad71a27SJaegeuk Kim 	struct inode *inode = file_inode(filp);
31811ad71a27SJaegeuk Kim 	__u32 pin;
31821ad71a27SJaegeuk Kim 	int ret = 0;
31831ad71a27SJaegeuk Kim 
31841ad71a27SJaegeuk Kim 	if (get_user(pin, (__u32 __user *)arg))
31851ad71a27SJaegeuk Kim 		return -EFAULT;
31861ad71a27SJaegeuk Kim 
31871ad71a27SJaegeuk Kim 	if (!S_ISREG(inode->i_mode))
31881ad71a27SJaegeuk Kim 		return -EINVAL;
31891ad71a27SJaegeuk Kim 
31901ad71a27SJaegeuk Kim 	if (f2fs_readonly(F2FS_I_SB(inode)->sb))
31911ad71a27SJaegeuk Kim 		return -EROFS;
31921ad71a27SJaegeuk Kim 
31931ad71a27SJaegeuk Kim 	ret = mnt_want_write_file(filp);
31941ad71a27SJaegeuk Kim 	if (ret)
31951ad71a27SJaegeuk Kim 		return ret;
31961ad71a27SJaegeuk Kim 
31971ad71a27SJaegeuk Kim 	inode_lock(inode);
31981ad71a27SJaegeuk Kim 
31991ad71a27SJaegeuk Kim 	if (!pin) {
32001ad71a27SJaegeuk Kim 		clear_inode_flag(inode, FI_PIN_FILE);
320130933364SChao Yu 		f2fs_i_gc_failures_write(inode, 0);
32021ad71a27SJaegeuk Kim 		goto done;
32031ad71a27SJaegeuk Kim 	}
32041ad71a27SJaegeuk Kim 
320519bdba52SJaegeuk Kim 	if (f2fs_should_update_outplace(inode, NULL)) {
320619bdba52SJaegeuk Kim 		ret = -EINVAL;
320719bdba52SJaegeuk Kim 		goto out;
320819bdba52SJaegeuk Kim 	}
320919bdba52SJaegeuk Kim 
32101ad71a27SJaegeuk Kim 	if (f2fs_pin_file_control(inode, false)) {
32111ad71a27SJaegeuk Kim 		ret = -EAGAIN;
32121ad71a27SJaegeuk Kim 		goto out;
32131ad71a27SJaegeuk Kim 	}
32144c8ff709SChao Yu 
32151ad71a27SJaegeuk Kim 	ret = f2fs_convert_inline_inode(inode);
32161ad71a27SJaegeuk Kim 	if (ret)
32171ad71a27SJaegeuk Kim 		goto out;
32181ad71a27SJaegeuk Kim 
321978134d03SDaeho Jeong 	if (!f2fs_disable_compressed_file(inode)) {
32204c8ff709SChao Yu 		ret = -EOPNOTSUPP;
32214c8ff709SChao Yu 		goto out;
32224c8ff709SChao Yu 	}
32234c8ff709SChao Yu 
32241ad71a27SJaegeuk Kim 	set_inode_flag(inode, FI_PIN_FILE);
32252ef79ecbSChao Yu 	ret = F2FS_I(inode)->i_gc_failures[GC_FAILURE_PIN];
32261ad71a27SJaegeuk Kim done:
32271ad71a27SJaegeuk Kim 	f2fs_update_time(F2FS_I_SB(inode), REQ_TIME);
32281ad71a27SJaegeuk Kim out:
32291ad71a27SJaegeuk Kim 	inode_unlock(inode);
32301ad71a27SJaegeuk Kim 	mnt_drop_write_file(filp);
32311ad71a27SJaegeuk Kim 	return ret;
32321ad71a27SJaegeuk Kim }
32331ad71a27SJaegeuk Kim 
f2fs_ioc_get_pin_file(struct file * filp,unsigned long arg)32341ad71a27SJaegeuk Kim static int f2fs_ioc_get_pin_file(struct file *filp, unsigned long arg)
32351ad71a27SJaegeuk Kim {
32361ad71a27SJaegeuk Kim 	struct inode *inode = file_inode(filp);
32371ad71a27SJaegeuk Kim 	__u32 pin = 0;
32381ad71a27SJaegeuk Kim 
32391ad71a27SJaegeuk Kim 	if (is_inode_flag_set(inode, FI_PIN_FILE))
32402ef79ecbSChao Yu 		pin = F2FS_I(inode)->i_gc_failures[GC_FAILURE_PIN];
32411ad71a27SJaegeuk Kim 	return put_user(pin, (u32 __user *)arg);
32421ad71a27SJaegeuk Kim }
32431ad71a27SJaegeuk Kim 
f2fs_precache_extents(struct inode * inode)3244c4020b2dSChao Yu int f2fs_precache_extents(struct inode *inode)
3245c4020b2dSChao Yu {
3246c4020b2dSChao Yu 	struct f2fs_inode_info *fi = F2FS_I(inode);
3247c4020b2dSChao Yu 	struct f2fs_map_blocks map;
3248c4020b2dSChao Yu 	pgoff_t m_next_extent;
3249c4020b2dSChao Yu 	loff_t end;
3250c4020b2dSChao Yu 	int err;
3251c4020b2dSChao Yu 
3252c4020b2dSChao Yu 	if (is_inode_flag_set(inode, FI_NO_EXTENT))
3253c4020b2dSChao Yu 		return -EOPNOTSUPP;
3254c4020b2dSChao Yu 
3255c4020b2dSChao Yu 	map.m_lblk = 0;
3256f1aeaf3cSChao Yu 	map.m_pblk = 0;
3257c4020b2dSChao Yu 	map.m_next_pgofs = NULL;
3258c4020b2dSChao Yu 	map.m_next_extent = &m_next_extent;
3259c4020b2dSChao Yu 	map.m_seg_type = NO_CHECK_TYPE;
3260f4f0b677SJia Zhu 	map.m_may_create = false;
32616d1451bfSChengguang Xu 	end = max_file_blocks(inode);
3262c4020b2dSChao Yu 
3263c4020b2dSChao Yu 	while (map.m_lblk < end) {
3264c4020b2dSChao Yu 		map.m_len = end - map.m_lblk;
3265c4020b2dSChao Yu 
3266e4544b63STim Murray 		f2fs_down_write(&fi->i_gc_rwsem[WRITE]);
3267cd8fc522SChristoph Hellwig 		err = f2fs_map_blocks(inode, &map, F2FS_GET_BLOCK_PRECACHE);
3268e4544b63STim Murray 		f2fs_up_write(&fi->i_gc_rwsem[WRITE]);
3269c4020b2dSChao Yu 		if (err)
3270c4020b2dSChao Yu 			return err;
3271c4020b2dSChao Yu 
3272c4020b2dSChao Yu 		map.m_lblk = m_next_extent;
3273c4020b2dSChao Yu 	}
3274c4020b2dSChao Yu 
32754f55dc2aSTom Rix 	return 0;
3276c4020b2dSChao Yu }
3277c4020b2dSChao Yu 
f2fs_ioc_precache_extents(struct file * filp)3278ddf1eca4SYangtao Li static int f2fs_ioc_precache_extents(struct file *filp)
3279c4020b2dSChao Yu {
3280c4020b2dSChao Yu 	return f2fs_precache_extents(file_inode(filp));
3281c4020b2dSChao Yu }
3282c4020b2dSChao Yu 
f2fs_ioc_resize_fs(struct file * filp,unsigned long arg)328304f0b2eaSQiuyang Sun static int f2fs_ioc_resize_fs(struct file *filp, unsigned long arg)
328404f0b2eaSQiuyang Sun {
328504f0b2eaSQiuyang Sun 	struct f2fs_sb_info *sbi = F2FS_I_SB(file_inode(filp));
328604f0b2eaSQiuyang Sun 	__u64 block_count;
328704f0b2eaSQiuyang Sun 
328804f0b2eaSQiuyang Sun 	if (!capable(CAP_SYS_ADMIN))
328904f0b2eaSQiuyang Sun 		return -EPERM;
329004f0b2eaSQiuyang Sun 
329104f0b2eaSQiuyang Sun 	if (f2fs_readonly(sbi->sb))
329204f0b2eaSQiuyang Sun 		return -EROFS;
329304f0b2eaSQiuyang Sun 
329404f0b2eaSQiuyang Sun 	if (copy_from_user(&block_count, (void __user *)arg,
329504f0b2eaSQiuyang Sun 			   sizeof(block_count)))
329604f0b2eaSQiuyang Sun 		return -EFAULT;
329704f0b2eaSQiuyang Sun 
3298d8189834SChao Yu 	return f2fs_resize_fs(filp, block_count);
329904f0b2eaSQiuyang Sun }
330004f0b2eaSQiuyang Sun 
f2fs_ioc_enable_verity(struct file * filp,unsigned long arg)330195ae251fSEric Biggers static int f2fs_ioc_enable_verity(struct file *filp, unsigned long arg)
330295ae251fSEric Biggers {
330395ae251fSEric Biggers 	struct inode *inode = file_inode(filp);
330495ae251fSEric Biggers 
330595ae251fSEric Biggers 	f2fs_update_time(F2FS_I_SB(inode), REQ_TIME);
330695ae251fSEric Biggers 
330795ae251fSEric Biggers 	if (!f2fs_sb_has_verity(F2FS_I_SB(inode))) {
330895ae251fSEric Biggers 		f2fs_warn(F2FS_I_SB(inode),
3309833dcd35SJoe Perches 			  "Can't enable fs-verity on inode %lu: the verity feature is not enabled on this filesystem",
331095ae251fSEric Biggers 			  inode->i_ino);
331195ae251fSEric Biggers 		return -EOPNOTSUPP;
331295ae251fSEric Biggers 	}
331395ae251fSEric Biggers 
331495ae251fSEric Biggers 	return fsverity_ioctl_enable(filp, (const void __user *)arg);
331595ae251fSEric Biggers }
331695ae251fSEric Biggers 
f2fs_ioc_measure_verity(struct file * filp,unsigned long arg)331795ae251fSEric Biggers static int f2fs_ioc_measure_verity(struct file *filp, unsigned long arg)
331895ae251fSEric Biggers {
331995ae251fSEric Biggers 	if (!f2fs_sb_has_verity(F2FS_I_SB(file_inode(filp))))
332095ae251fSEric Biggers 		return -EOPNOTSUPP;
332195ae251fSEric Biggers 
332295ae251fSEric Biggers 	return fsverity_ioctl_measure(filp, (void __user *)arg);
332395ae251fSEric Biggers }
332495ae251fSEric Biggers 
f2fs_ioc_read_verity_metadata(struct file * filp,unsigned long arg)3325e17fe657SEric Biggers static int f2fs_ioc_read_verity_metadata(struct file *filp, unsigned long arg)
3326e17fe657SEric Biggers {
3327e17fe657SEric Biggers 	if (!f2fs_sb_has_verity(F2FS_I_SB(file_inode(filp))))
3328e17fe657SEric Biggers 		return -EOPNOTSUPP;
3329e17fe657SEric Biggers 
3330e17fe657SEric Biggers 	return fsverity_ioctl_read_metadata(filp, (const void __user *)arg);
3331e17fe657SEric Biggers }
3332e17fe657SEric Biggers 
f2fs_ioc_getfslabel(struct file * filp,unsigned long arg)33333357af8fSEric Biggers static int f2fs_ioc_getfslabel(struct file *filp, unsigned long arg)
33344507847cSChao Yu {
33354507847cSChao Yu 	struct inode *inode = file_inode(filp);
33364507847cSChao Yu 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
33374507847cSChao Yu 	char *vbuf;
33384507847cSChao Yu 	int count;
33394507847cSChao Yu 	int err = 0;
33404507847cSChao Yu 
33414507847cSChao Yu 	vbuf = f2fs_kzalloc(sbi, MAX_VOLUME_NAME, GFP_KERNEL);
33424507847cSChao Yu 	if (!vbuf)
33434507847cSChao Yu 		return -ENOMEM;
33444507847cSChao Yu 
3345e4544b63STim Murray 	f2fs_down_read(&sbi->sb_lock);
33464507847cSChao Yu 	count = utf16s_to_utf8s(sbi->raw_super->volume_name,
33474507847cSChao Yu 			ARRAY_SIZE(sbi->raw_super->volume_name),
33484507847cSChao Yu 			UTF16_LITTLE_ENDIAN, vbuf, MAX_VOLUME_NAME);
3349e4544b63STim Murray 	f2fs_up_read(&sbi->sb_lock);
33504507847cSChao Yu 
33514507847cSChao Yu 	if (copy_to_user((char __user *)arg, vbuf,
33524507847cSChao Yu 				min(FSLABEL_MAX, count)))
33534507847cSChao Yu 		err = -EFAULT;
33544507847cSChao Yu 
3355c8eb7024SChao Yu 	kfree(vbuf);
33564507847cSChao Yu 	return err;
33574507847cSChao Yu }
33584507847cSChao Yu 
f2fs_ioc_setfslabel(struct file * filp,unsigned long arg)33593357af8fSEric Biggers static int f2fs_ioc_setfslabel(struct file *filp, unsigned long arg)
33604507847cSChao Yu {
33614507847cSChao Yu 	struct inode *inode = file_inode(filp);
33624507847cSChao Yu 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
33634507847cSChao Yu 	char *vbuf;
33644507847cSChao Yu 	int err = 0;
33654507847cSChao Yu 
33664507847cSChao Yu 	if (!capable(CAP_SYS_ADMIN))
33674507847cSChao Yu 		return -EPERM;
33684507847cSChao Yu 
33694507847cSChao Yu 	vbuf = strndup_user((const char __user *)arg, FSLABEL_MAX);
33704507847cSChao Yu 	if (IS_ERR(vbuf))
33714507847cSChao Yu 		return PTR_ERR(vbuf);
33724507847cSChao Yu 
33734507847cSChao Yu 	err = mnt_want_write_file(filp);
33744507847cSChao Yu 	if (err)
33754507847cSChao Yu 		goto out;
33764507847cSChao Yu 
3377e4544b63STim Murray 	f2fs_down_write(&sbi->sb_lock);
33784507847cSChao Yu 
33794507847cSChao Yu 	memset(sbi->raw_super->volume_name, 0,
33804507847cSChao Yu 			sizeof(sbi->raw_super->volume_name));
33814507847cSChao Yu 	utf8s_to_utf16s(vbuf, strlen(vbuf), UTF16_LITTLE_ENDIAN,
33824507847cSChao Yu 			sbi->raw_super->volume_name,
33834507847cSChao Yu 			ARRAY_SIZE(sbi->raw_super->volume_name));
33844507847cSChao Yu 
33854507847cSChao Yu 	err = f2fs_commit_super(sbi, false);
33864507847cSChao Yu 
3387e4544b63STim Murray 	f2fs_up_write(&sbi->sb_lock);
33884507847cSChao Yu 
33894507847cSChao Yu 	mnt_drop_write_file(filp);
33904507847cSChao Yu out:
33914507847cSChao Yu 	kfree(vbuf);
33924507847cSChao Yu 	return err;
33934507847cSChao Yu }
33944507847cSChao Yu 
f2fs_get_compress_blocks(struct inode * inode,__u64 * blocks)3395ac1ee161SSheng Yong static int f2fs_get_compress_blocks(struct inode *inode, __u64 *blocks)
3396439dfb10SChao Yu {
3397439dfb10SChao Yu 	if (!f2fs_sb_has_compression(F2FS_I_SB(inode)))
3398439dfb10SChao Yu 		return -EOPNOTSUPP;
3399439dfb10SChao Yu 
3400439dfb10SChao Yu 	if (!f2fs_compressed_file(inode))
3401439dfb10SChao Yu 		return -EINVAL;
3402439dfb10SChao Yu 
3403ac1ee161SSheng Yong 	*blocks = atomic_read(&F2FS_I(inode)->i_compr_blocks);
3404ac1ee161SSheng Yong 
3405ac1ee161SSheng Yong 	return 0;
3406ac1ee161SSheng Yong }
3407ac1ee161SSheng Yong 
f2fs_ioc_get_compress_blocks(struct file * filp,unsigned long arg)3408ac1ee161SSheng Yong static int f2fs_ioc_get_compress_blocks(struct file *filp, unsigned long arg)
3409ac1ee161SSheng Yong {
3410ac1ee161SSheng Yong 	struct inode *inode = file_inode(filp);
3411ac1ee161SSheng Yong 	__u64 blocks;
3412ac1ee161SSheng Yong 	int ret;
3413ac1ee161SSheng Yong 
3414ac1ee161SSheng Yong 	ret = f2fs_get_compress_blocks(inode, &blocks);
3415ac1ee161SSheng Yong 	if (ret < 0)
3416ac1ee161SSheng Yong 		return ret;
3417ac1ee161SSheng Yong 
3418439dfb10SChao Yu 	return put_user(blocks, (u64 __user *)arg);
3419439dfb10SChao Yu }
3420439dfb10SChao Yu 
release_compress_blocks(struct dnode_of_data * dn,pgoff_t count)3421ef8d563fSChao Yu static int release_compress_blocks(struct dnode_of_data *dn, pgoff_t count)
3422ef8d563fSChao Yu {
3423ef8d563fSChao Yu 	struct f2fs_sb_info *sbi = F2FS_I_SB(dn->inode);
3424ef8d563fSChao Yu 	unsigned int released_blocks = 0;
3425ef8d563fSChao Yu 	int cluster_size = F2FS_I(dn->inode)->i_cluster_size;
3426ef8d563fSChao Yu 	block_t blkaddr;
3427ef8d563fSChao Yu 	int i;
3428ef8d563fSChao Yu 
3429ef8d563fSChao Yu 	for (i = 0; i < count; i++) {
3430ef8d563fSChao Yu 		blkaddr = data_blkaddr(dn->inode, dn->node_page,
3431ef8d563fSChao Yu 						dn->ofs_in_node + i);
3432ef8d563fSChao Yu 
3433ef8d563fSChao Yu 		if (!__is_valid_data_blkaddr(blkaddr))
3434ef8d563fSChao Yu 			continue;
3435ef8d563fSChao Yu 		if (unlikely(!f2fs_is_valid_blkaddr(sbi, blkaddr,
343695fa90c9SChao Yu 					DATA_GENERIC_ENHANCE))) {
343795fa90c9SChao Yu 			f2fs_handle_error(sbi, ERROR_INVALID_BLKADDR);
3438ef8d563fSChao Yu 			return -EFSCORRUPTED;
3439ef8d563fSChao Yu 		}
344095fa90c9SChao Yu 	}
3441ef8d563fSChao Yu 
3442ef8d563fSChao Yu 	while (count) {
3443ef8d563fSChao Yu 		int compr_blocks = 0;
3444ef8d563fSChao Yu 
3445ef8d563fSChao Yu 		for (i = 0; i < cluster_size; i++, dn->ofs_in_node++) {
3446ef8d563fSChao Yu 			blkaddr = f2fs_data_blkaddr(dn);
3447ef8d563fSChao Yu 
3448ef8d563fSChao Yu 			if (i == 0) {
3449ef8d563fSChao Yu 				if (blkaddr == COMPRESS_ADDR)
3450ef8d563fSChao Yu 					continue;
3451ef8d563fSChao Yu 				dn->ofs_in_node += cluster_size;
3452ef8d563fSChao Yu 				goto next;
3453ef8d563fSChao Yu 			}
3454ef8d563fSChao Yu 
3455ef8d563fSChao Yu 			if (__is_valid_data_blkaddr(blkaddr))
3456ef8d563fSChao Yu 				compr_blocks++;
3457ef8d563fSChao Yu 
3458ef8d563fSChao Yu 			if (blkaddr != NEW_ADDR)
3459ef8d563fSChao Yu 				continue;
3460ef8d563fSChao Yu 
3461eb6d30bcSChao Yu 			f2fs_set_data_blkaddr(dn, NULL_ADDR);
3462ef8d563fSChao Yu 		}
3463ef8d563fSChao Yu 
3464ef8d563fSChao Yu 		f2fs_i_compr_blocks_update(dn->inode, compr_blocks, false);
3465ef8d563fSChao Yu 		dec_valid_block_count(sbi, dn->inode,
3466ef8d563fSChao Yu 					cluster_size - compr_blocks);
3467ef8d563fSChao Yu 
3468ef8d563fSChao Yu 		released_blocks += cluster_size - compr_blocks;
3469ef8d563fSChao Yu next:
3470ef8d563fSChao Yu 		count -= cluster_size;
3471ef8d563fSChao Yu 	}
3472ef8d563fSChao Yu 
3473ef8d563fSChao Yu 	return released_blocks;
3474ef8d563fSChao Yu }
3475ef8d563fSChao Yu 
f2fs_release_compress_blocks(struct file * filp,unsigned long arg)3476ef8d563fSChao Yu static int f2fs_release_compress_blocks(struct file *filp, unsigned long arg)
3477ef8d563fSChao Yu {
3478ef8d563fSChao Yu 	struct inode *inode = file_inode(filp);
3479ef8d563fSChao Yu 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
3480ef8d563fSChao Yu 	pgoff_t page_idx = 0, last_idx;
3481ef8d563fSChao Yu 	unsigned int released_blocks = 0;
3482ef8d563fSChao Yu 	int ret;
3483ef8d563fSChao Yu 	int writecount;
3484ef8d563fSChao Yu 
3485c3355ea9SYangtao Li 	if (!f2fs_sb_has_compression(sbi))
3486ef8d563fSChao Yu 		return -EOPNOTSUPP;
3487ef8d563fSChao Yu 
3488ef8d563fSChao Yu 	if (!f2fs_compressed_file(inode))
3489ef8d563fSChao Yu 		return -EINVAL;
3490ef8d563fSChao Yu 
3491ef8d563fSChao Yu 	if (f2fs_readonly(sbi->sb))
3492ef8d563fSChao Yu 		return -EROFS;
3493ef8d563fSChao Yu 
3494ef8d563fSChao Yu 	ret = mnt_want_write_file(filp);
3495ef8d563fSChao Yu 	if (ret)
3496ef8d563fSChao Yu 		return ret;
3497ef8d563fSChao Yu 
3498c3355ea9SYangtao Li 	f2fs_balance_fs(sbi, true);
3499ef8d563fSChao Yu 
3500ef8d563fSChao Yu 	inode_lock(inode);
3501ef8d563fSChao Yu 
3502ef8d563fSChao Yu 	writecount = atomic_read(&inode->i_writecount);
35038c8cf26aSDaeho Jeong 	if ((filp->f_mode & FMODE_WRITE && writecount != 1) ||
35048c8cf26aSDaeho Jeong 			(!(filp->f_mode & FMODE_WRITE) && writecount)) {
3505ef8d563fSChao Yu 		ret = -EBUSY;
3506ef8d563fSChao Yu 		goto out;
3507ef8d563fSChao Yu 	}
3508ef8d563fSChao Yu 
3509c6140415SJaegeuk Kim 	if (is_inode_flag_set(inode, FI_COMPRESS_RELEASED)) {
3510ef8d563fSChao Yu 		ret = -EINVAL;
3511ef8d563fSChao Yu 		goto out;
3512ef8d563fSChao Yu 	}
3513ef8d563fSChao Yu 
3514ef8d563fSChao Yu 	ret = filemap_write_and_wait_range(inode->i_mapping, 0, LLONG_MAX);
3515ef8d563fSChao Yu 	if (ret)
3516ef8d563fSChao Yu 		goto out;
3517ef8d563fSChao Yu 
351887a91a15SSheng Yong 	if (!atomic_read(&F2FS_I(inode)->i_compr_blocks)) {
351987a91a15SSheng Yong 		ret = -EPERM;
352087a91a15SSheng Yong 		goto out;
352187a91a15SSheng Yong 	}
352287a91a15SSheng Yong 
3523c6140415SJaegeuk Kim 	set_inode_flag(inode, FI_COMPRESS_RELEASED);
3524c62ebd35SJeff Layton 	inode_set_ctime_current(inode);
3525ef8d563fSChao Yu 	f2fs_mark_inode_dirty_sync(inode, true);
3526ef8d563fSChao Yu 
3527e4544b63STim Murray 	f2fs_down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
3528edc6d01bSJan Kara 	filemap_invalidate_lock(inode->i_mapping);
3529ef8d563fSChao Yu 
3530ef8d563fSChao Yu 	last_idx = DIV_ROUND_UP(i_size_read(inode), PAGE_SIZE);
3531ef8d563fSChao Yu 
3532ef8d563fSChao Yu 	while (page_idx < last_idx) {
3533ef8d563fSChao Yu 		struct dnode_of_data dn;
3534ef8d563fSChao Yu 		pgoff_t end_offset, count;
3535ef8d563fSChao Yu 
3536ef8d563fSChao Yu 		set_new_dnode(&dn, inode, NULL, NULL, 0);
3537ef8d563fSChao Yu 		ret = f2fs_get_dnode_of_data(&dn, page_idx, LOOKUP_NODE);
3538ef8d563fSChao Yu 		if (ret) {
3539ef8d563fSChao Yu 			if (ret == -ENOENT) {
3540ef8d563fSChao Yu 				page_idx = f2fs_get_next_page_offset(&dn,
3541ef8d563fSChao Yu 								page_idx);
3542ef8d563fSChao Yu 				ret = 0;
3543ef8d563fSChao Yu 				continue;
3544ef8d563fSChao Yu 			}
3545ef8d563fSChao Yu 			break;
3546ef8d563fSChao Yu 		}
3547ef8d563fSChao Yu 
3548ef8d563fSChao Yu 		end_offset = ADDRS_PER_PAGE(dn.node_page, inode);
3549ef8d563fSChao Yu 		count = min(end_offset - dn.ofs_in_node, last_idx - page_idx);
35504fec3fc0SChao Yu 		count = round_up(count, F2FS_I(inode)->i_cluster_size);
3551ef8d563fSChao Yu 
3552ef8d563fSChao Yu 		ret = release_compress_blocks(&dn, count);
3553ef8d563fSChao Yu 
3554ef8d563fSChao Yu 		f2fs_put_dnode(&dn);
3555ef8d563fSChao Yu 
3556ef8d563fSChao Yu 		if (ret < 0)
3557ef8d563fSChao Yu 			break;
3558ef8d563fSChao Yu 
3559ef8d563fSChao Yu 		page_idx += count;
3560ef8d563fSChao Yu 		released_blocks += ret;
3561ef8d563fSChao Yu 	}
3562ef8d563fSChao Yu 
3563edc6d01bSJan Kara 	filemap_invalidate_unlock(inode->i_mapping);
3564e4544b63STim Murray 	f2fs_up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
3565ef8d563fSChao Yu out:
3566ef8d563fSChao Yu 	inode_unlock(inode);
3567ef8d563fSChao Yu 
3568ef8d563fSChao Yu 	mnt_drop_write_file(filp);
3569ef8d563fSChao Yu 
3570ef8d563fSChao Yu 	if (ret >= 0) {
3571ef8d563fSChao Yu 		ret = put_user(released_blocks, (u64 __user *)arg);
3572c2759ebaSDaeho Jeong 	} else if (released_blocks &&
3573c2759ebaSDaeho Jeong 			atomic_read(&F2FS_I(inode)->i_compr_blocks)) {
3574ef8d563fSChao Yu 		set_sbi_flag(sbi, SBI_NEED_FSCK);
3575ef8d563fSChao Yu 		f2fs_warn(sbi, "%s: partial blocks were released i_ino=%lx "
3576c2759ebaSDaeho Jeong 			"iblocks=%llu, released=%u, compr_blocks=%u, "
3577ef8d563fSChao Yu 			"run fsck to fix.",
3578ef8d563fSChao Yu 			__func__, inode->i_ino, inode->i_blocks,
3579ef8d563fSChao Yu 			released_blocks,
3580c2759ebaSDaeho Jeong 			atomic_read(&F2FS_I(inode)->i_compr_blocks));
3581ef8d563fSChao Yu 	}
3582ef8d563fSChao Yu 
3583ef8d563fSChao Yu 	return ret;
3584ef8d563fSChao Yu }
3585ef8d563fSChao Yu 
reserve_compress_blocks(struct dnode_of_data * dn,pgoff_t count,unsigned int * reserved_blocks)3586*f0bf89e8SXiuhong Wang static int reserve_compress_blocks(struct dnode_of_data *dn, pgoff_t count,
3587*f0bf89e8SXiuhong Wang 		unsigned int *reserved_blocks)
3588c75488fbSChao Yu {
3589c75488fbSChao Yu 	struct f2fs_sb_info *sbi = F2FS_I_SB(dn->inode);
3590c75488fbSChao Yu 	int cluster_size = F2FS_I(dn->inode)->i_cluster_size;
3591c75488fbSChao Yu 	block_t blkaddr;
3592c75488fbSChao Yu 	int i;
3593c75488fbSChao Yu 
3594c75488fbSChao Yu 	for (i = 0; i < count; i++) {
3595c75488fbSChao Yu 		blkaddr = data_blkaddr(dn->inode, dn->node_page,
3596c75488fbSChao Yu 						dn->ofs_in_node + i);
3597c75488fbSChao Yu 
3598c75488fbSChao Yu 		if (!__is_valid_data_blkaddr(blkaddr))
3599c75488fbSChao Yu 			continue;
3600c75488fbSChao Yu 		if (unlikely(!f2fs_is_valid_blkaddr(sbi, blkaddr,
360195fa90c9SChao Yu 					DATA_GENERIC_ENHANCE))) {
360295fa90c9SChao Yu 			f2fs_handle_error(sbi, ERROR_INVALID_BLKADDR);
3603c75488fbSChao Yu 			return -EFSCORRUPTED;
3604c75488fbSChao Yu 		}
360595fa90c9SChao Yu 	}
3606c75488fbSChao Yu 
3607c75488fbSChao Yu 	while (count) {
3608c75488fbSChao Yu 		int compr_blocks = 0;
3609c75488fbSChao Yu 		blkcnt_t reserved;
3610c75488fbSChao Yu 		int ret;
3611c75488fbSChao Yu 
3612bc1e3992SChao Yu 		for (i = 0; i < cluster_size; i++) {
3613bc1e3992SChao Yu 			blkaddr = data_blkaddr(dn->inode, dn->node_page,
3614bc1e3992SChao Yu 						dn->ofs_in_node + i);
3615c75488fbSChao Yu 
3616c75488fbSChao Yu 			if (i == 0) {
3617bc1e3992SChao Yu 				if (blkaddr != COMPRESS_ADDR) {
3618c75488fbSChao Yu 					dn->ofs_in_node += cluster_size;
3619c75488fbSChao Yu 					goto next;
3620c75488fbSChao Yu 				}
3621bc1e3992SChao Yu 				continue;
3622bc1e3992SChao Yu 			}
3623c75488fbSChao Yu 
3624d415e1c9SSheng Yong 			/*
3625d415e1c9SSheng Yong 			 * compressed cluster was not released due to it
3626d415e1c9SSheng Yong 			 * fails in release_compress_blocks(), so NEW_ADDR
3627d415e1c9SSheng Yong 			 * is a possible case.
3628d415e1c9SSheng Yong 			 */
3629d415e1c9SSheng Yong 			if (blkaddr == NEW_ADDR ||
3630d415e1c9SSheng Yong 				__is_valid_data_blkaddr(blkaddr)) {
3631c75488fbSChao Yu 				compr_blocks++;
3632c75488fbSChao Yu 				continue;
3633c75488fbSChao Yu 			}
3634c75488fbSChao Yu 		}
3635c75488fbSChao Yu 
3636c75488fbSChao Yu 		reserved = cluster_size - compr_blocks;
3637d415e1c9SSheng Yong 
3638d415e1c9SSheng Yong 		/* for the case all blocks in cluster were reserved */
3639d415e1c9SSheng Yong 		if (reserved == 1)
3640d415e1c9SSheng Yong 			goto next;
3641d415e1c9SSheng Yong 
3642bc1e3992SChao Yu 		ret = inc_valid_block_count(sbi, dn->inode, &reserved, false);
3643bc1e3992SChao Yu 		if (unlikely(ret))
3644c75488fbSChao Yu 			return ret;
3645c75488fbSChao Yu 
3646bc1e3992SChao Yu 		for (i = 0; i < cluster_size; i++, dn->ofs_in_node++) {
3647bc1e3992SChao Yu 			if (f2fs_data_blkaddr(dn) == NULL_ADDR)
3648bc1e3992SChao Yu 				f2fs_set_data_blkaddr(dn, NEW_ADDR);
3649bc1e3992SChao Yu 		}
3650c75488fbSChao Yu 
3651c75488fbSChao Yu 		f2fs_i_compr_blocks_update(dn->inode, compr_blocks, true);
3652c75488fbSChao Yu 
3653*f0bf89e8SXiuhong Wang 		*reserved_blocks += reserved;
3654c75488fbSChao Yu next:
3655c75488fbSChao Yu 		count -= cluster_size;
3656c75488fbSChao Yu 	}
3657c75488fbSChao Yu 
3658*f0bf89e8SXiuhong Wang 	return 0;
3659c75488fbSChao Yu }
3660c75488fbSChao Yu 
f2fs_reserve_compress_blocks(struct file * filp,unsigned long arg)3661c75488fbSChao Yu static int f2fs_reserve_compress_blocks(struct file *filp, unsigned long arg)
3662c75488fbSChao Yu {
3663c75488fbSChao Yu 	struct inode *inode = file_inode(filp);
3664c75488fbSChao Yu 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
3665c75488fbSChao Yu 	pgoff_t page_idx = 0, last_idx;
3666c75488fbSChao Yu 	unsigned int reserved_blocks = 0;
3667c75488fbSChao Yu 	int ret;
3668c75488fbSChao Yu 
3669c3355ea9SYangtao Li 	if (!f2fs_sb_has_compression(sbi))
3670c75488fbSChao Yu 		return -EOPNOTSUPP;
3671c75488fbSChao Yu 
3672c75488fbSChao Yu 	if (!f2fs_compressed_file(inode))
3673c75488fbSChao Yu 		return -EINVAL;
3674c75488fbSChao Yu 
3675c75488fbSChao Yu 	if (f2fs_readonly(sbi->sb))
3676c75488fbSChao Yu 		return -EROFS;
3677c75488fbSChao Yu 
3678c75488fbSChao Yu 	ret = mnt_want_write_file(filp);
3679c75488fbSChao Yu 	if (ret)
3680c75488fbSChao Yu 		return ret;
3681c75488fbSChao Yu 
3682c3355ea9SYangtao Li 	f2fs_balance_fs(sbi, true);
3683c75488fbSChao Yu 
3684c75488fbSChao Yu 	inode_lock(inode);
3685c75488fbSChao Yu 
3686c6140415SJaegeuk Kim 	if (!is_inode_flag_set(inode, FI_COMPRESS_RELEASED)) {
3687c75488fbSChao Yu 		ret = -EINVAL;
3688c75488fbSChao Yu 		goto unlock_inode;
3689c75488fbSChao Yu 	}
3690c75488fbSChao Yu 
36914d1a3b79SXiuhong Wang 	if (atomic_read(&F2FS_I(inode)->i_compr_blocks))
36924d1a3b79SXiuhong Wang 		goto unlock_inode;
36934d1a3b79SXiuhong Wang 
3694e4544b63STim Murray 	f2fs_down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
3695edc6d01bSJan Kara 	filemap_invalidate_lock(inode->i_mapping);
3696c75488fbSChao Yu 
3697c75488fbSChao Yu 	last_idx = DIV_ROUND_UP(i_size_read(inode), PAGE_SIZE);
3698c75488fbSChao Yu 
3699c75488fbSChao Yu 	while (page_idx < last_idx) {
3700c75488fbSChao Yu 		struct dnode_of_data dn;
3701c75488fbSChao Yu 		pgoff_t end_offset, count;
3702c75488fbSChao Yu 
3703c75488fbSChao Yu 		set_new_dnode(&dn, inode, NULL, NULL, 0);
3704c75488fbSChao Yu 		ret = f2fs_get_dnode_of_data(&dn, page_idx, LOOKUP_NODE);
3705c75488fbSChao Yu 		if (ret) {
3706c75488fbSChao Yu 			if (ret == -ENOENT) {
3707c75488fbSChao Yu 				page_idx = f2fs_get_next_page_offset(&dn,
3708c75488fbSChao Yu 								page_idx);
3709c75488fbSChao Yu 				ret = 0;
3710c75488fbSChao Yu 				continue;
3711c75488fbSChao Yu 			}
3712c75488fbSChao Yu 			break;
3713c75488fbSChao Yu 		}
3714c75488fbSChao Yu 
3715c75488fbSChao Yu 		end_offset = ADDRS_PER_PAGE(dn.node_page, inode);
3716c75488fbSChao Yu 		count = min(end_offset - dn.ofs_in_node, last_idx - page_idx);
37174fec3fc0SChao Yu 		count = round_up(count, F2FS_I(inode)->i_cluster_size);
3718c75488fbSChao Yu 
3719*f0bf89e8SXiuhong Wang 		ret = reserve_compress_blocks(&dn, count, &reserved_blocks);
3720c75488fbSChao Yu 
3721c75488fbSChao Yu 		f2fs_put_dnode(&dn);
3722c75488fbSChao Yu 
3723c75488fbSChao Yu 		if (ret < 0)
3724c75488fbSChao Yu 			break;
3725c75488fbSChao Yu 
3726c75488fbSChao Yu 		page_idx += count;
3727c75488fbSChao Yu 	}
3728c75488fbSChao Yu 
3729edc6d01bSJan Kara 	filemap_invalidate_unlock(inode->i_mapping);
3730e4544b63STim Murray 	f2fs_up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
3731c75488fbSChao Yu 
3732*f0bf89e8SXiuhong Wang 	if (!ret) {
3733c6140415SJaegeuk Kim 		clear_inode_flag(inode, FI_COMPRESS_RELEASED);
3734c62ebd35SJeff Layton 		inode_set_ctime_current(inode);
3735c75488fbSChao Yu 		f2fs_mark_inode_dirty_sync(inode, true);
3736c75488fbSChao Yu 	}
3737c75488fbSChao Yu unlock_inode:
3738c75488fbSChao Yu 	inode_unlock(inode);
3739c75488fbSChao Yu 	mnt_drop_write_file(filp);
3740c75488fbSChao Yu 
3741*f0bf89e8SXiuhong Wang 	if (!ret) {
3742c75488fbSChao Yu 		ret = put_user(reserved_blocks, (u64 __user *)arg);
3743c2759ebaSDaeho Jeong 	} else if (reserved_blocks &&
3744c2759ebaSDaeho Jeong 			atomic_read(&F2FS_I(inode)->i_compr_blocks)) {
3745c75488fbSChao Yu 		set_sbi_flag(sbi, SBI_NEED_FSCK);
3746c75488fbSChao Yu 		f2fs_warn(sbi, "%s: partial blocks were released i_ino=%lx "
3747c2759ebaSDaeho Jeong 			"iblocks=%llu, reserved=%u, compr_blocks=%u, "
3748c75488fbSChao Yu 			"run fsck to fix.",
3749c75488fbSChao Yu 			__func__, inode->i_ino, inode->i_blocks,
3750c75488fbSChao Yu 			reserved_blocks,
3751c2759ebaSDaeho Jeong 			atomic_read(&F2FS_I(inode)->i_compr_blocks));
3752c75488fbSChao Yu 	}
3753c75488fbSChao Yu 
3754c75488fbSChao Yu 	return ret;
3755c75488fbSChao Yu }
3756c75488fbSChao Yu 
f2fs_secure_erase(struct block_device * bdev,struct inode * inode,pgoff_t off,block_t block,block_t len,u32 flags)37579af84648SDaeho Jeong static int f2fs_secure_erase(struct block_device *bdev, struct inode *inode,
37589af84648SDaeho Jeong 		pgoff_t off, block_t block, block_t len, u32 flags)
37599af84648SDaeho Jeong {
37609af84648SDaeho Jeong 	sector_t sector = SECTOR_FROM_BLOCK(block);
37619af84648SDaeho Jeong 	sector_t nr_sects = SECTOR_FROM_BLOCK(len);
37629af84648SDaeho Jeong 	int ret = 0;
37639af84648SDaeho Jeong 
376444abff2cSChristoph Hellwig 	if (flags & F2FS_TRIM_FILE_DISCARD) {
376544abff2cSChristoph Hellwig 		if (bdev_max_secure_erase_sectors(bdev))
376644abff2cSChristoph Hellwig 			ret = blkdev_issue_secure_erase(bdev, sector, nr_sects,
376744abff2cSChristoph Hellwig 					GFP_NOFS);
376844abff2cSChristoph Hellwig 		else
376944abff2cSChristoph Hellwig 			ret = blkdev_issue_discard(bdev, sector, nr_sects,
377044abff2cSChristoph Hellwig 					GFP_NOFS);
377144abff2cSChristoph Hellwig 	}
37729af84648SDaeho Jeong 
37739af84648SDaeho Jeong 	if (!ret && (flags & F2FS_TRIM_FILE_ZEROOUT)) {
37749af84648SDaeho Jeong 		if (IS_ENCRYPTED(inode))
37759af84648SDaeho Jeong 			ret = fscrypt_zeroout_range(inode, off, block, len);
37769af84648SDaeho Jeong 		else
37779af84648SDaeho Jeong 			ret = blkdev_issue_zeroout(bdev, sector, nr_sects,
37789af84648SDaeho Jeong 					GFP_NOFS, 0);
37799af84648SDaeho Jeong 	}
37809af84648SDaeho Jeong 
37819af84648SDaeho Jeong 	return ret;
37829af84648SDaeho Jeong }
37839af84648SDaeho Jeong 
f2fs_sec_trim_file(struct file * filp,unsigned long arg)37849af84648SDaeho Jeong static int f2fs_sec_trim_file(struct file *filp, unsigned long arg)
37859af84648SDaeho Jeong {
37869af84648SDaeho Jeong 	struct inode *inode = file_inode(filp);
37879af84648SDaeho Jeong 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
37889af84648SDaeho Jeong 	struct address_space *mapping = inode->i_mapping;
37899af84648SDaeho Jeong 	struct block_device *prev_bdev = NULL;
37909af84648SDaeho Jeong 	struct f2fs_sectrim_range range;
37919af84648SDaeho Jeong 	pgoff_t index, pg_end, prev_index = 0;
37929af84648SDaeho Jeong 	block_t prev_block = 0, len = 0;
37939af84648SDaeho Jeong 	loff_t end_addr;
37949af84648SDaeho Jeong 	bool to_end = false;
37959af84648SDaeho Jeong 	int ret = 0;
37969af84648SDaeho Jeong 
37979af84648SDaeho Jeong 	if (!(filp->f_mode & FMODE_WRITE))
37989af84648SDaeho Jeong 		return -EBADF;
37999af84648SDaeho Jeong 
38009af84648SDaeho Jeong 	if (copy_from_user(&range, (struct f2fs_sectrim_range __user *)arg,
38019af84648SDaeho Jeong 				sizeof(range)))
38029af84648SDaeho Jeong 		return -EFAULT;
38039af84648SDaeho Jeong 
38049af84648SDaeho Jeong 	if (range.flags == 0 || (range.flags & ~F2FS_TRIM_FILE_MASK) ||
38059af84648SDaeho Jeong 			!S_ISREG(inode->i_mode))
38069af84648SDaeho Jeong 		return -EINVAL;
38079af84648SDaeho Jeong 
38089af84648SDaeho Jeong 	if (((range.flags & F2FS_TRIM_FILE_DISCARD) &&
38099af84648SDaeho Jeong 			!f2fs_hw_support_discard(sbi)) ||
38109af84648SDaeho Jeong 			((range.flags & F2FS_TRIM_FILE_ZEROOUT) &&
38119af84648SDaeho Jeong 			 IS_ENCRYPTED(inode) && f2fs_is_multi_device(sbi)))
38129af84648SDaeho Jeong 		return -EOPNOTSUPP;
38139af84648SDaeho Jeong 
38149af84648SDaeho Jeong 	file_start_write(filp);
38159af84648SDaeho Jeong 	inode_lock(inode);
38169af84648SDaeho Jeong 
38179af84648SDaeho Jeong 	if (f2fs_is_atomic_file(inode) || f2fs_compressed_file(inode) ||
38189af84648SDaeho Jeong 			range.start >= inode->i_size) {
38199af84648SDaeho Jeong 		ret = -EINVAL;
38209af84648SDaeho Jeong 		goto err;
38219af84648SDaeho Jeong 	}
38229af84648SDaeho Jeong 
38239af84648SDaeho Jeong 	if (range.len == 0)
38249af84648SDaeho Jeong 		goto err;
38259af84648SDaeho Jeong 
38269af84648SDaeho Jeong 	if (inode->i_size - range.start > range.len) {
38279af84648SDaeho Jeong 		end_addr = range.start + range.len;
38289af84648SDaeho Jeong 	} else {
38299af84648SDaeho Jeong 		end_addr = range.len == (u64)-1 ?
38309af84648SDaeho Jeong 			sbi->sb->s_maxbytes : inode->i_size;
38319af84648SDaeho Jeong 		to_end = true;
38329af84648SDaeho Jeong 	}
38339af84648SDaeho Jeong 
38349af84648SDaeho Jeong 	if (!IS_ALIGNED(range.start, F2FS_BLKSIZE) ||
38359af84648SDaeho Jeong 			(!to_end && !IS_ALIGNED(end_addr, F2FS_BLKSIZE))) {
38369af84648SDaeho Jeong 		ret = -EINVAL;
38379af84648SDaeho Jeong 		goto err;
38389af84648SDaeho Jeong 	}
38399af84648SDaeho Jeong 
38409af84648SDaeho Jeong 	index = F2FS_BYTES_TO_BLK(range.start);
38419af84648SDaeho Jeong 	pg_end = DIV_ROUND_UP(end_addr, F2FS_BLKSIZE);
38429af84648SDaeho Jeong 
38439af84648SDaeho Jeong 	ret = f2fs_convert_inline_inode(inode);
38449af84648SDaeho Jeong 	if (ret)
38459af84648SDaeho Jeong 		goto err;
38469af84648SDaeho Jeong 
3847e4544b63STim Murray 	f2fs_down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
3848edc6d01bSJan Kara 	filemap_invalidate_lock(mapping);
38499af84648SDaeho Jeong 
38509af84648SDaeho Jeong 	ret = filemap_write_and_wait_range(mapping, range.start,
38519af84648SDaeho Jeong 			to_end ? LLONG_MAX : end_addr - 1);
38529af84648SDaeho Jeong 	if (ret)
38539af84648SDaeho Jeong 		goto out;
38549af84648SDaeho Jeong 
38559af84648SDaeho Jeong 	truncate_inode_pages_range(mapping, range.start,
38569af84648SDaeho Jeong 			to_end ? -1 : end_addr - 1);
38579af84648SDaeho Jeong 
38589af84648SDaeho Jeong 	while (index < pg_end) {
38599af84648SDaeho Jeong 		struct dnode_of_data dn;
38609af84648SDaeho Jeong 		pgoff_t end_offset, count;
38619af84648SDaeho Jeong 		int i;
38629af84648SDaeho Jeong 
38639af84648SDaeho Jeong 		set_new_dnode(&dn, inode, NULL, NULL, 0);
38649af84648SDaeho Jeong 		ret = f2fs_get_dnode_of_data(&dn, index, LOOKUP_NODE);
38659af84648SDaeho Jeong 		if (ret) {
38669af84648SDaeho Jeong 			if (ret == -ENOENT) {
38679af84648SDaeho Jeong 				index = f2fs_get_next_page_offset(&dn, index);
38689af84648SDaeho Jeong 				continue;
38699af84648SDaeho Jeong 			}
38709af84648SDaeho Jeong 			goto out;
38719af84648SDaeho Jeong 		}
38729af84648SDaeho Jeong 
38739af84648SDaeho Jeong 		end_offset = ADDRS_PER_PAGE(dn.node_page, inode);
38749af84648SDaeho Jeong 		count = min(end_offset - dn.ofs_in_node, pg_end - index);
38759af84648SDaeho Jeong 		for (i = 0; i < count; i++, index++, dn.ofs_in_node++) {
38769af84648SDaeho Jeong 			struct block_device *cur_bdev;
38779af84648SDaeho Jeong 			block_t blkaddr = f2fs_data_blkaddr(&dn);
38789af84648SDaeho Jeong 
38799af84648SDaeho Jeong 			if (!__is_valid_data_blkaddr(blkaddr))
38809af84648SDaeho Jeong 				continue;
38819af84648SDaeho Jeong 
38829af84648SDaeho Jeong 			if (!f2fs_is_valid_blkaddr(sbi, blkaddr,
38839af84648SDaeho Jeong 						DATA_GENERIC_ENHANCE)) {
38849af84648SDaeho Jeong 				ret = -EFSCORRUPTED;
38859af84648SDaeho Jeong 				f2fs_put_dnode(&dn);
388695fa90c9SChao Yu 				f2fs_handle_error(sbi,
388795fa90c9SChao Yu 						ERROR_INVALID_BLKADDR);
38889af84648SDaeho Jeong 				goto out;
38899af84648SDaeho Jeong 			}
38909af84648SDaeho Jeong 
38919af84648SDaeho Jeong 			cur_bdev = f2fs_target_device(sbi, blkaddr, NULL);
38929af84648SDaeho Jeong 			if (f2fs_is_multi_device(sbi)) {
38939af84648SDaeho Jeong 				int di = f2fs_target_device_index(sbi, blkaddr);
38949af84648SDaeho Jeong 
38959af84648SDaeho Jeong 				blkaddr -= FDEV(di).start_blk;
38969af84648SDaeho Jeong 			}
38979af84648SDaeho Jeong 
38989af84648SDaeho Jeong 			if (len) {
38999af84648SDaeho Jeong 				if (prev_bdev == cur_bdev &&
39009af84648SDaeho Jeong 						index == prev_index + len &&
39019af84648SDaeho Jeong 						blkaddr == prev_block + len) {
39029af84648SDaeho Jeong 					len++;
39039af84648SDaeho Jeong 				} else {
39049af84648SDaeho Jeong 					ret = f2fs_secure_erase(prev_bdev,
39059af84648SDaeho Jeong 						inode, prev_index, prev_block,
39069af84648SDaeho Jeong 						len, range.flags);
39079af84648SDaeho Jeong 					if (ret) {
39089af84648SDaeho Jeong 						f2fs_put_dnode(&dn);
39099af84648SDaeho Jeong 						goto out;
39109af84648SDaeho Jeong 					}
39119af84648SDaeho Jeong 
39129af84648SDaeho Jeong 					len = 0;
39139af84648SDaeho Jeong 				}
39149af84648SDaeho Jeong 			}
39159af84648SDaeho Jeong 
39169af84648SDaeho Jeong 			if (!len) {
39179af84648SDaeho Jeong 				prev_bdev = cur_bdev;
39189af84648SDaeho Jeong 				prev_index = index;
39199af84648SDaeho Jeong 				prev_block = blkaddr;
39209af84648SDaeho Jeong 				len = 1;
39219af84648SDaeho Jeong 			}
39229af84648SDaeho Jeong 		}
39239af84648SDaeho Jeong 
39249af84648SDaeho Jeong 		f2fs_put_dnode(&dn);
39259af84648SDaeho Jeong 
39269af84648SDaeho Jeong 		if (fatal_signal_pending(current)) {
39279af84648SDaeho Jeong 			ret = -EINTR;
39289af84648SDaeho Jeong 			goto out;
39299af84648SDaeho Jeong 		}
39309af84648SDaeho Jeong 		cond_resched();
39319af84648SDaeho Jeong 	}
39329af84648SDaeho Jeong 
39339af84648SDaeho Jeong 	if (len)
39349af84648SDaeho Jeong 		ret = f2fs_secure_erase(prev_bdev, inode, prev_index,
39359af84648SDaeho Jeong 				prev_block, len, range.flags);
39369af84648SDaeho Jeong out:
3937edc6d01bSJan Kara 	filemap_invalidate_unlock(mapping);
3938e4544b63STim Murray 	f2fs_up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
39399af84648SDaeho Jeong err:
39409af84648SDaeho Jeong 	inode_unlock(inode);
39419af84648SDaeho Jeong 	file_end_write(filp);
39429af84648SDaeho Jeong 
39439af84648SDaeho Jeong 	return ret;
39449af84648SDaeho Jeong }
39459af84648SDaeho Jeong 
f2fs_ioc_get_compress_option(struct file * filp,unsigned long arg)39469e2a5f8cSDaeho Jeong static int f2fs_ioc_get_compress_option(struct file *filp, unsigned long arg)
394752656e6cSJaegeuk Kim {
39489e2a5f8cSDaeho Jeong 	struct inode *inode = file_inode(filp);
39499e2a5f8cSDaeho Jeong 	struct f2fs_comp_option option;
39501f227a3eSJaegeuk Kim 
39519e2a5f8cSDaeho Jeong 	if (!f2fs_sb_has_compression(F2FS_I_SB(inode)))
39529e2a5f8cSDaeho Jeong 		return -EOPNOTSUPP;
39539e2a5f8cSDaeho Jeong 
39549e2a5f8cSDaeho Jeong 	inode_lock_shared(inode);
39559e2a5f8cSDaeho Jeong 
39569e2a5f8cSDaeho Jeong 	if (!f2fs_compressed_file(inode)) {
39579e2a5f8cSDaeho Jeong 		inode_unlock_shared(inode);
39589e2a5f8cSDaeho Jeong 		return -ENODATA;
39599e2a5f8cSDaeho Jeong 	}
39609e2a5f8cSDaeho Jeong 
39619e2a5f8cSDaeho Jeong 	option.algorithm = F2FS_I(inode)->i_compress_algorithm;
39629e2a5f8cSDaeho Jeong 	option.log_cluster_size = F2FS_I(inode)->i_log_cluster_size;
39639e2a5f8cSDaeho Jeong 
39649e2a5f8cSDaeho Jeong 	inode_unlock_shared(inode);
39659e2a5f8cSDaeho Jeong 
39669e2a5f8cSDaeho Jeong 	if (copy_to_user((struct f2fs_comp_option __user *)arg, &option,
39679e2a5f8cSDaeho Jeong 				sizeof(option)))
39689e2a5f8cSDaeho Jeong 		return -EFAULT;
39699e2a5f8cSDaeho Jeong 
39709e2a5f8cSDaeho Jeong 	return 0;
39719e2a5f8cSDaeho Jeong }
39729e2a5f8cSDaeho Jeong 
f2fs_ioc_set_compress_option(struct file * filp,unsigned long arg)3973e1e8debeSDaeho Jeong static int f2fs_ioc_set_compress_option(struct file *filp, unsigned long arg)
3974e1e8debeSDaeho Jeong {
3975e1e8debeSDaeho Jeong 	struct inode *inode = file_inode(filp);
3976e1e8debeSDaeho Jeong 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
3977e1e8debeSDaeho Jeong 	struct f2fs_comp_option option;
3978e1e8debeSDaeho Jeong 	int ret = 0;
3979e1e8debeSDaeho Jeong 
3980e1e8debeSDaeho Jeong 	if (!f2fs_sb_has_compression(sbi))
3981e1e8debeSDaeho Jeong 		return -EOPNOTSUPP;
3982e1e8debeSDaeho Jeong 
3983e1e8debeSDaeho Jeong 	if (!(filp->f_mode & FMODE_WRITE))
3984e1e8debeSDaeho Jeong 		return -EBADF;
3985e1e8debeSDaeho Jeong 
3986e1e8debeSDaeho Jeong 	if (copy_from_user(&option, (struct f2fs_comp_option __user *)arg,
3987e1e8debeSDaeho Jeong 				sizeof(option)))
3988e1e8debeSDaeho Jeong 		return -EFAULT;
3989e1e8debeSDaeho Jeong 
399041e8018bSChao Yu 	if (option.log_cluster_size < MIN_COMPRESS_LOG_SIZE ||
3991e1e8debeSDaeho Jeong 		option.log_cluster_size > MAX_COMPRESS_LOG_SIZE ||
3992e1e8debeSDaeho Jeong 		option.algorithm >= COMPRESS_MAX)
3993e1e8debeSDaeho Jeong 		return -EINVAL;
3994e1e8debeSDaeho Jeong 
3995e1e8debeSDaeho Jeong 	file_start_write(filp);
3996e1e8debeSDaeho Jeong 	inode_lock(inode);
3997e1e8debeSDaeho Jeong 
3998b5ab3276SChao Yu 	f2fs_down_write(&F2FS_I(inode)->i_sem);
399941e8018bSChao Yu 	if (!f2fs_compressed_file(inode)) {
400041e8018bSChao Yu 		ret = -EINVAL;
400141e8018bSChao Yu 		goto out;
400241e8018bSChao Yu 	}
400341e8018bSChao Yu 
4004e1e8debeSDaeho Jeong 	if (f2fs_is_mmap_file(inode) || get_dirty_pages(inode)) {
4005e1e8debeSDaeho Jeong 		ret = -EBUSY;
4006e1e8debeSDaeho Jeong 		goto out;
4007e1e8debeSDaeho Jeong 	}
4008e1e8debeSDaeho Jeong 
4009e6261bebSYangtao Li 	if (F2FS_HAS_BLOCKS(inode)) {
4010e1e8debeSDaeho Jeong 		ret = -EFBIG;
4011e1e8debeSDaeho Jeong 		goto out;
4012e1e8debeSDaeho Jeong 	}
4013e1e8debeSDaeho Jeong 
4014e1e8debeSDaeho Jeong 	F2FS_I(inode)->i_compress_algorithm = option.algorithm;
4015e1e8debeSDaeho Jeong 	F2FS_I(inode)->i_log_cluster_size = option.log_cluster_size;
4016447286ebSYangtao Li 	F2FS_I(inode)->i_cluster_size = BIT(option.log_cluster_size);
401700de7280SJaegeuk Kim 	/* Set default level */
401800de7280SJaegeuk Kim 	if (F2FS_I(inode)->i_compress_algorithm == COMPRESS_ZSTD)
401900de7280SJaegeuk Kim 		F2FS_I(inode)->i_compress_level = F2FS_ZSTD_DEFAULT_CLEVEL;
402000de7280SJaegeuk Kim 	else
402100de7280SJaegeuk Kim 		F2FS_I(inode)->i_compress_level = 0;
402200de7280SJaegeuk Kim 	/* Adjust mount option level */
402300de7280SJaegeuk Kim 	if (option.algorithm == F2FS_OPTION(sbi).compress_algorithm &&
402400de7280SJaegeuk Kim 	    F2FS_OPTION(sbi).compress_level)
402500de7280SJaegeuk Kim 		F2FS_I(inode)->i_compress_level = F2FS_OPTION(sbi).compress_level;
4026e1e8debeSDaeho Jeong 	f2fs_mark_inode_dirty_sync(inode, true);
4027e1e8debeSDaeho Jeong 
4028e1e8debeSDaeho Jeong 	if (!f2fs_is_compress_backend_ready(inode))
4029e1e8debeSDaeho Jeong 		f2fs_warn(sbi, "compression algorithm is successfully set, "
4030e1e8debeSDaeho Jeong 			"but current kernel doesn't support this algorithm.");
4031e1e8debeSDaeho Jeong out:
4032b5ab3276SChao Yu 	f2fs_up_write(&F2FS_I(inode)->i_sem);
4033e1e8debeSDaeho Jeong 	inode_unlock(inode);
4034e1e8debeSDaeho Jeong 	file_end_write(filp);
4035e1e8debeSDaeho Jeong 
4036e1e8debeSDaeho Jeong 	return ret;
4037e1e8debeSDaeho Jeong }
4038e1e8debeSDaeho Jeong 
redirty_blocks(struct inode * inode,pgoff_t page_idx,int len)40395fdb322fSDaeho Jeong static int redirty_blocks(struct inode *inode, pgoff_t page_idx, int len)
40405fdb322fSDaeho Jeong {
4041fcd9ae4fSMatthew Wilcox (Oracle) 	DEFINE_READAHEAD(ractl, NULL, NULL, inode->i_mapping, page_idx);
40425fdb322fSDaeho Jeong 	struct address_space *mapping = inode->i_mapping;
40435fdb322fSDaeho Jeong 	struct page *page;
40445fdb322fSDaeho Jeong 	pgoff_t redirty_idx = page_idx;
40455fdb322fSDaeho Jeong 	int i, page_len = 0, ret = 0;
40465fdb322fSDaeho Jeong 
40475fdb322fSDaeho Jeong 	page_cache_ra_unbounded(&ractl, len, 0);
40485fdb322fSDaeho Jeong 
40495fdb322fSDaeho Jeong 	for (i = 0; i < len; i++, page_idx++) {
40505fdb322fSDaeho Jeong 		page = read_cache_page(mapping, page_idx, NULL, NULL);
40515fdb322fSDaeho Jeong 		if (IS_ERR(page)) {
40525fdb322fSDaeho Jeong 			ret = PTR_ERR(page);
40535fdb322fSDaeho Jeong 			break;
40545fdb322fSDaeho Jeong 		}
40555fdb322fSDaeho Jeong 		page_len++;
40565fdb322fSDaeho Jeong 	}
40575fdb322fSDaeho Jeong 
40585fdb322fSDaeho Jeong 	for (i = 0; i < page_len; i++, redirty_idx++) {
40595fdb322fSDaeho Jeong 		page = find_lock_page(mapping, redirty_idx);
4060a4a0e16dSJack Qiu 
4061a4a0e16dSJack Qiu 		/* It will never fail, when page has pinned above */
4062a4a0e16dSJack Qiu 		f2fs_bug_on(F2FS_I_SB(inode), !page);
4063a4a0e16dSJack Qiu 
40645fdb322fSDaeho Jeong 		set_page_dirty(page);
4065417b8a91SChao Yu 		set_page_private_gcing(page);
40665fdb322fSDaeho Jeong 		f2fs_put_page(page, 1);
40675fdb322fSDaeho Jeong 		f2fs_put_page(page, 0);
40685fdb322fSDaeho Jeong 	}
40695fdb322fSDaeho Jeong 
40705fdb322fSDaeho Jeong 	return ret;
40715fdb322fSDaeho Jeong }
40725fdb322fSDaeho Jeong 
f2fs_ioc_decompress_file(struct file * filp)4073ddf1eca4SYangtao Li static int f2fs_ioc_decompress_file(struct file *filp)
40745fdb322fSDaeho Jeong {
40755fdb322fSDaeho Jeong 	struct inode *inode = file_inode(filp);
40765fdb322fSDaeho Jeong 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
40775fdb322fSDaeho Jeong 	struct f2fs_inode_info *fi = F2FS_I(inode);
40785fdb322fSDaeho Jeong 	pgoff_t page_idx = 0, last_idx;
40795fdb322fSDaeho Jeong 	unsigned int blk_per_seg = sbi->blocks_per_seg;
4080054cb289SYufen Yu 	int cluster_size = fi->i_cluster_size;
40815fdb322fSDaeho Jeong 	int count, ret;
40825fdb322fSDaeho Jeong 
40835fdb322fSDaeho Jeong 	if (!f2fs_sb_has_compression(sbi) ||
40845fdb322fSDaeho Jeong 			F2FS_OPTION(sbi).compress_mode != COMPR_MODE_USER)
40855fdb322fSDaeho Jeong 		return -EOPNOTSUPP;
40865fdb322fSDaeho Jeong 
40875fdb322fSDaeho Jeong 	if (!(filp->f_mode & FMODE_WRITE))
40885fdb322fSDaeho Jeong 		return -EBADF;
40895fdb322fSDaeho Jeong 
40905fdb322fSDaeho Jeong 	if (!f2fs_compressed_file(inode))
40915fdb322fSDaeho Jeong 		return -EINVAL;
40925fdb322fSDaeho Jeong 
4093c3355ea9SYangtao Li 	f2fs_balance_fs(sbi, true);
40945fdb322fSDaeho Jeong 
40955fdb322fSDaeho Jeong 	file_start_write(filp);
40965fdb322fSDaeho Jeong 	inode_lock(inode);
40975fdb322fSDaeho Jeong 
40985fdb322fSDaeho Jeong 	if (!f2fs_is_compress_backend_ready(inode)) {
40995fdb322fSDaeho Jeong 		ret = -EOPNOTSUPP;
41005fdb322fSDaeho Jeong 		goto out;
41015fdb322fSDaeho Jeong 	}
41025fdb322fSDaeho Jeong 
410390be48bdSJaewook Kim 	if (is_inode_flag_set(inode, FI_COMPRESS_RELEASED)) {
410490be48bdSJaewook Kim 		ret = -EINVAL;
410590be48bdSJaewook Kim 		goto out;
410690be48bdSJaewook Kim 	}
410790be48bdSJaewook Kim 
41085fdb322fSDaeho Jeong 	ret = filemap_write_and_wait_range(inode->i_mapping, 0, LLONG_MAX);
41095fdb322fSDaeho Jeong 	if (ret)
41105fdb322fSDaeho Jeong 		goto out;
41115fdb322fSDaeho Jeong 
41125fdb322fSDaeho Jeong 	if (!atomic_read(&fi->i_compr_blocks))
41135fdb322fSDaeho Jeong 		goto out;
41145fdb322fSDaeho Jeong 
41155fdb322fSDaeho Jeong 	last_idx = DIV_ROUND_UP(i_size_read(inode), PAGE_SIZE);
41165fdb322fSDaeho Jeong 
41175fdb322fSDaeho Jeong 	count = last_idx - page_idx;
4118025b3602SChao Yu 	while (count && count >= cluster_size) {
4119025b3602SChao Yu 		ret = redirty_blocks(inode, page_idx, cluster_size);
41205fdb322fSDaeho Jeong 		if (ret < 0)
41215fdb322fSDaeho Jeong 			break;
41225fdb322fSDaeho Jeong 
4123b822dc91SYangtao Li 		if (get_dirty_pages(inode) >= blk_per_seg) {
4124b822dc91SYangtao Li 			ret = filemap_fdatawrite(inode->i_mapping);
4125b822dc91SYangtao Li 			if (ret < 0)
4126b822dc91SYangtao Li 				break;
4127b822dc91SYangtao Li 		}
41285fdb322fSDaeho Jeong 
4129025b3602SChao Yu 		count -= cluster_size;
4130025b3602SChao Yu 		page_idx += cluster_size;
41313a2c0e55SChao Yu 
41323a2c0e55SChao Yu 		cond_resched();
41333a2c0e55SChao Yu 		if (fatal_signal_pending(current)) {
41343a2c0e55SChao Yu 			ret = -EINTR;
41353a2c0e55SChao Yu 			break;
41363a2c0e55SChao Yu 		}
41375fdb322fSDaeho Jeong 	}
41385fdb322fSDaeho Jeong 
41395fdb322fSDaeho Jeong 	if (!ret)
41405fdb322fSDaeho Jeong 		ret = filemap_write_and_wait_range(inode->i_mapping, 0,
41415fdb322fSDaeho Jeong 							LLONG_MAX);
41425fdb322fSDaeho Jeong 
41435fdb322fSDaeho Jeong 	if (ret)
4144833dcd35SJoe Perches 		f2fs_warn(sbi, "%s: The file might be partially decompressed (errno=%d). Please delete the file.",
41455fdb322fSDaeho Jeong 			  __func__, ret);
41465fdb322fSDaeho Jeong out:
41475fdb322fSDaeho Jeong 	inode_unlock(inode);
41485fdb322fSDaeho Jeong 	file_end_write(filp);
41495fdb322fSDaeho Jeong 
41505fdb322fSDaeho Jeong 	return ret;
41515fdb322fSDaeho Jeong }
41525fdb322fSDaeho Jeong 
f2fs_ioc_compress_file(struct file * filp)4153ddf1eca4SYangtao Li static int f2fs_ioc_compress_file(struct file *filp)
41545fdb322fSDaeho Jeong {
41555fdb322fSDaeho Jeong 	struct inode *inode = file_inode(filp);
41565fdb322fSDaeho Jeong 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
41575fdb322fSDaeho Jeong 	pgoff_t page_idx = 0, last_idx;
41585fdb322fSDaeho Jeong 	unsigned int blk_per_seg = sbi->blocks_per_seg;
41595fdb322fSDaeho Jeong 	int cluster_size = F2FS_I(inode)->i_cluster_size;
41605fdb322fSDaeho Jeong 	int count, ret;
41615fdb322fSDaeho Jeong 
41625fdb322fSDaeho Jeong 	if (!f2fs_sb_has_compression(sbi) ||
41635fdb322fSDaeho Jeong 			F2FS_OPTION(sbi).compress_mode != COMPR_MODE_USER)
41645fdb322fSDaeho Jeong 		return -EOPNOTSUPP;
41655fdb322fSDaeho Jeong 
41665fdb322fSDaeho Jeong 	if (!(filp->f_mode & FMODE_WRITE))
41675fdb322fSDaeho Jeong 		return -EBADF;
41685fdb322fSDaeho Jeong 
41695fdb322fSDaeho Jeong 	if (!f2fs_compressed_file(inode))
41705fdb322fSDaeho Jeong 		return -EINVAL;
41715fdb322fSDaeho Jeong 
4172c3355ea9SYangtao Li 	f2fs_balance_fs(sbi, true);
41735fdb322fSDaeho Jeong 
41745fdb322fSDaeho Jeong 	file_start_write(filp);
41755fdb322fSDaeho Jeong 	inode_lock(inode);
41765fdb322fSDaeho Jeong 
41775fdb322fSDaeho Jeong 	if (!f2fs_is_compress_backend_ready(inode)) {
41785fdb322fSDaeho Jeong 		ret = -EOPNOTSUPP;
41795fdb322fSDaeho Jeong 		goto out;
41805fdb322fSDaeho Jeong 	}
41815fdb322fSDaeho Jeong 
418290be48bdSJaewook Kim 	if (is_inode_flag_set(inode, FI_COMPRESS_RELEASED)) {
418390be48bdSJaewook Kim 		ret = -EINVAL;
418490be48bdSJaewook Kim 		goto out;
418590be48bdSJaewook Kim 	}
418690be48bdSJaewook Kim 
41875fdb322fSDaeho Jeong 	ret = filemap_write_and_wait_range(inode->i_mapping, 0, LLONG_MAX);
41885fdb322fSDaeho Jeong 	if (ret)
41895fdb322fSDaeho Jeong 		goto out;
41905fdb322fSDaeho Jeong 
41915fdb322fSDaeho Jeong 	set_inode_flag(inode, FI_ENABLE_COMPRESS);
41925fdb322fSDaeho Jeong 
41935fdb322fSDaeho Jeong 	last_idx = DIV_ROUND_UP(i_size_read(inode), PAGE_SIZE);
41945fdb322fSDaeho Jeong 
41955fdb322fSDaeho Jeong 	count = last_idx - page_idx;
4196025b3602SChao Yu 	while (count && count >= cluster_size) {
4197025b3602SChao Yu 		ret = redirty_blocks(inode, page_idx, cluster_size);
41985fdb322fSDaeho Jeong 		if (ret < 0)
41995fdb322fSDaeho Jeong 			break;
42005fdb322fSDaeho Jeong 
4201b822dc91SYangtao Li 		if (get_dirty_pages(inode) >= blk_per_seg) {
4202b822dc91SYangtao Li 			ret = filemap_fdatawrite(inode->i_mapping);
4203b822dc91SYangtao Li 			if (ret < 0)
4204b822dc91SYangtao Li 				break;
4205b822dc91SYangtao Li 		}
42065fdb322fSDaeho Jeong 
4207025b3602SChao Yu 		count -= cluster_size;
4208025b3602SChao Yu 		page_idx += cluster_size;
42093a2c0e55SChao Yu 
42103a2c0e55SChao Yu 		cond_resched();
42113a2c0e55SChao Yu 		if (fatal_signal_pending(current)) {
42123a2c0e55SChao Yu 			ret = -EINTR;
42133a2c0e55SChao Yu 			break;
42143a2c0e55SChao Yu 		}
42155fdb322fSDaeho Jeong 	}
42165fdb322fSDaeho Jeong 
42175fdb322fSDaeho Jeong 	if (!ret)
42185fdb322fSDaeho Jeong 		ret = filemap_write_and_wait_range(inode->i_mapping, 0,
42195fdb322fSDaeho Jeong 							LLONG_MAX);
42205fdb322fSDaeho Jeong 
42215fdb322fSDaeho Jeong 	clear_inode_flag(inode, FI_ENABLE_COMPRESS);
42225fdb322fSDaeho Jeong 
42235fdb322fSDaeho Jeong 	if (ret)
4224833dcd35SJoe Perches 		f2fs_warn(sbi, "%s: The file might be partially compressed (errno=%d). Please delete the file.",
42255fdb322fSDaeho Jeong 			  __func__, ret);
42265fdb322fSDaeho Jeong out:
42275fdb322fSDaeho Jeong 	inode_unlock(inode);
42285fdb322fSDaeho Jeong 	file_end_write(filp);
42295fdb322fSDaeho Jeong 
42305fdb322fSDaeho Jeong 	return ret;
42315fdb322fSDaeho Jeong }
42325fdb322fSDaeho Jeong 
__f2fs_ioctl(struct file * filp,unsigned int cmd,unsigned long arg)423334178b1bSChao Yu static long __f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
4234fbfa2cc5SJaegeuk Kim {
423552656e6cSJaegeuk Kim 	switch (cmd) {
42363357af8fSEric Biggers 	case FS_IOC_GETVERSION:
4237d49f3e89SChao Yu 		return f2fs_ioc_getversion(filp, arg);
423888b88a66SJaegeuk Kim 	case F2FS_IOC_START_ATOMIC_WRITE:
423941e8f85aSDaeho Jeong 		return f2fs_ioc_start_atomic_write(filp, false);
424041e8f85aSDaeho Jeong 	case F2FS_IOC_START_ATOMIC_REPLACE:
424141e8f85aSDaeho Jeong 		return f2fs_ioc_start_atomic_write(filp, true);
424288b88a66SJaegeuk Kim 	case F2FS_IOC_COMMIT_ATOMIC_WRITE:
424388b88a66SJaegeuk Kim 		return f2fs_ioc_commit_atomic_write(filp);
424423339e57SDaeho Jeong 	case F2FS_IOC_ABORT_ATOMIC_WRITE:
424523339e57SDaeho Jeong 		return f2fs_ioc_abort_atomic_write(filp);
424602a1335fSJaegeuk Kim 	case F2FS_IOC_START_VOLATILE_WRITE:
42471e84371fSJaegeuk Kim 	case F2FS_IOC_RELEASE_VOLATILE_WRITE:
42487bc155feSJaegeuk Kim 		return -EOPNOTSUPP;
42491abff93dSJaegeuk Kim 	case F2FS_IOC_SHUTDOWN:
42501abff93dSJaegeuk Kim 		return f2fs_ioc_shutdown(filp, arg);
425152656e6cSJaegeuk Kim 	case FITRIM:
425252656e6cSJaegeuk Kim 		return f2fs_ioc_fitrim(filp, arg);
42533357af8fSEric Biggers 	case FS_IOC_SET_ENCRYPTION_POLICY:
4254f424f664SJaegeuk Kim 		return f2fs_ioc_set_encryption_policy(filp, arg);
42553357af8fSEric Biggers 	case FS_IOC_GET_ENCRYPTION_POLICY:
4256f424f664SJaegeuk Kim 		return f2fs_ioc_get_encryption_policy(filp, arg);
42573357af8fSEric Biggers 	case FS_IOC_GET_ENCRYPTION_PWSALT:
4258f424f664SJaegeuk Kim 		return f2fs_ioc_get_encryption_pwsalt(filp, arg);
42598ce589c7SEric Biggers 	case FS_IOC_GET_ENCRYPTION_POLICY_EX:
42608ce589c7SEric Biggers 		return f2fs_ioc_get_encryption_policy_ex(filp, arg);
42618ce589c7SEric Biggers 	case FS_IOC_ADD_ENCRYPTION_KEY:
42628ce589c7SEric Biggers 		return f2fs_ioc_add_encryption_key(filp, arg);
42638ce589c7SEric Biggers 	case FS_IOC_REMOVE_ENCRYPTION_KEY:
42648ce589c7SEric Biggers 		return f2fs_ioc_remove_encryption_key(filp, arg);
42658ce589c7SEric Biggers 	case FS_IOC_REMOVE_ENCRYPTION_KEY_ALL_USERS:
42668ce589c7SEric Biggers 		return f2fs_ioc_remove_encryption_key_all_users(filp, arg);
42678ce589c7SEric Biggers 	case FS_IOC_GET_ENCRYPTION_KEY_STATUS:
42688ce589c7SEric Biggers 		return f2fs_ioc_get_encryption_key_status(filp, arg);
4269ee446e1aSEric Biggers 	case FS_IOC_GET_ENCRYPTION_NONCE:
4270ee446e1aSEric Biggers 		return f2fs_ioc_get_encryption_nonce(filp, arg);
4271c1c1b583SChao Yu 	case F2FS_IOC_GARBAGE_COLLECT:
4272c1c1b583SChao Yu 		return f2fs_ioc_gc(filp, arg);
427334dc77adSJaegeuk Kim 	case F2FS_IOC_GARBAGE_COLLECT_RANGE:
427434dc77adSJaegeuk Kim 		return f2fs_ioc_gc_range(filp, arg);
4275456b88e4SChao Yu 	case F2FS_IOC_WRITE_CHECKPOINT:
4276ddf1eca4SYangtao Li 		return f2fs_ioc_write_checkpoint(filp);
4277d323d005SChao Yu 	case F2FS_IOC_DEFRAGMENT:
4278d323d005SChao Yu 		return f2fs_ioc_defragment(filp, arg);
42794dd6f977SJaegeuk Kim 	case F2FS_IOC_MOVE_RANGE:
42804dd6f977SJaegeuk Kim 		return f2fs_ioc_move_range(filp, arg);
4281e066b83cSJaegeuk Kim 	case F2FS_IOC_FLUSH_DEVICE:
4282e066b83cSJaegeuk Kim 		return f2fs_ioc_flush_device(filp, arg);
4283e65ef207SJaegeuk Kim 	case F2FS_IOC_GET_FEATURES:
4284e65ef207SJaegeuk Kim 		return f2fs_ioc_get_features(filp, arg);
42851ad71a27SJaegeuk Kim 	case F2FS_IOC_GET_PIN_FILE:
42861ad71a27SJaegeuk Kim 		return f2fs_ioc_get_pin_file(filp, arg);
42871ad71a27SJaegeuk Kim 	case F2FS_IOC_SET_PIN_FILE:
42881ad71a27SJaegeuk Kim 		return f2fs_ioc_set_pin_file(filp, arg);
4289c4020b2dSChao Yu 	case F2FS_IOC_PRECACHE_EXTENTS:
4290ddf1eca4SYangtao Li 		return f2fs_ioc_precache_extents(filp);
429104f0b2eaSQiuyang Sun 	case F2FS_IOC_RESIZE_FS:
429204f0b2eaSQiuyang Sun 		return f2fs_ioc_resize_fs(filp, arg);
429395ae251fSEric Biggers 	case FS_IOC_ENABLE_VERITY:
429495ae251fSEric Biggers 		return f2fs_ioc_enable_verity(filp, arg);
429595ae251fSEric Biggers 	case FS_IOC_MEASURE_VERITY:
429695ae251fSEric Biggers 		return f2fs_ioc_measure_verity(filp, arg);
4297e17fe657SEric Biggers 	case FS_IOC_READ_VERITY_METADATA:
4298e17fe657SEric Biggers 		return f2fs_ioc_read_verity_metadata(filp, arg);
42993357af8fSEric Biggers 	case FS_IOC_GETFSLABEL:
43003357af8fSEric Biggers 		return f2fs_ioc_getfslabel(filp, arg);
43013357af8fSEric Biggers 	case FS_IOC_SETFSLABEL:
43023357af8fSEric Biggers 		return f2fs_ioc_setfslabel(filp, arg);
4303439dfb10SChao Yu 	case F2FS_IOC_GET_COMPRESS_BLOCKS:
4304ac1ee161SSheng Yong 		return f2fs_ioc_get_compress_blocks(filp, arg);
4305ef8d563fSChao Yu 	case F2FS_IOC_RELEASE_COMPRESS_BLOCKS:
4306ef8d563fSChao Yu 		return f2fs_release_compress_blocks(filp, arg);
4307c75488fbSChao Yu 	case F2FS_IOC_RESERVE_COMPRESS_BLOCKS:
4308c75488fbSChao Yu 		return f2fs_reserve_compress_blocks(filp, arg);
43099af84648SDaeho Jeong 	case F2FS_IOC_SEC_TRIM_FILE:
43109af84648SDaeho Jeong 		return f2fs_sec_trim_file(filp, arg);
43119e2a5f8cSDaeho Jeong 	case F2FS_IOC_GET_COMPRESS_OPTION:
43129e2a5f8cSDaeho Jeong 		return f2fs_ioc_get_compress_option(filp, arg);
4313e1e8debeSDaeho Jeong 	case F2FS_IOC_SET_COMPRESS_OPTION:
4314e1e8debeSDaeho Jeong 		return f2fs_ioc_set_compress_option(filp, arg);
43155fdb322fSDaeho Jeong 	case F2FS_IOC_DECOMPRESS_FILE:
4316ddf1eca4SYangtao Li 		return f2fs_ioc_decompress_file(filp);
43175fdb322fSDaeho Jeong 	case F2FS_IOC_COMPRESS_FILE:
4318ddf1eca4SYangtao Li 		return f2fs_ioc_compress_file(filp);
4319fbfa2cc5SJaegeuk Kim 	default:
4320fbfa2cc5SJaegeuk Kim 		return -ENOTTY;
4321fbfa2cc5SJaegeuk Kim 	}
4322fbfa2cc5SJaegeuk Kim }
4323fbfa2cc5SJaegeuk Kim 
f2fs_ioctl(struct file * filp,unsigned int cmd,unsigned long arg)432434178b1bSChao Yu long f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
432534178b1bSChao Yu {
432634178b1bSChao Yu 	if (unlikely(f2fs_cp_error(F2FS_I_SB(file_inode(filp)))))
432734178b1bSChao Yu 		return -EIO;
432834178b1bSChao Yu 	if (!f2fs_is_checkpoint_ready(F2FS_I_SB(file_inode(filp))))
432934178b1bSChao Yu 		return -ENOSPC;
433034178b1bSChao Yu 
433134178b1bSChao Yu 	return __f2fs_ioctl(filp, cmd, arg);
433234178b1bSChao Yu }
433334178b1bSChao Yu 
4334a1e09b03SEric Biggers /*
4335a1e09b03SEric Biggers  * Return %true if the given read or write request should use direct I/O, or
4336a1e09b03SEric Biggers  * %false if it should use buffered I/O.
4337a1e09b03SEric Biggers  */
f2fs_should_use_dio(struct inode * inode,struct kiocb * iocb,struct iov_iter * iter)4338a1e09b03SEric Biggers static bool f2fs_should_use_dio(struct inode *inode, struct kiocb *iocb,
4339a1e09b03SEric Biggers 				struct iov_iter *iter)
4340a1e09b03SEric Biggers {
4341a1e09b03SEric Biggers 	unsigned int align;
4342a1e09b03SEric Biggers 
4343a1e09b03SEric Biggers 	if (!(iocb->ki_flags & IOCB_DIRECT))
4344a1e09b03SEric Biggers 		return false;
4345a1e09b03SEric Biggers 
4346bd367329SEric Biggers 	if (f2fs_force_buffered_io(inode, iov_iter_rw(iter)))
4347a1e09b03SEric Biggers 		return false;
4348a1e09b03SEric Biggers 
4349a1e09b03SEric Biggers 	/*
4350a1e09b03SEric Biggers 	 * Direct I/O not aligned to the disk's logical_block_size will be
4351a1e09b03SEric Biggers 	 * attempted, but will fail with -EINVAL.
4352a1e09b03SEric Biggers 	 *
4353a1e09b03SEric Biggers 	 * f2fs additionally requires that direct I/O be aligned to the
4354a1e09b03SEric Biggers 	 * filesystem block size, which is often a stricter requirement.
4355a1e09b03SEric Biggers 	 * However, f2fs traditionally falls back to buffered I/O on requests
4356a1e09b03SEric Biggers 	 * that are logical_block_size-aligned but not fs-block aligned.
4357a1e09b03SEric Biggers 	 *
4358a1e09b03SEric Biggers 	 * The below logic implements this behavior.
4359a1e09b03SEric Biggers 	 */
4360a1e09b03SEric Biggers 	align = iocb->ki_pos | iov_iter_alignment(iter);
4361a1e09b03SEric Biggers 	if (!IS_ALIGNED(align, i_blocksize(inode)) &&
4362a1e09b03SEric Biggers 	    IS_ALIGNED(align, bdev_logical_block_size(inode->i_sb->s_bdev)))
4363a1e09b03SEric Biggers 		return false;
4364a1e09b03SEric Biggers 
4365a1e09b03SEric Biggers 	return true;
4366a1e09b03SEric Biggers }
4367a1e09b03SEric Biggers 
f2fs_dio_read_end_io(struct kiocb * iocb,ssize_t size,int error,unsigned int flags)4368a1e09b03SEric Biggers static int f2fs_dio_read_end_io(struct kiocb *iocb, ssize_t size, int error,
4369a1e09b03SEric Biggers 				unsigned int flags)
4370a1e09b03SEric Biggers {
4371a1e09b03SEric Biggers 	struct f2fs_sb_info *sbi = F2FS_I_SB(file_inode(iocb->ki_filp));
4372a1e09b03SEric Biggers 
4373a1e09b03SEric Biggers 	dec_page_count(sbi, F2FS_DIO_READ);
4374a1e09b03SEric Biggers 	if (error)
4375a1e09b03SEric Biggers 		return error;
437634a23525SChao Yu 	f2fs_update_iostat(sbi, NULL, APP_DIRECT_READ_IO, size);
4377a1e09b03SEric Biggers 	return 0;
4378a1e09b03SEric Biggers }
4379a1e09b03SEric Biggers 
4380a1e09b03SEric Biggers static const struct iomap_dio_ops f2fs_iomap_dio_read_ops = {
4381a1e09b03SEric Biggers 	.end_io = f2fs_dio_read_end_io,
4382a1e09b03SEric Biggers };
4383a1e09b03SEric Biggers 
f2fs_dio_read_iter(struct kiocb * iocb,struct iov_iter * to)4384a1e09b03SEric Biggers static ssize_t f2fs_dio_read_iter(struct kiocb *iocb, struct iov_iter *to)
43854c8ff709SChao Yu {
43864c8ff709SChao Yu 	struct file *file = iocb->ki_filp;
43874c8ff709SChao Yu 	struct inode *inode = file_inode(file);
4388a1e09b03SEric Biggers 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
4389a1e09b03SEric Biggers 	struct f2fs_inode_info *fi = F2FS_I(inode);
4390a1e09b03SEric Biggers 	const loff_t pos = iocb->ki_pos;
4391a1e09b03SEric Biggers 	const size_t count = iov_iter_count(to);
4392a1e09b03SEric Biggers 	struct iomap_dio *dio;
4393a1e09b03SEric Biggers 	ssize_t ret;
4394a1e09b03SEric Biggers 
4395a1e09b03SEric Biggers 	if (count == 0)
4396a1e09b03SEric Biggers 		return 0; /* skip atime update */
4397a1e09b03SEric Biggers 
4398bd984c03SJaegeuk Kim 	trace_f2fs_direct_IO_enter(inode, iocb, count, READ);
4399a1e09b03SEric Biggers 
4400a1e09b03SEric Biggers 	if (iocb->ki_flags & IOCB_NOWAIT) {
4401e4544b63STim Murray 		if (!f2fs_down_read_trylock(&fi->i_gc_rwsem[READ])) {
4402a1e09b03SEric Biggers 			ret = -EAGAIN;
4403a1e09b03SEric Biggers 			goto out;
4404a1e09b03SEric Biggers 		}
4405a1e09b03SEric Biggers 	} else {
4406e4544b63STim Murray 		f2fs_down_read(&fi->i_gc_rwsem[READ]);
4407a1e09b03SEric Biggers 	}
4408a1e09b03SEric Biggers 
4409a1e09b03SEric Biggers 	/*
4410a1e09b03SEric Biggers 	 * We have to use __iomap_dio_rw() and iomap_dio_complete() instead of
4411a1e09b03SEric Biggers 	 * the higher-level function iomap_dio_rw() in order to ensure that the
4412a1e09b03SEric Biggers 	 * F2FS_DIO_READ counter will be decremented correctly in all cases.
4413a1e09b03SEric Biggers 	 */
4414a1e09b03SEric Biggers 	inc_page_count(sbi, F2FS_DIO_READ);
4415a1e09b03SEric Biggers 	dio = __iomap_dio_rw(iocb, to, &f2fs_iomap_ops,
4416786f847fSChristoph Hellwig 			     &f2fs_iomap_dio_read_ops, 0, NULL, 0);
4417a1e09b03SEric Biggers 	if (IS_ERR_OR_NULL(dio)) {
4418a1e09b03SEric Biggers 		ret = PTR_ERR_OR_ZERO(dio);
4419a1e09b03SEric Biggers 		if (ret != -EIOCBQUEUED)
4420a1e09b03SEric Biggers 			dec_page_count(sbi, F2FS_DIO_READ);
4421a1e09b03SEric Biggers 	} else {
4422a1e09b03SEric Biggers 		ret = iomap_dio_complete(dio);
4423a1e09b03SEric Biggers 	}
4424a1e09b03SEric Biggers 
4425e4544b63STim Murray 	f2fs_up_read(&fi->i_gc_rwsem[READ]);
4426a1e09b03SEric Biggers 
4427a1e09b03SEric Biggers 	file_accessed(file);
4428a1e09b03SEric Biggers out:
4429a1e09b03SEric Biggers 	trace_f2fs_direct_IO_exit(inode, pos, count, READ, ret);
4430a1e09b03SEric Biggers 	return ret;
4431a1e09b03SEric Biggers }
4432a1e09b03SEric Biggers 
f2fs_trace_rw_file_path(struct file * file,loff_t pos,size_t count,int rw)4433ceb11d0eSDavid Howells static void f2fs_trace_rw_file_path(struct file *file, loff_t pos, size_t count,
4434ceb11d0eSDavid Howells 				    int rw)
4435a28bca0fSChristoph Hellwig {
4436ceb11d0eSDavid Howells 	struct inode *inode = file_inode(file);
4437a28bca0fSChristoph Hellwig 	char *buf, *path;
4438a28bca0fSChristoph Hellwig 
443955847850SWu Bo 	buf = f2fs_getname(F2FS_I_SB(inode));
4440a28bca0fSChristoph Hellwig 	if (!buf)
4441a28bca0fSChristoph Hellwig 		return;
4442ceb11d0eSDavid Howells 	path = dentry_path_raw(file_dentry(file), buf, PATH_MAX);
4443a28bca0fSChristoph Hellwig 	if (IS_ERR(path))
4444a28bca0fSChristoph Hellwig 		goto free_buf;
4445a28bca0fSChristoph Hellwig 	if (rw == WRITE)
4446ceb11d0eSDavid Howells 		trace_f2fs_datawrite_start(inode, pos, count,
4447a28bca0fSChristoph Hellwig 				current->pid, path, current->comm);
4448a28bca0fSChristoph Hellwig 	else
4449ceb11d0eSDavid Howells 		trace_f2fs_dataread_start(inode, pos, count,
4450a28bca0fSChristoph Hellwig 				current->pid, path, current->comm);
4451a28bca0fSChristoph Hellwig free_buf:
445255847850SWu Bo 	f2fs_putname(buf);
4453a28bca0fSChristoph Hellwig }
4454a28bca0fSChristoph Hellwig 
f2fs_file_read_iter(struct kiocb * iocb,struct iov_iter * to)4455a1e09b03SEric Biggers static ssize_t f2fs_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
4456a1e09b03SEric Biggers {
4457a1e09b03SEric Biggers 	struct inode *inode = file_inode(iocb->ki_filp);
4458c277f141SJaegeuk Kim 	const loff_t pos = iocb->ki_pos;
4459a1e09b03SEric Biggers 	ssize_t ret;
44604c8ff709SChao Yu 
44614c8ff709SChao Yu 	if (!f2fs_is_compress_backend_ready(inode))
44624c8ff709SChao Yu 		return -EOPNOTSUPP;
44634c8ff709SChao Yu 
4464a28bca0fSChristoph Hellwig 	if (trace_f2fs_dataread_start_enabled())
4465ceb11d0eSDavid Howells 		f2fs_trace_rw_file_path(iocb->ki_filp, iocb->ki_pos,
4466ceb11d0eSDavid Howells 					iov_iter_count(to), READ);
44678b83ac81SChao Yu 
4468c277f141SJaegeuk Kim 	if (f2fs_should_use_dio(inode, iocb, to)) {
4469c277f141SJaegeuk Kim 		ret = f2fs_dio_read_iter(iocb, to);
4470c277f141SJaegeuk Kim 	} else {
4471a1e09b03SEric Biggers 		ret = filemap_read(iocb, to, 0);
44728b83ac81SChao Yu 		if (ret > 0)
447334a23525SChao Yu 			f2fs_update_iostat(F2FS_I_SB(inode), inode,
447434a23525SChao Yu 						APP_BUFFERED_READ_IO, ret);
4475c277f141SJaegeuk Kim 	}
4476c277f141SJaegeuk Kim 	if (trace_f2fs_dataread_end_enabled())
4477c277f141SJaegeuk Kim 		trace_f2fs_dataread_end(inode, pos, ret);
44788b83ac81SChao Yu 	return ret;
44794c8ff709SChao Yu }
44804c8ff709SChao Yu 
f2fs_file_splice_read(struct file * in,loff_t * ppos,struct pipe_inode_info * pipe,size_t len,unsigned int flags)4481ceb11d0eSDavid Howells static ssize_t f2fs_file_splice_read(struct file *in, loff_t *ppos,
4482ceb11d0eSDavid Howells 				     struct pipe_inode_info *pipe,
4483ceb11d0eSDavid Howells 				     size_t len, unsigned int flags)
4484ceb11d0eSDavid Howells {
4485ceb11d0eSDavid Howells 	struct inode *inode = file_inode(in);
4486ceb11d0eSDavid Howells 	const loff_t pos = *ppos;
4487ceb11d0eSDavid Howells 	ssize_t ret;
4488ceb11d0eSDavid Howells 
4489ceb11d0eSDavid Howells 	if (!f2fs_is_compress_backend_ready(inode))
4490ceb11d0eSDavid Howells 		return -EOPNOTSUPP;
4491ceb11d0eSDavid Howells 
4492ceb11d0eSDavid Howells 	if (trace_f2fs_dataread_start_enabled())
4493ceb11d0eSDavid Howells 		f2fs_trace_rw_file_path(in, pos, len, READ);
4494ceb11d0eSDavid Howells 
4495ceb11d0eSDavid Howells 	ret = filemap_splice_read(in, ppos, pipe, len, flags);
4496ceb11d0eSDavid Howells 	if (ret > 0)
4497ceb11d0eSDavid Howells 		f2fs_update_iostat(F2FS_I_SB(inode), inode,
4498ceb11d0eSDavid Howells 				   APP_BUFFERED_READ_IO, ret);
4499ceb11d0eSDavid Howells 
4500ceb11d0eSDavid Howells 	if (trace_f2fs_dataread_end_enabled())
4501ceb11d0eSDavid Howells 		trace_f2fs_dataread_end(inode, pos, ret);
4502ceb11d0eSDavid Howells 	return ret;
4503ceb11d0eSDavid Howells }
4504ceb11d0eSDavid Howells 
f2fs_write_checks(struct kiocb * iocb,struct iov_iter * from)4505a1e09b03SEric Biggers static ssize_t f2fs_write_checks(struct kiocb *iocb, struct iov_iter *from)
4506a1e09b03SEric Biggers {
4507a1e09b03SEric Biggers 	struct file *file = iocb->ki_filp;
4508a1e09b03SEric Biggers 	struct inode *inode = file_inode(file);
4509a1e09b03SEric Biggers 	ssize_t count;
4510a1e09b03SEric Biggers 	int err;
4511a1e09b03SEric Biggers 
4512a1e09b03SEric Biggers 	if (IS_IMMUTABLE(inode))
4513a1e09b03SEric Biggers 		return -EPERM;
4514a1e09b03SEric Biggers 
4515a1e09b03SEric Biggers 	if (is_inode_flag_set(inode, FI_COMPRESS_RELEASED))
4516a1e09b03SEric Biggers 		return -EPERM;
4517a1e09b03SEric Biggers 
4518a1e09b03SEric Biggers 	count = generic_write_checks(iocb, from);
4519a1e09b03SEric Biggers 	if (count <= 0)
4520a1e09b03SEric Biggers 		return count;
4521a1e09b03SEric Biggers 
4522a1e09b03SEric Biggers 	err = file_modified(file);
4523a1e09b03SEric Biggers 	if (err)
4524a1e09b03SEric Biggers 		return err;
4525a1e09b03SEric Biggers 	return count;
4526a1e09b03SEric Biggers }
4527a1e09b03SEric Biggers 
45283d697a4aSEric Biggers /*
45293d697a4aSEric Biggers  * Preallocate blocks for a write request, if it is possible and helpful to do
45303d697a4aSEric Biggers  * so.  Returns a positive number if blocks may have been preallocated, 0 if no
45313d697a4aSEric Biggers  * blocks were preallocated, or a negative errno value if something went
45323d697a4aSEric Biggers  * seriously wrong.  Also sets FI_PREALLOCATED_ALL on the inode if *all* the
45333d697a4aSEric Biggers  * requested blocks (not just some of them) have been allocated.
45343d697a4aSEric Biggers  */
f2fs_preallocate_blocks(struct kiocb * iocb,struct iov_iter * iter,bool dio)4535a1e09b03SEric Biggers static int f2fs_preallocate_blocks(struct kiocb *iocb, struct iov_iter *iter,
4536a1e09b03SEric Biggers 				   bool dio)
45373d697a4aSEric Biggers {
45383d697a4aSEric Biggers 	struct inode *inode = file_inode(iocb->ki_filp);
45393d697a4aSEric Biggers 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
45403d697a4aSEric Biggers 	const loff_t pos = iocb->ki_pos;
45413d697a4aSEric Biggers 	const size_t count = iov_iter_count(iter);
45423d697a4aSEric Biggers 	struct f2fs_map_blocks map = {};
45433d697a4aSEric Biggers 	int flag;
45443d697a4aSEric Biggers 	int ret;
45453d697a4aSEric Biggers 
45463d697a4aSEric Biggers 	/* If it will be an out-of-place direct write, don't bother. */
45473d697a4aSEric Biggers 	if (dio && f2fs_lfs_mode(sbi))
45483d697a4aSEric Biggers 		return 0;
4549d4dd19ecSJaegeuk Kim 	/*
4550d4dd19ecSJaegeuk Kim 	 * Don't preallocate holes aligned to DIO_SKIP_HOLES which turns into
4551d4dd19ecSJaegeuk Kim 	 * buffered IO, if DIO meets any holes.
4552d4dd19ecSJaegeuk Kim 	 */
4553d4dd19ecSJaegeuk Kim 	if (dio && i_size_read(inode) &&
4554d4dd19ecSJaegeuk Kim 		(F2FS_BYTES_TO_BLK(pos) < F2FS_BLK_ALIGN(i_size_read(inode))))
4555d4dd19ecSJaegeuk Kim 		return 0;
45563d697a4aSEric Biggers 
45573d697a4aSEric Biggers 	/* No-wait I/O can't allocate blocks. */
45583d697a4aSEric Biggers 	if (iocb->ki_flags & IOCB_NOWAIT)
45593d697a4aSEric Biggers 		return 0;
45603d697a4aSEric Biggers 
45613d697a4aSEric Biggers 	/* If it will be a short write, don't bother. */
45623d697a4aSEric Biggers 	if (fault_in_iov_iter_readable(iter, count))
45633d697a4aSEric Biggers 		return 0;
45643d697a4aSEric Biggers 
45653d697a4aSEric Biggers 	if (f2fs_has_inline_data(inode)) {
45663d697a4aSEric Biggers 		/* If the data will fit inline, don't bother. */
45673d697a4aSEric Biggers 		if (pos + count <= MAX_INLINE_DATA(inode))
45683d697a4aSEric Biggers 			return 0;
45693d697a4aSEric Biggers 		ret = f2fs_convert_inline_inode(inode);
45703d697a4aSEric Biggers 		if (ret)
45713d697a4aSEric Biggers 			return ret;
45723d697a4aSEric Biggers 	}
45733d697a4aSEric Biggers 
45743d697a4aSEric Biggers 	/* Do not preallocate blocks that will be written partially in 4KB. */
45753d697a4aSEric Biggers 	map.m_lblk = F2FS_BLK_ALIGN(pos);
45763d697a4aSEric Biggers 	map.m_len = F2FS_BYTES_TO_BLK(pos + count);
45773d697a4aSEric Biggers 	if (map.m_len > map.m_lblk)
45783d697a4aSEric Biggers 		map.m_len -= map.m_lblk;
45793d697a4aSEric Biggers 	else
45803d697a4aSEric Biggers 		map.m_len = 0;
45813d697a4aSEric Biggers 	map.m_may_create = true;
45823d697a4aSEric Biggers 	if (dio) {
45833d697a4aSEric Biggers 		map.m_seg_type = f2fs_rw_hint_to_seg_type(inode->i_write_hint);
45843d697a4aSEric Biggers 		flag = F2FS_GET_BLOCK_PRE_DIO;
45853d697a4aSEric Biggers 	} else {
45863d697a4aSEric Biggers 		map.m_seg_type = NO_CHECK_TYPE;
45873d697a4aSEric Biggers 		flag = F2FS_GET_BLOCK_PRE_AIO;
45883d697a4aSEric Biggers 	}
45893d697a4aSEric Biggers 
4590cd8fc522SChristoph Hellwig 	ret = f2fs_map_blocks(inode, &map, flag);
4591d4dd19ecSJaegeuk Kim 	/* -ENOSPC|-EDQUOT are fine to report the number of allocated blocks. */
4592d4dd19ecSJaegeuk Kim 	if (ret < 0 && !((ret == -ENOSPC || ret == -EDQUOT) && map.m_len > 0))
45933d697a4aSEric Biggers 		return ret;
45943d697a4aSEric Biggers 	if (ret == 0)
45953d697a4aSEric Biggers 		set_inode_flag(inode, FI_PREALLOCATED_ALL);
45963d697a4aSEric Biggers 	return map.m_len;
45973d697a4aSEric Biggers }
45983d697a4aSEric Biggers 
f2fs_buffered_write_iter(struct kiocb * iocb,struct iov_iter * from)4599a1e09b03SEric Biggers static ssize_t f2fs_buffered_write_iter(struct kiocb *iocb,
4600a1e09b03SEric Biggers 					struct iov_iter *from)
4601fcc85a4dSJaegeuk Kim {
4602b439b103SJaegeuk Kim 	struct file *file = iocb->ki_filp;
4603b439b103SJaegeuk Kim 	struct inode *inode = file_inode(file);
4604a1e09b03SEric Biggers 	ssize_t ret;
4605a1e09b03SEric Biggers 
4606a1e09b03SEric Biggers 	if (iocb->ki_flags & IOCB_NOWAIT)
4607a1e09b03SEric Biggers 		return -EOPNOTSUPP;
4608a1e09b03SEric Biggers 
4609800ba295SMatthew Wilcox (Oracle) 	ret = generic_perform_write(iocb, from);
4610a1e09b03SEric Biggers 
4611a1e09b03SEric Biggers 	if (ret > 0) {
461234a23525SChao Yu 		f2fs_update_iostat(F2FS_I_SB(inode), inode,
461334a23525SChao Yu 						APP_BUFFERED_IO, ret);
4614a1e09b03SEric Biggers 	}
4615a1e09b03SEric Biggers 	return ret;
4616a1e09b03SEric Biggers }
4617a1e09b03SEric Biggers 
f2fs_dio_write_end_io(struct kiocb * iocb,ssize_t size,int error,unsigned int flags)4618a1e09b03SEric Biggers static int f2fs_dio_write_end_io(struct kiocb *iocb, ssize_t size, int error,
4619a1e09b03SEric Biggers 				 unsigned int flags)
4620a1e09b03SEric Biggers {
4621a1e09b03SEric Biggers 	struct f2fs_sb_info *sbi = F2FS_I_SB(file_inode(iocb->ki_filp));
4622a1e09b03SEric Biggers 
4623a1e09b03SEric Biggers 	dec_page_count(sbi, F2FS_DIO_WRITE);
4624a1e09b03SEric Biggers 	if (error)
4625a1e09b03SEric Biggers 		return error;
46260cc81b1aSZhiguo Niu 	f2fs_update_time(sbi, REQ_TIME);
462734a23525SChao Yu 	f2fs_update_iostat(sbi, NULL, APP_DIRECT_IO, size);
4628a1e09b03SEric Biggers 	return 0;
4629a1e09b03SEric Biggers }
4630a1e09b03SEric Biggers 
4631a1e09b03SEric Biggers static const struct iomap_dio_ops f2fs_iomap_dio_write_ops = {
4632a1e09b03SEric Biggers 	.end_io = f2fs_dio_write_end_io,
4633a1e09b03SEric Biggers };
4634a1e09b03SEric Biggers 
f2fs_flush_buffered_write(struct address_space * mapping,loff_t start_pos,loff_t end_pos)463592318f20SHans Holmberg static void f2fs_flush_buffered_write(struct address_space *mapping,
463692318f20SHans Holmberg 				      loff_t start_pos, loff_t end_pos)
463792318f20SHans Holmberg {
463892318f20SHans Holmberg 	int ret;
463992318f20SHans Holmberg 
464092318f20SHans Holmberg 	ret = filemap_write_and_wait_range(mapping, start_pos, end_pos);
464192318f20SHans Holmberg 	if (ret < 0)
464292318f20SHans Holmberg 		return;
464392318f20SHans Holmberg 	invalidate_mapping_pages(mapping,
464492318f20SHans Holmberg 				 start_pos >> PAGE_SHIFT,
464592318f20SHans Holmberg 				 end_pos >> PAGE_SHIFT);
464692318f20SHans Holmberg }
464792318f20SHans Holmberg 
f2fs_dio_write_iter(struct kiocb * iocb,struct iov_iter * from,bool * may_need_sync)4648a1e09b03SEric Biggers static ssize_t f2fs_dio_write_iter(struct kiocb *iocb, struct iov_iter *from,
4649a1e09b03SEric Biggers 				   bool *may_need_sync)
4650a1e09b03SEric Biggers {
4651a1e09b03SEric Biggers 	struct file *file = iocb->ki_filp;
4652a1e09b03SEric Biggers 	struct inode *inode = file_inode(file);
4653a1e09b03SEric Biggers 	struct f2fs_inode_info *fi = F2FS_I(inode);
4654a1e09b03SEric Biggers 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
4655a1e09b03SEric Biggers 	const bool do_opu = f2fs_lfs_mode(sbi);
4656a1e09b03SEric Biggers 	const loff_t pos = iocb->ki_pos;
4657a1e09b03SEric Biggers 	const ssize_t count = iov_iter_count(from);
4658a1e09b03SEric Biggers 	unsigned int dio_flags;
4659a1e09b03SEric Biggers 	struct iomap_dio *dio;
4660a1e09b03SEric Biggers 	ssize_t ret;
4661a1e09b03SEric Biggers 
4662bd984c03SJaegeuk Kim 	trace_f2fs_direct_IO_enter(inode, iocb, count, WRITE);
4663a1e09b03SEric Biggers 
4664a1e09b03SEric Biggers 	if (iocb->ki_flags & IOCB_NOWAIT) {
4665a1e09b03SEric Biggers 		/* f2fs_convert_inline_inode() and block allocation can block */
4666a1e09b03SEric Biggers 		if (f2fs_has_inline_data(inode) ||
4667a1e09b03SEric Biggers 		    !f2fs_overwrite_io(inode, pos, count)) {
4668a1e09b03SEric Biggers 			ret = -EAGAIN;
4669a1e09b03SEric Biggers 			goto out;
4670a1e09b03SEric Biggers 		}
4671a1e09b03SEric Biggers 
4672e4544b63STim Murray 		if (!f2fs_down_read_trylock(&fi->i_gc_rwsem[WRITE])) {
4673a1e09b03SEric Biggers 			ret = -EAGAIN;
4674a1e09b03SEric Biggers 			goto out;
4675a1e09b03SEric Biggers 		}
4676e4544b63STim Murray 		if (do_opu && !f2fs_down_read_trylock(&fi->i_gc_rwsem[READ])) {
4677e4544b63STim Murray 			f2fs_up_read(&fi->i_gc_rwsem[WRITE]);
4678a1e09b03SEric Biggers 			ret = -EAGAIN;
4679a1e09b03SEric Biggers 			goto out;
4680a1e09b03SEric Biggers 		}
4681a1e09b03SEric Biggers 	} else {
4682a1e09b03SEric Biggers 		ret = f2fs_convert_inline_inode(inode);
4683a1e09b03SEric Biggers 		if (ret)
4684a1e09b03SEric Biggers 			goto out;
4685a1e09b03SEric Biggers 
4686e4544b63STim Murray 		f2fs_down_read(&fi->i_gc_rwsem[WRITE]);
4687a1e09b03SEric Biggers 		if (do_opu)
4688e4544b63STim Murray 			f2fs_down_read(&fi->i_gc_rwsem[READ]);
4689a1e09b03SEric Biggers 	}
4690a1e09b03SEric Biggers 
4691a1e09b03SEric Biggers 	/*
4692a1e09b03SEric Biggers 	 * We have to use __iomap_dio_rw() and iomap_dio_complete() instead of
4693a1e09b03SEric Biggers 	 * the higher-level function iomap_dio_rw() in order to ensure that the
4694a1e09b03SEric Biggers 	 * F2FS_DIO_WRITE counter will be decremented correctly in all cases.
4695a1e09b03SEric Biggers 	 */
4696a1e09b03SEric Biggers 	inc_page_count(sbi, F2FS_DIO_WRITE);
4697a1e09b03SEric Biggers 	dio_flags = 0;
4698a1e09b03SEric Biggers 	if (pos + count > inode->i_size)
4699a1e09b03SEric Biggers 		dio_flags |= IOMAP_DIO_FORCE_WAIT;
4700a1e09b03SEric Biggers 	dio = __iomap_dio_rw(iocb, from, &f2fs_iomap_ops,
4701786f847fSChristoph Hellwig 			     &f2fs_iomap_dio_write_ops, dio_flags, NULL, 0);
4702a1e09b03SEric Biggers 	if (IS_ERR_OR_NULL(dio)) {
4703a1e09b03SEric Biggers 		ret = PTR_ERR_OR_ZERO(dio);
4704a1e09b03SEric Biggers 		if (ret == -ENOTBLK)
4705a1e09b03SEric Biggers 			ret = 0;
4706a1e09b03SEric Biggers 		if (ret != -EIOCBQUEUED)
4707a1e09b03SEric Biggers 			dec_page_count(sbi, F2FS_DIO_WRITE);
4708a1e09b03SEric Biggers 	} else {
4709a1e09b03SEric Biggers 		ret = iomap_dio_complete(dio);
4710a1e09b03SEric Biggers 	}
4711a1e09b03SEric Biggers 
4712a1e09b03SEric Biggers 	if (do_opu)
4713e4544b63STim Murray 		f2fs_up_read(&fi->i_gc_rwsem[READ]);
4714e4544b63STim Murray 	f2fs_up_read(&fi->i_gc_rwsem[WRITE]);
4715a1e09b03SEric Biggers 
4716a1e09b03SEric Biggers 	if (ret < 0)
4717a1e09b03SEric Biggers 		goto out;
4718a1e09b03SEric Biggers 	if (pos + ret > inode->i_size)
4719a1e09b03SEric Biggers 		f2fs_i_size_write(inode, pos + ret);
4720a1e09b03SEric Biggers 	if (!do_opu)
4721a1e09b03SEric Biggers 		set_inode_flag(inode, FI_UPDATE_WRITE);
4722a1e09b03SEric Biggers 
4723a1e09b03SEric Biggers 	if (iov_iter_count(from)) {
4724a1e09b03SEric Biggers 		ssize_t ret2;
4725a1e09b03SEric Biggers 		loff_t bufio_start_pos = iocb->ki_pos;
4726a1e09b03SEric Biggers 
4727a1e09b03SEric Biggers 		/*
4728a1e09b03SEric Biggers 		 * The direct write was partial, so we need to fall back to a
4729a1e09b03SEric Biggers 		 * buffered write for the remainder.
4730a1e09b03SEric Biggers 		 */
4731a1e09b03SEric Biggers 
4732a1e09b03SEric Biggers 		ret2 = f2fs_buffered_write_iter(iocb, from);
4733a1e09b03SEric Biggers 		if (iov_iter_count(from))
4734a1e09b03SEric Biggers 			f2fs_write_failed(inode, iocb->ki_pos);
4735a1e09b03SEric Biggers 		if (ret2 < 0)
4736a1e09b03SEric Biggers 			goto out;
4737a1e09b03SEric Biggers 
4738a1e09b03SEric Biggers 		/*
4739a1e09b03SEric Biggers 		 * Ensure that the pagecache pages are written to disk and
4740a1e09b03SEric Biggers 		 * invalidated to preserve the expected O_DIRECT semantics.
4741a1e09b03SEric Biggers 		 */
4742a1e09b03SEric Biggers 		if (ret2 > 0) {
4743a1e09b03SEric Biggers 			loff_t bufio_end_pos = bufio_start_pos + ret2 - 1;
4744a1e09b03SEric Biggers 
4745a1e09b03SEric Biggers 			ret += ret2;
4746a1e09b03SEric Biggers 
474792318f20SHans Holmberg 			f2fs_flush_buffered_write(file->f_mapping,
4748a1e09b03SEric Biggers 						  bufio_start_pos,
4749a1e09b03SEric Biggers 						  bufio_end_pos);
4750a1e09b03SEric Biggers 		}
4751a1e09b03SEric Biggers 	} else {
4752a1e09b03SEric Biggers 		/* iomap_dio_rw() already handled the generic_write_sync(). */
4753a1e09b03SEric Biggers 		*may_need_sync = false;
4754a1e09b03SEric Biggers 	}
4755a1e09b03SEric Biggers out:
4756a1e09b03SEric Biggers 	trace_f2fs_direct_IO_exit(inode, pos, count, WRITE, ret);
4757a1e09b03SEric Biggers 	return ret;
4758a1e09b03SEric Biggers }
4759a1e09b03SEric Biggers 
f2fs_file_write_iter(struct kiocb * iocb,struct iov_iter * from)4760a1e09b03SEric Biggers static ssize_t f2fs_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
4761a1e09b03SEric Biggers {
4762a1e09b03SEric Biggers 	struct inode *inode = file_inode(iocb->ki_filp);
4763ccf7cf92SEric Biggers 	const loff_t orig_pos = iocb->ki_pos;
4764ccf7cf92SEric Biggers 	const size_t orig_count = iov_iter_count(from);
47653d697a4aSEric Biggers 	loff_t target_size;
4766a1e09b03SEric Biggers 	bool dio;
4767a1e09b03SEric Biggers 	bool may_need_sync = true;
47683d697a4aSEric Biggers 	int preallocated;
4769b439b103SJaegeuk Kim 	ssize_t ret;
4770fcc85a4dSJaegeuk Kim 
4771126ce721SChao Yu 	if (unlikely(f2fs_cp_error(F2FS_I_SB(inode)))) {
4772126ce721SChao Yu 		ret = -EIO;
4773126ce721SChao Yu 		goto out;
4774126ce721SChao Yu 	}
47751f227a3eSJaegeuk Kim 
47767bd29358SChao Yu 	if (!f2fs_is_compress_backend_ready(inode)) {
47777bd29358SChao Yu 		ret = -EOPNOTSUPP;
47787bd29358SChao Yu 		goto out;
47797bd29358SChao Yu 	}
47804c8ff709SChao Yu 
4781126ce721SChao Yu 	if (iocb->ki_flags & IOCB_NOWAIT) {
4782cb8434f1SGoldwyn Rodrigues 		if (!inode_trylock(inode)) {
4783126ce721SChao Yu 			ret = -EAGAIN;
4784126ce721SChao Yu 			goto out;
4785126ce721SChao Yu 		}
4786cb8434f1SGoldwyn Rodrigues 	} else {
4787b439b103SJaegeuk Kim 		inode_lock(inode);
4788b91050a8SHyunchul Lee 	}
4789b91050a8SHyunchul Lee 
4790a1e09b03SEric Biggers 	ret = f2fs_write_checks(iocb, from);
4791b31bf0f9SEric Biggers 	if (ret <= 0)
4792b31bf0f9SEric Biggers 		goto out_unlock;
4793b31bf0f9SEric Biggers 
4794a1e09b03SEric Biggers 	/* Determine whether we will do a direct write or a buffered write. */
4795a1e09b03SEric Biggers 	dio = f2fs_should_use_dio(inode, iocb, from);
4796b31bf0f9SEric Biggers 
47973d697a4aSEric Biggers 	/* Possibly preallocate the blocks for the write. */
4798dc7a10ddSJaegeuk Kim 	target_size = iocb->ki_pos + iov_iter_count(from);
4799a1e09b03SEric Biggers 	preallocated = f2fs_preallocate_blocks(iocb, from, dio);
4800c277f141SJaegeuk Kim 	if (preallocated < 0) {
48013d697a4aSEric Biggers 		ret = preallocated;
4802c277f141SJaegeuk Kim 	} else {
4803a28bca0fSChristoph Hellwig 		if (trace_f2fs_datawrite_start_enabled())
4804ceb11d0eSDavid Howells 			f2fs_trace_rw_file_path(iocb->ki_filp, iocb->ki_pos,
4805ceb11d0eSDavid Howells 						orig_count, WRITE);
4806c277f141SJaegeuk Kim 
4807a1e09b03SEric Biggers 		/* Do the actual write. */
4808a1e09b03SEric Biggers 		ret = dio ?
4809a1e09b03SEric Biggers 			f2fs_dio_write_iter(iocb, from, &may_need_sync) :
4810a1e09b03SEric Biggers 			f2fs_buffered_write_iter(iocb, from);
48113d697a4aSEric Biggers 
4812c277f141SJaegeuk Kim 		if (trace_f2fs_datawrite_end_enabled())
4813c277f141SJaegeuk Kim 			trace_f2fs_datawrite_end(inode, orig_pos, ret);
4814c277f141SJaegeuk Kim 	}
4815c277f141SJaegeuk Kim 
48163d697a4aSEric Biggers 	/* Don't leave any preallocated blocks around past i_size. */
4817d4dd19ecSJaegeuk Kim 	if (preallocated && i_size_read(inode) < target_size) {
4818e4544b63STim Murray 		f2fs_down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
4819edc6d01bSJan Kara 		filemap_invalidate_lock(inode->i_mapping);
4820d4dd19ecSJaegeuk Kim 		if (!f2fs_truncate(inode))
4821d4dd19ecSJaegeuk Kim 			file_dont_truncate(inode);
4822edc6d01bSJan Kara 		filemap_invalidate_unlock(inode->i_mapping);
4823e4544b63STim Murray 		f2fs_up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
4824d4dd19ecSJaegeuk Kim 	} else {
4825d4dd19ecSJaegeuk Kim 		file_dont_truncate(inode);
4826a303b0acSChao Yu 	}
4827b31bf0f9SEric Biggers 
48283d697a4aSEric Biggers 	clear_inode_flag(inode, FI_PREALLOCATED_ALL);
48293d697a4aSEric Biggers out_unlock:
4830b439b103SJaegeuk Kim 	inode_unlock(inode);
4831126ce721SChao Yu out:
4832ccf7cf92SEric Biggers 	trace_f2fs_file_write_iter(inode, orig_pos, orig_count, ret);
483392318f20SHans Holmberg 
4834a1e09b03SEric Biggers 	if (ret > 0 && may_need_sync)
4835e2592217SChristoph Hellwig 		ret = generic_write_sync(iocb, ret);
483692318f20SHans Holmberg 
483792318f20SHans Holmberg 	/* If buffered IO was forced, flush and drop the data from
483892318f20SHans Holmberg 	 * the page cache to preserve O_DIRECT semantics
483992318f20SHans Holmberg 	 */
484092318f20SHans Holmberg 	if (ret > 0 && !dio && (iocb->ki_flags & IOCB_DIRECT))
484192318f20SHans Holmberg 		f2fs_flush_buffered_write(iocb->ki_filp->f_mapping,
484292318f20SHans Holmberg 					  orig_pos,
484392318f20SHans Holmberg 					  orig_pos + ret - 1);
484492318f20SHans Holmberg 
4845b439b103SJaegeuk Kim 	return ret;
4846fcc85a4dSJaegeuk Kim }
4847fcc85a4dSJaegeuk Kim 
f2fs_file_fadvise(struct file * filp,loff_t offset,loff_t len,int advice)48480f6b56ecSDaeho Jeong static int f2fs_file_fadvise(struct file *filp, loff_t offset, loff_t len,
48490f6b56ecSDaeho Jeong 		int advice)
48500f6b56ecSDaeho Jeong {
48510f6b56ecSDaeho Jeong 	struct address_space *mapping;
48520f6b56ecSDaeho Jeong 	struct backing_dev_info *bdi;
4853e64347aeSFengnan Chang 	struct inode *inode = file_inode(filp);
4854e64347aeSFengnan Chang 	int err;
48550f6b56ecSDaeho Jeong 
48560f6b56ecSDaeho Jeong 	if (advice == POSIX_FADV_SEQUENTIAL) {
48570f6b56ecSDaeho Jeong 		if (S_ISFIFO(inode->i_mode))
48580f6b56ecSDaeho Jeong 			return -ESPIPE;
48590f6b56ecSDaeho Jeong 
48600f6b56ecSDaeho Jeong 		mapping = filp->f_mapping;
48610f6b56ecSDaeho Jeong 		if (!mapping || len < 0)
48620f6b56ecSDaeho Jeong 			return -EINVAL;
48630f6b56ecSDaeho Jeong 
48640f6b56ecSDaeho Jeong 		bdi = inode_to_bdi(mapping->host);
48650f6b56ecSDaeho Jeong 		filp->f_ra.ra_pages = bdi->ra_pages *
48660f6b56ecSDaeho Jeong 			F2FS_I_SB(inode)->seq_file_ra_mul;
48670f6b56ecSDaeho Jeong 		spin_lock(&filp->f_lock);
48680f6b56ecSDaeho Jeong 		filp->f_mode &= ~FMODE_RANDOM;
48690f6b56ecSDaeho Jeong 		spin_unlock(&filp->f_lock);
48700f6b56ecSDaeho Jeong 		return 0;
48710f6b56ecSDaeho Jeong 	}
48720f6b56ecSDaeho Jeong 
4873e64347aeSFengnan Chang 	err = generic_fadvise(filp, offset, len, advice);
4874e64347aeSFengnan Chang 	if (!err && advice == POSIX_FADV_DONTNEED &&
4875e64347aeSFengnan Chang 		test_opt(F2FS_I_SB(inode), COMPRESS_CACHE) &&
4876e64347aeSFengnan Chang 		f2fs_compressed_file(inode))
4877e64347aeSFengnan Chang 		f2fs_invalidate_compress_pages(F2FS_I_SB(inode), inode->i_ino);
4878e64347aeSFengnan Chang 
4879e64347aeSFengnan Chang 	return err;
48800f6b56ecSDaeho Jeong }
48810f6b56ecSDaeho Jeong 
4882fbfa2cc5SJaegeuk Kim #ifdef CONFIG_COMPAT
488334178b1bSChao Yu struct compat_f2fs_gc_range {
488434178b1bSChao Yu 	u32 sync;
488534178b1bSChao Yu 	compat_u64 start;
488634178b1bSChao Yu 	compat_u64 len;
488734178b1bSChao Yu };
488834178b1bSChao Yu #define F2FS_IOC32_GARBAGE_COLLECT_RANGE	_IOW(F2FS_IOCTL_MAGIC, 11,\
488934178b1bSChao Yu 						struct compat_f2fs_gc_range)
489034178b1bSChao Yu 
f2fs_compat_ioc_gc_range(struct file * file,unsigned long arg)489134178b1bSChao Yu static int f2fs_compat_ioc_gc_range(struct file *file, unsigned long arg)
489234178b1bSChao Yu {
489334178b1bSChao Yu 	struct compat_f2fs_gc_range __user *urange;
489434178b1bSChao Yu 	struct f2fs_gc_range range;
489534178b1bSChao Yu 	int err;
489634178b1bSChao Yu 
489734178b1bSChao Yu 	urange = compat_ptr(arg);
489834178b1bSChao Yu 	err = get_user(range.sync, &urange->sync);
489934178b1bSChao Yu 	err |= get_user(range.start, &urange->start);
490034178b1bSChao Yu 	err |= get_user(range.len, &urange->len);
490134178b1bSChao Yu 	if (err)
490234178b1bSChao Yu 		return -EFAULT;
490334178b1bSChao Yu 
490434178b1bSChao Yu 	return __f2fs_ioc_gc_range(file, &range);
490534178b1bSChao Yu }
490634178b1bSChao Yu 
490734178b1bSChao Yu struct compat_f2fs_move_range {
490834178b1bSChao Yu 	u32 dst_fd;
490934178b1bSChao Yu 	compat_u64 pos_in;
491034178b1bSChao Yu 	compat_u64 pos_out;
491134178b1bSChao Yu 	compat_u64 len;
491234178b1bSChao Yu };
491334178b1bSChao Yu #define F2FS_IOC32_MOVE_RANGE		_IOWR(F2FS_IOCTL_MAGIC, 9,	\
491434178b1bSChao Yu 					struct compat_f2fs_move_range)
491534178b1bSChao Yu 
f2fs_compat_ioc_move_range(struct file * file,unsigned long arg)491634178b1bSChao Yu static int f2fs_compat_ioc_move_range(struct file *file, unsigned long arg)
491734178b1bSChao Yu {
491834178b1bSChao Yu 	struct compat_f2fs_move_range __user *urange;
491934178b1bSChao Yu 	struct f2fs_move_range range;
492034178b1bSChao Yu 	int err;
492134178b1bSChao Yu 
492234178b1bSChao Yu 	urange = compat_ptr(arg);
492334178b1bSChao Yu 	err = get_user(range.dst_fd, &urange->dst_fd);
492434178b1bSChao Yu 	err |= get_user(range.pos_in, &urange->pos_in);
492534178b1bSChao Yu 	err |= get_user(range.pos_out, &urange->pos_out);
492634178b1bSChao Yu 	err |= get_user(range.len, &urange->len);
492734178b1bSChao Yu 	if (err)
492834178b1bSChao Yu 		return -EFAULT;
492934178b1bSChao Yu 
493034178b1bSChao Yu 	return __f2fs_ioc_move_range(file, &range);
493134178b1bSChao Yu }
493234178b1bSChao Yu 
f2fs_compat_ioctl(struct file * file,unsigned int cmd,unsigned long arg)4933fbfa2cc5SJaegeuk Kim long f2fs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
4934fbfa2cc5SJaegeuk Kim {
493534178b1bSChao Yu 	if (unlikely(f2fs_cp_error(F2FS_I_SB(file_inode(file)))))
493634178b1bSChao Yu 		return -EIO;
493734178b1bSChao Yu 	if (!f2fs_is_checkpoint_ready(F2FS_I_SB(file_inode(file))))
493834178b1bSChao Yu 		return -ENOSPC;
493934178b1bSChao Yu 
4940fbfa2cc5SJaegeuk Kim 	switch (cmd) {
49413357af8fSEric Biggers 	case FS_IOC32_GETVERSION:
49423357af8fSEric Biggers 		cmd = FS_IOC_GETVERSION;
494304ef4b62SChao Yu 		break;
494434178b1bSChao Yu 	case F2FS_IOC32_GARBAGE_COLLECT_RANGE:
494534178b1bSChao Yu 		return f2fs_compat_ioc_gc_range(file, arg);
494634178b1bSChao Yu 	case F2FS_IOC32_MOVE_RANGE:
494734178b1bSChao Yu 		return f2fs_compat_ioc_move_range(file, arg);
494804ef4b62SChao Yu 	case F2FS_IOC_START_ATOMIC_WRITE:
4949933141e4SChao Yu 	case F2FS_IOC_START_ATOMIC_REPLACE:
495004ef4b62SChao Yu 	case F2FS_IOC_COMMIT_ATOMIC_WRITE:
495104ef4b62SChao Yu 	case F2FS_IOC_START_VOLATILE_WRITE:
495204ef4b62SChao Yu 	case F2FS_IOC_RELEASE_VOLATILE_WRITE:
495323339e57SDaeho Jeong 	case F2FS_IOC_ABORT_ATOMIC_WRITE:
495404ef4b62SChao Yu 	case F2FS_IOC_SHUTDOWN:
4955314999dcSArnd Bergmann 	case FITRIM:
49563357af8fSEric Biggers 	case FS_IOC_SET_ENCRYPTION_POLICY:
49573357af8fSEric Biggers 	case FS_IOC_GET_ENCRYPTION_PWSALT:
49583357af8fSEric Biggers 	case FS_IOC_GET_ENCRYPTION_POLICY:
49598ce589c7SEric Biggers 	case FS_IOC_GET_ENCRYPTION_POLICY_EX:
49608ce589c7SEric Biggers 	case FS_IOC_ADD_ENCRYPTION_KEY:
49618ce589c7SEric Biggers 	case FS_IOC_REMOVE_ENCRYPTION_KEY:
49628ce589c7SEric Biggers 	case FS_IOC_REMOVE_ENCRYPTION_KEY_ALL_USERS:
49638ce589c7SEric Biggers 	case FS_IOC_GET_ENCRYPTION_KEY_STATUS:
4964ee446e1aSEric Biggers 	case FS_IOC_GET_ENCRYPTION_NONCE:
496504ef4b62SChao Yu 	case F2FS_IOC_GARBAGE_COLLECT:
496604ef4b62SChao Yu 	case F2FS_IOC_WRITE_CHECKPOINT:
496704ef4b62SChao Yu 	case F2FS_IOC_DEFRAGMENT:
4968e066b83cSJaegeuk Kim 	case F2FS_IOC_FLUSH_DEVICE:
4969e65ef207SJaegeuk Kim 	case F2FS_IOC_GET_FEATURES:
49701ad71a27SJaegeuk Kim 	case F2FS_IOC_GET_PIN_FILE:
49711ad71a27SJaegeuk Kim 	case F2FS_IOC_SET_PIN_FILE:
4972c4020b2dSChao Yu 	case F2FS_IOC_PRECACHE_EXTENTS:
497304f0b2eaSQiuyang Sun 	case F2FS_IOC_RESIZE_FS:
497495ae251fSEric Biggers 	case FS_IOC_ENABLE_VERITY:
497595ae251fSEric Biggers 	case FS_IOC_MEASURE_VERITY:
4976e17fe657SEric Biggers 	case FS_IOC_READ_VERITY_METADATA:
49773357af8fSEric Biggers 	case FS_IOC_GETFSLABEL:
49783357af8fSEric Biggers 	case FS_IOC_SETFSLABEL:
4979439dfb10SChao Yu 	case F2FS_IOC_GET_COMPRESS_BLOCKS:
4980ef8d563fSChao Yu 	case F2FS_IOC_RELEASE_COMPRESS_BLOCKS:
4981c75488fbSChao Yu 	case F2FS_IOC_RESERVE_COMPRESS_BLOCKS:
49829af84648SDaeho Jeong 	case F2FS_IOC_SEC_TRIM_FILE:
49839e2a5f8cSDaeho Jeong 	case F2FS_IOC_GET_COMPRESS_OPTION:
4984e1e8debeSDaeho Jeong 	case F2FS_IOC_SET_COMPRESS_OPTION:
49855fdb322fSDaeho Jeong 	case F2FS_IOC_DECOMPRESS_FILE:
49865fdb322fSDaeho Jeong 	case F2FS_IOC_COMPRESS_FILE:
49874dd6f977SJaegeuk Kim 		break;
4988fbfa2cc5SJaegeuk Kim 	default:
4989fbfa2cc5SJaegeuk Kim 		return -ENOIOCTLCMD;
4990fbfa2cc5SJaegeuk Kim 	}
499134178b1bSChao Yu 	return __f2fs_ioctl(file, cmd, (unsigned long) compat_ptr(arg));
4992fbfa2cc5SJaegeuk Kim }
4993fbfa2cc5SJaegeuk Kim #endif
4994fbfa2cc5SJaegeuk Kim 
4995fbfa2cc5SJaegeuk Kim const struct file_operations f2fs_file_operations = {
4996267378d4SChao Yu 	.llseek		= f2fs_llseek,
49974c8ff709SChao Yu 	.read_iter	= f2fs_file_read_iter,
4998fcc85a4dSJaegeuk Kim 	.write_iter	= f2fs_file_write_iter,
499950aa6f44SWu Bo 	.iopoll		= iocb_bio_iopoll,
5000fcc85a4dSJaegeuk Kim 	.open		= f2fs_file_open,
500112662234SJaegeuk Kim 	.release	= f2fs_release_file,
5002fbfa2cc5SJaegeuk Kim 	.mmap		= f2fs_file_mmap,
50037a10f017SJaegeuk Kim 	.flush		= f2fs_file_flush,
5004fbfa2cc5SJaegeuk Kim 	.fsync		= f2fs_sync_file,
5005fbfa2cc5SJaegeuk Kim 	.fallocate	= f2fs_fallocate,
5006fbfa2cc5SJaegeuk Kim 	.unlocked_ioctl	= f2fs_ioctl,
5007e9750824SNamjae Jeon #ifdef CONFIG_COMPAT
5008e9750824SNamjae Jeon 	.compat_ioctl	= f2fs_compat_ioctl,
5009e9750824SNamjae Jeon #endif
5010ceb11d0eSDavid Howells 	.splice_read	= f2fs_file_splice_read,
50118d020765SAl Viro 	.splice_write	= iter_file_splice_write,
50120f6b56ecSDaeho Jeong 	.fadvise	= f2fs_file_fadvise,
5013fbfa2cc5SJaegeuk Kim };
5014