Commit a02cd422 authored by Linus Torvalds's avatar Linus Torvalds

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

Pull f2fs updates from Jaegeuk Kim:
 "In this round, we introduce sysfile-based quota support which is
  required for Android by default. In addition, we allow that users are
  able to reserve some blocks in runtime to mitigate performance drops
  in low free space.

  Enhancements:
   - assign proper data segments according to write_hints given by user
   - issue cache_flush on dirty devices only among multiple devices
   - exploit cp_error flag and add more faults to enhance fault
     injection test
   - conduct more readaheads during f2fs_readdir
   - add a range for discard commands

  Bug fixes:
   - fix zero stat->st_blocks when inline_data is set
   - drop crypto key and free stale memory pointer while evict_inode is
     failing
   - fix some corner cases in free space and segment management
   - fix wrong last_disk_size

  This series includes lots of clean-ups and code enhancement in terms
  of xattr operations, discard/flush command control. In addition, it
  adds versatile debugfs entries to monitor f2fs status"

* tag 'f2fs-for-4.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs: (75 commits)
  f2fs: deny accessing encryption policy if encryption is off
  f2fs: inject fault in inc_valid_node_count
  f2fs: fix to clear FI_NO_PREALLOC
  f2fs: expose quota information in debugfs
  f2fs: separate nat entry mem alloc from nat_tree_lock
  f2fs: validate before set/clear free nat bitmap
  f2fs: avoid opened loop codes in __add_ino_entry
  f2fs: apply write hints to select the type of segments for buffered write
  f2fs: introduce scan_curseg_cache for cleanup
  f2fs: optimize the way of traversing free_nid_bitmap
  f2fs: keep scanning until enough free nids are acquired
  f2fs: trace checkpoint reason in fsync()
  f2fs: keep isize once block is reserved cross EOF
  f2fs: avoid race in between GC and block exchange
  f2fs: save a multiplication for last_nid calculation
  f2fs: fix summary info corruption
  f2fs: remove dead code in update_meta_page
  f2fs: remove unneeded semicolon
  f2fs: don't bother with inode->i_version
  f2fs: check curseg space before foreground GC
  ...
