summaryrefslogtreecommitdiff
path: root/fs/f2fs/file.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/f2fs/file.c')
-rw-r--r--fs/f2fs/file.c460
1 files changed, 408 insertions, 52 deletions
diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
index 089759366cdc..edc352569e87 100644
--- a/fs/f2fs/file.c
+++ b/fs/f2fs/file.c
@@ -36,23 +36,69 @@
#include <trace/events/f2fs.h>
#include <uapi/linux/f2fs.h>
-static void f2fs_zero_post_eof_page(struct inode *inode,
- loff_t new_size, bool lock)
+static int fill_zero(struct inode *inode, pgoff_t index,
+ loff_t start, loff_t len);
+
+static int do_zero_post_eof_page(struct inode *inode, loff_t new_size)
{
loff_t old_size = i_size_read(inode);
+ unsigned int offset, len;
+ pgoff_t index;
+ int err;
+
+ offset = old_size & (PAGE_SIZE - 1);
+
+ if (!offset)
+ return 0;
+
+ len = min_t(loff_t, PAGE_SIZE - offset, new_size - old_size);
+ index = old_size >> PAGE_SHIFT;
+
+ if (f2fs_has_inline_data(inode)) {
+ /* data post eof should be always zero */
+ if (new_size <= MAX_INLINE_DATA(inode))
+ return 0;
+ err = f2fs_convert_inline_inode(inode);
+ if (err)
+ return err;
+ }
+
+ err = fill_zero(inode, index, offset, len);
+ if (err)
+ return err;
+ return filemap_write_and_wait_range(inode->i_mapping,
+ old_size, old_size + len - 1);
+}
+
+static int f2fs_zero_post_eof_page(struct inode *inode,
+ loff_t new_size, bool lock, bool writeback)
+{
+ loff_t old_size = i_size_read(inode);
+ bool strict =
+ F2FS_OPTION(F2FS_I_SB(inode)).fsync_mode == FSYNC_MODE_STRICT;
if (old_size >= new_size)
- return;
+ return 0;
- if (mapping_empty(inode->i_mapping))
- return;
+ if (!strict && mapping_empty(inode->i_mapping))
+ return 0;
if (lock)
filemap_invalidate_lock(inode->i_mapping);
/* zero or drop pages only in range of [old_size, new_size] */
- truncate_inode_pages_range(inode->i_mapping, old_size, new_size);
+ truncate_inode_pages_range(inode->i_mapping, old_size, new_size - 1);
if (lock)
filemap_invalidate_unlock(inode->i_mapping);
+
+ if (!writeback || !strict)
+ return 0;
+ /*
+ * In fsync_mode=strict, when we expand an unaligned EOF size, we
+ * should zero post EOF data and writeback the data immediately,
+ * so that it can avoid exposing stale data after metadata flush
+ * and POR.
+ */
+ return do_zero_post_eof_page(inode, new_size);
}
static vm_fault_t f2fs_filemap_fault(struct vm_fault *vmf)
@@ -132,7 +178,10 @@ static vm_fault_t f2fs_vm_page_mkwrite(struct vm_fault *vmf)
f2fs_bug_on(sbi, f2fs_has_inline_data(inode));
- f2fs_zero_post_eof_page(inode, (folio->index + 1) << PAGE_SHIFT, true);
+ err = f2fs_zero_post_eof_page(inode,
+ (folio->index + 1) << PAGE_SHIFT, true, false);
+ if (err)
+ goto out_pagefault;
file_update_time(vmf->vma->vm_file);
filemap_invalidate_lock_shared(inode->i_mapping);
@@ -189,7 +238,7 @@ static vm_fault_t f2fs_vm_page_mkwrite(struct vm_fault *vmf)
out_sem:
filemap_invalidate_unlock_shared(inode->i_mapping);
-
+out_pagefault:
sb_end_pagefault(inode->i_sb);
out:
ret = vmf_fs_error(err);
@@ -813,13 +862,19 @@ int f2fs_do_truncate_blocks(struct inode *inode, u64 from, bool lock)
if (IS_DEVICE_ALIASING(inode)) {
struct extent_tree *et = F2FS_I(inode)->extent_tree[EX_READ];
- struct extent_info ei = et->largest;
+ struct extent_info ei;
+
+ read_lock(&et->lock);
+ ei = et->largest;
+ read_unlock(&et->lock);
f2fs_invalidate_blocks(sbi, ei.blk, ei.len);
dec_valid_block_count(sbi, inode, ei.len);
f2fs_update_time(sbi, REQ_TIME);
+ f2fs_drop_extent_tree(inode);
+
f2fs_folio_put(ifolio, true);
goto out;
}
@@ -1096,24 +1151,31 @@ int f2fs_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
if ((attr->ia_valid & ATTR_SIZE)) {
if (mapping_large_folio_support(inode->i_mapping))
return -EOPNOTSUPP;
- if (!f2fs_is_compress_backend_ready(inode) ||
- IS_DEVICE_ALIASING(inode))
+ if (IS_DEVICE_ALIASING(inode))
+ return -EPERM;
+ if (!f2fs_is_compress_backend_ready(inode))
return -EOPNOTSUPP;
if (is_inode_flag_set(inode, FI_COMPRESS_RELEASED) &&
!IS_ALIGNED(attr->ia_size,
F2FS_BLK_TO_BYTES(fi->i_cluster_size)))
return -EINVAL;
- /*
- * To prevent scattered pin block generation, we don't allow
- * smaller/equal size unaligned truncation for pinned file.
- * We only support overwrite IO to pinned file, so don't
- * care about larger size truncation.
- */
- if (f2fs_is_pinned_file(inode) &&
- attr->ia_size <= i_size_read(inode) &&
- !IS_ALIGNED(attr->ia_size,
- F2FS_BLK_TO_BYTES(CAP_BLKS_PER_SEC(sbi))))
- return -EINVAL;
+
+ if (f2fs_is_pinned_file(inode)) {
+ /*
+ * It may break section-aligned fallocate recovery
+ * mechanism, so do not allow larger size truncation.
+ */
+ if (attr->ia_size > i_size_read(inode))
+ return -EINVAL;
+ /*
+ * To prevent scattered pin block generation, we don't
+ * allow smaller/equal size unaligned truncation for
+ * pinned file.
+ */
+ else if (!IS_ALIGNED(attr->ia_size,
+ F2FS_BLK_TO_BYTES(CAP_BLKS_PER_SEC(sbi))))
+ return -EINVAL;
+ }
}
if (is_quota_modification(idmap, inode, attr)) {
@@ -1165,8 +1227,12 @@ int f2fs_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
f2fs_down_write(&fi->i_gc_rwsem[WRITE]);
filemap_invalidate_lock(inode->i_mapping);
- if (attr->ia_size > old_size)
- f2fs_zero_post_eof_page(inode, attr->ia_size, false);
+ if (attr->ia_size > old_size) {
+ err = f2fs_zero_post_eof_page(inode,
+ attr->ia_size, false, true);
+ if (err)
+ goto err_out;
+ }
truncate_setsize(inode, attr->ia_size);
if (attr->ia_size <= old_size)
@@ -1175,6 +1241,7 @@ int f2fs_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
* do not trim all blocks after i_size if target size is
* larger than i_size.
*/
+err_out:
filemap_invalidate_unlock(inode->i_mapping);
f2fs_up_write(&fi->i_gc_rwsem[WRITE]);
if (err)
@@ -1286,7 +1353,9 @@ static int f2fs_punch_hole(struct inode *inode, loff_t offset, loff_t len)
if (ret)
return ret;
- f2fs_zero_post_eof_page(inode, offset + len, true);
+ ret = f2fs_zero_post_eof_page(inode, offset + len, true, false);
+ if (ret)
+ return ret;
pg_start = ((unsigned long long) offset) >> PAGE_SHIFT;
pg_end = ((unsigned long long) offset + len) >> PAGE_SHIFT;
@@ -1573,7 +1642,9 @@ static int f2fs_do_collapse(struct inode *inode, loff_t offset, loff_t len)
f2fs_down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
filemap_invalidate_lock(inode->i_mapping);
- f2fs_zero_post_eof_page(inode, offset + len, false);
+ ret = f2fs_zero_post_eof_page(inode, offset + len, false, false);
+ if (ret)
+ goto out_unlock;
f2fs_lock_op(sbi, &lc);
f2fs_drop_extent_tree(inode);
@@ -1581,6 +1652,7 @@ static int f2fs_do_collapse(struct inode *inode, loff_t offset, loff_t len)
ret = __exchange_data_block(inode, inode, end, start, nrpages - end, true);
f2fs_unlock_op(sbi, &lc);
+out_unlock:
filemap_invalidate_unlock(inode->i_mapping);
f2fs_up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
return ret;
@@ -1613,11 +1685,14 @@ static int f2fs_collapse_range(struct inode *inode, loff_t offset, loff_t len)
/* write out all moved pages, if possible */
filemap_invalidate_lock(inode->i_mapping);
- filemap_write_and_wait_range(inode->i_mapping, offset, LLONG_MAX);
+ ret = filemap_write_and_wait_range(inode->i_mapping, offset, LLONG_MAX);
+ if (ret)
+ goto out_unlock;
truncate_pagecache(inode, offset);
new_size = i_size_read(inode) - len;
ret = f2fs_truncate_blocks(inode, new_size, true);
+out_unlock:
filemap_invalidate_unlock(inode->i_mapping);
if (!ret)
f2fs_i_size_write(inode, new_size);
@@ -1699,7 +1774,9 @@ static int f2fs_zero_range(struct inode *inode, loff_t offset, loff_t len,
if (ret)
return ret;
- f2fs_zero_post_eof_page(inode, offset + len, true);
+ ret = f2fs_zero_post_eof_page(inode, offset + len, true, false);
+ if (ret)
+ return ret;
pg_start = ((unsigned long long) offset) >> PAGE_SHIFT;
pg_end = ((unsigned long long) offset + len) >> PAGE_SHIFT;
@@ -1834,7 +1911,9 @@ static int f2fs_insert_range(struct inode *inode, loff_t offset, loff_t len)
f2fs_down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
filemap_invalidate_lock(mapping);
- f2fs_zero_post_eof_page(inode, offset + len, false);
+ ret = f2fs_zero_post_eof_page(inode, offset + len, false, false);
+ if (ret)
+ goto out_unlock;
truncate_pagecache(inode, offset);
while (!ret && idx > pg_start) {
@@ -1852,6 +1931,7 @@ static int f2fs_insert_range(struct inode *inode, loff_t offset, loff_t len)
idx + delta, nr, false);
f2fs_unlock_op(sbi, &lc);
}
+out_unlock:
filemap_invalidate_unlock(mapping);
f2fs_up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
if (ret)
@@ -1894,7 +1974,9 @@ static int f2fs_expand_inode_data(struct inode *inode, loff_t offset,
if (err)
return err;
- f2fs_zero_post_eof_page(inode, offset + len, true);
+ err = f2fs_zero_post_eof_page(inode, offset + len, true, true);
+ if (err)
+ return err;
f2fs_balance_fs(sbi, true);
@@ -1915,8 +1997,9 @@ static int f2fs_expand_inode_data(struct inode *inode, loff_t offset,
block_t sec_len;
if (map.m_lblk % sec_blks) {
- map.m_lblk = rounddown(map.m_lblk, sec_blks);
- map.m_len = pg_end - map.m_lblk;
+ pg_start = rounddown(map.m_lblk, sec_blks);
+ map.m_lblk = pg_start;
+ map.m_len = pg_end - pg_start;
if (off_end)
map.m_len++;
}
@@ -2126,6 +2209,9 @@ static int f2fs_setflags_common(struct inode *inode, u32 iflags, u32 mask)
if (IS_NOQUOTA(inode))
return -EPERM;
+ if (IS_DEVICE_ALIASING(inode))
+ return -EPERM;
+
if ((iflags ^ masked_flags) & F2FS_CASEFOLD_FL) {
if (!f2fs_sb_has_casefold(F2FS_I_SB(inode)))
return -EOPNOTSUPP;
@@ -2674,6 +2760,17 @@ static int f2fs_ioc_get_encryption_policy(struct file *filp, unsigned long arg)
return fscrypt_ioctl_get_policy(filp, (void __user *)arg);
}
+static int f2fs_ioc_get_dev_alias_status(struct file *filp, unsigned long arg)
+{
+ struct inode *inode = file_inode(filp);
+
+ if (!IS_DEVICE_ALIASING(inode))
+ return -EINVAL;
+
+ return put_user(F2FS_HAS_BLOCKS(inode) ? F2FS_DEV_ALIAS_STATUS_RESERVED :
+ F2FS_DEV_ALIAS_STATUS_RELEASED, (u32 __user *)arg);
+}
+
static int f2fs_ioc_get_encryption_pwsalt(struct file *filp, unsigned long arg)
{
struct inode *inode = file_inode(filp);
@@ -3079,6 +3176,9 @@ static int f2fs_ioc_defragment(struct file *filp, unsigned long arg)
if (f2fs_readonly(sbi->sb))
return -EROFS;
+ if (IS_DEVICE_ALIASING(inode))
+ return -EOPNOTSUPP;
+
if (copy_from_user(&range, (struct f2fs_defragment __user *)arg,
sizeof(range)))
return -EFAULT;
@@ -3117,8 +3217,9 @@ static int f2fs_move_file_range(struct file *file_in, loff_t pos_in,
struct inode *dst = file_inode(file_out);
struct f2fs_sb_info *sbi = F2FS_I_SB(src);
struct f2fs_lock_context lc;
- size_t olen = len, dst_max_i_size = 0;
- size_t dst_osize;
+ size_t olen = len;
+ loff_t dst_max_i_size = 0;
+ loff_t dst_osize, dst_end;
int ret;
if (file_in->f_path.mnt != file_out->f_path.mnt ||
@@ -3131,7 +3232,8 @@ static int f2fs_move_file_range(struct file *file_in, loff_t pos_in,
if (!S_ISREG(src->i_mode) || !S_ISREG(dst->i_mode))
return -EINVAL;
- if (IS_ENCRYPTED(src) || IS_ENCRYPTED(dst))
+ if (IS_ENCRYPTED(src) || IS_ENCRYPTED(dst) ||
+ IS_DEVICE_ALIASING(src) || IS_DEVICE_ALIASING(dst))
return -EOPNOTSUPP;
if (pos_out < 0 || pos_in < 0)
@@ -3140,8 +3242,6 @@ static int f2fs_move_file_range(struct file *file_in, loff_t pos_in,
if (src == dst) {
if (pos_in == pos_out)
return 0;
- if (pos_out > pos_in && pos_out < pos_in + len)
- return -EINVAL;
}
inode_lock(src);
@@ -3167,6 +3267,8 @@ static int f2fs_move_file_range(struct file *file_in, loff_t pos_in,
goto out_unlock;
if (len == 0)
olen = len = src->i_size - pos_in;
+ if (src == dst && pos_out > pos_in && pos_out < pos_in + len)
+ goto out_unlock;
if (pos_in + len == src->i_size)
len = ALIGN(src->i_size, F2FS_BLKSIZE) - pos_in;
if (len == 0) {
@@ -3175,8 +3277,15 @@ static int f2fs_move_file_range(struct file *file_in, loff_t pos_in,
}
dst_osize = dst->i_size;
- if (pos_out + olen > dst->i_size)
- dst_max_i_size = pos_out + olen;
+ if (olen > LLONG_MAX - pos_out)
+ goto out_unlock;
+ dst_end = pos_out + olen;
+ if (dst_end > dst->i_size) {
+ ret = inode_newsize_ok(dst, dst_end);
+ if (ret)
+ goto out_unlock;
+ dst_max_i_size = dst_end;
+ }
/* verify the end result is block aligned */
if (!IS_ALIGNED(pos_in, F2FS_BLKSIZE) ||
@@ -3612,6 +3721,241 @@ static int f2fs_ioc_get_dev_alias_file(struct file *filp, unsigned long arg)
(u32 __user *)arg);
}
+static bool f2fs_get_dev_alias_extent(struct f2fs_sb_info *sbi,
+ struct dentry *dentry,
+ struct extent_info *ei)
+{
+ int i;
+
+ for (i = 1; i < sbi->s_ndevs; i++) {
+ char *name = strrchr(FDEV(i).path, '/');
+
+ name = name ? name + 1 : FDEV(i).path;
+ if (strcmp(name, dentry->d_name.name))
+ continue;
+
+ ei->blk = FDEV(i).start_blk;
+ ei->len = FDEV(i).total_segments << sbi->log_blocks_per_seg;
+ ei->fofs = 0;
+ return true;
+ }
+ return false;
+}
+
+static int f2fs_ioc_reserve_dev_alias(struct file *filp)
+{
+ struct inode *inode = file_inode(filp);
+ struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
+ struct extent_tree *et = F2FS_I(inode)->extent_tree[EX_READ];
+ struct extent_info ei;
+ struct cp_control cpc = { CP_SYNC, 0, 0, 0 };
+ struct f2fs_lock_context lc, glc;
+ blkcnt_t count;
+ unsigned int start, end;
+ int type, err;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED)))
+ return -EINVAL;
+
+ err = mnt_want_write_file(filp);
+ if (err)
+ return err;
+
+ inode_lock(inode);
+
+ if (!IS_DEVICE_ALIASING(inode)) {
+ err = -EINVAL;
+ goto out_inode_unlock;
+ }
+
+ if (F2FS_HAS_BLOCKS(inode)) {
+ err = 0;
+ goto out_inode_unlock;
+ }
+
+ if (!f2fs_get_dev_alias_extent(sbi, filp->f_path.dentry, &ei)) {
+ f2fs_warn(sbi, "device alias file (%s, ino=%llu) has no matching device",
+ filp->f_path.dentry->d_name.name,
+ (unsigned long long)inode->i_ino);
+ set_sbi_flag(sbi, SBI_NEED_FSCK);
+ f2fs_handle_error(sbi, ERROR_CORRUPTED_INODE);
+ err = -EFSCORRUPTED;
+ goto out_inode_unlock;
+ }
+
+ spin_lock(&sbi->stat_lock);
+ if (sbi->total_valid_block_count + ei.len >
+ get_available_block_count(sbi, inode, true)) {
+ spin_unlock(&sbi->stat_lock);
+ err = -ENOSPC;
+ goto out_inode_unlock;
+ }
+ sbi->alias_reserved_blocks += ei.len;
+ spin_unlock(&sbi->stat_lock);
+
+ spin_lock(&FREE_I(sbi)->segmap_lock);
+ FDEV(f2fs_target_device_index(sbi, ei.blk)).is_reserving = true;
+ spin_unlock(&FREE_I(sbi)->segmap_lock);
+
+ start = GET_SEGNO(sbi, ei.blk);
+ end = GET_SEGNO(sbi, ei.blk + ei.len - 1);
+
+ /* Acquire gc_lock for victim reset, curseg resize, and range GC */
+ f2fs_down_write_trace(&sbi->gc_lock, &glc);
+
+ /* Reset the victim information to prevent GC from targeting the range */
+ f2fs_reset_gc_victim_resource(sbi, start, end);
+
+ /* Move out cursegs from the target range */
+ for (type = CURSEG_HOT_DATA; type < NR_CURSEG_PERSIST_TYPE; type++) {
+ err = f2fs_allocate_segment_for_resize(sbi, type, start, end);
+ if (err)
+ goto out_gc_unlock;
+ }
+
+ f2fs_lock_op(sbi, &lc);
+
+ if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED))) {
+ err = -EINVAL;
+ f2fs_unlock_op(sbi, &lc);
+ goto out_gc_unlock;
+ }
+
+ /* do GC to move out valid blocks in the range all at once! */
+ err = f2fs_gc_range(sbi, start, end, false, 0, false);
+ if (err) {
+ f2fs_unlock_op(sbi, &lc);
+ goto out_gc_unlock;
+ }
+
+ count = ei.len;
+ err = inc_valid_block_count(sbi, inode, &count, false, true);
+ if (err) {
+ f2fs_unlock_op(sbi, &lc);
+ goto out_gc_unlock;
+ }
+
+ write_lock(&et->lock);
+ et->largest = ei;
+ write_unlock(&et->lock);
+ clear_inode_flag(inode, FI_NO_EXTENT);
+
+ f2fs_reserve_device_alias(sbi, ei.blk, ei.len);
+
+ i_size_write(inode, (loff_t)ei.len << sbi->log_blocksize);
+ f2fs_update_inode_page(inode);
+
+ spin_lock(&FREE_I(sbi)->segmap_lock);
+ FDEV(f2fs_target_device_index(sbi, ei.blk)).is_reserving = false;
+ spin_unlock(&FREE_I(sbi)->segmap_lock);
+
+ f2fs_unlock_op(sbi, &lc);
+ f2fs_up_write_trace(&sbi->gc_lock, &glc);
+
+ inode_unlock(inode);
+ mnt_drop_write_file(filp);
+
+ return f2fs_write_checkpoint(sbi, &cpc);
+
+out_gc_unlock:
+ spin_lock(&sbi->stat_lock);
+ sbi->alias_reserved_blocks -= ei.len;
+ spin_unlock(&sbi->stat_lock);
+
+ spin_lock(&FREE_I(sbi)->segmap_lock);
+ FDEV(f2fs_target_device_index(sbi, ei.blk)).is_reserving = false;
+ spin_unlock(&FREE_I(sbi)->segmap_lock);
+ f2fs_up_write_trace(&sbi->gc_lock, &glc);
+
+out_inode_unlock:
+ inode_unlock(inode);
+ mnt_drop_write_file(filp);
+ return err;
+}
+
+static int f2fs_ioc_release_dev_alias(struct file *filp)
+{
+ struct inode *inode = file_inode(filp);
+ struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
+ struct extent_tree *et = F2FS_I(inode)->extent_tree[EX_READ];
+ struct extent_info ei = {0, };
+ struct cp_control cpc = { CP_SYNC, 0, 0, 0 };
+ struct f2fs_lock_context lc, glc;
+ int err;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED)))
+ return -EINVAL;
+
+ err = mnt_want_write_file(filp);
+ if (err)
+ return err;
+
+ inode_lock(inode);
+
+ if (!IS_DEVICE_ALIASING(inode)) {
+ err = -EINVAL;
+ goto out_inode_unlock;
+ }
+
+ if (!F2FS_HAS_BLOCKS(inode)) {
+ err = 0;
+ goto out_inode_unlock;
+ }
+
+ err = filemap_write_and_wait(inode->i_mapping);
+ if (err)
+ goto out_inode_unlock;
+
+ read_lock(&et->lock);
+ ei = et->largest;
+ read_unlock(&et->lock);
+
+ f2fs_down_write_trace(&sbi->gc_lock, &glc);
+ f2fs_lock_op(sbi, &lc);
+
+ if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED))) {
+ err = -EINVAL;
+ f2fs_unlock_op(sbi, &lc);
+ f2fs_up_write_trace(&sbi->gc_lock, &glc);
+ goto out_inode_unlock;
+ }
+
+ filemap_invalidate_lock(inode->i_mapping);
+ truncate_setsize(inode, 0);
+
+ err = f2fs_truncate_blocks(inode, 0, false);
+ if (err)
+ i_size_write(inode, (loff_t)ei.len << sbi->log_blocksize);
+ filemap_invalidate_unlock(inode->i_mapping);
+
+ if (err) {
+ f2fs_unlock_op(sbi, &lc);
+ f2fs_up_write_trace(&sbi->gc_lock, &glc);
+ goto out_inode_unlock;
+ }
+
+ f2fs_update_inode_page(inode);
+
+ f2fs_unlock_op(sbi, &lc);
+ f2fs_up_write_trace(&sbi->gc_lock, &glc);
+
+ inode_unlock(inode);
+ mnt_drop_write_file(filp);
+
+ return f2fs_write_checkpoint(sbi, &cpc);
+
+out_inode_unlock:
+ inode_unlock(inode);
+ mnt_drop_write_file(filp);
+ return err;
+}
+
static int f2fs_ioc_io_prio(struct file *filp, unsigned long arg)
{
struct inode *inode = file_inode(filp);
@@ -4037,7 +4381,7 @@ static int reserve_compress_blocks(struct dnode_of_data *dn, pgoff_t count,
}
ret = inc_valid_block_count(sbi, dn->inode,
- &to_reserved, false);
+ &to_reserved, false, false);
if (unlikely(ret))
return ret;
@@ -4469,7 +4813,7 @@ static int redirty_blocks(struct inode *inode, pgoff_t page_idx, int len)
page_idx = folio_next_index(folio);
} while (page_len < len);
- do {
+ while (redirty_idx < page_idx) {
folio = filemap_lock_folio(mapping, redirty_idx);
/* It will never fail, when folio has pinned above */
@@ -4482,7 +4826,7 @@ static int redirty_blocks(struct inode *inode, pgoff_t page_idx, int len)
redirty_idx = folio_next_index(folio);
folio_unlock(folio);
folio_put_refs(folio, 2);
- } while (redirty_idx < page_idx);
+ }
return ret;
}
@@ -4738,8 +5082,14 @@ static long __f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
return f2fs_ioc_compress_file(filp);
case F2FS_IOC_GET_DEV_ALIAS_FILE:
return f2fs_ioc_get_dev_alias_file(filp, arg);
+ case F2FS_IOC_GET_DEV_ALIAS_STATUS:
+ return f2fs_ioc_get_dev_alias_status(filp, arg);
case F2FS_IOC_IO_PRIO:
return f2fs_ioc_io_prio(filp, arg);
+ case F2FS_IOC_RESERVE_DEV_ALIAS:
+ return f2fs_ioc_reserve_dev_alias(filp);
+ case F2FS_IOC_RELEASE_DEV_ALIAS:
+ return f2fs_ioc_release_dev_alias(filp);
default:
return -ENOTTY;
}
@@ -4998,8 +5348,10 @@ static ssize_t f2fs_write_checks(struct kiocb *iocb, struct iov_iter *from)
if (err)
return err;
- f2fs_zero_post_eof_page(inode,
- iocb->ki_pos + iov_iter_count(from), true);
+ err = f2fs_zero_post_eof_page(inode,
+ iocb->ki_pos + iov_iter_count(from), true, true);
+ if (err)
+ return err;
return count;
}
@@ -5285,9 +5637,8 @@ static ssize_t f2fs_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
bool dio;
bool may_need_sync = true;
int preallocated;
- const loff_t pos = iocb->ki_pos;
- const ssize_t count = iov_iter_count(from);
ssize_t ret;
+ loff_t bufio_start_pos;
if (unlikely(f2fs_cp_error(F2FS_I_SB(inode)))) {
ret = -EIO;
@@ -5308,15 +5659,17 @@ static ssize_t f2fs_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
inode_lock(inode);
}
+ ret = f2fs_write_checks(iocb, from);
+ if (ret <= 0)
+ goto out_unlock;
+
if (f2fs_is_pinned_file(inode) &&
- !f2fs_overwrite_io(inode, pos, count)) {
+ !f2fs_overwrite_io(inode, iocb->ki_pos, iov_iter_count(from))) {
ret = -EIO;
goto out_unlock;
}
- ret = f2fs_write_checks(iocb, from);
- if (ret <= 0)
- goto out_unlock;
+ bufio_start_pos = iocb->ki_pos;
/* Determine whether we will do a direct write or a buffered write. */
dio = f2fs_should_use_dio(inode, iocb, from);
@@ -5371,8 +5724,8 @@ out:
*/
if (ret > 0 && !dio && (iocb->ki_flags & IOCB_DIRECT))
f2fs_flush_buffered_write(iocb->ki_filp->f_mapping,
- orig_pos,
- orig_pos + ret - 1);
+ bufio_start_pos,
+ bufio_start_pos + ret - 1);
return ret;
}
@@ -5526,7 +5879,10 @@ long f2fs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
case F2FS_IOC_DECOMPRESS_FILE:
case F2FS_IOC_COMPRESS_FILE:
case F2FS_IOC_GET_DEV_ALIAS_FILE:
+ case F2FS_IOC_GET_DEV_ALIAS_STATUS:
case F2FS_IOC_IO_PRIO:
+ case F2FS_IOC_RESERVE_DEV_ALIAS:
+ case F2FS_IOC_RELEASE_DEV_ALIAS:
break;
default:
return -ENOIOCTLCMD;