f2fs update for 6.8-rc1

In this series, we've some progress to support Zoned block device regarding to
 the power-cut recovery flow and enabling checkpoint=disable feature which is
 essential for Android OTA. Other than that, some patches touched sysfs entries
 and tracepoints which are minor, while several bug fixes on error handlers and
 compression flows are good to improve the overall stability.
 
 Enhancement:
  - enable checkpoint=disable for zoned block device
  - sysfs entries such as discard status, discard_io_aware, dir_level
  - tracepoints such as f2fs_vm_page_mkwrite(), f2fs_rename(), f2fs_new_inode()
  - use shared inode lock during f2fs_fiemap() and f2fs_seek_block()
 
 Bug fix:
  - address some power-cut recovery issues on zoned block device
  - handle errors and logics on do_garbage_collect(), f2fs_reserve_new_block(),
    f2fs_move_file_range(), f2fs_recover_xattr_data()
  - don't set FI_PREALLOCATED_ALL for partial write
  - fix to update iostat correctly in f2fs_filemap_fault()
  - fix to wait on block writeback for post_read case
  - fix to tag gcing flag on page during block migration
  - restrict max filesize for 16K f2fs
  - fix to avoid dirent corruption
  - explicitly null-terminate the xattr list
 
 There are also several clean-up patches to remove dead codes and better
 readability.
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEE00UqedjCtOrGVvQiQBSofoJIUNIFAmWgMYcACgkQQBSofoJI
 UNJShxAAiYOXP7LPOAbPS1251BBgl8AIfs6u96hGTZkxOYsLHrBBbPbkWf3+nVbC
 JsBsVOe9K50rssK9kPg6XHPbmFGC8ERlyYcZTpONLfjtHOaQicbRnc//2qOvnCx8
 JOKcMVkZyLU/HbOCoUW6mzNCQlOl0aAV8tRcb7jwAxT0HgpjHTHxej/62gRcPKzC
 1E5w4iNTY//R97YGB36jPeGlKhbBZ7Ox1NM6AWadgE7B0j9rcYiBnPQllyeyaVVo
 XMCWRdl42tNMks2zgvU+vC41OrZ55bwLTQmVj3P1wnyKXig5/ZLQsrEcIGE+b2tP
 Mx+imCIRNYZqLwv5KYl6FU+KuLQGuZT1AjpP70Cb95WLyiYvVE6+xeiZg0fVTCEF
 3Hg7lEqMtAEAh1NEmJyYmbiAm9KQ3vHyse9ix++tfm+Xvgqj8b2flmzAtIFKpCBV
 J+yFI+A55IYuYZt7gzPoZLkQL0tULPf80TKQrzwlnHNtZ6T6FK2Nunu+Urwf1/Th
 s5IulqHJZxHU/Bgd6yQZUVfDILcXTkqNCpO3+qLZMPZizlH1hXiJFTeVzS6mnGvZ
 sK2LL4rEJ8EhDHU1F0SJzCWJcuR8cQ/t2zKYUygo9LvHbtEM1bZwC1Bqfolt7NrU
 +pgiM2wnE9yjkPdfZN1JgYZDq0/lGvxPQ5NAc/5ERX71QonRyn8=
 =MQl3
 -----END PGP SIGNATURE-----

Merge tag 'f2fs-for-6.8-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs

Pull f2fs update from Jaegeuk Kim:
 "In this series, we've some progress to support Zoned block device
  regarding to the power-cut recovery flow and enabling
  checkpoint=disable feature which is essential for Android OTA.

  Other than that, some patches touched sysfs entries and tracepoints
  which are minor, while several bug fixes on error handlers and
  compression flows are good to improve the overall stability.

  Enhancements:
   - enable checkpoint=disable for zoned block device
   - sysfs entries such as discard status, discard_io_aware, dir_level
   - tracepoints such as f2fs_vm_page_mkwrite(), f2fs_rename(),
     f2fs_new_inode()
   - use shared inode lock during f2fs_fiemap() and f2fs_seek_block()

  Bug fixes:
   - address some power-cut recovery issues on zoned block device
   - handle errors and logics on do_garbage_collect(),
     f2fs_reserve_new_block(), f2fs_move_file_range(),
     f2fs_recover_xattr_data()
   - don't set FI_PREALLOCATED_ALL for partial write
   - fix to update iostat correctly in f2fs_filemap_fault()
   - fix to wait on block writeback for post_read case
   - fix to tag gcing flag on page during block migration
   - restrict max filesize for 16K f2fs
   - fix to avoid dirent corruption
   - explicitly null-terminate the xattr list

  There are also several clean-up patches to remove dead codes and
  better readability"

* tag 'f2fs-for-6.8-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs: (33 commits)
  f2fs: show more discard status by sysfs
  f2fs: Add error handling for negative returns from do_garbage_collect
  f2fs: Constrain the modification range of dir_level in the sysfs
  f2fs: Use wait_event_freezable_timeout() for freezable kthread
  f2fs: fix to check return value of f2fs_recover_xattr_data
  f2fs: don't set FI_PREALLOCATED_ALL for partial write
  f2fs: fix to update iostat correctly in f2fs_filemap_fault()
  f2fs: fix to check compress file in f2fs_move_file_range()
  f2fs: fix to wait on block writeback for post_read case
  f2fs: fix to tag gcing flag on page during block migration
  f2fs: add tracepoint for f2fs_vm_page_mkwrite()
  f2fs: introduce f2fs_invalidate_internal_cache() for cleanup
  f2fs: update blkaddr in __set_data_blkaddr() for cleanup
  f2fs: introduce get_dnode_addr() to clean up codes
  f2fs: delete obsolete FI_DROP_CACHE
  f2fs: delete obsolete FI_FIRST_BLOCK_WRITTEN
  f2fs: Restrict max filesize for 16K f2fs
  f2fs: let's finish or reset zones all the time
  f2fs: check write pointers when checkpoint=disable
  f2fs: fix write pointers on zoned device after roll forward
  ...
This commit is contained in:
Linus Torvalds 2024-01-11 20:39:15 -08:00
commit 70d201a408
16 changed files with 395 additions and 269 deletions

View File

@ -498,6 +498,21 @@ Description: Show status of f2fs checkpoint in real time.
CP_RESIZEFS_FLAG 0x00004000
=============================== ==============================
What: /sys/fs/f2fs/<disk>/stat/issued_discard
Date: December 2023
Contact: "Zhiguo Niu" <zhiguo.niu@unisoc.com>
Description: Shows the number of issued discard.
What: /sys/fs/f2fs/<disk>/stat/queued_discard
Date: December 2023
Contact: "Zhiguo Niu" <zhiguo.niu@unisoc.com>
Description: Shows the number of queued discard.
What: /sys/fs/f2fs/<disk>/stat/undiscard_blks
Date: December 2023
Contact: "Zhiguo Niu" <zhiguo.niu@unisoc.com>
Description: Shows the total number of undiscard blocks.
What: /sys/fs/f2fs/<disk>/ckpt_thread_ioprio
Date: January 2021
Contact: "Daeho Jeong" <daehojeong@google.com>
@ -740,3 +755,9 @@ Description: When compress cache is on, it controls cached page
If cached page percent exceed threshold, then deny caching compress page.
The value should be in range of (0, 100], by default it was initialized
as 20(%).
What: /sys/fs/f2fs/<disk>/discard_io_aware
Date: November 2023
Contact: "Chao Yu" <chao@kernel.org>
Description: It controls to enable/disable IO aware feature for background discard.
By default, the value is 1 which indicates IO aware is on.

View File