parents 487e2c9f ead710b7
...@@ -51,6 +51,18 @@ Description: ...@@ -51,6 +51,18 @@ Description:
Controls the dirty page count condition for the in-place-update Controls the dirty page count condition for the in-place-update
policies. policies.
What: /sys/fs/f2fs/<disk>/min_hot_blocks
Date: March 2017
Contact: "Jaegeuk Kim" <jaegeuk@kernel.org>
Description:
Controls the dirty page count condition for redefining hot data.
What: /sys/fs/f2fs/<disk>/min_ssr_sections
Date: October 2017
Contact: "Chao Yu" <yuchao0@huawei.com>
Description:
Controls the fee section threshold to trigger SSR allocation.
What: /sys/fs/f2fs/<disk>/max_small_discards What: /sys/fs/f2fs/<disk>/max_small_discards
Date: November 2013 Date: November 2013
Contact: "Jaegeuk Kim" <jaegeuk.kim@samsung.com> Contact: "Jaegeuk Kim" <jaegeuk.kim@samsung.com>
...@@ -102,6 +114,12 @@ Contact: "Jaegeuk Kim" <jaegeuk@kernel.org> ...@@ -102,6 +114,12 @@ Contact: "Jaegeuk Kim" <jaegeuk@kernel.org>
Description: Description:
Controls the idle timing. Controls the idle timing.
What: /sys/fs/f2fs/<disk>/iostat_enable
Date: August 2017
Contact: "Chao Yu" <yuchao0@huawei.com>
Description:
Controls to enable/disable IO stat.
What: /sys/fs/f2fs/<disk>/ra_nid_pages What: /sys/fs/f2fs/<disk>/ra_nid_pages
Date: October 2015 Date: October 2015
Contact: "Chao Yu" <chao2.yu@samsung.com> Contact: "Chao Yu" <chao2.yu@samsung.com>
...@@ -122,6 +140,12 @@ Contact: "Shuoran Liu" <liushuoran@huawei.com> ...@@ -122,6 +140,12 @@ Contact: "Shuoran Liu" <liushuoran@huawei.com>
Description: Description:
Shows total written kbytes issued to disk. Shows total written kbytes issued to disk.
What: /sys/fs/f2fs/<disk>/feature
Date: July 2017
Contact: "Jaegeuk Kim" <jaegeuk@kernel.org>
Description:
Shows all enabled features in current device.
What: /sys/fs/f2fs/<disk>/inject_rate What: /sys/fs/f2fs/<disk>/inject_rate
Date: May 2016 Date: May 2016
Contact: "Sheng Yong" <shengyong1@huawei.com> Contact: "Sheng Yong" <shengyong1@huawei.com>
...@@ -138,7 +162,18 @@ What: /sys/fs/f2fs/<disk>/reserved_blocks ...@@ -138,7 +162,18 @@ What: /sys/fs/f2fs/<disk>/reserved_blocks
Date: June 2017 Date: June 2017
Contact: "Chao Yu" <yuchao0@huawei.com> Contact: "Chao Yu" <yuchao0@huawei.com>
Description: Description:
Controls current reserved blocks in system. Controls target reserved blocks in system, the threshold
is soft, it could exceed current available user space.
What: /sys/fs/f2fs/<disk>/current_reserved_blocks
Date: October 2017
Contact: "Yunlong Song" <yunlong.song@huawei.com>
Contact: "Chao Yu" <yuchao0@huawei.com>
Description:
Shows current reserved blocks in system, it may be temporarily
smaller than target_reserved_blocks, but will gradually
increase to target_reserved_blocks when more free blocks are
freed by user later.
What: /sys/fs/f2fs/<disk>/gc_urgent What: /sys/fs/f2fs/<disk>/gc_urgent
Date: August 2017 Date: August 2017
......
...@@ -250,6 +250,9 @@ static int __f2fs_set_acl(struct inode *inode, int type, ...@@ -250,6 +250,9 @@ static int __f2fs_set_acl(struct inode *inode, int type,
int f2fs_set_acl(struct inode *inode, struct posix_acl *acl, int type) int f2fs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
{ {
if (unlikely(f2fs_cp_error(F2FS_I_SB(inode))))
return -EIO;
return __f2fs_set_acl(inode, type, acl, NULL); return __f2fs_set_acl(inode, type, acl, NULL);
} }
......
...@@ -29,7 +29,6 @@ struct kmem_cache *inode_entry_slab; ...@@ -29,7 +29,6 @@ struct kmem_cache *inode_entry_slab;
void f2fs_stop_checkpoint(struct f2fs_sb_info *sbi, bool end_io) void f2fs_stop_checkpoint(struct f2fs_sb_info *sbi, bool end_io)
{ {
set_ckpt_flags(sbi, CP_ERROR_FLAG); set_ckpt_flags(sbi, CP_ERROR_FLAG);
sbi->sb->s_flags |= MS_RDONLY;
if (!end_io) if (!end_io)
f2fs_flush_merged_writes(sbi); f2fs_flush_merged_writes(sbi);
} }
...@@ -398,24 +397,23 @@ const struct address_space_operations f2fs_meta_aops = { ...@@ -398,24 +397,23 @@ const struct address_space_operations f2fs_meta_aops = {
#endif #endif
}; };
static void __add_ino_entry(struct f2fs_sb_info *sbi, nid_t ino, int type) static void __add_ino_entry(struct f2fs_sb_info *sbi, nid_t ino,
unsigned int devidx, int type)
{ {
struct inode_management *im = &sbi->im[type]; struct inode_management *im = &sbi->im[type];
struct ino_entry *e, *tmp; struct ino_entry *e, *tmp;
tmp = f2fs_kmem_cache_alloc(ino_entry_slab, GFP_NOFS); tmp = f2fs_kmem_cache_alloc(ino_entry_slab, GFP_NOFS);
retry:
radix_tree_preload(GFP_NOFS | __GFP_NOFAIL); radix_tree_preload(GFP_NOFS | __GFP_NOFAIL);
spin_lock(&im->ino_lock); spin_lock(&im->ino_lock);
e = radix_tree_lookup(&im->ino_root, ino); e = radix_tree_lookup(&im->ino_root, ino);
if (!e) { if (!e) {
e = tmp; e = tmp;
if (radix_tree_insert(&im->ino_root, ino, e)) { if (unlikely(radix_tree_insert(&im->ino_root, ino, e)))
spin_unlock(&im->ino_lock); f2fs_bug_on(sbi, 1);
radix_tree_preload_end();
goto retry;
}
memset(e, 0, sizeof(struct ino_entry)); memset(e, 0, sizeof(struct ino_entry));
e->ino = ino; e->ino = ino;
...@@ -423,6 +421,10 @@ static void __add_ino_entry(struct f2fs_sb_info *sbi, nid_t ino, int type) ...@@ -423,6 +421,10 @@ static void __add_ino_entry(struct f2fs_sb_info *sbi, nid_t ino, int type)
if (type != ORPHAN_INO) if (type != ORPHAN_INO)
im->ino_num++; im->ino_num++;
} }
if (type == FLUSH_INO)
f2fs_set_bit(devidx, (char *)&e->dirty_device);
spin_unlock(&im->ino_lock); spin_unlock(&im->ino_lock);
radix_tree_preload_end(); radix_tree_preload_end();
...@@ -451,7 +453,7 @@ static void __remove_ino_entry(struct f2fs_sb_info *sbi, nid_t ino, int type) ...@@ -451,7 +453,7 @@ static void __remove_ino_entry(struct f2fs_sb_info *sbi, nid_t ino, int type)
void add_ino_entry(struct f2fs_sb_info *sbi, nid_t ino, int type) void add_ino_entry(struct f2fs_sb_info *sbi, nid_t ino, int type)
{ {
/* add new dirty ino entry into list */ /* add new dirty ino entry into list */
__add_ino_entry(sbi, ino, type); __add_ino_entry(sbi, ino, 0, type);
} }
void remove_ino_entry(struct f2fs_sb_info *sbi, nid_t ino, int type) void remove_ino_entry(struct f2fs_sb_info *sbi, nid_t ino, int type)
...@@ -477,7 +479,7 @@ void release_ino_entry(struct f2fs_sb_info *sbi, bool all) ...@@ -477,7 +479,7 @@ void release_ino_entry(struct f2fs_sb_info *sbi, bool all)
struct ino_entry *e, *tmp; struct ino_entry *e, *tmp;
int i; int i;
for (i = all ? ORPHAN_INO: APPEND_INO; i <= UPDATE_INO; i++) { for (i = all ? ORPHAN_INO : APPEND_INO; i < MAX_INO_ENTRY; i++) {
struct inode_management *im = &sbi->im[i]; struct inode_management *im = &sbi->im[i];
spin_lock(&im->ino_lock); spin_lock(&im->ino_lock);
...@@ -491,6 +493,27 @@ void release_ino_entry(struct f2fs_sb_info *sbi, bool all) ...@@ -491,6 +493,27 @@ void release_ino_entry(struct f2fs_sb_info *sbi, bool all)
} }
} }
void set_dirty_device(struct f2fs_sb_info *sbi, nid_t ino,
unsigned int devidx, int type)
{
__add_ino_entry(sbi, ino, devidx, type);
}
bool is_dirty_device(struct f2fs_sb_info *sbi, nid_t ino,
unsigned int devidx, int type)
{
struct inode_management *im = &sbi->im[type];
struct ino_entry *e;
bool is_dirty = false;
spin_lock(&im->ino_lock);
e = radix_tree_lookup(&im->ino_root, ino);
if (e && f2fs_test_bit(devidx, (char *)&e->dirty_device))
is_dirty = true;
spin_unlock(&im->ino_lock);
return is_dirty;
}
int acquire_orphan_inode(struct f2fs_sb_info *sbi) int acquire_orphan_inode(struct f2fs_sb_info *sbi)
{ {
struct inode_management *im = &sbi->im[ORPHAN_INO]; struct inode_management *im = &sbi->im[ORPHAN_INO];
...@@ -527,7 +550,7 @@ void release_orphan_inode(struct f2fs_sb_info *sbi) ...@@ -527,7 +550,7 @@ void release_orphan_inode(struct f2fs_sb_info *sbi)
void add_orphan_inode(struct inode *inode) void add_orphan_inode(struct inode *inode)
{ {
/* add new orphan ino entry into list */ /* add new orphan ino entry into list */
__add_ino_entry(F2FS_I_SB(inode), inode->i_ino, ORPHAN_INO); __add_ino_entry(F2FS_I_SB(inode), inode->i_ino, 0, ORPHAN_INO);
update_inode_page(inode); update_inode_page(inode);
} }
...@@ -551,7 +574,7 @@ static int recover_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino) ...@@ -551,7 +574,7 @@ static int recover_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino)
return err; return err;
} }
__add_ino_entry(sbi, ino, ORPHAN_INO); __add_ino_entry(sbi, ino, 0, ORPHAN_INO);
inode = f2fs_iget_retry(sbi->sb, ino); inode = f2fs_iget_retry(sbi->sb, ino);
if (IS_ERR(inode)) { if (IS_ERR(inode)) {
...@@ -587,6 +610,9 @@ int recover_orphan_inodes(struct f2fs_sb_info *sbi) ...@@ -587,6 +610,9 @@ int recover_orphan_inodes(struct f2fs_sb_info *sbi)
block_t start_blk, orphan_blocks, i, j; block_t start_blk, orphan_blocks, i, j;
unsigned int s_flags = sbi->sb->s_flags; unsigned int s_flags = sbi->sb->s_flags;
int err = 0; int err = 0;
#ifdef CONFIG_QUOTA
int quota_enabled;
#endif
if (!is_set_ckpt_flags(sbi, CP_ORPHAN_PRESENT_FLAG)) if (!is_set_ckpt_flags(sbi, CP_ORPHAN_PRESENT_FLAG))
return 0; return 0;
...@@ -599,8 +625,9 @@ int recover_orphan_inodes(struct f2fs_sb_info *sbi) ...@@ -599,8 +625,9 @@ int recover_orphan_inodes(struct f2fs_sb_info *sbi)
#ifdef CONFIG_QUOTA #ifdef CONFIG_QUOTA
/* Needed for iput() to work correctly and not trash data */ /* Needed for iput() to work correctly and not trash data */
sbi->sb->s_flags |= MS_ACTIVE; sbi->sb->s_flags |= MS_ACTIVE;
/* Turn on quotas so that they are updated correctly */ /* Turn on quotas so that they are updated correctly */
f2fs_enable_quota_files(sbi); quota_enabled = f2fs_enable_quota_files(sbi, s_flags & MS_RDONLY);
#endif #endif
start_blk = __start_cp_addr(sbi) + 1 + __cp_payload(sbi); start_blk = __start_cp_addr(sbi) + 1 + __cp_payload(sbi);
...@@ -628,7 +655,8 @@ int recover_orphan_inodes(struct f2fs_sb_info *sbi) ...@@ -628,7 +655,8 @@ int recover_orphan_inodes(struct f2fs_sb_info *sbi)
out: out:
#ifdef CONFIG_QUOTA #ifdef CONFIG_QUOTA
/* Turn quotas off */ /* Turn quotas off */
f2fs_quota_off_umount(sbi->sb); if (quota_enabled)
f2fs_quota_off_umount(sbi->sb);
#endif #endif
sbi->sb->s_flags = s_flags; /* Restore MS_RDONLY status */ sbi->sb->s_flags = s_flags; /* Restore MS_RDONLY status */
...@@ -983,7 +1011,7 @@ int f2fs_sync_inode_meta(struct f2fs_sb_info *sbi) ...@@ -983,7 +1011,7 @@ int f2fs_sync_inode_meta(struct f2fs_sb_info *sbi)
update_inode_page(inode); update_inode_page(inode);
iput(inode); iput(inode);
} }
}; }
return 0; return 0;
} }
...@@ -1143,6 +1171,7 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) ...@@ -1143,6 +1171,7 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
struct super_block *sb = sbi->sb; struct super_block *sb = sbi->sb;
struct curseg_info *seg_i = CURSEG_I(sbi, CURSEG_HOT_NODE); struct curseg_info *seg_i = CURSEG_I(sbi, CURSEG_HOT_NODE);
u64 kbytes_written; u64 kbytes_written;
int err;
/* Flush all the NAT/SIT pages */ /* Flush all the NAT/SIT pages */
while (get_pages(sbi, F2FS_DIRTY_META)) { while (get_pages(sbi, F2FS_DIRTY_META)) {
...@@ -1236,6 +1265,11 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) ...@@ -1236,6 +1265,11 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
if (unlikely(f2fs_cp_error(sbi))) if (unlikely(f2fs_cp_error(sbi)))
return -EIO; return -EIO;
/* flush all device cache */
err = f2fs_flush_device_cache(sbi);
if (err)
return err;
/* write out checkpoint buffer at block 0 */ /* write out checkpoint buffer at block 0 */
update_meta_page(sbi, ckpt, start_blk++); update_meta_page(sbi, ckpt, start_blk++);
......
...@@ -173,7 +173,7 @@ static struct bio *__bio_alloc(struct f2fs_sb_info *sbi, block_t blk_addr, ...@@ -173,7 +173,7 @@ static struct bio *__bio_alloc(struct f2fs_sb_info *sbi, block_t blk_addr,
{ {
struct bio *bio; struct bio *bio;
bio = f2fs_bio_alloc(npages); bio = f2fs_bio_alloc(sbi, npages, true);
f2fs_target_device(sbi, blk_addr, bio); f2fs_target_device(sbi, blk_addr, bio);
bio->bi_end_io = is_read ? f2fs_read_end_io : f2fs_write_end_io; bio->bi_end_io = is_read ? f2fs_read_end_io : f2fs_write_end_io;
...@@ -418,8 +418,8 @@ int f2fs_submit_page_write(struct f2fs_io_info *fio) ...@@ -418,8 +418,8 @@ int f2fs_submit_page_write(struct f2fs_io_info *fio)
bio_page = fio->encrypted_page ? fio->encrypted_page : fio->page; bio_page = fio->encrypted_page ? fio->encrypted_page : fio->page;
/* set submitted = 1 as a return value */ /* set submitted = true as a return value */
fio->submitted = 1; fio->submitted = true;
inc_page_count(sbi, WB_DATA_TYPE(bio_page)); inc_page_count(sbi, WB_DATA_TYPE(bio_page));
...@@ -473,7 +473,7 @@ static struct bio *f2fs_grab_read_bio(struct inode *inode, block_t blkaddr, ...@@ -473,7 +473,7 @@ static struct bio *f2fs_grab_read_bio(struct inode *inode, block_t blkaddr,
f2fs_wait_on_block_writeback(sbi, blkaddr); f2fs_wait_on_block_writeback(sbi, blkaddr);
} }
bio = bio_alloc(GFP_KERNEL, min_t(int, nr_pages, BIO_MAX_PAGES)); bio = f2fs_bio_alloc(sbi, min_t(int, nr_pages, BIO_MAX_PAGES), false);
if (!bio) { if (!bio) {
if (ctx) if (ctx)
fscrypt_release_ctx(ctx); fscrypt_release_ctx(ctx);
...@@ -833,6 +833,13 @@ int f2fs_preallocate_blocks(struct kiocb *iocb, struct iov_iter *from) ...@@ -833,6 +833,13 @@ int f2fs_preallocate_blocks(struct kiocb *iocb, struct iov_iter *from)
struct f2fs_map_blocks map; struct f2fs_map_blocks map;
int err = 0; int err = 0;
/* convert inline data for Direct I/O*/
if (iocb->ki_flags & IOCB_DIRECT) {
err = f2fs_convert_inline_inode(inode);
if (err)
return err;
}
if (is_inode_flag_set(inode, FI_NO_PREALLOC)) if (is_inode_flag_set(inode, FI_NO_PREALLOC))
return 0; return 0;
...@@ -845,15 +852,11 @@ int f2fs_preallocate_blocks(struct kiocb *iocb, struct iov_iter *from) ...@@ -845,15 +852,11 @@ int f2fs_preallocate_blocks(struct kiocb *iocb, struct iov_iter *from)
map.m_next_pgofs = NULL; map.m_next_pgofs = NULL;
if (iocb->ki_flags & IOCB_DIRECT) { if (iocb->ki_flags & IOCB_DIRECT)
err = f2fs_convert_inline_inode(inode);
if (err)
return err;
return f2fs_map_blocks(inode, &map, 1, return f2fs_map_blocks(inode, &map, 1,
__force_buffered_io(inode, WRITE) ? __force_buffered_io(inode, WRITE) ?
F2FS_GET_BLOCK_PRE_AIO : F2FS_GET_BLOCK_PRE_AIO :
F2FS_GET_BLOCK_PRE_DIO); F2FS_GET_BLOCK_PRE_DIO);
}
if (iocb->ki_pos + iov_iter_count(from) > MAX_INLINE_DATA(inode)) { if (iocb->ki_pos + iov_iter_count(from) > MAX_INLINE_DATA(inode)) {
err = f2fs_convert_inline_inode(inode); err = f2fs_convert_inline_inode(inode);
if (err) if (err)
...@@ -1334,7 +1337,7 @@ static int f2fs_read_data_pages(struct file *file, ...@@ -1334,7 +1337,7 @@ static int f2fs_read_data_pages(struct file *file,
struct address_space *mapping, struct address_space *mapping,
struct list_head *pages, unsigned nr_pages) struct list_head *pages, unsigned nr_pages)
{ {
struct inode *inode = file->f_mapping->host; struct inode *inode = mapping->host;
struct page *page = list_last_entry(pages, struct page, lru); struct page *page = list_last_entry(pages, struct page, lru);
trace_f2fs_readpages(inode, page, nr_pages); trace_f2fs_readpages(inode, page, nr_pages);
...@@ -1495,6 +1498,7 @@ static int __write_data_page(struct page *page, bool *submitted, ...@@ -1495,6 +1498,7 @@ static int __write_data_page(struct page *page, bool *submitted,
int err = 0; int err = 0;
struct f2fs_io_info fio = { struct f2fs_io_info fio = {
.sbi = sbi, .sbi = sbi,
.ino = inode->i_ino,
.type = DATA, .type = DATA,
.op = REQ_OP_WRITE, .op = REQ_OP_WRITE,
.op_flags = wbc_to_write_flags(wbc), .op_flags = wbc_to_write_flags(wbc),
...@@ -1566,8 +1570,11 @@ static int __write_data_page(struct page *page, bool *submitted, ...@@ -1566,8 +1570,11 @@ static int __write_data_page(struct page *page, bool *submitted,
err = do_write_data_page(&fio); err = do_write_data_page(&fio);
} }
} }
down_write(&F2FS_I(inode)->i_sem);
if (F2FS_I(inode)->last_disk_size < psize) if (F2FS_I(inode)->last_disk_size < psize)
F2FS_I(inode)->last_disk_size = psize; F2FS_I(inode)->last_disk_size = psize;
up_write(&F2FS_I(inode)->i_sem);
done: done:
if (err && err != -ENOENT) if (err && err != -ENOENT)
...@@ -1932,6 +1939,12 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping, ...@@ -1932,6 +1939,12 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping,
trace_f2fs_write_begin(inode, pos, len, flags); trace_f2fs_write_begin(inode, pos, len, flags);
if (f2fs_is_atomic_file(inode) &&
!available_free_memory(sbi, INMEM_PAGES)) {
err = -ENOMEM;
goto fail;
}
/* /*
* We should check this at this moment to avoid deadlock on inode page * We should check this at this moment to avoid deadlock on inode page
* and #0 page. The locking rule for inline_data conversion should be: * and #0 page. The locking rule for inline_data conversion should be:
...@@ -1947,7 +1960,7 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping, ...@@ -1947,7 +1960,7 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping,
* Do not use grab_cache_page_write_begin() to avoid deadlock due to * Do not use grab_cache_page_write_begin() to avoid deadlock due to
* wait_for_stable_page. Will wait that below with our IO control. * wait_for_stable_page. Will wait that below with our IO control.
*/ */
page = pagecache_get_page(mapping, index, page = f2fs_pagecache_get_page(mapping, index,
FGP_LOCK | FGP_WRITE | FGP_CREAT, GFP_NOFS); FGP_LOCK | FGP_WRITE | FGP_CREAT, GFP_NOFS);
if (!page) { if (!page) {
err = -ENOMEM; err = -ENOMEM;
...@@ -2009,6 +2022,8 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping, ...@@ -2009,6 +2022,8 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping,
fail: fail:
f2fs_put_page(page, 1); f2fs_put_page(page, 1);
f2fs_write_failed(mapping, pos + len); f2fs_write_failed(mapping, pos + len);
if (f2fs_is_atomic_file(inode))
drop_inmem_pages_all(sbi);
return err; return err;
} }
......
...@@ -45,9 +45,18 @@ static void update_general_status(struct f2fs_sb_info *sbi) ...@@ -45,9 +45,18 @@ static void update_general_status(struct f2fs_sb_info *sbi)
si->ndirty_dent = get_pages(sbi, F2FS_DIRTY_DENTS); si->ndirty_dent = get_pages(sbi, F2FS_DIRTY_DENTS);
si->ndirty_meta = get_pages(sbi, F2FS_DIRTY_META); si->ndirty_meta = get_pages(sbi, F2FS_DIRTY_META);
si->ndirty_data = get_pages(sbi, F2FS_DIRTY_DATA); si->ndirty_data = get_pages(sbi, F2FS_DIRTY_DATA);
si->ndirty_qdata = get_pages(sbi, F2FS_DIRTY_QDATA);
si->ndirty_imeta = get_pages(sbi, F2FS_DIRTY_IMETA); si->ndirty_imeta = get_pages(sbi, F2FS_DIRTY_IMETA);
si->ndirty_dirs = sbi->ndirty_inode[DIR_INODE]; si->ndirty_dirs = sbi->ndirty_inode[DIR_INODE];
si->ndirty_files = sbi->ndirty_inode[FILE_INODE]; si->ndirty_files = sbi->ndirty_inode[FILE_INODE];
si->nquota_files = 0;
if (f2fs_sb_has_quota_ino(sbi->sb)) {
for (i = 0; i < MAXQUOTAS; i++) {
if (f2fs_qf_ino(sbi->sb, i))
si->nquota_files++;
}
}
si->ndirty_all = sbi->ndirty_inode[DIRTY_META]; si->ndirty_all = sbi->ndirty_inode[DIRTY_META];
si->inmem_pages = get_pages(sbi, F2FS_INMEM_PAGES); si->inmem_pages = get_pages(sbi, F2FS_INMEM_PAGES);
si->aw_cnt = atomic_read(&sbi->aw_cnt); si->aw_cnt = atomic_read(&sbi->aw_cnt);
...@@ -61,6 +70,8 @@ static void update_general_status(struct f2fs_sb_info *sbi) ...@@ -61,6 +70,8 @@ static void update_general_status(struct f2fs_sb_info *sbi)
atomic_read(&SM_I(sbi)->fcc_info->issued_flush); atomic_read(&SM_I(sbi)->fcc_info->issued_flush);
si->nr_flushing = si->nr_flushing =
atomic_read(&SM_I(sbi)->fcc_info->issing_flush); atomic_read(&SM_I(sbi)->fcc_info->issing_flush);
si->flush_list_empty =
llist_empty(&SM_I(sbi)->fcc_info->issue_list);
} }
if (SM_I(sbi) && SM_I(sbi)->dcc_info) { if (SM_I(sbi) && SM_I(sbi)->dcc_info) {
si->nr_discarded = si->nr_discarded =
...@@ -96,9 +107,9 @@ static void update_general_status(struct f2fs_sb_info *sbi) ...@@ -96,9 +107,9 @@ static void update_general_status(struct f2fs_sb_info *sbi)
si->dirty_nats = NM_I(sbi)->dirty_nat_cnt; si->dirty_nats = NM_I(sbi)->dirty_nat_cnt;
si->sits = MAIN_SEGS(sbi); si->sits = MAIN_SEGS(sbi);
si->dirty_sits = SIT_I(sbi)->dirty_sentries; si->dirty_sits = SIT_I(sbi)->dirty_sentries;
si->free_nids = NM_I(sbi)->nid_cnt[FREE_NID_LIST]; si->free_nids = NM_I(sbi)->nid_cnt[FREE_NID];
si->avail_nids = NM_I(sbi)->available_nids; si->avail_nids = NM_I(sbi)->available_nids;
si->alloc_nids = NM_I(sbi)->nid_cnt[ALLOC_NID_LIST]; si->alloc_nids = NM_I(sbi)->nid_cnt[PREALLOC_NID];
si->bg_gc = sbi->bg_gc; si->bg_gc = sbi->bg_gc;
si->util_free = (int)(free_user_blocks(sbi) >> sbi->log_blocks_per_seg) si->util_free = (int)(free_user_blocks(sbi) >> sbi->log_blocks_per_seg)
* 100 / (int)(sbi->user_block_count >> sbi->log_blocks_per_seg) * 100 / (int)(sbi->user_block_count >> sbi->log_blocks_per_seg)
...@@ -231,14 +242,14 @@ static void update_mem_info(struct f2fs_sb_info *sbi) ...@@ -231,14 +242,14 @@ static void update_mem_info(struct f2fs_sb_info *sbi)
} }
/* free nids */ /* free nids */
si->cache_mem += (NM_I(sbi)->nid_cnt[FREE_NID_LIST] + si->cache_mem += (NM_I(sbi)->nid_cnt[FREE_NID] +
NM_I(sbi)->nid_cnt[ALLOC_NID_LIST]) * NM_I(sbi)->nid_cnt[PREALLOC_NID]) *
sizeof(struct free_nid); sizeof(struct free_nid);
si->cache_mem += NM_I(sbi)->nat_cnt * sizeof(struct nat_entry); si->cache_mem += NM_I(sbi)->nat_cnt * sizeof(struct nat_entry);
si->cache_mem += NM_I(sbi)->dirty_nat_cnt * si->cache_mem += NM_I(sbi)->dirty_nat_cnt *
sizeof(struct nat_entry_set); sizeof(struct nat_entry_set);
si->cache_mem += si->inmem_pages * sizeof(struct inmem_pages); si->cache_mem += si->inmem_pages * sizeof(struct inmem_pages);
for (i = 0; i <= ORPHAN_INO; i++) for (i = 0; i < MAX_INO_ENTRY; i++)
si->cache_mem += sbi->im[i].ino_num * sizeof(struct ino_entry); si->cache_mem += sbi->im[i].ino_num * sizeof(struct ino_entry);
si->cache_mem += atomic_read(&sbi->total_ext_tree) * si->cache_mem += atomic_read(&sbi->total_ext_tree) *
sizeof(struct extent_tree); sizeof(struct extent_tree);
...@@ -262,9 +273,10 @@ static int stat_show(struct seq_file *s, void *v) ...@@ -262,9 +273,10 @@ static int stat_show(struct seq_file *s, void *v)
list_for_each_entry(si, &f2fs_stat_list, stat_list) { list_for_each_entry(si, &f2fs_stat_list, stat_list) {
update_general_status(si->sbi); update_general_status(si->sbi);
seq_printf(s, "\n=====[ partition info(%pg). #%d, %s]=====\n", seq_printf(s, "\n=====[ partition info(%pg). #%d, %s, CP: %s]=====\n",
si->sbi->sb->s_bdev, i++, si->sbi->sb->s_bdev, i++,
f2fs_readonly(si->sbi->sb) ? "RO": "RW"); f2fs_readonly(si->sbi->sb) ? "RO": "RW",
f2fs_cp_error(si->sbi) ? "Error": "Good");
seq_printf(s, "[SB: 1] [CP: 2] [SIT: %d] [NAT: %d] ", seq_printf(s, "[SB: 1] [CP: 2] [SIT: %d] [NAT: %d] ",
si->sit_area_segs, si->nat_area_segs); si->sit_area_segs, si->nat_area_segs);
seq_printf(s, "[SSA: %d] [MAIN: %d", seq_printf(s, "[SSA: %d] [MAIN: %d",
...@@ -349,10 +361,11 @@ static int stat_show(struct seq_file *s, void *v) ...@@ -349,10 +361,11 @@ static int stat_show(struct seq_file *s, void *v)
seq_printf(s, " - Inner Struct Count: tree: %d(%d), node: %d\n", seq_printf(s, " - Inner Struct Count: tree: %d(%d), node: %d\n",
si->ext_tree, si->zombie_tree, si->ext_node); si->ext_tree, si->zombie_tree, si->ext_node);
seq_puts(s, "\nBalancing F2FS Async:\n"); seq_puts(s, "\nBalancing F2FS Async:\n");
seq_printf(s, " - IO (CP: %4d, Data: %4d, Flush: (%4d %4d), " seq_printf(s, " - IO (CP: %4d, Data: %4d, Flush: (%4d %4d %4d), "
"Discard: (%4d %4d)) cmd: %4d undiscard:%4u\n", "Discard: (%4d %4d)) cmd: %4d undiscard:%4u\n",
si->nr_wb_cp_data, si->nr_wb_data, si->nr_wb_cp_data, si->nr_wb_data,
si->nr_flushing, si->nr_flushed, si->nr_flushing, si->nr_flushed,
si->flush_list_empty,
si->nr_discarding, si->nr_discarded, si->nr_discarding, si->nr_discarded,
si->nr_discard_cmd, si->undiscard_blks); si->nr_discard_cmd, si->undiscard_blks);
seq_printf(s, " - inmem: %4d, atomic IO: %4d (Max. %4d), " seq_printf(s, " - inmem: %4d, atomic IO: %4d (Max. %4d), "
...@@ -365,6 +378,8 @@ static int stat_show(struct seq_file *s, void *v) ...@@ -365,6 +378,8 @@ static int stat_show(struct seq_file *s, void *v)
si->ndirty_dent, si->ndirty_dirs, si->ndirty_all); si->ndirty_dent, si->ndirty_dirs, si->ndirty_all);
seq_printf(s, " - datas: %4d in files:%4d\n", seq_printf(s, " - datas: %4d in files:%4d\n",
si->ndirty_data, si->ndirty_files); si->ndirty_data, si->ndirty_files);
seq_printf(s, " - quota datas: %4d in quota files:%4d\n",
si->ndirty_qdata, si->nquota_files);
seq_printf(s, " - meta: %4d in %4d\n", seq_printf(s, " - meta: %4d in %4d\n",
si->ndirty_meta, si->meta_pages); si->ndirty_meta, si->meta_pages);
seq_printf(s, " - imeta: %4d\n", seq_printf(s, " - imeta: %4d\n",
......
...@@ -10,10 +10,12 @@ ...@@ -10,10 +10,12 @@
*/ */
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/f2fs_fs.h> #include <linux/f2fs_fs.h>
#include <linux/sched/signal.h>
#include "f2fs.h" #include "f2fs.h"
#include "node.h" #include "node.h"
#include "acl.h" #include "acl.h"
#include "xattr.h" #include "xattr.h"
#include <trace/events/f2fs.h>
static unsigned long dir_blocks(struct inode *inode) static unsigned long dir_blocks(struct inode *inode)
{ {
...@@ -847,6 +849,7 @@ static int f2fs_readdir(struct file *file, struct dir_context *ctx) ...@@ -847,6 +849,7 @@ static int f2fs_readdir(struct file *file, struct dir_context *ctx)
struct f2fs_dentry_block *dentry_blk = NULL; struct f2fs_dentry_block *dentry_blk = NULL;
struct page *dentry_page = NULL; struct page *dentry_page = NULL;
struct file_ra_state *ra = &file->f_ra; struct file_ra_state *ra = &file->f_ra;
loff_t start_pos = ctx->pos;
unsigned int n = ((unsigned long)ctx->pos / NR_DENTRY_IN_BLOCK); unsigned int n = ((unsigned long)ctx->pos / NR_DENTRY_IN_BLOCK);
struct f2fs_dentry_ptr d; struct f2fs_dentry_ptr d;
struct fscrypt_str fstr = FSTR_INIT(NULL, 0); struct fscrypt_str fstr = FSTR_INIT(NULL, 0);
...@@ -855,24 +858,32 @@ static int f2fs_readdir(struct file *file, struct dir_context *ctx) ...@@ -855,24 +858,32 @@ static int f2fs_readdir(struct file *file, struct dir_context *ctx)
if (f2fs_encrypted_inode(inode)) { if (f2fs_encrypted_inode(inode)) {
err = fscrypt_get_encryption_info(inode); err = fscrypt_get_encryption_info(inode);
if (err && err != -ENOKEY) if (err && err != -ENOKEY)
return err; goto out;
err = fscrypt_fname_alloc_buffer(inode, F2FS_NAME_LEN, &fstr); err = fscrypt_fname_alloc_buffer(inode, F2FS_NAME_LEN, &fstr);
if (err < 0) if (err < 0)
return err; goto out;
} }
if (f2fs_has_inline_dentry(inode)) { if (f2fs_has_inline_dentry(inode)) {
err = f2fs_read_inline_dir(file, ctx, &fstr); err = f2fs_read_inline_dir(file, ctx, &fstr);
goto out; goto out_free;
} }
/* readahead for multi pages of dir */ for (; n < npages; n++, ctx->pos = n * NR_DENTRY_IN_BLOCK) {
if (npages - n > 1 && !ra_has_index(ra, n))
page_cache_sync_readahead(inode->i_mapping, ra, file, n, /* allow readdir() to be interrupted */
if (fatal_signal_pending(current)) {
err = -ERESTARTSYS;
goto out_free;
}
cond_resched();
/* readahead for multi pages of dir */
if (npages - n > 1 && !ra_has_index(ra, n))
page_cache_sync_readahead(inode->i_mapping, ra, file, n,
min(npages - n, (pgoff_t)MAX_DIR_RA_PAGES)); min(npages - n, (pgoff_t)MAX_DIR_RA_PAGES));
for (; n < npages; n++) {
dentry_page = get_lock_data_page(inode, n, false); dentry_page = get_lock_data_page(inode, n, false);
if (IS_ERR(dentry_page)) { if (IS_ERR(dentry_page)) {
err = PTR_ERR(dentry_page); err = PTR_ERR(dentry_page);
...@@ -880,7 +891,7 @@ static int f2fs_readdir(struct file *file, struct dir_context *ctx) ...@@ -880,7 +891,7 @@ static int f2fs_readdir(struct file *file, struct dir_context *ctx)
err = 0; err = 0;
continue; continue;
} else { } else {
goto out; goto out_free;
} }
} }
...@@ -896,12 +907,13 @@ static int f2fs_readdir(struct file *file, struct dir_context *ctx) ...@@ -896,12 +907,13 @@ static int f2fs_readdir(struct file *file, struct dir_context *ctx)
break; break;
} }
ctx->pos = (n + 1) * NR_DENTRY_IN_BLOCK;
kunmap(dentry_page); kunmap(dentry_page);
f2fs_put_page(dentry_page, 1); f2fs_put_page(dentry_page, 1);
} }
out: out_free:
fscrypt_fname_free_buffer(&fstr); fscrypt_fname_free_buffer(&fstr);
out:
trace_f2fs_readdir(inode, start_pos, ctx->pos, err);
return err < 0 ? err : 0; return err < 0 ? err : 0;
} }
......
This diff is collapsed.
...@@ -53,6 +53,11 @@ static int f2fs_vm_page_mkwrite(struct vm_fault *vmf) ...@@ -53,6 +53,11 @@ static int f2fs_vm_page_mkwrite(struct vm_fault *vmf)
struct dnode_of_data dn; struct dnode_of_data dn;
int err; int err;
if (unlikely(f2fs_cp_error(sbi))) {
err = -EIO;
goto err;
}
sb_start_pagefault(inode->i_sb); sb_start_pagefault(inode->i_sb);
f2fs_bug_on(sbi, f2fs_has_inline_data(inode)); f2fs_bug_on(sbi, f2fs_has_inline_data(inode));
...@@ -114,6 +119,7 @@ static int f2fs_vm_page_mkwrite(struct vm_fault *vmf) ...@@ -114,6 +119,7 @@ static int f2fs_vm_page_mkwrite(struct vm_fault *vmf)
out: out:
sb_end_pagefault(inode->i_sb); sb_end_pagefault(inode->i_sb);
f2fs_update_time(sbi, REQ_TIME); f2fs_update_time(sbi, REQ_TIME);
err:
return block_page_mkwrite_return(err); return block_page_mkwrite_return(err);
} }
...@@ -138,27 +144,29 @@ static int get_parent_ino(struct inode *inode, nid_t *pino) ...@@ -138,27 +144,29 @@ static int get_parent_ino(struct inode *inode, nid_t *pino)
return 1; return 1;
} }
static inline bool need_do_checkpoint(struct inode *inode) static inline enum cp_reason_type need_do_checkpoint(struct inode *inode)
{ {
struct f2fs_sb_info *sbi = F2FS_I_SB(inode); struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
bool need_cp = false; enum cp_reason_type cp_reason = CP_NO_NEEDED;
if (!S_ISREG(inode->i_mode) || inode->i_nlink != 1) if (!S_ISREG(inode->i_mode))
need_cp = true; cp_reason = CP_NON_REGULAR;
else if (inode->i_nlink != 1)
cp_reason = CP_HARDLINK;
else if (is_sbi_flag_set(sbi, SBI_NEED_CP)) else if (is_sbi_flag_set(sbi, SBI_NEED_CP))
need_cp = true; cp_reason = CP_SB_NEED_CP;
else if (file_wrong_pino(inode)) else if (file_wrong_pino(inode))
need_cp = true; cp_reason = CP_WRONG_PINO;
else if (!space_for_roll_forward(sbi)) else if (!space_for_roll_forward(sbi))
need_cp = true; cp_reason = CP_NO_SPC_ROLL;
else if (!is_checkpointed_node(sbi, F2FS_I(inode)->i_pino)) else if (!is_checkpointed_node(sbi, F2FS_I(inode)->i_pino))
need_cp = true; cp_reason = CP_NODE_NEED_CP;
else if (test_opt(sbi, FASTBOOT)) else if (test_opt(sbi, FASTBOOT))
need_cp = true; cp_reason = CP_FASTBOOT_MODE;
else if (sbi->active_logs == 2) else if (sbi->active_logs == 2)
need_cp = true; cp_reason = CP_SPEC_LOG_NUM;
return need_cp; return cp_reason;
} }
static bool need_inode_page_update(struct f2fs_sb_info *sbi, nid_t ino) static bool need_inode_page_update(struct f2fs_sb_info *sbi, nid_t ino)
...@@ -193,7 +201,7 @@ static int f2fs_do_sync_file(struct file *file, loff_t start, loff_t end, ...@@ -193,7 +201,7 @@ static int f2fs_do_sync_file(struct file *file, loff_t start, loff_t end,
struct f2fs_sb_info *sbi = F2FS_I_SB(inode); struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
nid_t ino = inode->i_ino; nid_t ino = inode->i_ino;
int ret = 0; int ret = 0;
bool need_cp = false; enum cp_reason_type cp_reason = 0;
struct writeback_control wbc = { struct writeback_control wbc = {
.sync_mode = WB_SYNC_ALL, .sync_mode = WB_SYNC_ALL,
.nr_to_write = LONG_MAX, .nr_to_write = LONG_MAX,
...@@ -212,7 +220,7 @@ static int f2fs_do_sync_file(struct file *file, loff_t start, loff_t end, ...@@ -212,7 +220,7 @@ static int f2fs_do_sync_file(struct file *file, loff_t start, loff_t end,
clear_inode_flag(inode, FI_NEED_IPU); clear_inode_flag(inode, FI_NEED_IPU);
if (ret) { if (ret) {
trace_f2fs_sync_file_exit(inode, need_cp, datasync, ret); trace_f2fs_sync_file_exit(inode, cp_reason, datasync, ret);
return ret; return ret;
} }
...@@ -243,10 +251,10 @@ static int f2fs_do_sync_file(struct file *file, loff_t start, loff_t end, ...@@ -243,10 +251,10 @@ static int f2fs_do_sync_file(struct file *file, loff_t start, loff_t end,
* sudden-power-off. * sudden-power-off.
*/ */
down_read(&F2FS_I(inode)->i_sem); down_read(&F2FS_I(inode)->i_sem);
need_cp = need_do_checkpoint(inode); cp_reason = need_do_checkpoint(inode);
up_read(&F2FS_I(inode)->i_sem); up_read(&F2FS_I(inode)->i_sem);
if (need_cp) { if (cp_reason) {
/* all the dirty node pages should be flushed for POR */ /* all the dirty node pages should be flushed for POR */
ret = f2fs_sync_fs(inode->i_sb, 1); ret = f2fs_sync_fs(inode->i_sb, 1);
...@@ -294,19 +302,24 @@ static int f2fs_do_sync_file(struct file *file, loff_t start, loff_t end, ...@@ -294,19 +302,24 @@ static int f2fs_do_sync_file(struct file *file, loff_t start, loff_t end,
remove_ino_entry(sbi, ino, APPEND_INO); remove_ino_entry(sbi, ino, APPEND_INO);
clear_inode_flag(inode, FI_APPEND_WRITE); clear_inode_flag(inode, FI_APPEND_WRITE);
flush_out: flush_out:
remove_ino_entry(sbi, ino, UPDATE_INO);
clear_inode_flag(inode, FI_UPDATE_WRITE);
if (!atomic) if (!atomic)
ret = f2fs_issue_flush(sbi); ret = f2fs_issue_flush(sbi, inode->i_ino);
if (!ret) {
remove_ino_entry(sbi, ino, UPDATE_INO);
clear_inode_flag(inode, FI_UPDATE_WRITE);
remove_ino_entry(sbi, ino, FLUSH_INO);
}
f2fs_update_time(sbi, REQ_TIME); f2fs_update_time(sbi, REQ_TIME);
out: out:
trace_f2fs_sync_file_exit(inode, need_cp, datasync, ret); trace_f2fs_sync_file_exit(inode, cp_reason, datasync, ret);
f2fs_trace_ios(NULL, 1); f2fs_trace_ios(NULL, 1);
return ret; return ret;
} }
int f2fs_sync_file(struct file *file, loff_t start, loff_t end, int datasync) int f2fs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
{ {
if (unlikely(f2fs_cp_error(F2FS_I_SB(file_inode(file)))))
return -EIO;
return f2fs_do_sync_file(file, start, end, datasync, false); return f2fs_do_sync_file(file, start, end, datasync, false);
} }
...@@ -444,6 +457,9 @@ static int f2fs_file_mmap(struct file *file, struct vm_area_struct *vma) ...@@ -444,6 +457,9 @@ static int f2fs_file_mmap(struct file *file, struct vm_area_struct *vma)
struct inode *inode = file_inode(file); struct inode *inode = file_inode(file);
int err; int err;
if (unlikely(f2fs_cp_error(F2FS_I_SB(inode))))
return -EIO;
/* we don't need to use inline_data strictly */ /* we don't need to use inline_data strictly */
err = f2fs_convert_inline_inode(inode); err = f2fs_convert_inline_inode(inode);
if (err) if (err)
...@@ -630,6 +646,9 @@ int f2fs_truncate(struct inode *inode) ...@@ -630,6 +646,9 @@ int f2fs_truncate(struct inode *inode)
{ {
int err; int err;
if (unlikely(f2fs_cp_error(F2FS_I_SB(inode))))
return -EIO;
if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
S_ISLNK(inode->i_mode))) S_ISLNK(inode->i_mode)))
return 0; return 0;
...@@ -684,6 +703,12 @@ int f2fs_getattr(const struct path *path, struct kstat *stat, ...@@ -684,6 +703,12 @@ int f2fs_getattr(const struct path *path, struct kstat *stat,
STATX_ATTR_NODUMP); STATX_ATTR_NODUMP);
generic_fillattr(inode, stat); generic_fillattr(inode, stat);
/* we need to show initial sectors used for inline_data/dentries */
if ((S_ISREG(inode->i_mode) && f2fs_has_inline_data(inode)) ||
f2fs_has_inline_dentry(inode))
stat->blocks += (stat->size + 511) >> 9;
return 0; return 0;
} }
...@@ -723,6 +748,9 @@ int f2fs_setattr(struct dentry *dentry, struct iattr *attr) ...@@ -723,6 +748,9 @@ int f2fs_setattr(struct dentry *dentry, struct iattr *attr)
int err; int err;
bool size_changed = false; bool size_changed = false;
if (unlikely(f2fs_cp_error(F2FS_I_SB(inode))))
return -EIO;
err = setattr_prepare(dentry, attr); err = setattr_prepare(dentry, attr);
if (err) if (err)
return err; return err;
...@@ -775,6 +803,10 @@ int f2fs_setattr(struct dentry *dentry, struct iattr *attr) ...@@ -775,6 +803,10 @@ int f2fs_setattr(struct dentry *dentry, struct iattr *attr)
inode->i_mtime = inode->i_ctime = current_time(inode); inode->i_mtime = inode->i_ctime = current_time(inode);
} }
down_write(&F2FS_I(inode)->i_sem);
F2FS_I(inode)->last_disk_size = i_size_read(inode);
up_write(&F2FS_I(inode)->i_sem);
size_changed = true; size_changed = true;
} }
...@@ -845,7 +877,7 @@ int truncate_hole(struct inode *inode, pgoff_t pg_start, pgoff_t pg_end) ...@@ -845,7 +877,7 @@ int truncate_hole(struct inode *inode, pgoff_t pg_start, pgoff_t pg_end)
err = get_dnode_of_data(&dn, pg_start, LOOKUP_NODE); err = get_dnode_of_data(&dn, pg_start, LOOKUP_NODE);
if (err) { if (err) {
if (err == -ENOENT) { if (err == -ENOENT) {
pg_start++; pg_start = get_next_page_offset(&dn, pg_start);
continue; continue;
} }
return err; return err;
...@@ -1160,11 +1192,14 @@ static int f2fs_collapse_range(struct inode *inode, loff_t offset, loff_t len) ...@@ -1160,11 +1192,14 @@ static int f2fs_collapse_range(struct inode *inode, loff_t offset, loff_t len)
if (ret) if (ret)
goto out; goto out;
/* avoid gc operation during block exchange */
down_write(&F2FS_I(inode)->dio_rwsem[WRITE]);
truncate_pagecache(inode, offset); truncate_pagecache(inode, offset);
ret = f2fs_do_collapse(inode, pg_start, pg_end); ret = f2fs_do_collapse(inode, pg_start, pg_end);
if (ret) if (ret)
goto out; goto out_unlock;
/* write out all moved pages, if possible */ /* write out all moved pages, if possible */
filemap_write_and_wait_range(inode->i_mapping, offset, LLONG_MAX); filemap_write_and_wait_range(inode->i_mapping, offset, LLONG_MAX);
...@@ -1176,7 +1211,8 @@ static int f2fs_collapse_range(struct inode *inode, loff_t offset, loff_t len) ...@@ -1176,7 +1211,8 @@ static int f2fs_collapse_range(struct inode *inode, loff_t offset, loff_t len)
ret = truncate_blocks(inode, new_size, true); ret = truncate_blocks(inode, new_size, true);
if (!ret) if (!ret)
f2fs_i_size_write(inode, new_size); f2fs_i_size_write(inode, new_size);
out_unlock:
up_write(&F2FS_I(inode)->dio_rwsem[WRITE]);
out: out:
up_write(&F2FS_I(inode)->i_mmap_sem); up_write(&F2FS_I(inode)->i_mmap_sem);
return ret; return ret;
...@@ -1359,6 +1395,9 @@ static int f2fs_insert_range(struct inode *inode, loff_t offset, loff_t len) ...@@ -1359,6 +1395,9 @@ static int f2fs_insert_range(struct inode *inode, loff_t offset, loff_t len)
if (ret) if (ret)
goto out; goto out;
/* avoid gc operation during block exchange */
down_write(&F2FS_I(inode)->dio_rwsem[WRITE]);
truncate_pagecache(inode, offset); truncate_pagecache(inode, offset);
pg_start = offset >> PAGE_SHIFT; pg_start = offset >> PAGE_SHIFT;
...@@ -1386,6 +1425,8 @@ static int f2fs_insert_range(struct inode *inode, loff_t offset, loff_t len) ...@@ -1386,6 +1425,8 @@ static int f2fs_insert_range(struct inode *inode, loff_t offset, loff_t len)
if (!ret) if (!ret)
f2fs_i_size_write(inode, new_size); f2fs_i_size_write(inode, new_size);
up_write(&F2FS_I(inode)->dio_rwsem[WRITE]);
out: out:
up_write(&F2FS_I(inode)->i_mmap_sem); up_write(&F2FS_I(inode)->i_mmap_sem);
return ret; return ret;
...@@ -1435,8 +1476,12 @@ static int expand_inode_data(struct inode *inode, loff_t offset, ...@@ -1435,8 +1476,12 @@ static int expand_inode_data(struct inode *inode, loff_t offset,
new_size = ((loff_t)pg_end << PAGE_SHIFT) + off_end; new_size = ((loff_t)pg_end << PAGE_SHIFT) + off_end;
} }
if (!(mode & FALLOC_FL_KEEP_SIZE) && i_size_read(inode) < new_size) if (new_size > i_size_read(inode)) {
f2fs_i_size_write(inode, new_size); if (mode & FALLOC_FL_KEEP_SIZE)
file_set_keep_isize(inode);
else
f2fs_i_size_write(inode, new_size);
}
return err; return err;
} }
...@@ -1447,6 +1492,9 @@ static long f2fs_fallocate(struct file *file, int mode, ...@@ -1447,6 +1492,9 @@ static long f2fs_fallocate(struct file *file, int mode,
struct inode *inode = file_inode(file); struct inode *inode = file_inode(file);
long ret = 0; long ret = 0;
if (unlikely(f2fs_cp_error(F2FS_I_SB(inode))))
return -EIO;
/* f2fs only support ->fallocate for regular file */ /* f2fs only support ->fallocate for regular file */
if (!S_ISREG(inode->i_mode)) if (!S_ISREG(inode->i_mode))
return -EINVAL; return -EINVAL;
...@@ -1480,8 +1528,6 @@ static long f2fs_fallocate(struct file *file, int mode, ...@@ -1480,8 +1528,6 @@ static long f2fs_fallocate(struct file *file, int mode,
if (!ret) { if (!ret) {
inode->i_mtime = inode->i_ctime = current_time(inode); inode->i_mtime = inode->i_ctime = current_time(inode);
f2fs_mark_inode_dirty_sync(inode, false); f2fs_mark_inode_dirty_sync(inode, false);
if (mode & FALLOC_FL_KEEP_SIZE)
file_set_keep_isize(inode);
f2fs_update_time(F2FS_I_SB(inode), REQ_TIME); f2fs_update_time(F2FS_I_SB(inode), REQ_TIME);
} }
...@@ -1883,6 +1929,9 @@ static int f2fs_ioc_set_encryption_policy(struct file *filp, unsigned long arg) ...@@ -1883,6 +1929,9 @@ static int f2fs_ioc_set_encryption_policy(struct file *filp, unsigned long arg)
{ {
struct inode *inode = file_inode(filp); struct inode *inode = file_inode(filp);
if (!f2fs_sb_has_crypto(inode->i_sb))
return -EOPNOTSUPP;
f2fs_update_time(F2FS_I_SB(inode), REQ_TIME); f2fs_update_time(F2FS_I_SB(inode), REQ_TIME);
return fscrypt_ioctl_set_policy(filp, (const void __user *)arg); return fscrypt_ioctl_set_policy(filp, (const void __user *)arg);
...@@ -1890,6 +1939,8 @@ static int f2fs_ioc_set_encryption_policy(struct file *filp, unsigned long arg) ...@@ -1890,6 +1939,8 @@ static int f2fs_ioc_set_encryption_policy(struct file *filp, unsigned long arg)
static int f2fs_ioc_get_encryption_policy(struct file *filp, unsigned long arg) static int f2fs_ioc_get_encryption_policy(struct file *filp, unsigned long arg)
{ {
if (!f2fs_sb_has_crypto(file_inode(filp)->i_sb))
return -EOPNOTSUPP;
return fscrypt_ioctl_get_policy(filp, (void __user *)arg); return fscrypt_ioctl_get_policy(filp, (void __user *)arg);
} }
...@@ -2245,9 +2296,13 @@ static int f2fs_move_file_range(struct file *file_in, loff_t pos_in, ...@@ -2245,9 +2296,13 @@ static int f2fs_move_file_range(struct file *file_in, loff_t pos_in,
} }
inode_lock(src); inode_lock(src);
down_write(&F2FS_I(src)->dio_rwsem[WRITE]);
if (src != dst) { if (src != dst) {
if (!inode_trylock(dst)) { ret = -EBUSY;
ret = -EBUSY; if (!inode_trylock(dst))
goto out;
if (!down_write_trylock(&F2FS_I(dst)->dio_rwsem[WRITE])) {
inode_unlock(dst);
goto out; goto out;
} }
} }
...@@ -2307,9 +2362,12 @@ static int f2fs_move_file_range(struct file *file_in, loff_t pos_in, ...@@ -2307,9 +2362,12 @@ static int f2fs_move_file_range(struct file *file_in, loff_t pos_in,
} }
f2fs_unlock_op(sbi); f2fs_unlock_op(sbi);
out_unlock: out_unlock:
if (src != dst) if (src != dst) {
up_write(&F2FS_I(dst)->dio_rwsem[WRITE]);
inode_unlock(dst); inode_unlock(dst);
}
out: out:
up_write(&F2FS_I(src)->dio_rwsem[WRITE]);
inode_unlock(src); inode_unlock(src);
return ret; return ret;
} }
...@@ -2625,6 +2683,9 @@ static int f2fs_ioc_fssetxattr(struct file *filp, unsigned long arg) ...@@ -2625,6 +2683,9 @@ static int f2fs_ioc_fssetxattr(struct file *filp, unsigned long arg)
long f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) long f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{ {
if (unlikely(f2fs_cp_error(F2FS_I_SB(file_inode(filp)))))
return -EIO;
switch (cmd) { switch (cmd) {
case F2FS_IOC_GETFLAGS: case F2FS_IOC_GETFLAGS:
return f2fs_ioc_getflags(filp, arg); return f2fs_ioc_getflags(filp, arg);
...@@ -2682,6 +2743,9 @@ static ssize_t f2fs_file_write_iter(struct kiocb *iocb, struct iov_iter *from) ...@@ -2682,6 +2743,9 @@ static ssize_t f2fs_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
struct blk_plug plug; struct blk_plug plug;
ssize_t ret; ssize_t ret;
if (unlikely(f2fs_cp_error(F2FS_I_SB(inode))))
return -EIO;
inode_lock(inode); inode_lock(inode);
ret = generic_write_checks(iocb, from); ret = generic_write_checks(iocb, from);
if (ret > 0) { if (ret > 0) {
...@@ -2692,6 +2756,7 @@ static ssize_t f2fs_file_write_iter(struct kiocb *iocb, struct iov_iter *from) ...@@ -2692,6 +2756,7 @@ static ssize_t f2fs_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
err = f2fs_preallocate_blocks(iocb, from); err = f2fs_preallocate_blocks(iocb, from);
if (err) { if (err) {
clear_inode_flag(inode, FI_NO_PREALLOC);
inode_unlock(inode); inode_unlock(inode);
return err; return err;
} }
......
...@@ -267,16 +267,6 @@ static unsigned int get_cb_cost(struct f2fs_sb_info *sbi, unsigned int segno) ...@@ -267,16 +267,6 @@ static unsigned int get_cb_cost(struct f2fs_sb_info *sbi, unsigned int segno)
return UINT_MAX - ((100 * (100 - u) * age) / (100 + u)); return UINT_MAX - ((100 * (100 - u) * age) / (100 + u));
} }
static unsigned int get_greedy_cost(struct f2fs_sb_info *sbi,
unsigned int segno)
{
unsigned int valid_blocks =
get_valid_blocks(sbi, segno, true);
return IS_DATASEG(get_seg_entry(sbi, segno)->type) ?
valid_blocks * 2 : valid_blocks;
}
static inline unsigned int get_gc_cost(struct f2fs_sb_info *sbi, static inline unsigned int get_gc_cost(struct f2fs_sb_info *sbi,
unsigned int segno, struct victim_sel_policy *p) unsigned int segno, struct victim_sel_policy *p)
{ {
...@@ -285,7 +275,7 @@ static inline unsigned int get_gc_cost(struct f2fs_sb_info *sbi, ...@@ -285,7 +275,7 @@ static inline unsigned int get_gc_cost(struct f2fs_sb_info *sbi,
/* alloc_mode == LFS */ /* alloc_mode == LFS */
if (p->gc_mode == GC_GREEDY) if (p->gc_mode == GC_GREEDY)
return get_greedy_cost(sbi, segno); return get_valid_blocks(sbi, segno, true);
else else
return get_cb_cost(sbi, segno); return get_cb_cost(sbi, segno);
} }
...@@ -466,10 +456,10 @@ static int check_valid_map(struct f2fs_sb_info *sbi, ...@@ -466,10 +456,10 @@ static int check_valid_map(struct f2fs_sb_info *sbi,
struct seg_entry *sentry; struct seg_entry *sentry;
int ret; int ret;
mutex_lock(&sit_i->sentry_lock); down_read(&sit_i->sentry_lock);
sentry = get_seg_entry(sbi, segno); sentry = get_seg_entry(sbi, segno);
ret = f2fs_test_bit(offset, sentry->cur_valid_map); ret = f2fs_test_bit(offset, sentry->cur_valid_map);
mutex_unlock(&sit_i->sentry_lock); up_read(&sit_i->sentry_lock);
return ret; return ret;
} }
...@@ -608,6 +598,7 @@ static void move_data_block(struct inode *inode, block_t bidx, ...@@ -608,6 +598,7 @@ static void move_data_block(struct inode *inode, block_t bidx,
{ {
struct f2fs_io_info fio = { struct f2fs_io_info fio = {
.sbi = F2FS_I_SB(inode), .sbi = F2FS_I_SB(inode),
.ino = inode->i_ino,
.type = DATA, .type = DATA,
.temp = COLD, .temp = COLD,
.op = REQ_OP_READ, .op = REQ_OP_READ,
...@@ -659,8 +650,8 @@ static void move_data_block(struct inode *inode, block_t bidx, ...@@ -659,8 +650,8 @@ static void move_data_block(struct inode *inode, block_t bidx,
allocate_data_block(fio.sbi, NULL, fio.old_blkaddr, &newaddr, allocate_data_block(fio.sbi, NULL, fio.old_blkaddr, &newaddr,
&sum, CURSEG_COLD_DATA, NULL, false); &sum, CURSEG_COLD_DATA, NULL, false);
fio.encrypted_page = pagecache_get_page(META_MAPPING(fio.sbi), newaddr, fio.encrypted_page = f2fs_pagecache_get_page(META_MAPPING(fio.sbi),
FGP_LOCK | FGP_CREAT, GFP_NOFS); newaddr, FGP_LOCK | FGP_CREAT, GFP_NOFS);
if (!fio.encrypted_page) { if (!fio.encrypted_page) {
err = -ENOMEM; err = -ENOMEM;
goto recover_block; goto recover_block;
...@@ -738,6 +729,7 @@ static void move_data_page(struct inode *inode, block_t bidx, int gc_type, ...@@ -738,6 +729,7 @@ static void move_data_page(struct inode *inode, block_t bidx, int gc_type,
} else { } else {
struct f2fs_io_info fio = { struct f2fs_io_info fio = {
.sbi = F2FS_I_SB(inode), .sbi = F2FS_I_SB(inode),
.ino = inode->i_ino,
.type = DATA, .type = DATA,
.temp = COLD, .temp = COLD,
.op = REQ_OP_WRITE, .op = REQ_OP_WRITE,
...@@ -840,10 +832,17 @@ static void gc_data_segment(struct f2fs_sb_info *sbi, struct f2fs_summary *sum, ...@@ -840,10 +832,17 @@ static void gc_data_segment(struct f2fs_sb_info *sbi, struct f2fs_summary *sum,
continue; continue;
} }
if (!down_write_trylock(
&F2FS_I(inode)->dio_rwsem[WRITE])) {
iput(inode);
continue;
}
start_bidx = start_bidx_of_node(nofs, inode); start_bidx = start_bidx_of_node(nofs, inode);
data_page = get_read_data_page(inode, data_page = get_read_data_page(inode,
start_bidx + ofs_in_node, REQ_RAHEAD, start_bidx + ofs_in_node, REQ_RAHEAD,
true); true);
up_write(&F2FS_I(inode)->dio_rwsem[WRITE]);
if (IS_ERR(data_page)) { if (IS_ERR(data_page)) {
iput(inode); iput(inode);
continue; continue;
...@@ -901,10 +900,10 @@ static int __get_victim(struct f2fs_sb_info *sbi, unsigned int *victim, ...@@ -901,10 +900,10 @@ static int __get_victim(struct f2fs_sb_info *sbi, unsigned int *victim,
struct sit_info *sit_i = SIT_I(sbi); struct sit_info *sit_i = SIT_I(sbi);
int ret; int ret;
mutex_lock(&sit_i->sentry_lock); down_write(&sit_i->sentry_lock);
ret = DIRTY_I(sbi)->v_ops->get_victim(sbi, victim, gc_type, ret = DIRTY_I(sbi)->v_ops->get_victim(sbi, victim, gc_type,
NO_CHECK_TYPE, LFS); NO_CHECK_TYPE, LFS);
mutex_unlock(&sit_i->sentry_lock); up_write(&sit_i->sentry_lock);
return ret; return ret;
} }
...@@ -952,8 +951,8 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi, ...@@ -952,8 +951,8 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi,
/* /*
* this is to avoid deadlock: * this is to avoid deadlock:
* - lock_page(sum_page) - f2fs_replace_block * - lock_page(sum_page) - f2fs_replace_block
* - check_valid_map() - mutex_lock(sentry_lock) * - check_valid_map() - down_write(sentry_lock)
* - mutex_lock(sentry_lock) - change_curseg() * - down_read(sentry_lock) - change_curseg()
* - lock_page(sum_page) * - lock_page(sum_page)
*/ */
if (type == SUM_TYPE_NODE) if (type == SUM_TYPE_NODE)
......
...@@ -112,6 +112,7 @@ int f2fs_convert_inline_page(struct dnode_of_data *dn, struct page *page) ...@@ -112,6 +112,7 @@ int f2fs_convert_inline_page(struct dnode_of_data *dn, struct page *page)
{ {
struct f2fs_io_info fio = { struct f2fs_io_info fio = {
.sbi = F2FS_I_SB(dn->inode), .sbi = F2FS_I_SB(dn->inode),
.ino = dn->inode->i_ino,
.type = DATA, .type = DATA,
.op = REQ_OP_WRITE, .op = REQ_OP_WRITE,
.op_flags = REQ_SYNC | REQ_PRIO, .op_flags = REQ_SYNC | REQ_PRIO,
......
...@@ -235,6 +235,23 @@ static int do_read_inode(struct inode *inode) ...@@ -235,6 +235,23 @@ static int do_read_inode(struct inode *inode)
fi->i_extra_isize = f2fs_has_extra_attr(inode) ? fi->i_extra_isize = f2fs_has_extra_attr(inode) ?
le16_to_cpu(ri->i_extra_isize) : 0; le16_to_cpu(ri->i_extra_isize) : 0;
if (f2fs_sb_has_flexible_inline_xattr(sbi->sb)) {
f2fs_bug_on(sbi, !f2fs_has_extra_attr(inode));
fi->i_inline_xattr_size = le16_to_cpu(ri->i_inline_xattr_size);
} else if (f2fs_has_inline_xattr(inode) ||
f2fs_has_inline_dentry(inode)) {
fi->i_inline_xattr_size = DEFAULT_INLINE_XATTR_ADDRS;
} else {
/*
* Previous inline data or directory always reserved 200 bytes
* in inode layout, even if inline_xattr is disabled. In order
* to keep inline_dentry's structure for backward compatibility,
* we get the space back only from inline_data.
*/
fi->i_inline_xattr_size = 0;
}
/* check data exist */ /* check data exist */
if (f2fs_has_inline_data(inode) && !f2fs_exist_data(inode)) if (f2fs_has_inline_data(inode) && !f2fs_exist_data(inode))
__recover_inline_status(inode, node_page); __recover_inline_status(inode, node_page);
...@@ -387,6 +404,10 @@ int update_inode(struct inode *inode, struct page *node_page) ...@@ -387,6 +404,10 @@ int update_inode(struct inode *inode, struct page *node_page)
if (f2fs_has_extra_attr(inode)) { if (f2fs_has_extra_attr(inode)) {
ri->i_extra_isize = cpu_to_le16(F2FS_I(inode)->i_extra_isize); ri->i_extra_isize = cpu_to_le16(F2FS_I(inode)->i_extra_isize);
if (f2fs_sb_has_flexible_inline_xattr(F2FS_I_SB(inode)->sb))
ri->i_inline_xattr_size =
cpu_to_le16(F2FS_I(inode)->i_inline_xattr_size);
if (f2fs_sb_has_project_quota(F2FS_I_SB(inode)->sb) && if (f2fs_sb_has_project_quota(F2FS_I_SB(inode)->sb) &&
F2FS_FITS_IN_INODE(ri, F2FS_I(inode)->i_extra_isize, F2FS_FITS_IN_INODE(ri, F2FS_I(inode)->i_extra_isize,
i_projid)) { i_projid)) {
...@@ -483,6 +504,7 @@ void f2fs_evict_inode(struct inode *inode) ...@@ -483,6 +504,7 @@ void f2fs_evict_inode(struct inode *inode)
remove_ino_entry(sbi, inode->i_ino, APPEND_INO); remove_ino_entry(sbi, inode->i_ino, APPEND_INO);
remove_ino_entry(sbi, inode->i_ino, UPDATE_INO); remove_ino_entry(sbi, inode->i_ino, UPDATE_INO);
remove_ino_entry(sbi, inode->i_ino, FLUSH_INO);
sb_start_intwrite(inode->i_sb); sb_start_intwrite(inode->i_sb);
set_inode_flag(inode, FI_NO_ALLOC); set_inode_flag(inode, FI_NO_ALLOC);
...@@ -522,8 +544,10 @@ void f2fs_evict_inode(struct inode *inode) ...@@ -522,8 +544,10 @@ void f2fs_evict_inode(struct inode *inode)
stat_dec_inline_dir(inode); stat_dec_inline_dir(inode);
stat_dec_inline_inode(inode); stat_dec_inline_inode(inode);
if (!is_set_ckpt_flags(sbi, CP_ERROR_FLAG)) if (likely(!is_set_ckpt_flags(sbi, CP_ERROR_FLAG)))
f2fs_bug_on(sbi, is_inode_flag_set(inode, FI_DIRTY_INODE)); f2fs_bug_on(sbi, is_inode_flag_set(inode, FI_DIRTY_INODE));
else
f2fs_inode_synced(inode);
/* ino == 0, if f2fs_new_inode() was failed t*/ /* ino == 0, if f2fs_new_inode() was failed t*/
if (inode->i_ino) if (inode->i_ino)
......
...@@ -29,6 +29,7 @@ static struct inode *f2fs_new_inode(struct inode *dir, umode_t mode) ...@@ -29,6 +29,7 @@ static struct inode *f2fs_new_inode(struct inode *dir, umode_t mode)
nid_t ino; nid_t ino;
struct inode *inode; struct inode *inode;
bool nid_free = false; bool nid_free = false;
int xattr_size = 0;
int err; int err;
inode = new_inode(dir->i_sb); inode = new_inode(dir->i_sb);
...@@ -86,11 +87,23 @@ static struct inode *f2fs_new_inode(struct inode *dir, umode_t mode) ...@@ -86,11 +87,23 @@ static struct inode *f2fs_new_inode(struct inode *dir, umode_t mode)
if (test_opt(sbi, INLINE_XATTR)) if (test_opt(sbi, INLINE_XATTR))
set_inode_flag(inode, FI_INLINE_XATTR); set_inode_flag(inode, FI_INLINE_XATTR);
if (test_opt(sbi, INLINE_DATA) && f2fs_may_inline_data(inode)) if (test_opt(sbi, INLINE_DATA) && f2fs_may_inline_data(inode))
set_inode_flag(inode, FI_INLINE_DATA); set_inode_flag(inode, FI_INLINE_DATA);
if (f2fs_may_inline_dentry(inode)) if (f2fs_may_inline_dentry(inode))
set_inode_flag(inode, FI_INLINE_DENTRY); set_inode_flag(inode, FI_INLINE_DENTRY);
if (f2fs_sb_has_flexible_inline_xattr(sbi->sb)) {
f2fs_bug_on(sbi, !f2fs_has_extra_attr(inode));
if (f2fs_has_inline_xattr(inode))
xattr_size = sbi->inline_xattr_size;
/* Otherwise, will be 0 */
} else if (f2fs_has_inline_xattr(inode) ||
f2fs_has_inline_dentry(inode)) {
xattr_size = DEFAULT_INLINE_XATTR_ADDRS;
}
F2FS_I(inode)->i_inline_xattr_size = xattr_size;
f2fs_init_extent_tree(inode, NULL); f2fs_init_extent_tree(inode, NULL);
stat_inc_inline_xattr(inode); stat_inc_inline_xattr(inode);
...@@ -177,6 +190,9 @@ static int f2fs_create(struct inode *dir, struct dentry *dentry, umode_t mode, ...@@ -177,6 +190,9 @@ static int f2fs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
nid_t ino = 0; nid_t ino = 0;
int err; int err;
if (unlikely(f2fs_cp_error(sbi)))
return -EIO;
err = dquot_initialize(dir); err = dquot_initialize(dir);
if (err) if (err)
return err; return err;
...@@ -221,6 +237,9 @@ static int f2fs_link(struct dentry *old_dentry, struct inode *dir, ...@@ -221,6 +237,9 @@ static int f2fs_link(struct dentry *old_dentry, struct inode *dir,
struct f2fs_sb_info *sbi = F2FS_I_SB(dir); struct f2fs_sb_info *sbi = F2FS_I_SB(dir);
int err; int err;
if (unlikely(f2fs_cp_error(sbi)))
return -EIO;
if (f2fs_encrypted_inode(dir) && if (f2fs_encrypted_inode(dir) &&
!fscrypt_has_permitted_context(dir, inode)) !fscrypt_has_permitted_context(dir, inode))
return -EPERM; return -EPERM;
...@@ -331,12 +350,15 @@ static struct dentry *f2fs_lookup(struct inode *dir, struct dentry *dentry, ...@@ -331,12 +350,15 @@ static struct dentry *f2fs_lookup(struct inode *dir, struct dentry *dentry,
struct inode *inode = NULL; struct inode *inode = NULL;
struct f2fs_dir_entry *de; struct f2fs_dir_entry *de;
struct page *page; struct page *page;
nid_t ino; struct dentry *new;
nid_t ino = -1;
int err = 0; int err = 0;
unsigned int root_ino = F2FS_ROOT_INO(F2FS_I_SB(dir)); unsigned int root_ino = F2FS_ROOT_INO(F2FS_I_SB(dir));
trace_f2fs_lookup_start(dir, dentry, flags);
if (f2fs_encrypted_inode(dir)) { if (f2fs_encrypted_inode(dir)) {
int res = fscrypt_get_encryption_info(dir); err = fscrypt_get_encryption_info(dir);
/* /*
* DCACHE_ENCRYPTED_WITH_KEY is set if the dentry is * DCACHE_ENCRYPTED_WITH_KEY is set if the dentry is
...@@ -346,18 +368,22 @@ static struct dentry *f2fs_lookup(struct inode *dir, struct dentry *dentry, ...@@ -346,18 +368,22 @@ static struct dentry *f2fs_lookup(struct inode *dir, struct dentry *dentry,
if (fscrypt_has_encryption_key(dir)) if (fscrypt_has_encryption_key(dir))
fscrypt_set_encrypted_dentry(dentry); fscrypt_set_encrypted_dentry(dentry);
fscrypt_set_d_op(dentry); fscrypt_set_d_op(dentry);
if (res && res != -ENOKEY) if (err && err != -ENOKEY)
return ERR_PTR(res); goto out;
} }
if (dentry->d_name.len > F2FS_NAME_LEN) if (dentry->d_name.len > F2FS_NAME_LEN) {
return ERR_PTR(-ENAMETOOLONG); err = -ENAMETOOLONG;
goto out;
}
de = f2fs_find_entry(dir, &dentry->d_name, &page); de = f2fs_find_entry(dir, &dentry->d_name, &page);
if (!de) { if (!de) {
if (IS_ERR(page)) if (IS_ERR(page)) {
return (struct dentry *)page; err = PTR_ERR(page);
return d_splice_alias(inode, dentry); goto out;
}
goto out_splice;
} }
ino = le32_to_cpu(de->ino); ino = le32_to_cpu(de->ino);
...@@ -365,19 +391,21 @@ static struct dentry *f2fs_lookup(struct inode *dir, struct dentry *dentry, ...@@ -365,19 +391,21 @@ static struct dentry *f2fs_lookup(struct inode *dir, struct dentry *dentry,
f2fs_put_page(page, 0); f2fs_put_page(page, 0);
inode = f2fs_iget(dir->i_sb, ino); inode = f2fs_iget(dir->i_sb, ino);
if (IS_ERR(inode)) if (IS_ERR(inode)) {
return ERR_CAST(inode); err = PTR_ERR(inode);
goto out;
}
if ((dir->i_ino == root_ino) && f2fs_has_inline_dots(dir)) { if ((dir->i_ino == root_ino) && f2fs_has_inline_dots(dir)) {
err = __recover_dot_dentries(dir, root_ino); err = __recover_dot_dentries(dir, root_ino);
if (err) if (err)
goto err_out; goto out_iput;
} }
if (f2fs_has_inline_dots(inode)) { if (f2fs_has_inline_dots(inode)) {
err = __recover_dot_dentries(inode, dir->i_ino); err = __recover_dot_dentries(inode, dir->i_ino);
if (err) if (err)
goto err_out; goto out_iput;
} }
if (f2fs_encrypted_inode(dir) && if (f2fs_encrypted_inode(dir) &&
(S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)) && (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)) &&
...@@ -386,12 +414,18 @@ static struct dentry *f2fs_lookup(struct inode *dir, struct dentry *dentry, ...@@ -386,12 +414,18 @@ static struct dentry *f2fs_lookup(struct inode *dir, struct dentry *dentry,
"Inconsistent encryption contexts: %lu/%lu", "Inconsistent encryption contexts: %lu/%lu",
dir->i_ino, inode->i_ino); dir->i_ino, inode->i_ino);
err = -EPERM; err = -EPERM;
goto err_out; goto out_iput;
} }
return d_splice_alias(inode, dentry); out_splice:
new = d_splice_alias(inode, dentry);
err_out: if (IS_ERR(new))
err = PTR_ERR(new);
trace_f2fs_lookup_end(dir, dentry, ino, err);
return new;
out_iput:
iput(inode); iput(inode);
out:
trace_f2fs_lookup_end(dir, dentry, ino, err);
return ERR_PTR(err); return ERR_PTR(err);
} }
...@@ -405,7 +439,13 @@ static int f2fs_unlink(struct inode *dir, struct dentry *dentry) ...@@ -405,7 +439,13 @@ static int f2fs_unlink(struct inode *dir, struct dentry *dentry)
trace_f2fs_unlink_enter(dir, dentry); trace_f2fs_unlink_enter(dir, dentry);
if (unlikely(f2fs_cp_error(sbi)))
return -EIO;
err = dquot_initialize(dir); err = dquot_initialize(dir);
if (err)
return err;
err = dquot_initialize(inode);
if (err) if (err)
return err; return err;
...@@ -460,6 +500,9 @@ static int f2fs_symlink(struct inode *dir, struct dentry *dentry, ...@@ -460,6 +500,9 @@ static int f2fs_symlink(struct inode *dir, struct dentry *dentry,
struct fscrypt_symlink_data *sd = NULL; struct fscrypt_symlink_data *sd = NULL;
int err; int err;
if (unlikely(f2fs_cp_error(sbi)))
return -EIO;
if (f2fs_encrypted_inode(dir)) { if (f2fs_encrypted_inode(dir)) {
err = fscrypt_get_encryption_info(dir); err = fscrypt_get_encryption_info(dir);
if (err) if (err)
...@@ -566,6 +609,9 @@ static int f2fs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) ...@@ -566,6 +609,9 @@ static int f2fs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
struct inode *inode; struct inode *inode;
int err; int err;
if (unlikely(f2fs_cp_error(sbi)))
return -EIO;
err = dquot_initialize(dir); err = dquot_initialize(dir);
if (err) if (err)
return err; return err;
...@@ -618,6 +664,9 @@ static int f2fs_mknod(struct inode *dir, struct dentry *dentry, ...@@ -618,6 +664,9 @@ static int f2fs_mknod(struct inode *dir, struct dentry *dentry,
struct inode *inode; struct inode *inode;
int err = 0; int err = 0;
if (unlikely(f2fs_cp_error(sbi)))
return -EIO;
err = dquot_initialize(dir); err = dquot_initialize(dir);
if (err) if (err)
return err; return err;
...@@ -712,6 +761,9 @@ static int __f2fs_tmpfile(struct inode *dir, struct dentry *dentry, ...@@ -712,6 +761,9 @@ static int __f2fs_tmpfile(struct inode *dir, struct dentry *dentry,
static int f2fs_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode) static int f2fs_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode)
{ {
if (unlikely(f2fs_cp_error(F2FS_I_SB(dir))))
return -EIO;
if (f2fs_encrypted_inode(dir)) { if (f2fs_encrypted_inode(dir)) {
int err = fscrypt_get_encryption_info(dir); int err = fscrypt_get_encryption_info(dir);
if (err) if (err)
...@@ -723,6 +775,9 @@ static int f2fs_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode) ...@@ -723,6 +775,9 @@ static int f2fs_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode)
static int f2fs_create_whiteout(struct inode *dir, struct inode **whiteout) static int f2fs_create_whiteout(struct inode *dir, struct inode **whiteout)
{ {
if (unlikely(f2fs_cp_error(F2FS_I_SB(dir))))
return -EIO;
return __f2fs_tmpfile(dir, NULL, S_IFCHR | WHITEOUT_MODE, whiteout); return __f2fs_tmpfile(dir, NULL, S_IFCHR | WHITEOUT_MODE, whiteout);
} }
...@@ -742,6 +797,9 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -742,6 +797,9 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
bool is_old_inline = f2fs_has_inline_dentry(old_dir); bool is_old_inline = f2fs_has_inline_dentry(old_dir);
int err = -ENOENT; int err = -ENOENT;
if (unlikely(f2fs_cp_error(sbi)))
return -EIO;
if ((f2fs_encrypted_inode(old_dir) && if ((f2fs_encrypted_inode(old_dir) &&
!fscrypt_has_encryption_key(old_dir)) || !fscrypt_has_encryption_key(old_dir)) ||
(f2fs_encrypted_inode(new_dir) && (f2fs_encrypted_inode(new_dir) &&
...@@ -767,6 +825,12 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -767,6 +825,12 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
if (err) if (err)
goto out; goto out;
if (new_inode) {
err = dquot_initialize(new_inode);
if (err)
goto out;
}
old_entry = f2fs_find_entry(old_dir, &old_dentry->d_name, &old_page); old_entry = f2fs_find_entry(old_dir, &old_dentry->d_name, &old_page);
if (!old_entry) { if (!old_entry) {
if (IS_ERR(old_page)) if (IS_ERR(old_page))
...@@ -935,6 +999,9 @@ static int f2fs_cross_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -935,6 +999,9 @@ static int f2fs_cross_rename(struct inode *old_dir, struct dentry *old_dentry,
int old_nlink = 0, new_nlink = 0; int old_nlink = 0, new_nlink = 0;
int err = -ENOENT; int err = -ENOENT;
if (unlikely(f2fs_cp_error(sbi)))
return -EIO;
if ((f2fs_encrypted_inode(old_dir) && if ((f2fs_encrypted_inode(old_dir) &&
!fscrypt_has_encryption_key(old_dir)) || !fscrypt_has_encryption_key(old_dir)) ||
(f2fs_encrypted_inode(new_dir) && (f2fs_encrypted_inode(new_dir) &&
......
This diff is collapsed.
...@@ -140,6 +140,7 @@ enum mem_type { ...@@ -140,6 +140,7 @@ enum mem_type {
DIRTY_DENTS, /* indicates dirty dentry pages */ DIRTY_DENTS, /* indicates dirty dentry pages */
INO_ENTRIES, /* indicates inode entries */ INO_ENTRIES, /* indicates inode entries */
EXTENT_CACHE, /* indicates extent cache */ EXTENT_CACHE, /* indicates extent cache */
INMEM_PAGES, /* indicates inmemory pages */
BASE_CHECK, /* check kernel status */ BASE_CHECK, /* check kernel status */
}; };
...@@ -150,18 +151,10 @@ struct nat_entry_set { ...@@ -150,18 +151,10 @@ struct nat_entry_set {
unsigned int entry_cnt; /* the # of nat entries in set */ unsigned int entry_cnt; /* the # of nat entries in set */
}; };
/*
* For free nid mangement
*/
enum nid_state {
NID_NEW, /* newly added to free nid list */
NID_ALLOC /* it is allocated */
};
struct free_nid { struct free_nid {
struct list_head list; /* for free node id list */ struct list_head list; /* for free node id list */
nid_t nid; /* node id */ nid_t nid; /* node id */
int state; /* in use or not: NID_NEW or NID_ALLOC */ int state; /* in use or not: FREE_NID or PREALLOC_NID */
}; };
static inline void next_free_nid(struct f2fs_sb_info *sbi, nid_t *nid) static inline void next_free_nid(struct f2fs_sb_info *sbi, nid_t *nid)
...@@ -170,12 +163,11 @@ static inline void next_free_nid(struct f2fs_sb_info *sbi, nid_t *nid) ...@@ -170,12 +163,11 @@ static inline void next_free_nid(struct f2fs_sb_info *sbi, nid_t *nid)
struct free_nid *fnid; struct free_nid *fnid;
spin_lock(&nm_i->nid_list_lock); spin_lock(&nm_i->nid_list_lock);
if (nm_i->nid_cnt[FREE_NID_LIST] <= 0) { if (nm_i->nid_cnt[FREE_NID] <= 0) {
spin_unlock(&nm_i->nid_list_lock); spin_unlock(&nm_i->nid_list_lock);
return; return;
} }
fnid = list_first_entry(&nm_i->nid_list[FREE_NID_LIST], fnid = list_first_entry(&nm_i->free_nid_list, struct free_nid, list);
struct free_nid, list);
*nid = fnid->nid; *nid = fnid->nid;
spin_unlock(&nm_i->nid_list_lock); spin_unlock(&nm_i->nid_list_lock);
} }
......
...@@ -594,6 +594,9 @@ int recover_fsync_data(struct f2fs_sb_info *sbi, bool check_only) ...@@ -594,6 +594,9 @@ int recover_fsync_data(struct f2fs_sb_info *sbi, bool check_only)
int ret = 0; int ret = 0;
unsigned long s_flags = sbi->sb->s_flags; unsigned long s_flags = sbi->sb->s_flags;
bool need_writecp = false; bool need_writecp = false;
#ifdef CONFIG_QUOTA
int quota_enabled;
#endif
if (s_flags & MS_RDONLY) { if (s_flags & MS_RDONLY) {
f2fs_msg(sbi->sb, KERN_INFO, "orphan cleanup on readonly fs"); f2fs_msg(sbi->sb, KERN_INFO, "orphan cleanup on readonly fs");
...@@ -604,7 +607,7 @@ int recover_fsync_data(struct f2fs_sb_info *sbi, bool check_only) ...@@ -604,7 +607,7 @@ int recover_fsync_data(struct f2fs_sb_info *sbi, bool check_only)
/* Needed for iput() to work correctly and not trash data */ /* Needed for iput() to work correctly and not trash data */
sbi->sb->s_flags |= MS_ACTIVE; sbi->sb->s_flags |= MS_ACTIVE;
/* Turn on quotas so that they are updated correctly */ /* Turn on quotas so that they are updated correctly */
f2fs_enable_quota_files(sbi); quota_enabled = f2fs_enable_quota_files(sbi, s_flags & MS_RDONLY);
#endif #endif
fsync_entry_slab = f2fs_kmem_cache_create("f2fs_fsync_inode_entry", fsync_entry_slab = f2fs_kmem_cache_create("f2fs_fsync_inode_entry",
...@@ -665,7 +668,8 @@ int recover_fsync_data(struct f2fs_sb_info *sbi, bool check_only) ...@@ -665,7 +668,8 @@ int recover_fsync_data(struct f2fs_sb_info *sbi, bool check_only)
out: out:
#ifdef CONFIG_QUOTA #ifdef CONFIG_QUOTA
/* Turn quotas off */ /* Turn quotas off */
f2fs_quota_off_umount(sbi->sb); if (quota_enabled)
f2fs_quota_off_umount(sbi->sb);
#endif #endif
sbi->sb->s_flags = s_flags; /* Restore MS_RDONLY status */ sbi->sb->s_flags = s_flags; /* Restore MS_RDONLY status */
......
This diff is collapsed.
...@@ -231,7 +231,7 @@ struct sit_info { ...@@ -231,7 +231,7 @@ struct sit_info {
unsigned long *dirty_sentries_bitmap; /* bitmap for dirty sentries */ unsigned long *dirty_sentries_bitmap; /* bitmap for dirty sentries */
unsigned int dirty_sentries; /* # of dirty sentries */ unsigned int dirty_sentries; /* # of dirty sentries */
unsigned int sents_per_block; /* # of SIT entries per block */ unsigned int sents_per_block; /* # of SIT entries per block */
struct mutex sentry_lock; /* to protect SIT cache */ struct rw_semaphore sentry_lock; /* to protect SIT cache */
struct seg_entry *sentries; /* SIT segment-level cache */ struct seg_entry *sentries; /* SIT segment-level cache */
struct sec_entry *sec_entries; /* SIT section-level cache */ struct sec_entry *sec_entries; /* SIT section-level cache */
...@@ -497,6 +497,33 @@ static inline int reserved_sections(struct f2fs_sb_info *sbi) ...@@ -497,6 +497,33 @@ static inline int reserved_sections(struct f2fs_sb_info *sbi)
return GET_SEC_FROM_SEG(sbi, (unsigned int)reserved_segments(sbi)); return GET_SEC_FROM_SEG(sbi, (unsigned int)reserved_segments(sbi));
} }
static inline bool has_curseg_enough_space(struct f2fs_sb_info *sbi)
{
unsigned int node_blocks = get_pages(sbi, F2FS_DIRTY_NODES) +
get_pages(sbi, F2FS_DIRTY_DENTS);
unsigned int dent_blocks = get_pages(sbi, F2FS_DIRTY_DENTS);
unsigned int segno, left_blocks;
int i;
/* check current node segment */
for (i = CURSEG_HOT_NODE; i <= CURSEG_COLD_NODE; i++) {
segno = CURSEG_I(sbi, i)->segno;
left_blocks = sbi->blocks_per_seg -
get_seg_entry(sbi, segno)->ckpt_valid_blocks;
if (node_blocks > left_blocks)
return false;
}
/* check current data segment */
segno = CURSEG_I(sbi, CURSEG_HOT_DATA)->segno;
left_blocks = sbi->blocks_per_seg -
get_seg_entry(sbi, segno)->ckpt_valid_blocks;
if (dent_blocks > left_blocks)
return false;
return true;
}
static inline bool has_not_enough_free_secs(struct f2fs_sb_info *sbi, static inline bool has_not_enough_free_secs(struct f2fs_sb_info *sbi,
int freed, int needed) int freed, int needed)
{ {
...@@ -507,6 +534,9 @@ static inline bool has_not_enough_free_secs(struct f2fs_sb_info *sbi, ...@@ -507,6 +534,9 @@ static inline bool has_not_enough_free_secs(struct f2fs_sb_info *sbi,
if (unlikely(is_sbi_flag_set(sbi, SBI_POR_DOING))) if (unlikely(is_sbi_flag_set(sbi, SBI_POR_DOING)))
return false; return false;
if (free_sections(sbi) + freed == reserved_sections(sbi) + needed &&
has_curseg_enough_space(sbi))
return false;
return (free_sections(sbi) + freed) <= return (free_sections(sbi) + freed) <=
(node_secs + 2 * dent_secs + imeta_secs + (node_secs + 2 * dent_secs + imeta_secs +
reserved_sections(sbi) + needed); reserved_sections(sbi) + needed);
...@@ -731,7 +761,7 @@ static inline block_t sum_blk_addr(struct f2fs_sb_info *sbi, int base, int type) ...@@ -731,7 +761,7 @@ static inline block_t sum_blk_addr(struct f2fs_sb_info *sbi, int base, int type)
static inline bool no_fggc_candidate(struct f2fs_sb_info *sbi, static inline bool no_fggc_candidate(struct f2fs_sb_info *sbi,
unsigned int secno) unsigned int secno)
{ {
if (get_valid_blocks(sbi, GET_SEG_FROM_SEC(sbi, secno), true) >= if (get_valid_blocks(sbi, GET_SEG_FROM_SEC(sbi, secno), true) >
sbi->fggc_threshold) sbi->fggc_threshold)
return true; return true;
return false; return false;
...@@ -796,8 +826,9 @@ static inline void wake_up_discard_thread(struct f2fs_sb_info *sbi, bool force) ...@@ -796,8 +826,9 @@ static inline void wake_up_discard_thread(struct f2fs_sb_info *sbi, bool force)
goto wake_up; goto wake_up;
mutex_lock(&dcc->cmd_lock); mutex_lock(&dcc->cmd_lock);
for (i = MAX_PLIST_NUM - 1; for (i = MAX_PLIST_NUM - 1; i >= 0; i--) {
i >= 0 && plist_issue(dcc->pend_list_tag[i]); i--) { if (i + 1 < dcc->discard_granularity)
break;
if (!list_empty(&dcc->pend_list[i])) { if (!list_empty(&dcc->pend_list[i])) {
wakeup = true; wakeup = true;
break; break;
......
...@@ -28,7 +28,7 @@ static unsigned long __count_nat_entries(struct f2fs_sb_info *sbi) ...@@ -28,7 +28,7 @@ static unsigned long __count_nat_entries(struct f2fs_sb_info *sbi)
static unsigned long __count_free_nids(struct f2fs_sb_info *sbi) static unsigned long __count_free_nids(struct f2fs_sb_info *sbi)
{ {
long count = NM_I(sbi)->nid_cnt[FREE_NID_LIST] - MAX_FREE_NIDS; long count = NM_I(sbi)->nid_cnt[FREE_NID] - MAX_FREE_NIDS;
return count > 0 ? count : 0; return count > 0 ? count : 0;
} }
......
This diff is collapsed.
...@@ -30,7 +30,7 @@ enum { ...@@ -30,7 +30,7 @@ enum {
FAULT_INFO_RATE, /* struct f2fs_fault_info */ FAULT_INFO_RATE, /* struct f2fs_fault_info */
FAULT_INFO_TYPE, /* struct f2fs_fault_info */ FAULT_INFO_TYPE, /* struct f2fs_fault_info */
#endif #endif
RESERVED_BLOCKS, RESERVED_BLOCKS, /* struct f2fs_sb_info */
}; };
struct f2fs_attr { struct f2fs_attr {
...@@ -63,6 +63,13 @@ static unsigned char *__struct_ptr(struct f2fs_sb_info *sbi, int struct_type) ...@@ -63,6 +63,13 @@ static unsigned char *__struct_ptr(struct f2fs_sb_info *sbi, int struct_type)
return NULL; return NULL;
} }
static ssize_t dirty_segments_show(struct f2fs_attr *a,
struct f2fs_sb_info *sbi, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%llu\n",
(unsigned long long)(dirty_segments(sbi)));
}
static ssize_t lifetime_write_kbytes_show(struct f2fs_attr *a, static ssize_t lifetime_write_kbytes_show(struct f2fs_attr *a,
struct f2fs_sb_info *sbi, char *buf) struct f2fs_sb_info *sbi, char *buf)
{ {
...@@ -100,10 +107,22 @@ static ssize_t features_show(struct f2fs_attr *a, ...@@ -100,10 +107,22 @@ static ssize_t features_show(struct f2fs_attr *a,
if (f2fs_sb_has_inode_chksum(sb)) if (f2fs_sb_has_inode_chksum(sb))
len += snprintf(buf + len, PAGE_SIZE - len, "%s%s", len += snprintf(buf + len, PAGE_SIZE - len, "%s%s",
len ? ", " : "", "inode_checksum"); len ? ", " : "", "inode_checksum");
if (f2fs_sb_has_flexible_inline_xattr(sb))
len += snprintf(buf + len, PAGE_SIZE - len, "%s%s",
len ? ", " : "", "flexible_inline_xattr");
if (f2fs_sb_has_quota_ino(sb))
len += snprintf(buf + len, PAGE_SIZE - len, "%s%s",
len ? ", " : "", "quota_ino");
len += snprintf(buf + len, PAGE_SIZE - len, "\n"); len += snprintf(buf + len, PAGE_SIZE - len, "\n");
return len; return len;
} }
static ssize_t current_reserved_blocks_show(struct f2fs_attr *a,
struct f2fs_sb_info *sbi, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%u\n", sbi->current_reserved_blocks);
}
static ssize_t f2fs_sbi_show(struct f2fs_attr *a, static ssize_t f2fs_sbi_show(struct f2fs_attr *a,
struct f2fs_sb_info *sbi, char *buf) struct f2fs_sb_info *sbi, char *buf)
{ {
...@@ -143,34 +162,22 @@ static ssize_t f2fs_sbi_store(struct f2fs_attr *a, ...@@ -143,34 +162,22 @@ static ssize_t f2fs_sbi_store(struct f2fs_attr *a,
#endif #endif
if (a->struct_type == RESERVED_BLOCKS) { if (a->struct_type == RESERVED_BLOCKS) {
spin_lock(&sbi->stat_lock); spin_lock(&sbi->stat_lock);
if ((unsigned long)sbi->total_valid_block_count + t > if (t > (unsigned long)sbi->user_block_count) {
(unsigned long)sbi->user_block_count) {
spin_unlock(&sbi->stat_lock); spin_unlock(&sbi->stat_lock);
return -EINVAL; return -EINVAL;
} }
*ui = t; *ui = t;
sbi->current_reserved_blocks = min(sbi->reserved_blocks,
sbi->user_block_count - valid_user_blocks(sbi));
spin_unlock(&sbi->stat_lock); spin_unlock(&sbi->stat_lock);
return count; return count;
} }
if (!strcmp(a->attr.name, "discard_granularity")) { if (!strcmp(a->attr.name, "discard_granularity")) {
struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
int i;
if (t == 0 || t > MAX_PLIST_NUM) if (t == 0 || t > MAX_PLIST_NUM)
return -EINVAL; return -EINVAL;
if (t == *ui) if (t == *ui)
return count; return count;
mutex_lock(&dcc->cmd_lock);
for (i = 0; i < MAX_PLIST_NUM; i++) {
if (i >= t - 1)
dcc->pend_list_tag[i] |= P_ACTIVE;
else
dcc->pend_list_tag[i] &= (~P_ACTIVE);
}
mutex_unlock(&dcc->cmd_lock);
*ui = t; *ui = t;
return count; return count;
} }
...@@ -222,6 +229,8 @@ enum feat_id { ...@@ -222,6 +229,8 @@ enum feat_id {
FEAT_EXTRA_ATTR, FEAT_EXTRA_ATTR,
FEAT_PROJECT_QUOTA, FEAT_PROJECT_QUOTA,
FEAT_INODE_CHECKSUM, FEAT_INODE_CHECKSUM,
FEAT_FLEXIBLE_INLINE_XATTR,
FEAT_QUOTA_INO,
}; };
static ssize_t f2fs_feature_show(struct f2fs_attr *a, static ssize_t f2fs_feature_show(struct f2fs_attr *a,
...@@ -234,6 +243,8 @@ static ssize_t f2fs_feature_show(struct f2fs_attr *a, ...@@ -234,6 +243,8 @@ static ssize_t f2fs_feature_show(struct f2fs_attr *a,
case FEAT_EXTRA_ATTR: case FEAT_EXTRA_ATTR:
case FEAT_PROJECT_QUOTA: case FEAT_PROJECT_QUOTA:
case FEAT_INODE_CHECKSUM: case FEAT_INODE_CHECKSUM:
case FEAT_FLEXIBLE_INLINE_XATTR:
case FEAT_QUOTA_INO:
return snprintf(buf, PAGE_SIZE, "supported\n"); return snprintf(buf, PAGE_SIZE, "supported\n");
} }
return 0; return 0;
...@@ -279,6 +290,7 @@ F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, ipu_policy, ipu_policy); ...@@ -279,6 +290,7 @@ F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, ipu_policy, ipu_policy);
F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, min_ipu_util, min_ipu_util); F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, min_ipu_util, min_ipu_util);
F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, min_fsync_blocks, min_fsync_blocks); F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, min_fsync_blocks, min_fsync_blocks);
F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, min_hot_blocks, min_hot_blocks); F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, min_hot_blocks, min_hot_blocks);
F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, min_ssr_sections, min_ssr_sections);
F2FS_RW_ATTR(NM_INFO, f2fs_nm_info, ram_thresh, ram_thresh); F2FS_RW_ATTR(NM_INFO, f2fs_nm_info, ram_thresh, ram_thresh);
F2FS_RW_ATTR(NM_INFO, f2fs_nm_info, ra_nid_pages, ra_nid_pages); F2FS_RW_ATTR(NM_INFO, f2fs_nm_info, ra_nid_pages, ra_nid_pages);
F2FS_RW_ATTR(NM_INFO, f2fs_nm_info, dirty_nats_ratio, dirty_nats_ratio); F2FS_RW_ATTR(NM_INFO, f2fs_nm_info, dirty_nats_ratio, dirty_nats_ratio);
...@@ -291,8 +303,10 @@ F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, iostat_enable, iostat_enable); ...@@ -291,8 +303,10 @@ F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, iostat_enable, iostat_enable);
F2FS_RW_ATTR(FAULT_INFO_RATE, f2fs_fault_info, inject_rate, inject_rate); F2FS_RW_ATTR(FAULT_INFO_RATE, f2fs_fault_info, inject_rate, inject_rate);
F2FS_RW_ATTR(FAULT_INFO_TYPE, f2fs_fault_info, inject_type, inject_type); F2FS_RW_ATTR(FAULT_INFO_TYPE, f2fs_fault_info, inject_type, inject_type);
#endif #endif
F2FS_GENERAL_RO_ATTR(dirty_segments);
F2FS_GENERAL_RO_ATTR(lifetime_write_kbytes); F2FS_GENERAL_RO_ATTR(lifetime_write_kbytes);
F2FS_GENERAL_RO_ATTR(features); F2FS_GENERAL_RO_ATTR(features);
F2FS_GENERAL_RO_ATTR(current_reserved_blocks);
#ifdef CONFIG_F2FS_FS_ENCRYPTION #ifdef CONFIG_F2FS_FS_ENCRYPTION
F2FS_FEATURE_RO_ATTR(encryption, FEAT_CRYPTO); F2FS_FEATURE_RO_ATTR(encryption, FEAT_CRYPTO);
...@@ -304,6 +318,8 @@ F2FS_FEATURE_RO_ATTR(atomic_write, FEAT_ATOMIC_WRITE); ...@@ -304,6 +318,8 @@ F2FS_FEATURE_RO_ATTR(atomic_write, FEAT_ATOMIC_WRITE);
F2FS_FEATURE_RO_ATTR(extra_attr, FEAT_EXTRA_ATTR); F2FS_FEATURE_RO_ATTR(extra_attr, FEAT_EXTRA_ATTR);
F2FS_FEATURE_RO_ATTR(project_quota, FEAT_PROJECT_QUOTA); F2FS_FEATURE_RO_ATTR(project_quota, FEAT_PROJECT_QUOTA);
F2FS_FEATURE_RO_ATTR(inode_checksum, FEAT_INODE_CHECKSUM); F2FS_FEATURE_RO_ATTR(inode_checksum, FEAT_INODE_CHECKSUM);
F2FS_FEATURE_RO_ATTR(flexible_inline_xattr, FEAT_FLEXIBLE_INLINE_XATTR);
F2FS_FEATURE_RO_ATTR(quota_ino, FEAT_QUOTA_INO);
#define ATTR_LIST(name) (&f2fs_attr_##name.attr) #define ATTR_LIST(name) (&f2fs_attr_##name.attr)
static struct attribute *f2fs_attrs[] = { static struct attribute *f2fs_attrs[] = {
...@@ -321,6 +337,7 @@ static struct attribute *f2fs_attrs[] = { ...@@ -321,6 +337,7 @@ static struct attribute *f2fs_attrs[] = {
ATTR_LIST(min_ipu_util), ATTR_LIST(min_ipu_util),
ATTR_LIST(min_fsync_blocks), ATTR_LIST(min_fsync_blocks),
ATTR_LIST(min_hot_blocks), ATTR_LIST(min_hot_blocks),
ATTR_LIST(min_ssr_sections),
ATTR_LIST(max_victim_search), ATTR_LIST(max_victim_search),
ATTR_LIST(dir_level), ATTR_LIST(dir_level),
ATTR_LIST(ram_thresh), ATTR_LIST(ram_thresh),
...@@ -333,9 +350,11 @@ static struct attribute *f2fs_attrs[] = { ...@@ -333,9 +350,11 @@ static struct attribute *f2fs_attrs[] = {
ATTR_LIST(inject_rate), ATTR_LIST(inject_rate),
ATTR_LIST(inject_type), ATTR_LIST(inject_type),
#endif #endif
ATTR_LIST(dirty_segments),
ATTR_LIST(lifetime_write_kbytes), ATTR_LIST(lifetime_write_kbytes),
ATTR_LIST(features), ATTR_LIST(features),
ATTR_LIST(reserved_blocks), ATTR_LIST(reserved_blocks),
ATTR_LIST(current_reserved_blocks),
NULL, NULL,
}; };
...@@ -350,6 +369,8 @@ static struct attribute *f2fs_feat_attrs[] = { ...@@ -350,6 +369,8 @@ static struct attribute *f2fs_feat_attrs[] = {
ATTR_LIST(extra_attr), ATTR_LIST(extra_attr),
ATTR_LIST(project_quota), ATTR_LIST(project_quota),
ATTR_LIST(inode_checksum), ATTR_LIST(inode_checksum),
ATTR_LIST(flexible_inline_xattr),
ATTR_LIST(quota_ino),
NULL, NULL,
}; };
......
...@@ -217,12 +217,12 @@ static struct f2fs_xattr_entry *__find_xattr(void *base_addr, int index, ...@@ -217,12 +217,12 @@ static struct f2fs_xattr_entry *__find_xattr(void *base_addr, int index,
return entry; return entry;
} }
static struct f2fs_xattr_entry *__find_inline_xattr(void *base_addr, static struct f2fs_xattr_entry *__find_inline_xattr(struct inode *inode,
void **last_addr, int index, void *base_addr, void **last_addr, int index,
size_t len, const char *name) size_t len, const char *name)
{ {
struct f2fs_xattr_entry *entry; struct f2fs_xattr_entry *entry;
unsigned int inline_size = F2FS_INLINE_XATTR_ADDRS << 2; unsigned int inline_size = inline_xattr_size(inode);
list_for_each_xattr(entry, base_addr) { list_for_each_xattr(entry, base_addr) {
if ((void *)entry + sizeof(__u32) > base_addr + inline_size || if ((void *)entry + sizeof(__u32) > base_addr + inline_size ||
...@@ -241,12 +241,54 @@ static struct f2fs_xattr_entry *__find_inline_xattr(void *base_addr, ...@@ -241,12 +241,54 @@ static struct f2fs_xattr_entry *__find_inline_xattr(void *base_addr,
return entry; return entry;
} }
static int read_inline_xattr(struct inode *inode, struct page *ipage,
void *txattr_addr)
{
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
unsigned int inline_size = inline_xattr_size(inode);
struct page *page = NULL;
void *inline_addr;
if (ipage) {
inline_addr = inline_xattr_addr(inode, ipage);
} else {
page = get_node_page(sbi, inode->i_ino);
if (IS_ERR(page))
return PTR_ERR(page);
inline_addr = inline_xattr_addr(inode, page);
}
memcpy(txattr_addr, inline_addr, inline_size);
f2fs_put_page(page, 1);
return 0;
}
static int read_xattr_block(struct inode *inode, void *txattr_addr)
{
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
nid_t xnid = F2FS_I(inode)->i_xattr_nid;
unsigned int inline_size = inline_xattr_size(inode);
struct page *xpage;
void *xattr_addr;
/* The inode already has an extended attribute block. */
xpage = get_node_page(sbi, xnid);
if (IS_ERR(xpage))
return PTR_ERR(xpage);
xattr_addr = page_address(xpage);
memcpy(txattr_addr + inline_size, xattr_addr, VALID_XATTR_BLOCK_SIZE);
f2fs_put_page(xpage, 1);
return 0;
}
static int lookup_all_xattrs(struct inode *inode, struct page *ipage, static int lookup_all_xattrs(struct inode *inode, struct page *ipage,
unsigned int index, unsigned int len, unsigned int index, unsigned int len,
const char *name, struct f2fs_xattr_entry **xe, const char *name, struct f2fs_xattr_entry **xe,
void **base_addr) void **base_addr)
{ {
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
void *cur_addr, *txattr_addr, *last_addr = NULL; void *cur_addr, *txattr_addr, *last_addr = NULL;
nid_t xnid = F2FS_I(inode)->i_xattr_nid; nid_t xnid = F2FS_I(inode)->i_xattr_nid;
unsigned int size = xnid ? VALID_XATTR_BLOCK_SIZE : 0; unsigned int size = xnid ? VALID_XATTR_BLOCK_SIZE : 0;
...@@ -263,23 +305,11 @@ static int lookup_all_xattrs(struct inode *inode, struct page *ipage, ...@@ -263,23 +305,11 @@ static int lookup_all_xattrs(struct inode *inode, struct page *ipage,
/* read from inline xattr */ /* read from inline xattr */
if (inline_size) { if (inline_size) {
struct page *page = NULL; err = read_inline_xattr(inode, ipage, txattr_addr);
void *inline_addr; if (err)
goto out;
if (ipage) {
inline_addr = inline_xattr_addr(ipage);
} else {
page = get_node_page(sbi, inode->i_ino);
if (IS_ERR(page)) {
err = PTR_ERR(page);
goto out;
}
inline_addr = inline_xattr_addr(page);
}
memcpy(txattr_addr, inline_addr, inline_size);
f2fs_put_page(page, 1);
*xe = __find_inline_xattr(txattr_addr, &last_addr, *xe = __find_inline_xattr(inode, txattr_addr, &last_addr,
index, len, name); index, len, name);
if (*xe) if (*xe)
goto check; goto check;
...@@ -287,19 +317,9 @@ static int lookup_all_xattrs(struct inode *inode, struct page *ipage, ...@@ -287,19 +317,9 @@ static int lookup_all_xattrs(struct inode *inode, struct page *ipage,
/* read from xattr node block */ /* read from xattr node block */
if (xnid) { if (xnid) {
struct page *xpage; err = read_xattr_block(inode, txattr_addr);
void *xattr_addr; if (err)
/* The inode already has an extended attribute block. */
xpage = get_node_page(sbi, xnid);
if (IS_ERR(xpage)) {
err = PTR_ERR(xpage);
goto out; goto out;
}
xattr_addr = page_address(xpage);
memcpy(txattr_addr + inline_size, xattr_addr, size);
f2fs_put_page(xpage, 1);
} }
if (last_addr) if (last_addr)
...@@ -324,7 +344,6 @@ static int lookup_all_xattrs(struct inode *inode, struct page *ipage, ...@@ -324,7 +344,6 @@ static int lookup_all_xattrs(struct inode *inode, struct page *ipage,
static int read_all_xattrs(struct inode *inode, struct page *ipage, static int read_all_xattrs(struct inode *inode, struct page *ipage,
void **base_addr) void **base_addr)
{ {
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
struct f2fs_xattr_header *header; struct f2fs_xattr_header *header;
nid_t xnid = F2FS_I(inode)->i_xattr_nid; nid_t xnid = F2FS_I(inode)->i_xattr_nid;
unsigned int size = VALID_XATTR_BLOCK_SIZE; unsigned int size = VALID_XATTR_BLOCK_SIZE;
...@@ -339,38 +358,16 @@ static int read_all_xattrs(struct inode *inode, struct page *ipage, ...@@ -339,38 +358,16 @@ static int read_all_xattrs(struct inode *inode, struct page *ipage,
/* read from inline xattr */ /* read from inline xattr */
if (inline_size) { if (inline_size) {
struct page *page = NULL; err = read_inline_xattr(inode, ipage, txattr_addr);
void *inline_addr; if (err)
goto fail;
if (ipage) {
inline_addr = inline_xattr_addr(ipage);
} else {
page = get_node_page(sbi, inode->i_ino);
if (IS_ERR(page)) {
err = PTR_ERR(page);
goto fail;
}
inline_addr = inline_xattr_addr(page);
}
memcpy(txattr_addr, inline_addr, inline_size);
f2fs_put_page(page, 1);
} }
/* read from xattr node block */ /* read from xattr node block */
if (xnid) { if (xnid) {
struct page *xpage; err = read_xattr_block(inode, txattr_addr);
void *xattr_addr; if (err)
/* The inode already has an extended attribute block. */
xpage = get_node_page(sbi, xnid);
if (IS_ERR(xpage)) {
err = PTR_ERR(xpage);
goto fail; goto fail;
}
xattr_addr = page_address(xpage);
memcpy(txattr_addr + inline_size, xattr_addr, size);
f2fs_put_page(xpage, 1);
} }
header = XATTR_HDR(txattr_addr); header = XATTR_HDR(txattr_addr);
...@@ -392,10 +389,12 @@ static inline int write_all_xattrs(struct inode *inode, __u32 hsize, ...@@ -392,10 +389,12 @@ static inline int write_all_xattrs(struct inode *inode, __u32 hsize,
{ {
struct f2fs_sb_info *sbi = F2FS_I_SB(inode); struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
size_t inline_size = inline_xattr_size(inode); size_t inline_size = inline_xattr_size(inode);
struct page *in_page = NULL;
void *xattr_addr; void *xattr_addr;
void *inline_addr = NULL;
struct page *xpage; struct page *xpage;
nid_t new_nid = 0; nid_t new_nid = 0;
int err; int err = 0;
if (hsize > inline_size && !F2FS_I(inode)->i_xattr_nid) if (hsize > inline_size && !F2FS_I(inode)->i_xattr_nid)
if (!alloc_nid(sbi, &new_nid)) if (!alloc_nid(sbi, &new_nid))
...@@ -403,30 +402,30 @@ static inline int write_all_xattrs(struct inode *inode, __u32 hsize, ...@@ -403,30 +402,30 @@ static inline int write_all_xattrs(struct inode *inode, __u32 hsize,
/* write to inline xattr */ /* write to inline xattr */
if (inline_size) { if (inline_size) {
struct page *page = NULL;
void *inline_addr;
if (ipage) { if (ipage) {
inline_addr = inline_xattr_addr(ipage); inline_addr = inline_xattr_addr(inode, ipage);
f2fs_wait_on_page_writeback(ipage, NODE, true);
set_page_dirty(ipage);
} else { } else {
page = get_node_page(sbi, inode->i_ino); in_page = get_node_page(sbi, inode->i_ino);
if (IS_ERR(page)) { if (IS_ERR(in_page)) {
alloc_nid_failed(sbi, new_nid); alloc_nid_failed(sbi, new_nid);
return PTR_ERR(page); return PTR_ERR(in_page);
} }
inline_addr = inline_xattr_addr(page); inline_addr = inline_xattr_addr(inode, in_page);
f2fs_wait_on_page_writeback(page, NODE, true);
} }
memcpy(inline_addr, txattr_addr, inline_size);
f2fs_put_page(page, 1);
f2fs_wait_on_page_writeback(ipage ? ipage : in_page,
NODE, true);
/* no need to use xattr node block */ /* no need to use xattr node block */
if (hsize <= inline_size) { if (hsize <= inline_size) {
err = truncate_xattr_node(inode, ipage); err = truncate_xattr_node(inode);
alloc_nid_failed(sbi, new_nid); alloc_nid_failed(sbi, new_nid);
return err; if (err) {
f2fs_put_page(in_page, 1);
return err;
}
memcpy(inline_addr, txattr_addr, inline_size);
set_page_dirty(ipage ? ipage : in_page);
goto in_page_out;
} }
} }
...@@ -435,7 +434,7 @@ static inline int write_all_xattrs(struct inode *inode, __u32 hsize, ...@@ -435,7 +434,7 @@ static inline int write_all_xattrs(struct inode *inode, __u32 hsize,
xpage = get_node_page(sbi, F2FS_I(inode)->i_xattr_nid); xpage = get_node_page(sbi, F2FS_I(inode)->i_xattr_nid);
if (IS_ERR(xpage)) { if (IS_ERR(xpage)) {
alloc_nid_failed(sbi, new_nid); alloc_nid_failed(sbi, new_nid);
return PTR_ERR(xpage); goto in_page_out;
} }
f2fs_bug_on(sbi, new_nid); f2fs_bug_on(sbi, new_nid);
f2fs_wait_on_page_writeback(xpage, NODE, true); f2fs_wait_on_page_writeback(xpage, NODE, true);
...@@ -445,17 +444,24 @@ static inline int write_all_xattrs(struct inode *inode, __u32 hsize, ...@@ -445,17 +444,24 @@ static inline int write_all_xattrs(struct inode *inode, __u32 hsize,
xpage = new_node_page(&dn, XATTR_NODE_OFFSET); xpage = new_node_page(&dn, XATTR_NODE_OFFSET);
if (IS_ERR(xpage)) { if (IS_ERR(xpage)) {
alloc_nid_failed(sbi, new_nid); alloc_nid_failed(sbi, new_nid);
return PTR_ERR(xpage); goto in_page_out;
} }
alloc_nid_done(sbi, new_nid); alloc_nid_done(sbi, new_nid);
} }
xattr_addr = page_address(xpage); xattr_addr = page_address(xpage);
if (inline_size)
memcpy(inline_addr, txattr_addr, inline_size);
memcpy(xattr_addr, txattr_addr + inline_size, VALID_XATTR_BLOCK_SIZE); memcpy(xattr_addr, txattr_addr + inline_size, VALID_XATTR_BLOCK_SIZE);
if (inline_size)
set_page_dirty(ipage ? ipage : in_page);
set_page_dirty(xpage); set_page_dirty(xpage);
f2fs_put_page(xpage, 1);
return 0; f2fs_put_page(xpage, 1);
in_page_out:
f2fs_put_page(in_page, 1);
return err;
} }
int f2fs_getxattr(struct inode *inode, int index, const char *name, int f2fs_getxattr(struct inode *inode, int index, const char *name,
...@@ -681,6 +687,10 @@ int f2fs_setxattr(struct inode *inode, int index, const char *name, ...@@ -681,6 +687,10 @@ int f2fs_setxattr(struct inode *inode, int index, const char *name,
struct f2fs_sb_info *sbi = F2FS_I_SB(inode); struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
int err; int err;
err = dquot_initialize(inode);
if (err)
return err;
/* this case is only from init_inode_metadata */ /* this case is only from init_inode_metadata */
if (ipage) if (ipage)
return __f2fs_setxattr(inode, index, name, value, return __f2fs_setxattr(inode, index, name, value,
......
...@@ -36,6 +36,8 @@ ...@@ -36,6 +36,8 @@
#define F2FS_NODE_INO(sbi) ((sbi)->node_ino_num) #define F2FS_NODE_INO(sbi) ((sbi)->node_ino_num)
#define F2FS_META_INO(sbi) ((sbi)->meta_ino_num) #define F2FS_META_INO(sbi) ((sbi)->meta_ino_num)
#define F2FS_MAX_QUOTAS 3
#define F2FS_IO_SIZE(sbi) (1 << (sbi)->write_io_size_bits) /* Blocks */ #define F2FS_IO_SIZE(sbi) (1 << (sbi)->write_io_size_bits) /* Blocks */
#define F2FS_IO_SIZE_KB(sbi) (1 << ((sbi)->write_io_size_bits + 2)) /* KB */ #define F2FS_IO_SIZE_KB(sbi) (1 << ((sbi)->write_io_size_bits + 2)) /* KB */
#define F2FS_IO_SIZE_BYTES(sbi) (1 << ((sbi)->write_io_size_bits + 12)) /* B */ #define F2FS_IO_SIZE_BYTES(sbi) (1 << ((sbi)->write_io_size_bits + 12)) /* B */
...@@ -108,7 +110,8 @@ struct f2fs_super_block { ...@@ -108,7 +110,8 @@ struct f2fs_super_block {
__u8 encryption_level; /* versioning level for encryption */ __u8 encryption_level; /* versioning level for encryption */
__u8 encrypt_pw_salt[16]; /* Salt used for string2key algorithm */ __u8 encrypt_pw_salt[16]; /* Salt used for string2key algorithm */
struct f2fs_device devs[MAX_DEVICES]; /* device list */ struct f2fs_device devs[MAX_DEVICES]; /* device list */
__u8 reserved[327]; /* valid reserved region */ __le32 qf_ino[F2FS_MAX_QUOTAS]; /* quota inode numbers */
__u8 reserved[315]; /* valid reserved region */
} __packed; } __packed;
/* /*
...@@ -184,7 +187,8 @@ struct f2fs_extent { ...@@ -184,7 +187,8 @@ struct f2fs_extent {
} __packed; } __packed;
#define F2FS_NAME_LEN 255 #define F2FS_NAME_LEN 255
#define F2FS_INLINE_XATTR_ADDRS 50 /* 200 bytes for inline xattrs */ /* 200 bytes for inline xattrs by default */
#define DEFAULT_INLINE_XATTR_ADDRS 50
#define DEF_ADDRS_PER_INODE 923 /* Address Pointers in an Inode */ #define DEF_ADDRS_PER_INODE 923 /* Address Pointers in an Inode */
#define CUR_ADDRS_PER_INODE(inode) (DEF_ADDRS_PER_INODE - \ #define CUR_ADDRS_PER_INODE(inode) (DEF_ADDRS_PER_INODE - \
get_extra_isize(inode)) get_extra_isize(inode))
...@@ -238,7 +242,7 @@ struct f2fs_inode { ...@@ -238,7 +242,7 @@ struct f2fs_inode {
union { union {
struct { struct {
__le16 i_extra_isize; /* extra inode attribute size */ __le16 i_extra_isize; /* extra inode attribute size */
__le16 i_padding; /* padding */ __le16 i_inline_xattr_size; /* inline xattr size, unit: 4 bytes */
__le32 i_projid; /* project id */ __le32 i_projid; /* project id */
__le32 i_inode_checksum;/* inode meta checksum */ __le32 i_inode_checksum;/* inode meta checksum */
__le32 i_extra_end[0]; /* for attribute size calculation */ __le32 i_extra_end[0]; /* for attribute size calculation */
......
...@@ -137,6 +137,18 @@ TRACE_DEFINE_ENUM(CP_TRIMMED); ...@@ -137,6 +137,18 @@ TRACE_DEFINE_ENUM(CP_TRIMMED);
{ CP_UMOUNT, "Umount" }, \ { CP_UMOUNT, "Umount" }, \
{ CP_TRIMMED, "Trimmed" }) { CP_TRIMMED, "Trimmed" })
#define show_fsync_cpreason(type) \
__print_symbolic(type, \
{ CP_NO_NEEDED, "no needed" }, \
{ CP_NON_REGULAR, "non regular" }, \
{ CP_HARDLINK, "hardlink" }, \
{ CP_SB_NEED_CP, "sb needs cp" }, \
{ CP_WRONG_PINO, "wrong pino" }, \
{ CP_NO_SPC_ROLL, "no space roll forward" }, \
{ CP_NODE_NEED_CP, "node needs cp" }, \
{ CP_FASTBOOT_MODE, "fastboot mode" }, \
{ CP_SPEC_LOG_NUM, "log type is 2" })
struct victim_sel_policy; struct victim_sel_policy;
struct f2fs_map_blocks; struct f2fs_map_blocks;
...@@ -211,14 +223,14 @@ DEFINE_EVENT(f2fs__inode, f2fs_sync_file_enter, ...@@ -211,14 +223,14 @@ DEFINE_EVENT(f2fs__inode, f2fs_sync_file_enter,
TRACE_EVENT(f2fs_sync_file_exit, TRACE_EVENT(f2fs_sync_file_exit,
TP_PROTO(struct inode *inode, int need_cp, int datasync, int ret), TP_PROTO(struct inode *inode, int cp_reason, int datasync, int ret),
TP_ARGS(inode, need_cp, datasync, ret), TP_ARGS(inode, cp_reason, datasync, ret),
TP_STRUCT__entry( TP_STRUCT__entry(
__field(dev_t, dev) __field(dev_t, dev)
__field(ino_t, ino) __field(ino_t, ino)
__field(int, need_cp) __field(int, cp_reason)
__field(int, datasync) __field(int, datasync)
__field(int, ret) __field(int, ret)
), ),
...@@ -226,15 +238,15 @@ TRACE_EVENT(f2fs_sync_file_exit, ...@@ -226,15 +238,15 @@ TRACE_EVENT(f2fs_sync_file_exit,
TP_fast_assign( TP_fast_assign(
__entry->dev = inode->i_sb->s_dev; __entry->dev = inode->i_sb->s_dev;
__entry->ino = inode->i_ino; __entry->ino = inode->i_ino;
__entry->need_cp = need_cp; __entry->cp_reason = cp_reason;
__entry->datasync = datasync; __entry->datasync = datasync;
__entry->ret = ret; __entry->ret = ret;
), ),
TP_printk("dev = (%d,%d), ino = %lu, checkpoint is %s, " TP_printk("dev = (%d,%d), ino = %lu, cp_reason: %s, "
"datasync = %d, ret = %d", "datasync = %d, ret = %d",
show_dev_ino(__entry), show_dev_ino(__entry),
__entry->need_cp ? "needed" : "not needed", show_fsync_cpreason(__entry->cp_reason),
__entry->datasync, __entry->datasync,
__entry->ret) __entry->ret)
); );
...@@ -729,6 +741,91 @@ TRACE_EVENT(f2fs_get_victim, ...@@ -729,6 +741,91 @@ TRACE_EVENT(f2fs_get_victim,
__entry->free) __entry->free)
); );
TRACE_EVENT(f2fs_lookup_start,
TP_PROTO(struct inode *dir, struct dentry *dentry, unsigned int flags),
TP_ARGS(dir, dentry, flags),
TP_STRUCT__entry(
__field(dev_t, dev)
__field(ino_t, ino)
__field(const char *, name)
__field(unsigned int, flags)
),
TP_fast_assign(
__entry->dev = dir->i_sb->s_dev;
__entry->ino = dir->i_ino;
__entry->name = dentry->d_name.name;
__entry->flags = flags;
),
TP_printk("dev = (%d,%d), pino = %lu, name:%s, flags:%u",
show_dev_ino(__entry),
__entry->name,
__entry->flags)
);
TRACE_EVENT(f2fs_lookup_end,
TP_PROTO(struct inode *dir, struct dentry *dentry, nid_t ino,
int err),
TP_ARGS(dir, dentry, ino, err),
TP_STRUCT__entry(
__field(dev_t, dev)
__field(ino_t, ino)
__field(const char *, name)
__field(nid_t, cino)
__field(int, err)
),
TP_fast_assign(
__entry->dev = dir->i_sb->s_dev;
__entry->ino = dir->i_ino;
__entry->name = dentry->d_name.name;
__entry->cino = ino;
__entry->err = err;
),
TP_printk("dev = (%d,%d), pino = %lu, name:%s, ino:%u, err:%d",
show_dev_ino(__entry),
__entry->name,
__entry->cino,
__entry->err)
);
TRACE_EVENT(f2fs_readdir,
TP_PROTO(struct inode *dir, loff_t start_pos, loff_t end_pos, int err),
TP_ARGS(dir, start_pos, end_pos, err),
TP_STRUCT__entry(
__field(dev_t, dev)
__field(ino_t, ino)
__field(loff_t, start)
__field(loff_t, end)
__field(int, err)
),
TP_fast_assign(
__entry->dev = dir->i_sb->s_dev;
__entry->ino = dir->i_ino;
__entry->start = start_pos;
__entry->end = end_pos;
__entry->err = err;
),
TP_printk("dev = (%d,%d), ino = %lu, start_pos:%llu, end_pos:%llu, err:%d",
show_dev_ino(__entry),
__entry->start,
__entry->end,
__entry->err)
);
TRACE_EVENT(f2fs_fallocate, TRACE_EVENT(f2fs_fallocate,
TP_PROTO(struct inode *inode, int mode, TP_PROTO(struct inode *inode, int mode,
...@@ -1287,6 +1384,13 @@ DEFINE_EVENT(f2fs_discard, f2fs_issue_discard, ...@@ -1287,6 +1384,13 @@ DEFINE_EVENT(f2fs_discard, f2fs_issue_discard,
TP_ARGS(dev, blkstart, blklen) TP_ARGS(dev, blkstart, blklen)
); );
DEFINE_EVENT(f2fs_discard, f2fs_remove_discard,
TP_PROTO(struct block_device *dev, block_t blkstart, block_t blklen),
TP_ARGS(dev, blkstart, blklen)
);
TRACE_EVENT(f2fs_issue_reset_zone, TRACE_EVENT(f2fs_issue_reset_zone,
TP_PROTO(struct block_device *dev, block_t blkstart), TP_PROTO(struct block_device *dev, block_t blkstart),
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment