162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * fs/f2fs/file.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2012 Samsung Electronics Co., Ltd. 662306a36Sopenharmony_ci * http://www.samsung.com/ 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci#include <linux/fs.h> 962306a36Sopenharmony_ci#include <linux/f2fs_fs.h> 1062306a36Sopenharmony_ci#include <linux/stat.h> 1162306a36Sopenharmony_ci#include <linux/buffer_head.h> 1262306a36Sopenharmony_ci#include <linux/writeback.h> 1362306a36Sopenharmony_ci#include <linux/blkdev.h> 1462306a36Sopenharmony_ci#include <linux/falloc.h> 1562306a36Sopenharmony_ci#include <linux/types.h> 1662306a36Sopenharmony_ci#include <linux/compat.h> 1762306a36Sopenharmony_ci#include <linux/uaccess.h> 1862306a36Sopenharmony_ci#include <linux/mount.h> 1962306a36Sopenharmony_ci#include <linux/pagevec.h> 2062306a36Sopenharmony_ci#include <linux/uio.h> 2162306a36Sopenharmony_ci#include <linux/uuid.h> 2262306a36Sopenharmony_ci#include <linux/file.h> 2362306a36Sopenharmony_ci#include <linux/nls.h> 2462306a36Sopenharmony_ci#include <linux/sched/signal.h> 2562306a36Sopenharmony_ci#include <linux/fileattr.h> 2662306a36Sopenharmony_ci#include <linux/fadvise.h> 2762306a36Sopenharmony_ci#include <linux/iomap.h> 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#include "f2fs.h" 3062306a36Sopenharmony_ci#include "node.h" 3162306a36Sopenharmony_ci#include "segment.h" 3262306a36Sopenharmony_ci#include "xattr.h" 3362306a36Sopenharmony_ci#include "acl.h" 3462306a36Sopenharmony_ci#include "gc.h" 3562306a36Sopenharmony_ci#include "iostat.h" 3662306a36Sopenharmony_ci#include <trace/events/f2fs.h> 3762306a36Sopenharmony_ci#include <uapi/linux/f2fs.h> 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_cistatic vm_fault_t f2fs_filemap_fault(struct vm_fault *vmf) 4062306a36Sopenharmony_ci{ 4162306a36Sopenharmony_ci struct inode *inode = file_inode(vmf->vma->vm_file); 4262306a36Sopenharmony_ci vm_fault_t ret; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci ret = filemap_fault(vmf); 4562306a36Sopenharmony_ci if (ret & VM_FAULT_LOCKED) 4662306a36Sopenharmony_ci f2fs_update_iostat(F2FS_I_SB(inode), inode, 4762306a36Sopenharmony_ci APP_MAPPED_READ_IO, F2FS_BLKSIZE); 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci trace_f2fs_filemap_fault(inode, vmf->pgoff, (unsigned long)ret); 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci return ret; 5262306a36Sopenharmony_ci} 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_cistatic vm_fault_t f2fs_vm_page_mkwrite(struct vm_fault *vmf) 5562306a36Sopenharmony_ci{ 5662306a36Sopenharmony_ci struct page *page = vmf->page; 5762306a36Sopenharmony_ci struct inode *inode = file_inode(vmf->vma->vm_file); 5862306a36Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_I_SB(inode); 5962306a36Sopenharmony_ci struct dnode_of_data dn; 6062306a36Sopenharmony_ci bool need_alloc = true; 6162306a36Sopenharmony_ci int err = 0; 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci if (unlikely(IS_IMMUTABLE(inode))) 6462306a36Sopenharmony_ci return VM_FAULT_SIGBUS; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci if (is_inode_flag_set(inode, FI_COMPRESS_RELEASED)) 6762306a36Sopenharmony_ci return VM_FAULT_SIGBUS; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci if (unlikely(f2fs_cp_error(sbi))) { 7062306a36Sopenharmony_ci err = -EIO; 7162306a36Sopenharmony_ci goto err; 7262306a36Sopenharmony_ci } 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci if (!f2fs_is_checkpoint_ready(sbi)) { 7562306a36Sopenharmony_ci err = -ENOSPC; 7662306a36Sopenharmony_ci goto err; 7762306a36Sopenharmony_ci } 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci err = f2fs_convert_inline_inode(inode); 8062306a36Sopenharmony_ci if (err) 8162306a36Sopenharmony_ci goto err; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci#ifdef CONFIG_F2FS_FS_COMPRESSION 8462306a36Sopenharmony_ci if (f2fs_compressed_file(inode)) { 8562306a36Sopenharmony_ci int ret = f2fs_is_compressed_cluster(inode, page->index); 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci if (ret < 0) { 8862306a36Sopenharmony_ci err = ret; 8962306a36Sopenharmony_ci goto err; 9062306a36Sopenharmony_ci } else if (ret) { 9162306a36Sopenharmony_ci need_alloc = false; 9262306a36Sopenharmony_ci } 9362306a36Sopenharmony_ci } 9462306a36Sopenharmony_ci#endif 9562306a36Sopenharmony_ci /* should do out of any locked page */ 9662306a36Sopenharmony_ci if (need_alloc) 9762306a36Sopenharmony_ci f2fs_balance_fs(sbi, true); 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci sb_start_pagefault(inode->i_sb); 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci f2fs_bug_on(sbi, f2fs_has_inline_data(inode)); 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci file_update_time(vmf->vma->vm_file); 10462306a36Sopenharmony_ci filemap_invalidate_lock_shared(inode->i_mapping); 10562306a36Sopenharmony_ci lock_page(page); 10662306a36Sopenharmony_ci if (unlikely(page->mapping != inode->i_mapping || 10762306a36Sopenharmony_ci page_offset(page) > i_size_read(inode) || 10862306a36Sopenharmony_ci !PageUptodate(page))) { 10962306a36Sopenharmony_ci unlock_page(page); 11062306a36Sopenharmony_ci err = -EFAULT; 11162306a36Sopenharmony_ci goto out_sem; 11262306a36Sopenharmony_ci } 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci if (need_alloc) { 11562306a36Sopenharmony_ci /* block allocation */ 11662306a36Sopenharmony_ci set_new_dnode(&dn, inode, NULL, NULL, 0); 11762306a36Sopenharmony_ci err = f2fs_get_block_locked(&dn, page->index); 11862306a36Sopenharmony_ci } 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci#ifdef CONFIG_F2FS_FS_COMPRESSION 12162306a36Sopenharmony_ci if (!need_alloc) { 12262306a36Sopenharmony_ci set_new_dnode(&dn, inode, NULL, NULL, 0); 12362306a36Sopenharmony_ci err = f2fs_get_dnode_of_data(&dn, page->index, LOOKUP_NODE); 12462306a36Sopenharmony_ci f2fs_put_dnode(&dn); 12562306a36Sopenharmony_ci } 12662306a36Sopenharmony_ci#endif 12762306a36Sopenharmony_ci if (err) { 12862306a36Sopenharmony_ci unlock_page(page); 12962306a36Sopenharmony_ci goto out_sem; 13062306a36Sopenharmony_ci } 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci f2fs_wait_on_page_writeback(page, DATA, false, true); 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci /* wait for GCed page writeback via META_MAPPING */ 13562306a36Sopenharmony_ci f2fs_wait_on_block_writeback(inode, dn.data_blkaddr); 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci /* 13862306a36Sopenharmony_ci * check to see if the page is mapped already (no holes) 13962306a36Sopenharmony_ci */ 14062306a36Sopenharmony_ci if (PageMappedToDisk(page)) 14162306a36Sopenharmony_ci goto out_sem; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci /* page is wholly or partially inside EOF */ 14462306a36Sopenharmony_ci if (((loff_t)(page->index + 1) << PAGE_SHIFT) > 14562306a36Sopenharmony_ci i_size_read(inode)) { 14662306a36Sopenharmony_ci loff_t offset; 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci offset = i_size_read(inode) & ~PAGE_MASK; 14962306a36Sopenharmony_ci zero_user_segment(page, offset, PAGE_SIZE); 15062306a36Sopenharmony_ci } 15162306a36Sopenharmony_ci set_page_dirty(page); 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci f2fs_update_iostat(sbi, inode, APP_MAPPED_IO, F2FS_BLKSIZE); 15462306a36Sopenharmony_ci f2fs_update_time(sbi, REQ_TIME); 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci trace_f2fs_vm_page_mkwrite(page, DATA); 15762306a36Sopenharmony_ciout_sem: 15862306a36Sopenharmony_ci filemap_invalidate_unlock_shared(inode->i_mapping); 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci sb_end_pagefault(inode->i_sb); 16162306a36Sopenharmony_cierr: 16262306a36Sopenharmony_ci return vmf_fs_error(err); 16362306a36Sopenharmony_ci} 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_cistatic const struct vm_operations_struct f2fs_file_vm_ops = { 16662306a36Sopenharmony_ci .fault = f2fs_filemap_fault, 16762306a36Sopenharmony_ci .map_pages = filemap_map_pages, 16862306a36Sopenharmony_ci .page_mkwrite = f2fs_vm_page_mkwrite, 16962306a36Sopenharmony_ci}; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_cistatic int get_parent_ino(struct inode *inode, nid_t *pino) 17262306a36Sopenharmony_ci{ 17362306a36Sopenharmony_ci struct dentry *dentry; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci /* 17662306a36Sopenharmony_ci * Make sure to get the non-deleted alias. The alias associated with 17762306a36Sopenharmony_ci * the open file descriptor being fsync()'ed may be deleted already. 17862306a36Sopenharmony_ci */ 17962306a36Sopenharmony_ci dentry = d_find_alias(inode); 18062306a36Sopenharmony_ci if (!dentry) 18162306a36Sopenharmony_ci return 0; 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci *pino = parent_ino(dentry); 18462306a36Sopenharmony_ci dput(dentry); 18562306a36Sopenharmony_ci return 1; 18662306a36Sopenharmony_ci} 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_cistatic inline enum cp_reason_type need_do_checkpoint(struct inode *inode) 18962306a36Sopenharmony_ci{ 19062306a36Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_I_SB(inode); 19162306a36Sopenharmony_ci enum cp_reason_type cp_reason = CP_NO_NEEDED; 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci if (!S_ISREG(inode->i_mode)) 19462306a36Sopenharmony_ci cp_reason = CP_NON_REGULAR; 19562306a36Sopenharmony_ci else if (f2fs_compressed_file(inode)) 19662306a36Sopenharmony_ci cp_reason = CP_COMPRESSED; 19762306a36Sopenharmony_ci else if (inode->i_nlink != 1) 19862306a36Sopenharmony_ci cp_reason = CP_HARDLINK; 19962306a36Sopenharmony_ci else if (is_sbi_flag_set(sbi, SBI_NEED_CP)) 20062306a36Sopenharmony_ci cp_reason = CP_SB_NEED_CP; 20162306a36Sopenharmony_ci else if (file_wrong_pino(inode)) 20262306a36Sopenharmony_ci cp_reason = CP_WRONG_PINO; 20362306a36Sopenharmony_ci else if (!f2fs_space_for_roll_forward(sbi)) 20462306a36Sopenharmony_ci cp_reason = CP_NO_SPC_ROLL; 20562306a36Sopenharmony_ci else if (!f2fs_is_checkpointed_node(sbi, F2FS_I(inode)->i_pino)) 20662306a36Sopenharmony_ci cp_reason = CP_NODE_NEED_CP; 20762306a36Sopenharmony_ci else if (test_opt(sbi, FASTBOOT)) 20862306a36Sopenharmony_ci cp_reason = CP_FASTBOOT_MODE; 20962306a36Sopenharmony_ci else if (F2FS_OPTION(sbi).active_logs == 2) 21062306a36Sopenharmony_ci cp_reason = CP_SPEC_LOG_NUM; 21162306a36Sopenharmony_ci else if (F2FS_OPTION(sbi).fsync_mode == FSYNC_MODE_STRICT && 21262306a36Sopenharmony_ci f2fs_need_dentry_mark(sbi, inode->i_ino) && 21362306a36Sopenharmony_ci f2fs_exist_written_data(sbi, F2FS_I(inode)->i_pino, 21462306a36Sopenharmony_ci TRANS_DIR_INO)) 21562306a36Sopenharmony_ci cp_reason = CP_RECOVER_DIR; 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci return cp_reason; 21862306a36Sopenharmony_ci} 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_cistatic bool need_inode_page_update(struct f2fs_sb_info *sbi, nid_t ino) 22162306a36Sopenharmony_ci{ 22262306a36Sopenharmony_ci struct page *i = find_get_page(NODE_MAPPING(sbi), ino); 22362306a36Sopenharmony_ci bool ret = false; 22462306a36Sopenharmony_ci /* But we need to avoid that there are some inode updates */ 22562306a36Sopenharmony_ci if ((i && PageDirty(i)) || f2fs_need_inode_block_update(sbi, ino)) 22662306a36Sopenharmony_ci ret = true; 22762306a36Sopenharmony_ci f2fs_put_page(i, 0); 22862306a36Sopenharmony_ci return ret; 22962306a36Sopenharmony_ci} 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_cistatic void try_to_fix_pino(struct inode *inode) 23262306a36Sopenharmony_ci{ 23362306a36Sopenharmony_ci struct f2fs_inode_info *fi = F2FS_I(inode); 23462306a36Sopenharmony_ci nid_t pino; 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci f2fs_down_write(&fi->i_sem); 23762306a36Sopenharmony_ci if (file_wrong_pino(inode) && inode->i_nlink == 1 && 23862306a36Sopenharmony_ci get_parent_ino(inode, &pino)) { 23962306a36Sopenharmony_ci f2fs_i_pino_write(inode, pino); 24062306a36Sopenharmony_ci file_got_pino(inode); 24162306a36Sopenharmony_ci } 24262306a36Sopenharmony_ci f2fs_up_write(&fi->i_sem); 24362306a36Sopenharmony_ci} 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_cistatic int f2fs_do_sync_file(struct file *file, loff_t start, loff_t end, 24662306a36Sopenharmony_ci int datasync, bool atomic) 24762306a36Sopenharmony_ci{ 24862306a36Sopenharmony_ci struct inode *inode = file->f_mapping->host; 24962306a36Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_I_SB(inode); 25062306a36Sopenharmony_ci nid_t ino = inode->i_ino; 25162306a36Sopenharmony_ci int ret = 0; 25262306a36Sopenharmony_ci enum cp_reason_type cp_reason = 0; 25362306a36Sopenharmony_ci struct writeback_control wbc = { 25462306a36Sopenharmony_ci .sync_mode = WB_SYNC_ALL, 25562306a36Sopenharmony_ci .nr_to_write = LONG_MAX, 25662306a36Sopenharmony_ci .for_reclaim = 0, 25762306a36Sopenharmony_ci }; 25862306a36Sopenharmony_ci unsigned int seq_id = 0; 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci if (unlikely(f2fs_readonly(inode->i_sb))) 26162306a36Sopenharmony_ci return 0; 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci trace_f2fs_sync_file_enter(inode); 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci if (S_ISDIR(inode->i_mode)) 26662306a36Sopenharmony_ci goto go_write; 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci /* if fdatasync is triggered, let's do in-place-update */ 26962306a36Sopenharmony_ci if (datasync || get_dirty_pages(inode) <= SM_I(sbi)->min_fsync_blocks) 27062306a36Sopenharmony_ci set_inode_flag(inode, FI_NEED_IPU); 27162306a36Sopenharmony_ci ret = file_write_and_wait_range(file, start, end); 27262306a36Sopenharmony_ci clear_inode_flag(inode, FI_NEED_IPU); 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci if (ret || is_sbi_flag_set(sbi, SBI_CP_DISABLED)) { 27562306a36Sopenharmony_ci trace_f2fs_sync_file_exit(inode, cp_reason, datasync, ret); 27662306a36Sopenharmony_ci return ret; 27762306a36Sopenharmony_ci } 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci /* if the inode is dirty, let's recover all the time */ 28062306a36Sopenharmony_ci if (!f2fs_skip_inode_update(inode, datasync)) { 28162306a36Sopenharmony_ci f2fs_write_inode(inode, NULL); 28262306a36Sopenharmony_ci goto go_write; 28362306a36Sopenharmony_ci } 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci /* 28662306a36Sopenharmony_ci * if there is no written data, don't waste time to write recovery info. 28762306a36Sopenharmony_ci */ 28862306a36Sopenharmony_ci if (!is_inode_flag_set(inode, FI_APPEND_WRITE) && 28962306a36Sopenharmony_ci !f2fs_exist_written_data(sbi, ino, APPEND_INO)) { 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci /* it may call write_inode just prior to fsync */ 29262306a36Sopenharmony_ci if (need_inode_page_update(sbi, ino)) 29362306a36Sopenharmony_ci goto go_write; 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci if (is_inode_flag_set(inode, FI_UPDATE_WRITE) || 29662306a36Sopenharmony_ci f2fs_exist_written_data(sbi, ino, UPDATE_INO)) 29762306a36Sopenharmony_ci goto flush_out; 29862306a36Sopenharmony_ci goto out; 29962306a36Sopenharmony_ci } else { 30062306a36Sopenharmony_ci /* 30162306a36Sopenharmony_ci * for OPU case, during fsync(), node can be persisted before 30262306a36Sopenharmony_ci * data when lower device doesn't support write barrier, result 30362306a36Sopenharmony_ci * in data corruption after SPO. 30462306a36Sopenharmony_ci * So for strict fsync mode, force to use atomic write semantics 30562306a36Sopenharmony_ci * to keep write order in between data/node and last node to 30662306a36Sopenharmony_ci * avoid potential data corruption. 30762306a36Sopenharmony_ci */ 30862306a36Sopenharmony_ci if (F2FS_OPTION(sbi).fsync_mode == 30962306a36Sopenharmony_ci FSYNC_MODE_STRICT && !atomic) 31062306a36Sopenharmony_ci atomic = true; 31162306a36Sopenharmony_ci } 31262306a36Sopenharmony_cigo_write: 31362306a36Sopenharmony_ci /* 31462306a36Sopenharmony_ci * Both of fdatasync() and fsync() are able to be recovered from 31562306a36Sopenharmony_ci * sudden-power-off. 31662306a36Sopenharmony_ci */ 31762306a36Sopenharmony_ci f2fs_down_read(&F2FS_I(inode)->i_sem); 31862306a36Sopenharmony_ci cp_reason = need_do_checkpoint(inode); 31962306a36Sopenharmony_ci f2fs_up_read(&F2FS_I(inode)->i_sem); 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci if (cp_reason) { 32262306a36Sopenharmony_ci /* all the dirty node pages should be flushed for POR */ 32362306a36Sopenharmony_ci ret = f2fs_sync_fs(inode->i_sb, 1); 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci /* 32662306a36Sopenharmony_ci * We've secured consistency through sync_fs. Following pino 32762306a36Sopenharmony_ci * will be used only for fsynced inodes after checkpoint. 32862306a36Sopenharmony_ci */ 32962306a36Sopenharmony_ci try_to_fix_pino(inode); 33062306a36Sopenharmony_ci clear_inode_flag(inode, FI_APPEND_WRITE); 33162306a36Sopenharmony_ci clear_inode_flag(inode, FI_UPDATE_WRITE); 33262306a36Sopenharmony_ci goto out; 33362306a36Sopenharmony_ci } 33462306a36Sopenharmony_cisync_nodes: 33562306a36Sopenharmony_ci atomic_inc(&sbi->wb_sync_req[NODE]); 33662306a36Sopenharmony_ci ret = f2fs_fsync_node_pages(sbi, inode, &wbc, atomic, &seq_id); 33762306a36Sopenharmony_ci atomic_dec(&sbi->wb_sync_req[NODE]); 33862306a36Sopenharmony_ci if (ret) 33962306a36Sopenharmony_ci goto out; 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci /* if cp_error was enabled, we should avoid infinite loop */ 34262306a36Sopenharmony_ci if (unlikely(f2fs_cp_error(sbi))) { 34362306a36Sopenharmony_ci ret = -EIO; 34462306a36Sopenharmony_ci goto out; 34562306a36Sopenharmony_ci } 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci if (f2fs_need_inode_block_update(sbi, ino)) { 34862306a36Sopenharmony_ci f2fs_mark_inode_dirty_sync(inode, true); 34962306a36Sopenharmony_ci f2fs_write_inode(inode, NULL); 35062306a36Sopenharmony_ci goto sync_nodes; 35162306a36Sopenharmony_ci } 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci /* 35462306a36Sopenharmony_ci * If it's atomic_write, it's just fine to keep write ordering. So 35562306a36Sopenharmony_ci * here we don't need to wait for node write completion, since we use 35662306a36Sopenharmony_ci * node chain which serializes node blocks. If one of node writes are 35762306a36Sopenharmony_ci * reordered, we can see simply broken chain, resulting in stopping 35862306a36Sopenharmony_ci * roll-forward recovery. It means we'll recover all or none node blocks 35962306a36Sopenharmony_ci * given fsync mark. 36062306a36Sopenharmony_ci */ 36162306a36Sopenharmony_ci if (!atomic) { 36262306a36Sopenharmony_ci ret = f2fs_wait_on_node_pages_writeback(sbi, seq_id); 36362306a36Sopenharmony_ci if (ret) 36462306a36Sopenharmony_ci goto out; 36562306a36Sopenharmony_ci } 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci /* once recovery info is written, don't need to tack this */ 36862306a36Sopenharmony_ci f2fs_remove_ino_entry(sbi, ino, APPEND_INO); 36962306a36Sopenharmony_ci clear_inode_flag(inode, FI_APPEND_WRITE); 37062306a36Sopenharmony_ciflush_out: 37162306a36Sopenharmony_ci if ((!atomic && F2FS_OPTION(sbi).fsync_mode != FSYNC_MODE_NOBARRIER) || 37262306a36Sopenharmony_ci (atomic && !test_opt(sbi, NOBARRIER) && f2fs_sb_has_blkzoned(sbi))) 37362306a36Sopenharmony_ci ret = f2fs_issue_flush(sbi, inode->i_ino); 37462306a36Sopenharmony_ci if (!ret) { 37562306a36Sopenharmony_ci f2fs_remove_ino_entry(sbi, ino, UPDATE_INO); 37662306a36Sopenharmony_ci clear_inode_flag(inode, FI_UPDATE_WRITE); 37762306a36Sopenharmony_ci f2fs_remove_ino_entry(sbi, ino, FLUSH_INO); 37862306a36Sopenharmony_ci } 37962306a36Sopenharmony_ci f2fs_update_time(sbi, REQ_TIME); 38062306a36Sopenharmony_ciout: 38162306a36Sopenharmony_ci trace_f2fs_sync_file_exit(inode, cp_reason, datasync, ret); 38262306a36Sopenharmony_ci return ret; 38362306a36Sopenharmony_ci} 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ciint f2fs_sync_file(struct file *file, loff_t start, loff_t end, int datasync) 38662306a36Sopenharmony_ci{ 38762306a36Sopenharmony_ci if (unlikely(f2fs_cp_error(F2FS_I_SB(file_inode(file))))) 38862306a36Sopenharmony_ci return -EIO; 38962306a36Sopenharmony_ci return f2fs_do_sync_file(file, start, end, datasync, false); 39062306a36Sopenharmony_ci} 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_cistatic bool __found_offset(struct address_space *mapping, block_t blkaddr, 39362306a36Sopenharmony_ci pgoff_t index, int whence) 39462306a36Sopenharmony_ci{ 39562306a36Sopenharmony_ci switch (whence) { 39662306a36Sopenharmony_ci case SEEK_DATA: 39762306a36Sopenharmony_ci if (__is_valid_data_blkaddr(blkaddr)) 39862306a36Sopenharmony_ci return true; 39962306a36Sopenharmony_ci if (blkaddr == NEW_ADDR && 40062306a36Sopenharmony_ci xa_get_mark(&mapping->i_pages, index, PAGECACHE_TAG_DIRTY)) 40162306a36Sopenharmony_ci return true; 40262306a36Sopenharmony_ci break; 40362306a36Sopenharmony_ci case SEEK_HOLE: 40462306a36Sopenharmony_ci if (blkaddr == NULL_ADDR) 40562306a36Sopenharmony_ci return true; 40662306a36Sopenharmony_ci break; 40762306a36Sopenharmony_ci } 40862306a36Sopenharmony_ci return false; 40962306a36Sopenharmony_ci} 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_cistatic loff_t f2fs_seek_block(struct file *file, loff_t offset, int whence) 41262306a36Sopenharmony_ci{ 41362306a36Sopenharmony_ci struct inode *inode = file->f_mapping->host; 41462306a36Sopenharmony_ci loff_t maxbytes = inode->i_sb->s_maxbytes; 41562306a36Sopenharmony_ci struct dnode_of_data dn; 41662306a36Sopenharmony_ci pgoff_t pgofs, end_offset; 41762306a36Sopenharmony_ci loff_t data_ofs = offset; 41862306a36Sopenharmony_ci loff_t isize; 41962306a36Sopenharmony_ci int err = 0; 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci inode_lock(inode); 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci isize = i_size_read(inode); 42462306a36Sopenharmony_ci if (offset >= isize) 42562306a36Sopenharmony_ci goto fail; 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci /* handle inline data case */ 42862306a36Sopenharmony_ci if (f2fs_has_inline_data(inode)) { 42962306a36Sopenharmony_ci if (whence == SEEK_HOLE) { 43062306a36Sopenharmony_ci data_ofs = isize; 43162306a36Sopenharmony_ci goto found; 43262306a36Sopenharmony_ci } else if (whence == SEEK_DATA) { 43362306a36Sopenharmony_ci data_ofs = offset; 43462306a36Sopenharmony_ci goto found; 43562306a36Sopenharmony_ci } 43662306a36Sopenharmony_ci } 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci pgofs = (pgoff_t)(offset >> PAGE_SHIFT); 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci for (; data_ofs < isize; data_ofs = (loff_t)pgofs << PAGE_SHIFT) { 44162306a36Sopenharmony_ci set_new_dnode(&dn, inode, NULL, NULL, 0); 44262306a36Sopenharmony_ci err = f2fs_get_dnode_of_data(&dn, pgofs, LOOKUP_NODE); 44362306a36Sopenharmony_ci if (err && err != -ENOENT) { 44462306a36Sopenharmony_ci goto fail; 44562306a36Sopenharmony_ci } else if (err == -ENOENT) { 44662306a36Sopenharmony_ci /* direct node does not exists */ 44762306a36Sopenharmony_ci if (whence == SEEK_DATA) { 44862306a36Sopenharmony_ci pgofs = f2fs_get_next_page_offset(&dn, pgofs); 44962306a36Sopenharmony_ci continue; 45062306a36Sopenharmony_ci } else { 45162306a36Sopenharmony_ci goto found; 45262306a36Sopenharmony_ci } 45362306a36Sopenharmony_ci } 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci end_offset = ADDRS_PER_PAGE(dn.node_page, inode); 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci /* find data/hole in dnode block */ 45862306a36Sopenharmony_ci for (; dn.ofs_in_node < end_offset; 45962306a36Sopenharmony_ci dn.ofs_in_node++, pgofs++, 46062306a36Sopenharmony_ci data_ofs = (loff_t)pgofs << PAGE_SHIFT) { 46162306a36Sopenharmony_ci block_t blkaddr; 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci blkaddr = f2fs_data_blkaddr(&dn); 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci if (__is_valid_data_blkaddr(blkaddr) && 46662306a36Sopenharmony_ci !f2fs_is_valid_blkaddr(F2FS_I_SB(inode), 46762306a36Sopenharmony_ci blkaddr, DATA_GENERIC_ENHANCE)) { 46862306a36Sopenharmony_ci f2fs_put_dnode(&dn); 46962306a36Sopenharmony_ci goto fail; 47062306a36Sopenharmony_ci } 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci if (__found_offset(file->f_mapping, blkaddr, 47362306a36Sopenharmony_ci pgofs, whence)) { 47462306a36Sopenharmony_ci f2fs_put_dnode(&dn); 47562306a36Sopenharmony_ci goto found; 47662306a36Sopenharmony_ci } 47762306a36Sopenharmony_ci } 47862306a36Sopenharmony_ci f2fs_put_dnode(&dn); 47962306a36Sopenharmony_ci } 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci if (whence == SEEK_DATA) 48262306a36Sopenharmony_ci goto fail; 48362306a36Sopenharmony_cifound: 48462306a36Sopenharmony_ci if (whence == SEEK_HOLE && data_ofs > isize) 48562306a36Sopenharmony_ci data_ofs = isize; 48662306a36Sopenharmony_ci inode_unlock(inode); 48762306a36Sopenharmony_ci return vfs_setpos(file, data_ofs, maxbytes); 48862306a36Sopenharmony_cifail: 48962306a36Sopenharmony_ci inode_unlock(inode); 49062306a36Sopenharmony_ci return -ENXIO; 49162306a36Sopenharmony_ci} 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_cistatic loff_t f2fs_llseek(struct file *file, loff_t offset, int whence) 49462306a36Sopenharmony_ci{ 49562306a36Sopenharmony_ci struct inode *inode = file->f_mapping->host; 49662306a36Sopenharmony_ci loff_t maxbytes = inode->i_sb->s_maxbytes; 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci if (f2fs_compressed_file(inode)) 49962306a36Sopenharmony_ci maxbytes = max_file_blocks(inode) << F2FS_BLKSIZE_BITS; 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci switch (whence) { 50262306a36Sopenharmony_ci case SEEK_SET: 50362306a36Sopenharmony_ci case SEEK_CUR: 50462306a36Sopenharmony_ci case SEEK_END: 50562306a36Sopenharmony_ci return generic_file_llseek_size(file, offset, whence, 50662306a36Sopenharmony_ci maxbytes, i_size_read(inode)); 50762306a36Sopenharmony_ci case SEEK_DATA: 50862306a36Sopenharmony_ci case SEEK_HOLE: 50962306a36Sopenharmony_ci if (offset < 0) 51062306a36Sopenharmony_ci return -ENXIO; 51162306a36Sopenharmony_ci return f2fs_seek_block(file, offset, whence); 51262306a36Sopenharmony_ci } 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci return -EINVAL; 51562306a36Sopenharmony_ci} 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_cistatic int f2fs_file_mmap(struct file *file, struct vm_area_struct *vma) 51862306a36Sopenharmony_ci{ 51962306a36Sopenharmony_ci struct inode *inode = file_inode(file); 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci if (unlikely(f2fs_cp_error(F2FS_I_SB(inode)))) 52262306a36Sopenharmony_ci return -EIO; 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci if (!f2fs_is_compress_backend_ready(inode)) 52562306a36Sopenharmony_ci return -EOPNOTSUPP; 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci file_accessed(file); 52862306a36Sopenharmony_ci vma->vm_ops = &f2fs_file_vm_ops; 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci f2fs_down_read(&F2FS_I(inode)->i_sem); 53162306a36Sopenharmony_ci set_inode_flag(inode, FI_MMAP_FILE); 53262306a36Sopenharmony_ci f2fs_up_read(&F2FS_I(inode)->i_sem); 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci return 0; 53562306a36Sopenharmony_ci} 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_cistatic int f2fs_file_open(struct inode *inode, struct file *filp) 53862306a36Sopenharmony_ci{ 53962306a36Sopenharmony_ci int err = fscrypt_file_open(inode, filp); 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci if (err) 54262306a36Sopenharmony_ci return err; 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci if (!f2fs_is_compress_backend_ready(inode)) 54562306a36Sopenharmony_ci return -EOPNOTSUPP; 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci err = fsverity_file_open(inode, filp); 54862306a36Sopenharmony_ci if (err) 54962306a36Sopenharmony_ci return err; 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci filp->f_mode |= FMODE_NOWAIT | FMODE_BUF_RASYNC; 55262306a36Sopenharmony_ci filp->f_mode |= FMODE_CAN_ODIRECT; 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci return dquot_file_open(inode, filp); 55562306a36Sopenharmony_ci} 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_civoid f2fs_truncate_data_blocks_range(struct dnode_of_data *dn, int count) 55862306a36Sopenharmony_ci{ 55962306a36Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_I_SB(dn->inode); 56062306a36Sopenharmony_ci int nr_free = 0, ofs = dn->ofs_in_node, len = count; 56162306a36Sopenharmony_ci __le32 *addr; 56262306a36Sopenharmony_ci bool compressed_cluster = false; 56362306a36Sopenharmony_ci int cluster_index = 0, valid_blocks = 0; 56462306a36Sopenharmony_ci int cluster_size = F2FS_I(dn->inode)->i_cluster_size; 56562306a36Sopenharmony_ci bool released = !atomic_read(&F2FS_I(dn->inode)->i_compr_blocks); 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci addr = get_dnode_addr(dn->inode, dn->node_page) + ofs; 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci /* Assumption: truncation starts with cluster */ 57062306a36Sopenharmony_ci for (; count > 0; count--, addr++, dn->ofs_in_node++, cluster_index++) { 57162306a36Sopenharmony_ci block_t blkaddr = le32_to_cpu(*addr); 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci if (f2fs_compressed_file(dn->inode) && 57462306a36Sopenharmony_ci !(cluster_index & (cluster_size - 1))) { 57562306a36Sopenharmony_ci if (compressed_cluster) 57662306a36Sopenharmony_ci f2fs_i_compr_blocks_update(dn->inode, 57762306a36Sopenharmony_ci valid_blocks, false); 57862306a36Sopenharmony_ci compressed_cluster = (blkaddr == COMPRESS_ADDR); 57962306a36Sopenharmony_ci valid_blocks = 0; 58062306a36Sopenharmony_ci } 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci if (blkaddr == NULL_ADDR) 58362306a36Sopenharmony_ci continue; 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci f2fs_set_data_blkaddr(dn, NULL_ADDR); 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci if (__is_valid_data_blkaddr(blkaddr)) { 58862306a36Sopenharmony_ci if (!f2fs_is_valid_blkaddr(sbi, blkaddr, 58962306a36Sopenharmony_ci DATA_GENERIC_ENHANCE)) 59062306a36Sopenharmony_ci continue; 59162306a36Sopenharmony_ci if (compressed_cluster) 59262306a36Sopenharmony_ci valid_blocks++; 59362306a36Sopenharmony_ci } 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci f2fs_invalidate_blocks(sbi, blkaddr); 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci if (!released || blkaddr != COMPRESS_ADDR) 59862306a36Sopenharmony_ci nr_free++; 59962306a36Sopenharmony_ci } 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci if (compressed_cluster) 60262306a36Sopenharmony_ci f2fs_i_compr_blocks_update(dn->inode, valid_blocks, false); 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci if (nr_free) { 60562306a36Sopenharmony_ci pgoff_t fofs; 60662306a36Sopenharmony_ci /* 60762306a36Sopenharmony_ci * once we invalidate valid blkaddr in range [ofs, ofs + count], 60862306a36Sopenharmony_ci * we will invalidate all blkaddr in the whole range. 60962306a36Sopenharmony_ci */ 61062306a36Sopenharmony_ci fofs = f2fs_start_bidx_of_node(ofs_of_node(dn->node_page), 61162306a36Sopenharmony_ci dn->inode) + ofs; 61262306a36Sopenharmony_ci f2fs_update_read_extent_cache_range(dn, fofs, 0, len); 61362306a36Sopenharmony_ci f2fs_update_age_extent_cache_range(dn, fofs, len); 61462306a36Sopenharmony_ci dec_valid_block_count(sbi, dn->inode, nr_free); 61562306a36Sopenharmony_ci } 61662306a36Sopenharmony_ci dn->ofs_in_node = ofs; 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci f2fs_update_time(sbi, REQ_TIME); 61962306a36Sopenharmony_ci trace_f2fs_truncate_data_blocks_range(dn->inode, dn->nid, 62062306a36Sopenharmony_ci dn->ofs_in_node, nr_free); 62162306a36Sopenharmony_ci} 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_cistatic int truncate_partial_data_page(struct inode *inode, u64 from, 62462306a36Sopenharmony_ci bool cache_only) 62562306a36Sopenharmony_ci{ 62662306a36Sopenharmony_ci loff_t offset = from & (PAGE_SIZE - 1); 62762306a36Sopenharmony_ci pgoff_t index = from >> PAGE_SHIFT; 62862306a36Sopenharmony_ci struct address_space *mapping = inode->i_mapping; 62962306a36Sopenharmony_ci struct page *page; 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci if (!offset && !cache_only) 63262306a36Sopenharmony_ci return 0; 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci if (cache_only) { 63562306a36Sopenharmony_ci page = find_lock_page(mapping, index); 63662306a36Sopenharmony_ci if (page && PageUptodate(page)) 63762306a36Sopenharmony_ci goto truncate_out; 63862306a36Sopenharmony_ci f2fs_put_page(page, 1); 63962306a36Sopenharmony_ci return 0; 64062306a36Sopenharmony_ci } 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci page = f2fs_get_lock_data_page(inode, index, true); 64362306a36Sopenharmony_ci if (IS_ERR(page)) 64462306a36Sopenharmony_ci return PTR_ERR(page) == -ENOENT ? 0 : PTR_ERR(page); 64562306a36Sopenharmony_citruncate_out: 64662306a36Sopenharmony_ci f2fs_wait_on_page_writeback(page, DATA, true, true); 64762306a36Sopenharmony_ci zero_user(page, offset, PAGE_SIZE - offset); 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci /* An encrypted inode should have a key and truncate the last page. */ 65062306a36Sopenharmony_ci f2fs_bug_on(F2FS_I_SB(inode), cache_only && IS_ENCRYPTED(inode)); 65162306a36Sopenharmony_ci if (!cache_only) 65262306a36Sopenharmony_ci set_page_dirty(page); 65362306a36Sopenharmony_ci f2fs_put_page(page, 1); 65462306a36Sopenharmony_ci return 0; 65562306a36Sopenharmony_ci} 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ciint f2fs_do_truncate_blocks(struct inode *inode, u64 from, bool lock) 65862306a36Sopenharmony_ci{ 65962306a36Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_I_SB(inode); 66062306a36Sopenharmony_ci struct dnode_of_data dn; 66162306a36Sopenharmony_ci pgoff_t free_from; 66262306a36Sopenharmony_ci int count = 0, err = 0; 66362306a36Sopenharmony_ci struct page *ipage; 66462306a36Sopenharmony_ci bool truncate_page = false; 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci trace_f2fs_truncate_blocks_enter(inode, from); 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci free_from = (pgoff_t)F2FS_BLK_ALIGN(from); 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci if (free_from >= max_file_blocks(inode)) 67162306a36Sopenharmony_ci goto free_partial; 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci if (lock) 67462306a36Sopenharmony_ci f2fs_lock_op(sbi); 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci ipage = f2fs_get_node_page(sbi, inode->i_ino); 67762306a36Sopenharmony_ci if (IS_ERR(ipage)) { 67862306a36Sopenharmony_ci err = PTR_ERR(ipage); 67962306a36Sopenharmony_ci goto out; 68062306a36Sopenharmony_ci } 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci if (f2fs_has_inline_data(inode)) { 68362306a36Sopenharmony_ci f2fs_truncate_inline_inode(inode, ipage, from); 68462306a36Sopenharmony_ci f2fs_put_page(ipage, 1); 68562306a36Sopenharmony_ci truncate_page = true; 68662306a36Sopenharmony_ci goto out; 68762306a36Sopenharmony_ci } 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci set_new_dnode(&dn, inode, ipage, NULL, 0); 69062306a36Sopenharmony_ci err = f2fs_get_dnode_of_data(&dn, free_from, LOOKUP_NODE_RA); 69162306a36Sopenharmony_ci if (err) { 69262306a36Sopenharmony_ci if (err == -ENOENT) 69362306a36Sopenharmony_ci goto free_next; 69462306a36Sopenharmony_ci goto out; 69562306a36Sopenharmony_ci } 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci count = ADDRS_PER_PAGE(dn.node_page, inode); 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_ci count -= dn.ofs_in_node; 70062306a36Sopenharmony_ci f2fs_bug_on(sbi, count < 0); 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci if (dn.ofs_in_node || IS_INODE(dn.node_page)) { 70362306a36Sopenharmony_ci f2fs_truncate_data_blocks_range(&dn, count); 70462306a36Sopenharmony_ci free_from += count; 70562306a36Sopenharmony_ci } 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci f2fs_put_dnode(&dn); 70862306a36Sopenharmony_cifree_next: 70962306a36Sopenharmony_ci err = f2fs_truncate_inode_blocks(inode, free_from); 71062306a36Sopenharmony_ciout: 71162306a36Sopenharmony_ci if (lock) 71262306a36Sopenharmony_ci f2fs_unlock_op(sbi); 71362306a36Sopenharmony_cifree_partial: 71462306a36Sopenharmony_ci /* lastly zero out the first data page */ 71562306a36Sopenharmony_ci if (!err) 71662306a36Sopenharmony_ci err = truncate_partial_data_page(inode, from, truncate_page); 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci trace_f2fs_truncate_blocks_exit(inode, err); 71962306a36Sopenharmony_ci return err; 72062306a36Sopenharmony_ci} 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ciint f2fs_truncate_blocks(struct inode *inode, u64 from, bool lock) 72362306a36Sopenharmony_ci{ 72462306a36Sopenharmony_ci u64 free_from = from; 72562306a36Sopenharmony_ci int err; 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci#ifdef CONFIG_F2FS_FS_COMPRESSION 72862306a36Sopenharmony_ci /* 72962306a36Sopenharmony_ci * for compressed file, only support cluster size 73062306a36Sopenharmony_ci * aligned truncation. 73162306a36Sopenharmony_ci */ 73262306a36Sopenharmony_ci if (f2fs_compressed_file(inode)) 73362306a36Sopenharmony_ci free_from = round_up(from, 73462306a36Sopenharmony_ci F2FS_I(inode)->i_cluster_size << PAGE_SHIFT); 73562306a36Sopenharmony_ci#endif 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci err = f2fs_do_truncate_blocks(inode, free_from, lock); 73862306a36Sopenharmony_ci if (err) 73962306a36Sopenharmony_ci return err; 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci#ifdef CONFIG_F2FS_FS_COMPRESSION 74262306a36Sopenharmony_ci /* 74362306a36Sopenharmony_ci * For compressed file, after release compress blocks, don't allow write 74462306a36Sopenharmony_ci * direct, but we should allow write direct after truncate to zero. 74562306a36Sopenharmony_ci */ 74662306a36Sopenharmony_ci if (f2fs_compressed_file(inode) && !free_from 74762306a36Sopenharmony_ci && is_inode_flag_set(inode, FI_COMPRESS_RELEASED)) 74862306a36Sopenharmony_ci clear_inode_flag(inode, FI_COMPRESS_RELEASED); 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci if (from != free_from) { 75162306a36Sopenharmony_ci err = f2fs_truncate_partial_cluster(inode, from, lock); 75262306a36Sopenharmony_ci if (err) 75362306a36Sopenharmony_ci return err; 75462306a36Sopenharmony_ci } 75562306a36Sopenharmony_ci#endif 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci return 0; 75862306a36Sopenharmony_ci} 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ciint f2fs_truncate(struct inode *inode) 76162306a36Sopenharmony_ci{ 76262306a36Sopenharmony_ci int err; 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci if (unlikely(f2fs_cp_error(F2FS_I_SB(inode)))) 76562306a36Sopenharmony_ci return -EIO; 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_ci if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || 76862306a36Sopenharmony_ci S_ISLNK(inode->i_mode))) 76962306a36Sopenharmony_ci return 0; 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci trace_f2fs_truncate(inode); 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci if (time_to_inject(F2FS_I_SB(inode), FAULT_TRUNCATE)) 77462306a36Sopenharmony_ci return -EIO; 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci err = f2fs_dquot_initialize(inode); 77762306a36Sopenharmony_ci if (err) 77862306a36Sopenharmony_ci return err; 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci /* we should check inline_data size */ 78162306a36Sopenharmony_ci if (!f2fs_may_inline_data(inode)) { 78262306a36Sopenharmony_ci err = f2fs_convert_inline_inode(inode); 78362306a36Sopenharmony_ci if (err) 78462306a36Sopenharmony_ci return err; 78562306a36Sopenharmony_ci } 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_ci err = f2fs_truncate_blocks(inode, i_size_read(inode), true); 78862306a36Sopenharmony_ci if (err) 78962306a36Sopenharmony_ci return err; 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_ci inode->i_mtime = inode_set_ctime_current(inode); 79262306a36Sopenharmony_ci f2fs_mark_inode_dirty_sync(inode, false); 79362306a36Sopenharmony_ci return 0; 79462306a36Sopenharmony_ci} 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_cistatic bool f2fs_force_buffered_io(struct inode *inode, int rw) 79762306a36Sopenharmony_ci{ 79862306a36Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_I_SB(inode); 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_ci if (!fscrypt_dio_supported(inode)) 80162306a36Sopenharmony_ci return true; 80262306a36Sopenharmony_ci if (fsverity_active(inode)) 80362306a36Sopenharmony_ci return true; 80462306a36Sopenharmony_ci if (f2fs_compressed_file(inode)) 80562306a36Sopenharmony_ci return true; 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_ci /* disallow direct IO if any of devices has unaligned blksize */ 80862306a36Sopenharmony_ci if (f2fs_is_multi_device(sbi) && !sbi->aligned_blksize) 80962306a36Sopenharmony_ci return true; 81062306a36Sopenharmony_ci /* 81162306a36Sopenharmony_ci * for blkzoned device, fallback direct IO to buffered IO, so 81262306a36Sopenharmony_ci * all IOs can be serialized by log-structured write. 81362306a36Sopenharmony_ci */ 81462306a36Sopenharmony_ci if (f2fs_sb_has_blkzoned(sbi) && (rw == WRITE)) 81562306a36Sopenharmony_ci return true; 81662306a36Sopenharmony_ci if (f2fs_lfs_mode(sbi) && rw == WRITE && F2FS_IO_ALIGNED(sbi)) 81762306a36Sopenharmony_ci return true; 81862306a36Sopenharmony_ci if (is_sbi_flag_set(sbi, SBI_CP_DISABLED)) 81962306a36Sopenharmony_ci return true; 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ci return false; 82262306a36Sopenharmony_ci} 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ciint f2fs_getattr(struct mnt_idmap *idmap, const struct path *path, 82562306a36Sopenharmony_ci struct kstat *stat, u32 request_mask, unsigned int query_flags) 82662306a36Sopenharmony_ci{ 82762306a36Sopenharmony_ci struct inode *inode = d_inode(path->dentry); 82862306a36Sopenharmony_ci struct f2fs_inode_info *fi = F2FS_I(inode); 82962306a36Sopenharmony_ci struct f2fs_inode *ri = NULL; 83062306a36Sopenharmony_ci unsigned int flags; 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci if (f2fs_has_extra_attr(inode) && 83362306a36Sopenharmony_ci f2fs_sb_has_inode_crtime(F2FS_I_SB(inode)) && 83462306a36Sopenharmony_ci F2FS_FITS_IN_INODE(ri, fi->i_extra_isize, i_crtime)) { 83562306a36Sopenharmony_ci stat->result_mask |= STATX_BTIME; 83662306a36Sopenharmony_ci stat->btime.tv_sec = fi->i_crtime.tv_sec; 83762306a36Sopenharmony_ci stat->btime.tv_nsec = fi->i_crtime.tv_nsec; 83862306a36Sopenharmony_ci } 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci /* 84162306a36Sopenharmony_ci * Return the DIO alignment restrictions if requested. We only return 84262306a36Sopenharmony_ci * this information when requested, since on encrypted files it might 84362306a36Sopenharmony_ci * take a fair bit of work to get if the file wasn't opened recently. 84462306a36Sopenharmony_ci * 84562306a36Sopenharmony_ci * f2fs sometimes supports DIO reads but not DIO writes. STATX_DIOALIGN 84662306a36Sopenharmony_ci * cannot represent that, so in that case we report no DIO support. 84762306a36Sopenharmony_ci */ 84862306a36Sopenharmony_ci if ((request_mask & STATX_DIOALIGN) && S_ISREG(inode->i_mode)) { 84962306a36Sopenharmony_ci unsigned int bsize = i_blocksize(inode); 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_ci stat->result_mask |= STATX_DIOALIGN; 85262306a36Sopenharmony_ci if (!f2fs_force_buffered_io(inode, WRITE)) { 85362306a36Sopenharmony_ci stat->dio_mem_align = bsize; 85462306a36Sopenharmony_ci stat->dio_offset_align = bsize; 85562306a36Sopenharmony_ci } 85662306a36Sopenharmony_ci } 85762306a36Sopenharmony_ci 85862306a36Sopenharmony_ci flags = fi->i_flags; 85962306a36Sopenharmony_ci if (flags & F2FS_COMPR_FL) 86062306a36Sopenharmony_ci stat->attributes |= STATX_ATTR_COMPRESSED; 86162306a36Sopenharmony_ci if (flags & F2FS_APPEND_FL) 86262306a36Sopenharmony_ci stat->attributes |= STATX_ATTR_APPEND; 86362306a36Sopenharmony_ci if (IS_ENCRYPTED(inode)) 86462306a36Sopenharmony_ci stat->attributes |= STATX_ATTR_ENCRYPTED; 86562306a36Sopenharmony_ci if (flags & F2FS_IMMUTABLE_FL) 86662306a36Sopenharmony_ci stat->attributes |= STATX_ATTR_IMMUTABLE; 86762306a36Sopenharmony_ci if (flags & F2FS_NODUMP_FL) 86862306a36Sopenharmony_ci stat->attributes |= STATX_ATTR_NODUMP; 86962306a36Sopenharmony_ci if (IS_VERITY(inode)) 87062306a36Sopenharmony_ci stat->attributes |= STATX_ATTR_VERITY; 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_ci stat->attributes_mask |= (STATX_ATTR_COMPRESSED | 87362306a36Sopenharmony_ci STATX_ATTR_APPEND | 87462306a36Sopenharmony_ci STATX_ATTR_ENCRYPTED | 87562306a36Sopenharmony_ci STATX_ATTR_IMMUTABLE | 87662306a36Sopenharmony_ci STATX_ATTR_NODUMP | 87762306a36Sopenharmony_ci STATX_ATTR_VERITY); 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_ci generic_fillattr(idmap, request_mask, inode, stat); 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_ci /* we need to show initial sectors used for inline_data/dentries */ 88262306a36Sopenharmony_ci if ((S_ISREG(inode->i_mode) && f2fs_has_inline_data(inode)) || 88362306a36Sopenharmony_ci f2fs_has_inline_dentry(inode)) 88462306a36Sopenharmony_ci stat->blocks += (stat->size + 511) >> 9; 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci return 0; 88762306a36Sopenharmony_ci} 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci#ifdef CONFIG_F2FS_FS_POSIX_ACL 89062306a36Sopenharmony_cistatic void __setattr_copy(struct mnt_idmap *idmap, 89162306a36Sopenharmony_ci struct inode *inode, const struct iattr *attr) 89262306a36Sopenharmony_ci{ 89362306a36Sopenharmony_ci unsigned int ia_valid = attr->ia_valid; 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ci i_uid_update(idmap, attr, inode); 89662306a36Sopenharmony_ci i_gid_update(idmap, attr, inode); 89762306a36Sopenharmony_ci if (ia_valid & ATTR_ATIME) 89862306a36Sopenharmony_ci inode->i_atime = attr->ia_atime; 89962306a36Sopenharmony_ci if (ia_valid & ATTR_MTIME) 90062306a36Sopenharmony_ci inode->i_mtime = attr->ia_mtime; 90162306a36Sopenharmony_ci if (ia_valid & ATTR_CTIME) 90262306a36Sopenharmony_ci inode_set_ctime_to_ts(inode, attr->ia_ctime); 90362306a36Sopenharmony_ci if (ia_valid & ATTR_MODE) { 90462306a36Sopenharmony_ci umode_t mode = attr->ia_mode; 90562306a36Sopenharmony_ci vfsgid_t vfsgid = i_gid_into_vfsgid(idmap, inode); 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_ci if (!vfsgid_in_group_p(vfsgid) && 90862306a36Sopenharmony_ci !capable_wrt_inode_uidgid(idmap, inode, CAP_FSETID)) 90962306a36Sopenharmony_ci mode &= ~S_ISGID; 91062306a36Sopenharmony_ci set_acl_inode(inode, mode); 91162306a36Sopenharmony_ci } 91262306a36Sopenharmony_ci} 91362306a36Sopenharmony_ci#else 91462306a36Sopenharmony_ci#define __setattr_copy setattr_copy 91562306a36Sopenharmony_ci#endif 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_ciint f2fs_setattr(struct mnt_idmap *idmap, struct dentry *dentry, 91862306a36Sopenharmony_ci struct iattr *attr) 91962306a36Sopenharmony_ci{ 92062306a36Sopenharmony_ci struct inode *inode = d_inode(dentry); 92162306a36Sopenharmony_ci int err; 92262306a36Sopenharmony_ci 92362306a36Sopenharmony_ci if (unlikely(f2fs_cp_error(F2FS_I_SB(inode)))) 92462306a36Sopenharmony_ci return -EIO; 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_ci if (unlikely(IS_IMMUTABLE(inode))) 92762306a36Sopenharmony_ci return -EPERM; 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_ci if (unlikely(IS_APPEND(inode) && 93062306a36Sopenharmony_ci (attr->ia_valid & (ATTR_MODE | ATTR_UID | 93162306a36Sopenharmony_ci ATTR_GID | ATTR_TIMES_SET)))) 93262306a36Sopenharmony_ci return -EPERM; 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_ci if ((attr->ia_valid & ATTR_SIZE) && 93562306a36Sopenharmony_ci !f2fs_is_compress_backend_ready(inode)) 93662306a36Sopenharmony_ci return -EOPNOTSUPP; 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_ci err = setattr_prepare(idmap, dentry, attr); 93962306a36Sopenharmony_ci if (err) 94062306a36Sopenharmony_ci return err; 94162306a36Sopenharmony_ci 94262306a36Sopenharmony_ci err = fscrypt_prepare_setattr(dentry, attr); 94362306a36Sopenharmony_ci if (err) 94462306a36Sopenharmony_ci return err; 94562306a36Sopenharmony_ci 94662306a36Sopenharmony_ci err = fsverity_prepare_setattr(dentry, attr); 94762306a36Sopenharmony_ci if (err) 94862306a36Sopenharmony_ci return err; 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_ci if (is_quota_modification(idmap, inode, attr)) { 95162306a36Sopenharmony_ci err = f2fs_dquot_initialize(inode); 95262306a36Sopenharmony_ci if (err) 95362306a36Sopenharmony_ci return err; 95462306a36Sopenharmony_ci } 95562306a36Sopenharmony_ci if (i_uid_needs_update(idmap, attr, inode) || 95662306a36Sopenharmony_ci i_gid_needs_update(idmap, attr, inode)) { 95762306a36Sopenharmony_ci f2fs_lock_op(F2FS_I_SB(inode)); 95862306a36Sopenharmony_ci err = dquot_transfer(idmap, inode, attr); 95962306a36Sopenharmony_ci if (err) { 96062306a36Sopenharmony_ci set_sbi_flag(F2FS_I_SB(inode), 96162306a36Sopenharmony_ci SBI_QUOTA_NEED_REPAIR); 96262306a36Sopenharmony_ci f2fs_unlock_op(F2FS_I_SB(inode)); 96362306a36Sopenharmony_ci return err; 96462306a36Sopenharmony_ci } 96562306a36Sopenharmony_ci /* 96662306a36Sopenharmony_ci * update uid/gid under lock_op(), so that dquot and inode can 96762306a36Sopenharmony_ci * be updated atomically. 96862306a36Sopenharmony_ci */ 96962306a36Sopenharmony_ci i_uid_update(idmap, attr, inode); 97062306a36Sopenharmony_ci i_gid_update(idmap, attr, inode); 97162306a36Sopenharmony_ci f2fs_mark_inode_dirty_sync(inode, true); 97262306a36Sopenharmony_ci f2fs_unlock_op(F2FS_I_SB(inode)); 97362306a36Sopenharmony_ci } 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_ci if (attr->ia_valid & ATTR_SIZE) { 97662306a36Sopenharmony_ci loff_t old_size = i_size_read(inode); 97762306a36Sopenharmony_ci 97862306a36Sopenharmony_ci if (attr->ia_size > MAX_INLINE_DATA(inode)) { 97962306a36Sopenharmony_ci /* 98062306a36Sopenharmony_ci * should convert inline inode before i_size_write to 98162306a36Sopenharmony_ci * keep smaller than inline_data size with inline flag. 98262306a36Sopenharmony_ci */ 98362306a36Sopenharmony_ci err = f2fs_convert_inline_inode(inode); 98462306a36Sopenharmony_ci if (err) 98562306a36Sopenharmony_ci return err; 98662306a36Sopenharmony_ci } 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_ci f2fs_down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]); 98962306a36Sopenharmony_ci filemap_invalidate_lock(inode->i_mapping); 99062306a36Sopenharmony_ci 99162306a36Sopenharmony_ci truncate_setsize(inode, attr->ia_size); 99262306a36Sopenharmony_ci 99362306a36Sopenharmony_ci if (attr->ia_size <= old_size) 99462306a36Sopenharmony_ci err = f2fs_truncate(inode); 99562306a36Sopenharmony_ci /* 99662306a36Sopenharmony_ci * do not trim all blocks after i_size if target size is 99762306a36Sopenharmony_ci * larger than i_size. 99862306a36Sopenharmony_ci */ 99962306a36Sopenharmony_ci filemap_invalidate_unlock(inode->i_mapping); 100062306a36Sopenharmony_ci f2fs_up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]); 100162306a36Sopenharmony_ci if (err) 100262306a36Sopenharmony_ci return err; 100362306a36Sopenharmony_ci 100462306a36Sopenharmony_ci spin_lock(&F2FS_I(inode)->i_size_lock); 100562306a36Sopenharmony_ci inode->i_mtime = inode_set_ctime_current(inode); 100662306a36Sopenharmony_ci F2FS_I(inode)->last_disk_size = i_size_read(inode); 100762306a36Sopenharmony_ci spin_unlock(&F2FS_I(inode)->i_size_lock); 100862306a36Sopenharmony_ci } 100962306a36Sopenharmony_ci 101062306a36Sopenharmony_ci __setattr_copy(idmap, inode, attr); 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_ci if (attr->ia_valid & ATTR_MODE) { 101362306a36Sopenharmony_ci err = posix_acl_chmod(idmap, dentry, f2fs_get_inode_mode(inode)); 101462306a36Sopenharmony_ci 101562306a36Sopenharmony_ci if (is_inode_flag_set(inode, FI_ACL_MODE)) { 101662306a36Sopenharmony_ci if (!err) 101762306a36Sopenharmony_ci inode->i_mode = F2FS_I(inode)->i_acl_mode; 101862306a36Sopenharmony_ci clear_inode_flag(inode, FI_ACL_MODE); 101962306a36Sopenharmony_ci } 102062306a36Sopenharmony_ci } 102162306a36Sopenharmony_ci 102262306a36Sopenharmony_ci /* file size may changed here */ 102362306a36Sopenharmony_ci f2fs_mark_inode_dirty_sync(inode, true); 102462306a36Sopenharmony_ci 102562306a36Sopenharmony_ci /* inode change will produce dirty node pages flushed by checkpoint */ 102662306a36Sopenharmony_ci f2fs_balance_fs(F2FS_I_SB(inode), true); 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_ci return err; 102962306a36Sopenharmony_ci} 103062306a36Sopenharmony_ci 103162306a36Sopenharmony_ciconst struct inode_operations f2fs_file_inode_operations = { 103262306a36Sopenharmony_ci .getattr = f2fs_getattr, 103362306a36Sopenharmony_ci .setattr = f2fs_setattr, 103462306a36Sopenharmony_ci .get_inode_acl = f2fs_get_acl, 103562306a36Sopenharmony_ci .set_acl = f2fs_set_acl, 103662306a36Sopenharmony_ci .listxattr = f2fs_listxattr, 103762306a36Sopenharmony_ci .fiemap = f2fs_fiemap, 103862306a36Sopenharmony_ci .fileattr_get = f2fs_fileattr_get, 103962306a36Sopenharmony_ci .fileattr_set = f2fs_fileattr_set, 104062306a36Sopenharmony_ci}; 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_cistatic int fill_zero(struct inode *inode, pgoff_t index, 104362306a36Sopenharmony_ci loff_t start, loff_t len) 104462306a36Sopenharmony_ci{ 104562306a36Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_I_SB(inode); 104662306a36Sopenharmony_ci struct page *page; 104762306a36Sopenharmony_ci 104862306a36Sopenharmony_ci if (!len) 104962306a36Sopenharmony_ci return 0; 105062306a36Sopenharmony_ci 105162306a36Sopenharmony_ci f2fs_balance_fs(sbi, true); 105262306a36Sopenharmony_ci 105362306a36Sopenharmony_ci f2fs_lock_op(sbi); 105462306a36Sopenharmony_ci page = f2fs_get_new_data_page(inode, NULL, index, false); 105562306a36Sopenharmony_ci f2fs_unlock_op(sbi); 105662306a36Sopenharmony_ci 105762306a36Sopenharmony_ci if (IS_ERR(page)) 105862306a36Sopenharmony_ci return PTR_ERR(page); 105962306a36Sopenharmony_ci 106062306a36Sopenharmony_ci f2fs_wait_on_page_writeback(page, DATA, true, true); 106162306a36Sopenharmony_ci zero_user(page, start, len); 106262306a36Sopenharmony_ci set_page_dirty(page); 106362306a36Sopenharmony_ci f2fs_put_page(page, 1); 106462306a36Sopenharmony_ci return 0; 106562306a36Sopenharmony_ci} 106662306a36Sopenharmony_ci 106762306a36Sopenharmony_ciint f2fs_truncate_hole(struct inode *inode, pgoff_t pg_start, pgoff_t pg_end) 106862306a36Sopenharmony_ci{ 106962306a36Sopenharmony_ci int err; 107062306a36Sopenharmony_ci 107162306a36Sopenharmony_ci while (pg_start < pg_end) { 107262306a36Sopenharmony_ci struct dnode_of_data dn; 107362306a36Sopenharmony_ci pgoff_t end_offset, count; 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_ci set_new_dnode(&dn, inode, NULL, NULL, 0); 107662306a36Sopenharmony_ci err = f2fs_get_dnode_of_data(&dn, pg_start, LOOKUP_NODE); 107762306a36Sopenharmony_ci if (err) { 107862306a36Sopenharmony_ci if (err == -ENOENT) { 107962306a36Sopenharmony_ci pg_start = f2fs_get_next_page_offset(&dn, 108062306a36Sopenharmony_ci pg_start); 108162306a36Sopenharmony_ci continue; 108262306a36Sopenharmony_ci } 108362306a36Sopenharmony_ci return err; 108462306a36Sopenharmony_ci } 108562306a36Sopenharmony_ci 108662306a36Sopenharmony_ci end_offset = ADDRS_PER_PAGE(dn.node_page, inode); 108762306a36Sopenharmony_ci count = min(end_offset - dn.ofs_in_node, pg_end - pg_start); 108862306a36Sopenharmony_ci 108962306a36Sopenharmony_ci f2fs_bug_on(F2FS_I_SB(inode), count == 0 || count > end_offset); 109062306a36Sopenharmony_ci 109162306a36Sopenharmony_ci f2fs_truncate_data_blocks_range(&dn, count); 109262306a36Sopenharmony_ci f2fs_put_dnode(&dn); 109362306a36Sopenharmony_ci 109462306a36Sopenharmony_ci pg_start += count; 109562306a36Sopenharmony_ci } 109662306a36Sopenharmony_ci return 0; 109762306a36Sopenharmony_ci} 109862306a36Sopenharmony_ci 109962306a36Sopenharmony_cistatic int f2fs_punch_hole(struct inode *inode, loff_t offset, loff_t len) 110062306a36Sopenharmony_ci{ 110162306a36Sopenharmony_ci pgoff_t pg_start, pg_end; 110262306a36Sopenharmony_ci loff_t off_start, off_end; 110362306a36Sopenharmony_ci int ret; 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_ci ret = f2fs_convert_inline_inode(inode); 110662306a36Sopenharmony_ci if (ret) 110762306a36Sopenharmony_ci return ret; 110862306a36Sopenharmony_ci 110962306a36Sopenharmony_ci pg_start = ((unsigned long long) offset) >> PAGE_SHIFT; 111062306a36Sopenharmony_ci pg_end = ((unsigned long long) offset + len) >> PAGE_SHIFT; 111162306a36Sopenharmony_ci 111262306a36Sopenharmony_ci off_start = offset & (PAGE_SIZE - 1); 111362306a36Sopenharmony_ci off_end = (offset + len) & (PAGE_SIZE - 1); 111462306a36Sopenharmony_ci 111562306a36Sopenharmony_ci if (pg_start == pg_end) { 111662306a36Sopenharmony_ci ret = fill_zero(inode, pg_start, off_start, 111762306a36Sopenharmony_ci off_end - off_start); 111862306a36Sopenharmony_ci if (ret) 111962306a36Sopenharmony_ci return ret; 112062306a36Sopenharmony_ci } else { 112162306a36Sopenharmony_ci if (off_start) { 112262306a36Sopenharmony_ci ret = fill_zero(inode, pg_start++, off_start, 112362306a36Sopenharmony_ci PAGE_SIZE - off_start); 112462306a36Sopenharmony_ci if (ret) 112562306a36Sopenharmony_ci return ret; 112662306a36Sopenharmony_ci } 112762306a36Sopenharmony_ci if (off_end) { 112862306a36Sopenharmony_ci ret = fill_zero(inode, pg_end, 0, off_end); 112962306a36Sopenharmony_ci if (ret) 113062306a36Sopenharmony_ci return ret; 113162306a36Sopenharmony_ci } 113262306a36Sopenharmony_ci 113362306a36Sopenharmony_ci if (pg_start < pg_end) { 113462306a36Sopenharmony_ci loff_t blk_start, blk_end; 113562306a36Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_I_SB(inode); 113662306a36Sopenharmony_ci 113762306a36Sopenharmony_ci f2fs_balance_fs(sbi, true); 113862306a36Sopenharmony_ci 113962306a36Sopenharmony_ci blk_start = (loff_t)pg_start << PAGE_SHIFT; 114062306a36Sopenharmony_ci blk_end = (loff_t)pg_end << PAGE_SHIFT; 114162306a36Sopenharmony_ci 114262306a36Sopenharmony_ci f2fs_down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]); 114362306a36Sopenharmony_ci filemap_invalidate_lock(inode->i_mapping); 114462306a36Sopenharmony_ci 114562306a36Sopenharmony_ci truncate_pagecache_range(inode, blk_start, blk_end - 1); 114662306a36Sopenharmony_ci 114762306a36Sopenharmony_ci f2fs_lock_op(sbi); 114862306a36Sopenharmony_ci ret = f2fs_truncate_hole(inode, pg_start, pg_end); 114962306a36Sopenharmony_ci f2fs_unlock_op(sbi); 115062306a36Sopenharmony_ci 115162306a36Sopenharmony_ci filemap_invalidate_unlock(inode->i_mapping); 115262306a36Sopenharmony_ci f2fs_up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]); 115362306a36Sopenharmony_ci } 115462306a36Sopenharmony_ci } 115562306a36Sopenharmony_ci 115662306a36Sopenharmony_ci return ret; 115762306a36Sopenharmony_ci} 115862306a36Sopenharmony_ci 115962306a36Sopenharmony_cistatic int __read_out_blkaddrs(struct inode *inode, block_t *blkaddr, 116062306a36Sopenharmony_ci int *do_replace, pgoff_t off, pgoff_t len) 116162306a36Sopenharmony_ci{ 116262306a36Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_I_SB(inode); 116362306a36Sopenharmony_ci struct dnode_of_data dn; 116462306a36Sopenharmony_ci int ret, done, i; 116562306a36Sopenharmony_ci 116662306a36Sopenharmony_cinext_dnode: 116762306a36Sopenharmony_ci set_new_dnode(&dn, inode, NULL, NULL, 0); 116862306a36Sopenharmony_ci ret = f2fs_get_dnode_of_data(&dn, off, LOOKUP_NODE_RA); 116962306a36Sopenharmony_ci if (ret && ret != -ENOENT) { 117062306a36Sopenharmony_ci return ret; 117162306a36Sopenharmony_ci } else if (ret == -ENOENT) { 117262306a36Sopenharmony_ci if (dn.max_level == 0) 117362306a36Sopenharmony_ci return -ENOENT; 117462306a36Sopenharmony_ci done = min((pgoff_t)ADDRS_PER_BLOCK(inode) - 117562306a36Sopenharmony_ci dn.ofs_in_node, len); 117662306a36Sopenharmony_ci blkaddr += done; 117762306a36Sopenharmony_ci do_replace += done; 117862306a36Sopenharmony_ci goto next; 117962306a36Sopenharmony_ci } 118062306a36Sopenharmony_ci 118162306a36Sopenharmony_ci done = min((pgoff_t)ADDRS_PER_PAGE(dn.node_page, inode) - 118262306a36Sopenharmony_ci dn.ofs_in_node, len); 118362306a36Sopenharmony_ci for (i = 0; i < done; i++, blkaddr++, do_replace++, dn.ofs_in_node++) { 118462306a36Sopenharmony_ci *blkaddr = f2fs_data_blkaddr(&dn); 118562306a36Sopenharmony_ci 118662306a36Sopenharmony_ci if (__is_valid_data_blkaddr(*blkaddr) && 118762306a36Sopenharmony_ci !f2fs_is_valid_blkaddr(sbi, *blkaddr, 118862306a36Sopenharmony_ci DATA_GENERIC_ENHANCE)) { 118962306a36Sopenharmony_ci f2fs_put_dnode(&dn); 119062306a36Sopenharmony_ci f2fs_handle_error(sbi, ERROR_INVALID_BLKADDR); 119162306a36Sopenharmony_ci return -EFSCORRUPTED; 119262306a36Sopenharmony_ci } 119362306a36Sopenharmony_ci 119462306a36Sopenharmony_ci if (!f2fs_is_checkpointed_data(sbi, *blkaddr)) { 119562306a36Sopenharmony_ci 119662306a36Sopenharmony_ci if (f2fs_lfs_mode(sbi)) { 119762306a36Sopenharmony_ci f2fs_put_dnode(&dn); 119862306a36Sopenharmony_ci return -EOPNOTSUPP; 119962306a36Sopenharmony_ci } 120062306a36Sopenharmony_ci 120162306a36Sopenharmony_ci /* do not invalidate this block address */ 120262306a36Sopenharmony_ci f2fs_update_data_blkaddr(&dn, NULL_ADDR); 120362306a36Sopenharmony_ci *do_replace = 1; 120462306a36Sopenharmony_ci } 120562306a36Sopenharmony_ci } 120662306a36Sopenharmony_ci f2fs_put_dnode(&dn); 120762306a36Sopenharmony_cinext: 120862306a36Sopenharmony_ci len -= done; 120962306a36Sopenharmony_ci off += done; 121062306a36Sopenharmony_ci if (len) 121162306a36Sopenharmony_ci goto next_dnode; 121262306a36Sopenharmony_ci return 0; 121362306a36Sopenharmony_ci} 121462306a36Sopenharmony_ci 121562306a36Sopenharmony_cistatic int __roll_back_blkaddrs(struct inode *inode, block_t *blkaddr, 121662306a36Sopenharmony_ci int *do_replace, pgoff_t off, int len) 121762306a36Sopenharmony_ci{ 121862306a36Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_I_SB(inode); 121962306a36Sopenharmony_ci struct dnode_of_data dn; 122062306a36Sopenharmony_ci int ret, i; 122162306a36Sopenharmony_ci 122262306a36Sopenharmony_ci for (i = 0; i < len; i++, do_replace++, blkaddr++) { 122362306a36Sopenharmony_ci if (*do_replace == 0) 122462306a36Sopenharmony_ci continue; 122562306a36Sopenharmony_ci 122662306a36Sopenharmony_ci set_new_dnode(&dn, inode, NULL, NULL, 0); 122762306a36Sopenharmony_ci ret = f2fs_get_dnode_of_data(&dn, off + i, LOOKUP_NODE_RA); 122862306a36Sopenharmony_ci if (ret) { 122962306a36Sopenharmony_ci dec_valid_block_count(sbi, inode, 1); 123062306a36Sopenharmony_ci f2fs_invalidate_blocks(sbi, *blkaddr); 123162306a36Sopenharmony_ci } else { 123262306a36Sopenharmony_ci f2fs_update_data_blkaddr(&dn, *blkaddr); 123362306a36Sopenharmony_ci } 123462306a36Sopenharmony_ci f2fs_put_dnode(&dn); 123562306a36Sopenharmony_ci } 123662306a36Sopenharmony_ci return 0; 123762306a36Sopenharmony_ci} 123862306a36Sopenharmony_ci 123962306a36Sopenharmony_cistatic int __clone_blkaddrs(struct inode *src_inode, struct inode *dst_inode, 124062306a36Sopenharmony_ci block_t *blkaddr, int *do_replace, 124162306a36Sopenharmony_ci pgoff_t src, pgoff_t dst, pgoff_t len, bool full) 124262306a36Sopenharmony_ci{ 124362306a36Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_I_SB(src_inode); 124462306a36Sopenharmony_ci pgoff_t i = 0; 124562306a36Sopenharmony_ci int ret; 124662306a36Sopenharmony_ci 124762306a36Sopenharmony_ci while (i < len) { 124862306a36Sopenharmony_ci if (blkaddr[i] == NULL_ADDR && !full) { 124962306a36Sopenharmony_ci i++; 125062306a36Sopenharmony_ci continue; 125162306a36Sopenharmony_ci } 125262306a36Sopenharmony_ci 125362306a36Sopenharmony_ci if (do_replace[i] || blkaddr[i] == NULL_ADDR) { 125462306a36Sopenharmony_ci struct dnode_of_data dn; 125562306a36Sopenharmony_ci struct node_info ni; 125662306a36Sopenharmony_ci size_t new_size; 125762306a36Sopenharmony_ci pgoff_t ilen; 125862306a36Sopenharmony_ci 125962306a36Sopenharmony_ci set_new_dnode(&dn, dst_inode, NULL, NULL, 0); 126062306a36Sopenharmony_ci ret = f2fs_get_dnode_of_data(&dn, dst + i, ALLOC_NODE); 126162306a36Sopenharmony_ci if (ret) 126262306a36Sopenharmony_ci return ret; 126362306a36Sopenharmony_ci 126462306a36Sopenharmony_ci ret = f2fs_get_node_info(sbi, dn.nid, &ni, false); 126562306a36Sopenharmony_ci if (ret) { 126662306a36Sopenharmony_ci f2fs_put_dnode(&dn); 126762306a36Sopenharmony_ci return ret; 126862306a36Sopenharmony_ci } 126962306a36Sopenharmony_ci 127062306a36Sopenharmony_ci ilen = min((pgoff_t) 127162306a36Sopenharmony_ci ADDRS_PER_PAGE(dn.node_page, dst_inode) - 127262306a36Sopenharmony_ci dn.ofs_in_node, len - i); 127362306a36Sopenharmony_ci do { 127462306a36Sopenharmony_ci dn.data_blkaddr = f2fs_data_blkaddr(&dn); 127562306a36Sopenharmony_ci f2fs_truncate_data_blocks_range(&dn, 1); 127662306a36Sopenharmony_ci 127762306a36Sopenharmony_ci if (do_replace[i]) { 127862306a36Sopenharmony_ci f2fs_i_blocks_write(src_inode, 127962306a36Sopenharmony_ci 1, false, false); 128062306a36Sopenharmony_ci f2fs_i_blocks_write(dst_inode, 128162306a36Sopenharmony_ci 1, true, false); 128262306a36Sopenharmony_ci f2fs_replace_block(sbi, &dn, dn.data_blkaddr, 128362306a36Sopenharmony_ci blkaddr[i], ni.version, true, false); 128462306a36Sopenharmony_ci 128562306a36Sopenharmony_ci do_replace[i] = 0; 128662306a36Sopenharmony_ci } 128762306a36Sopenharmony_ci dn.ofs_in_node++; 128862306a36Sopenharmony_ci i++; 128962306a36Sopenharmony_ci new_size = (loff_t)(dst + i) << PAGE_SHIFT; 129062306a36Sopenharmony_ci if (dst_inode->i_size < new_size) 129162306a36Sopenharmony_ci f2fs_i_size_write(dst_inode, new_size); 129262306a36Sopenharmony_ci } while (--ilen && (do_replace[i] || blkaddr[i] == NULL_ADDR)); 129362306a36Sopenharmony_ci 129462306a36Sopenharmony_ci f2fs_put_dnode(&dn); 129562306a36Sopenharmony_ci } else { 129662306a36Sopenharmony_ci struct page *psrc, *pdst; 129762306a36Sopenharmony_ci 129862306a36Sopenharmony_ci psrc = f2fs_get_lock_data_page(src_inode, 129962306a36Sopenharmony_ci src + i, true); 130062306a36Sopenharmony_ci if (IS_ERR(psrc)) 130162306a36Sopenharmony_ci return PTR_ERR(psrc); 130262306a36Sopenharmony_ci pdst = f2fs_get_new_data_page(dst_inode, NULL, dst + i, 130362306a36Sopenharmony_ci true); 130462306a36Sopenharmony_ci if (IS_ERR(pdst)) { 130562306a36Sopenharmony_ci f2fs_put_page(psrc, 1); 130662306a36Sopenharmony_ci return PTR_ERR(pdst); 130762306a36Sopenharmony_ci } 130862306a36Sopenharmony_ci memcpy_page(pdst, 0, psrc, 0, PAGE_SIZE); 130962306a36Sopenharmony_ci set_page_dirty(pdst); 131062306a36Sopenharmony_ci set_page_private_gcing(pdst); 131162306a36Sopenharmony_ci f2fs_put_page(pdst, 1); 131262306a36Sopenharmony_ci f2fs_put_page(psrc, 1); 131362306a36Sopenharmony_ci 131462306a36Sopenharmony_ci ret = f2fs_truncate_hole(src_inode, 131562306a36Sopenharmony_ci src + i, src + i + 1); 131662306a36Sopenharmony_ci if (ret) 131762306a36Sopenharmony_ci return ret; 131862306a36Sopenharmony_ci i++; 131962306a36Sopenharmony_ci } 132062306a36Sopenharmony_ci } 132162306a36Sopenharmony_ci return 0; 132262306a36Sopenharmony_ci} 132362306a36Sopenharmony_ci 132462306a36Sopenharmony_cistatic int __exchange_data_block(struct inode *src_inode, 132562306a36Sopenharmony_ci struct inode *dst_inode, pgoff_t src, pgoff_t dst, 132662306a36Sopenharmony_ci pgoff_t len, bool full) 132762306a36Sopenharmony_ci{ 132862306a36Sopenharmony_ci block_t *src_blkaddr; 132962306a36Sopenharmony_ci int *do_replace; 133062306a36Sopenharmony_ci pgoff_t olen; 133162306a36Sopenharmony_ci int ret; 133262306a36Sopenharmony_ci 133362306a36Sopenharmony_ci while (len) { 133462306a36Sopenharmony_ci olen = min((pgoff_t)4 * ADDRS_PER_BLOCK(src_inode), len); 133562306a36Sopenharmony_ci 133662306a36Sopenharmony_ci src_blkaddr = f2fs_kvzalloc(F2FS_I_SB(src_inode), 133762306a36Sopenharmony_ci array_size(olen, sizeof(block_t)), 133862306a36Sopenharmony_ci GFP_NOFS); 133962306a36Sopenharmony_ci if (!src_blkaddr) 134062306a36Sopenharmony_ci return -ENOMEM; 134162306a36Sopenharmony_ci 134262306a36Sopenharmony_ci do_replace = f2fs_kvzalloc(F2FS_I_SB(src_inode), 134362306a36Sopenharmony_ci array_size(olen, sizeof(int)), 134462306a36Sopenharmony_ci GFP_NOFS); 134562306a36Sopenharmony_ci if (!do_replace) { 134662306a36Sopenharmony_ci kvfree(src_blkaddr); 134762306a36Sopenharmony_ci return -ENOMEM; 134862306a36Sopenharmony_ci } 134962306a36Sopenharmony_ci 135062306a36Sopenharmony_ci ret = __read_out_blkaddrs(src_inode, src_blkaddr, 135162306a36Sopenharmony_ci do_replace, src, olen); 135262306a36Sopenharmony_ci if (ret) 135362306a36Sopenharmony_ci goto roll_back; 135462306a36Sopenharmony_ci 135562306a36Sopenharmony_ci ret = __clone_blkaddrs(src_inode, dst_inode, src_blkaddr, 135662306a36Sopenharmony_ci do_replace, src, dst, olen, full); 135762306a36Sopenharmony_ci if (ret) 135862306a36Sopenharmony_ci goto roll_back; 135962306a36Sopenharmony_ci 136062306a36Sopenharmony_ci src += olen; 136162306a36Sopenharmony_ci dst += olen; 136262306a36Sopenharmony_ci len -= olen; 136362306a36Sopenharmony_ci 136462306a36Sopenharmony_ci kvfree(src_blkaddr); 136562306a36Sopenharmony_ci kvfree(do_replace); 136662306a36Sopenharmony_ci } 136762306a36Sopenharmony_ci return 0; 136862306a36Sopenharmony_ci 136962306a36Sopenharmony_ciroll_back: 137062306a36Sopenharmony_ci __roll_back_blkaddrs(src_inode, src_blkaddr, do_replace, src, olen); 137162306a36Sopenharmony_ci kvfree(src_blkaddr); 137262306a36Sopenharmony_ci kvfree(do_replace); 137362306a36Sopenharmony_ci return ret; 137462306a36Sopenharmony_ci} 137562306a36Sopenharmony_ci 137662306a36Sopenharmony_cistatic int f2fs_do_collapse(struct inode *inode, loff_t offset, loff_t len) 137762306a36Sopenharmony_ci{ 137862306a36Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_I_SB(inode); 137962306a36Sopenharmony_ci pgoff_t nrpages = DIV_ROUND_UP(i_size_read(inode), PAGE_SIZE); 138062306a36Sopenharmony_ci pgoff_t start = offset >> PAGE_SHIFT; 138162306a36Sopenharmony_ci pgoff_t end = (offset + len) >> PAGE_SHIFT; 138262306a36Sopenharmony_ci int ret; 138362306a36Sopenharmony_ci 138462306a36Sopenharmony_ci f2fs_balance_fs(sbi, true); 138562306a36Sopenharmony_ci 138662306a36Sopenharmony_ci /* avoid gc operation during block exchange */ 138762306a36Sopenharmony_ci f2fs_down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]); 138862306a36Sopenharmony_ci filemap_invalidate_lock(inode->i_mapping); 138962306a36Sopenharmony_ci 139062306a36Sopenharmony_ci f2fs_lock_op(sbi); 139162306a36Sopenharmony_ci f2fs_drop_extent_tree(inode); 139262306a36Sopenharmony_ci truncate_pagecache(inode, offset); 139362306a36Sopenharmony_ci ret = __exchange_data_block(inode, inode, end, start, nrpages - end, true); 139462306a36Sopenharmony_ci f2fs_unlock_op(sbi); 139562306a36Sopenharmony_ci 139662306a36Sopenharmony_ci filemap_invalidate_unlock(inode->i_mapping); 139762306a36Sopenharmony_ci f2fs_up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]); 139862306a36Sopenharmony_ci return ret; 139962306a36Sopenharmony_ci} 140062306a36Sopenharmony_ci 140162306a36Sopenharmony_cistatic int f2fs_collapse_range(struct inode *inode, loff_t offset, loff_t len) 140262306a36Sopenharmony_ci{ 140362306a36Sopenharmony_ci loff_t new_size; 140462306a36Sopenharmony_ci int ret; 140562306a36Sopenharmony_ci 140662306a36Sopenharmony_ci if (offset + len >= i_size_read(inode)) 140762306a36Sopenharmony_ci return -EINVAL; 140862306a36Sopenharmony_ci 140962306a36Sopenharmony_ci /* collapse range should be aligned to block size of f2fs. */ 141062306a36Sopenharmony_ci if (offset & (F2FS_BLKSIZE - 1) || len & (F2FS_BLKSIZE - 1)) 141162306a36Sopenharmony_ci return -EINVAL; 141262306a36Sopenharmony_ci 141362306a36Sopenharmony_ci ret = f2fs_convert_inline_inode(inode); 141462306a36Sopenharmony_ci if (ret) 141562306a36Sopenharmony_ci return ret; 141662306a36Sopenharmony_ci 141762306a36Sopenharmony_ci /* write out all dirty pages from offset */ 141862306a36Sopenharmony_ci ret = filemap_write_and_wait_range(inode->i_mapping, offset, LLONG_MAX); 141962306a36Sopenharmony_ci if (ret) 142062306a36Sopenharmony_ci return ret; 142162306a36Sopenharmony_ci 142262306a36Sopenharmony_ci ret = f2fs_do_collapse(inode, offset, len); 142362306a36Sopenharmony_ci if (ret) 142462306a36Sopenharmony_ci return ret; 142562306a36Sopenharmony_ci 142662306a36Sopenharmony_ci /* write out all moved pages, if possible */ 142762306a36Sopenharmony_ci filemap_invalidate_lock(inode->i_mapping); 142862306a36Sopenharmony_ci filemap_write_and_wait_range(inode->i_mapping, offset, LLONG_MAX); 142962306a36Sopenharmony_ci truncate_pagecache(inode, offset); 143062306a36Sopenharmony_ci 143162306a36Sopenharmony_ci new_size = i_size_read(inode) - len; 143262306a36Sopenharmony_ci ret = f2fs_truncate_blocks(inode, new_size, true); 143362306a36Sopenharmony_ci filemap_invalidate_unlock(inode->i_mapping); 143462306a36Sopenharmony_ci if (!ret) 143562306a36Sopenharmony_ci f2fs_i_size_write(inode, new_size); 143662306a36Sopenharmony_ci return ret; 143762306a36Sopenharmony_ci} 143862306a36Sopenharmony_ci 143962306a36Sopenharmony_cistatic int f2fs_do_zero_range(struct dnode_of_data *dn, pgoff_t start, 144062306a36Sopenharmony_ci pgoff_t end) 144162306a36Sopenharmony_ci{ 144262306a36Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_I_SB(dn->inode); 144362306a36Sopenharmony_ci pgoff_t index = start; 144462306a36Sopenharmony_ci unsigned int ofs_in_node = dn->ofs_in_node; 144562306a36Sopenharmony_ci blkcnt_t count = 0; 144662306a36Sopenharmony_ci int ret; 144762306a36Sopenharmony_ci 144862306a36Sopenharmony_ci for (; index < end; index++, dn->ofs_in_node++) { 144962306a36Sopenharmony_ci if (f2fs_data_blkaddr(dn) == NULL_ADDR) 145062306a36Sopenharmony_ci count++; 145162306a36Sopenharmony_ci } 145262306a36Sopenharmony_ci 145362306a36Sopenharmony_ci dn->ofs_in_node = ofs_in_node; 145462306a36Sopenharmony_ci ret = f2fs_reserve_new_blocks(dn, count); 145562306a36Sopenharmony_ci if (ret) 145662306a36Sopenharmony_ci return ret; 145762306a36Sopenharmony_ci 145862306a36Sopenharmony_ci dn->ofs_in_node = ofs_in_node; 145962306a36Sopenharmony_ci for (index = start; index < end; index++, dn->ofs_in_node++) { 146062306a36Sopenharmony_ci dn->data_blkaddr = f2fs_data_blkaddr(dn); 146162306a36Sopenharmony_ci /* 146262306a36Sopenharmony_ci * f2fs_reserve_new_blocks will not guarantee entire block 146362306a36Sopenharmony_ci * allocation. 146462306a36Sopenharmony_ci */ 146562306a36Sopenharmony_ci if (dn->data_blkaddr == NULL_ADDR) { 146662306a36Sopenharmony_ci ret = -ENOSPC; 146762306a36Sopenharmony_ci break; 146862306a36Sopenharmony_ci } 146962306a36Sopenharmony_ci 147062306a36Sopenharmony_ci if (dn->data_blkaddr == NEW_ADDR) 147162306a36Sopenharmony_ci continue; 147262306a36Sopenharmony_ci 147362306a36Sopenharmony_ci if (!f2fs_is_valid_blkaddr(sbi, dn->data_blkaddr, 147462306a36Sopenharmony_ci DATA_GENERIC_ENHANCE)) { 147562306a36Sopenharmony_ci ret = -EFSCORRUPTED; 147662306a36Sopenharmony_ci f2fs_handle_error(sbi, ERROR_INVALID_BLKADDR); 147762306a36Sopenharmony_ci break; 147862306a36Sopenharmony_ci } 147962306a36Sopenharmony_ci 148062306a36Sopenharmony_ci f2fs_invalidate_blocks(sbi, dn->data_blkaddr); 148162306a36Sopenharmony_ci f2fs_set_data_blkaddr(dn, NEW_ADDR); 148262306a36Sopenharmony_ci } 148362306a36Sopenharmony_ci 148462306a36Sopenharmony_ci f2fs_update_read_extent_cache_range(dn, start, 0, index - start); 148562306a36Sopenharmony_ci f2fs_update_age_extent_cache_range(dn, start, index - start); 148662306a36Sopenharmony_ci 148762306a36Sopenharmony_ci return ret; 148862306a36Sopenharmony_ci} 148962306a36Sopenharmony_ci 149062306a36Sopenharmony_cistatic int f2fs_zero_range(struct inode *inode, loff_t offset, loff_t len, 149162306a36Sopenharmony_ci int mode) 149262306a36Sopenharmony_ci{ 149362306a36Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_I_SB(inode); 149462306a36Sopenharmony_ci struct address_space *mapping = inode->i_mapping; 149562306a36Sopenharmony_ci pgoff_t index, pg_start, pg_end; 149662306a36Sopenharmony_ci loff_t new_size = i_size_read(inode); 149762306a36Sopenharmony_ci loff_t off_start, off_end; 149862306a36Sopenharmony_ci int ret = 0; 149962306a36Sopenharmony_ci 150062306a36Sopenharmony_ci ret = inode_newsize_ok(inode, (len + offset)); 150162306a36Sopenharmony_ci if (ret) 150262306a36Sopenharmony_ci return ret; 150362306a36Sopenharmony_ci 150462306a36Sopenharmony_ci ret = f2fs_convert_inline_inode(inode); 150562306a36Sopenharmony_ci if (ret) 150662306a36Sopenharmony_ci return ret; 150762306a36Sopenharmony_ci 150862306a36Sopenharmony_ci ret = filemap_write_and_wait_range(mapping, offset, offset + len - 1); 150962306a36Sopenharmony_ci if (ret) 151062306a36Sopenharmony_ci return ret; 151162306a36Sopenharmony_ci 151262306a36Sopenharmony_ci pg_start = ((unsigned long long) offset) >> PAGE_SHIFT; 151362306a36Sopenharmony_ci pg_end = ((unsigned long long) offset + len) >> PAGE_SHIFT; 151462306a36Sopenharmony_ci 151562306a36Sopenharmony_ci off_start = offset & (PAGE_SIZE - 1); 151662306a36Sopenharmony_ci off_end = (offset + len) & (PAGE_SIZE - 1); 151762306a36Sopenharmony_ci 151862306a36Sopenharmony_ci if (pg_start == pg_end) { 151962306a36Sopenharmony_ci ret = fill_zero(inode, pg_start, off_start, 152062306a36Sopenharmony_ci off_end - off_start); 152162306a36Sopenharmony_ci if (ret) 152262306a36Sopenharmony_ci return ret; 152362306a36Sopenharmony_ci 152462306a36Sopenharmony_ci new_size = max_t(loff_t, new_size, offset + len); 152562306a36Sopenharmony_ci } else { 152662306a36Sopenharmony_ci if (off_start) { 152762306a36Sopenharmony_ci ret = fill_zero(inode, pg_start++, off_start, 152862306a36Sopenharmony_ci PAGE_SIZE - off_start); 152962306a36Sopenharmony_ci if (ret) 153062306a36Sopenharmony_ci return ret; 153162306a36Sopenharmony_ci 153262306a36Sopenharmony_ci new_size = max_t(loff_t, new_size, 153362306a36Sopenharmony_ci (loff_t)pg_start << PAGE_SHIFT); 153462306a36Sopenharmony_ci } 153562306a36Sopenharmony_ci 153662306a36Sopenharmony_ci for (index = pg_start; index < pg_end;) { 153762306a36Sopenharmony_ci struct dnode_of_data dn; 153862306a36Sopenharmony_ci unsigned int end_offset; 153962306a36Sopenharmony_ci pgoff_t end; 154062306a36Sopenharmony_ci 154162306a36Sopenharmony_ci f2fs_down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]); 154262306a36Sopenharmony_ci filemap_invalidate_lock(mapping); 154362306a36Sopenharmony_ci 154462306a36Sopenharmony_ci truncate_pagecache_range(inode, 154562306a36Sopenharmony_ci (loff_t)index << PAGE_SHIFT, 154662306a36Sopenharmony_ci ((loff_t)pg_end << PAGE_SHIFT) - 1); 154762306a36Sopenharmony_ci 154862306a36Sopenharmony_ci f2fs_lock_op(sbi); 154962306a36Sopenharmony_ci 155062306a36Sopenharmony_ci set_new_dnode(&dn, inode, NULL, NULL, 0); 155162306a36Sopenharmony_ci ret = f2fs_get_dnode_of_data(&dn, index, ALLOC_NODE); 155262306a36Sopenharmony_ci if (ret) { 155362306a36Sopenharmony_ci f2fs_unlock_op(sbi); 155462306a36Sopenharmony_ci filemap_invalidate_unlock(mapping); 155562306a36Sopenharmony_ci f2fs_up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]); 155662306a36Sopenharmony_ci goto out; 155762306a36Sopenharmony_ci } 155862306a36Sopenharmony_ci 155962306a36Sopenharmony_ci end_offset = ADDRS_PER_PAGE(dn.node_page, inode); 156062306a36Sopenharmony_ci end = min(pg_end, end_offset - dn.ofs_in_node + index); 156162306a36Sopenharmony_ci 156262306a36Sopenharmony_ci ret = f2fs_do_zero_range(&dn, index, end); 156362306a36Sopenharmony_ci f2fs_put_dnode(&dn); 156462306a36Sopenharmony_ci 156562306a36Sopenharmony_ci f2fs_unlock_op(sbi); 156662306a36Sopenharmony_ci filemap_invalidate_unlock(mapping); 156762306a36Sopenharmony_ci f2fs_up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]); 156862306a36Sopenharmony_ci 156962306a36Sopenharmony_ci f2fs_balance_fs(sbi, dn.node_changed); 157062306a36Sopenharmony_ci 157162306a36Sopenharmony_ci if (ret) 157262306a36Sopenharmony_ci goto out; 157362306a36Sopenharmony_ci 157462306a36Sopenharmony_ci index = end; 157562306a36Sopenharmony_ci new_size = max_t(loff_t, new_size, 157662306a36Sopenharmony_ci (loff_t)index << PAGE_SHIFT); 157762306a36Sopenharmony_ci } 157862306a36Sopenharmony_ci 157962306a36Sopenharmony_ci if (off_end) { 158062306a36Sopenharmony_ci ret = fill_zero(inode, pg_end, 0, off_end); 158162306a36Sopenharmony_ci if (ret) 158262306a36Sopenharmony_ci goto out; 158362306a36Sopenharmony_ci 158462306a36Sopenharmony_ci new_size = max_t(loff_t, new_size, offset + len); 158562306a36Sopenharmony_ci } 158662306a36Sopenharmony_ci } 158762306a36Sopenharmony_ci 158862306a36Sopenharmony_ciout: 158962306a36Sopenharmony_ci if (new_size > i_size_read(inode)) { 159062306a36Sopenharmony_ci if (mode & FALLOC_FL_KEEP_SIZE) 159162306a36Sopenharmony_ci file_set_keep_isize(inode); 159262306a36Sopenharmony_ci else 159362306a36Sopenharmony_ci f2fs_i_size_write(inode, new_size); 159462306a36Sopenharmony_ci } 159562306a36Sopenharmony_ci return ret; 159662306a36Sopenharmony_ci} 159762306a36Sopenharmony_ci 159862306a36Sopenharmony_cistatic int f2fs_insert_range(struct inode *inode, loff_t offset, loff_t len) 159962306a36Sopenharmony_ci{ 160062306a36Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_I_SB(inode); 160162306a36Sopenharmony_ci struct address_space *mapping = inode->i_mapping; 160262306a36Sopenharmony_ci pgoff_t nr, pg_start, pg_end, delta, idx; 160362306a36Sopenharmony_ci loff_t new_size; 160462306a36Sopenharmony_ci int ret = 0; 160562306a36Sopenharmony_ci 160662306a36Sopenharmony_ci new_size = i_size_read(inode) + len; 160762306a36Sopenharmony_ci ret = inode_newsize_ok(inode, new_size); 160862306a36Sopenharmony_ci if (ret) 160962306a36Sopenharmony_ci return ret; 161062306a36Sopenharmony_ci 161162306a36Sopenharmony_ci if (offset >= i_size_read(inode)) 161262306a36Sopenharmony_ci return -EINVAL; 161362306a36Sopenharmony_ci 161462306a36Sopenharmony_ci /* insert range should be aligned to block size of f2fs. */ 161562306a36Sopenharmony_ci if (offset & (F2FS_BLKSIZE - 1) || len & (F2FS_BLKSIZE - 1)) 161662306a36Sopenharmony_ci return -EINVAL; 161762306a36Sopenharmony_ci 161862306a36Sopenharmony_ci ret = f2fs_convert_inline_inode(inode); 161962306a36Sopenharmony_ci if (ret) 162062306a36Sopenharmony_ci return ret; 162162306a36Sopenharmony_ci 162262306a36Sopenharmony_ci f2fs_balance_fs(sbi, true); 162362306a36Sopenharmony_ci 162462306a36Sopenharmony_ci filemap_invalidate_lock(mapping); 162562306a36Sopenharmony_ci ret = f2fs_truncate_blocks(inode, i_size_read(inode), true); 162662306a36Sopenharmony_ci filemap_invalidate_unlock(mapping); 162762306a36Sopenharmony_ci if (ret) 162862306a36Sopenharmony_ci return ret; 162962306a36Sopenharmony_ci 163062306a36Sopenharmony_ci /* write out all dirty pages from offset */ 163162306a36Sopenharmony_ci ret = filemap_write_and_wait_range(mapping, offset, LLONG_MAX); 163262306a36Sopenharmony_ci if (ret) 163362306a36Sopenharmony_ci return ret; 163462306a36Sopenharmony_ci 163562306a36Sopenharmony_ci pg_start = offset >> PAGE_SHIFT; 163662306a36Sopenharmony_ci pg_end = (offset + len) >> PAGE_SHIFT; 163762306a36Sopenharmony_ci delta = pg_end - pg_start; 163862306a36Sopenharmony_ci idx = DIV_ROUND_UP(i_size_read(inode), PAGE_SIZE); 163962306a36Sopenharmony_ci 164062306a36Sopenharmony_ci /* avoid gc operation during block exchange */ 164162306a36Sopenharmony_ci f2fs_down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]); 164262306a36Sopenharmony_ci filemap_invalidate_lock(mapping); 164362306a36Sopenharmony_ci truncate_pagecache(inode, offset); 164462306a36Sopenharmony_ci 164562306a36Sopenharmony_ci while (!ret && idx > pg_start) { 164662306a36Sopenharmony_ci nr = idx - pg_start; 164762306a36Sopenharmony_ci if (nr > delta) 164862306a36Sopenharmony_ci nr = delta; 164962306a36Sopenharmony_ci idx -= nr; 165062306a36Sopenharmony_ci 165162306a36Sopenharmony_ci f2fs_lock_op(sbi); 165262306a36Sopenharmony_ci f2fs_drop_extent_tree(inode); 165362306a36Sopenharmony_ci 165462306a36Sopenharmony_ci ret = __exchange_data_block(inode, inode, idx, 165562306a36Sopenharmony_ci idx + delta, nr, false); 165662306a36Sopenharmony_ci f2fs_unlock_op(sbi); 165762306a36Sopenharmony_ci } 165862306a36Sopenharmony_ci filemap_invalidate_unlock(mapping); 165962306a36Sopenharmony_ci f2fs_up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]); 166062306a36Sopenharmony_ci 166162306a36Sopenharmony_ci /* write out all moved pages, if possible */ 166262306a36Sopenharmony_ci filemap_invalidate_lock(mapping); 166362306a36Sopenharmony_ci filemap_write_and_wait_range(mapping, offset, LLONG_MAX); 166462306a36Sopenharmony_ci truncate_pagecache(inode, offset); 166562306a36Sopenharmony_ci filemap_invalidate_unlock(mapping); 166662306a36Sopenharmony_ci 166762306a36Sopenharmony_ci if (!ret) 166862306a36Sopenharmony_ci f2fs_i_size_write(inode, new_size); 166962306a36Sopenharmony_ci return ret; 167062306a36Sopenharmony_ci} 167162306a36Sopenharmony_ci 167262306a36Sopenharmony_cistatic int f2fs_expand_inode_data(struct inode *inode, loff_t offset, 167362306a36Sopenharmony_ci loff_t len, int mode) 167462306a36Sopenharmony_ci{ 167562306a36Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_I_SB(inode); 167662306a36Sopenharmony_ci struct f2fs_map_blocks map = { .m_next_pgofs = NULL, 167762306a36Sopenharmony_ci .m_next_extent = NULL, .m_seg_type = NO_CHECK_TYPE, 167862306a36Sopenharmony_ci .m_may_create = true }; 167962306a36Sopenharmony_ci struct f2fs_gc_control gc_control = { .victim_segno = NULL_SEGNO, 168062306a36Sopenharmony_ci .init_gc_type = FG_GC, 168162306a36Sopenharmony_ci .should_migrate_blocks = false, 168262306a36Sopenharmony_ci .err_gc_skipped = true, 168362306a36Sopenharmony_ci .nr_free_secs = 0 }; 168462306a36Sopenharmony_ci pgoff_t pg_start, pg_end; 168562306a36Sopenharmony_ci loff_t new_size; 168662306a36Sopenharmony_ci loff_t off_end; 168762306a36Sopenharmony_ci block_t expanded = 0; 168862306a36Sopenharmony_ci int err; 168962306a36Sopenharmony_ci 169062306a36Sopenharmony_ci err = inode_newsize_ok(inode, (len + offset)); 169162306a36Sopenharmony_ci if (err) 169262306a36Sopenharmony_ci return err; 169362306a36Sopenharmony_ci 169462306a36Sopenharmony_ci err = f2fs_convert_inline_inode(inode); 169562306a36Sopenharmony_ci if (err) 169662306a36Sopenharmony_ci return err; 169762306a36Sopenharmony_ci 169862306a36Sopenharmony_ci f2fs_balance_fs(sbi, true); 169962306a36Sopenharmony_ci 170062306a36Sopenharmony_ci pg_start = ((unsigned long long)offset) >> PAGE_SHIFT; 170162306a36Sopenharmony_ci pg_end = ((unsigned long long)offset + len) >> PAGE_SHIFT; 170262306a36Sopenharmony_ci off_end = (offset + len) & (PAGE_SIZE - 1); 170362306a36Sopenharmony_ci 170462306a36Sopenharmony_ci map.m_lblk = pg_start; 170562306a36Sopenharmony_ci map.m_len = pg_end - pg_start; 170662306a36Sopenharmony_ci if (off_end) 170762306a36Sopenharmony_ci map.m_len++; 170862306a36Sopenharmony_ci 170962306a36Sopenharmony_ci if (!map.m_len) 171062306a36Sopenharmony_ci return 0; 171162306a36Sopenharmony_ci 171262306a36Sopenharmony_ci if (f2fs_is_pinned_file(inode)) { 171362306a36Sopenharmony_ci block_t sec_blks = CAP_BLKS_PER_SEC(sbi); 171462306a36Sopenharmony_ci block_t sec_len = roundup(map.m_len, sec_blks); 171562306a36Sopenharmony_ci 171662306a36Sopenharmony_ci map.m_len = sec_blks; 171762306a36Sopenharmony_cinext_alloc: 171862306a36Sopenharmony_ci if (has_not_enough_free_secs(sbi, 0, 171962306a36Sopenharmony_ci GET_SEC_FROM_SEG(sbi, overprovision_segments(sbi)))) { 172062306a36Sopenharmony_ci f2fs_down_write(&sbi->gc_lock); 172162306a36Sopenharmony_ci stat_inc_gc_call_count(sbi, FOREGROUND); 172262306a36Sopenharmony_ci err = f2fs_gc(sbi, &gc_control); 172362306a36Sopenharmony_ci if (err && err != -ENODATA) 172462306a36Sopenharmony_ci goto out_err; 172562306a36Sopenharmony_ci } 172662306a36Sopenharmony_ci 172762306a36Sopenharmony_ci f2fs_down_write(&sbi->pin_sem); 172862306a36Sopenharmony_ci 172962306a36Sopenharmony_ci f2fs_lock_op(sbi); 173062306a36Sopenharmony_ci f2fs_allocate_new_section(sbi, CURSEG_COLD_DATA_PINNED, false); 173162306a36Sopenharmony_ci f2fs_unlock_op(sbi); 173262306a36Sopenharmony_ci 173362306a36Sopenharmony_ci map.m_seg_type = CURSEG_COLD_DATA_PINNED; 173462306a36Sopenharmony_ci err = f2fs_map_blocks(inode, &map, F2FS_GET_BLOCK_PRE_DIO); 173562306a36Sopenharmony_ci file_dont_truncate(inode); 173662306a36Sopenharmony_ci 173762306a36Sopenharmony_ci f2fs_up_write(&sbi->pin_sem); 173862306a36Sopenharmony_ci 173962306a36Sopenharmony_ci expanded += map.m_len; 174062306a36Sopenharmony_ci sec_len -= map.m_len; 174162306a36Sopenharmony_ci map.m_lblk += map.m_len; 174262306a36Sopenharmony_ci if (!err && sec_len) 174362306a36Sopenharmony_ci goto next_alloc; 174462306a36Sopenharmony_ci 174562306a36Sopenharmony_ci map.m_len = expanded; 174662306a36Sopenharmony_ci } else { 174762306a36Sopenharmony_ci err = f2fs_map_blocks(inode, &map, F2FS_GET_BLOCK_PRE_AIO); 174862306a36Sopenharmony_ci expanded = map.m_len; 174962306a36Sopenharmony_ci } 175062306a36Sopenharmony_ciout_err: 175162306a36Sopenharmony_ci if (err) { 175262306a36Sopenharmony_ci pgoff_t last_off; 175362306a36Sopenharmony_ci 175462306a36Sopenharmony_ci if (!expanded) 175562306a36Sopenharmony_ci return err; 175662306a36Sopenharmony_ci 175762306a36Sopenharmony_ci last_off = pg_start + expanded - 1; 175862306a36Sopenharmony_ci 175962306a36Sopenharmony_ci /* update new size to the failed position */ 176062306a36Sopenharmony_ci new_size = (last_off == pg_end) ? offset + len : 176162306a36Sopenharmony_ci (loff_t)(last_off + 1) << PAGE_SHIFT; 176262306a36Sopenharmony_ci } else { 176362306a36Sopenharmony_ci new_size = ((loff_t)pg_end << PAGE_SHIFT) + off_end; 176462306a36Sopenharmony_ci } 176562306a36Sopenharmony_ci 176662306a36Sopenharmony_ci if (new_size > i_size_read(inode)) { 176762306a36Sopenharmony_ci if (mode & FALLOC_FL_KEEP_SIZE) 176862306a36Sopenharmony_ci file_set_keep_isize(inode); 176962306a36Sopenharmony_ci else 177062306a36Sopenharmony_ci f2fs_i_size_write(inode, new_size); 177162306a36Sopenharmony_ci } 177262306a36Sopenharmony_ci 177362306a36Sopenharmony_ci return err; 177462306a36Sopenharmony_ci} 177562306a36Sopenharmony_ci 177662306a36Sopenharmony_cistatic long f2fs_fallocate(struct file *file, int mode, 177762306a36Sopenharmony_ci loff_t offset, loff_t len) 177862306a36Sopenharmony_ci{ 177962306a36Sopenharmony_ci struct inode *inode = file_inode(file); 178062306a36Sopenharmony_ci long ret = 0; 178162306a36Sopenharmony_ci 178262306a36Sopenharmony_ci if (unlikely(f2fs_cp_error(F2FS_I_SB(inode)))) 178362306a36Sopenharmony_ci return -EIO; 178462306a36Sopenharmony_ci if (!f2fs_is_checkpoint_ready(F2FS_I_SB(inode))) 178562306a36Sopenharmony_ci return -ENOSPC; 178662306a36Sopenharmony_ci if (!f2fs_is_compress_backend_ready(inode)) 178762306a36Sopenharmony_ci return -EOPNOTSUPP; 178862306a36Sopenharmony_ci 178962306a36Sopenharmony_ci /* f2fs only support ->fallocate for regular file */ 179062306a36Sopenharmony_ci if (!S_ISREG(inode->i_mode)) 179162306a36Sopenharmony_ci return -EINVAL; 179262306a36Sopenharmony_ci 179362306a36Sopenharmony_ci if (IS_ENCRYPTED(inode) && 179462306a36Sopenharmony_ci (mode & (FALLOC_FL_COLLAPSE_RANGE | FALLOC_FL_INSERT_RANGE))) 179562306a36Sopenharmony_ci return -EOPNOTSUPP; 179662306a36Sopenharmony_ci 179762306a36Sopenharmony_ci /* 179862306a36Sopenharmony_ci * Pinned file should not support partial truncation since the block 179962306a36Sopenharmony_ci * can be used by applications. 180062306a36Sopenharmony_ci */ 180162306a36Sopenharmony_ci if ((f2fs_compressed_file(inode) || f2fs_is_pinned_file(inode)) && 180262306a36Sopenharmony_ci (mode & (FALLOC_FL_PUNCH_HOLE | FALLOC_FL_COLLAPSE_RANGE | 180362306a36Sopenharmony_ci FALLOC_FL_ZERO_RANGE | FALLOC_FL_INSERT_RANGE))) 180462306a36Sopenharmony_ci return -EOPNOTSUPP; 180562306a36Sopenharmony_ci 180662306a36Sopenharmony_ci if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE | 180762306a36Sopenharmony_ci FALLOC_FL_COLLAPSE_RANGE | FALLOC_FL_ZERO_RANGE | 180862306a36Sopenharmony_ci FALLOC_FL_INSERT_RANGE)) 180962306a36Sopenharmony_ci return -EOPNOTSUPP; 181062306a36Sopenharmony_ci 181162306a36Sopenharmony_ci inode_lock(inode); 181262306a36Sopenharmony_ci 181362306a36Sopenharmony_ci ret = file_modified(file); 181462306a36Sopenharmony_ci if (ret) 181562306a36Sopenharmony_ci goto out; 181662306a36Sopenharmony_ci 181762306a36Sopenharmony_ci if (mode & FALLOC_FL_PUNCH_HOLE) { 181862306a36Sopenharmony_ci if (offset >= inode->i_size) 181962306a36Sopenharmony_ci goto out; 182062306a36Sopenharmony_ci 182162306a36Sopenharmony_ci ret = f2fs_punch_hole(inode, offset, len); 182262306a36Sopenharmony_ci } else if (mode & FALLOC_FL_COLLAPSE_RANGE) { 182362306a36Sopenharmony_ci ret = f2fs_collapse_range(inode, offset, len); 182462306a36Sopenharmony_ci } else if (mode & FALLOC_FL_ZERO_RANGE) { 182562306a36Sopenharmony_ci ret = f2fs_zero_range(inode, offset, len, mode); 182662306a36Sopenharmony_ci } else if (mode & FALLOC_FL_INSERT_RANGE) { 182762306a36Sopenharmony_ci ret = f2fs_insert_range(inode, offset, len); 182862306a36Sopenharmony_ci } else { 182962306a36Sopenharmony_ci ret = f2fs_expand_inode_data(inode, offset, len, mode); 183062306a36Sopenharmony_ci } 183162306a36Sopenharmony_ci 183262306a36Sopenharmony_ci if (!ret) { 183362306a36Sopenharmony_ci inode->i_mtime = inode_set_ctime_current(inode); 183462306a36Sopenharmony_ci f2fs_mark_inode_dirty_sync(inode, false); 183562306a36Sopenharmony_ci f2fs_update_time(F2FS_I_SB(inode), REQ_TIME); 183662306a36Sopenharmony_ci } 183762306a36Sopenharmony_ci 183862306a36Sopenharmony_ciout: 183962306a36Sopenharmony_ci inode_unlock(inode); 184062306a36Sopenharmony_ci 184162306a36Sopenharmony_ci trace_f2fs_fallocate(inode, mode, offset, len, ret); 184262306a36Sopenharmony_ci return ret; 184362306a36Sopenharmony_ci} 184462306a36Sopenharmony_ci 184562306a36Sopenharmony_cistatic int f2fs_release_file(struct inode *inode, struct file *filp) 184662306a36Sopenharmony_ci{ 184762306a36Sopenharmony_ci /* 184862306a36Sopenharmony_ci * f2fs_release_file is called at every close calls. So we should 184962306a36Sopenharmony_ci * not drop any inmemory pages by close called by other process. 185062306a36Sopenharmony_ci */ 185162306a36Sopenharmony_ci if (!(filp->f_mode & FMODE_WRITE) || 185262306a36Sopenharmony_ci atomic_read(&inode->i_writecount) != 1) 185362306a36Sopenharmony_ci return 0; 185462306a36Sopenharmony_ci 185562306a36Sopenharmony_ci inode_lock(inode); 185662306a36Sopenharmony_ci f2fs_abort_atomic_write(inode, true); 185762306a36Sopenharmony_ci inode_unlock(inode); 185862306a36Sopenharmony_ci 185962306a36Sopenharmony_ci return 0; 186062306a36Sopenharmony_ci} 186162306a36Sopenharmony_ci 186262306a36Sopenharmony_cistatic int f2fs_file_flush(struct file *file, fl_owner_t id) 186362306a36Sopenharmony_ci{ 186462306a36Sopenharmony_ci struct inode *inode = file_inode(file); 186562306a36Sopenharmony_ci 186662306a36Sopenharmony_ci /* 186762306a36Sopenharmony_ci * If the process doing a transaction is crashed, we should do 186862306a36Sopenharmony_ci * roll-back. Otherwise, other reader/write can see corrupted database 186962306a36Sopenharmony_ci * until all the writers close its file. Since this should be done 187062306a36Sopenharmony_ci * before dropping file lock, it needs to do in ->flush. 187162306a36Sopenharmony_ci */ 187262306a36Sopenharmony_ci if (F2FS_I(inode)->atomic_write_task == current && 187362306a36Sopenharmony_ci (current->flags & PF_EXITING)) { 187462306a36Sopenharmony_ci inode_lock(inode); 187562306a36Sopenharmony_ci f2fs_abort_atomic_write(inode, true); 187662306a36Sopenharmony_ci inode_unlock(inode); 187762306a36Sopenharmony_ci } 187862306a36Sopenharmony_ci 187962306a36Sopenharmony_ci return 0; 188062306a36Sopenharmony_ci} 188162306a36Sopenharmony_ci 188262306a36Sopenharmony_cistatic int f2fs_setflags_common(struct inode *inode, u32 iflags, u32 mask) 188362306a36Sopenharmony_ci{ 188462306a36Sopenharmony_ci struct f2fs_inode_info *fi = F2FS_I(inode); 188562306a36Sopenharmony_ci u32 masked_flags = fi->i_flags & mask; 188662306a36Sopenharmony_ci 188762306a36Sopenharmony_ci /* mask can be shrunk by flags_valid selector */ 188862306a36Sopenharmony_ci iflags &= mask; 188962306a36Sopenharmony_ci 189062306a36Sopenharmony_ci /* Is it quota file? Do not allow user to mess with it */ 189162306a36Sopenharmony_ci if (IS_NOQUOTA(inode)) 189262306a36Sopenharmony_ci return -EPERM; 189362306a36Sopenharmony_ci 189462306a36Sopenharmony_ci if ((iflags ^ masked_flags) & F2FS_CASEFOLD_FL) { 189562306a36Sopenharmony_ci if (!f2fs_sb_has_casefold(F2FS_I_SB(inode))) 189662306a36Sopenharmony_ci return -EOPNOTSUPP; 189762306a36Sopenharmony_ci if (!f2fs_empty_dir(inode)) 189862306a36Sopenharmony_ci return -ENOTEMPTY; 189962306a36Sopenharmony_ci } 190062306a36Sopenharmony_ci 190162306a36Sopenharmony_ci if (iflags & (F2FS_COMPR_FL | F2FS_NOCOMP_FL)) { 190262306a36Sopenharmony_ci if (!f2fs_sb_has_compression(F2FS_I_SB(inode))) 190362306a36Sopenharmony_ci return -EOPNOTSUPP; 190462306a36Sopenharmony_ci if ((iflags & F2FS_COMPR_FL) && (iflags & F2FS_NOCOMP_FL)) 190562306a36Sopenharmony_ci return -EINVAL; 190662306a36Sopenharmony_ci } 190762306a36Sopenharmony_ci 190862306a36Sopenharmony_ci if ((iflags ^ masked_flags) & F2FS_COMPR_FL) { 190962306a36Sopenharmony_ci if (masked_flags & F2FS_COMPR_FL) { 191062306a36Sopenharmony_ci if (!f2fs_disable_compressed_file(inode)) 191162306a36Sopenharmony_ci return -EINVAL; 191262306a36Sopenharmony_ci } else { 191362306a36Sopenharmony_ci /* try to convert inline_data to support compression */ 191462306a36Sopenharmony_ci int err = f2fs_convert_inline_inode(inode); 191562306a36Sopenharmony_ci if (err) 191662306a36Sopenharmony_ci return err; 191762306a36Sopenharmony_ci 191862306a36Sopenharmony_ci f2fs_down_write(&F2FS_I(inode)->i_sem); 191962306a36Sopenharmony_ci if (!f2fs_may_compress(inode) || 192062306a36Sopenharmony_ci (S_ISREG(inode->i_mode) && 192162306a36Sopenharmony_ci F2FS_HAS_BLOCKS(inode))) { 192262306a36Sopenharmony_ci f2fs_up_write(&F2FS_I(inode)->i_sem); 192362306a36Sopenharmony_ci return -EINVAL; 192462306a36Sopenharmony_ci } 192562306a36Sopenharmony_ci err = set_compress_context(inode); 192662306a36Sopenharmony_ci f2fs_up_write(&F2FS_I(inode)->i_sem); 192762306a36Sopenharmony_ci 192862306a36Sopenharmony_ci if (err) 192962306a36Sopenharmony_ci return err; 193062306a36Sopenharmony_ci } 193162306a36Sopenharmony_ci } 193262306a36Sopenharmony_ci 193362306a36Sopenharmony_ci fi->i_flags = iflags | (fi->i_flags & ~mask); 193462306a36Sopenharmony_ci f2fs_bug_on(F2FS_I_SB(inode), (fi->i_flags & F2FS_COMPR_FL) && 193562306a36Sopenharmony_ci (fi->i_flags & F2FS_NOCOMP_FL)); 193662306a36Sopenharmony_ci 193762306a36Sopenharmony_ci if (fi->i_flags & F2FS_PROJINHERIT_FL) 193862306a36Sopenharmony_ci set_inode_flag(inode, FI_PROJ_INHERIT); 193962306a36Sopenharmony_ci else 194062306a36Sopenharmony_ci clear_inode_flag(inode, FI_PROJ_INHERIT); 194162306a36Sopenharmony_ci 194262306a36Sopenharmony_ci inode_set_ctime_current(inode); 194362306a36Sopenharmony_ci f2fs_set_inode_flags(inode); 194462306a36Sopenharmony_ci f2fs_mark_inode_dirty_sync(inode, true); 194562306a36Sopenharmony_ci return 0; 194662306a36Sopenharmony_ci} 194762306a36Sopenharmony_ci 194862306a36Sopenharmony_ci/* FS_IOC_[GS]ETFLAGS and FS_IOC_FS[GS]ETXATTR support */ 194962306a36Sopenharmony_ci 195062306a36Sopenharmony_ci/* 195162306a36Sopenharmony_ci * To make a new on-disk f2fs i_flag gettable via FS_IOC_GETFLAGS, add an entry 195262306a36Sopenharmony_ci * for it to f2fs_fsflags_map[], and add its FS_*_FL equivalent to 195362306a36Sopenharmony_ci * F2FS_GETTABLE_FS_FL. To also make it settable via FS_IOC_SETFLAGS, also add 195462306a36Sopenharmony_ci * its FS_*_FL equivalent to F2FS_SETTABLE_FS_FL. 195562306a36Sopenharmony_ci * 195662306a36Sopenharmony_ci * Translating flags to fsx_flags value used by FS_IOC_FSGETXATTR and 195762306a36Sopenharmony_ci * FS_IOC_FSSETXATTR is done by the VFS. 195862306a36Sopenharmony_ci */ 195962306a36Sopenharmony_ci 196062306a36Sopenharmony_cistatic const struct { 196162306a36Sopenharmony_ci u32 iflag; 196262306a36Sopenharmony_ci u32 fsflag; 196362306a36Sopenharmony_ci} f2fs_fsflags_map[] = { 196462306a36Sopenharmony_ci { F2FS_COMPR_FL, FS_COMPR_FL }, 196562306a36Sopenharmony_ci { F2FS_SYNC_FL, FS_SYNC_FL }, 196662306a36Sopenharmony_ci { F2FS_IMMUTABLE_FL, FS_IMMUTABLE_FL }, 196762306a36Sopenharmony_ci { F2FS_APPEND_FL, FS_APPEND_FL }, 196862306a36Sopenharmony_ci { F2FS_NODUMP_FL, FS_NODUMP_FL }, 196962306a36Sopenharmony_ci { F2FS_NOATIME_FL, FS_NOATIME_FL }, 197062306a36Sopenharmony_ci { F2FS_NOCOMP_FL, FS_NOCOMP_FL }, 197162306a36Sopenharmony_ci { F2FS_INDEX_FL, FS_INDEX_FL }, 197262306a36Sopenharmony_ci { F2FS_DIRSYNC_FL, FS_DIRSYNC_FL }, 197362306a36Sopenharmony_ci { F2FS_PROJINHERIT_FL, FS_PROJINHERIT_FL }, 197462306a36Sopenharmony_ci { F2FS_CASEFOLD_FL, FS_CASEFOLD_FL }, 197562306a36Sopenharmony_ci}; 197662306a36Sopenharmony_ci 197762306a36Sopenharmony_ci#define F2FS_GETTABLE_FS_FL ( \ 197862306a36Sopenharmony_ci FS_COMPR_FL | \ 197962306a36Sopenharmony_ci FS_SYNC_FL | \ 198062306a36Sopenharmony_ci FS_IMMUTABLE_FL | \ 198162306a36Sopenharmony_ci FS_APPEND_FL | \ 198262306a36Sopenharmony_ci FS_NODUMP_FL | \ 198362306a36Sopenharmony_ci FS_NOATIME_FL | \ 198462306a36Sopenharmony_ci FS_NOCOMP_FL | \ 198562306a36Sopenharmony_ci FS_INDEX_FL | \ 198662306a36Sopenharmony_ci FS_DIRSYNC_FL | \ 198762306a36Sopenharmony_ci FS_PROJINHERIT_FL | \ 198862306a36Sopenharmony_ci FS_ENCRYPT_FL | \ 198962306a36Sopenharmony_ci FS_INLINE_DATA_FL | \ 199062306a36Sopenharmony_ci FS_NOCOW_FL | \ 199162306a36Sopenharmony_ci FS_VERITY_FL | \ 199262306a36Sopenharmony_ci FS_CASEFOLD_FL) 199362306a36Sopenharmony_ci 199462306a36Sopenharmony_ci#define F2FS_SETTABLE_FS_FL ( \ 199562306a36Sopenharmony_ci FS_COMPR_FL | \ 199662306a36Sopenharmony_ci FS_SYNC_FL | \ 199762306a36Sopenharmony_ci FS_IMMUTABLE_FL | \ 199862306a36Sopenharmony_ci FS_APPEND_FL | \ 199962306a36Sopenharmony_ci FS_NODUMP_FL | \ 200062306a36Sopenharmony_ci FS_NOATIME_FL | \ 200162306a36Sopenharmony_ci FS_NOCOMP_FL | \ 200262306a36Sopenharmony_ci FS_DIRSYNC_FL | \ 200362306a36Sopenharmony_ci FS_PROJINHERIT_FL | \ 200462306a36Sopenharmony_ci FS_CASEFOLD_FL) 200562306a36Sopenharmony_ci 200662306a36Sopenharmony_ci/* Convert f2fs on-disk i_flags to FS_IOC_{GET,SET}FLAGS flags */ 200762306a36Sopenharmony_cistatic inline u32 f2fs_iflags_to_fsflags(u32 iflags) 200862306a36Sopenharmony_ci{ 200962306a36Sopenharmony_ci u32 fsflags = 0; 201062306a36Sopenharmony_ci int i; 201162306a36Sopenharmony_ci 201262306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(f2fs_fsflags_map); i++) 201362306a36Sopenharmony_ci if (iflags & f2fs_fsflags_map[i].iflag) 201462306a36Sopenharmony_ci fsflags |= f2fs_fsflags_map[i].fsflag; 201562306a36Sopenharmony_ci 201662306a36Sopenharmony_ci return fsflags; 201762306a36Sopenharmony_ci} 201862306a36Sopenharmony_ci 201962306a36Sopenharmony_ci/* Convert FS_IOC_{GET,SET}FLAGS flags to f2fs on-disk i_flags */ 202062306a36Sopenharmony_cistatic inline u32 f2fs_fsflags_to_iflags(u32 fsflags) 202162306a36Sopenharmony_ci{ 202262306a36Sopenharmony_ci u32 iflags = 0; 202362306a36Sopenharmony_ci int i; 202462306a36Sopenharmony_ci 202562306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(f2fs_fsflags_map); i++) 202662306a36Sopenharmony_ci if (fsflags & f2fs_fsflags_map[i].fsflag) 202762306a36Sopenharmony_ci iflags |= f2fs_fsflags_map[i].iflag; 202862306a36Sopenharmony_ci 202962306a36Sopenharmony_ci return iflags; 203062306a36Sopenharmony_ci} 203162306a36Sopenharmony_ci 203262306a36Sopenharmony_cistatic int f2fs_ioc_getversion(struct file *filp, unsigned long arg) 203362306a36Sopenharmony_ci{ 203462306a36Sopenharmony_ci struct inode *inode = file_inode(filp); 203562306a36Sopenharmony_ci 203662306a36Sopenharmony_ci return put_user(inode->i_generation, (int __user *)arg); 203762306a36Sopenharmony_ci} 203862306a36Sopenharmony_ci 203962306a36Sopenharmony_cistatic int f2fs_ioc_start_atomic_write(struct file *filp, bool truncate) 204062306a36Sopenharmony_ci{ 204162306a36Sopenharmony_ci struct inode *inode = file_inode(filp); 204262306a36Sopenharmony_ci struct mnt_idmap *idmap = file_mnt_idmap(filp); 204362306a36Sopenharmony_ci struct f2fs_inode_info *fi = F2FS_I(inode); 204462306a36Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_I_SB(inode); 204562306a36Sopenharmony_ci struct inode *pinode; 204662306a36Sopenharmony_ci loff_t isize; 204762306a36Sopenharmony_ci int ret; 204862306a36Sopenharmony_ci 204962306a36Sopenharmony_ci if (!inode_owner_or_capable(idmap, inode)) 205062306a36Sopenharmony_ci return -EACCES; 205162306a36Sopenharmony_ci 205262306a36Sopenharmony_ci if (!S_ISREG(inode->i_mode)) 205362306a36Sopenharmony_ci return -EINVAL; 205462306a36Sopenharmony_ci 205562306a36Sopenharmony_ci if (filp->f_flags & O_DIRECT) 205662306a36Sopenharmony_ci return -EINVAL; 205762306a36Sopenharmony_ci 205862306a36Sopenharmony_ci ret = mnt_want_write_file(filp); 205962306a36Sopenharmony_ci if (ret) 206062306a36Sopenharmony_ci return ret; 206162306a36Sopenharmony_ci 206262306a36Sopenharmony_ci inode_lock(inode); 206362306a36Sopenharmony_ci 206462306a36Sopenharmony_ci if (!f2fs_disable_compressed_file(inode)) { 206562306a36Sopenharmony_ci ret = -EINVAL; 206662306a36Sopenharmony_ci goto out; 206762306a36Sopenharmony_ci } 206862306a36Sopenharmony_ci 206962306a36Sopenharmony_ci if (f2fs_is_atomic_file(inode)) 207062306a36Sopenharmony_ci goto out; 207162306a36Sopenharmony_ci 207262306a36Sopenharmony_ci ret = f2fs_convert_inline_inode(inode); 207362306a36Sopenharmony_ci if (ret) 207462306a36Sopenharmony_ci goto out; 207562306a36Sopenharmony_ci 207662306a36Sopenharmony_ci f2fs_down_write(&fi->i_gc_rwsem[WRITE]); 207762306a36Sopenharmony_ci 207862306a36Sopenharmony_ci /* 207962306a36Sopenharmony_ci * Should wait end_io to count F2FS_WB_CP_DATA correctly by 208062306a36Sopenharmony_ci * f2fs_is_atomic_file. 208162306a36Sopenharmony_ci */ 208262306a36Sopenharmony_ci if (get_dirty_pages(inode)) 208362306a36Sopenharmony_ci f2fs_warn(sbi, "Unexpected flush for atomic writes: ino=%lu, npages=%u", 208462306a36Sopenharmony_ci inode->i_ino, get_dirty_pages(inode)); 208562306a36Sopenharmony_ci ret = filemap_write_and_wait_range(inode->i_mapping, 0, LLONG_MAX); 208662306a36Sopenharmony_ci if (ret) { 208762306a36Sopenharmony_ci f2fs_up_write(&fi->i_gc_rwsem[WRITE]); 208862306a36Sopenharmony_ci goto out; 208962306a36Sopenharmony_ci } 209062306a36Sopenharmony_ci 209162306a36Sopenharmony_ci /* Check if the inode already has a COW inode */ 209262306a36Sopenharmony_ci if (fi->cow_inode == NULL) { 209362306a36Sopenharmony_ci /* Create a COW inode for atomic write */ 209462306a36Sopenharmony_ci pinode = f2fs_iget(inode->i_sb, fi->i_pino); 209562306a36Sopenharmony_ci if (IS_ERR(pinode)) { 209662306a36Sopenharmony_ci f2fs_up_write(&fi->i_gc_rwsem[WRITE]); 209762306a36Sopenharmony_ci ret = PTR_ERR(pinode); 209862306a36Sopenharmony_ci goto out; 209962306a36Sopenharmony_ci } 210062306a36Sopenharmony_ci 210162306a36Sopenharmony_ci ret = f2fs_get_tmpfile(idmap, pinode, &fi->cow_inode); 210262306a36Sopenharmony_ci iput(pinode); 210362306a36Sopenharmony_ci if (ret) { 210462306a36Sopenharmony_ci f2fs_up_write(&fi->i_gc_rwsem[WRITE]); 210562306a36Sopenharmony_ci goto out; 210662306a36Sopenharmony_ci } 210762306a36Sopenharmony_ci 210862306a36Sopenharmony_ci set_inode_flag(fi->cow_inode, FI_COW_FILE); 210962306a36Sopenharmony_ci clear_inode_flag(fi->cow_inode, FI_INLINE_DATA); 211062306a36Sopenharmony_ci } else { 211162306a36Sopenharmony_ci /* Reuse the already created COW inode */ 211262306a36Sopenharmony_ci ret = f2fs_do_truncate_blocks(fi->cow_inode, 0, true); 211362306a36Sopenharmony_ci if (ret) { 211462306a36Sopenharmony_ci f2fs_up_write(&fi->i_gc_rwsem[WRITE]); 211562306a36Sopenharmony_ci goto out; 211662306a36Sopenharmony_ci } 211762306a36Sopenharmony_ci } 211862306a36Sopenharmony_ci 211962306a36Sopenharmony_ci f2fs_write_inode(inode, NULL); 212062306a36Sopenharmony_ci 212162306a36Sopenharmony_ci stat_inc_atomic_inode(inode); 212262306a36Sopenharmony_ci 212362306a36Sopenharmony_ci set_inode_flag(inode, FI_ATOMIC_FILE); 212462306a36Sopenharmony_ci 212562306a36Sopenharmony_ci isize = i_size_read(inode); 212662306a36Sopenharmony_ci fi->original_i_size = isize; 212762306a36Sopenharmony_ci if (truncate) { 212862306a36Sopenharmony_ci set_inode_flag(inode, FI_ATOMIC_REPLACE); 212962306a36Sopenharmony_ci truncate_inode_pages_final(inode->i_mapping); 213062306a36Sopenharmony_ci f2fs_i_size_write(inode, 0); 213162306a36Sopenharmony_ci isize = 0; 213262306a36Sopenharmony_ci } 213362306a36Sopenharmony_ci f2fs_i_size_write(fi->cow_inode, isize); 213462306a36Sopenharmony_ci 213562306a36Sopenharmony_ci f2fs_up_write(&fi->i_gc_rwsem[WRITE]); 213662306a36Sopenharmony_ci 213762306a36Sopenharmony_ci f2fs_update_time(sbi, REQ_TIME); 213862306a36Sopenharmony_ci fi->atomic_write_task = current; 213962306a36Sopenharmony_ci stat_update_max_atomic_write(inode); 214062306a36Sopenharmony_ci fi->atomic_write_cnt = 0; 214162306a36Sopenharmony_ciout: 214262306a36Sopenharmony_ci inode_unlock(inode); 214362306a36Sopenharmony_ci mnt_drop_write_file(filp); 214462306a36Sopenharmony_ci return ret; 214562306a36Sopenharmony_ci} 214662306a36Sopenharmony_ci 214762306a36Sopenharmony_cistatic int f2fs_ioc_commit_atomic_write(struct file *filp) 214862306a36Sopenharmony_ci{ 214962306a36Sopenharmony_ci struct inode *inode = file_inode(filp); 215062306a36Sopenharmony_ci struct mnt_idmap *idmap = file_mnt_idmap(filp); 215162306a36Sopenharmony_ci int ret; 215262306a36Sopenharmony_ci 215362306a36Sopenharmony_ci if (!inode_owner_or_capable(idmap, inode)) 215462306a36Sopenharmony_ci return -EACCES; 215562306a36Sopenharmony_ci 215662306a36Sopenharmony_ci ret = mnt_want_write_file(filp); 215762306a36Sopenharmony_ci if (ret) 215862306a36Sopenharmony_ci return ret; 215962306a36Sopenharmony_ci 216062306a36Sopenharmony_ci f2fs_balance_fs(F2FS_I_SB(inode), true); 216162306a36Sopenharmony_ci 216262306a36Sopenharmony_ci inode_lock(inode); 216362306a36Sopenharmony_ci 216462306a36Sopenharmony_ci if (f2fs_is_atomic_file(inode)) { 216562306a36Sopenharmony_ci ret = f2fs_commit_atomic_write(inode); 216662306a36Sopenharmony_ci if (!ret) 216762306a36Sopenharmony_ci ret = f2fs_do_sync_file(filp, 0, LLONG_MAX, 0, true); 216862306a36Sopenharmony_ci 216962306a36Sopenharmony_ci f2fs_abort_atomic_write(inode, ret); 217062306a36Sopenharmony_ci } else { 217162306a36Sopenharmony_ci ret = f2fs_do_sync_file(filp, 0, LLONG_MAX, 1, false); 217262306a36Sopenharmony_ci } 217362306a36Sopenharmony_ci 217462306a36Sopenharmony_ci inode_unlock(inode); 217562306a36Sopenharmony_ci mnt_drop_write_file(filp); 217662306a36Sopenharmony_ci return ret; 217762306a36Sopenharmony_ci} 217862306a36Sopenharmony_ci 217962306a36Sopenharmony_cistatic int f2fs_ioc_abort_atomic_write(struct file *filp) 218062306a36Sopenharmony_ci{ 218162306a36Sopenharmony_ci struct inode *inode = file_inode(filp); 218262306a36Sopenharmony_ci struct mnt_idmap *idmap = file_mnt_idmap(filp); 218362306a36Sopenharmony_ci int ret; 218462306a36Sopenharmony_ci 218562306a36Sopenharmony_ci if (!inode_owner_or_capable(idmap, inode)) 218662306a36Sopenharmony_ci return -EACCES; 218762306a36Sopenharmony_ci 218862306a36Sopenharmony_ci ret = mnt_want_write_file(filp); 218962306a36Sopenharmony_ci if (ret) 219062306a36Sopenharmony_ci return ret; 219162306a36Sopenharmony_ci 219262306a36Sopenharmony_ci inode_lock(inode); 219362306a36Sopenharmony_ci 219462306a36Sopenharmony_ci f2fs_abort_atomic_write(inode, true); 219562306a36Sopenharmony_ci 219662306a36Sopenharmony_ci inode_unlock(inode); 219762306a36Sopenharmony_ci 219862306a36Sopenharmony_ci mnt_drop_write_file(filp); 219962306a36Sopenharmony_ci f2fs_update_time(F2FS_I_SB(inode), REQ_TIME); 220062306a36Sopenharmony_ci return ret; 220162306a36Sopenharmony_ci} 220262306a36Sopenharmony_ci 220362306a36Sopenharmony_cistatic int f2fs_ioc_shutdown(struct file *filp, unsigned long arg) 220462306a36Sopenharmony_ci{ 220562306a36Sopenharmony_ci struct inode *inode = file_inode(filp); 220662306a36Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_I_SB(inode); 220762306a36Sopenharmony_ci struct super_block *sb = sbi->sb; 220862306a36Sopenharmony_ci __u32 in; 220962306a36Sopenharmony_ci int ret = 0; 221062306a36Sopenharmony_ci 221162306a36Sopenharmony_ci if (!capable(CAP_SYS_ADMIN)) 221262306a36Sopenharmony_ci return -EPERM; 221362306a36Sopenharmony_ci 221462306a36Sopenharmony_ci if (get_user(in, (__u32 __user *)arg)) 221562306a36Sopenharmony_ci return -EFAULT; 221662306a36Sopenharmony_ci 221762306a36Sopenharmony_ci if (in != F2FS_GOING_DOWN_FULLSYNC) { 221862306a36Sopenharmony_ci ret = mnt_want_write_file(filp); 221962306a36Sopenharmony_ci if (ret) { 222062306a36Sopenharmony_ci if (ret == -EROFS) { 222162306a36Sopenharmony_ci ret = 0; 222262306a36Sopenharmony_ci f2fs_stop_checkpoint(sbi, false, 222362306a36Sopenharmony_ci STOP_CP_REASON_SHUTDOWN); 222462306a36Sopenharmony_ci trace_f2fs_shutdown(sbi, in, ret); 222562306a36Sopenharmony_ci } 222662306a36Sopenharmony_ci return ret; 222762306a36Sopenharmony_ci } 222862306a36Sopenharmony_ci } 222962306a36Sopenharmony_ci 223062306a36Sopenharmony_ci switch (in) { 223162306a36Sopenharmony_ci case F2FS_GOING_DOWN_FULLSYNC: 223262306a36Sopenharmony_ci ret = freeze_bdev(sb->s_bdev); 223362306a36Sopenharmony_ci if (ret) 223462306a36Sopenharmony_ci goto out; 223562306a36Sopenharmony_ci f2fs_stop_checkpoint(sbi, false, STOP_CP_REASON_SHUTDOWN); 223662306a36Sopenharmony_ci thaw_bdev(sb->s_bdev); 223762306a36Sopenharmony_ci break; 223862306a36Sopenharmony_ci case F2FS_GOING_DOWN_METASYNC: 223962306a36Sopenharmony_ci /* do checkpoint only */ 224062306a36Sopenharmony_ci ret = f2fs_sync_fs(sb, 1); 224162306a36Sopenharmony_ci if (ret) 224262306a36Sopenharmony_ci goto out; 224362306a36Sopenharmony_ci f2fs_stop_checkpoint(sbi, false, STOP_CP_REASON_SHUTDOWN); 224462306a36Sopenharmony_ci break; 224562306a36Sopenharmony_ci case F2FS_GOING_DOWN_NOSYNC: 224662306a36Sopenharmony_ci f2fs_stop_checkpoint(sbi, false, STOP_CP_REASON_SHUTDOWN); 224762306a36Sopenharmony_ci break; 224862306a36Sopenharmony_ci case F2FS_GOING_DOWN_METAFLUSH: 224962306a36Sopenharmony_ci f2fs_sync_meta_pages(sbi, META, LONG_MAX, FS_META_IO); 225062306a36Sopenharmony_ci f2fs_stop_checkpoint(sbi, false, STOP_CP_REASON_SHUTDOWN); 225162306a36Sopenharmony_ci break; 225262306a36Sopenharmony_ci case F2FS_GOING_DOWN_NEED_FSCK: 225362306a36Sopenharmony_ci set_sbi_flag(sbi, SBI_NEED_FSCK); 225462306a36Sopenharmony_ci set_sbi_flag(sbi, SBI_CP_DISABLED_QUICK); 225562306a36Sopenharmony_ci set_sbi_flag(sbi, SBI_IS_DIRTY); 225662306a36Sopenharmony_ci /* do checkpoint only */ 225762306a36Sopenharmony_ci ret = f2fs_sync_fs(sb, 1); 225862306a36Sopenharmony_ci goto out; 225962306a36Sopenharmony_ci default: 226062306a36Sopenharmony_ci ret = -EINVAL; 226162306a36Sopenharmony_ci goto out; 226262306a36Sopenharmony_ci } 226362306a36Sopenharmony_ci 226462306a36Sopenharmony_ci f2fs_stop_gc_thread(sbi); 226562306a36Sopenharmony_ci f2fs_stop_discard_thread(sbi); 226662306a36Sopenharmony_ci 226762306a36Sopenharmony_ci f2fs_drop_discard_cmd(sbi); 226862306a36Sopenharmony_ci clear_opt(sbi, DISCARD); 226962306a36Sopenharmony_ci 227062306a36Sopenharmony_ci f2fs_update_time(sbi, REQ_TIME); 227162306a36Sopenharmony_ciout: 227262306a36Sopenharmony_ci if (in != F2FS_GOING_DOWN_FULLSYNC) 227362306a36Sopenharmony_ci mnt_drop_write_file(filp); 227462306a36Sopenharmony_ci 227562306a36Sopenharmony_ci trace_f2fs_shutdown(sbi, in, ret); 227662306a36Sopenharmony_ci 227762306a36Sopenharmony_ci return ret; 227862306a36Sopenharmony_ci} 227962306a36Sopenharmony_ci 228062306a36Sopenharmony_cistatic int f2fs_ioc_fitrim(struct file *filp, unsigned long arg) 228162306a36Sopenharmony_ci{ 228262306a36Sopenharmony_ci struct inode *inode = file_inode(filp); 228362306a36Sopenharmony_ci struct super_block *sb = inode->i_sb; 228462306a36Sopenharmony_ci struct fstrim_range range; 228562306a36Sopenharmony_ci int ret; 228662306a36Sopenharmony_ci 228762306a36Sopenharmony_ci if (!capable(CAP_SYS_ADMIN)) 228862306a36Sopenharmony_ci return -EPERM; 228962306a36Sopenharmony_ci 229062306a36Sopenharmony_ci if (!f2fs_hw_support_discard(F2FS_SB(sb))) 229162306a36Sopenharmony_ci return -EOPNOTSUPP; 229262306a36Sopenharmony_ci 229362306a36Sopenharmony_ci if (copy_from_user(&range, (struct fstrim_range __user *)arg, 229462306a36Sopenharmony_ci sizeof(range))) 229562306a36Sopenharmony_ci return -EFAULT; 229662306a36Sopenharmony_ci 229762306a36Sopenharmony_ci ret = mnt_want_write_file(filp); 229862306a36Sopenharmony_ci if (ret) 229962306a36Sopenharmony_ci return ret; 230062306a36Sopenharmony_ci 230162306a36Sopenharmony_ci range.minlen = max((unsigned int)range.minlen, 230262306a36Sopenharmony_ci bdev_discard_granularity(sb->s_bdev)); 230362306a36Sopenharmony_ci ret = f2fs_trim_fs(F2FS_SB(sb), &range); 230462306a36Sopenharmony_ci mnt_drop_write_file(filp); 230562306a36Sopenharmony_ci if (ret < 0) 230662306a36Sopenharmony_ci return ret; 230762306a36Sopenharmony_ci 230862306a36Sopenharmony_ci if (copy_to_user((struct fstrim_range __user *)arg, &range, 230962306a36Sopenharmony_ci sizeof(range))) 231062306a36Sopenharmony_ci return -EFAULT; 231162306a36Sopenharmony_ci f2fs_update_time(F2FS_I_SB(inode), REQ_TIME); 231262306a36Sopenharmony_ci return 0; 231362306a36Sopenharmony_ci} 231462306a36Sopenharmony_ci 231562306a36Sopenharmony_cistatic bool uuid_is_nonzero(__u8 u[16]) 231662306a36Sopenharmony_ci{ 231762306a36Sopenharmony_ci int i; 231862306a36Sopenharmony_ci 231962306a36Sopenharmony_ci for (i = 0; i < 16; i++) 232062306a36Sopenharmony_ci if (u[i]) 232162306a36Sopenharmony_ci return true; 232262306a36Sopenharmony_ci return false; 232362306a36Sopenharmony_ci} 232462306a36Sopenharmony_ci 232562306a36Sopenharmony_cistatic int f2fs_ioc_set_encryption_policy(struct file *filp, unsigned long arg) 232662306a36Sopenharmony_ci{ 232762306a36Sopenharmony_ci struct inode *inode = file_inode(filp); 232862306a36Sopenharmony_ci 232962306a36Sopenharmony_ci if (!f2fs_sb_has_encrypt(F2FS_I_SB(inode))) 233062306a36Sopenharmony_ci return -EOPNOTSUPP; 233162306a36Sopenharmony_ci 233262306a36Sopenharmony_ci f2fs_update_time(F2FS_I_SB(inode), REQ_TIME); 233362306a36Sopenharmony_ci 233462306a36Sopenharmony_ci return fscrypt_ioctl_set_policy(filp, (const void __user *)arg); 233562306a36Sopenharmony_ci} 233662306a36Sopenharmony_ci 233762306a36Sopenharmony_cistatic int f2fs_ioc_get_encryption_policy(struct file *filp, unsigned long arg) 233862306a36Sopenharmony_ci{ 233962306a36Sopenharmony_ci if (!f2fs_sb_has_encrypt(F2FS_I_SB(file_inode(filp)))) 234062306a36Sopenharmony_ci return -EOPNOTSUPP; 234162306a36Sopenharmony_ci return fscrypt_ioctl_get_policy(filp, (void __user *)arg); 234262306a36Sopenharmony_ci} 234362306a36Sopenharmony_ci 234462306a36Sopenharmony_cistatic int f2fs_ioc_get_encryption_pwsalt(struct file *filp, unsigned long arg) 234562306a36Sopenharmony_ci{ 234662306a36Sopenharmony_ci struct inode *inode = file_inode(filp); 234762306a36Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_I_SB(inode); 234862306a36Sopenharmony_ci u8 encrypt_pw_salt[16]; 234962306a36Sopenharmony_ci int err; 235062306a36Sopenharmony_ci 235162306a36Sopenharmony_ci if (!f2fs_sb_has_encrypt(sbi)) 235262306a36Sopenharmony_ci return -EOPNOTSUPP; 235362306a36Sopenharmony_ci 235462306a36Sopenharmony_ci err = mnt_want_write_file(filp); 235562306a36Sopenharmony_ci if (err) 235662306a36Sopenharmony_ci return err; 235762306a36Sopenharmony_ci 235862306a36Sopenharmony_ci f2fs_down_write(&sbi->sb_lock); 235962306a36Sopenharmony_ci 236062306a36Sopenharmony_ci if (uuid_is_nonzero(sbi->raw_super->encrypt_pw_salt)) 236162306a36Sopenharmony_ci goto got_it; 236262306a36Sopenharmony_ci 236362306a36Sopenharmony_ci /* update superblock with uuid */ 236462306a36Sopenharmony_ci generate_random_uuid(sbi->raw_super->encrypt_pw_salt); 236562306a36Sopenharmony_ci 236662306a36Sopenharmony_ci err = f2fs_commit_super(sbi, false); 236762306a36Sopenharmony_ci if (err) { 236862306a36Sopenharmony_ci /* undo new data */ 236962306a36Sopenharmony_ci memset(sbi->raw_super->encrypt_pw_salt, 0, 16); 237062306a36Sopenharmony_ci goto out_err; 237162306a36Sopenharmony_ci } 237262306a36Sopenharmony_cigot_it: 237362306a36Sopenharmony_ci memcpy(encrypt_pw_salt, sbi->raw_super->encrypt_pw_salt, 16); 237462306a36Sopenharmony_ciout_err: 237562306a36Sopenharmony_ci f2fs_up_write(&sbi->sb_lock); 237662306a36Sopenharmony_ci mnt_drop_write_file(filp); 237762306a36Sopenharmony_ci 237862306a36Sopenharmony_ci if (!err && copy_to_user((__u8 __user *)arg, encrypt_pw_salt, 16)) 237962306a36Sopenharmony_ci err = -EFAULT; 238062306a36Sopenharmony_ci 238162306a36Sopenharmony_ci return err; 238262306a36Sopenharmony_ci} 238362306a36Sopenharmony_ci 238462306a36Sopenharmony_cistatic int f2fs_ioc_get_encryption_policy_ex(struct file *filp, 238562306a36Sopenharmony_ci unsigned long arg) 238662306a36Sopenharmony_ci{ 238762306a36Sopenharmony_ci if (!f2fs_sb_has_encrypt(F2FS_I_SB(file_inode(filp)))) 238862306a36Sopenharmony_ci return -EOPNOTSUPP; 238962306a36Sopenharmony_ci 239062306a36Sopenharmony_ci return fscrypt_ioctl_get_policy_ex(filp, (void __user *)arg); 239162306a36Sopenharmony_ci} 239262306a36Sopenharmony_ci 239362306a36Sopenharmony_cistatic int f2fs_ioc_add_encryption_key(struct file *filp, unsigned long arg) 239462306a36Sopenharmony_ci{ 239562306a36Sopenharmony_ci if (!f2fs_sb_has_encrypt(F2FS_I_SB(file_inode(filp)))) 239662306a36Sopenharmony_ci return -EOPNOTSUPP; 239762306a36Sopenharmony_ci 239862306a36Sopenharmony_ci return fscrypt_ioctl_add_key(filp, (void __user *)arg); 239962306a36Sopenharmony_ci} 240062306a36Sopenharmony_ci 240162306a36Sopenharmony_cistatic int f2fs_ioc_remove_encryption_key(struct file *filp, unsigned long arg) 240262306a36Sopenharmony_ci{ 240362306a36Sopenharmony_ci if (!f2fs_sb_has_encrypt(F2FS_I_SB(file_inode(filp)))) 240462306a36Sopenharmony_ci return -EOPNOTSUPP; 240562306a36Sopenharmony_ci 240662306a36Sopenharmony_ci return fscrypt_ioctl_remove_key(filp, (void __user *)arg); 240762306a36Sopenharmony_ci} 240862306a36Sopenharmony_ci 240962306a36Sopenharmony_cistatic int f2fs_ioc_remove_encryption_key_all_users(struct file *filp, 241062306a36Sopenharmony_ci unsigned long arg) 241162306a36Sopenharmony_ci{ 241262306a36Sopenharmony_ci if (!f2fs_sb_has_encrypt(F2FS_I_SB(file_inode(filp)))) 241362306a36Sopenharmony_ci return -EOPNOTSUPP; 241462306a36Sopenharmony_ci 241562306a36Sopenharmony_ci return fscrypt_ioctl_remove_key_all_users(filp, (void __user *)arg); 241662306a36Sopenharmony_ci} 241762306a36Sopenharmony_ci 241862306a36Sopenharmony_cistatic int f2fs_ioc_get_encryption_key_status(struct file *filp, 241962306a36Sopenharmony_ci unsigned long arg) 242062306a36Sopenharmony_ci{ 242162306a36Sopenharmony_ci if (!f2fs_sb_has_encrypt(F2FS_I_SB(file_inode(filp)))) 242262306a36Sopenharmony_ci return -EOPNOTSUPP; 242362306a36Sopenharmony_ci 242462306a36Sopenharmony_ci return fscrypt_ioctl_get_key_status(filp, (void __user *)arg); 242562306a36Sopenharmony_ci} 242662306a36Sopenharmony_ci 242762306a36Sopenharmony_cistatic int f2fs_ioc_get_encryption_nonce(struct file *filp, unsigned long arg) 242862306a36Sopenharmony_ci{ 242962306a36Sopenharmony_ci if (!f2fs_sb_has_encrypt(F2FS_I_SB(file_inode(filp)))) 243062306a36Sopenharmony_ci return -EOPNOTSUPP; 243162306a36Sopenharmony_ci 243262306a36Sopenharmony_ci return fscrypt_ioctl_get_nonce(filp, (void __user *)arg); 243362306a36Sopenharmony_ci} 243462306a36Sopenharmony_ci 243562306a36Sopenharmony_cistatic int f2fs_ioc_gc(struct file *filp, unsigned long arg) 243662306a36Sopenharmony_ci{ 243762306a36Sopenharmony_ci struct inode *inode = file_inode(filp); 243862306a36Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_I_SB(inode); 243962306a36Sopenharmony_ci struct f2fs_gc_control gc_control = { .victim_segno = NULL_SEGNO, 244062306a36Sopenharmony_ci .no_bg_gc = false, 244162306a36Sopenharmony_ci .should_migrate_blocks = false, 244262306a36Sopenharmony_ci .nr_free_secs = 0 }; 244362306a36Sopenharmony_ci __u32 sync; 244462306a36Sopenharmony_ci int ret; 244562306a36Sopenharmony_ci 244662306a36Sopenharmony_ci if (!capable(CAP_SYS_ADMIN)) 244762306a36Sopenharmony_ci return -EPERM; 244862306a36Sopenharmony_ci 244962306a36Sopenharmony_ci if (get_user(sync, (__u32 __user *)arg)) 245062306a36Sopenharmony_ci return -EFAULT; 245162306a36Sopenharmony_ci 245262306a36Sopenharmony_ci if (f2fs_readonly(sbi->sb)) 245362306a36Sopenharmony_ci return -EROFS; 245462306a36Sopenharmony_ci 245562306a36Sopenharmony_ci ret = mnt_want_write_file(filp); 245662306a36Sopenharmony_ci if (ret) 245762306a36Sopenharmony_ci return ret; 245862306a36Sopenharmony_ci 245962306a36Sopenharmony_ci if (!sync) { 246062306a36Sopenharmony_ci if (!f2fs_down_write_trylock(&sbi->gc_lock)) { 246162306a36Sopenharmony_ci ret = -EBUSY; 246262306a36Sopenharmony_ci goto out; 246362306a36Sopenharmony_ci } 246462306a36Sopenharmony_ci } else { 246562306a36Sopenharmony_ci f2fs_down_write(&sbi->gc_lock); 246662306a36Sopenharmony_ci } 246762306a36Sopenharmony_ci 246862306a36Sopenharmony_ci gc_control.init_gc_type = sync ? FG_GC : BG_GC; 246962306a36Sopenharmony_ci gc_control.err_gc_skipped = sync; 247062306a36Sopenharmony_ci stat_inc_gc_call_count(sbi, FOREGROUND); 247162306a36Sopenharmony_ci ret = f2fs_gc(sbi, &gc_control); 247262306a36Sopenharmony_ciout: 247362306a36Sopenharmony_ci mnt_drop_write_file(filp); 247462306a36Sopenharmony_ci return ret; 247562306a36Sopenharmony_ci} 247662306a36Sopenharmony_ci 247762306a36Sopenharmony_cistatic int __f2fs_ioc_gc_range(struct file *filp, struct f2fs_gc_range *range) 247862306a36Sopenharmony_ci{ 247962306a36Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_I_SB(file_inode(filp)); 248062306a36Sopenharmony_ci struct f2fs_gc_control gc_control = { 248162306a36Sopenharmony_ci .init_gc_type = range->sync ? FG_GC : BG_GC, 248262306a36Sopenharmony_ci .no_bg_gc = false, 248362306a36Sopenharmony_ci .should_migrate_blocks = false, 248462306a36Sopenharmony_ci .err_gc_skipped = range->sync, 248562306a36Sopenharmony_ci .nr_free_secs = 0 }; 248662306a36Sopenharmony_ci u64 end; 248762306a36Sopenharmony_ci int ret; 248862306a36Sopenharmony_ci 248962306a36Sopenharmony_ci if (!capable(CAP_SYS_ADMIN)) 249062306a36Sopenharmony_ci return -EPERM; 249162306a36Sopenharmony_ci if (f2fs_readonly(sbi->sb)) 249262306a36Sopenharmony_ci return -EROFS; 249362306a36Sopenharmony_ci 249462306a36Sopenharmony_ci end = range->start + range->len; 249562306a36Sopenharmony_ci if (end < range->start || range->start < MAIN_BLKADDR(sbi) || 249662306a36Sopenharmony_ci end >= MAX_BLKADDR(sbi)) 249762306a36Sopenharmony_ci return -EINVAL; 249862306a36Sopenharmony_ci 249962306a36Sopenharmony_ci ret = mnt_want_write_file(filp); 250062306a36Sopenharmony_ci if (ret) 250162306a36Sopenharmony_ci return ret; 250262306a36Sopenharmony_ci 250362306a36Sopenharmony_cido_more: 250462306a36Sopenharmony_ci if (!range->sync) { 250562306a36Sopenharmony_ci if (!f2fs_down_write_trylock(&sbi->gc_lock)) { 250662306a36Sopenharmony_ci ret = -EBUSY; 250762306a36Sopenharmony_ci goto out; 250862306a36Sopenharmony_ci } 250962306a36Sopenharmony_ci } else { 251062306a36Sopenharmony_ci f2fs_down_write(&sbi->gc_lock); 251162306a36Sopenharmony_ci } 251262306a36Sopenharmony_ci 251362306a36Sopenharmony_ci gc_control.victim_segno = GET_SEGNO(sbi, range->start); 251462306a36Sopenharmony_ci stat_inc_gc_call_count(sbi, FOREGROUND); 251562306a36Sopenharmony_ci ret = f2fs_gc(sbi, &gc_control); 251662306a36Sopenharmony_ci if (ret) { 251762306a36Sopenharmony_ci if (ret == -EBUSY) 251862306a36Sopenharmony_ci ret = -EAGAIN; 251962306a36Sopenharmony_ci goto out; 252062306a36Sopenharmony_ci } 252162306a36Sopenharmony_ci range->start += CAP_BLKS_PER_SEC(sbi); 252262306a36Sopenharmony_ci if (range->start <= end) 252362306a36Sopenharmony_ci goto do_more; 252462306a36Sopenharmony_ciout: 252562306a36Sopenharmony_ci mnt_drop_write_file(filp); 252662306a36Sopenharmony_ci return ret; 252762306a36Sopenharmony_ci} 252862306a36Sopenharmony_ci 252962306a36Sopenharmony_cistatic int f2fs_ioc_gc_range(struct file *filp, unsigned long arg) 253062306a36Sopenharmony_ci{ 253162306a36Sopenharmony_ci struct f2fs_gc_range range; 253262306a36Sopenharmony_ci 253362306a36Sopenharmony_ci if (copy_from_user(&range, (struct f2fs_gc_range __user *)arg, 253462306a36Sopenharmony_ci sizeof(range))) 253562306a36Sopenharmony_ci return -EFAULT; 253662306a36Sopenharmony_ci return __f2fs_ioc_gc_range(filp, &range); 253762306a36Sopenharmony_ci} 253862306a36Sopenharmony_ci 253962306a36Sopenharmony_cistatic int f2fs_ioc_write_checkpoint(struct file *filp) 254062306a36Sopenharmony_ci{ 254162306a36Sopenharmony_ci struct inode *inode = file_inode(filp); 254262306a36Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_I_SB(inode); 254362306a36Sopenharmony_ci int ret; 254462306a36Sopenharmony_ci 254562306a36Sopenharmony_ci if (!capable(CAP_SYS_ADMIN)) 254662306a36Sopenharmony_ci return -EPERM; 254762306a36Sopenharmony_ci 254862306a36Sopenharmony_ci if (f2fs_readonly(sbi->sb)) 254962306a36Sopenharmony_ci return -EROFS; 255062306a36Sopenharmony_ci 255162306a36Sopenharmony_ci if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED))) { 255262306a36Sopenharmony_ci f2fs_info(sbi, "Skipping Checkpoint. Checkpoints currently disabled."); 255362306a36Sopenharmony_ci return -EINVAL; 255462306a36Sopenharmony_ci } 255562306a36Sopenharmony_ci 255662306a36Sopenharmony_ci ret = mnt_want_write_file(filp); 255762306a36Sopenharmony_ci if (ret) 255862306a36Sopenharmony_ci return ret; 255962306a36Sopenharmony_ci 256062306a36Sopenharmony_ci ret = f2fs_sync_fs(sbi->sb, 1); 256162306a36Sopenharmony_ci 256262306a36Sopenharmony_ci mnt_drop_write_file(filp); 256362306a36Sopenharmony_ci return ret; 256462306a36Sopenharmony_ci} 256562306a36Sopenharmony_ci 256662306a36Sopenharmony_cistatic int f2fs_defragment_range(struct f2fs_sb_info *sbi, 256762306a36Sopenharmony_ci struct file *filp, 256862306a36Sopenharmony_ci struct f2fs_defragment *range) 256962306a36Sopenharmony_ci{ 257062306a36Sopenharmony_ci struct inode *inode = file_inode(filp); 257162306a36Sopenharmony_ci struct f2fs_map_blocks map = { .m_next_extent = NULL, 257262306a36Sopenharmony_ci .m_seg_type = NO_CHECK_TYPE, 257362306a36Sopenharmony_ci .m_may_create = false }; 257462306a36Sopenharmony_ci struct extent_info ei = {}; 257562306a36Sopenharmony_ci pgoff_t pg_start, pg_end, next_pgofs; 257662306a36Sopenharmony_ci unsigned int blk_per_seg = sbi->blocks_per_seg; 257762306a36Sopenharmony_ci unsigned int total = 0, sec_num; 257862306a36Sopenharmony_ci block_t blk_end = 0; 257962306a36Sopenharmony_ci bool fragmented = false; 258062306a36Sopenharmony_ci int err; 258162306a36Sopenharmony_ci 258262306a36Sopenharmony_ci pg_start = range->start >> PAGE_SHIFT; 258362306a36Sopenharmony_ci pg_end = (range->start + range->len) >> PAGE_SHIFT; 258462306a36Sopenharmony_ci 258562306a36Sopenharmony_ci f2fs_balance_fs(sbi, true); 258662306a36Sopenharmony_ci 258762306a36Sopenharmony_ci inode_lock(inode); 258862306a36Sopenharmony_ci 258962306a36Sopenharmony_ci if (is_inode_flag_set(inode, FI_COMPRESS_RELEASED)) { 259062306a36Sopenharmony_ci err = -EINVAL; 259162306a36Sopenharmony_ci goto unlock_out; 259262306a36Sopenharmony_ci } 259362306a36Sopenharmony_ci 259462306a36Sopenharmony_ci /* if in-place-update policy is enabled, don't waste time here */ 259562306a36Sopenharmony_ci set_inode_flag(inode, FI_OPU_WRITE); 259662306a36Sopenharmony_ci if (f2fs_should_update_inplace(inode, NULL)) { 259762306a36Sopenharmony_ci err = -EINVAL; 259862306a36Sopenharmony_ci goto out; 259962306a36Sopenharmony_ci } 260062306a36Sopenharmony_ci 260162306a36Sopenharmony_ci /* writeback all dirty pages in the range */ 260262306a36Sopenharmony_ci err = filemap_write_and_wait_range(inode->i_mapping, range->start, 260362306a36Sopenharmony_ci range->start + range->len - 1); 260462306a36Sopenharmony_ci if (err) 260562306a36Sopenharmony_ci goto out; 260662306a36Sopenharmony_ci 260762306a36Sopenharmony_ci /* 260862306a36Sopenharmony_ci * lookup mapping info in extent cache, skip defragmenting if physical 260962306a36Sopenharmony_ci * block addresses are continuous. 261062306a36Sopenharmony_ci */ 261162306a36Sopenharmony_ci if (f2fs_lookup_read_extent_cache(inode, pg_start, &ei)) { 261262306a36Sopenharmony_ci if (ei.fofs + ei.len >= pg_end) 261362306a36Sopenharmony_ci goto out; 261462306a36Sopenharmony_ci } 261562306a36Sopenharmony_ci 261662306a36Sopenharmony_ci map.m_lblk = pg_start; 261762306a36Sopenharmony_ci map.m_next_pgofs = &next_pgofs; 261862306a36Sopenharmony_ci 261962306a36Sopenharmony_ci /* 262062306a36Sopenharmony_ci * lookup mapping info in dnode page cache, skip defragmenting if all 262162306a36Sopenharmony_ci * physical block addresses are continuous even if there are hole(s) 262262306a36Sopenharmony_ci * in logical blocks. 262362306a36Sopenharmony_ci */ 262462306a36Sopenharmony_ci while (map.m_lblk < pg_end) { 262562306a36Sopenharmony_ci map.m_len = pg_end - map.m_lblk; 262662306a36Sopenharmony_ci err = f2fs_map_blocks(inode, &map, F2FS_GET_BLOCK_DEFAULT); 262762306a36Sopenharmony_ci if (err) 262862306a36Sopenharmony_ci goto out; 262962306a36Sopenharmony_ci 263062306a36Sopenharmony_ci if (!(map.m_flags & F2FS_MAP_FLAGS)) { 263162306a36Sopenharmony_ci map.m_lblk = next_pgofs; 263262306a36Sopenharmony_ci continue; 263362306a36Sopenharmony_ci } 263462306a36Sopenharmony_ci 263562306a36Sopenharmony_ci if (blk_end && blk_end != map.m_pblk) 263662306a36Sopenharmony_ci fragmented = true; 263762306a36Sopenharmony_ci 263862306a36Sopenharmony_ci /* record total count of block that we're going to move */ 263962306a36Sopenharmony_ci total += map.m_len; 264062306a36Sopenharmony_ci 264162306a36Sopenharmony_ci blk_end = map.m_pblk + map.m_len; 264262306a36Sopenharmony_ci 264362306a36Sopenharmony_ci map.m_lblk += map.m_len; 264462306a36Sopenharmony_ci } 264562306a36Sopenharmony_ci 264662306a36Sopenharmony_ci if (!fragmented) { 264762306a36Sopenharmony_ci total = 0; 264862306a36Sopenharmony_ci goto out; 264962306a36Sopenharmony_ci } 265062306a36Sopenharmony_ci 265162306a36Sopenharmony_ci sec_num = DIV_ROUND_UP(total, CAP_BLKS_PER_SEC(sbi)); 265262306a36Sopenharmony_ci 265362306a36Sopenharmony_ci /* 265462306a36Sopenharmony_ci * make sure there are enough free section for LFS allocation, this can 265562306a36Sopenharmony_ci * avoid defragment running in SSR mode when free section are allocated 265662306a36Sopenharmony_ci * intensively 265762306a36Sopenharmony_ci */ 265862306a36Sopenharmony_ci if (has_not_enough_free_secs(sbi, 0, sec_num)) { 265962306a36Sopenharmony_ci err = -EAGAIN; 266062306a36Sopenharmony_ci goto out; 266162306a36Sopenharmony_ci } 266262306a36Sopenharmony_ci 266362306a36Sopenharmony_ci map.m_lblk = pg_start; 266462306a36Sopenharmony_ci map.m_len = pg_end - pg_start; 266562306a36Sopenharmony_ci total = 0; 266662306a36Sopenharmony_ci 266762306a36Sopenharmony_ci while (map.m_lblk < pg_end) { 266862306a36Sopenharmony_ci pgoff_t idx; 266962306a36Sopenharmony_ci int cnt = 0; 267062306a36Sopenharmony_ci 267162306a36Sopenharmony_cido_map: 267262306a36Sopenharmony_ci map.m_len = pg_end - map.m_lblk; 267362306a36Sopenharmony_ci err = f2fs_map_blocks(inode, &map, F2FS_GET_BLOCK_DEFAULT); 267462306a36Sopenharmony_ci if (err) 267562306a36Sopenharmony_ci goto clear_out; 267662306a36Sopenharmony_ci 267762306a36Sopenharmony_ci if (!(map.m_flags & F2FS_MAP_FLAGS)) { 267862306a36Sopenharmony_ci map.m_lblk = next_pgofs; 267962306a36Sopenharmony_ci goto check; 268062306a36Sopenharmony_ci } 268162306a36Sopenharmony_ci 268262306a36Sopenharmony_ci set_inode_flag(inode, FI_SKIP_WRITES); 268362306a36Sopenharmony_ci 268462306a36Sopenharmony_ci idx = map.m_lblk; 268562306a36Sopenharmony_ci while (idx < map.m_lblk + map.m_len && cnt < blk_per_seg) { 268662306a36Sopenharmony_ci struct page *page; 268762306a36Sopenharmony_ci 268862306a36Sopenharmony_ci page = f2fs_get_lock_data_page(inode, idx, true); 268962306a36Sopenharmony_ci if (IS_ERR(page)) { 269062306a36Sopenharmony_ci err = PTR_ERR(page); 269162306a36Sopenharmony_ci goto clear_out; 269262306a36Sopenharmony_ci } 269362306a36Sopenharmony_ci 269462306a36Sopenharmony_ci set_page_dirty(page); 269562306a36Sopenharmony_ci set_page_private_gcing(page); 269662306a36Sopenharmony_ci f2fs_put_page(page, 1); 269762306a36Sopenharmony_ci 269862306a36Sopenharmony_ci idx++; 269962306a36Sopenharmony_ci cnt++; 270062306a36Sopenharmony_ci total++; 270162306a36Sopenharmony_ci } 270262306a36Sopenharmony_ci 270362306a36Sopenharmony_ci map.m_lblk = idx; 270462306a36Sopenharmony_cicheck: 270562306a36Sopenharmony_ci if (map.m_lblk < pg_end && cnt < blk_per_seg) 270662306a36Sopenharmony_ci goto do_map; 270762306a36Sopenharmony_ci 270862306a36Sopenharmony_ci clear_inode_flag(inode, FI_SKIP_WRITES); 270962306a36Sopenharmony_ci 271062306a36Sopenharmony_ci err = filemap_fdatawrite(inode->i_mapping); 271162306a36Sopenharmony_ci if (err) 271262306a36Sopenharmony_ci goto out; 271362306a36Sopenharmony_ci } 271462306a36Sopenharmony_ciclear_out: 271562306a36Sopenharmony_ci clear_inode_flag(inode, FI_SKIP_WRITES); 271662306a36Sopenharmony_ciout: 271762306a36Sopenharmony_ci clear_inode_flag(inode, FI_OPU_WRITE); 271862306a36Sopenharmony_ciunlock_out: 271962306a36Sopenharmony_ci inode_unlock(inode); 272062306a36Sopenharmony_ci if (!err) 272162306a36Sopenharmony_ci range->len = (u64)total << PAGE_SHIFT; 272262306a36Sopenharmony_ci return err; 272362306a36Sopenharmony_ci} 272462306a36Sopenharmony_ci 272562306a36Sopenharmony_cistatic int f2fs_ioc_defragment(struct file *filp, unsigned long arg) 272662306a36Sopenharmony_ci{ 272762306a36Sopenharmony_ci struct inode *inode = file_inode(filp); 272862306a36Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_I_SB(inode); 272962306a36Sopenharmony_ci struct f2fs_defragment range; 273062306a36Sopenharmony_ci int err; 273162306a36Sopenharmony_ci 273262306a36Sopenharmony_ci if (!capable(CAP_SYS_ADMIN)) 273362306a36Sopenharmony_ci return -EPERM; 273462306a36Sopenharmony_ci 273562306a36Sopenharmony_ci if (!S_ISREG(inode->i_mode) || f2fs_is_atomic_file(inode)) 273662306a36Sopenharmony_ci return -EINVAL; 273762306a36Sopenharmony_ci 273862306a36Sopenharmony_ci if (f2fs_readonly(sbi->sb)) 273962306a36Sopenharmony_ci return -EROFS; 274062306a36Sopenharmony_ci 274162306a36Sopenharmony_ci if (copy_from_user(&range, (struct f2fs_defragment __user *)arg, 274262306a36Sopenharmony_ci sizeof(range))) 274362306a36Sopenharmony_ci return -EFAULT; 274462306a36Sopenharmony_ci 274562306a36Sopenharmony_ci /* verify alignment of offset & size */ 274662306a36Sopenharmony_ci if (range.start & (F2FS_BLKSIZE - 1) || range.len & (F2FS_BLKSIZE - 1)) 274762306a36Sopenharmony_ci return -EINVAL; 274862306a36Sopenharmony_ci 274962306a36Sopenharmony_ci if (unlikely((range.start + range.len) >> PAGE_SHIFT > 275062306a36Sopenharmony_ci max_file_blocks(inode))) 275162306a36Sopenharmony_ci return -EINVAL; 275262306a36Sopenharmony_ci 275362306a36Sopenharmony_ci err = mnt_want_write_file(filp); 275462306a36Sopenharmony_ci if (err) 275562306a36Sopenharmony_ci return err; 275662306a36Sopenharmony_ci 275762306a36Sopenharmony_ci err = f2fs_defragment_range(sbi, filp, &range); 275862306a36Sopenharmony_ci mnt_drop_write_file(filp); 275962306a36Sopenharmony_ci 276062306a36Sopenharmony_ci f2fs_update_time(sbi, REQ_TIME); 276162306a36Sopenharmony_ci if (err < 0) 276262306a36Sopenharmony_ci return err; 276362306a36Sopenharmony_ci 276462306a36Sopenharmony_ci if (copy_to_user((struct f2fs_defragment __user *)arg, &range, 276562306a36Sopenharmony_ci sizeof(range))) 276662306a36Sopenharmony_ci return -EFAULT; 276762306a36Sopenharmony_ci 276862306a36Sopenharmony_ci return 0; 276962306a36Sopenharmony_ci} 277062306a36Sopenharmony_ci 277162306a36Sopenharmony_cistatic int f2fs_move_file_range(struct file *file_in, loff_t pos_in, 277262306a36Sopenharmony_ci struct file *file_out, loff_t pos_out, size_t len) 277362306a36Sopenharmony_ci{ 277462306a36Sopenharmony_ci struct inode *src = file_inode(file_in); 277562306a36Sopenharmony_ci struct inode *dst = file_inode(file_out); 277662306a36Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_I_SB(src); 277762306a36Sopenharmony_ci size_t olen = len, dst_max_i_size = 0; 277862306a36Sopenharmony_ci size_t dst_osize; 277962306a36Sopenharmony_ci int ret; 278062306a36Sopenharmony_ci 278162306a36Sopenharmony_ci if (file_in->f_path.mnt != file_out->f_path.mnt || 278262306a36Sopenharmony_ci src->i_sb != dst->i_sb) 278362306a36Sopenharmony_ci return -EXDEV; 278462306a36Sopenharmony_ci 278562306a36Sopenharmony_ci if (unlikely(f2fs_readonly(src->i_sb))) 278662306a36Sopenharmony_ci return -EROFS; 278762306a36Sopenharmony_ci 278862306a36Sopenharmony_ci if (!S_ISREG(src->i_mode) || !S_ISREG(dst->i_mode)) 278962306a36Sopenharmony_ci return -EINVAL; 279062306a36Sopenharmony_ci 279162306a36Sopenharmony_ci if (IS_ENCRYPTED(src) || IS_ENCRYPTED(dst)) 279262306a36Sopenharmony_ci return -EOPNOTSUPP; 279362306a36Sopenharmony_ci 279462306a36Sopenharmony_ci if (pos_out < 0 || pos_in < 0) 279562306a36Sopenharmony_ci return -EINVAL; 279662306a36Sopenharmony_ci 279762306a36Sopenharmony_ci if (src == dst) { 279862306a36Sopenharmony_ci if (pos_in == pos_out) 279962306a36Sopenharmony_ci return 0; 280062306a36Sopenharmony_ci if (pos_out > pos_in && pos_out < pos_in + len) 280162306a36Sopenharmony_ci return -EINVAL; 280262306a36Sopenharmony_ci } 280362306a36Sopenharmony_ci 280462306a36Sopenharmony_ci inode_lock(src); 280562306a36Sopenharmony_ci if (src != dst) { 280662306a36Sopenharmony_ci ret = -EBUSY; 280762306a36Sopenharmony_ci if (!inode_trylock(dst)) 280862306a36Sopenharmony_ci goto out; 280962306a36Sopenharmony_ci } 281062306a36Sopenharmony_ci 281162306a36Sopenharmony_ci if (f2fs_compressed_file(src) || f2fs_compressed_file(dst)) { 281262306a36Sopenharmony_ci ret = -EOPNOTSUPP; 281362306a36Sopenharmony_ci goto out_unlock; 281462306a36Sopenharmony_ci } 281562306a36Sopenharmony_ci 281662306a36Sopenharmony_ci ret = -EINVAL; 281762306a36Sopenharmony_ci if (pos_in + len > src->i_size || pos_in + len < pos_in) 281862306a36Sopenharmony_ci goto out_unlock; 281962306a36Sopenharmony_ci if (len == 0) 282062306a36Sopenharmony_ci olen = len = src->i_size - pos_in; 282162306a36Sopenharmony_ci if (pos_in + len == src->i_size) 282262306a36Sopenharmony_ci len = ALIGN(src->i_size, F2FS_BLKSIZE) - pos_in; 282362306a36Sopenharmony_ci if (len == 0) { 282462306a36Sopenharmony_ci ret = 0; 282562306a36Sopenharmony_ci goto out_unlock; 282662306a36Sopenharmony_ci } 282762306a36Sopenharmony_ci 282862306a36Sopenharmony_ci dst_osize = dst->i_size; 282962306a36Sopenharmony_ci if (pos_out + olen > dst->i_size) 283062306a36Sopenharmony_ci dst_max_i_size = pos_out + olen; 283162306a36Sopenharmony_ci 283262306a36Sopenharmony_ci /* verify the end result is block aligned */ 283362306a36Sopenharmony_ci if (!IS_ALIGNED(pos_in, F2FS_BLKSIZE) || 283462306a36Sopenharmony_ci !IS_ALIGNED(pos_in + len, F2FS_BLKSIZE) || 283562306a36Sopenharmony_ci !IS_ALIGNED(pos_out, F2FS_BLKSIZE)) 283662306a36Sopenharmony_ci goto out_unlock; 283762306a36Sopenharmony_ci 283862306a36Sopenharmony_ci ret = f2fs_convert_inline_inode(src); 283962306a36Sopenharmony_ci if (ret) 284062306a36Sopenharmony_ci goto out_unlock; 284162306a36Sopenharmony_ci 284262306a36Sopenharmony_ci ret = f2fs_convert_inline_inode(dst); 284362306a36Sopenharmony_ci if (ret) 284462306a36Sopenharmony_ci goto out_unlock; 284562306a36Sopenharmony_ci 284662306a36Sopenharmony_ci /* write out all dirty pages from offset */ 284762306a36Sopenharmony_ci ret = filemap_write_and_wait_range(src->i_mapping, 284862306a36Sopenharmony_ci pos_in, pos_in + len); 284962306a36Sopenharmony_ci if (ret) 285062306a36Sopenharmony_ci goto out_unlock; 285162306a36Sopenharmony_ci 285262306a36Sopenharmony_ci ret = filemap_write_and_wait_range(dst->i_mapping, 285362306a36Sopenharmony_ci pos_out, pos_out + len); 285462306a36Sopenharmony_ci if (ret) 285562306a36Sopenharmony_ci goto out_unlock; 285662306a36Sopenharmony_ci 285762306a36Sopenharmony_ci f2fs_balance_fs(sbi, true); 285862306a36Sopenharmony_ci 285962306a36Sopenharmony_ci f2fs_down_write(&F2FS_I(src)->i_gc_rwsem[WRITE]); 286062306a36Sopenharmony_ci if (src != dst) { 286162306a36Sopenharmony_ci ret = -EBUSY; 286262306a36Sopenharmony_ci if (!f2fs_down_write_trylock(&F2FS_I(dst)->i_gc_rwsem[WRITE])) 286362306a36Sopenharmony_ci goto out_src; 286462306a36Sopenharmony_ci } 286562306a36Sopenharmony_ci 286662306a36Sopenharmony_ci f2fs_lock_op(sbi); 286762306a36Sopenharmony_ci ret = __exchange_data_block(src, dst, pos_in >> F2FS_BLKSIZE_BITS, 286862306a36Sopenharmony_ci pos_out >> F2FS_BLKSIZE_BITS, 286962306a36Sopenharmony_ci len >> F2FS_BLKSIZE_BITS, false); 287062306a36Sopenharmony_ci 287162306a36Sopenharmony_ci if (!ret) { 287262306a36Sopenharmony_ci if (dst_max_i_size) 287362306a36Sopenharmony_ci f2fs_i_size_write(dst, dst_max_i_size); 287462306a36Sopenharmony_ci else if (dst_osize != dst->i_size) 287562306a36Sopenharmony_ci f2fs_i_size_write(dst, dst_osize); 287662306a36Sopenharmony_ci } 287762306a36Sopenharmony_ci f2fs_unlock_op(sbi); 287862306a36Sopenharmony_ci 287962306a36Sopenharmony_ci if (src != dst) 288062306a36Sopenharmony_ci f2fs_up_write(&F2FS_I(dst)->i_gc_rwsem[WRITE]); 288162306a36Sopenharmony_ciout_src: 288262306a36Sopenharmony_ci f2fs_up_write(&F2FS_I(src)->i_gc_rwsem[WRITE]); 288362306a36Sopenharmony_ci if (ret) 288462306a36Sopenharmony_ci goto out_unlock; 288562306a36Sopenharmony_ci 288662306a36Sopenharmony_ci src->i_mtime = inode_set_ctime_current(src); 288762306a36Sopenharmony_ci f2fs_mark_inode_dirty_sync(src, false); 288862306a36Sopenharmony_ci if (src != dst) { 288962306a36Sopenharmony_ci dst->i_mtime = inode_set_ctime_current(dst); 289062306a36Sopenharmony_ci f2fs_mark_inode_dirty_sync(dst, false); 289162306a36Sopenharmony_ci } 289262306a36Sopenharmony_ci f2fs_update_time(sbi, REQ_TIME); 289362306a36Sopenharmony_ci 289462306a36Sopenharmony_ciout_unlock: 289562306a36Sopenharmony_ci if (src != dst) 289662306a36Sopenharmony_ci inode_unlock(dst); 289762306a36Sopenharmony_ciout: 289862306a36Sopenharmony_ci inode_unlock(src); 289962306a36Sopenharmony_ci return ret; 290062306a36Sopenharmony_ci} 290162306a36Sopenharmony_ci 290262306a36Sopenharmony_cistatic int __f2fs_ioc_move_range(struct file *filp, 290362306a36Sopenharmony_ci struct f2fs_move_range *range) 290462306a36Sopenharmony_ci{ 290562306a36Sopenharmony_ci struct fd dst; 290662306a36Sopenharmony_ci int err; 290762306a36Sopenharmony_ci 290862306a36Sopenharmony_ci if (!(filp->f_mode & FMODE_READ) || 290962306a36Sopenharmony_ci !(filp->f_mode & FMODE_WRITE)) 291062306a36Sopenharmony_ci return -EBADF; 291162306a36Sopenharmony_ci 291262306a36Sopenharmony_ci dst = fdget(range->dst_fd); 291362306a36Sopenharmony_ci if (!dst.file) 291462306a36Sopenharmony_ci return -EBADF; 291562306a36Sopenharmony_ci 291662306a36Sopenharmony_ci if (!(dst.file->f_mode & FMODE_WRITE)) { 291762306a36Sopenharmony_ci err = -EBADF; 291862306a36Sopenharmony_ci goto err_out; 291962306a36Sopenharmony_ci } 292062306a36Sopenharmony_ci 292162306a36Sopenharmony_ci err = mnt_want_write_file(filp); 292262306a36Sopenharmony_ci if (err) 292362306a36Sopenharmony_ci goto err_out; 292462306a36Sopenharmony_ci 292562306a36Sopenharmony_ci err = f2fs_move_file_range(filp, range->pos_in, dst.file, 292662306a36Sopenharmony_ci range->pos_out, range->len); 292762306a36Sopenharmony_ci 292862306a36Sopenharmony_ci mnt_drop_write_file(filp); 292962306a36Sopenharmony_cierr_out: 293062306a36Sopenharmony_ci fdput(dst); 293162306a36Sopenharmony_ci return err; 293262306a36Sopenharmony_ci} 293362306a36Sopenharmony_ci 293462306a36Sopenharmony_cistatic int f2fs_ioc_move_range(struct file *filp, unsigned long arg) 293562306a36Sopenharmony_ci{ 293662306a36Sopenharmony_ci struct f2fs_move_range range; 293762306a36Sopenharmony_ci 293862306a36Sopenharmony_ci if (copy_from_user(&range, (struct f2fs_move_range __user *)arg, 293962306a36Sopenharmony_ci sizeof(range))) 294062306a36Sopenharmony_ci return -EFAULT; 294162306a36Sopenharmony_ci return __f2fs_ioc_move_range(filp, &range); 294262306a36Sopenharmony_ci} 294362306a36Sopenharmony_ci 294462306a36Sopenharmony_cistatic int f2fs_ioc_flush_device(struct file *filp, unsigned long arg) 294562306a36Sopenharmony_ci{ 294662306a36Sopenharmony_ci struct inode *inode = file_inode(filp); 294762306a36Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_I_SB(inode); 294862306a36Sopenharmony_ci struct sit_info *sm = SIT_I(sbi); 294962306a36Sopenharmony_ci unsigned int start_segno = 0, end_segno = 0; 295062306a36Sopenharmony_ci unsigned int dev_start_segno = 0, dev_end_segno = 0; 295162306a36Sopenharmony_ci struct f2fs_flush_device range; 295262306a36Sopenharmony_ci struct f2fs_gc_control gc_control = { 295362306a36Sopenharmony_ci .init_gc_type = FG_GC, 295462306a36Sopenharmony_ci .should_migrate_blocks = true, 295562306a36Sopenharmony_ci .err_gc_skipped = true, 295662306a36Sopenharmony_ci .nr_free_secs = 0 }; 295762306a36Sopenharmony_ci int ret; 295862306a36Sopenharmony_ci 295962306a36Sopenharmony_ci if (!capable(CAP_SYS_ADMIN)) 296062306a36Sopenharmony_ci return -EPERM; 296162306a36Sopenharmony_ci 296262306a36Sopenharmony_ci if (f2fs_readonly(sbi->sb)) 296362306a36Sopenharmony_ci return -EROFS; 296462306a36Sopenharmony_ci 296562306a36Sopenharmony_ci if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED))) 296662306a36Sopenharmony_ci return -EINVAL; 296762306a36Sopenharmony_ci 296862306a36Sopenharmony_ci if (copy_from_user(&range, (struct f2fs_flush_device __user *)arg, 296962306a36Sopenharmony_ci sizeof(range))) 297062306a36Sopenharmony_ci return -EFAULT; 297162306a36Sopenharmony_ci 297262306a36Sopenharmony_ci if (!f2fs_is_multi_device(sbi) || sbi->s_ndevs - 1 <= range.dev_num || 297362306a36Sopenharmony_ci __is_large_section(sbi)) { 297462306a36Sopenharmony_ci f2fs_warn(sbi, "Can't flush %u in %d for segs_per_sec %u != 1", 297562306a36Sopenharmony_ci range.dev_num, sbi->s_ndevs, sbi->segs_per_sec); 297662306a36Sopenharmony_ci return -EINVAL; 297762306a36Sopenharmony_ci } 297862306a36Sopenharmony_ci 297962306a36Sopenharmony_ci ret = mnt_want_write_file(filp); 298062306a36Sopenharmony_ci if (ret) 298162306a36Sopenharmony_ci return ret; 298262306a36Sopenharmony_ci 298362306a36Sopenharmony_ci if (range.dev_num != 0) 298462306a36Sopenharmony_ci dev_start_segno = GET_SEGNO(sbi, FDEV(range.dev_num).start_blk); 298562306a36Sopenharmony_ci dev_end_segno = GET_SEGNO(sbi, FDEV(range.dev_num).end_blk); 298662306a36Sopenharmony_ci 298762306a36Sopenharmony_ci start_segno = sm->last_victim[FLUSH_DEVICE]; 298862306a36Sopenharmony_ci if (start_segno < dev_start_segno || start_segno >= dev_end_segno) 298962306a36Sopenharmony_ci start_segno = dev_start_segno; 299062306a36Sopenharmony_ci end_segno = min(start_segno + range.segments, dev_end_segno); 299162306a36Sopenharmony_ci 299262306a36Sopenharmony_ci while (start_segno < end_segno) { 299362306a36Sopenharmony_ci if (!f2fs_down_write_trylock(&sbi->gc_lock)) { 299462306a36Sopenharmony_ci ret = -EBUSY; 299562306a36Sopenharmony_ci goto out; 299662306a36Sopenharmony_ci } 299762306a36Sopenharmony_ci sm->last_victim[GC_CB] = end_segno + 1; 299862306a36Sopenharmony_ci sm->last_victim[GC_GREEDY] = end_segno + 1; 299962306a36Sopenharmony_ci sm->last_victim[ALLOC_NEXT] = end_segno + 1; 300062306a36Sopenharmony_ci 300162306a36Sopenharmony_ci gc_control.victim_segno = start_segno; 300262306a36Sopenharmony_ci stat_inc_gc_call_count(sbi, FOREGROUND); 300362306a36Sopenharmony_ci ret = f2fs_gc(sbi, &gc_control); 300462306a36Sopenharmony_ci if (ret == -EAGAIN) 300562306a36Sopenharmony_ci ret = 0; 300662306a36Sopenharmony_ci else if (ret < 0) 300762306a36Sopenharmony_ci break; 300862306a36Sopenharmony_ci start_segno++; 300962306a36Sopenharmony_ci } 301062306a36Sopenharmony_ciout: 301162306a36Sopenharmony_ci mnt_drop_write_file(filp); 301262306a36Sopenharmony_ci return ret; 301362306a36Sopenharmony_ci} 301462306a36Sopenharmony_ci 301562306a36Sopenharmony_cistatic int f2fs_ioc_get_features(struct file *filp, unsigned long arg) 301662306a36Sopenharmony_ci{ 301762306a36Sopenharmony_ci struct inode *inode = file_inode(filp); 301862306a36Sopenharmony_ci u32 sb_feature = le32_to_cpu(F2FS_I_SB(inode)->raw_super->feature); 301962306a36Sopenharmony_ci 302062306a36Sopenharmony_ci /* Must validate to set it with SQLite behavior in Android. */ 302162306a36Sopenharmony_ci sb_feature |= F2FS_FEATURE_ATOMIC_WRITE; 302262306a36Sopenharmony_ci 302362306a36Sopenharmony_ci return put_user(sb_feature, (u32 __user *)arg); 302462306a36Sopenharmony_ci} 302562306a36Sopenharmony_ci 302662306a36Sopenharmony_ci#ifdef CONFIG_QUOTA 302762306a36Sopenharmony_ciint f2fs_transfer_project_quota(struct inode *inode, kprojid_t kprojid) 302862306a36Sopenharmony_ci{ 302962306a36Sopenharmony_ci struct dquot *transfer_to[MAXQUOTAS] = {}; 303062306a36Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_I_SB(inode); 303162306a36Sopenharmony_ci struct super_block *sb = sbi->sb; 303262306a36Sopenharmony_ci int err; 303362306a36Sopenharmony_ci 303462306a36Sopenharmony_ci transfer_to[PRJQUOTA] = dqget(sb, make_kqid_projid(kprojid)); 303562306a36Sopenharmony_ci if (IS_ERR(transfer_to[PRJQUOTA])) 303662306a36Sopenharmony_ci return PTR_ERR(transfer_to[PRJQUOTA]); 303762306a36Sopenharmony_ci 303862306a36Sopenharmony_ci err = __dquot_transfer(inode, transfer_to); 303962306a36Sopenharmony_ci if (err) 304062306a36Sopenharmony_ci set_sbi_flag(sbi, SBI_QUOTA_NEED_REPAIR); 304162306a36Sopenharmony_ci dqput(transfer_to[PRJQUOTA]); 304262306a36Sopenharmony_ci return err; 304362306a36Sopenharmony_ci} 304462306a36Sopenharmony_ci 304562306a36Sopenharmony_cistatic int f2fs_ioc_setproject(struct inode *inode, __u32 projid) 304662306a36Sopenharmony_ci{ 304762306a36Sopenharmony_ci struct f2fs_inode_info *fi = F2FS_I(inode); 304862306a36Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_I_SB(inode); 304962306a36Sopenharmony_ci struct f2fs_inode *ri = NULL; 305062306a36Sopenharmony_ci kprojid_t kprojid; 305162306a36Sopenharmony_ci int err; 305262306a36Sopenharmony_ci 305362306a36Sopenharmony_ci if (!f2fs_sb_has_project_quota(sbi)) { 305462306a36Sopenharmony_ci if (projid != F2FS_DEF_PROJID) 305562306a36Sopenharmony_ci return -EOPNOTSUPP; 305662306a36Sopenharmony_ci else 305762306a36Sopenharmony_ci return 0; 305862306a36Sopenharmony_ci } 305962306a36Sopenharmony_ci 306062306a36Sopenharmony_ci if (!f2fs_has_extra_attr(inode)) 306162306a36Sopenharmony_ci return -EOPNOTSUPP; 306262306a36Sopenharmony_ci 306362306a36Sopenharmony_ci kprojid = make_kprojid(&init_user_ns, (projid_t)projid); 306462306a36Sopenharmony_ci 306562306a36Sopenharmony_ci if (projid_eq(kprojid, fi->i_projid)) 306662306a36Sopenharmony_ci return 0; 306762306a36Sopenharmony_ci 306862306a36Sopenharmony_ci err = -EPERM; 306962306a36Sopenharmony_ci /* Is it quota file? Do not allow user to mess with it */ 307062306a36Sopenharmony_ci if (IS_NOQUOTA(inode)) 307162306a36Sopenharmony_ci return err; 307262306a36Sopenharmony_ci 307362306a36Sopenharmony_ci if (!F2FS_FITS_IN_INODE(ri, fi->i_extra_isize, i_projid)) 307462306a36Sopenharmony_ci return -EOVERFLOW; 307562306a36Sopenharmony_ci 307662306a36Sopenharmony_ci err = f2fs_dquot_initialize(inode); 307762306a36Sopenharmony_ci if (err) 307862306a36Sopenharmony_ci return err; 307962306a36Sopenharmony_ci 308062306a36Sopenharmony_ci f2fs_lock_op(sbi); 308162306a36Sopenharmony_ci err = f2fs_transfer_project_quota(inode, kprojid); 308262306a36Sopenharmony_ci if (err) 308362306a36Sopenharmony_ci goto out_unlock; 308462306a36Sopenharmony_ci 308562306a36Sopenharmony_ci fi->i_projid = kprojid; 308662306a36Sopenharmony_ci inode_set_ctime_current(inode); 308762306a36Sopenharmony_ci f2fs_mark_inode_dirty_sync(inode, true); 308862306a36Sopenharmony_ciout_unlock: 308962306a36Sopenharmony_ci f2fs_unlock_op(sbi); 309062306a36Sopenharmony_ci return err; 309162306a36Sopenharmony_ci} 309262306a36Sopenharmony_ci#else 309362306a36Sopenharmony_ciint f2fs_transfer_project_quota(struct inode *inode, kprojid_t kprojid) 309462306a36Sopenharmony_ci{ 309562306a36Sopenharmony_ci return 0; 309662306a36Sopenharmony_ci} 309762306a36Sopenharmony_ci 309862306a36Sopenharmony_cistatic int f2fs_ioc_setproject(struct inode *inode, __u32 projid) 309962306a36Sopenharmony_ci{ 310062306a36Sopenharmony_ci if (projid != F2FS_DEF_PROJID) 310162306a36Sopenharmony_ci return -EOPNOTSUPP; 310262306a36Sopenharmony_ci return 0; 310362306a36Sopenharmony_ci} 310462306a36Sopenharmony_ci#endif 310562306a36Sopenharmony_ci 310662306a36Sopenharmony_ciint f2fs_fileattr_get(struct dentry *dentry, struct fileattr *fa) 310762306a36Sopenharmony_ci{ 310862306a36Sopenharmony_ci struct inode *inode = d_inode(dentry); 310962306a36Sopenharmony_ci struct f2fs_inode_info *fi = F2FS_I(inode); 311062306a36Sopenharmony_ci u32 fsflags = f2fs_iflags_to_fsflags(fi->i_flags); 311162306a36Sopenharmony_ci 311262306a36Sopenharmony_ci if (IS_ENCRYPTED(inode)) 311362306a36Sopenharmony_ci fsflags |= FS_ENCRYPT_FL; 311462306a36Sopenharmony_ci if (IS_VERITY(inode)) 311562306a36Sopenharmony_ci fsflags |= FS_VERITY_FL; 311662306a36Sopenharmony_ci if (f2fs_has_inline_data(inode) || f2fs_has_inline_dentry(inode)) 311762306a36Sopenharmony_ci fsflags |= FS_INLINE_DATA_FL; 311862306a36Sopenharmony_ci if (is_inode_flag_set(inode, FI_PIN_FILE)) 311962306a36Sopenharmony_ci fsflags |= FS_NOCOW_FL; 312062306a36Sopenharmony_ci 312162306a36Sopenharmony_ci fileattr_fill_flags(fa, fsflags & F2FS_GETTABLE_FS_FL); 312262306a36Sopenharmony_ci 312362306a36Sopenharmony_ci if (f2fs_sb_has_project_quota(F2FS_I_SB(inode))) 312462306a36Sopenharmony_ci fa->fsx_projid = from_kprojid(&init_user_ns, fi->i_projid); 312562306a36Sopenharmony_ci 312662306a36Sopenharmony_ci return 0; 312762306a36Sopenharmony_ci} 312862306a36Sopenharmony_ci 312962306a36Sopenharmony_ciint f2fs_fileattr_set(struct mnt_idmap *idmap, 313062306a36Sopenharmony_ci struct dentry *dentry, struct fileattr *fa) 313162306a36Sopenharmony_ci{ 313262306a36Sopenharmony_ci struct inode *inode = d_inode(dentry); 313362306a36Sopenharmony_ci u32 fsflags = fa->flags, mask = F2FS_SETTABLE_FS_FL; 313462306a36Sopenharmony_ci u32 iflags; 313562306a36Sopenharmony_ci int err; 313662306a36Sopenharmony_ci 313762306a36Sopenharmony_ci if (unlikely(f2fs_cp_error(F2FS_I_SB(inode)))) 313862306a36Sopenharmony_ci return -EIO; 313962306a36Sopenharmony_ci if (!f2fs_is_checkpoint_ready(F2FS_I_SB(inode))) 314062306a36Sopenharmony_ci return -ENOSPC; 314162306a36Sopenharmony_ci if (fsflags & ~F2FS_GETTABLE_FS_FL) 314262306a36Sopenharmony_ci return -EOPNOTSUPP; 314362306a36Sopenharmony_ci fsflags &= F2FS_SETTABLE_FS_FL; 314462306a36Sopenharmony_ci if (!fa->flags_valid) 314562306a36Sopenharmony_ci mask &= FS_COMMON_FL; 314662306a36Sopenharmony_ci 314762306a36Sopenharmony_ci iflags = f2fs_fsflags_to_iflags(fsflags); 314862306a36Sopenharmony_ci if (f2fs_mask_flags(inode->i_mode, iflags) != iflags) 314962306a36Sopenharmony_ci return -EOPNOTSUPP; 315062306a36Sopenharmony_ci 315162306a36Sopenharmony_ci err = f2fs_setflags_common(inode, iflags, f2fs_fsflags_to_iflags(mask)); 315262306a36Sopenharmony_ci if (!err) 315362306a36Sopenharmony_ci err = f2fs_ioc_setproject(inode, fa->fsx_projid); 315462306a36Sopenharmony_ci 315562306a36Sopenharmony_ci return err; 315662306a36Sopenharmony_ci} 315762306a36Sopenharmony_ci 315862306a36Sopenharmony_ciint f2fs_pin_file_control(struct inode *inode, bool inc) 315962306a36Sopenharmony_ci{ 316062306a36Sopenharmony_ci struct f2fs_inode_info *fi = F2FS_I(inode); 316162306a36Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_I_SB(inode); 316262306a36Sopenharmony_ci 316362306a36Sopenharmony_ci /* Use i_gc_failures for normal file as a risk signal. */ 316462306a36Sopenharmony_ci if (inc) 316562306a36Sopenharmony_ci f2fs_i_gc_failures_write(inode, 316662306a36Sopenharmony_ci fi->i_gc_failures[GC_FAILURE_PIN] + 1); 316762306a36Sopenharmony_ci 316862306a36Sopenharmony_ci if (fi->i_gc_failures[GC_FAILURE_PIN] > sbi->gc_pin_file_threshold) { 316962306a36Sopenharmony_ci f2fs_warn(sbi, "%s: Enable GC = ino %lx after %x GC trials", 317062306a36Sopenharmony_ci __func__, inode->i_ino, 317162306a36Sopenharmony_ci fi->i_gc_failures[GC_FAILURE_PIN]); 317262306a36Sopenharmony_ci clear_inode_flag(inode, FI_PIN_FILE); 317362306a36Sopenharmony_ci return -EAGAIN; 317462306a36Sopenharmony_ci } 317562306a36Sopenharmony_ci return 0; 317662306a36Sopenharmony_ci} 317762306a36Sopenharmony_ci 317862306a36Sopenharmony_cistatic int f2fs_ioc_set_pin_file(struct file *filp, unsigned long arg) 317962306a36Sopenharmony_ci{ 318062306a36Sopenharmony_ci struct inode *inode = file_inode(filp); 318162306a36Sopenharmony_ci __u32 pin; 318262306a36Sopenharmony_ci int ret = 0; 318362306a36Sopenharmony_ci 318462306a36Sopenharmony_ci if (get_user(pin, (__u32 __user *)arg)) 318562306a36Sopenharmony_ci return -EFAULT; 318662306a36Sopenharmony_ci 318762306a36Sopenharmony_ci if (!S_ISREG(inode->i_mode)) 318862306a36Sopenharmony_ci return -EINVAL; 318962306a36Sopenharmony_ci 319062306a36Sopenharmony_ci if (f2fs_readonly(F2FS_I_SB(inode)->sb)) 319162306a36Sopenharmony_ci return -EROFS; 319262306a36Sopenharmony_ci 319362306a36Sopenharmony_ci ret = mnt_want_write_file(filp); 319462306a36Sopenharmony_ci if (ret) 319562306a36Sopenharmony_ci return ret; 319662306a36Sopenharmony_ci 319762306a36Sopenharmony_ci inode_lock(inode); 319862306a36Sopenharmony_ci 319962306a36Sopenharmony_ci if (!pin) { 320062306a36Sopenharmony_ci clear_inode_flag(inode, FI_PIN_FILE); 320162306a36Sopenharmony_ci f2fs_i_gc_failures_write(inode, 0); 320262306a36Sopenharmony_ci goto done; 320362306a36Sopenharmony_ci } 320462306a36Sopenharmony_ci 320562306a36Sopenharmony_ci if (f2fs_should_update_outplace(inode, NULL)) { 320662306a36Sopenharmony_ci ret = -EINVAL; 320762306a36Sopenharmony_ci goto out; 320862306a36Sopenharmony_ci } 320962306a36Sopenharmony_ci 321062306a36Sopenharmony_ci if (f2fs_pin_file_control(inode, false)) { 321162306a36Sopenharmony_ci ret = -EAGAIN; 321262306a36Sopenharmony_ci goto out; 321362306a36Sopenharmony_ci } 321462306a36Sopenharmony_ci 321562306a36Sopenharmony_ci ret = f2fs_convert_inline_inode(inode); 321662306a36Sopenharmony_ci if (ret) 321762306a36Sopenharmony_ci goto out; 321862306a36Sopenharmony_ci 321962306a36Sopenharmony_ci if (!f2fs_disable_compressed_file(inode)) { 322062306a36Sopenharmony_ci ret = -EOPNOTSUPP; 322162306a36Sopenharmony_ci goto out; 322262306a36Sopenharmony_ci } 322362306a36Sopenharmony_ci 322462306a36Sopenharmony_ci set_inode_flag(inode, FI_PIN_FILE); 322562306a36Sopenharmony_ci ret = F2FS_I(inode)->i_gc_failures[GC_FAILURE_PIN]; 322662306a36Sopenharmony_cidone: 322762306a36Sopenharmony_ci f2fs_update_time(F2FS_I_SB(inode), REQ_TIME); 322862306a36Sopenharmony_ciout: 322962306a36Sopenharmony_ci inode_unlock(inode); 323062306a36Sopenharmony_ci mnt_drop_write_file(filp); 323162306a36Sopenharmony_ci return ret; 323262306a36Sopenharmony_ci} 323362306a36Sopenharmony_ci 323462306a36Sopenharmony_cistatic int f2fs_ioc_get_pin_file(struct file *filp, unsigned long arg) 323562306a36Sopenharmony_ci{ 323662306a36Sopenharmony_ci struct inode *inode = file_inode(filp); 323762306a36Sopenharmony_ci __u32 pin = 0; 323862306a36Sopenharmony_ci 323962306a36Sopenharmony_ci if (is_inode_flag_set(inode, FI_PIN_FILE)) 324062306a36Sopenharmony_ci pin = F2FS_I(inode)->i_gc_failures[GC_FAILURE_PIN]; 324162306a36Sopenharmony_ci return put_user(pin, (u32 __user *)arg); 324262306a36Sopenharmony_ci} 324362306a36Sopenharmony_ci 324462306a36Sopenharmony_ciint f2fs_precache_extents(struct inode *inode) 324562306a36Sopenharmony_ci{ 324662306a36Sopenharmony_ci struct f2fs_inode_info *fi = F2FS_I(inode); 324762306a36Sopenharmony_ci struct f2fs_map_blocks map; 324862306a36Sopenharmony_ci pgoff_t m_next_extent; 324962306a36Sopenharmony_ci loff_t end; 325062306a36Sopenharmony_ci int err; 325162306a36Sopenharmony_ci 325262306a36Sopenharmony_ci if (is_inode_flag_set(inode, FI_NO_EXTENT)) 325362306a36Sopenharmony_ci return -EOPNOTSUPP; 325462306a36Sopenharmony_ci 325562306a36Sopenharmony_ci map.m_lblk = 0; 325662306a36Sopenharmony_ci map.m_pblk = 0; 325762306a36Sopenharmony_ci map.m_next_pgofs = NULL; 325862306a36Sopenharmony_ci map.m_next_extent = &m_next_extent; 325962306a36Sopenharmony_ci map.m_seg_type = NO_CHECK_TYPE; 326062306a36Sopenharmony_ci map.m_may_create = false; 326162306a36Sopenharmony_ci end = max_file_blocks(inode); 326262306a36Sopenharmony_ci 326362306a36Sopenharmony_ci while (map.m_lblk < end) { 326462306a36Sopenharmony_ci map.m_len = end - map.m_lblk; 326562306a36Sopenharmony_ci 326662306a36Sopenharmony_ci f2fs_down_write(&fi->i_gc_rwsem[WRITE]); 326762306a36Sopenharmony_ci err = f2fs_map_blocks(inode, &map, F2FS_GET_BLOCK_PRECACHE); 326862306a36Sopenharmony_ci f2fs_up_write(&fi->i_gc_rwsem[WRITE]); 326962306a36Sopenharmony_ci if (err) 327062306a36Sopenharmony_ci return err; 327162306a36Sopenharmony_ci 327262306a36Sopenharmony_ci map.m_lblk = m_next_extent; 327362306a36Sopenharmony_ci } 327462306a36Sopenharmony_ci 327562306a36Sopenharmony_ci return 0; 327662306a36Sopenharmony_ci} 327762306a36Sopenharmony_ci 327862306a36Sopenharmony_cistatic int f2fs_ioc_precache_extents(struct file *filp) 327962306a36Sopenharmony_ci{ 328062306a36Sopenharmony_ci return f2fs_precache_extents(file_inode(filp)); 328162306a36Sopenharmony_ci} 328262306a36Sopenharmony_ci 328362306a36Sopenharmony_cistatic int f2fs_ioc_resize_fs(struct file *filp, unsigned long arg) 328462306a36Sopenharmony_ci{ 328562306a36Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_I_SB(file_inode(filp)); 328662306a36Sopenharmony_ci __u64 block_count; 328762306a36Sopenharmony_ci 328862306a36Sopenharmony_ci if (!capable(CAP_SYS_ADMIN)) 328962306a36Sopenharmony_ci return -EPERM; 329062306a36Sopenharmony_ci 329162306a36Sopenharmony_ci if (f2fs_readonly(sbi->sb)) 329262306a36Sopenharmony_ci return -EROFS; 329362306a36Sopenharmony_ci 329462306a36Sopenharmony_ci if (copy_from_user(&block_count, (void __user *)arg, 329562306a36Sopenharmony_ci sizeof(block_count))) 329662306a36Sopenharmony_ci return -EFAULT; 329762306a36Sopenharmony_ci 329862306a36Sopenharmony_ci return f2fs_resize_fs(filp, block_count); 329962306a36Sopenharmony_ci} 330062306a36Sopenharmony_ci 330162306a36Sopenharmony_cistatic inline int f2fs_has_feature_verity(struct file *filp) 330262306a36Sopenharmony_ci{ 330362306a36Sopenharmony_ci struct inode *inode = file_inode(filp); 330462306a36Sopenharmony_ci 330562306a36Sopenharmony_ci f2fs_update_time(F2FS_I_SB(inode), REQ_TIME); 330662306a36Sopenharmony_ci 330762306a36Sopenharmony_ci if (!f2fs_sb_has_verity(F2FS_I_SB(inode))) { 330862306a36Sopenharmony_ci f2fs_warn(F2FS_I_SB(inode), 330962306a36Sopenharmony_ci "Can't enable fs-verity on inode %lu: the verity feature is not enabled on this filesystem", 331062306a36Sopenharmony_ci inode->i_ino); 331162306a36Sopenharmony_ci return -EOPNOTSUPP; 331262306a36Sopenharmony_ci } 331362306a36Sopenharmony_ci return 0; 331462306a36Sopenharmony_ci} 331562306a36Sopenharmony_ci 331662306a36Sopenharmony_cistatic int f2fs_ioc_enable_verity(struct file *filp, unsigned long arg) 331762306a36Sopenharmony_ci{ 331862306a36Sopenharmony_ci int err = f2fs_has_feature_verity(filp); 331962306a36Sopenharmony_ci 332062306a36Sopenharmony_ci if (err) 332162306a36Sopenharmony_ci return err; 332262306a36Sopenharmony_ci 332362306a36Sopenharmony_ci return fsverity_ioctl_enable(filp, (const void __user *)arg); 332462306a36Sopenharmony_ci} 332562306a36Sopenharmony_ci 332662306a36Sopenharmony_cistatic int f2fs_ioc_enable_code_sign(struct file *filp, unsigned long arg) 332762306a36Sopenharmony_ci{ 332862306a36Sopenharmony_ci int err = f2fs_has_feature_verity(filp); 332962306a36Sopenharmony_ci 333062306a36Sopenharmony_ci if (err) 333162306a36Sopenharmony_ci return err; 333262306a36Sopenharmony_ci 333362306a36Sopenharmony_ci return fsverity_ioctl_enable_code_sign(filp, (const void __user *)arg); 333462306a36Sopenharmony_ci} 333562306a36Sopenharmony_ci 333662306a36Sopenharmony_cistatic int f2fs_ioc_measure_verity(struct file *filp, unsigned long arg) 333762306a36Sopenharmony_ci{ 333862306a36Sopenharmony_ci if (!f2fs_sb_has_verity(F2FS_I_SB(file_inode(filp)))) 333962306a36Sopenharmony_ci return -EOPNOTSUPP; 334062306a36Sopenharmony_ci 334162306a36Sopenharmony_ci return fsverity_ioctl_measure(filp, (void __user *)arg); 334262306a36Sopenharmony_ci} 334362306a36Sopenharmony_ci 334462306a36Sopenharmony_cistatic int f2fs_ioc_read_verity_metadata(struct file *filp, unsigned long arg) 334562306a36Sopenharmony_ci{ 334662306a36Sopenharmony_ci if (!f2fs_sb_has_verity(F2FS_I_SB(file_inode(filp)))) 334762306a36Sopenharmony_ci return -EOPNOTSUPP; 334862306a36Sopenharmony_ci 334962306a36Sopenharmony_ci return fsverity_ioctl_read_metadata(filp, (const void __user *)arg); 335062306a36Sopenharmony_ci} 335162306a36Sopenharmony_ci 335262306a36Sopenharmony_cistatic int f2fs_ioc_getfslabel(struct file *filp, unsigned long arg) 335362306a36Sopenharmony_ci{ 335462306a36Sopenharmony_ci struct inode *inode = file_inode(filp); 335562306a36Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_I_SB(inode); 335662306a36Sopenharmony_ci char *vbuf; 335762306a36Sopenharmony_ci int count; 335862306a36Sopenharmony_ci int err = 0; 335962306a36Sopenharmony_ci 336062306a36Sopenharmony_ci vbuf = f2fs_kzalloc(sbi, MAX_VOLUME_NAME, GFP_KERNEL); 336162306a36Sopenharmony_ci if (!vbuf) 336262306a36Sopenharmony_ci return -ENOMEM; 336362306a36Sopenharmony_ci 336462306a36Sopenharmony_ci f2fs_down_read(&sbi->sb_lock); 336562306a36Sopenharmony_ci count = utf16s_to_utf8s(sbi->raw_super->volume_name, 336662306a36Sopenharmony_ci ARRAY_SIZE(sbi->raw_super->volume_name), 336762306a36Sopenharmony_ci UTF16_LITTLE_ENDIAN, vbuf, MAX_VOLUME_NAME); 336862306a36Sopenharmony_ci f2fs_up_read(&sbi->sb_lock); 336962306a36Sopenharmony_ci 337062306a36Sopenharmony_ci if (copy_to_user((char __user *)arg, vbuf, 337162306a36Sopenharmony_ci min(FSLABEL_MAX, count))) 337262306a36Sopenharmony_ci err = -EFAULT; 337362306a36Sopenharmony_ci 337462306a36Sopenharmony_ci kfree(vbuf); 337562306a36Sopenharmony_ci return err; 337662306a36Sopenharmony_ci} 337762306a36Sopenharmony_ci 337862306a36Sopenharmony_cistatic int f2fs_ioc_setfslabel(struct file *filp, unsigned long arg) 337962306a36Sopenharmony_ci{ 338062306a36Sopenharmony_ci struct inode *inode = file_inode(filp); 338162306a36Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_I_SB(inode); 338262306a36Sopenharmony_ci char *vbuf; 338362306a36Sopenharmony_ci int err = 0; 338462306a36Sopenharmony_ci 338562306a36Sopenharmony_ci if (!capable(CAP_SYS_ADMIN)) 338662306a36Sopenharmony_ci return -EPERM; 338762306a36Sopenharmony_ci 338862306a36Sopenharmony_ci vbuf = strndup_user((const char __user *)arg, FSLABEL_MAX); 338962306a36Sopenharmony_ci if (IS_ERR(vbuf)) 339062306a36Sopenharmony_ci return PTR_ERR(vbuf); 339162306a36Sopenharmony_ci 339262306a36Sopenharmony_ci err = mnt_want_write_file(filp); 339362306a36Sopenharmony_ci if (err) 339462306a36Sopenharmony_ci goto out; 339562306a36Sopenharmony_ci 339662306a36Sopenharmony_ci f2fs_down_write(&sbi->sb_lock); 339762306a36Sopenharmony_ci 339862306a36Sopenharmony_ci memset(sbi->raw_super->volume_name, 0, 339962306a36Sopenharmony_ci sizeof(sbi->raw_super->volume_name)); 340062306a36Sopenharmony_ci utf8s_to_utf16s(vbuf, strlen(vbuf), UTF16_LITTLE_ENDIAN, 340162306a36Sopenharmony_ci sbi->raw_super->volume_name, 340262306a36Sopenharmony_ci ARRAY_SIZE(sbi->raw_super->volume_name)); 340362306a36Sopenharmony_ci 340462306a36Sopenharmony_ci err = f2fs_commit_super(sbi, false); 340562306a36Sopenharmony_ci 340662306a36Sopenharmony_ci f2fs_up_write(&sbi->sb_lock); 340762306a36Sopenharmony_ci 340862306a36Sopenharmony_ci mnt_drop_write_file(filp); 340962306a36Sopenharmony_ciout: 341062306a36Sopenharmony_ci kfree(vbuf); 341162306a36Sopenharmony_ci return err; 341262306a36Sopenharmony_ci} 341362306a36Sopenharmony_ci 341462306a36Sopenharmony_cistatic int f2fs_get_compress_blocks(struct inode *inode, __u64 *blocks) 341562306a36Sopenharmony_ci{ 341662306a36Sopenharmony_ci if (!f2fs_sb_has_compression(F2FS_I_SB(inode))) 341762306a36Sopenharmony_ci return -EOPNOTSUPP; 341862306a36Sopenharmony_ci 341962306a36Sopenharmony_ci if (!f2fs_compressed_file(inode)) 342062306a36Sopenharmony_ci return -EINVAL; 342162306a36Sopenharmony_ci 342262306a36Sopenharmony_ci *blocks = atomic_read(&F2FS_I(inode)->i_compr_blocks); 342362306a36Sopenharmony_ci 342462306a36Sopenharmony_ci return 0; 342562306a36Sopenharmony_ci} 342662306a36Sopenharmony_ci 342762306a36Sopenharmony_cistatic int f2fs_ioc_get_compress_blocks(struct file *filp, unsigned long arg) 342862306a36Sopenharmony_ci{ 342962306a36Sopenharmony_ci struct inode *inode = file_inode(filp); 343062306a36Sopenharmony_ci __u64 blocks; 343162306a36Sopenharmony_ci int ret; 343262306a36Sopenharmony_ci 343362306a36Sopenharmony_ci ret = f2fs_get_compress_blocks(inode, &blocks); 343462306a36Sopenharmony_ci if (ret < 0) 343562306a36Sopenharmony_ci return ret; 343662306a36Sopenharmony_ci 343762306a36Sopenharmony_ci return put_user(blocks, (u64 __user *)arg); 343862306a36Sopenharmony_ci} 343962306a36Sopenharmony_ci 344062306a36Sopenharmony_cistatic int release_compress_blocks(struct dnode_of_data *dn, pgoff_t count) 344162306a36Sopenharmony_ci{ 344262306a36Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_I_SB(dn->inode); 344362306a36Sopenharmony_ci unsigned int released_blocks = 0; 344462306a36Sopenharmony_ci int cluster_size = F2FS_I(dn->inode)->i_cluster_size; 344562306a36Sopenharmony_ci block_t blkaddr; 344662306a36Sopenharmony_ci int i; 344762306a36Sopenharmony_ci 344862306a36Sopenharmony_ci for (i = 0; i < count; i++) { 344962306a36Sopenharmony_ci blkaddr = data_blkaddr(dn->inode, dn->node_page, 345062306a36Sopenharmony_ci dn->ofs_in_node + i); 345162306a36Sopenharmony_ci 345262306a36Sopenharmony_ci if (!__is_valid_data_blkaddr(blkaddr)) 345362306a36Sopenharmony_ci continue; 345462306a36Sopenharmony_ci if (unlikely(!f2fs_is_valid_blkaddr(sbi, blkaddr, 345562306a36Sopenharmony_ci DATA_GENERIC_ENHANCE))) { 345662306a36Sopenharmony_ci f2fs_handle_error(sbi, ERROR_INVALID_BLKADDR); 345762306a36Sopenharmony_ci return -EFSCORRUPTED; 345862306a36Sopenharmony_ci } 345962306a36Sopenharmony_ci } 346062306a36Sopenharmony_ci 346162306a36Sopenharmony_ci while (count) { 346262306a36Sopenharmony_ci int compr_blocks = 0; 346362306a36Sopenharmony_ci 346462306a36Sopenharmony_ci for (i = 0; i < cluster_size; i++, dn->ofs_in_node++) { 346562306a36Sopenharmony_ci blkaddr = f2fs_data_blkaddr(dn); 346662306a36Sopenharmony_ci 346762306a36Sopenharmony_ci if (i == 0) { 346862306a36Sopenharmony_ci if (blkaddr == COMPRESS_ADDR) 346962306a36Sopenharmony_ci continue; 347062306a36Sopenharmony_ci dn->ofs_in_node += cluster_size; 347162306a36Sopenharmony_ci goto next; 347262306a36Sopenharmony_ci } 347362306a36Sopenharmony_ci 347462306a36Sopenharmony_ci if (__is_valid_data_blkaddr(blkaddr)) 347562306a36Sopenharmony_ci compr_blocks++; 347662306a36Sopenharmony_ci 347762306a36Sopenharmony_ci if (blkaddr != NEW_ADDR) 347862306a36Sopenharmony_ci continue; 347962306a36Sopenharmony_ci 348062306a36Sopenharmony_ci f2fs_set_data_blkaddr(dn, NULL_ADDR); 348162306a36Sopenharmony_ci } 348262306a36Sopenharmony_ci 348362306a36Sopenharmony_ci f2fs_i_compr_blocks_update(dn->inode, compr_blocks, false); 348462306a36Sopenharmony_ci dec_valid_block_count(sbi, dn->inode, 348562306a36Sopenharmony_ci cluster_size - compr_blocks); 348662306a36Sopenharmony_ci 348762306a36Sopenharmony_ci released_blocks += cluster_size - compr_blocks; 348862306a36Sopenharmony_cinext: 348962306a36Sopenharmony_ci count -= cluster_size; 349062306a36Sopenharmony_ci } 349162306a36Sopenharmony_ci 349262306a36Sopenharmony_ci return released_blocks; 349362306a36Sopenharmony_ci} 349462306a36Sopenharmony_ci 349562306a36Sopenharmony_cistatic int f2fs_release_compress_blocks(struct file *filp, unsigned long arg) 349662306a36Sopenharmony_ci{ 349762306a36Sopenharmony_ci struct inode *inode = file_inode(filp); 349862306a36Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_I_SB(inode); 349962306a36Sopenharmony_ci pgoff_t page_idx = 0, last_idx; 350062306a36Sopenharmony_ci unsigned int released_blocks = 0; 350162306a36Sopenharmony_ci int ret; 350262306a36Sopenharmony_ci int writecount; 350362306a36Sopenharmony_ci 350462306a36Sopenharmony_ci if (!f2fs_sb_has_compression(sbi)) 350562306a36Sopenharmony_ci return -EOPNOTSUPP; 350662306a36Sopenharmony_ci 350762306a36Sopenharmony_ci if (!f2fs_compressed_file(inode)) 350862306a36Sopenharmony_ci return -EINVAL; 350962306a36Sopenharmony_ci 351062306a36Sopenharmony_ci if (f2fs_readonly(sbi->sb)) 351162306a36Sopenharmony_ci return -EROFS; 351262306a36Sopenharmony_ci 351362306a36Sopenharmony_ci ret = mnt_want_write_file(filp); 351462306a36Sopenharmony_ci if (ret) 351562306a36Sopenharmony_ci return ret; 351662306a36Sopenharmony_ci 351762306a36Sopenharmony_ci f2fs_balance_fs(sbi, true); 351862306a36Sopenharmony_ci 351962306a36Sopenharmony_ci inode_lock(inode); 352062306a36Sopenharmony_ci 352162306a36Sopenharmony_ci writecount = atomic_read(&inode->i_writecount); 352262306a36Sopenharmony_ci if ((filp->f_mode & FMODE_WRITE && writecount != 1) || 352362306a36Sopenharmony_ci (!(filp->f_mode & FMODE_WRITE) && writecount)) { 352462306a36Sopenharmony_ci ret = -EBUSY; 352562306a36Sopenharmony_ci goto out; 352662306a36Sopenharmony_ci } 352762306a36Sopenharmony_ci 352862306a36Sopenharmony_ci if (is_inode_flag_set(inode, FI_COMPRESS_RELEASED)) { 352962306a36Sopenharmony_ci ret = -EINVAL; 353062306a36Sopenharmony_ci goto out; 353162306a36Sopenharmony_ci } 353262306a36Sopenharmony_ci 353362306a36Sopenharmony_ci ret = filemap_write_and_wait_range(inode->i_mapping, 0, LLONG_MAX); 353462306a36Sopenharmony_ci if (ret) 353562306a36Sopenharmony_ci goto out; 353662306a36Sopenharmony_ci 353762306a36Sopenharmony_ci if (!atomic_read(&F2FS_I(inode)->i_compr_blocks)) { 353862306a36Sopenharmony_ci ret = -EPERM; 353962306a36Sopenharmony_ci goto out; 354062306a36Sopenharmony_ci } 354162306a36Sopenharmony_ci 354262306a36Sopenharmony_ci set_inode_flag(inode, FI_COMPRESS_RELEASED); 354362306a36Sopenharmony_ci inode_set_ctime_current(inode); 354462306a36Sopenharmony_ci f2fs_mark_inode_dirty_sync(inode, true); 354562306a36Sopenharmony_ci 354662306a36Sopenharmony_ci f2fs_down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]); 354762306a36Sopenharmony_ci filemap_invalidate_lock(inode->i_mapping); 354862306a36Sopenharmony_ci 354962306a36Sopenharmony_ci last_idx = DIV_ROUND_UP(i_size_read(inode), PAGE_SIZE); 355062306a36Sopenharmony_ci 355162306a36Sopenharmony_ci while (page_idx < last_idx) { 355262306a36Sopenharmony_ci struct dnode_of_data dn; 355362306a36Sopenharmony_ci pgoff_t end_offset, count; 355462306a36Sopenharmony_ci 355562306a36Sopenharmony_ci set_new_dnode(&dn, inode, NULL, NULL, 0); 355662306a36Sopenharmony_ci ret = f2fs_get_dnode_of_data(&dn, page_idx, LOOKUP_NODE); 355762306a36Sopenharmony_ci if (ret) { 355862306a36Sopenharmony_ci if (ret == -ENOENT) { 355962306a36Sopenharmony_ci page_idx = f2fs_get_next_page_offset(&dn, 356062306a36Sopenharmony_ci page_idx); 356162306a36Sopenharmony_ci ret = 0; 356262306a36Sopenharmony_ci continue; 356362306a36Sopenharmony_ci } 356462306a36Sopenharmony_ci break; 356562306a36Sopenharmony_ci } 356662306a36Sopenharmony_ci 356762306a36Sopenharmony_ci end_offset = ADDRS_PER_PAGE(dn.node_page, inode); 356862306a36Sopenharmony_ci count = min(end_offset - dn.ofs_in_node, last_idx - page_idx); 356962306a36Sopenharmony_ci count = round_up(count, F2FS_I(inode)->i_cluster_size); 357062306a36Sopenharmony_ci 357162306a36Sopenharmony_ci ret = release_compress_blocks(&dn, count); 357262306a36Sopenharmony_ci 357362306a36Sopenharmony_ci f2fs_put_dnode(&dn); 357462306a36Sopenharmony_ci 357562306a36Sopenharmony_ci if (ret < 0) 357662306a36Sopenharmony_ci break; 357762306a36Sopenharmony_ci 357862306a36Sopenharmony_ci page_idx += count; 357962306a36Sopenharmony_ci released_blocks += ret; 358062306a36Sopenharmony_ci } 358162306a36Sopenharmony_ci 358262306a36Sopenharmony_ci filemap_invalidate_unlock(inode->i_mapping); 358362306a36Sopenharmony_ci f2fs_up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]); 358462306a36Sopenharmony_ciout: 358562306a36Sopenharmony_ci inode_unlock(inode); 358662306a36Sopenharmony_ci 358762306a36Sopenharmony_ci mnt_drop_write_file(filp); 358862306a36Sopenharmony_ci 358962306a36Sopenharmony_ci if (ret >= 0) { 359062306a36Sopenharmony_ci ret = put_user(released_blocks, (u64 __user *)arg); 359162306a36Sopenharmony_ci } else if (released_blocks && 359262306a36Sopenharmony_ci atomic_read(&F2FS_I(inode)->i_compr_blocks)) { 359362306a36Sopenharmony_ci set_sbi_flag(sbi, SBI_NEED_FSCK); 359462306a36Sopenharmony_ci f2fs_warn(sbi, "%s: partial blocks were released i_ino=%lx " 359562306a36Sopenharmony_ci "iblocks=%llu, released=%u, compr_blocks=%u, " 359662306a36Sopenharmony_ci "run fsck to fix.", 359762306a36Sopenharmony_ci __func__, inode->i_ino, inode->i_blocks, 359862306a36Sopenharmony_ci released_blocks, 359962306a36Sopenharmony_ci atomic_read(&F2FS_I(inode)->i_compr_blocks)); 360062306a36Sopenharmony_ci } 360162306a36Sopenharmony_ci 360262306a36Sopenharmony_ci return ret; 360362306a36Sopenharmony_ci} 360462306a36Sopenharmony_ci 360562306a36Sopenharmony_cistatic int reserve_compress_blocks(struct dnode_of_data *dn, pgoff_t count, 360662306a36Sopenharmony_ci unsigned int *reserved_blocks) 360762306a36Sopenharmony_ci{ 360862306a36Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_I_SB(dn->inode); 360962306a36Sopenharmony_ci int cluster_size = F2FS_I(dn->inode)->i_cluster_size; 361062306a36Sopenharmony_ci block_t blkaddr; 361162306a36Sopenharmony_ci int i; 361262306a36Sopenharmony_ci 361362306a36Sopenharmony_ci for (i = 0; i < count; i++) { 361462306a36Sopenharmony_ci blkaddr = data_blkaddr(dn->inode, dn->node_page, 361562306a36Sopenharmony_ci dn->ofs_in_node + i); 361662306a36Sopenharmony_ci 361762306a36Sopenharmony_ci if (!__is_valid_data_blkaddr(blkaddr)) 361862306a36Sopenharmony_ci continue; 361962306a36Sopenharmony_ci if (unlikely(!f2fs_is_valid_blkaddr(sbi, blkaddr, 362062306a36Sopenharmony_ci DATA_GENERIC_ENHANCE))) { 362162306a36Sopenharmony_ci f2fs_handle_error(sbi, ERROR_INVALID_BLKADDR); 362262306a36Sopenharmony_ci return -EFSCORRUPTED; 362362306a36Sopenharmony_ci } 362462306a36Sopenharmony_ci } 362562306a36Sopenharmony_ci 362662306a36Sopenharmony_ci while (count) { 362762306a36Sopenharmony_ci int compr_blocks = 0; 362862306a36Sopenharmony_ci blkcnt_t reserved; 362962306a36Sopenharmony_ci int ret; 363062306a36Sopenharmony_ci 363162306a36Sopenharmony_ci for (i = 0; i < cluster_size; i++) { 363262306a36Sopenharmony_ci blkaddr = data_blkaddr(dn->inode, dn->node_page, 363362306a36Sopenharmony_ci dn->ofs_in_node + i); 363462306a36Sopenharmony_ci 363562306a36Sopenharmony_ci if (i == 0) { 363662306a36Sopenharmony_ci if (blkaddr != COMPRESS_ADDR) { 363762306a36Sopenharmony_ci dn->ofs_in_node += cluster_size; 363862306a36Sopenharmony_ci goto next; 363962306a36Sopenharmony_ci } 364062306a36Sopenharmony_ci continue; 364162306a36Sopenharmony_ci } 364262306a36Sopenharmony_ci 364362306a36Sopenharmony_ci /* 364462306a36Sopenharmony_ci * compressed cluster was not released due to it 364562306a36Sopenharmony_ci * fails in release_compress_blocks(), so NEW_ADDR 364662306a36Sopenharmony_ci * is a possible case. 364762306a36Sopenharmony_ci */ 364862306a36Sopenharmony_ci if (blkaddr == NEW_ADDR || 364962306a36Sopenharmony_ci __is_valid_data_blkaddr(blkaddr)) { 365062306a36Sopenharmony_ci compr_blocks++; 365162306a36Sopenharmony_ci continue; 365262306a36Sopenharmony_ci } 365362306a36Sopenharmony_ci } 365462306a36Sopenharmony_ci 365562306a36Sopenharmony_ci reserved = cluster_size - compr_blocks; 365662306a36Sopenharmony_ci 365762306a36Sopenharmony_ci /* for the case all blocks in cluster were reserved */ 365862306a36Sopenharmony_ci if (reserved == 1) 365962306a36Sopenharmony_ci goto next; 366062306a36Sopenharmony_ci 366162306a36Sopenharmony_ci ret = inc_valid_block_count(sbi, dn->inode, &reserved, false); 366262306a36Sopenharmony_ci if (unlikely(ret)) 366362306a36Sopenharmony_ci return ret; 366462306a36Sopenharmony_ci 366562306a36Sopenharmony_ci for (i = 0; i < cluster_size; i++, dn->ofs_in_node++) { 366662306a36Sopenharmony_ci if (f2fs_data_blkaddr(dn) == NULL_ADDR) 366762306a36Sopenharmony_ci f2fs_set_data_blkaddr(dn, NEW_ADDR); 366862306a36Sopenharmony_ci } 366962306a36Sopenharmony_ci 367062306a36Sopenharmony_ci f2fs_i_compr_blocks_update(dn->inode, compr_blocks, true); 367162306a36Sopenharmony_ci 367262306a36Sopenharmony_ci *reserved_blocks += reserved; 367362306a36Sopenharmony_cinext: 367462306a36Sopenharmony_ci count -= cluster_size; 367562306a36Sopenharmony_ci } 367662306a36Sopenharmony_ci 367762306a36Sopenharmony_ci return 0; 367862306a36Sopenharmony_ci} 367962306a36Sopenharmony_ci 368062306a36Sopenharmony_cistatic int f2fs_reserve_compress_blocks(struct file *filp, unsigned long arg) 368162306a36Sopenharmony_ci{ 368262306a36Sopenharmony_ci struct inode *inode = file_inode(filp); 368362306a36Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_I_SB(inode); 368462306a36Sopenharmony_ci pgoff_t page_idx = 0, last_idx; 368562306a36Sopenharmony_ci unsigned int reserved_blocks = 0; 368662306a36Sopenharmony_ci int ret; 368762306a36Sopenharmony_ci 368862306a36Sopenharmony_ci if (!f2fs_sb_has_compression(sbi)) 368962306a36Sopenharmony_ci return -EOPNOTSUPP; 369062306a36Sopenharmony_ci 369162306a36Sopenharmony_ci if (!f2fs_compressed_file(inode)) 369262306a36Sopenharmony_ci return -EINVAL; 369362306a36Sopenharmony_ci 369462306a36Sopenharmony_ci if (f2fs_readonly(sbi->sb)) 369562306a36Sopenharmony_ci return -EROFS; 369662306a36Sopenharmony_ci 369762306a36Sopenharmony_ci ret = mnt_want_write_file(filp); 369862306a36Sopenharmony_ci if (ret) 369962306a36Sopenharmony_ci return ret; 370062306a36Sopenharmony_ci 370162306a36Sopenharmony_ci f2fs_balance_fs(sbi, true); 370262306a36Sopenharmony_ci 370362306a36Sopenharmony_ci inode_lock(inode); 370462306a36Sopenharmony_ci 370562306a36Sopenharmony_ci if (!is_inode_flag_set(inode, FI_COMPRESS_RELEASED)) { 370662306a36Sopenharmony_ci ret = -EINVAL; 370762306a36Sopenharmony_ci goto unlock_inode; 370862306a36Sopenharmony_ci } 370962306a36Sopenharmony_ci 371062306a36Sopenharmony_ci if (atomic_read(&F2FS_I(inode)->i_compr_blocks)) 371162306a36Sopenharmony_ci goto unlock_inode; 371262306a36Sopenharmony_ci 371362306a36Sopenharmony_ci f2fs_down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]); 371462306a36Sopenharmony_ci filemap_invalidate_lock(inode->i_mapping); 371562306a36Sopenharmony_ci 371662306a36Sopenharmony_ci last_idx = DIV_ROUND_UP(i_size_read(inode), PAGE_SIZE); 371762306a36Sopenharmony_ci 371862306a36Sopenharmony_ci while (page_idx < last_idx) { 371962306a36Sopenharmony_ci struct dnode_of_data dn; 372062306a36Sopenharmony_ci pgoff_t end_offset, count; 372162306a36Sopenharmony_ci 372262306a36Sopenharmony_ci set_new_dnode(&dn, inode, NULL, NULL, 0); 372362306a36Sopenharmony_ci ret = f2fs_get_dnode_of_data(&dn, page_idx, LOOKUP_NODE); 372462306a36Sopenharmony_ci if (ret) { 372562306a36Sopenharmony_ci if (ret == -ENOENT) { 372662306a36Sopenharmony_ci page_idx = f2fs_get_next_page_offset(&dn, 372762306a36Sopenharmony_ci page_idx); 372862306a36Sopenharmony_ci ret = 0; 372962306a36Sopenharmony_ci continue; 373062306a36Sopenharmony_ci } 373162306a36Sopenharmony_ci break; 373262306a36Sopenharmony_ci } 373362306a36Sopenharmony_ci 373462306a36Sopenharmony_ci end_offset = ADDRS_PER_PAGE(dn.node_page, inode); 373562306a36Sopenharmony_ci count = min(end_offset - dn.ofs_in_node, last_idx - page_idx); 373662306a36Sopenharmony_ci count = round_up(count, F2FS_I(inode)->i_cluster_size); 373762306a36Sopenharmony_ci 373862306a36Sopenharmony_ci ret = reserve_compress_blocks(&dn, count, &reserved_blocks); 373962306a36Sopenharmony_ci 374062306a36Sopenharmony_ci f2fs_put_dnode(&dn); 374162306a36Sopenharmony_ci 374262306a36Sopenharmony_ci if (ret < 0) 374362306a36Sopenharmony_ci break; 374462306a36Sopenharmony_ci 374562306a36Sopenharmony_ci page_idx += count; 374662306a36Sopenharmony_ci } 374762306a36Sopenharmony_ci 374862306a36Sopenharmony_ci filemap_invalidate_unlock(inode->i_mapping); 374962306a36Sopenharmony_ci f2fs_up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]); 375062306a36Sopenharmony_ci 375162306a36Sopenharmony_ci if (!ret) { 375262306a36Sopenharmony_ci clear_inode_flag(inode, FI_COMPRESS_RELEASED); 375362306a36Sopenharmony_ci inode_set_ctime_current(inode); 375462306a36Sopenharmony_ci f2fs_mark_inode_dirty_sync(inode, true); 375562306a36Sopenharmony_ci } 375662306a36Sopenharmony_ciunlock_inode: 375762306a36Sopenharmony_ci inode_unlock(inode); 375862306a36Sopenharmony_ci mnt_drop_write_file(filp); 375962306a36Sopenharmony_ci 376062306a36Sopenharmony_ci if (!ret) { 376162306a36Sopenharmony_ci ret = put_user(reserved_blocks, (u64 __user *)arg); 376262306a36Sopenharmony_ci } else if (reserved_blocks && 376362306a36Sopenharmony_ci atomic_read(&F2FS_I(inode)->i_compr_blocks)) { 376462306a36Sopenharmony_ci set_sbi_flag(sbi, SBI_NEED_FSCK); 376562306a36Sopenharmony_ci f2fs_warn(sbi, "%s: partial blocks were released i_ino=%lx " 376662306a36Sopenharmony_ci "iblocks=%llu, reserved=%u, compr_blocks=%u, " 376762306a36Sopenharmony_ci "run fsck to fix.", 376862306a36Sopenharmony_ci __func__, inode->i_ino, inode->i_blocks, 376962306a36Sopenharmony_ci reserved_blocks, 377062306a36Sopenharmony_ci atomic_read(&F2FS_I(inode)->i_compr_blocks)); 377162306a36Sopenharmony_ci } 377262306a36Sopenharmony_ci 377362306a36Sopenharmony_ci return ret; 377462306a36Sopenharmony_ci} 377562306a36Sopenharmony_ci 377662306a36Sopenharmony_cistatic int f2fs_secure_erase(struct block_device *bdev, struct inode *inode, 377762306a36Sopenharmony_ci pgoff_t off, block_t block, block_t len, u32 flags) 377862306a36Sopenharmony_ci{ 377962306a36Sopenharmony_ci sector_t sector = SECTOR_FROM_BLOCK(block); 378062306a36Sopenharmony_ci sector_t nr_sects = SECTOR_FROM_BLOCK(len); 378162306a36Sopenharmony_ci int ret = 0; 378262306a36Sopenharmony_ci 378362306a36Sopenharmony_ci if (flags & F2FS_TRIM_FILE_DISCARD) { 378462306a36Sopenharmony_ci if (bdev_max_secure_erase_sectors(bdev)) 378562306a36Sopenharmony_ci ret = blkdev_issue_secure_erase(bdev, sector, nr_sects, 378662306a36Sopenharmony_ci GFP_NOFS); 378762306a36Sopenharmony_ci else 378862306a36Sopenharmony_ci ret = blkdev_issue_discard(bdev, sector, nr_sects, 378962306a36Sopenharmony_ci GFP_NOFS); 379062306a36Sopenharmony_ci } 379162306a36Sopenharmony_ci 379262306a36Sopenharmony_ci if (!ret && (flags & F2FS_TRIM_FILE_ZEROOUT)) { 379362306a36Sopenharmony_ci if (IS_ENCRYPTED(inode)) 379462306a36Sopenharmony_ci ret = fscrypt_zeroout_range(inode, off, block, len); 379562306a36Sopenharmony_ci else 379662306a36Sopenharmony_ci ret = blkdev_issue_zeroout(bdev, sector, nr_sects, 379762306a36Sopenharmony_ci GFP_NOFS, 0); 379862306a36Sopenharmony_ci } 379962306a36Sopenharmony_ci 380062306a36Sopenharmony_ci return ret; 380162306a36Sopenharmony_ci} 380262306a36Sopenharmony_ci 380362306a36Sopenharmony_cistatic int f2fs_sec_trim_file(struct file *filp, unsigned long arg) 380462306a36Sopenharmony_ci{ 380562306a36Sopenharmony_ci struct inode *inode = file_inode(filp); 380662306a36Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_I_SB(inode); 380762306a36Sopenharmony_ci struct address_space *mapping = inode->i_mapping; 380862306a36Sopenharmony_ci struct block_device *prev_bdev = NULL; 380962306a36Sopenharmony_ci struct f2fs_sectrim_range range; 381062306a36Sopenharmony_ci pgoff_t index, pg_end, prev_index = 0; 381162306a36Sopenharmony_ci block_t prev_block = 0, len = 0; 381262306a36Sopenharmony_ci loff_t end_addr; 381362306a36Sopenharmony_ci bool to_end = false; 381462306a36Sopenharmony_ci int ret = 0; 381562306a36Sopenharmony_ci 381662306a36Sopenharmony_ci if (!(filp->f_mode & FMODE_WRITE)) 381762306a36Sopenharmony_ci return -EBADF; 381862306a36Sopenharmony_ci 381962306a36Sopenharmony_ci if (copy_from_user(&range, (struct f2fs_sectrim_range __user *)arg, 382062306a36Sopenharmony_ci sizeof(range))) 382162306a36Sopenharmony_ci return -EFAULT; 382262306a36Sopenharmony_ci 382362306a36Sopenharmony_ci if (range.flags == 0 || (range.flags & ~F2FS_TRIM_FILE_MASK) || 382462306a36Sopenharmony_ci !S_ISREG(inode->i_mode)) 382562306a36Sopenharmony_ci return -EINVAL; 382662306a36Sopenharmony_ci 382762306a36Sopenharmony_ci if (((range.flags & F2FS_TRIM_FILE_DISCARD) && 382862306a36Sopenharmony_ci !f2fs_hw_support_discard(sbi)) || 382962306a36Sopenharmony_ci ((range.flags & F2FS_TRIM_FILE_ZEROOUT) && 383062306a36Sopenharmony_ci IS_ENCRYPTED(inode) && f2fs_is_multi_device(sbi))) 383162306a36Sopenharmony_ci return -EOPNOTSUPP; 383262306a36Sopenharmony_ci 383362306a36Sopenharmony_ci file_start_write(filp); 383462306a36Sopenharmony_ci inode_lock(inode); 383562306a36Sopenharmony_ci 383662306a36Sopenharmony_ci if (f2fs_is_atomic_file(inode) || f2fs_compressed_file(inode) || 383762306a36Sopenharmony_ci range.start >= inode->i_size) { 383862306a36Sopenharmony_ci ret = -EINVAL; 383962306a36Sopenharmony_ci goto err; 384062306a36Sopenharmony_ci } 384162306a36Sopenharmony_ci 384262306a36Sopenharmony_ci if (range.len == 0) 384362306a36Sopenharmony_ci goto err; 384462306a36Sopenharmony_ci 384562306a36Sopenharmony_ci if (inode->i_size - range.start > range.len) { 384662306a36Sopenharmony_ci end_addr = range.start + range.len; 384762306a36Sopenharmony_ci } else { 384862306a36Sopenharmony_ci end_addr = range.len == (u64)-1 ? 384962306a36Sopenharmony_ci sbi->sb->s_maxbytes : inode->i_size; 385062306a36Sopenharmony_ci to_end = true; 385162306a36Sopenharmony_ci } 385262306a36Sopenharmony_ci 385362306a36Sopenharmony_ci if (!IS_ALIGNED(range.start, F2FS_BLKSIZE) || 385462306a36Sopenharmony_ci (!to_end && !IS_ALIGNED(end_addr, F2FS_BLKSIZE))) { 385562306a36Sopenharmony_ci ret = -EINVAL; 385662306a36Sopenharmony_ci goto err; 385762306a36Sopenharmony_ci } 385862306a36Sopenharmony_ci 385962306a36Sopenharmony_ci index = F2FS_BYTES_TO_BLK(range.start); 386062306a36Sopenharmony_ci pg_end = DIV_ROUND_UP(end_addr, F2FS_BLKSIZE); 386162306a36Sopenharmony_ci 386262306a36Sopenharmony_ci ret = f2fs_convert_inline_inode(inode); 386362306a36Sopenharmony_ci if (ret) 386462306a36Sopenharmony_ci goto err; 386562306a36Sopenharmony_ci 386662306a36Sopenharmony_ci f2fs_down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]); 386762306a36Sopenharmony_ci filemap_invalidate_lock(mapping); 386862306a36Sopenharmony_ci 386962306a36Sopenharmony_ci ret = filemap_write_and_wait_range(mapping, range.start, 387062306a36Sopenharmony_ci to_end ? LLONG_MAX : end_addr - 1); 387162306a36Sopenharmony_ci if (ret) 387262306a36Sopenharmony_ci goto out; 387362306a36Sopenharmony_ci 387462306a36Sopenharmony_ci truncate_inode_pages_range(mapping, range.start, 387562306a36Sopenharmony_ci to_end ? -1 : end_addr - 1); 387662306a36Sopenharmony_ci 387762306a36Sopenharmony_ci while (index < pg_end) { 387862306a36Sopenharmony_ci struct dnode_of_data dn; 387962306a36Sopenharmony_ci pgoff_t end_offset, count; 388062306a36Sopenharmony_ci int i; 388162306a36Sopenharmony_ci 388262306a36Sopenharmony_ci set_new_dnode(&dn, inode, NULL, NULL, 0); 388362306a36Sopenharmony_ci ret = f2fs_get_dnode_of_data(&dn, index, LOOKUP_NODE); 388462306a36Sopenharmony_ci if (ret) { 388562306a36Sopenharmony_ci if (ret == -ENOENT) { 388662306a36Sopenharmony_ci index = f2fs_get_next_page_offset(&dn, index); 388762306a36Sopenharmony_ci continue; 388862306a36Sopenharmony_ci } 388962306a36Sopenharmony_ci goto out; 389062306a36Sopenharmony_ci } 389162306a36Sopenharmony_ci 389262306a36Sopenharmony_ci end_offset = ADDRS_PER_PAGE(dn.node_page, inode); 389362306a36Sopenharmony_ci count = min(end_offset - dn.ofs_in_node, pg_end - index); 389462306a36Sopenharmony_ci for (i = 0; i < count; i++, index++, dn.ofs_in_node++) { 389562306a36Sopenharmony_ci struct block_device *cur_bdev; 389662306a36Sopenharmony_ci block_t blkaddr = f2fs_data_blkaddr(&dn); 389762306a36Sopenharmony_ci 389862306a36Sopenharmony_ci if (!__is_valid_data_blkaddr(blkaddr)) 389962306a36Sopenharmony_ci continue; 390062306a36Sopenharmony_ci 390162306a36Sopenharmony_ci if (!f2fs_is_valid_blkaddr(sbi, blkaddr, 390262306a36Sopenharmony_ci DATA_GENERIC_ENHANCE)) { 390362306a36Sopenharmony_ci ret = -EFSCORRUPTED; 390462306a36Sopenharmony_ci f2fs_put_dnode(&dn); 390562306a36Sopenharmony_ci f2fs_handle_error(sbi, 390662306a36Sopenharmony_ci ERROR_INVALID_BLKADDR); 390762306a36Sopenharmony_ci goto out; 390862306a36Sopenharmony_ci } 390962306a36Sopenharmony_ci 391062306a36Sopenharmony_ci cur_bdev = f2fs_target_device(sbi, blkaddr, NULL); 391162306a36Sopenharmony_ci if (f2fs_is_multi_device(sbi)) { 391262306a36Sopenharmony_ci int di = f2fs_target_device_index(sbi, blkaddr); 391362306a36Sopenharmony_ci 391462306a36Sopenharmony_ci blkaddr -= FDEV(di).start_blk; 391562306a36Sopenharmony_ci } 391662306a36Sopenharmony_ci 391762306a36Sopenharmony_ci if (len) { 391862306a36Sopenharmony_ci if (prev_bdev == cur_bdev && 391962306a36Sopenharmony_ci index == prev_index + len && 392062306a36Sopenharmony_ci blkaddr == prev_block + len) { 392162306a36Sopenharmony_ci len++; 392262306a36Sopenharmony_ci } else { 392362306a36Sopenharmony_ci ret = f2fs_secure_erase(prev_bdev, 392462306a36Sopenharmony_ci inode, prev_index, prev_block, 392562306a36Sopenharmony_ci len, range.flags); 392662306a36Sopenharmony_ci if (ret) { 392762306a36Sopenharmony_ci f2fs_put_dnode(&dn); 392862306a36Sopenharmony_ci goto out; 392962306a36Sopenharmony_ci } 393062306a36Sopenharmony_ci 393162306a36Sopenharmony_ci len = 0; 393262306a36Sopenharmony_ci } 393362306a36Sopenharmony_ci } 393462306a36Sopenharmony_ci 393562306a36Sopenharmony_ci if (!len) { 393662306a36Sopenharmony_ci prev_bdev = cur_bdev; 393762306a36Sopenharmony_ci prev_index = index; 393862306a36Sopenharmony_ci prev_block = blkaddr; 393962306a36Sopenharmony_ci len = 1; 394062306a36Sopenharmony_ci } 394162306a36Sopenharmony_ci } 394262306a36Sopenharmony_ci 394362306a36Sopenharmony_ci f2fs_put_dnode(&dn); 394462306a36Sopenharmony_ci 394562306a36Sopenharmony_ci if (fatal_signal_pending(current)) { 394662306a36Sopenharmony_ci ret = -EINTR; 394762306a36Sopenharmony_ci goto out; 394862306a36Sopenharmony_ci } 394962306a36Sopenharmony_ci cond_resched(); 395062306a36Sopenharmony_ci } 395162306a36Sopenharmony_ci 395262306a36Sopenharmony_ci if (len) 395362306a36Sopenharmony_ci ret = f2fs_secure_erase(prev_bdev, inode, prev_index, 395462306a36Sopenharmony_ci prev_block, len, range.flags); 395562306a36Sopenharmony_ciout: 395662306a36Sopenharmony_ci filemap_invalidate_unlock(mapping); 395762306a36Sopenharmony_ci f2fs_up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]); 395862306a36Sopenharmony_cierr: 395962306a36Sopenharmony_ci inode_unlock(inode); 396062306a36Sopenharmony_ci file_end_write(filp); 396162306a36Sopenharmony_ci 396262306a36Sopenharmony_ci return ret; 396362306a36Sopenharmony_ci} 396462306a36Sopenharmony_ci 396562306a36Sopenharmony_cistatic int f2fs_ioc_get_compress_option(struct file *filp, unsigned long arg) 396662306a36Sopenharmony_ci{ 396762306a36Sopenharmony_ci struct inode *inode = file_inode(filp); 396862306a36Sopenharmony_ci struct f2fs_comp_option option; 396962306a36Sopenharmony_ci 397062306a36Sopenharmony_ci if (!f2fs_sb_has_compression(F2FS_I_SB(inode))) 397162306a36Sopenharmony_ci return -EOPNOTSUPP; 397262306a36Sopenharmony_ci 397362306a36Sopenharmony_ci inode_lock_shared(inode); 397462306a36Sopenharmony_ci 397562306a36Sopenharmony_ci if (!f2fs_compressed_file(inode)) { 397662306a36Sopenharmony_ci inode_unlock_shared(inode); 397762306a36Sopenharmony_ci return -ENODATA; 397862306a36Sopenharmony_ci } 397962306a36Sopenharmony_ci 398062306a36Sopenharmony_ci option.algorithm = F2FS_I(inode)->i_compress_algorithm; 398162306a36Sopenharmony_ci option.log_cluster_size = F2FS_I(inode)->i_log_cluster_size; 398262306a36Sopenharmony_ci 398362306a36Sopenharmony_ci inode_unlock_shared(inode); 398462306a36Sopenharmony_ci 398562306a36Sopenharmony_ci if (copy_to_user((struct f2fs_comp_option __user *)arg, &option, 398662306a36Sopenharmony_ci sizeof(option))) 398762306a36Sopenharmony_ci return -EFAULT; 398862306a36Sopenharmony_ci 398962306a36Sopenharmony_ci return 0; 399062306a36Sopenharmony_ci} 399162306a36Sopenharmony_ci 399262306a36Sopenharmony_cistatic int f2fs_ioc_set_compress_option(struct file *filp, unsigned long arg) 399362306a36Sopenharmony_ci{ 399462306a36Sopenharmony_ci struct inode *inode = file_inode(filp); 399562306a36Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_I_SB(inode); 399662306a36Sopenharmony_ci struct f2fs_comp_option option; 399762306a36Sopenharmony_ci int ret = 0; 399862306a36Sopenharmony_ci 399962306a36Sopenharmony_ci if (!f2fs_sb_has_compression(sbi)) 400062306a36Sopenharmony_ci return -EOPNOTSUPP; 400162306a36Sopenharmony_ci 400262306a36Sopenharmony_ci if (!(filp->f_mode & FMODE_WRITE)) 400362306a36Sopenharmony_ci return -EBADF; 400462306a36Sopenharmony_ci 400562306a36Sopenharmony_ci if (copy_from_user(&option, (struct f2fs_comp_option __user *)arg, 400662306a36Sopenharmony_ci sizeof(option))) 400762306a36Sopenharmony_ci return -EFAULT; 400862306a36Sopenharmony_ci 400962306a36Sopenharmony_ci if (option.log_cluster_size < MIN_COMPRESS_LOG_SIZE || 401062306a36Sopenharmony_ci option.log_cluster_size > MAX_COMPRESS_LOG_SIZE || 401162306a36Sopenharmony_ci option.algorithm >= COMPRESS_MAX) 401262306a36Sopenharmony_ci return -EINVAL; 401362306a36Sopenharmony_ci 401462306a36Sopenharmony_ci file_start_write(filp); 401562306a36Sopenharmony_ci inode_lock(inode); 401662306a36Sopenharmony_ci 401762306a36Sopenharmony_ci f2fs_down_write(&F2FS_I(inode)->i_sem); 401862306a36Sopenharmony_ci if (!f2fs_compressed_file(inode)) { 401962306a36Sopenharmony_ci ret = -EINVAL; 402062306a36Sopenharmony_ci goto out; 402162306a36Sopenharmony_ci } 402262306a36Sopenharmony_ci 402362306a36Sopenharmony_ci if (f2fs_is_mmap_file(inode) || get_dirty_pages(inode)) { 402462306a36Sopenharmony_ci ret = -EBUSY; 402562306a36Sopenharmony_ci goto out; 402662306a36Sopenharmony_ci } 402762306a36Sopenharmony_ci 402862306a36Sopenharmony_ci if (F2FS_HAS_BLOCKS(inode)) { 402962306a36Sopenharmony_ci ret = -EFBIG; 403062306a36Sopenharmony_ci goto out; 403162306a36Sopenharmony_ci } 403262306a36Sopenharmony_ci 403362306a36Sopenharmony_ci F2FS_I(inode)->i_compress_algorithm = option.algorithm; 403462306a36Sopenharmony_ci F2FS_I(inode)->i_log_cluster_size = option.log_cluster_size; 403562306a36Sopenharmony_ci F2FS_I(inode)->i_cluster_size = BIT(option.log_cluster_size); 403662306a36Sopenharmony_ci /* Set default level */ 403762306a36Sopenharmony_ci if (F2FS_I(inode)->i_compress_algorithm == COMPRESS_ZSTD) 403862306a36Sopenharmony_ci F2FS_I(inode)->i_compress_level = F2FS_ZSTD_DEFAULT_CLEVEL; 403962306a36Sopenharmony_ci else 404062306a36Sopenharmony_ci F2FS_I(inode)->i_compress_level = 0; 404162306a36Sopenharmony_ci /* Adjust mount option level */ 404262306a36Sopenharmony_ci if (option.algorithm == F2FS_OPTION(sbi).compress_algorithm && 404362306a36Sopenharmony_ci F2FS_OPTION(sbi).compress_level) 404462306a36Sopenharmony_ci F2FS_I(inode)->i_compress_level = F2FS_OPTION(sbi).compress_level; 404562306a36Sopenharmony_ci f2fs_mark_inode_dirty_sync(inode, true); 404662306a36Sopenharmony_ci 404762306a36Sopenharmony_ci if (!f2fs_is_compress_backend_ready(inode)) 404862306a36Sopenharmony_ci f2fs_warn(sbi, "compression algorithm is successfully set, " 404962306a36Sopenharmony_ci "but current kernel doesn't support this algorithm."); 405062306a36Sopenharmony_ciout: 405162306a36Sopenharmony_ci f2fs_up_write(&F2FS_I(inode)->i_sem); 405262306a36Sopenharmony_ci inode_unlock(inode); 405362306a36Sopenharmony_ci file_end_write(filp); 405462306a36Sopenharmony_ci 405562306a36Sopenharmony_ci return ret; 405662306a36Sopenharmony_ci} 405762306a36Sopenharmony_ci 405862306a36Sopenharmony_cistatic int redirty_blocks(struct inode *inode, pgoff_t page_idx, int len) 405962306a36Sopenharmony_ci{ 406062306a36Sopenharmony_ci DEFINE_READAHEAD(ractl, NULL, NULL, inode->i_mapping, page_idx); 406162306a36Sopenharmony_ci struct address_space *mapping = inode->i_mapping; 406262306a36Sopenharmony_ci struct page *page; 406362306a36Sopenharmony_ci pgoff_t redirty_idx = page_idx; 406462306a36Sopenharmony_ci int i, page_len = 0, ret = 0; 406562306a36Sopenharmony_ci 406662306a36Sopenharmony_ci page_cache_ra_unbounded(&ractl, len, 0); 406762306a36Sopenharmony_ci 406862306a36Sopenharmony_ci for (i = 0; i < len; i++, page_idx++) { 406962306a36Sopenharmony_ci page = read_cache_page(mapping, page_idx, NULL, NULL); 407062306a36Sopenharmony_ci if (IS_ERR(page)) { 407162306a36Sopenharmony_ci ret = PTR_ERR(page); 407262306a36Sopenharmony_ci break; 407362306a36Sopenharmony_ci } 407462306a36Sopenharmony_ci page_len++; 407562306a36Sopenharmony_ci } 407662306a36Sopenharmony_ci 407762306a36Sopenharmony_ci for (i = 0; i < page_len; i++, redirty_idx++) { 407862306a36Sopenharmony_ci page = find_lock_page(mapping, redirty_idx); 407962306a36Sopenharmony_ci 408062306a36Sopenharmony_ci /* It will never fail, when page has pinned above */ 408162306a36Sopenharmony_ci f2fs_bug_on(F2FS_I_SB(inode), !page); 408262306a36Sopenharmony_ci 408362306a36Sopenharmony_ci set_page_dirty(page); 408462306a36Sopenharmony_ci set_page_private_gcing(page); 408562306a36Sopenharmony_ci f2fs_put_page(page, 1); 408662306a36Sopenharmony_ci f2fs_put_page(page, 0); 408762306a36Sopenharmony_ci } 408862306a36Sopenharmony_ci 408962306a36Sopenharmony_ci return ret; 409062306a36Sopenharmony_ci} 409162306a36Sopenharmony_ci 409262306a36Sopenharmony_cistatic int f2fs_ioc_decompress_file(struct file *filp) 409362306a36Sopenharmony_ci{ 409462306a36Sopenharmony_ci struct inode *inode = file_inode(filp); 409562306a36Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_I_SB(inode); 409662306a36Sopenharmony_ci struct f2fs_inode_info *fi = F2FS_I(inode); 409762306a36Sopenharmony_ci pgoff_t page_idx = 0, last_idx; 409862306a36Sopenharmony_ci unsigned int blk_per_seg = sbi->blocks_per_seg; 409962306a36Sopenharmony_ci int cluster_size = fi->i_cluster_size; 410062306a36Sopenharmony_ci int count, ret; 410162306a36Sopenharmony_ci 410262306a36Sopenharmony_ci if (!f2fs_sb_has_compression(sbi) || 410362306a36Sopenharmony_ci F2FS_OPTION(sbi).compress_mode != COMPR_MODE_USER) 410462306a36Sopenharmony_ci return -EOPNOTSUPP; 410562306a36Sopenharmony_ci 410662306a36Sopenharmony_ci if (!(filp->f_mode & FMODE_WRITE)) 410762306a36Sopenharmony_ci return -EBADF; 410862306a36Sopenharmony_ci 410962306a36Sopenharmony_ci if (!f2fs_compressed_file(inode)) 411062306a36Sopenharmony_ci return -EINVAL; 411162306a36Sopenharmony_ci 411262306a36Sopenharmony_ci f2fs_balance_fs(sbi, true); 411362306a36Sopenharmony_ci 411462306a36Sopenharmony_ci file_start_write(filp); 411562306a36Sopenharmony_ci inode_lock(inode); 411662306a36Sopenharmony_ci 411762306a36Sopenharmony_ci if (!f2fs_is_compress_backend_ready(inode)) { 411862306a36Sopenharmony_ci ret = -EOPNOTSUPP; 411962306a36Sopenharmony_ci goto out; 412062306a36Sopenharmony_ci } 412162306a36Sopenharmony_ci 412262306a36Sopenharmony_ci if (is_inode_flag_set(inode, FI_COMPRESS_RELEASED)) { 412362306a36Sopenharmony_ci ret = -EINVAL; 412462306a36Sopenharmony_ci goto out; 412562306a36Sopenharmony_ci } 412662306a36Sopenharmony_ci 412762306a36Sopenharmony_ci ret = filemap_write_and_wait_range(inode->i_mapping, 0, LLONG_MAX); 412862306a36Sopenharmony_ci if (ret) 412962306a36Sopenharmony_ci goto out; 413062306a36Sopenharmony_ci 413162306a36Sopenharmony_ci if (!atomic_read(&fi->i_compr_blocks)) 413262306a36Sopenharmony_ci goto out; 413362306a36Sopenharmony_ci 413462306a36Sopenharmony_ci last_idx = DIV_ROUND_UP(i_size_read(inode), PAGE_SIZE); 413562306a36Sopenharmony_ci 413662306a36Sopenharmony_ci count = last_idx - page_idx; 413762306a36Sopenharmony_ci while (count && count >= cluster_size) { 413862306a36Sopenharmony_ci ret = redirty_blocks(inode, page_idx, cluster_size); 413962306a36Sopenharmony_ci if (ret < 0) 414062306a36Sopenharmony_ci break; 414162306a36Sopenharmony_ci 414262306a36Sopenharmony_ci if (get_dirty_pages(inode) >= blk_per_seg) { 414362306a36Sopenharmony_ci ret = filemap_fdatawrite(inode->i_mapping); 414462306a36Sopenharmony_ci if (ret < 0) 414562306a36Sopenharmony_ci break; 414662306a36Sopenharmony_ci } 414762306a36Sopenharmony_ci 414862306a36Sopenharmony_ci count -= cluster_size; 414962306a36Sopenharmony_ci page_idx += cluster_size; 415062306a36Sopenharmony_ci 415162306a36Sopenharmony_ci cond_resched(); 415262306a36Sopenharmony_ci if (fatal_signal_pending(current)) { 415362306a36Sopenharmony_ci ret = -EINTR; 415462306a36Sopenharmony_ci break; 415562306a36Sopenharmony_ci } 415662306a36Sopenharmony_ci } 415762306a36Sopenharmony_ci 415862306a36Sopenharmony_ci if (!ret) 415962306a36Sopenharmony_ci ret = filemap_write_and_wait_range(inode->i_mapping, 0, 416062306a36Sopenharmony_ci LLONG_MAX); 416162306a36Sopenharmony_ci 416262306a36Sopenharmony_ci if (ret) 416362306a36Sopenharmony_ci f2fs_warn(sbi, "%s: The file might be partially decompressed (errno=%d). Please delete the file.", 416462306a36Sopenharmony_ci __func__, ret); 416562306a36Sopenharmony_ciout: 416662306a36Sopenharmony_ci inode_unlock(inode); 416762306a36Sopenharmony_ci file_end_write(filp); 416862306a36Sopenharmony_ci 416962306a36Sopenharmony_ci return ret; 417062306a36Sopenharmony_ci} 417162306a36Sopenharmony_ci 417262306a36Sopenharmony_cistatic int f2fs_ioc_compress_file(struct file *filp) 417362306a36Sopenharmony_ci{ 417462306a36Sopenharmony_ci struct inode *inode = file_inode(filp); 417562306a36Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_I_SB(inode); 417662306a36Sopenharmony_ci pgoff_t page_idx = 0, last_idx; 417762306a36Sopenharmony_ci unsigned int blk_per_seg = sbi->blocks_per_seg; 417862306a36Sopenharmony_ci int cluster_size = F2FS_I(inode)->i_cluster_size; 417962306a36Sopenharmony_ci int count, ret; 418062306a36Sopenharmony_ci 418162306a36Sopenharmony_ci if (!f2fs_sb_has_compression(sbi) || 418262306a36Sopenharmony_ci F2FS_OPTION(sbi).compress_mode != COMPR_MODE_USER) 418362306a36Sopenharmony_ci return -EOPNOTSUPP; 418462306a36Sopenharmony_ci 418562306a36Sopenharmony_ci if (!(filp->f_mode & FMODE_WRITE)) 418662306a36Sopenharmony_ci return -EBADF; 418762306a36Sopenharmony_ci 418862306a36Sopenharmony_ci if (!f2fs_compressed_file(inode)) 418962306a36Sopenharmony_ci return -EINVAL; 419062306a36Sopenharmony_ci 419162306a36Sopenharmony_ci f2fs_balance_fs(sbi, true); 419262306a36Sopenharmony_ci 419362306a36Sopenharmony_ci file_start_write(filp); 419462306a36Sopenharmony_ci inode_lock(inode); 419562306a36Sopenharmony_ci 419662306a36Sopenharmony_ci if (!f2fs_is_compress_backend_ready(inode)) { 419762306a36Sopenharmony_ci ret = -EOPNOTSUPP; 419862306a36Sopenharmony_ci goto out; 419962306a36Sopenharmony_ci } 420062306a36Sopenharmony_ci 420162306a36Sopenharmony_ci if (is_inode_flag_set(inode, FI_COMPRESS_RELEASED)) { 420262306a36Sopenharmony_ci ret = -EINVAL; 420362306a36Sopenharmony_ci goto out; 420462306a36Sopenharmony_ci } 420562306a36Sopenharmony_ci 420662306a36Sopenharmony_ci ret = filemap_write_and_wait_range(inode->i_mapping, 0, LLONG_MAX); 420762306a36Sopenharmony_ci if (ret) 420862306a36Sopenharmony_ci goto out; 420962306a36Sopenharmony_ci 421062306a36Sopenharmony_ci set_inode_flag(inode, FI_ENABLE_COMPRESS); 421162306a36Sopenharmony_ci 421262306a36Sopenharmony_ci last_idx = DIV_ROUND_UP(i_size_read(inode), PAGE_SIZE); 421362306a36Sopenharmony_ci 421462306a36Sopenharmony_ci count = last_idx - page_idx; 421562306a36Sopenharmony_ci while (count && count >= cluster_size) { 421662306a36Sopenharmony_ci ret = redirty_blocks(inode, page_idx, cluster_size); 421762306a36Sopenharmony_ci if (ret < 0) 421862306a36Sopenharmony_ci break; 421962306a36Sopenharmony_ci 422062306a36Sopenharmony_ci if (get_dirty_pages(inode) >= blk_per_seg) { 422162306a36Sopenharmony_ci ret = filemap_fdatawrite(inode->i_mapping); 422262306a36Sopenharmony_ci if (ret < 0) 422362306a36Sopenharmony_ci break; 422462306a36Sopenharmony_ci } 422562306a36Sopenharmony_ci 422662306a36Sopenharmony_ci count -= cluster_size; 422762306a36Sopenharmony_ci page_idx += cluster_size; 422862306a36Sopenharmony_ci 422962306a36Sopenharmony_ci cond_resched(); 423062306a36Sopenharmony_ci if (fatal_signal_pending(current)) { 423162306a36Sopenharmony_ci ret = -EINTR; 423262306a36Sopenharmony_ci break; 423362306a36Sopenharmony_ci } 423462306a36Sopenharmony_ci } 423562306a36Sopenharmony_ci 423662306a36Sopenharmony_ci if (!ret) 423762306a36Sopenharmony_ci ret = filemap_write_and_wait_range(inode->i_mapping, 0, 423862306a36Sopenharmony_ci LLONG_MAX); 423962306a36Sopenharmony_ci 424062306a36Sopenharmony_ci clear_inode_flag(inode, FI_ENABLE_COMPRESS); 424162306a36Sopenharmony_ci 424262306a36Sopenharmony_ci if (ret) 424362306a36Sopenharmony_ci f2fs_warn(sbi, "%s: The file might be partially compressed (errno=%d). Please delete the file.", 424462306a36Sopenharmony_ci __func__, ret); 424562306a36Sopenharmony_ciout: 424662306a36Sopenharmony_ci inode_unlock(inode); 424762306a36Sopenharmony_ci file_end_write(filp); 424862306a36Sopenharmony_ci 424962306a36Sopenharmony_ci return ret; 425062306a36Sopenharmony_ci} 425162306a36Sopenharmony_ci 425262306a36Sopenharmony_cistatic long __f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) 425362306a36Sopenharmony_ci{ 425462306a36Sopenharmony_ci switch (cmd) { 425562306a36Sopenharmony_ci case FS_IOC_GETVERSION: 425662306a36Sopenharmony_ci return f2fs_ioc_getversion(filp, arg); 425762306a36Sopenharmony_ci case F2FS_IOC_START_ATOMIC_WRITE: 425862306a36Sopenharmony_ci return f2fs_ioc_start_atomic_write(filp, false); 425962306a36Sopenharmony_ci case F2FS_IOC_START_ATOMIC_REPLACE: 426062306a36Sopenharmony_ci return f2fs_ioc_start_atomic_write(filp, true); 426162306a36Sopenharmony_ci case F2FS_IOC_COMMIT_ATOMIC_WRITE: 426262306a36Sopenharmony_ci return f2fs_ioc_commit_atomic_write(filp); 426362306a36Sopenharmony_ci case F2FS_IOC_ABORT_ATOMIC_WRITE: 426462306a36Sopenharmony_ci return f2fs_ioc_abort_atomic_write(filp); 426562306a36Sopenharmony_ci case F2FS_IOC_START_VOLATILE_WRITE: 426662306a36Sopenharmony_ci case F2FS_IOC_RELEASE_VOLATILE_WRITE: 426762306a36Sopenharmony_ci return -EOPNOTSUPP; 426862306a36Sopenharmony_ci case F2FS_IOC_SHUTDOWN: 426962306a36Sopenharmony_ci return f2fs_ioc_shutdown(filp, arg); 427062306a36Sopenharmony_ci case FITRIM: 427162306a36Sopenharmony_ci return f2fs_ioc_fitrim(filp, arg); 427262306a36Sopenharmony_ci case FS_IOC_SET_ENCRYPTION_POLICY: 427362306a36Sopenharmony_ci return f2fs_ioc_set_encryption_policy(filp, arg); 427462306a36Sopenharmony_ci case FS_IOC_GET_ENCRYPTION_POLICY: 427562306a36Sopenharmony_ci return f2fs_ioc_get_encryption_policy(filp, arg); 427662306a36Sopenharmony_ci case FS_IOC_GET_ENCRYPTION_PWSALT: 427762306a36Sopenharmony_ci return f2fs_ioc_get_encryption_pwsalt(filp, arg); 427862306a36Sopenharmony_ci case FS_IOC_GET_ENCRYPTION_POLICY_EX: 427962306a36Sopenharmony_ci return f2fs_ioc_get_encryption_policy_ex(filp, arg); 428062306a36Sopenharmony_ci case FS_IOC_ADD_ENCRYPTION_KEY: 428162306a36Sopenharmony_ci return f2fs_ioc_add_encryption_key(filp, arg); 428262306a36Sopenharmony_ci case FS_IOC_REMOVE_ENCRYPTION_KEY: 428362306a36Sopenharmony_ci return f2fs_ioc_remove_encryption_key(filp, arg); 428462306a36Sopenharmony_ci case FS_IOC_REMOVE_ENCRYPTION_KEY_ALL_USERS: 428562306a36Sopenharmony_ci return f2fs_ioc_remove_encryption_key_all_users(filp, arg); 428662306a36Sopenharmony_ci case FS_IOC_GET_ENCRYPTION_KEY_STATUS: 428762306a36Sopenharmony_ci return f2fs_ioc_get_encryption_key_status(filp, arg); 428862306a36Sopenharmony_ci case FS_IOC_GET_ENCRYPTION_NONCE: 428962306a36Sopenharmony_ci return f2fs_ioc_get_encryption_nonce(filp, arg); 429062306a36Sopenharmony_ci case F2FS_IOC_GARBAGE_COLLECT: 429162306a36Sopenharmony_ci return f2fs_ioc_gc(filp, arg); 429262306a36Sopenharmony_ci case F2FS_IOC_GARBAGE_COLLECT_RANGE: 429362306a36Sopenharmony_ci return f2fs_ioc_gc_range(filp, arg); 429462306a36Sopenharmony_ci case F2FS_IOC_WRITE_CHECKPOINT: 429562306a36Sopenharmony_ci return f2fs_ioc_write_checkpoint(filp); 429662306a36Sopenharmony_ci case F2FS_IOC_DEFRAGMENT: 429762306a36Sopenharmony_ci return f2fs_ioc_defragment(filp, arg); 429862306a36Sopenharmony_ci case F2FS_IOC_MOVE_RANGE: 429962306a36Sopenharmony_ci return f2fs_ioc_move_range(filp, arg); 430062306a36Sopenharmony_ci case F2FS_IOC_FLUSH_DEVICE: 430162306a36Sopenharmony_ci return f2fs_ioc_flush_device(filp, arg); 430262306a36Sopenharmony_ci case F2FS_IOC_GET_FEATURES: 430362306a36Sopenharmony_ci return f2fs_ioc_get_features(filp, arg); 430462306a36Sopenharmony_ci case F2FS_IOC_GET_PIN_FILE: 430562306a36Sopenharmony_ci return f2fs_ioc_get_pin_file(filp, arg); 430662306a36Sopenharmony_ci case F2FS_IOC_SET_PIN_FILE: 430762306a36Sopenharmony_ci return f2fs_ioc_set_pin_file(filp, arg); 430862306a36Sopenharmony_ci case F2FS_IOC_PRECACHE_EXTENTS: 430962306a36Sopenharmony_ci return f2fs_ioc_precache_extents(filp); 431062306a36Sopenharmony_ci case F2FS_IOC_RESIZE_FS: 431162306a36Sopenharmony_ci return f2fs_ioc_resize_fs(filp, arg); 431262306a36Sopenharmony_ci case FS_IOC_ENABLE_VERITY: 431362306a36Sopenharmony_ci return f2fs_ioc_enable_verity(filp, arg); 431462306a36Sopenharmony_ci case FS_IOC_ENABLE_CODE_SIGN: 431562306a36Sopenharmony_ci return f2fs_ioc_enable_code_sign(filp, arg); 431662306a36Sopenharmony_ci case FS_IOC_MEASURE_VERITY: 431762306a36Sopenharmony_ci return f2fs_ioc_measure_verity(filp, arg); 431862306a36Sopenharmony_ci case FS_IOC_READ_VERITY_METADATA: 431962306a36Sopenharmony_ci return f2fs_ioc_read_verity_metadata(filp, arg); 432062306a36Sopenharmony_ci case FS_IOC_GETFSLABEL: 432162306a36Sopenharmony_ci return f2fs_ioc_getfslabel(filp, arg); 432262306a36Sopenharmony_ci case FS_IOC_SETFSLABEL: 432362306a36Sopenharmony_ci return f2fs_ioc_setfslabel(filp, arg); 432462306a36Sopenharmony_ci case F2FS_IOC_GET_COMPRESS_BLOCKS: 432562306a36Sopenharmony_ci return f2fs_ioc_get_compress_blocks(filp, arg); 432662306a36Sopenharmony_ci case F2FS_IOC_RELEASE_COMPRESS_BLOCKS: 432762306a36Sopenharmony_ci return f2fs_release_compress_blocks(filp, arg); 432862306a36Sopenharmony_ci case F2FS_IOC_RESERVE_COMPRESS_BLOCKS: 432962306a36Sopenharmony_ci return f2fs_reserve_compress_blocks(filp, arg); 433062306a36Sopenharmony_ci case F2FS_IOC_SEC_TRIM_FILE: 433162306a36Sopenharmony_ci return f2fs_sec_trim_file(filp, arg); 433262306a36Sopenharmony_ci case F2FS_IOC_GET_COMPRESS_OPTION: 433362306a36Sopenharmony_ci return f2fs_ioc_get_compress_option(filp, arg); 433462306a36Sopenharmony_ci case F2FS_IOC_SET_COMPRESS_OPTION: 433562306a36Sopenharmony_ci return f2fs_ioc_set_compress_option(filp, arg); 433662306a36Sopenharmony_ci case F2FS_IOC_DECOMPRESS_FILE: 433762306a36Sopenharmony_ci return f2fs_ioc_decompress_file(filp); 433862306a36Sopenharmony_ci case F2FS_IOC_COMPRESS_FILE: 433962306a36Sopenharmony_ci return f2fs_ioc_compress_file(filp); 434062306a36Sopenharmony_ci default: 434162306a36Sopenharmony_ci return -ENOTTY; 434262306a36Sopenharmony_ci } 434362306a36Sopenharmony_ci} 434462306a36Sopenharmony_ci 434562306a36Sopenharmony_cilong f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) 434662306a36Sopenharmony_ci{ 434762306a36Sopenharmony_ci if (unlikely(f2fs_cp_error(F2FS_I_SB(file_inode(filp))))) 434862306a36Sopenharmony_ci return -EIO; 434962306a36Sopenharmony_ci if (!f2fs_is_checkpoint_ready(F2FS_I_SB(file_inode(filp)))) 435062306a36Sopenharmony_ci return -ENOSPC; 435162306a36Sopenharmony_ci 435262306a36Sopenharmony_ci return __f2fs_ioctl(filp, cmd, arg); 435362306a36Sopenharmony_ci} 435462306a36Sopenharmony_ci 435562306a36Sopenharmony_ci/* 435662306a36Sopenharmony_ci * Return %true if the given read or write request should use direct I/O, or 435762306a36Sopenharmony_ci * %false if it should use buffered I/O. 435862306a36Sopenharmony_ci */ 435962306a36Sopenharmony_cistatic bool f2fs_should_use_dio(struct inode *inode, struct kiocb *iocb, 436062306a36Sopenharmony_ci struct iov_iter *iter) 436162306a36Sopenharmony_ci{ 436262306a36Sopenharmony_ci unsigned int align; 436362306a36Sopenharmony_ci 436462306a36Sopenharmony_ci if (!(iocb->ki_flags & IOCB_DIRECT)) 436562306a36Sopenharmony_ci return false; 436662306a36Sopenharmony_ci 436762306a36Sopenharmony_ci if (f2fs_force_buffered_io(inode, iov_iter_rw(iter))) 436862306a36Sopenharmony_ci return false; 436962306a36Sopenharmony_ci 437062306a36Sopenharmony_ci /* 437162306a36Sopenharmony_ci * Direct I/O not aligned to the disk's logical_block_size will be 437262306a36Sopenharmony_ci * attempted, but will fail with -EINVAL. 437362306a36Sopenharmony_ci * 437462306a36Sopenharmony_ci * f2fs additionally requires that direct I/O be aligned to the 437562306a36Sopenharmony_ci * filesystem block size, which is often a stricter requirement. 437662306a36Sopenharmony_ci * However, f2fs traditionally falls back to buffered I/O on requests 437762306a36Sopenharmony_ci * that are logical_block_size-aligned but not fs-block aligned. 437862306a36Sopenharmony_ci * 437962306a36Sopenharmony_ci * The below logic implements this behavior. 438062306a36Sopenharmony_ci */ 438162306a36Sopenharmony_ci align = iocb->ki_pos | iov_iter_alignment(iter); 438262306a36Sopenharmony_ci if (!IS_ALIGNED(align, i_blocksize(inode)) && 438362306a36Sopenharmony_ci IS_ALIGNED(align, bdev_logical_block_size(inode->i_sb->s_bdev))) 438462306a36Sopenharmony_ci return false; 438562306a36Sopenharmony_ci 438662306a36Sopenharmony_ci return true; 438762306a36Sopenharmony_ci} 438862306a36Sopenharmony_ci 438962306a36Sopenharmony_cistatic int f2fs_dio_read_end_io(struct kiocb *iocb, ssize_t size, int error, 439062306a36Sopenharmony_ci unsigned int flags) 439162306a36Sopenharmony_ci{ 439262306a36Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_I_SB(file_inode(iocb->ki_filp)); 439362306a36Sopenharmony_ci 439462306a36Sopenharmony_ci dec_page_count(sbi, F2FS_DIO_READ); 439562306a36Sopenharmony_ci if (error) 439662306a36Sopenharmony_ci return error; 439762306a36Sopenharmony_ci f2fs_update_iostat(sbi, NULL, APP_DIRECT_READ_IO, size); 439862306a36Sopenharmony_ci return 0; 439962306a36Sopenharmony_ci} 440062306a36Sopenharmony_ci 440162306a36Sopenharmony_cistatic const struct iomap_dio_ops f2fs_iomap_dio_read_ops = { 440262306a36Sopenharmony_ci .end_io = f2fs_dio_read_end_io, 440362306a36Sopenharmony_ci}; 440462306a36Sopenharmony_ci 440562306a36Sopenharmony_cistatic ssize_t f2fs_dio_read_iter(struct kiocb *iocb, struct iov_iter *to) 440662306a36Sopenharmony_ci{ 440762306a36Sopenharmony_ci struct file *file = iocb->ki_filp; 440862306a36Sopenharmony_ci struct inode *inode = file_inode(file); 440962306a36Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_I_SB(inode); 441062306a36Sopenharmony_ci struct f2fs_inode_info *fi = F2FS_I(inode); 441162306a36Sopenharmony_ci const loff_t pos = iocb->ki_pos; 441262306a36Sopenharmony_ci const size_t count = iov_iter_count(to); 441362306a36Sopenharmony_ci struct iomap_dio *dio; 441462306a36Sopenharmony_ci ssize_t ret; 441562306a36Sopenharmony_ci 441662306a36Sopenharmony_ci if (count == 0) 441762306a36Sopenharmony_ci return 0; /* skip atime update */ 441862306a36Sopenharmony_ci 441962306a36Sopenharmony_ci trace_f2fs_direct_IO_enter(inode, iocb, count, READ); 442062306a36Sopenharmony_ci 442162306a36Sopenharmony_ci if (iocb->ki_flags & IOCB_NOWAIT) { 442262306a36Sopenharmony_ci if (!f2fs_down_read_trylock(&fi->i_gc_rwsem[READ])) { 442362306a36Sopenharmony_ci ret = -EAGAIN; 442462306a36Sopenharmony_ci goto out; 442562306a36Sopenharmony_ci } 442662306a36Sopenharmony_ci } else { 442762306a36Sopenharmony_ci f2fs_down_read(&fi->i_gc_rwsem[READ]); 442862306a36Sopenharmony_ci } 442962306a36Sopenharmony_ci 443062306a36Sopenharmony_ci /* 443162306a36Sopenharmony_ci * We have to use __iomap_dio_rw() and iomap_dio_complete() instead of 443262306a36Sopenharmony_ci * the higher-level function iomap_dio_rw() in order to ensure that the 443362306a36Sopenharmony_ci * F2FS_DIO_READ counter will be decremented correctly in all cases. 443462306a36Sopenharmony_ci */ 443562306a36Sopenharmony_ci inc_page_count(sbi, F2FS_DIO_READ); 443662306a36Sopenharmony_ci dio = __iomap_dio_rw(iocb, to, &f2fs_iomap_ops, 443762306a36Sopenharmony_ci &f2fs_iomap_dio_read_ops, 0, NULL, 0); 443862306a36Sopenharmony_ci if (IS_ERR_OR_NULL(dio)) { 443962306a36Sopenharmony_ci ret = PTR_ERR_OR_ZERO(dio); 444062306a36Sopenharmony_ci if (ret != -EIOCBQUEUED) 444162306a36Sopenharmony_ci dec_page_count(sbi, F2FS_DIO_READ); 444262306a36Sopenharmony_ci } else { 444362306a36Sopenharmony_ci ret = iomap_dio_complete(dio); 444462306a36Sopenharmony_ci } 444562306a36Sopenharmony_ci 444662306a36Sopenharmony_ci f2fs_up_read(&fi->i_gc_rwsem[READ]); 444762306a36Sopenharmony_ci 444862306a36Sopenharmony_ci file_accessed(file); 444962306a36Sopenharmony_ciout: 445062306a36Sopenharmony_ci trace_f2fs_direct_IO_exit(inode, pos, count, READ, ret); 445162306a36Sopenharmony_ci return ret; 445262306a36Sopenharmony_ci} 445362306a36Sopenharmony_ci 445462306a36Sopenharmony_cistatic void f2fs_trace_rw_file_path(struct file *file, loff_t pos, size_t count, 445562306a36Sopenharmony_ci int rw) 445662306a36Sopenharmony_ci{ 445762306a36Sopenharmony_ci struct inode *inode = file_inode(file); 445862306a36Sopenharmony_ci char *buf, *path; 445962306a36Sopenharmony_ci 446062306a36Sopenharmony_ci buf = f2fs_getname(F2FS_I_SB(inode)); 446162306a36Sopenharmony_ci if (!buf) 446262306a36Sopenharmony_ci return; 446362306a36Sopenharmony_ci path = dentry_path_raw(file_dentry(file), buf, PATH_MAX); 446462306a36Sopenharmony_ci if (IS_ERR(path)) 446562306a36Sopenharmony_ci goto free_buf; 446662306a36Sopenharmony_ci if (rw == WRITE) 446762306a36Sopenharmony_ci trace_f2fs_datawrite_start(inode, pos, count, 446862306a36Sopenharmony_ci current->pid, path, current->comm); 446962306a36Sopenharmony_ci else 447062306a36Sopenharmony_ci trace_f2fs_dataread_start(inode, pos, count, 447162306a36Sopenharmony_ci current->pid, path, current->comm); 447262306a36Sopenharmony_cifree_buf: 447362306a36Sopenharmony_ci f2fs_putname(buf); 447462306a36Sopenharmony_ci} 447562306a36Sopenharmony_ci 447662306a36Sopenharmony_cistatic ssize_t f2fs_file_read_iter(struct kiocb *iocb, struct iov_iter *to) 447762306a36Sopenharmony_ci{ 447862306a36Sopenharmony_ci struct inode *inode = file_inode(iocb->ki_filp); 447962306a36Sopenharmony_ci const loff_t pos = iocb->ki_pos; 448062306a36Sopenharmony_ci ssize_t ret; 448162306a36Sopenharmony_ci 448262306a36Sopenharmony_ci if (!f2fs_is_compress_backend_ready(inode)) 448362306a36Sopenharmony_ci return -EOPNOTSUPP; 448462306a36Sopenharmony_ci 448562306a36Sopenharmony_ci if (trace_f2fs_dataread_start_enabled()) 448662306a36Sopenharmony_ci f2fs_trace_rw_file_path(iocb->ki_filp, iocb->ki_pos, 448762306a36Sopenharmony_ci iov_iter_count(to), READ); 448862306a36Sopenharmony_ci 448962306a36Sopenharmony_ci if (f2fs_should_use_dio(inode, iocb, to)) { 449062306a36Sopenharmony_ci ret = f2fs_dio_read_iter(iocb, to); 449162306a36Sopenharmony_ci } else { 449262306a36Sopenharmony_ci ret = filemap_read(iocb, to, 0); 449362306a36Sopenharmony_ci if (ret > 0) 449462306a36Sopenharmony_ci f2fs_update_iostat(F2FS_I_SB(inode), inode, 449562306a36Sopenharmony_ci APP_BUFFERED_READ_IO, ret); 449662306a36Sopenharmony_ci } 449762306a36Sopenharmony_ci if (trace_f2fs_dataread_end_enabled()) 449862306a36Sopenharmony_ci trace_f2fs_dataread_end(inode, pos, ret); 449962306a36Sopenharmony_ci return ret; 450062306a36Sopenharmony_ci} 450162306a36Sopenharmony_ci 450262306a36Sopenharmony_cistatic ssize_t f2fs_file_splice_read(struct file *in, loff_t *ppos, 450362306a36Sopenharmony_ci struct pipe_inode_info *pipe, 450462306a36Sopenharmony_ci size_t len, unsigned int flags) 450562306a36Sopenharmony_ci{ 450662306a36Sopenharmony_ci struct inode *inode = file_inode(in); 450762306a36Sopenharmony_ci const loff_t pos = *ppos; 450862306a36Sopenharmony_ci ssize_t ret; 450962306a36Sopenharmony_ci 451062306a36Sopenharmony_ci if (!f2fs_is_compress_backend_ready(inode)) 451162306a36Sopenharmony_ci return -EOPNOTSUPP; 451262306a36Sopenharmony_ci 451362306a36Sopenharmony_ci if (trace_f2fs_dataread_start_enabled()) 451462306a36Sopenharmony_ci f2fs_trace_rw_file_path(in, pos, len, READ); 451562306a36Sopenharmony_ci 451662306a36Sopenharmony_ci ret = filemap_splice_read(in, ppos, pipe, len, flags); 451762306a36Sopenharmony_ci if (ret > 0) 451862306a36Sopenharmony_ci f2fs_update_iostat(F2FS_I_SB(inode), inode, 451962306a36Sopenharmony_ci APP_BUFFERED_READ_IO, ret); 452062306a36Sopenharmony_ci 452162306a36Sopenharmony_ci if (trace_f2fs_dataread_end_enabled()) 452262306a36Sopenharmony_ci trace_f2fs_dataread_end(inode, pos, ret); 452362306a36Sopenharmony_ci return ret; 452462306a36Sopenharmony_ci} 452562306a36Sopenharmony_ci 452662306a36Sopenharmony_cistatic ssize_t f2fs_write_checks(struct kiocb *iocb, struct iov_iter *from) 452762306a36Sopenharmony_ci{ 452862306a36Sopenharmony_ci struct file *file = iocb->ki_filp; 452962306a36Sopenharmony_ci struct inode *inode = file_inode(file); 453062306a36Sopenharmony_ci ssize_t count; 453162306a36Sopenharmony_ci int err; 453262306a36Sopenharmony_ci 453362306a36Sopenharmony_ci if (IS_IMMUTABLE(inode)) 453462306a36Sopenharmony_ci return -EPERM; 453562306a36Sopenharmony_ci 453662306a36Sopenharmony_ci if (is_inode_flag_set(inode, FI_COMPRESS_RELEASED)) 453762306a36Sopenharmony_ci return -EPERM; 453862306a36Sopenharmony_ci 453962306a36Sopenharmony_ci count = generic_write_checks(iocb, from); 454062306a36Sopenharmony_ci if (count <= 0) 454162306a36Sopenharmony_ci return count; 454262306a36Sopenharmony_ci 454362306a36Sopenharmony_ci err = file_modified(file); 454462306a36Sopenharmony_ci if (err) 454562306a36Sopenharmony_ci return err; 454662306a36Sopenharmony_ci return count; 454762306a36Sopenharmony_ci} 454862306a36Sopenharmony_ci 454962306a36Sopenharmony_ci/* 455062306a36Sopenharmony_ci * Preallocate blocks for a write request, if it is possible and helpful to do 455162306a36Sopenharmony_ci * so. Returns a positive number if blocks may have been preallocated, 0 if no 455262306a36Sopenharmony_ci * blocks were preallocated, or a negative errno value if something went 455362306a36Sopenharmony_ci * seriously wrong. Also sets FI_PREALLOCATED_ALL on the inode if *all* the 455462306a36Sopenharmony_ci * requested blocks (not just some of them) have been allocated. 455562306a36Sopenharmony_ci */ 455662306a36Sopenharmony_cistatic int f2fs_preallocate_blocks(struct kiocb *iocb, struct iov_iter *iter, 455762306a36Sopenharmony_ci bool dio) 455862306a36Sopenharmony_ci{ 455962306a36Sopenharmony_ci struct inode *inode = file_inode(iocb->ki_filp); 456062306a36Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_I_SB(inode); 456162306a36Sopenharmony_ci const loff_t pos = iocb->ki_pos; 456262306a36Sopenharmony_ci const size_t count = iov_iter_count(iter); 456362306a36Sopenharmony_ci struct f2fs_map_blocks map = {}; 456462306a36Sopenharmony_ci int flag; 456562306a36Sopenharmony_ci int ret; 456662306a36Sopenharmony_ci 456762306a36Sopenharmony_ci /* If it will be an out-of-place direct write, don't bother. */ 456862306a36Sopenharmony_ci if (dio && f2fs_lfs_mode(sbi)) 456962306a36Sopenharmony_ci return 0; 457062306a36Sopenharmony_ci /* 457162306a36Sopenharmony_ci * Don't preallocate holes aligned to DIO_SKIP_HOLES which turns into 457262306a36Sopenharmony_ci * buffered IO, if DIO meets any holes. 457362306a36Sopenharmony_ci */ 457462306a36Sopenharmony_ci if (dio && i_size_read(inode) && 457562306a36Sopenharmony_ci (F2FS_BYTES_TO_BLK(pos) < F2FS_BLK_ALIGN(i_size_read(inode)))) 457662306a36Sopenharmony_ci return 0; 457762306a36Sopenharmony_ci 457862306a36Sopenharmony_ci /* No-wait I/O can't allocate blocks. */ 457962306a36Sopenharmony_ci if (iocb->ki_flags & IOCB_NOWAIT) 458062306a36Sopenharmony_ci return 0; 458162306a36Sopenharmony_ci 458262306a36Sopenharmony_ci /* If it will be a short write, don't bother. */ 458362306a36Sopenharmony_ci if (fault_in_iov_iter_readable(iter, count)) 458462306a36Sopenharmony_ci return 0; 458562306a36Sopenharmony_ci 458662306a36Sopenharmony_ci if (f2fs_has_inline_data(inode)) { 458762306a36Sopenharmony_ci /* If the data will fit inline, don't bother. */ 458862306a36Sopenharmony_ci if (pos + count <= MAX_INLINE_DATA(inode)) 458962306a36Sopenharmony_ci return 0; 459062306a36Sopenharmony_ci ret = f2fs_convert_inline_inode(inode); 459162306a36Sopenharmony_ci if (ret) 459262306a36Sopenharmony_ci return ret; 459362306a36Sopenharmony_ci } 459462306a36Sopenharmony_ci 459562306a36Sopenharmony_ci /* Do not preallocate blocks that will be written partially in 4KB. */ 459662306a36Sopenharmony_ci map.m_lblk = F2FS_BLK_ALIGN(pos); 459762306a36Sopenharmony_ci map.m_len = F2FS_BYTES_TO_BLK(pos + count); 459862306a36Sopenharmony_ci if (map.m_len > map.m_lblk) 459962306a36Sopenharmony_ci map.m_len -= map.m_lblk; 460062306a36Sopenharmony_ci else 460162306a36Sopenharmony_ci map.m_len = 0; 460262306a36Sopenharmony_ci map.m_may_create = true; 460362306a36Sopenharmony_ci if (dio) { 460462306a36Sopenharmony_ci map.m_seg_type = f2fs_rw_hint_to_seg_type(inode->i_write_hint); 460562306a36Sopenharmony_ci flag = F2FS_GET_BLOCK_PRE_DIO; 460662306a36Sopenharmony_ci } else { 460762306a36Sopenharmony_ci map.m_seg_type = NO_CHECK_TYPE; 460862306a36Sopenharmony_ci flag = F2FS_GET_BLOCK_PRE_AIO; 460962306a36Sopenharmony_ci } 461062306a36Sopenharmony_ci 461162306a36Sopenharmony_ci ret = f2fs_map_blocks(inode, &map, flag); 461262306a36Sopenharmony_ci /* -ENOSPC|-EDQUOT are fine to report the number of allocated blocks. */ 461362306a36Sopenharmony_ci if (ret < 0 && !((ret == -ENOSPC || ret == -EDQUOT) && map.m_len > 0)) 461462306a36Sopenharmony_ci return ret; 461562306a36Sopenharmony_ci if (ret == 0) 461662306a36Sopenharmony_ci set_inode_flag(inode, FI_PREALLOCATED_ALL); 461762306a36Sopenharmony_ci return map.m_len; 461862306a36Sopenharmony_ci} 461962306a36Sopenharmony_ci 462062306a36Sopenharmony_cistatic ssize_t f2fs_buffered_write_iter(struct kiocb *iocb, 462162306a36Sopenharmony_ci struct iov_iter *from) 462262306a36Sopenharmony_ci{ 462362306a36Sopenharmony_ci struct file *file = iocb->ki_filp; 462462306a36Sopenharmony_ci struct inode *inode = file_inode(file); 462562306a36Sopenharmony_ci ssize_t ret; 462662306a36Sopenharmony_ci 462762306a36Sopenharmony_ci if (iocb->ki_flags & IOCB_NOWAIT) 462862306a36Sopenharmony_ci return -EOPNOTSUPP; 462962306a36Sopenharmony_ci 463062306a36Sopenharmony_ci ret = generic_perform_write(iocb, from); 463162306a36Sopenharmony_ci 463262306a36Sopenharmony_ci if (ret > 0) { 463362306a36Sopenharmony_ci f2fs_update_iostat(F2FS_I_SB(inode), inode, 463462306a36Sopenharmony_ci APP_BUFFERED_IO, ret); 463562306a36Sopenharmony_ci } 463662306a36Sopenharmony_ci return ret; 463762306a36Sopenharmony_ci} 463862306a36Sopenharmony_ci 463962306a36Sopenharmony_cistatic int f2fs_dio_write_end_io(struct kiocb *iocb, ssize_t size, int error, 464062306a36Sopenharmony_ci unsigned int flags) 464162306a36Sopenharmony_ci{ 464262306a36Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_I_SB(file_inode(iocb->ki_filp)); 464362306a36Sopenharmony_ci 464462306a36Sopenharmony_ci dec_page_count(sbi, F2FS_DIO_WRITE); 464562306a36Sopenharmony_ci if (error) 464662306a36Sopenharmony_ci return error; 464762306a36Sopenharmony_ci f2fs_update_time(sbi, REQ_TIME); 464862306a36Sopenharmony_ci f2fs_update_iostat(sbi, NULL, APP_DIRECT_IO, size); 464962306a36Sopenharmony_ci return 0; 465062306a36Sopenharmony_ci} 465162306a36Sopenharmony_ci 465262306a36Sopenharmony_cistatic const struct iomap_dio_ops f2fs_iomap_dio_write_ops = { 465362306a36Sopenharmony_ci .end_io = f2fs_dio_write_end_io, 465462306a36Sopenharmony_ci}; 465562306a36Sopenharmony_ci 465662306a36Sopenharmony_cistatic void f2fs_flush_buffered_write(struct address_space *mapping, 465762306a36Sopenharmony_ci loff_t start_pos, loff_t end_pos) 465862306a36Sopenharmony_ci{ 465962306a36Sopenharmony_ci int ret; 466062306a36Sopenharmony_ci 466162306a36Sopenharmony_ci ret = filemap_write_and_wait_range(mapping, start_pos, end_pos); 466262306a36Sopenharmony_ci if (ret < 0) 466362306a36Sopenharmony_ci return; 466462306a36Sopenharmony_ci invalidate_mapping_pages(mapping, 466562306a36Sopenharmony_ci start_pos >> PAGE_SHIFT, 466662306a36Sopenharmony_ci end_pos >> PAGE_SHIFT); 466762306a36Sopenharmony_ci} 466862306a36Sopenharmony_ci 466962306a36Sopenharmony_cistatic ssize_t f2fs_dio_write_iter(struct kiocb *iocb, struct iov_iter *from, 467062306a36Sopenharmony_ci bool *may_need_sync) 467162306a36Sopenharmony_ci{ 467262306a36Sopenharmony_ci struct file *file = iocb->ki_filp; 467362306a36Sopenharmony_ci struct inode *inode = file_inode(file); 467462306a36Sopenharmony_ci struct f2fs_inode_info *fi = F2FS_I(inode); 467562306a36Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_I_SB(inode); 467662306a36Sopenharmony_ci const bool do_opu = f2fs_lfs_mode(sbi); 467762306a36Sopenharmony_ci const loff_t pos = iocb->ki_pos; 467862306a36Sopenharmony_ci const ssize_t count = iov_iter_count(from); 467962306a36Sopenharmony_ci unsigned int dio_flags; 468062306a36Sopenharmony_ci struct iomap_dio *dio; 468162306a36Sopenharmony_ci ssize_t ret; 468262306a36Sopenharmony_ci 468362306a36Sopenharmony_ci trace_f2fs_direct_IO_enter(inode, iocb, count, WRITE); 468462306a36Sopenharmony_ci 468562306a36Sopenharmony_ci if (iocb->ki_flags & IOCB_NOWAIT) { 468662306a36Sopenharmony_ci /* f2fs_convert_inline_inode() and block allocation can block */ 468762306a36Sopenharmony_ci if (f2fs_has_inline_data(inode) || 468862306a36Sopenharmony_ci !f2fs_overwrite_io(inode, pos, count)) { 468962306a36Sopenharmony_ci ret = -EAGAIN; 469062306a36Sopenharmony_ci goto out; 469162306a36Sopenharmony_ci } 469262306a36Sopenharmony_ci 469362306a36Sopenharmony_ci if (!f2fs_down_read_trylock(&fi->i_gc_rwsem[WRITE])) { 469462306a36Sopenharmony_ci ret = -EAGAIN; 469562306a36Sopenharmony_ci goto out; 469662306a36Sopenharmony_ci } 469762306a36Sopenharmony_ci if (do_opu && !f2fs_down_read_trylock(&fi->i_gc_rwsem[READ])) { 469862306a36Sopenharmony_ci f2fs_up_read(&fi->i_gc_rwsem[WRITE]); 469962306a36Sopenharmony_ci ret = -EAGAIN; 470062306a36Sopenharmony_ci goto out; 470162306a36Sopenharmony_ci } 470262306a36Sopenharmony_ci } else { 470362306a36Sopenharmony_ci ret = f2fs_convert_inline_inode(inode); 470462306a36Sopenharmony_ci if (ret) 470562306a36Sopenharmony_ci goto out; 470662306a36Sopenharmony_ci 470762306a36Sopenharmony_ci f2fs_down_read(&fi->i_gc_rwsem[WRITE]); 470862306a36Sopenharmony_ci if (do_opu) 470962306a36Sopenharmony_ci f2fs_down_read(&fi->i_gc_rwsem[READ]); 471062306a36Sopenharmony_ci } 471162306a36Sopenharmony_ci 471262306a36Sopenharmony_ci /* 471362306a36Sopenharmony_ci * We have to use __iomap_dio_rw() and iomap_dio_complete() instead of 471462306a36Sopenharmony_ci * the higher-level function iomap_dio_rw() in order to ensure that the 471562306a36Sopenharmony_ci * F2FS_DIO_WRITE counter will be decremented correctly in all cases. 471662306a36Sopenharmony_ci */ 471762306a36Sopenharmony_ci inc_page_count(sbi, F2FS_DIO_WRITE); 471862306a36Sopenharmony_ci dio_flags = 0; 471962306a36Sopenharmony_ci if (pos + count > inode->i_size) 472062306a36Sopenharmony_ci dio_flags |= IOMAP_DIO_FORCE_WAIT; 472162306a36Sopenharmony_ci dio = __iomap_dio_rw(iocb, from, &f2fs_iomap_ops, 472262306a36Sopenharmony_ci &f2fs_iomap_dio_write_ops, dio_flags, NULL, 0); 472362306a36Sopenharmony_ci if (IS_ERR_OR_NULL(dio)) { 472462306a36Sopenharmony_ci ret = PTR_ERR_OR_ZERO(dio); 472562306a36Sopenharmony_ci if (ret == -ENOTBLK) 472662306a36Sopenharmony_ci ret = 0; 472762306a36Sopenharmony_ci if (ret != -EIOCBQUEUED) 472862306a36Sopenharmony_ci dec_page_count(sbi, F2FS_DIO_WRITE); 472962306a36Sopenharmony_ci } else { 473062306a36Sopenharmony_ci ret = iomap_dio_complete(dio); 473162306a36Sopenharmony_ci } 473262306a36Sopenharmony_ci 473362306a36Sopenharmony_ci if (do_opu) 473462306a36Sopenharmony_ci f2fs_up_read(&fi->i_gc_rwsem[READ]); 473562306a36Sopenharmony_ci f2fs_up_read(&fi->i_gc_rwsem[WRITE]); 473662306a36Sopenharmony_ci 473762306a36Sopenharmony_ci if (ret < 0) 473862306a36Sopenharmony_ci goto out; 473962306a36Sopenharmony_ci if (pos + ret > inode->i_size) 474062306a36Sopenharmony_ci f2fs_i_size_write(inode, pos + ret); 474162306a36Sopenharmony_ci if (!do_opu) 474262306a36Sopenharmony_ci set_inode_flag(inode, FI_UPDATE_WRITE); 474362306a36Sopenharmony_ci 474462306a36Sopenharmony_ci if (iov_iter_count(from)) { 474562306a36Sopenharmony_ci ssize_t ret2; 474662306a36Sopenharmony_ci loff_t bufio_start_pos = iocb->ki_pos; 474762306a36Sopenharmony_ci 474862306a36Sopenharmony_ci /* 474962306a36Sopenharmony_ci * The direct write was partial, so we need to fall back to a 475062306a36Sopenharmony_ci * buffered write for the remainder. 475162306a36Sopenharmony_ci */ 475262306a36Sopenharmony_ci 475362306a36Sopenharmony_ci ret2 = f2fs_buffered_write_iter(iocb, from); 475462306a36Sopenharmony_ci if (iov_iter_count(from)) 475562306a36Sopenharmony_ci f2fs_write_failed(inode, iocb->ki_pos); 475662306a36Sopenharmony_ci if (ret2 < 0) 475762306a36Sopenharmony_ci goto out; 475862306a36Sopenharmony_ci 475962306a36Sopenharmony_ci /* 476062306a36Sopenharmony_ci * Ensure that the pagecache pages are written to disk and 476162306a36Sopenharmony_ci * invalidated to preserve the expected O_DIRECT semantics. 476262306a36Sopenharmony_ci */ 476362306a36Sopenharmony_ci if (ret2 > 0) { 476462306a36Sopenharmony_ci loff_t bufio_end_pos = bufio_start_pos + ret2 - 1; 476562306a36Sopenharmony_ci 476662306a36Sopenharmony_ci ret += ret2; 476762306a36Sopenharmony_ci 476862306a36Sopenharmony_ci f2fs_flush_buffered_write(file->f_mapping, 476962306a36Sopenharmony_ci bufio_start_pos, 477062306a36Sopenharmony_ci bufio_end_pos); 477162306a36Sopenharmony_ci } 477262306a36Sopenharmony_ci } else { 477362306a36Sopenharmony_ci /* iomap_dio_rw() already handled the generic_write_sync(). */ 477462306a36Sopenharmony_ci *may_need_sync = false; 477562306a36Sopenharmony_ci } 477662306a36Sopenharmony_ciout: 477762306a36Sopenharmony_ci trace_f2fs_direct_IO_exit(inode, pos, count, WRITE, ret); 477862306a36Sopenharmony_ci return ret; 477962306a36Sopenharmony_ci} 478062306a36Sopenharmony_ci 478162306a36Sopenharmony_cistatic ssize_t f2fs_file_write_iter(struct kiocb *iocb, struct iov_iter *from) 478262306a36Sopenharmony_ci{ 478362306a36Sopenharmony_ci struct inode *inode = file_inode(iocb->ki_filp); 478462306a36Sopenharmony_ci const loff_t orig_pos = iocb->ki_pos; 478562306a36Sopenharmony_ci const size_t orig_count = iov_iter_count(from); 478662306a36Sopenharmony_ci loff_t target_size; 478762306a36Sopenharmony_ci bool dio; 478862306a36Sopenharmony_ci bool may_need_sync = true; 478962306a36Sopenharmony_ci int preallocated; 479062306a36Sopenharmony_ci ssize_t ret; 479162306a36Sopenharmony_ci 479262306a36Sopenharmony_ci if (unlikely(f2fs_cp_error(F2FS_I_SB(inode)))) { 479362306a36Sopenharmony_ci ret = -EIO; 479462306a36Sopenharmony_ci goto out; 479562306a36Sopenharmony_ci } 479662306a36Sopenharmony_ci 479762306a36Sopenharmony_ci if (!f2fs_is_compress_backend_ready(inode)) { 479862306a36Sopenharmony_ci ret = -EOPNOTSUPP; 479962306a36Sopenharmony_ci goto out; 480062306a36Sopenharmony_ci } 480162306a36Sopenharmony_ci 480262306a36Sopenharmony_ci if (iocb->ki_flags & IOCB_NOWAIT) { 480362306a36Sopenharmony_ci if (!inode_trylock(inode)) { 480462306a36Sopenharmony_ci ret = -EAGAIN; 480562306a36Sopenharmony_ci goto out; 480662306a36Sopenharmony_ci } 480762306a36Sopenharmony_ci } else { 480862306a36Sopenharmony_ci inode_lock(inode); 480962306a36Sopenharmony_ci } 481062306a36Sopenharmony_ci 481162306a36Sopenharmony_ci ret = f2fs_write_checks(iocb, from); 481262306a36Sopenharmony_ci if (ret <= 0) 481362306a36Sopenharmony_ci goto out_unlock; 481462306a36Sopenharmony_ci 481562306a36Sopenharmony_ci /* Determine whether we will do a direct write or a buffered write. */ 481662306a36Sopenharmony_ci dio = f2fs_should_use_dio(inode, iocb, from); 481762306a36Sopenharmony_ci 481862306a36Sopenharmony_ci /* Possibly preallocate the blocks for the write. */ 481962306a36Sopenharmony_ci target_size = iocb->ki_pos + iov_iter_count(from); 482062306a36Sopenharmony_ci preallocated = f2fs_preallocate_blocks(iocb, from, dio); 482162306a36Sopenharmony_ci if (preallocated < 0) { 482262306a36Sopenharmony_ci ret = preallocated; 482362306a36Sopenharmony_ci } else { 482462306a36Sopenharmony_ci if (trace_f2fs_datawrite_start_enabled()) 482562306a36Sopenharmony_ci f2fs_trace_rw_file_path(iocb->ki_filp, iocb->ki_pos, 482662306a36Sopenharmony_ci orig_count, WRITE); 482762306a36Sopenharmony_ci 482862306a36Sopenharmony_ci /* Do the actual write. */ 482962306a36Sopenharmony_ci ret = dio ? 483062306a36Sopenharmony_ci f2fs_dio_write_iter(iocb, from, &may_need_sync) : 483162306a36Sopenharmony_ci f2fs_buffered_write_iter(iocb, from); 483262306a36Sopenharmony_ci 483362306a36Sopenharmony_ci if (trace_f2fs_datawrite_end_enabled()) 483462306a36Sopenharmony_ci trace_f2fs_datawrite_end(inode, orig_pos, ret); 483562306a36Sopenharmony_ci } 483662306a36Sopenharmony_ci 483762306a36Sopenharmony_ci /* Don't leave any preallocated blocks around past i_size. */ 483862306a36Sopenharmony_ci if (preallocated && i_size_read(inode) < target_size) { 483962306a36Sopenharmony_ci f2fs_down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]); 484062306a36Sopenharmony_ci filemap_invalidate_lock(inode->i_mapping); 484162306a36Sopenharmony_ci if (!f2fs_truncate(inode)) 484262306a36Sopenharmony_ci file_dont_truncate(inode); 484362306a36Sopenharmony_ci filemap_invalidate_unlock(inode->i_mapping); 484462306a36Sopenharmony_ci f2fs_up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]); 484562306a36Sopenharmony_ci } else { 484662306a36Sopenharmony_ci file_dont_truncate(inode); 484762306a36Sopenharmony_ci } 484862306a36Sopenharmony_ci 484962306a36Sopenharmony_ci clear_inode_flag(inode, FI_PREALLOCATED_ALL); 485062306a36Sopenharmony_ciout_unlock: 485162306a36Sopenharmony_ci inode_unlock(inode); 485262306a36Sopenharmony_ciout: 485362306a36Sopenharmony_ci trace_f2fs_file_write_iter(inode, orig_pos, orig_count, ret); 485462306a36Sopenharmony_ci 485562306a36Sopenharmony_ci if (ret > 0 && may_need_sync) 485662306a36Sopenharmony_ci ret = generic_write_sync(iocb, ret); 485762306a36Sopenharmony_ci 485862306a36Sopenharmony_ci /* If buffered IO was forced, flush and drop the data from 485962306a36Sopenharmony_ci * the page cache to preserve O_DIRECT semantics 486062306a36Sopenharmony_ci */ 486162306a36Sopenharmony_ci if (ret > 0 && !dio && (iocb->ki_flags & IOCB_DIRECT)) 486262306a36Sopenharmony_ci f2fs_flush_buffered_write(iocb->ki_filp->f_mapping, 486362306a36Sopenharmony_ci orig_pos, 486462306a36Sopenharmony_ci orig_pos + ret - 1); 486562306a36Sopenharmony_ci 486662306a36Sopenharmony_ci return ret; 486762306a36Sopenharmony_ci} 486862306a36Sopenharmony_ci 486962306a36Sopenharmony_cistatic int f2fs_file_fadvise(struct file *filp, loff_t offset, loff_t len, 487062306a36Sopenharmony_ci int advice) 487162306a36Sopenharmony_ci{ 487262306a36Sopenharmony_ci struct address_space *mapping; 487362306a36Sopenharmony_ci struct backing_dev_info *bdi; 487462306a36Sopenharmony_ci struct inode *inode = file_inode(filp); 487562306a36Sopenharmony_ci int err; 487662306a36Sopenharmony_ci 487762306a36Sopenharmony_ci if (advice == POSIX_FADV_SEQUENTIAL) { 487862306a36Sopenharmony_ci if (S_ISFIFO(inode->i_mode)) 487962306a36Sopenharmony_ci return -ESPIPE; 488062306a36Sopenharmony_ci 488162306a36Sopenharmony_ci mapping = filp->f_mapping; 488262306a36Sopenharmony_ci if (!mapping || len < 0) 488362306a36Sopenharmony_ci return -EINVAL; 488462306a36Sopenharmony_ci 488562306a36Sopenharmony_ci bdi = inode_to_bdi(mapping->host); 488662306a36Sopenharmony_ci filp->f_ra.ra_pages = bdi->ra_pages * 488762306a36Sopenharmony_ci F2FS_I_SB(inode)->seq_file_ra_mul; 488862306a36Sopenharmony_ci spin_lock(&filp->f_lock); 488962306a36Sopenharmony_ci filp->f_mode &= ~FMODE_RANDOM; 489062306a36Sopenharmony_ci spin_unlock(&filp->f_lock); 489162306a36Sopenharmony_ci return 0; 489262306a36Sopenharmony_ci } 489362306a36Sopenharmony_ci 489462306a36Sopenharmony_ci err = generic_fadvise(filp, offset, len, advice); 489562306a36Sopenharmony_ci if (!err && advice == POSIX_FADV_DONTNEED && 489662306a36Sopenharmony_ci test_opt(F2FS_I_SB(inode), COMPRESS_CACHE) && 489762306a36Sopenharmony_ci f2fs_compressed_file(inode)) 489862306a36Sopenharmony_ci f2fs_invalidate_compress_pages(F2FS_I_SB(inode), inode->i_ino); 489962306a36Sopenharmony_ci 490062306a36Sopenharmony_ci return err; 490162306a36Sopenharmony_ci} 490262306a36Sopenharmony_ci 490362306a36Sopenharmony_ci#ifdef CONFIG_COMPAT 490462306a36Sopenharmony_cistruct compat_f2fs_gc_range { 490562306a36Sopenharmony_ci u32 sync; 490662306a36Sopenharmony_ci compat_u64 start; 490762306a36Sopenharmony_ci compat_u64 len; 490862306a36Sopenharmony_ci}; 490962306a36Sopenharmony_ci#define F2FS_IOC32_GARBAGE_COLLECT_RANGE _IOW(F2FS_IOCTL_MAGIC, 11,\ 491062306a36Sopenharmony_ci struct compat_f2fs_gc_range) 491162306a36Sopenharmony_ci 491262306a36Sopenharmony_cistatic int f2fs_compat_ioc_gc_range(struct file *file, unsigned long arg) 491362306a36Sopenharmony_ci{ 491462306a36Sopenharmony_ci struct compat_f2fs_gc_range __user *urange; 491562306a36Sopenharmony_ci struct f2fs_gc_range range; 491662306a36Sopenharmony_ci int err; 491762306a36Sopenharmony_ci 491862306a36Sopenharmony_ci urange = compat_ptr(arg); 491962306a36Sopenharmony_ci err = get_user(range.sync, &urange->sync); 492062306a36Sopenharmony_ci err |= get_user(range.start, &urange->start); 492162306a36Sopenharmony_ci err |= get_user(range.len, &urange->len); 492262306a36Sopenharmony_ci if (err) 492362306a36Sopenharmony_ci return -EFAULT; 492462306a36Sopenharmony_ci 492562306a36Sopenharmony_ci return __f2fs_ioc_gc_range(file, &range); 492662306a36Sopenharmony_ci} 492762306a36Sopenharmony_ci 492862306a36Sopenharmony_cistruct compat_f2fs_move_range { 492962306a36Sopenharmony_ci u32 dst_fd; 493062306a36Sopenharmony_ci compat_u64 pos_in; 493162306a36Sopenharmony_ci compat_u64 pos_out; 493262306a36Sopenharmony_ci compat_u64 len; 493362306a36Sopenharmony_ci}; 493462306a36Sopenharmony_ci#define F2FS_IOC32_MOVE_RANGE _IOWR(F2FS_IOCTL_MAGIC, 9, \ 493562306a36Sopenharmony_ci struct compat_f2fs_move_range) 493662306a36Sopenharmony_ci 493762306a36Sopenharmony_cistatic int f2fs_compat_ioc_move_range(struct file *file, unsigned long arg) 493862306a36Sopenharmony_ci{ 493962306a36Sopenharmony_ci struct compat_f2fs_move_range __user *urange; 494062306a36Sopenharmony_ci struct f2fs_move_range range; 494162306a36Sopenharmony_ci int err; 494262306a36Sopenharmony_ci 494362306a36Sopenharmony_ci urange = compat_ptr(arg); 494462306a36Sopenharmony_ci err = get_user(range.dst_fd, &urange->dst_fd); 494562306a36Sopenharmony_ci err |= get_user(range.pos_in, &urange->pos_in); 494662306a36Sopenharmony_ci err |= get_user(range.pos_out, &urange->pos_out); 494762306a36Sopenharmony_ci err |= get_user(range.len, &urange->len); 494862306a36Sopenharmony_ci if (err) 494962306a36Sopenharmony_ci return -EFAULT; 495062306a36Sopenharmony_ci 495162306a36Sopenharmony_ci return __f2fs_ioc_move_range(file, &range); 495262306a36Sopenharmony_ci} 495362306a36Sopenharmony_ci 495462306a36Sopenharmony_cilong f2fs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 495562306a36Sopenharmony_ci{ 495662306a36Sopenharmony_ci if (unlikely(f2fs_cp_error(F2FS_I_SB(file_inode(file))))) 495762306a36Sopenharmony_ci return -EIO; 495862306a36Sopenharmony_ci if (!f2fs_is_checkpoint_ready(F2FS_I_SB(file_inode(file)))) 495962306a36Sopenharmony_ci return -ENOSPC; 496062306a36Sopenharmony_ci 496162306a36Sopenharmony_ci switch (cmd) { 496262306a36Sopenharmony_ci case FS_IOC32_GETVERSION: 496362306a36Sopenharmony_ci cmd = FS_IOC_GETVERSION; 496462306a36Sopenharmony_ci break; 496562306a36Sopenharmony_ci case F2FS_IOC32_GARBAGE_COLLECT_RANGE: 496662306a36Sopenharmony_ci return f2fs_compat_ioc_gc_range(file, arg); 496762306a36Sopenharmony_ci case F2FS_IOC32_MOVE_RANGE: 496862306a36Sopenharmony_ci return f2fs_compat_ioc_move_range(file, arg); 496962306a36Sopenharmony_ci case F2FS_IOC_START_ATOMIC_WRITE: 497062306a36Sopenharmony_ci case F2FS_IOC_START_ATOMIC_REPLACE: 497162306a36Sopenharmony_ci case F2FS_IOC_COMMIT_ATOMIC_WRITE: 497262306a36Sopenharmony_ci case F2FS_IOC_START_VOLATILE_WRITE: 497362306a36Sopenharmony_ci case F2FS_IOC_RELEASE_VOLATILE_WRITE: 497462306a36Sopenharmony_ci case F2FS_IOC_ABORT_ATOMIC_WRITE: 497562306a36Sopenharmony_ci case F2FS_IOC_SHUTDOWN: 497662306a36Sopenharmony_ci case FITRIM: 497762306a36Sopenharmony_ci case FS_IOC_SET_ENCRYPTION_POLICY: 497862306a36Sopenharmony_ci case FS_IOC_GET_ENCRYPTION_PWSALT: 497962306a36Sopenharmony_ci case FS_IOC_GET_ENCRYPTION_POLICY: 498062306a36Sopenharmony_ci case FS_IOC_GET_ENCRYPTION_POLICY_EX: 498162306a36Sopenharmony_ci case FS_IOC_ADD_ENCRYPTION_KEY: 498262306a36Sopenharmony_ci case FS_IOC_REMOVE_ENCRYPTION_KEY: 498362306a36Sopenharmony_ci case FS_IOC_REMOVE_ENCRYPTION_KEY_ALL_USERS: 498462306a36Sopenharmony_ci case FS_IOC_GET_ENCRYPTION_KEY_STATUS: 498562306a36Sopenharmony_ci case FS_IOC_GET_ENCRYPTION_NONCE: 498662306a36Sopenharmony_ci case F2FS_IOC_GARBAGE_COLLECT: 498762306a36Sopenharmony_ci case F2FS_IOC_WRITE_CHECKPOINT: 498862306a36Sopenharmony_ci case F2FS_IOC_DEFRAGMENT: 498962306a36Sopenharmony_ci case F2FS_IOC_FLUSH_DEVICE: 499062306a36Sopenharmony_ci case F2FS_IOC_GET_FEATURES: 499162306a36Sopenharmony_ci case F2FS_IOC_GET_PIN_FILE: 499262306a36Sopenharmony_ci case F2FS_IOC_SET_PIN_FILE: 499362306a36Sopenharmony_ci case F2FS_IOC_PRECACHE_EXTENTS: 499462306a36Sopenharmony_ci case F2FS_IOC_RESIZE_FS: 499562306a36Sopenharmony_ci case FS_IOC_ENABLE_VERITY: 499662306a36Sopenharmony_ci case FS_IOC_ENABLE_CODE_SIGN: 499762306a36Sopenharmony_ci case FS_IOC_MEASURE_VERITY: 499862306a36Sopenharmony_ci case FS_IOC_READ_VERITY_METADATA: 499962306a36Sopenharmony_ci case FS_IOC_GETFSLABEL: 500062306a36Sopenharmony_ci case FS_IOC_SETFSLABEL: 500162306a36Sopenharmony_ci case F2FS_IOC_GET_COMPRESS_BLOCKS: 500262306a36Sopenharmony_ci case F2FS_IOC_RELEASE_COMPRESS_BLOCKS: 500362306a36Sopenharmony_ci case F2FS_IOC_RESERVE_COMPRESS_BLOCKS: 500462306a36Sopenharmony_ci case F2FS_IOC_SEC_TRIM_FILE: 500562306a36Sopenharmony_ci case F2FS_IOC_GET_COMPRESS_OPTION: 500662306a36Sopenharmony_ci case F2FS_IOC_SET_COMPRESS_OPTION: 500762306a36Sopenharmony_ci case F2FS_IOC_DECOMPRESS_FILE: 500862306a36Sopenharmony_ci case F2FS_IOC_COMPRESS_FILE: 500962306a36Sopenharmony_ci break; 501062306a36Sopenharmony_ci default: 501162306a36Sopenharmony_ci return -ENOIOCTLCMD; 501262306a36Sopenharmony_ci } 501362306a36Sopenharmony_ci return __f2fs_ioctl(file, cmd, (unsigned long) compat_ptr(arg)); 501462306a36Sopenharmony_ci} 501562306a36Sopenharmony_ci#endif 501662306a36Sopenharmony_ci 501762306a36Sopenharmony_ciconst struct file_operations f2fs_file_operations = { 501862306a36Sopenharmony_ci .llseek = f2fs_llseek, 501962306a36Sopenharmony_ci .read_iter = f2fs_file_read_iter, 502062306a36Sopenharmony_ci .write_iter = f2fs_file_write_iter, 502162306a36Sopenharmony_ci .iopoll = iocb_bio_iopoll, 502262306a36Sopenharmony_ci .open = f2fs_file_open, 502362306a36Sopenharmony_ci .release = f2fs_release_file, 502462306a36Sopenharmony_ci .mmap = f2fs_file_mmap, 502562306a36Sopenharmony_ci .flush = f2fs_file_flush, 502662306a36Sopenharmony_ci .fsync = f2fs_sync_file, 502762306a36Sopenharmony_ci .fallocate = f2fs_fallocate, 502862306a36Sopenharmony_ci .unlocked_ioctl = f2fs_ioctl, 502962306a36Sopenharmony_ci#ifdef CONFIG_COMPAT 503062306a36Sopenharmony_ci .compat_ioctl = f2fs_compat_ioctl, 503162306a36Sopenharmony_ci#endif 503262306a36Sopenharmony_ci .splice_read = f2fs_file_splice_read, 503362306a36Sopenharmony_ci .splice_write = iter_file_splice_write, 503462306a36Sopenharmony_ci .fadvise = f2fs_file_fadvise, 503562306a36Sopenharmony_ci}; 5036