@ -1036,8 +1036,10 @@ static void set_cluster_dirty(struct compress_ctx *cc)
int i;
for (i = 0; i < cc->cluster_size; i++)
if (cc->rpages[i])
if (cc->rpages[i]) {
set_page_dirty(cc->rpages[i]);
set_page_private_gcing(cc->rpages[i]);
}
}
static int prepare_compress_overwrite(struct compress_ctx *cc,
@ -1369,8 +1371,6 @@ unlock_continue:
add_compr_block_stat(inode, cc->valid_nr_cpages);
set_inode_flag(cc->inode, FI_APPEND_WRITE);
if (cc->cluster_idx == 0)
set_inode_flag(inode, FI_FIRST_BLOCK_WRITTEN);
f2fs_put_dnode(&dn);
if (quota_inode)

View File

@ -1179,18 +1179,12 @@ static int f2fs_submit_page_read(struct inode *inode, struct page *page,
return 0;
}
static void __set_data_blkaddr(struct dnode_of_data *dn)
static void __set_data_blkaddr(struct dnode_of_data *dn, block_t blkaddr)
{
struct f2fs_node *rn = F2FS_NODE(dn->node_page);
__le32 *addr_array;
int base = 0;
__le32 *addr = get_dnode_addr(dn->inode, dn->node_page);
if (IS_INODE(dn->node_page) && f2fs_has_extra_attr(dn->inode))
base = get_extra_isize(dn->inode);
/* Get physical address of data block */
addr_array = blkaddr_in_node(rn);
addr_array[base + dn->ofs_in_node] = cpu_to_le32(dn->data_blkaddr);
dn->data_blkaddr = blkaddr;
addr[dn->ofs_in_node] = cpu_to_le32(dn->data_blkaddr);
}
/*
@ -1199,18 +1193,17 @@ static void __set_data_blkaddr(struct dnode_of_data *dn)
* ->node_page
* update block addresses in the node page
*/
void f2fs_set_data_blkaddr(struct dnode_of_data *dn)
void f2fs_set_data_blkaddr(struct dnode_of_data *dn, block_t blkaddr)
{
f2fs_wait_on_page_writeback(dn->node_page, NODE, true, true);
__set_data_blkaddr(dn);
__set_data_blkaddr(dn, blkaddr);
if (set_page_dirty(dn->node_page))
dn->node_changed = true;
}
void f2fs_update_data_blkaddr(struct dnode_of_data *dn, block_t blkaddr)
{
dn->data_blkaddr = blkaddr;
f2fs_set_data_blkaddr(dn);
f2fs_set_data_blkaddr(dn, blkaddr);
f2fs_update_read_extent_cache(dn);
}
@ -1237,8 +1230,7 @@ int f2fs_reserve_new_blocks(struct dnode_of_data *dn, blkcnt_t count)
block_t blkaddr = f2fs_data_blkaddr(dn);
if (blkaddr == NULL_ADDR) {
dn->data_blkaddr = NEW_ADDR;
__set_data_blkaddr(dn);
__set_data_blkaddr(dn, NEW_ADDR);
count--;
}
}
@ -1492,11 +1484,9 @@ static int __allocate_data_block(struct dnode_of_data *dn, int seg_type)
old_blkaddr = dn->data_blkaddr;
f2fs_allocate_data_block(sbi, NULL, old_blkaddr, &dn->data_blkaddr,
&sum, seg_type, NULL);
if (GET_SEGNO(sbi, old_blkaddr) != NULL_SEGNO) {
invalidate_mapping_pages(META_MAPPING(sbi),
old_blkaddr, old_blkaddr);
f2fs_invalidate_compress_page(sbi, old_blkaddr);
}
if (GET_SEGNO(sbi, old_blkaddr) != NULL_SEGNO)
f2fs_invalidate_internal_cache(sbi, old_blkaddr);
f2fs_update_data_blkaddr(dn, dn->data_blkaddr);
return 0;
}
@ -1992,7 +1982,7 @@ int f2fs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
if (ret)
return ret;
inode_lock(inode);
inode_lock_shared(inode);
maxbytes = max_file_blocks(inode) << F2FS_BLKSIZE_BITS;
if (start > maxbytes) {
@ -2112,7 +2102,7 @@ out:
if (ret == 1)
ret = 0;
inode_unlock(inode);
inode_unlock_shared(inode);
return ret;
}
@ -2566,9 +2556,6 @@ int f2fs_encrypt_one_page(struct f2fs_io_info *fio)
page = fio->compressed_page ? fio->compressed_page : fio->page;
/* wait for GCed page writeback via META_MAPPING */
f2fs_wait_on_block_writeback(inode, fio->old_blkaddr);
if (fscrypt_inode_uses_inline_crypto(inode))
return 0;
@ -2755,6 +2742,10 @@ got_it:
goto out_writepage;
}
/* wait for GCed page writeback via META_MAPPING */
if (fio->post_read)
f2fs_wait_on_block_writeback(inode, fio->old_blkaddr);
/*
* If current allocation needs SSR,
* it had better in-place writes for updated data.
@ -2810,8 +2801,6 @@ got_it:
f2fs_outplace_write_data(&dn, fio);
trace_f2fs_do_write_data_page(page, OPU);
set_inode_flag(inode, FI_APPEND_WRITE);
if (page->index == 0)
set_inode_flag(inode, FI_FIRST_BLOCK_WRITTEN);
out_writepage:
f2fs_put_dnode(&dn);
out:
@ -2894,9 +2883,6 @@ int f2fs_write_single_data_page(struct page *page, int *submitted,
zero_user_segment(page, offset, PAGE_SIZE);
write:
if (f2fs_is_drop_cache(inode))
goto out;
/* Dentry/quota blocks are controlled by checkpoint */
if (S_ISDIR(inode->i_mode) || quota_inode) {
/*

View File

@ -374,6 +374,12 @@ enum {
MAX_DPOLICY,
};
enum {
DPOLICY_IO_AWARE_DISABLE, /* force to not be aware of IO */
DPOLICY_IO_AWARE_ENABLE, /* force to be aware of IO */
DPOLICY_IO_AWARE_MAX,
};
struct discard_policy {
int type; /* type of discard */
unsigned int min_interval; /* used for candidates exist */
@ -406,6 +412,7 @@ struct discard_cmd_control {
unsigned int discard_urgent_util; /* utilization which issue discard proactively */
unsigned int discard_granularity; /* discard granularity */
unsigned int max_ordered_discard; /* maximum discard granularity issued by lba order */
unsigned int discard_io_aware; /* io_aware policy */
unsigned int undiscard_blks; /* # of undiscard blocks */
unsigned int next_pos; /* next discard position */
atomic_t issued_discard; /* # of issued discard */
@ -774,8 +781,6 @@ enum {
FI_UPDATE_WRITE, /* inode has in-place-update data */
FI_NEED_IPU, /* used for ipu per file */
FI_ATOMIC_FILE, /* indicate atomic file */
FI_FIRST_BLOCK_WRITTEN, /* indicate #0 data block was written */
FI_DROP_CACHE, /* drop dirty page cache */
FI_DATA_EXIST, /* indicate data exists */
FI_INLINE_DOTS, /* indicate inline dot dentries */
FI_SKIP_WRITES, /* should skip data page writeback */
@ -3272,22 +3277,13 @@ static inline bool f2fs_is_cow_file(struct inode *inode)
return is_inode_flag_set(inode, FI_COW_FILE);
}
static inline bool f2fs_is_first_block_written(struct inode *inode)
{
return is_inode_flag_set(inode, FI_FIRST_BLOCK_WRITTEN);
}
static inline bool f2fs_is_drop_cache(struct inode *inode)
{
return is_inode_flag_set(inode, FI_DROP_CACHE);
}
static inline __le32 *get_dnode_addr(struct inode *inode,
struct page *node_page);
static inline void *inline_data_addr(struct inode *inode, struct page *page)
{
struct f2fs_inode *ri = F2FS_INODE(page);
int extra_size = get_extra_isize(inode);
__le32 *addr = get_dnode_addr(inode, page);
return (void *)&(ri->i_addr[extra_size + DEF_INLINE_RESERVED_SIZE]);
return (void *)(addr + DEF_INLINE_RESERVED_SIZE);
}
static inline int f2fs_has_inline_dentry(struct inode *inode)
@ -3432,6 +3428,17 @@ static inline int get_inline_xattr_addrs(struct inode *inode)
return F2FS_I(inode)->i_inline_xattr_size;
}
static inline __le32 *get_dnode_addr(struct inode *inode,
struct page *node_page)
{
int base = 0;
if (IS_INODE(node_page) && f2fs_has_extra_attr(inode))
base = get_extra_isize(inode);
return blkaddr_in_node(F2FS_NODE(node_page)) + base;
}
#define f2fs_get_inode_mode(i) \
((is_inode_flag_set(i, FI_ACL_MODE)) ? \
(F2FS_I(i)->i_acl_mode) : ((i)->i_mode))
@ -3815,7 +3822,7 @@ void f2fs_submit_page_write(struct f2fs_io_info *fio);
struct block_device *f2fs_target_device(struct f2fs_sb_info *sbi,
block_t blk_addr, sector_t *sector);
int f2fs_target_device_index(struct f2fs_sb_info *sbi, block_t blkaddr);
void f2fs_set_data_blkaddr(struct dnode_of_data *dn);
void f2fs_set_data_blkaddr(struct dnode_of_data *dn, block_t blkaddr);
void f2fs_update_data_blkaddr(struct dnode_of_data *dn, block_t blkaddr);
int f2fs_reserve_new_blocks(struct dnode_of_data *dn, blkcnt_t count);
int f2fs_reserve_new_block(struct dnode_of_data *dn);
@ -4606,6 +4613,13 @@ static inline bool f2fs_is_readonly(struct f2fs_sb_info *sbi)
return f2fs_sb_has_readonly(sbi) || f2fs_readonly(sbi->sb);
}
static inline void f2fs_invalidate_internal_cache(struct f2fs_sb_info *sbi,
block_t blkaddr)
{
invalidate_mapping_pages(META_MAPPING(sbi), blkaddr, blkaddr);
f2fs_invalidate_compress_page(sbi, blkaddr);
}
#define EFSBADCRC EBADMSG /* Bad CRC detected */
#define EFSCORRUPTED EUCLEAN /* Filesystem is corrupted */

