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