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