View File

@ -42,11 +42,11 @@ static vm_fault_t f2fs_filemap_fault(struct vm_fault *vmf)
vm_fault_t ret;
ret = filemap_fault(vmf);
if (!ret)
if (ret & VM_FAULT_LOCKED)
f2fs_update_iostat(F2FS_I_SB(inode), inode,
APP_MAPPED_READ_IO, F2FS_BLKSIZE);
trace_f2fs_filemap_fault(inode, vmf->pgoff, (unsigned long)ret);
trace_f2fs_filemap_fault(inode, vmf->pgoff, vmf->vma->vm_flags, ret);
return ret;
}
@ -59,26 +59,29 @@ static vm_fault_t f2fs_vm_page_mkwrite(struct vm_fault *vmf)
struct dnode_of_data dn;
bool need_alloc = true;
int err = 0;
vm_fault_t ret;
if (unlikely(IS_IMMUTABLE(inode)))
return VM_FAULT_SIGBUS;
if (is_inode_flag_set(inode, FI_COMPRESS_RELEASED))
return VM_FAULT_SIGBUS;
if (is_inode_flag_set(inode, FI_COMPRESS_RELEASED)) {
err = -EIO;
goto out;
}
if (unlikely(f2fs_cp_error(sbi))) {
err = -EIO;
goto err;
goto out;
}
if (!f2fs_is_checkpoint_ready(sbi)) {
err = -ENOSPC;
goto err;
goto out;
}
err = f2fs_convert_inline_inode(inode);
if (err)
goto err;
goto out;
#ifdef CONFIG_F2FS_FS_COMPRESSION
if (f2fs_compressed_file(inode)) {
@ -86,7 +89,7 @@ static vm_fault_t f2fs_vm_page_mkwrite(struct vm_fault *vmf)
if (ret < 0) {
err = ret;
goto err;
goto out;
} else if (ret) {
need_alloc = false;
}
@ -153,13 +156,15 @@ static vm_fault_t f2fs_vm_page_mkwrite(struct vm_fault *vmf)
f2fs_update_iostat(sbi, inode, APP_MAPPED_IO, F2FS_BLKSIZE);
f2fs_update_time(sbi, REQ_TIME);
trace_f2fs_vm_page_mkwrite(page, DATA);
out_sem:
filemap_invalidate_unlock_shared(inode->i_mapping);
sb_end_pagefault(inode->i_sb);
err:
return vmf_fs_error(err);
out:
ret = vmf_fs_error(err);
trace_f2fs_vm_page_mkwrite(inode, page->index, vmf->vma->vm_flags, ret);
return ret;
}
static const struct vm_operations_struct f2fs_file_vm_ops = {
@ -418,7 +423,7 @@ static loff_t f2fs_seek_block(struct file *file, loff_t offset, int whence)
loff_t isize;
int err = 0;
inode_lock(inode);
inode_lock_shared(inode);
isize = i_size_read(inode);
if (offset >= isize)
@ -483,10 +488,10 @@ static loff_t f2fs_seek_block(struct file *file, loff_t offset, int whence)
found:
if (whence == SEEK_HOLE && data_ofs > isize)
data_ofs = isize;
inode_unlock(inode);
inode_unlock_shared(inode);
return vfs_setpos(file, data_ofs, maxbytes);
fail:
inode_unlock(inode);
inode_unlock_shared(inode);
return -ENXIO;
}
@ -557,20 +562,14 @@ static int f2fs_file_open(struct inode *inode, struct file *filp)
void f2fs_truncate_data_blocks_range(struct dnode_of_data *dn, int count)
{
struct f2fs_sb_info *sbi = F2FS_I_SB(dn->inode);
struct f2fs_node *raw_node;
int nr_free = 0, ofs = dn->ofs_in_node, len = count;
__le32 *addr;
int base = 0;
bool compressed_cluster = false;
int cluster_index = 0, valid_blocks = 0;
int cluster_size = F2FS_I(dn->inode)->i_cluster_size;
bool released = !atomic_read(&F2FS_I(dn->inode)->i_compr_blocks);
if (IS_INODE(dn->node_page) && f2fs_has_extra_attr(dn->inode))
base = get_extra_isize(dn->inode);
raw_node = F2FS_NODE(dn->node_page);
addr = blkaddr_in_node(raw_node) + base + ofs;
addr = get_dnode_addr(dn->inode, dn->node_page) + ofs;
/* Assumption: truncation starts with cluster */
for (; count > 0; count--, addr++, dn->ofs_in_node++, cluster_index++) {
@ -588,8 +587,7 @@ void f2fs_truncate_data_blocks_range(struct dnode_of_data *dn, int count)
if (blkaddr == NULL_ADDR)
continue;
dn->data_blkaddr = NULL_ADDR;
f2fs_set_data_blkaddr(dn);
f2fs_set_data_blkaddr(dn, NULL_ADDR);
if (__is_valid_data_blkaddr(blkaddr)) {
if (!f2fs_is_valid_blkaddr(sbi, blkaddr,
@ -599,9 +597,6 @@ void f2fs_truncate_data_blocks_range(struct dnode_of_data *dn, int count)
valid_blocks++;
}
if (dn->ofs_in_node == 0 && IS_INODE(dn->node_page))
clear_inode_flag(dn->inode, FI_FIRST_BLOCK_WRITTEN);
f2fs_invalidate_blocks(sbi, blkaddr);
if (!released || blkaddr != COMPRESS_ADDR)
@ -1317,6 +1312,7 @@ static int __clone_blkaddrs(struct inode *src_inode, struct inode *dst_inode,
}
memcpy_page(pdst, 0, psrc, 0, PAGE_SIZE);
set_page_dirty(pdst);
set_page_private_gcing(pdst);
f2fs_put_page(pdst, 1);
f2fs_put_page(psrc, 1);
@ -1487,8 +1483,7 @@ static int f2fs_do_zero_range(struct dnode_of_data *dn, pgoff_t start,
}
f2fs_invalidate_blocks(sbi, dn->data_blkaddr);
dn->data_blkaddr = NEW_ADDR;
f2fs_set_data_blkaddr(dn);
f2fs_set_data_blkaddr(dn, NEW_ADDR);
}
f2fs_update_read_extent_cache_range(dn, start, 0, index - start);
@ -2818,6 +2813,11 @@ static int f2fs_move_file_range(struct file *file_in, loff_t pos_in,
goto out;
}
if (f2fs_compressed_file(src) || f2fs_compressed_file(dst)) {
ret = -EOPNOTSUPP;
goto out_unlock;
}
ret = -EINVAL;
if (pos_in + len > src->i_size || pos_in + len < pos_in)
goto out_unlock;
@ -3463,8 +3463,7 @@ static int release_compress_blocks(struct dnode_of_data *dn, pgoff_t count)
if (blkaddr != NEW_ADDR)
continue;
dn->data_blkaddr = NULL_ADDR;
f2fs_set_data_blkaddr(dn);
f2fs_set_data_blkaddr(dn, NULL_ADDR);
}
f2fs_i_compr_blocks_update(dn->inode, compr_blocks, false);
@ -3630,8 +3629,7 @@ static int reserve_compress_blocks(struct dnode_of_data *dn, pgoff_t count)
continue;
}
dn->data_blkaddr = NEW_ADDR;
f2fs_set_data_blkaddr(dn);
f2fs_set_data_blkaddr(dn, NEW_ADDR);
}
reserved = cluster_size - compr_blocks;
@ -4054,6 +4052,7 @@ static int redirty_blocks(struct inode *inode, pgoff_t page_idx, int len)
f2fs_bug_on(F2FS_I_SB(inode), !page);
set_page_dirty(page);
set_page_private_gcing(page);
f2fs_put_page(page, 1);
f2fs_put_page(page, 0);
}
@ -4568,7 +4567,8 @@ static int f2fs_preallocate_blocks(struct kiocb *iocb, struct iov_iter *iter,
if (map.m_len > map.m_lblk)
map.m_len -= map.m_lblk;
else
map.m_len = 0;
return 0;
map.m_may_create = true;
if (dio) {
map.m_seg_type = f2fs_rw_hint_to_seg_type(inode->i_write_hint);

View File

@ -46,8 +46,8 @@ static int gc_thread_func(void *data)
do {
bool sync_mode, foreground = false;
wait_event_interruptible_timeout(*wq,
kthread_should_stop() || freezing(current) ||
wait_event_freezable_timeout(*wq,
kthread_should_stop() ||
waitqueue_active(fggc_wq) ||
gc_th->gc_wake,
msecs_to_jiffies(wait_ms));
@ -59,7 +59,7 @@ static int gc_thread_func(void *data)
if (gc_th->gc_wake)
gc_th->gc_wake = false;
if (try_to_freeze() || f2fs_readonly(sbi->sb)) {
if (f2fs_readonly(sbi->sb)) {
stat_other_skip_bggc_count(sbi);
continue;
}
@ -1380,9 +1380,8 @@ static int move_data_block(struct inode *inode, block_t bidx,
memcpy(page_address(fio.encrypted_page),
page_address(mpage), PAGE_SIZE);
f2fs_put_page(mpage, 1);
invalidate_mapping_pages(META_MAPPING(fio.sbi),
fio.old_blkaddr, fio.old_blkaddr);
f2fs_invalidate_compress_page(fio.sbi, fio.old_blkaddr);
f2fs_invalidate_internal_cache(fio.sbi, fio.old_blkaddr);
set_page_dirty(fio.encrypted_page);
if (clear_page_dirty_for_io(fio.encrypted_page))
@ -1405,8 +1404,6 @@ static int move_data_block(struct inode *inode, block_t bidx,
f2fs_update_data_blkaddr(&dn, newaddr);
set_inode_flag(inode, FI_APPEND_WRITE);
if (page->index == 0)
set_inode_flag(inode, FI_FIRST_BLOCK_WRITTEN);
put_page_out:
f2fs_put_page(fio.encrypted_page, 1);
recover_block:
@ -1868,6 +1865,9 @@ retry:
seg_freed = do_garbage_collect(sbi, segno, &gc_list, gc_type,
gc_control->should_migrate_blocks);
if (seg_freed < 0)
goto stop;
total_freed += seg_freed;
if (seg_freed == f2fs_usable_segs_in_sec(sbi, segno)) {

View File

@ -61,49 +61,31 @@ void f2fs_set_inode_flags(struct inode *inode)
S_ENCRYPTED|S_VERITY|S_CASEFOLD);
}
static void __get_inode_rdev(struct inode *inode, struct f2fs_inode *ri)
static void __get_inode_rdev(struct inode *inode, struct page *node_page)
{
int extra_size = get_extra_isize(inode);
__le32 *addr = get_dnode_addr(inode, node_page);
if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) ||
S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) {
if (ri->i_addr[extra_size])
inode->i_rdev = old_decode_dev(
le32_to_cpu(ri->i_addr[extra_size]));
if (addr[0])
inode->i_rdev = old_decode_dev(le32_to_cpu(addr[0]));
else
inode->i_rdev = new_decode_dev(
le32_to_cpu(ri->i_addr[extra_size + 1]));
inode->i_rdev = new_decode_dev(le32_to_cpu(addr[1]));
}
}
static int __written_first_block(struct f2fs_sb_info *sbi,
struct f2fs_inode *ri)
static void __set_inode_rdev(struct inode *inode, struct page *node_page)
{
block_t addr = le32_to_cpu(ri->i_addr[offset_in_addr(ri)]);
if (!__is_valid_data_blkaddr(addr))
return 1;
if (!f2fs_is_valid_blkaddr(sbi, addr, DATA_GENERIC_ENHANCE)) {
f2fs_handle_error(sbi, ERROR_INVALID_BLKADDR);
return -EFSCORRUPTED;
}
return 0;
}
static void __set_inode_rdev(struct inode *inode, struct f2fs_inode *ri)
{
int extra_size = get_extra_isize(inode);
__le32 *addr = get_dnode_addr(inode, node_page);
if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) {
if (old_valid_dev(inode->i_rdev)) {
ri->i_addr[extra_size] =
cpu_to_le32(old_encode_dev(inode->i_rdev));
ri->i_addr[extra_size + 1] = 0;
addr[0] = cpu_to_le32(old_encode_dev(inode->i_rdev));
addr[1] = 0;
} else {
ri->i_addr[extra_size] = 0;
ri->i_addr[extra_size + 1] =
cpu_to_le32(new_encode_dev(inode->i_rdev));
ri->i_addr[extra_size + 2] = 0;
addr[0] = 0;
addr[1] = cpu_to_le32(new_encode_dev(inode->i_rdev));
addr[2] = 0;
}
}
}
@ -398,7 +380,6 @@ static int do_read_inode(struct inode *inode)
struct page *node_page;
struct f2fs_inode *ri;
projid_t i_projid;
int err;
/* Check if ino is within scope */
if (f2fs_check_nid_range(sbi, inode->i_ino))
@ -478,17 +459,7 @@ static int do_read_inode(struct inode *inode)
}
/* get rdev by using inline_info */
__get_inode_rdev(inode, ri);
if (S_ISREG(inode->i_mode)) {
err = __written_first_block(sbi, ri);
if (err < 0) {
f2fs_put_page(node_page, 1);
return err;
}
if (!err)
set_inode_flag(inode, FI_FIRST_BLOCK_WRITTEN);
}
__get_inode_rdev(inode, node_page);
if (!f2fs_need_inode_block_update(sbi, inode->i_ino))
fi->last_disk_size = inode->i_size;
@ -761,7 +732,7 @@ void f2fs_update_inode(struct inode *inode, struct page *node_page)
}
}
__set_inode_rdev(inode, ri);
__set_inode_rdev(inode, node_page);
/* deleted inode */
if (inode->i_nlink == 0)

