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