View File

@ -459,7 +459,6 @@ static int __recover_dot_dentries(struct inode *dir, nid_t pino)
{
struct f2fs_sb_info *sbi = F2FS_I_SB(dir);
struct qstr dot = QSTR_INIT(".", 1);
struct qstr dotdot = QSTR_INIT("..", 2);
struct f2fs_dir_entry *de;
struct page *page;
int err = 0;
@ -497,13 +496,13 @@ static int __recover_dot_dentries(struct inode *dir, nid_t pino)
goto out;
}
de = f2fs_find_entry(dir, &dotdot, &page);
de = f2fs_find_entry(dir, &dotdot_name, &page);
if (de)
f2fs_put_page(page, 0);
else if (IS_ERR(page))
err = PTR_ERR(page);
else
err = f2fs_do_add_link(dir, &dotdot, NULL, pino, S_IFDIR);
err = f2fs_do_add_link(dir, &dotdot_name, NULL, pino, S_IFDIR);
out:
if (!err)
clear_inode_flag(dir, FI_INLINE_DOTS);
@ -1107,7 +1106,7 @@ static int f2fs_rename(struct mnt_idmap *idmap, struct inode *old_dir,
}
if (old_is_dir) {
if (old_dir_entry && !whiteout)
if (old_dir_entry)
f2fs_set_link(old_inode, old_dir_entry,
old_dir_page, new_dir);
else
@ -1317,21 +1316,27 @@ static int f2fs_rename2(struct mnt_idmap *idmap,
if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE | RENAME_WHITEOUT))
return -EINVAL;
trace_f2fs_rename_start(old_dir, old_dentry, new_dir, new_dentry,
flags);
err = fscrypt_prepare_rename(old_dir, old_dentry, new_dir, new_dentry,
flags);
if (err)
return err;
if (flags & RENAME_EXCHANGE) {
return f2fs_cross_rename(old_dir, old_dentry,
new_dir, new_dentry);
}
if (flags & RENAME_EXCHANGE)
err = f2fs_cross_rename(old_dir, old_dentry,
new_dir, new_dentry);
else
/*
* VFS has already handled the new dentry existence case,
* here, we just deal with "RENAME_NOREPLACE" as regular rename.
*/
return f2fs_rename(idmap, old_dir, old_dentry,
err = f2fs_rename(idmap, old_dir, old_dentry,
new_dir, new_dentry, flags);
trace_f2fs_rename_end(old_dentry, new_dentry, flags, err);
return err;
}
static const char *f2fs_encrypted_get_link(struct dentry *dentry,

View File

@ -2751,11 +2751,11 @@ recover_xnid:
f2fs_update_inode_page(inode);
/* 3: update and set xattr node page dirty */
if (page)
if (page) {
memcpy(F2FS_NODE(xpage), F2FS_NODE(page),
VALID_XATTR_BLOCK_SIZE);
set_page_dirty(xpage);
set_page_dirty(xpage);
}
f2fs_put_page(xpage, 1);
return 0;

View File

@ -712,7 +712,16 @@ retry_dn:
*/
if (dest == NEW_ADDR) {
f2fs_truncate_data_blocks_range(&dn, 1);
f2fs_reserve_new_block(&dn);
do {
err = f2fs_reserve_new_block(&dn);
if (err == -ENOSPC) {
f2fs_bug_on(sbi, 1);
break;
}
} while (err &&
IS_ENABLED(CONFIG_F2FS_FAULT_INJECTION));
if (err)
goto err;
continue;
}
@ -720,12 +729,14 @@ retry_dn:
if (f2fs_is_valid_blkaddr(sbi, dest, META_POR)) {
if (src == NULL_ADDR) {
err = f2fs_reserve_new_block(&dn);
while (err &&
IS_ENABLED(CONFIG_F2FS_FAULT_INJECTION))
do {
err = f2fs_reserve_new_block(&dn);
/* We should not get -ENOSPC */
f2fs_bug_on(sbi, err);
if (err == -ENOSPC) {
f2fs_bug_on(sbi, 1);
break;
}
} while (err &&
IS_ENABLED(CONFIG_F2FS_FAULT_INJECTION));
if (err)
goto err;
}
@ -906,6 +917,8 @@ skip:
if (!err && fix_curseg_write_pointer && !f2fs_readonly(sbi->sb) &&
f2fs_sb_has_blkzoned(sbi)) {
err = f2fs_fix_curseg_write_pointer(sbi);
if (!err)
err = f2fs_check_write_pointer(sbi);
ret = err;
}

View File

@ -1172,7 +1172,10 @@ static void __init_discard_policy(struct f2fs_sb_info *sbi,
dpolicy->min_interval = dcc->min_discard_issue_time;
dpolicy->mid_interval = dcc->mid_discard_issue_time;
dpolicy->max_interval = dcc->max_discard_issue_time;
dpolicy->io_aware = true;
if (dcc->discard_io_aware == DPOLICY_IO_AWARE_ENABLE)
dpolicy->io_aware = true;
else if (dcc->discard_io_aware == DPOLICY_IO_AWARE_DISABLE)
dpolicy->io_aware = false;
dpolicy->sync = false;
dpolicy->ordered = true;
if (utilization(sbi) > dcc->discard_urgent_util) {
@ -1380,7 +1383,8 @@ static void __insert_discard_cmd(struct f2fs_sb_info *sbi,
p = &(*p)->rb_right;
leftmost = false;
} else {
f2fs_bug_on(sbi, 1);
/* Let's skip to add, if exists */
return;
}
}
@ -1883,9 +1887,8 @@ static int issue_discard_thread(void *data)
set_freezable();
do {
wait_event_interruptible_timeout(*q,
kthread_should_stop() || freezing(current) ||
dcc->discard_wake,
wait_event_freezable_timeout(*q,
kthread_should_stop() || dcc->discard_wake,
msecs_to_jiffies(wait_ms));
if (sbi->gc_mode == GC_URGENT_HIGH ||
@ -1903,8 +1906,6 @@ static int issue_discard_thread(void *data)
if (atomic_read(&dcc->queued_discard))
__wait_all_discard_cmd(sbi, NULL);
if (try_to_freeze())
continue;
if (f2fs_readonly(sbi->sb))
continue;
if (kthread_should_stop())
@ -2274,6 +2275,7 @@ static int create_discard_cmd_control(struct f2fs_sb_info *sbi)
dcc->discard_io_aware_gran = MAX_PLIST_NUM;
dcc->discard_granularity = DEFAULT_DISCARD_GRANULARITY;
dcc->max_ordered_discard = DEFAULT_MAX_ORDERED_DISCARD_GRANULARITY;
dcc->discard_io_aware = DPOLICY_IO_AWARE_ENABLE;
if (F2FS_OPTION(sbi).discard_unit == DISCARD_UNIT_SEGMENT)
dcc->discard_granularity = sbi->blocks_per_seg;
else if (F2FS_OPTION(sbi).discard_unit == DISCARD_UNIT_SECTION)
@ -2495,8 +2497,7 @@ void f2fs_invalidate_blocks(struct f2fs_sb_info *sbi, block_t addr)
if (addr == NEW_ADDR || addr == COMPRESS_ADDR)
return;
invalidate_mapping_pages(META_MAPPING(sbi), addr, addr);
f2fs_invalidate_compress_page(sbi, addr);
f2fs_invalidate_internal_cache(sbi, addr);
/* add it into sit main buffer */
down_write(&sit_i->sentry_lock);
@ -3557,11 +3558,8 @@ static void do_write_page(struct f2fs_summary *sum, struct f2fs_io_info *fio)
reallocate:
f2fs_allocate_data_block(fio->sbi, fio->page, fio->old_blkaddr,
&fio->new_blkaddr, sum, type, fio);
if (GET_SEGNO(fio->sbi, fio->old_blkaddr) != NULL_SEGNO) {
invalidate_mapping_pages(META_MAPPING(fio->sbi),
fio->old_blkaddr, fio->old_blkaddr);
f2fs_invalidate_compress_page(fio->sbi, fio->old_blkaddr);
}
if (GET_SEGNO(fio->sbi, fio->old_blkaddr) != NULL_SEGNO)
f2fs_invalidate_internal_cache(fio->sbi, fio->old_blkaddr);
/* writeout dirty page into bdev */
f2fs_submit_page_write(fio);
@ -3757,9 +3755,7 @@ void f2fs_do_replace_block(struct f2fs_sb_info *sbi, struct f2fs_summary *sum,
update_sit_entry(sbi, new_blkaddr, 1);
}
if (GET_SEGNO(sbi, old_blkaddr) != NULL_SEGNO) {
invalidate_mapping_pages(META_MAPPING(sbi),
old_blkaddr, old_blkaddr);
f2fs_invalidate_compress_page(sbi, old_blkaddr);
f2fs_invalidate_internal_cache(sbi, old_blkaddr);
if (!from_gc)
update_segment_mtime(sbi, old_blkaddr, 0);
update_sit_entry(sbi, old_blkaddr, -1);
@ -4865,99 +4861,56 @@ static int check_zone_write_pointer(struct f2fs_sb_info *sbi,
struct f2fs_dev_info *fdev,
struct blk_zone *zone)
{
unsigned int wp_segno, wp_blkoff, zone_secno, zone_segno, segno;
block_t zone_block, wp_block, last_valid_block;
unsigned int zone_segno;
block_t zone_block, valid_block_cnt;
unsigned int log_sectors_per_block = sbi->log_blocksize - SECTOR_SHIFT;
int i, s, b, ret;
struct seg_entry *se;
int ret;
if (zone->type != BLK_ZONE_TYPE_SEQWRITE_REQ)
return 0;
wp_block = fdev->start_blk + (zone->wp >> log_sectors_per_block);
wp_segno = GET_SEGNO(sbi, wp_block);
wp_blkoff = wp_block - START_BLOCK(sbi, wp_segno);
zone_block = fdev->start_blk + (zone->start >> log_sectors_per_block);
zone_segno = GET_SEGNO(sbi, zone_block);
zone_secno = GET_SEC_FROM_SEG(sbi, zone_segno);
if (zone_segno >= MAIN_SEGS(sbi))
return 0;
/*
* Skip check of zones cursegs point to, since
* fix_curseg_write_pointer() checks them.
*/
for (i = 0; i < NO_CHECK_TYPE; i++)
if (zone_secno == GET_SEC_FROM_SEG(sbi,
CURSEG_I(sbi, i)->segno))
return 0;
if (zone_segno >= MAIN_SEGS(sbi) ||
IS_CURSEC(sbi, GET_SEC_FROM_SEG(sbi, zone_segno)))
return 0;
/*
* Get last valid block of the zone.
* Get # of valid block of the zone.
*/
last_valid_block = zone_block - 1;
for (s = sbi->segs_per_sec - 1; s >= 0; s--) {
segno = zone_segno + s;
se = get_seg_entry(sbi, segno);
for (b = sbi->blocks_per_seg - 1; b >= 0; b--)
if (f2fs_test_bit(b, se->cur_valid_map)) {
last_valid_block = START_BLOCK(sbi, segno) + b;
break;
}
if (last_valid_block >= zone_block)
break;
}
valid_block_cnt = get_valid_blocks(sbi, zone_segno, true);
/*
* When safely unmounted in the previous mount, we can trust write
* pointers. Otherwise, finish zones.
*/
if (is_set_ckpt_flags(sbi, CP_UMOUNT_FLAG)) {
/*
* The write pointer matches with the valid blocks or
* already points to the end of the zone.
*/
if ((last_valid_block + 1 == wp_block) ||
(zone->wp == zone->start + zone->len))
return 0;
}
if ((!valid_block_cnt && zone->cond == BLK_ZONE_COND_EMPTY) ||
(valid_block_cnt && zone->cond == BLK_ZONE_COND_FULL))
return 0;
if (last_valid_block + 1 == zone_block) {
if (is_set_ckpt_flags(sbi, CP_UMOUNT_FLAG)) {
/*
* If there is no valid block in the zone and if write
* pointer is not at zone start, reset the write
* pointer.
*/
f2fs_notice(sbi,
"Zone without valid block has non-zero write "
"pointer. Reset the write pointer: wp[0x%x,0x%x]",
wp_segno, wp_blkoff);
}
if (!valid_block_cnt) {
f2fs_notice(sbi, "Zone without valid block has non-zero write "
"pointer. Reset the write pointer: cond[0x%x]",
zone->cond);
ret = __f2fs_issue_discard_zone(sbi, fdev->bdev, zone_block,
zone->len >> log_sectors_per_block);
if (ret)
f2fs_err(sbi, "Discard zone failed: %s (errno=%d)",
fdev->path, ret);
return ret;
}
if (is_set_ckpt_flags(sbi, CP_UMOUNT_FLAG)) {
/*
* If there are valid blocks and the write pointer doesn't match
* with them, we need to report the inconsistency and fill
* the zone till the end to close the zone. This inconsistency
* does not cause write error because the zone will not be
* selected for write operation until it get discarded.
*/
f2fs_notice(sbi, "Valid blocks are not aligned with write "
"pointer: valid block[0x%x,0x%x] wp[0x%x,0x%x]",
GET_SEGNO(sbi, last_valid_block),
GET_BLKOFF_FROM_SEG0(sbi, last_valid_block),
wp_segno, wp_blkoff);
}
/*
* If there are valid blocks and the write pointer doesn't match
* with them, we need to report the inconsistency and fill
* the zone till the end to close the zone. This inconsistency
* does not cause write error because the zone will not be
* selected for write operation until it get discarded.
*/
f2fs_notice(sbi, "Valid blocks are not aligned with write "
"pointer: valid block[0x%x,0x%x] cond[0x%x]",
zone_segno, valid_block_cnt, zone->cond);
ret = blkdev_zone_mgmt(fdev->bdev, REQ_OP_ZONE_FINISH,
zone->start, zone->len, GFP_NOFS);
@ -5048,15 +5001,18 @@ static int fix_curseg_write_pointer(struct f2fs_sb_info *sbi, int type)
f2fs_notice(sbi, "Unaligned curseg[%d] with write pointer: "
"curseg[0x%x,0x%x] wp[0x%x,0x%x]", type, cs->segno,
cs->next_blkoff, wp_segno, wp_blkoff);
} else {
f2fs_notice(sbi, "Not successfully unmounted in the previous "
"mount");
}
f2fs_notice(sbi, "Assign new section to curseg[%d]: "
"curseg[0x%x,0x%x]", type, cs->segno, cs->next_blkoff);
/* Allocate a new section if it's not new. */
if (cs->next_blkoff) {
unsigned int old_segno = cs->segno, old_blkoff = cs->next_blkoff;
f2fs_allocate_new_section(sbi, type, true);
f2fs_allocate_new_section(sbi, type, true);
f2fs_notice(sbi, "Assign new section to curseg[%d]: "
"[0x%x,0x%x] -> [0x%x,0x%x]",
type, old_segno, old_blkoff,
cs->segno, cs->next_blkoff);
}
/* check consistency of the zone curseg pointed to */
if (check_zone_write_pointer(sbi, zbd, &zone))

View File

@ -1422,11 +1422,6 @@ default_check:
}
}
if (test_opt(sbi, DISABLE_CHECKPOINT) && f2fs_lfs_mode(sbi)) {
f2fs_err(sbi, "LFS is not compatible with checkpoint=disable");
return -EINVAL;
}
if (test_opt(sbi, ATGC) && f2fs_lfs_mode(sbi)) {
f2fs_err(sbi, "LFS is not compatible with ATGC");
return -EINVAL;
@ -3361,6 +3356,14 @@ loff_t max_file_blocks(struct inode *inode)
leaf_count *= NIDS_PER_BLOCK;
result += leaf_count;
/*
* For compatibility with FSCRYPT_POLICY_FLAG_IV_INO_LBLK_{64,32} with
* a 4K crypto data unit, we must restrict the max filesize to what can
* fit within U32_MAX + 1 data units.
*/
result = min(result, (((loff_t)U32_MAX + 1) * 4096) >> F2FS_BLKSIZE_BITS);
return result;
}
@ -4740,7 +4743,7 @@ try_onemore:
#ifdef CONFIG_QUOTA
f2fs_recover_quota_end(sbi, quota_enabled);
#endif
reset_checkpoint:
/*
* If the f2fs is not readonly and fsync data recovery succeeds,
* check zoned block devices' write pointer consistency.
@ -4751,7 +4754,6 @@ try_onemore:
goto free_meta;
}
reset_checkpoint:
f2fs_init_inmem_curseg(sbi);
/* f2fs_recover_fsync_data() cleared this already */

View File

@ -143,6 +143,33 @@ static ssize_t pending_discard_show(struct f2fs_attr *a,
&SM_I(sbi)->dcc_info->discard_cmd_cnt));
}
static ssize_t issued_discard_show(struct f2fs_attr *a,
struct f2fs_sb_info *sbi, char *buf)
{
if (!SM_I(sbi)->dcc_info)
return -EINVAL;
return sysfs_emit(buf, "%llu\n", (unsigned long long)atomic_read(
&SM_I(sbi)->dcc_info->issued_discard));
}
static ssize_t queued_discard_show(struct f2fs_attr *a,
struct f2fs_sb_info *sbi, char *buf)
{
if (!SM_I(sbi)->dcc_info)
return -EINVAL;
return sysfs_emit(buf, "%llu\n", (unsigned long long)atomic_read(
&SM_I(sbi)->dcc_info->queued_discard));
}
static ssize_t undiscard_blks_show(struct f2fs_attr *a,
struct f2fs_sb_info *sbi, char *buf)
{
if (!SM_I(sbi)->dcc_info)
return -EINVAL;
return sysfs_emit(buf, "%u\n",
SM_I(sbi)->dcc_info->undiscard_blks);
}
static ssize_t gc_mode_show(struct f2fs_attr *a,
struct f2fs_sb_info *sbi, char *buf)
{
@ -516,6 +543,13 @@ out:
return count;
}
if (!strcmp(a->attr.name, "discard_io_aware")) {
if (t >= DPOLICY_IO_AWARE_MAX)
return -EINVAL;
*ui = t;
return count;
}
if (!strcmp(a->attr.name, "migration_granularity")) {
if (t == 0 || t > sbi->segs_per_sec)
return -EINVAL;
@ -734,6 +768,13 @@ out:
return count;
}
if (!strcmp(a->attr.name, "dir_level")) {
if (t > MAX_DIR_HASH_DEPTH)
return -EINVAL;
sbi->dir_level = t;
return count;
}
*ui = (unsigned int)t;
return count;
@ -926,6 +967,7 @@ DCC_INFO_GENERAL_RW_ATTR(discard_io_aware_gran);
DCC_INFO_GENERAL_RW_ATTR(discard_urgent_util);
DCC_INFO_GENERAL_RW_ATTR(discard_granularity);
DCC_INFO_GENERAL_RW_ATTR(max_ordered_discard);
DCC_INFO_GENERAL_RW_ATTR(discard_io_aware);
/* NM_INFO ATTR */
NM_INFO_RW_ATTR(max_roll_forward_node_blocks, max_rf_node_blocks);
@ -1074,6 +1116,7 @@ static struct attribute *f2fs_attrs[] = {
ATTR_LIST(discard_urgent_util),
ATTR_LIST(discard_granularity),
ATTR_LIST(max_ordered_discard),
ATTR_LIST(discard_io_aware),
ATTR_LIST(pending_discard),
ATTR_LIST(gc_mode),
ATTR_LIST(ipu_policy),
@ -1197,9 +1240,16 @@ ATTRIBUTE_GROUPS(f2fs_feat);
F2FS_GENERAL_RO_ATTR(sb_status);
F2FS_GENERAL_RO_ATTR(cp_status);
F2FS_GENERAL_RO_ATTR(issued_discard);
F2FS_GENERAL_RO_ATTR(queued_discard);
F2FS_GENERAL_RO_ATTR(undiscard_blks);
static struct attribute *f2fs_stat_attrs[] = {
ATTR_LIST(sb_status),
ATTR_LIST(cp_status),
ATTR_LIST(issued_discard),
ATTR_LIST(queued_discard),
ATTR_LIST(undiscard_blks),
NULL,
};
ATTRIBUTE_GROUPS(f2fs_stat);

View File

@ -660,11 +660,14 @@ retry:
here = __find_xattr(base_addr, last_base_addr, NULL, index, len, name);
if (!here) {
if (!F2FS_I(inode)->i_xattr_nid) {
error = f2fs_recover_xattr_data(inode, NULL);
f2fs_notice(F2FS_I_SB(inode),
"recover xattr in inode (%lu)", inode->i_ino);
f2fs_recover_xattr_data(inode, NULL);
kfree(base_addr);
goto retry;
"recover xattr in inode (%lu), error(%d)",
inode->i_ino, error);
if (!error) {
kfree(base_addr);
goto retry;
}
}
f2fs_err(F2FS_I_SB(inode), "set inode (%lu) has corrupted xattr",
inode->i_ino);
@ -754,6 +757,12 @@ retry:
memcpy(pval, value, size);
last->e_value_size = cpu_to_le16(size);
new_hsize += newsize;
/*
* Explicitly add the null terminator. The unused xattr space
* is supposed to always be zeroed, which would make this
* unnecessary, but don't depend on that.
*/
*(u32 *)((u8 *)last + newsize) = 0;
}
error = write_all_xattrs(inode, new_hsize, base_addr, ipage);

View File

@ -441,7 +441,7 @@ struct f2fs_sit_block {
* ex) data_blkaddr = (block_t)(nodepage_start_address + ofs_in_node)
*/
#define ENTRIES_IN_SUM (F2FS_BLKSIZE / 8)
#define SUMMARY_SIZE (7) /* sizeof(struct summary) */
#define SUMMARY_SIZE (7) /* sizeof(struct f2fs_summary) */
#define SUM_FOOTER_SIZE (5) /* sizeof(struct summary_footer) */
#define SUM_ENTRY_SIZE (SUMMARY_SIZE * ENTRIES_IN_SUM)

View File

@ -161,6 +161,19 @@ TRACE_DEFINE_ENUM(EX_BLOCK_AGE);
{ EX_READ, "Read" }, \
{ EX_BLOCK_AGE, "Block Age" })
#define show_inode_type(x) \
__print_symbolic(x, \
{ S_IFLNK, "symbolic" }, \
{ S_IFREG, "regular" }, \
{ S_IFDIR, "directory" }, \
{ S_IFCHR, "character" }, \
{ S_IFBLK, "block" }, \
{ S_IFIFO, "fifo" }, \
{ S_IFSOCK, "sock" })
#define S_ALL_PERM (S_ISUID | S_ISGID | S_ISVTX | \
S_IRWXU | S_IRWXG | S_IRWXO)
struct f2fs_sb_info;
struct f2fs_io_info;
struct extent_info;
@ -215,17 +228,21 @@ DECLARE_EVENT_CLASS(f2fs__inode_exit,
TP_STRUCT__entry(
__field(dev_t, dev)
__field(ino_t, ino)
__field(umode_t, mode)
__field(int, ret)
),
TP_fast_assign(
__entry->dev = inode->i_sb->s_dev;
__entry->ino = inode->i_ino;
__entry->mode = inode->i_mode;
__entry->ret = ret;
),
TP_printk("dev = (%d,%d), ino = %lu, ret = %d",
TP_printk("dev = (%d,%d), ino = %lu, type: %s, mode = 0%o, ret = %d",
show_dev_ino(__entry),
show_inode_type(__entry->mode & S_IFMT),
__entry->mode & S_ALL_PERM,
__entry->ret)
);
@ -866,6 +883,75 @@ TRACE_EVENT(f2fs_lookup_end,
__entry->err)
);
TRACE_EVENT(f2fs_rename_start,
TP_PROTO(struct inode *old_dir, struct dentry *old_dentry,
struct inode *new_dir, struct dentry *new_dentry,
unsigned int flags),
TP_ARGS(old_dir, old_dentry, new_dir, new_dentry, flags),
TP_STRUCT__entry(
__field(dev_t, dev)
__field(ino_t, ino)
__string(old_name, old_dentry->d_name.name)
__field(ino_t, new_pino)
__string(new_name, new_dentry->d_name.name)
__field(unsigned int, flags)
),
TP_fast_assign(
__entry->dev = old_dir->i_sb->s_dev;
__entry->ino = old_dir->i_ino;
__assign_str(old_name, old_dentry->d_name.name);
__entry->new_pino = new_dir->i_ino;
__assign_str(new_name, new_dentry->d_name.name);
__entry->flags = flags;
),
TP_printk("dev = (%d,%d), old_dir = %lu, old_name: %s, "
"new_dir = %lu, new_name: %s, flags = %u",
show_dev_ino(__entry),
__get_str(old_name),
__entry->new_pino,
__get_str(new_name),
__entry->flags)
);
TRACE_EVENT(f2fs_rename_end,
TP_PROTO(struct dentry *old_dentry, struct dentry *new_dentry,
unsigned int flags, int ret),
TP_ARGS(old_dentry, new_dentry, flags, ret),
TP_STRUCT__entry(
__field(dev_t, dev)
__field(ino_t, ino)
__string(old_name, old_dentry->d_name.name)
__string(new_name, new_dentry->d_name.name)
__field(unsigned int, flags)
__field(int, ret)
),
TP_fast_assign(
__entry->dev = old_dentry->d_sb->s_dev;
__entry->ino = old_dentry->d_inode->i_ino;
__assign_str(old_name, old_dentry->d_name.name);
__assign_str(new_name, new_dentry->d_name.name);
__entry->flags = flags;
__entry->ret = ret;
),
TP_printk("dev = (%d,%d), ino = %lu, old_name: %s, "
"new_name: %s, flags = %u, ret = %d",
show_dev_ino(__entry),
__get_str(old_name),
__get_str(new_name),
__entry->flags,
__entry->ret)
);
TRACE_EVENT(f2fs_readdir,
TP_PROTO(struct inode *dir, loff_t start_pos, loff_t end_pos, int err),
@ -1283,13 +1369,6 @@ DEFINE_EVENT(f2fs__page, f2fs_set_page_dirty,
TP_ARGS(page, type)
);
DEFINE_EVENT(f2fs__page, f2fs_vm_page_mkwrite,
TP_PROTO(struct page *page, int type),
TP_ARGS(page, type)
);
TRACE_EVENT(f2fs_replace_atomic_write_block,
TP_PROTO(struct inode *inode, struct inode *cow_inode, pgoff_t index,
@ -1327,30 +1406,50 @@ TRACE_EVENT(f2fs_replace_atomic_write_block,
__entry->recovery)
);
TRACE_EVENT(f2fs_filemap_fault,
DECLARE_EVENT_CLASS(f2fs_mmap,
TP_PROTO(struct inode *inode, pgoff_t index, unsigned long ret),
TP_PROTO(struct inode *inode, pgoff_t index,
vm_flags_t flags, vm_fault_t ret),
TP_ARGS(inode, index, ret),
TP_ARGS(inode, index, flags, ret),
TP_STRUCT__entry(
__field(dev_t, dev)
__field(ino_t, ino)
__field(pgoff_t, index)
__field(unsigned long, ret)
__field(vm_flags_t, flags)
__field(vm_fault_t, ret)
),
TP_fast_assign(
__entry->dev = inode->i_sb->s_dev;
__entry->ino = inode->i_ino;
__entry->index = index;
__entry->flags = flags;
__entry->ret = ret;
),
TP_printk("dev = (%d,%d), ino = %lu, index = %lu, ret = %lx",
TP_printk("dev = (%d,%d), ino = %lu, index = %lu, flags: %s, ret: %s",
show_dev_ino(__entry),
(unsigned long)__entry->index,
__entry->ret)
__print_flags(__entry->flags, "|", FAULT_FLAG_TRACE),
__print_flags(__entry->ret, "|", VM_FAULT_RESULT_TRACE))
);
DEFINE_EVENT(f2fs_mmap, f2fs_filemap_fault,
TP_PROTO(struct inode *inode, pgoff_t index,
vm_flags_t flags, vm_fault_t ret),
TP_ARGS(inode, index, flags, ret)
);
DEFINE_EVENT(f2fs_mmap, f2fs_vm_page_mkwrite,
TP_PROTO(struct inode *inode, pgoff_t index,
vm_flags_t flags, vm_fault_t ret),
TP_ARGS(inode, index, flags, ret)
);
TRACE_EVENT(f2fs_writepages,