mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-11-25 10:40:53 +07:00
f2fs updates for v3.13
This patch-set includes the following major enhancement patches. o add a sysfs to control reclaiming free segments o enhance the f2fs global lock procedures o enhance the victim selection flow o wait for selected node blocks during fsync o add some tracepoints o add a config to remove abundant BUG_ONs The other bug fixes are as follows. o fix deadlock on acl operations o fix some bugs with respect to orphan inodes And, there are a bunch of cleanups. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.11 (GNU/Linux) iQIcBAABAgAGBQJSgMZ/AAoJEEAUqH6CSFDSsL4P/Ri6GZyy5F0DGjAJElX825gO gthRZ1uq1OAXUYDOEy150CsFgIiWeu2MxiOV15UnmX893a5cXrf32afoa/Cqx8GG FVEYc5+dDdogezQCW6XSatQ4s7cDQDymyT2Mky4MJyAxhpYtvbpcyVI/OWdVcTwh pqdJfsfuOikbOOL6VU2B5dDKwjc+6lgntdv/eICzNCH9NqHv8kxmm+h3NfaqUVrW pK1irqsXrktcwLIrOH0c5ZpPcKPghJuw37oFpEw8MxYbTnpdrbLq4BKE/fRh8Fhf R+sQgEoWZriE1SISHmYjWdt87hnFCk3wysl61Z/zkOxnYKebRBrjEiudzxAHDIGY +I71ovpVCWe0uljdiTBpLQ/iN4p2fRMLjn7j1IsMzoG9yfVFduMaY70m1AOZI/7z 03QRpkmiRi7F8GYTSlPefsUUAnMYVDO6DzsyfHdxa8v+4UvWhSE4380L9DttNbCr 2/+NGRZ4kga6GSsMhdn2Bnm6i3TkMDJosu4USkv4qGR1SH1+S5dodwxfQdonPUZg 380kPkV7/gBYaMBSdrQFds3lh7g431gfYEfGSWt3vA14fFIWP7nIFpVIPGMM6/Sd GFe6gqZ2JLatqJnQNwEjPsBPPsiCAt6exbg86fTCvrS+oyQTiv44FNOWbz7iTrxw 5nZQfQHSMhKtux7rpM/N =Grs1 -----END PGP SIGNATURE----- Merge tag 'for-f2fs-3.13' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs Pull f2fs updates from Jaegeuk Kim: "This patch-set includes the following major enhancement patches. - add a sysfs to control reclaiming free segments - enhance the f2fs global lock procedures - enhance the victim selection flow - wait for selected node blocks during fsync - add some tracepoints - add a config to remove abundant BUG_ONs The other bug fixes are as follows. - fix deadlock on acl operations - fix some bugs with respect to orphan inodes And, there are a bunch of cleanups" * tag 'for-f2fs-3.13' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs: (42 commits) f2fs: issue more large discard command f2fs: fix memory leak after kobject init failed in fill_super f2fs: cleanup waiting routine for writeback pages in cp f2fs: avoid to use a NULL point in destroy_segment_manager f2fs: remove unnecessary TestClearPageError when wait pages writeback f2fs: update f2fs document f2fs: avoid to wait all the node blocks during fsync f2fs: check all ones or zeros bitmap with bitops for better mount performance f2fs: change the method of calculating the number summary blocks f2fs: fix calculating incorrect free size when update xattr in __f2fs_setxattr f2fs: add an option to avoid unnecessary BUG_ONs f2fs: introduce CONFIG_F2FS_CHECK_FS for BUG_ON control f2fs: fix a deadlock during init_acl procedure f2fs: clean up acl flow for better readability f2fs: remove unnecessary segment bitmap updates f2fs: add tracepoint for vm_page_mkwrite f2fs: add tracepoint for set_page_dirty f2fs: remove redundant set_page_dirty from write_compacted_summaries f2fs: add reclaiming control by sysfs f2fs: introduce f2fs_balance_fs_bg for some background jobs ...
This commit is contained in:
commit
dd1d1399f2
@ -119,6 +119,7 @@ active_logs=%u Support configuring the number of active logs. In the
|
||||
Default number is 6.
|
||||
disable_ext_identify Disable the extension list configured by mkfs, so f2fs
|
||||
does not aware of cold files such as media files.
|
||||
inline_xattr Enable the inline xattrs feature.
|
||||
|
||||
================================================================================
|
||||
DEBUGFS ENTRIES
|
||||
@ -164,6 +165,12 @@ Files in /sys/fs/f2fs/<devname>
|
||||
gc_idle = 1 will select the Cost Benefit approach
|
||||
& setting gc_idle = 2 will select the greedy aproach.
|
||||
|
||||
reclaim_segments This parameter controls the number of prefree
|
||||
segments to be reclaimed. If the number of prefree
|
||||
segments is larger than this number, f2fs tries to
|
||||
conduct checkpoint to reclaim the prefree segments
|
||||
to free segments. By default, 100 segments, 200MB.
|
||||
|
||||
================================================================================
|
||||
USAGE
|
||||
================================================================================
|
||||
|
@ -63,3 +63,11 @@ config F2FS_FS_SECURITY
|
||||
the extended attribute support in advance.
|
||||
|
||||
If you are not using a security module, say N.
|
||||
|
||||
config F2FS_CHECK_FS
|
||||
bool "F2FS consistency checking feature"
|
||||
depends on F2FS_FS
|
||||
help
|
||||
Enables BUG_ONs which check the file system consistency in runtime.
|
||||
|
||||
If you want to improve the performance, say N.
|
||||
|
@ -205,7 +205,8 @@ struct posix_acl *f2fs_get_acl(struct inode *inode, int type)
|
||||
return acl;
|
||||
}
|
||||
|
||||
static int f2fs_set_acl(struct inode *inode, int type, struct posix_acl *acl)
|
||||
static int f2fs_set_acl(struct inode *inode, int type,
|
||||
struct posix_acl *acl, struct page *ipage)
|
||||
{
|
||||
struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
|
||||
struct f2fs_inode_info *fi = F2FS_I(inode);
|
||||
@ -250,7 +251,7 @@ static int f2fs_set_acl(struct inode *inode, int type, struct posix_acl *acl)
|
||||
}
|
||||
}
|
||||
|
||||
error = f2fs_setxattr(inode, name_index, "", value, size, NULL);
|
||||
error = f2fs_setxattr(inode, name_index, "", value, size, ipage);
|
||||
|
||||
kfree(value);
|
||||
if (!error)
|
||||
@ -260,10 +261,10 @@ static int f2fs_set_acl(struct inode *inode, int type, struct posix_acl *acl)
|
||||
return error;
|
||||
}
|
||||
|
||||
int f2fs_init_acl(struct inode *inode, struct inode *dir)
|
||||
int f2fs_init_acl(struct inode *inode, struct inode *dir, struct page *ipage)
|
||||
{
|
||||
struct posix_acl *acl = NULL;
|
||||
struct f2fs_sb_info *sbi = F2FS_SB(dir->i_sb);
|
||||
struct posix_acl *acl = NULL;
|
||||
int error = 0;
|
||||
|
||||
if (!S_ISLNK(inode->i_mode)) {
|
||||
@ -276,19 +277,19 @@ int f2fs_init_acl(struct inode *inode, struct inode *dir)
|
||||
inode->i_mode &= ~current_umask();
|
||||
}
|
||||
|
||||
if (test_opt(sbi, POSIX_ACL) && acl) {
|
||||
if (!test_opt(sbi, POSIX_ACL) || !acl)
|
||||
goto cleanup;
|
||||
|
||||
if (S_ISDIR(inode->i_mode)) {
|
||||
error = f2fs_set_acl(inode, ACL_TYPE_DEFAULT, acl);
|
||||
if (error)
|
||||
goto cleanup;
|
||||
}
|
||||
error = posix_acl_create(&acl, GFP_KERNEL, &inode->i_mode);
|
||||
if (error < 0)
|
||||
return error;
|
||||
if (error > 0)
|
||||
error = f2fs_set_acl(inode, ACL_TYPE_ACCESS, acl);
|
||||
if (S_ISDIR(inode->i_mode)) {
|
||||
error = f2fs_set_acl(inode, ACL_TYPE_DEFAULT, acl, ipage);
|
||||
if (error)
|
||||
goto cleanup;
|
||||
}
|
||||
error = posix_acl_create(&acl, GFP_KERNEL, &inode->i_mode);
|
||||
if (error < 0)
|
||||
return error;
|
||||
if (error > 0)
|
||||
error = f2fs_set_acl(inode, ACL_TYPE_ACCESS, acl, ipage);
|
||||
cleanup:
|
||||
posix_acl_release(acl);
|
||||
return error;
|
||||
@ -313,7 +314,8 @@ int f2fs_acl_chmod(struct inode *inode)
|
||||
error = posix_acl_chmod(&acl, GFP_KERNEL, mode);
|
||||
if (error)
|
||||
return error;
|
||||
error = f2fs_set_acl(inode, ACL_TYPE_ACCESS, acl);
|
||||
|
||||
error = f2fs_set_acl(inode, ACL_TYPE_ACCESS, acl, NULL);
|
||||
posix_acl_release(acl);
|
||||
return error;
|
||||
}
|
||||
@ -388,7 +390,7 @@ static int f2fs_xattr_set_acl(struct dentry *dentry, const char *name,
|
||||
acl = NULL;
|
||||
}
|
||||
|
||||
error = f2fs_set_acl(inode, type, acl);
|
||||
error = f2fs_set_acl(inode, type, acl, NULL);
|
||||
|
||||
release_and_out:
|
||||
posix_acl_release(acl);
|
||||
|
@ -36,9 +36,9 @@ struct f2fs_acl_header {
|
||||
|
||||
#ifdef CONFIG_F2FS_FS_POSIX_ACL
|
||||
|
||||
extern struct posix_acl *f2fs_get_acl(struct inode *inode, int type);
|
||||
extern int f2fs_acl_chmod(struct inode *inode);
|
||||
extern int f2fs_init_acl(struct inode *inode, struct inode *dir);
|
||||
extern struct posix_acl *f2fs_get_acl(struct inode *, int);
|
||||
extern int f2fs_acl_chmod(struct inode *);
|
||||
extern int f2fs_init_acl(struct inode *, struct inode *, struct page *);
|
||||
#else
|
||||
#define f2fs_check_acl NULL
|
||||
#define f2fs_get_acl NULL
|
||||
@ -49,7 +49,8 @@ static inline int f2fs_acl_chmod(struct inode *inode)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int f2fs_init_acl(struct inode *inode, struct inode *dir)
|
||||
static inline int f2fs_init_acl(struct inode *inode, struct inode *dir,
|
||||
struct page *page)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
@ -81,7 +81,7 @@ static int f2fs_write_meta_page(struct page *page,
|
||||
struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
|
||||
|
||||
/* Should not write any meta pages, if any IO error was occurred */
|
||||
if (wbc->for_reclaim ||
|
||||
if (wbc->for_reclaim || sbi->por_doing ||
|
||||
is_set_ckpt_flags(F2FS_CKPT(sbi), CP_ERROR_FLAG)) {
|
||||
dec_page_count(sbi, F2FS_DIRTY_META);
|
||||
wbc->pages_skipped++;
|
||||
@ -142,8 +142,8 @@ long sync_meta_pages(struct f2fs_sb_info *sbi, enum page_type type,
|
||||
for (i = 0; i < nr_pages; i++) {
|
||||
struct page *page = pvec.pages[i];
|
||||
lock_page(page);
|
||||
BUG_ON(page->mapping != mapping);
|
||||
BUG_ON(!PageDirty(page));
|
||||
f2fs_bug_on(page->mapping != mapping);
|
||||
f2fs_bug_on(!PageDirty(page));
|
||||
clear_page_dirty_for_io(page);
|
||||
if (f2fs_write_meta_page(page, &wbc)) {
|
||||
unlock_page(page);
|
||||
@ -167,6 +167,8 @@ static int f2fs_set_meta_page_dirty(struct page *page)
|
||||
struct address_space *mapping = page->mapping;
|
||||
struct f2fs_sb_info *sbi = F2FS_SB(mapping->host->i_sb);
|
||||
|
||||
trace_f2fs_set_page_dirty(page, META);
|
||||
|
||||
SetPageUptodate(page);
|
||||
if (!PageDirty(page)) {
|
||||
__set_page_dirty_nobuffers(page);
|
||||
@ -206,6 +208,7 @@ int acquire_orphan_inode(struct f2fs_sb_info *sbi)
|
||||
void release_orphan_inode(struct f2fs_sb_info *sbi)
|
||||
{
|
||||
mutex_lock(&sbi->orphan_inode_mutex);
|
||||
f2fs_bug_on(sbi->n_orphans == 0);
|
||||
sbi->n_orphans--;
|
||||
mutex_unlock(&sbi->orphan_inode_mutex);
|
||||
}
|
||||
@ -225,12 +228,8 @@ void add_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino)
|
||||
break;
|
||||
orphan = NULL;
|
||||
}
|
||||
retry:
|
||||
new = kmem_cache_alloc(orphan_entry_slab, GFP_ATOMIC);
|
||||
if (!new) {
|
||||
cond_resched();
|
||||
goto retry;
|
||||
}
|
||||
|
||||
new = f2fs_kmem_cache_alloc(orphan_entry_slab, GFP_ATOMIC);
|
||||
new->ino = ino;
|
||||
|
||||
/* add new_oentry into list which is sorted by inode number */
|
||||
@ -253,6 +252,7 @@ void remove_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino)
|
||||
if (orphan->ino == ino) {
|
||||
list_del(&orphan->list);
|
||||
kmem_cache_free(orphan_entry_slab, orphan);
|
||||
f2fs_bug_on(sbi->n_orphans == 0);
|
||||
sbi->n_orphans--;
|
||||
break;
|
||||
}
|
||||
@ -263,7 +263,7 @@ void remove_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino)
|
||||
static void recover_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino)
|
||||
{
|
||||
struct inode *inode = f2fs_iget(sbi->sb, ino);
|
||||
BUG_ON(IS_ERR(inode));
|
||||
f2fs_bug_on(IS_ERR(inode));
|
||||
clear_nlink(inode);
|
||||
|
||||
/* truncate all the data during iput */
|
||||
@ -277,7 +277,7 @@ int recover_orphan_inodes(struct f2fs_sb_info *sbi)
|
||||
if (!is_set_ckpt_flags(F2FS_CKPT(sbi), CP_ORPHAN_PRESENT_FLAG))
|
||||
return 0;
|
||||
|
||||
sbi->por_doing = 1;
|
||||
sbi->por_doing = true;
|
||||
start_blk = __start_cp_addr(sbi) + 1;
|
||||
orphan_blkaddr = __start_sum_addr(sbi) - 1;
|
||||
|
||||
@ -294,7 +294,7 @@ int recover_orphan_inodes(struct f2fs_sb_info *sbi)
|
||||
}
|
||||
/* clear Orphan Flag */
|
||||
clear_ckpt_flags(F2FS_CKPT(sbi), CP_ORPHAN_PRESENT_FLAG);
|
||||
sbi->por_doing = 0;
|
||||
sbi->por_doing = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -469,9 +469,7 @@ static int __add_dirty_inode(struct inode *inode, struct dir_inode_entry *new)
|
||||
return -EEXIST;
|
||||
}
|
||||
list_add_tail(&new->list, head);
|
||||
#ifdef CONFIG_F2FS_STAT_FS
|
||||
sbi->n_dirty_dirs++;
|
||||
#endif
|
||||
stat_inc_dirty_dir(sbi);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -482,12 +480,8 @@ void set_dirty_dir_page(struct inode *inode, struct page *page)
|
||||
|
||||
if (!S_ISDIR(inode->i_mode))
|
||||
return;
|
||||
retry:
|
||||
new = kmem_cache_alloc(inode_entry_slab, GFP_NOFS);
|
||||
if (!new) {
|
||||
cond_resched();
|
||||
goto retry;
|
||||
}
|
||||
|
||||
new = f2fs_kmem_cache_alloc(inode_entry_slab, GFP_NOFS);
|
||||
new->inode = inode;
|
||||
INIT_LIST_HEAD(&new->list);
|
||||
|
||||
@ -504,13 +498,9 @@ void set_dirty_dir_page(struct inode *inode, struct page *page)
|
||||
void add_dirty_dir_inode(struct inode *inode)
|
||||
{
|
||||
struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
|
||||
struct dir_inode_entry *new;
|
||||
retry:
|
||||
new = kmem_cache_alloc(inode_entry_slab, GFP_NOFS);
|
||||
if (!new) {
|
||||
cond_resched();
|
||||
goto retry;
|
||||
}
|
||||
struct dir_inode_entry *new =
|
||||
f2fs_kmem_cache_alloc(inode_entry_slab, GFP_NOFS);
|
||||
|
||||
new->inode = inode;
|
||||
INIT_LIST_HEAD(&new->list);
|
||||
|
||||
@ -541,9 +531,7 @@ void remove_dirty_dir_inode(struct inode *inode)
|
||||
if (entry->inode == inode) {
|
||||
list_del(&entry->list);
|
||||
kmem_cache_free(inode_entry_slab, entry);
|
||||
#ifdef CONFIG_F2FS_STAT_FS
|
||||
sbi->n_dirty_dirs--;
|
||||
#endif
|
||||
stat_dec_dirty_dir(sbi);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -617,11 +605,10 @@ static void block_operations(struct f2fs_sb_info *sbi)
|
||||
blk_start_plug(&plug);
|
||||
|
||||
retry_flush_dents:
|
||||
mutex_lock_all(sbi);
|
||||
|
||||
f2fs_lock_all(sbi);
|
||||
/* write all the dirty dentry pages */
|
||||
if (get_pages(sbi, F2FS_DIRTY_DENTS)) {
|
||||
mutex_unlock_all(sbi);
|
||||
f2fs_unlock_all(sbi);
|
||||
sync_dirty_dir_inodes(sbi);
|
||||
goto retry_flush_dents;
|
||||
}
|
||||
@ -644,7 +631,22 @@ static void block_operations(struct f2fs_sb_info *sbi)
|
||||
static void unblock_operations(struct f2fs_sb_info *sbi)
|
||||
{
|
||||
mutex_unlock(&sbi->node_write);
|
||||
mutex_unlock_all(sbi);
|
||||
f2fs_unlock_all(sbi);
|
||||
}
|
||||
|
||||
static void wait_on_all_pages_writeback(struct f2fs_sb_info *sbi)
|
||||
{
|
||||
DEFINE_WAIT(wait);
|
||||
|
||||
for (;;) {
|
||||
prepare_to_wait(&sbi->cp_wait, &wait, TASK_UNINTERRUPTIBLE);
|
||||
|
||||
if (!get_pages(sbi, F2FS_WRITEBACK))
|
||||
break;
|
||||
|
||||
io_schedule();
|
||||
}
|
||||
finish_wait(&sbi->cp_wait, &wait);
|
||||
}
|
||||
|
||||
static void do_checkpoint(struct f2fs_sb_info *sbi, bool is_umount)
|
||||
@ -756,8 +758,7 @@ static void do_checkpoint(struct f2fs_sb_info *sbi, bool is_umount)
|
||||
f2fs_put_page(cp_page, 1);
|
||||
|
||||
/* wait for previous submitted node/meta pages writeback */
|
||||
while (get_pages(sbi, F2FS_WRITEBACK))
|
||||
congestion_wait(BLK_RW_ASYNC, HZ / 50);
|
||||
wait_on_all_pages_writeback(sbi);
|
||||
|
||||
filemap_fdatawait_range(sbi->node_inode->i_mapping, 0, LONG_MAX);
|
||||
filemap_fdatawait_range(sbi->meta_inode->i_mapping, 0, LONG_MAX);
|
||||
|
@ -68,9 +68,6 @@ static int check_extent_cache(struct inode *inode, pgoff_t pgofs,
|
||||
struct buffer_head *bh_result)
|
||||
{
|
||||
struct f2fs_inode_info *fi = F2FS_I(inode);
|
||||
#ifdef CONFIG_F2FS_STAT_FS
|
||||
struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
|
||||
#endif
|
||||
pgoff_t start_fofs, end_fofs;
|
||||
block_t start_blkaddr;
|
||||
|
||||
@ -80,9 +77,8 @@ static int check_extent_cache(struct inode *inode, pgoff_t pgofs,
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_F2FS_STAT_FS
|
||||
sbi->total_hit_ext++;
|
||||
#endif
|
||||
stat_inc_total_hit(inode->i_sb);
|
||||
|
||||
start_fofs = fi->ext.fofs;
|
||||
end_fofs = fi->ext.fofs + fi->ext.len - 1;
|
||||
start_blkaddr = fi->ext.blk_addr;
|
||||
@ -100,9 +96,7 @@ static int check_extent_cache(struct inode *inode, pgoff_t pgofs,
|
||||
else
|
||||
bh_result->b_size = UINT_MAX;
|
||||
|
||||
#ifdef CONFIG_F2FS_STAT_FS
|
||||
sbi->read_hit_ext++;
|
||||
#endif
|
||||
stat_inc_read_hit(inode->i_sb);
|
||||
read_unlock(&fi->ext.ext_lock);
|
||||
return 1;
|
||||
}
|
||||
@ -116,7 +110,7 @@ void update_extent_cache(block_t blk_addr, struct dnode_of_data *dn)
|
||||
pgoff_t fofs, start_fofs, end_fofs;
|
||||
block_t start_blkaddr, end_blkaddr;
|
||||
|
||||
BUG_ON(blk_addr == NEW_ADDR);
|
||||
f2fs_bug_on(blk_addr == NEW_ADDR);
|
||||
fofs = start_bidx_of_node(ofs_of_node(dn->node_page), fi) +
|
||||
dn->ofs_in_node;
|
||||
|
||||
@ -442,7 +436,7 @@ static int get_data_block_ro(struct inode *inode, sector_t iblock,
|
||||
}
|
||||
|
||||
/* It does not support data allocation */
|
||||
BUG_ON(create);
|
||||
f2fs_bug_on(create);
|
||||
|
||||
if (dn.data_blkaddr != NEW_ADDR && dn.data_blkaddr != NULL_ADDR) {
|
||||
int i;
|
||||
@ -560,9 +554,9 @@ static int f2fs_write_data_page(struct page *page,
|
||||
inode_dec_dirty_dents(inode);
|
||||
err = do_write_data_page(page);
|
||||
} else {
|
||||
int ilock = mutex_lock_op(sbi);
|
||||
f2fs_lock_op(sbi);
|
||||
err = do_write_data_page(page);
|
||||
mutex_unlock_op(sbi, ilock);
|
||||
f2fs_unlock_op(sbi);
|
||||
need_balance_fs = true;
|
||||
}
|
||||
if (err == -ENOENT)
|
||||
@ -641,7 +635,6 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping,
|
||||
pgoff_t index = ((unsigned long long) pos) >> PAGE_CACHE_SHIFT;
|
||||
struct dnode_of_data dn;
|
||||
int err = 0;
|
||||
int ilock;
|
||||
|
||||
f2fs_balance_fs(sbi);
|
||||
repeat:
|
||||
@ -650,7 +643,7 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping,
|
||||
return -ENOMEM;
|
||||
*pagep = page;
|
||||
|
||||
ilock = mutex_lock_op(sbi);
|
||||
f2fs_lock_op(sbi);
|
||||
|
||||
set_new_dnode(&dn, inode, NULL, NULL, 0);
|
||||
err = get_dnode_of_data(&dn, index, ALLOC_NODE);
|
||||
@ -664,7 +657,7 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping,
|
||||
if (err)
|
||||
goto err;
|
||||
|
||||
mutex_unlock_op(sbi, ilock);
|
||||
f2fs_unlock_op(sbi);
|
||||
|
||||
if ((len == PAGE_CACHE_SIZE) || PageUptodate(page))
|
||||
return 0;
|
||||
@ -700,7 +693,7 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping,
|
||||
return 0;
|
||||
|
||||
err:
|
||||
mutex_unlock_op(sbi, ilock);
|
||||
f2fs_unlock_op(sbi);
|
||||
f2fs_put_page(page, 1);
|
||||
return err;
|
||||
}
|
||||
@ -763,6 +756,8 @@ static int f2fs_set_data_page_dirty(struct page *page)
|
||||
struct address_space *mapping = page->mapping;
|
||||
struct inode *inode = mapping->host;
|
||||
|
||||
trace_f2fs_set_page_dirty(page, DATA);
|
||||
|
||||
SetPageUptodate(page);
|
||||
if (!PageDirty(page)) {
|
||||
__set_page_dirty_nobuffers(page);
|
||||
|
@ -139,7 +139,7 @@ static struct f2fs_dir_entry *find_in_level(struct inode *dir,
|
||||
bool room = false;
|
||||
int max_slots = 0;
|
||||
|
||||
BUG_ON(level > MAX_DIR_HASH_DEPTH);
|
||||
f2fs_bug_on(level > MAX_DIR_HASH_DEPTH);
|
||||
|
||||
nbucket = dir_buckets(level);
|
||||
nblock = bucket_blocks(level);
|
||||
@ -346,7 +346,7 @@ static struct page *init_inode_metadata(struct inode *inode,
|
||||
goto error;
|
||||
}
|
||||
|
||||
err = f2fs_init_acl(inode, dir);
|
||||
err = f2fs_init_acl(inode, dir, page);
|
||||
if (err)
|
||||
goto error;
|
||||
|
||||
|
117
fs/f2fs/f2fs.h
117
fs/f2fs/f2fs.h
@ -18,6 +18,13 @@
|
||||
#include <linux/crc32.h>
|
||||
#include <linux/magic.h>
|
||||
#include <linux/kobject.h>
|
||||
#include <linux/sched.h>
|
||||
|
||||
#ifdef CONFIG_F2FS_CHECK_FS
|
||||
#define f2fs_bug_on(condition) BUG_ON(condition)
|
||||
#else
|
||||
#define f2fs_bug_on(condition)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* For mount options
|
||||
@ -298,6 +305,9 @@ struct f2fs_sm_info {
|
||||
unsigned int main_segments; /* # of segments in main area */
|
||||
unsigned int reserved_segments; /* # of reserved segments */
|
||||
unsigned int ovp_segments; /* # of overprovision segments */
|
||||
|
||||
/* a threshold to reclaim prefree segments */
|
||||
unsigned int rec_prefree_segments;
|
||||
};
|
||||
|
||||
/*
|
||||
@ -317,14 +327,6 @@ enum count_type {
|
||||
NR_COUNT_TYPE,
|
||||
};
|
||||
|
||||
/*
|
||||
* Uses as sbi->fs_lock[NR_GLOBAL_LOCKS].
|
||||
* The checkpoint procedure blocks all the locks in this fs_lock array.
|
||||
* Some FS operations grab free locks, and if there is no free lock,
|
||||
* then wait to grab a lock in a round-robin manner.
|
||||
*/
|
||||
#define NR_GLOBAL_LOCKS 8
|
||||
|
||||
/*
|
||||
* The below are the page types of bios used in submti_bio().
|
||||
* The available types are:
|
||||
@ -365,12 +367,12 @@ struct f2fs_sb_info {
|
||||
struct f2fs_checkpoint *ckpt; /* raw checkpoint pointer */
|
||||
struct inode *meta_inode; /* cache meta blocks */
|
||||
struct mutex cp_mutex; /* checkpoint procedure lock */
|
||||
struct mutex fs_lock[NR_GLOBAL_LOCKS]; /* blocking FS operations */
|
||||
struct rw_semaphore cp_rwsem; /* blocking FS operations */
|
||||
struct mutex node_write; /* locking node writes */
|
||||
struct mutex writepages; /* mutex for writepages() */
|
||||
unsigned char next_lock_num; /* round-robin global locks */
|
||||
int por_doing; /* recovery is doing or not */
|
||||
int on_build_free_nids; /* build_free_nids is doing */
|
||||
bool por_doing; /* recovery is doing or not */
|
||||
bool on_build_free_nids; /* build_free_nids is doing */
|
||||
wait_queue_head_t cp_wait;
|
||||
|
||||
/* for orphan inode management */
|
||||
struct list_head orphan_inode_list; /* orphan inode list */
|
||||
@ -520,48 +522,24 @@ static inline void clear_ckpt_flags(struct f2fs_checkpoint *cp, unsigned int f)
|
||||
cp->ckpt_flags = cpu_to_le32(ckpt_flags);
|
||||
}
|
||||
|
||||
static inline void mutex_lock_all(struct f2fs_sb_info *sbi)
|
||||
static inline void f2fs_lock_op(struct f2fs_sb_info *sbi)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NR_GLOBAL_LOCKS; i++) {
|
||||
/*
|
||||
* This is the only time we take multiple fs_lock[]
|
||||
* instances; the order is immaterial since we
|
||||
* always hold cp_mutex, which serializes multiple
|
||||
* such operations.
|
||||
*/
|
||||
mutex_lock_nest_lock(&sbi->fs_lock[i], &sbi->cp_mutex);
|
||||
}
|
||||
down_read(&sbi->cp_rwsem);
|
||||
}
|
||||
|
||||
static inline void mutex_unlock_all(struct f2fs_sb_info *sbi)
|
||||
static inline void f2fs_unlock_op(struct f2fs_sb_info *sbi)
|
||||
{
|
||||
int i = 0;
|
||||
for (; i < NR_GLOBAL_LOCKS; i++)
|
||||
mutex_unlock(&sbi->fs_lock[i]);
|
||||
up_read(&sbi->cp_rwsem);
|
||||
}
|
||||
|
||||
static inline int mutex_lock_op(struct f2fs_sb_info *sbi)
|
||||
static inline void f2fs_lock_all(struct f2fs_sb_info *sbi)
|
||||
{
|
||||
unsigned char next_lock = sbi->next_lock_num % NR_GLOBAL_LOCKS;
|
||||
int i = 0;
|
||||
|
||||
for (; i < NR_GLOBAL_LOCKS; i++)
|
||||
if (mutex_trylock(&sbi->fs_lock[i]))
|
||||
return i;
|
||||
|
||||
mutex_lock(&sbi->fs_lock[next_lock]);
|
||||
sbi->next_lock_num++;
|
||||
return next_lock;
|
||||
down_write_nest_lock(&sbi->cp_rwsem, &sbi->cp_mutex);
|
||||
}
|
||||
|
||||
static inline void mutex_unlock_op(struct f2fs_sb_info *sbi, int ilock)
|
||||
static inline void f2fs_unlock_all(struct f2fs_sb_info *sbi)
|
||||
{
|
||||
if (ilock < 0)
|
||||
return;
|
||||
BUG_ON(ilock >= NR_GLOBAL_LOCKS);
|
||||
mutex_unlock(&sbi->fs_lock[ilock]);
|
||||
up_write(&sbi->cp_rwsem);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -612,8 +590,8 @@ static inline int dec_valid_block_count(struct f2fs_sb_info *sbi,
|
||||
blkcnt_t count)
|
||||
{
|
||||
spin_lock(&sbi->stat_lock);
|
||||
BUG_ON(sbi->total_valid_block_count < (block_t) count);
|
||||
BUG_ON(inode->i_blocks < count);
|
||||
f2fs_bug_on(sbi->total_valid_block_count < (block_t) count);
|
||||
f2fs_bug_on(inode->i_blocks < count);
|
||||
inode->i_blocks -= count;
|
||||
sbi->total_valid_block_count -= (block_t)count;
|
||||
spin_unlock(&sbi->stat_lock);
|
||||
@ -745,9 +723,9 @@ static inline void dec_valid_node_count(struct f2fs_sb_info *sbi,
|
||||
{
|
||||
spin_lock(&sbi->stat_lock);
|
||||
|
||||
BUG_ON(sbi->total_valid_block_count < count);
|
||||
BUG_ON(sbi->total_valid_node_count < count);
|
||||
BUG_ON(inode->i_blocks < count);
|
||||
f2fs_bug_on(sbi->total_valid_block_count < count);
|
||||
f2fs_bug_on(sbi->total_valid_node_count < count);
|
||||
f2fs_bug_on(inode->i_blocks < count);
|
||||
|
||||
inode->i_blocks -= count;
|
||||
sbi->total_valid_node_count -= count;
|
||||
@ -768,7 +746,7 @@ static inline unsigned int valid_node_count(struct f2fs_sb_info *sbi)
|
||||
static inline void inc_valid_inode_count(struct f2fs_sb_info *sbi)
|
||||
{
|
||||
spin_lock(&sbi->stat_lock);
|
||||
BUG_ON(sbi->total_valid_inode_count == sbi->total_node_count);
|
||||
f2fs_bug_on(sbi->total_valid_inode_count == sbi->total_node_count);
|
||||
sbi->total_valid_inode_count++;
|
||||
spin_unlock(&sbi->stat_lock);
|
||||
}
|
||||
@ -776,7 +754,7 @@ static inline void inc_valid_inode_count(struct f2fs_sb_info *sbi)
|
||||
static inline int dec_valid_inode_count(struct f2fs_sb_info *sbi)
|
||||
{
|
||||
spin_lock(&sbi->stat_lock);
|
||||
BUG_ON(!sbi->total_valid_inode_count);
|
||||
f2fs_bug_on(!sbi->total_valid_inode_count);
|
||||
sbi->total_valid_inode_count--;
|
||||
spin_unlock(&sbi->stat_lock);
|
||||
return 0;
|
||||
@ -797,7 +775,7 @@ static inline void f2fs_put_page(struct page *page, int unlock)
|
||||
return;
|
||||
|
||||
if (unlock) {
|
||||
BUG_ON(!PageLocked(page));
|
||||
f2fs_bug_on(!PageLocked(page));
|
||||
unlock_page(page);
|
||||
}
|
||||
page_cache_release(page);
|
||||
@ -819,6 +797,20 @@ static inline struct kmem_cache *f2fs_kmem_cache_create(const char *name,
|
||||
return kmem_cache_create(name, size, 0, SLAB_RECLAIM_ACCOUNT, ctor);
|
||||
}
|
||||
|
||||
static inline void *f2fs_kmem_cache_alloc(struct kmem_cache *cachep,
|
||||
gfp_t flags)
|
||||
{
|
||||
void *entry;
|
||||
retry:
|
||||
entry = kmem_cache_alloc(cachep, flags);
|
||||
if (!entry) {
|
||||
cond_resched();
|
||||
goto retry;
|
||||
}
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
#define RAW_IS_INODE(p) ((p)->footer.nid == (p)->footer.ino)
|
||||
|
||||
static inline bool IS_INODE(struct page *page)
|
||||
@ -979,6 +971,7 @@ long f2fs_compat_ioctl(struct file *, unsigned int, unsigned long);
|
||||
*/
|
||||
void f2fs_set_inode_flags(struct inode *);
|
||||
struct inode *f2fs_iget(struct super_block *, unsigned long);
|
||||
int try_to_free_nats(struct f2fs_sb_info *, int);
|
||||
void update_inode(struct inode *, struct page *);
|
||||
int update_inode_page(struct inode *);
|
||||
int f2fs_write_inode(struct inode *, struct writeback_control *);
|
||||
@ -1033,6 +1026,7 @@ void get_node_info(struct f2fs_sb_info *, nid_t, struct node_info *);
|
||||
int get_dnode_of_data(struct dnode_of_data *, pgoff_t, int);
|
||||
int truncate_inode_blocks(struct inode *, pgoff_t);
|
||||
int truncate_xattr_node(struct inode *, struct page *);
|
||||
int wait_on_node_pages_writeback(struct f2fs_sb_info *, nid_t);
|
||||
int remove_inode_page(struct inode *);
|
||||
struct page *new_inode_page(struct inode *, const struct qstr *);
|
||||
struct page *new_node_page(struct dnode_of_data *, unsigned int, struct page *);
|
||||
@ -1059,6 +1053,7 @@ void destroy_node_manager_caches(void);
|
||||
* segment.c
|
||||
*/
|
||||
void f2fs_balance_fs(struct f2fs_sb_info *);
|
||||
void f2fs_balance_fs_bg(struct f2fs_sb_info *);
|
||||
void invalidate_blocks(struct f2fs_sb_info *, block_t);
|
||||
void clear_prefree_segments(struct f2fs_sb_info *);
|
||||
int npages_for_summary_flush(struct f2fs_sb_info *);
|
||||
@ -1172,7 +1167,16 @@ static inline struct f2fs_stat_info *F2FS_STAT(struct f2fs_sb_info *sbi)
|
||||
return (struct f2fs_stat_info*)sbi->stat_info;
|
||||
}
|
||||
|
||||
#define stat_inc_call_count(si) ((si)->call_count++)
|
||||
#define stat_inc_call_count(si) ((si)->call_count++)
|
||||
#define stat_inc_bggc_count(sbi) ((sbi)->bg_gc++)
|
||||
#define stat_inc_dirty_dir(sbi) ((sbi)->n_dirty_dirs++)
|
||||
#define stat_dec_dirty_dir(sbi) ((sbi)->n_dirty_dirs--)
|
||||
#define stat_inc_total_hit(sb) ((F2FS_SB(sb))->total_hit_ext++)
|
||||
#define stat_inc_read_hit(sb) ((F2FS_SB(sb))->read_hit_ext++)
|
||||
#define stat_inc_seg_type(sbi, curseg) \
|
||||
((sbi)->segment_count[(curseg)->alloc_type]++)
|
||||
#define stat_inc_block_count(sbi, curseg) \
|
||||
((sbi)->block_count[(curseg)->alloc_type]++)
|
||||
|
||||
#define stat_inc_seg_count(sbi, type) \
|
||||
do { \
|
||||
@ -1207,6 +1211,13 @@ void __init f2fs_create_root_stats(void);
|
||||
void f2fs_destroy_root_stats(void);
|
||||
#else
|
||||
#define stat_inc_call_count(si)
|
||||
#define stat_inc_bggc_count(si)
|
||||
#define stat_inc_dirty_dir(sbi)
|
||||
#define stat_dec_dirty_dir(sbi)
|
||||
#define stat_inc_total_hit(sb)
|
||||
#define stat_inc_read_hit(sb)
|
||||
#define stat_inc_seg_type(sbi, curseg)
|
||||
#define stat_inc_block_count(sbi, curseg)
|
||||
#define stat_inc_seg_count(si, type)
|
||||
#define stat_inc_tot_blk_count(si, blks)
|
||||
#define stat_inc_data_blk_count(si, blks)
|
||||
|
@ -35,18 +35,18 @@ static int f2fs_vm_page_mkwrite(struct vm_area_struct *vma,
|
||||
struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
|
||||
block_t old_blk_addr;
|
||||
struct dnode_of_data dn;
|
||||
int err, ilock;
|
||||
int err;
|
||||
|
||||
f2fs_balance_fs(sbi);
|
||||
|
||||
sb_start_pagefault(inode->i_sb);
|
||||
|
||||
/* block allocation */
|
||||
ilock = mutex_lock_op(sbi);
|
||||
f2fs_lock_op(sbi);
|
||||
set_new_dnode(&dn, inode, NULL, NULL, 0);
|
||||
err = get_dnode_of_data(&dn, page->index, ALLOC_NODE);
|
||||
if (err) {
|
||||
mutex_unlock_op(sbi, ilock);
|
||||
f2fs_unlock_op(sbi);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -56,12 +56,12 @@ static int f2fs_vm_page_mkwrite(struct vm_area_struct *vma,
|
||||
err = reserve_new_block(&dn);
|
||||
if (err) {
|
||||
f2fs_put_dnode(&dn);
|
||||
mutex_unlock_op(sbi, ilock);
|
||||
f2fs_unlock_op(sbi);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
f2fs_put_dnode(&dn);
|
||||
mutex_unlock_op(sbi, ilock);
|
||||
f2fs_unlock_op(sbi);
|
||||
|
||||
file_update_time(vma->vm_file);
|
||||
lock_page(page);
|
||||
@ -88,6 +88,7 @@ static int f2fs_vm_page_mkwrite(struct vm_area_struct *vma,
|
||||
set_page_dirty(page);
|
||||
SetPageUptodate(page);
|
||||
|
||||
trace_f2fs_vm_page_mkwrite(page, DATA);
|
||||
mapped:
|
||||
/* fill the page */
|
||||
wait_on_page_writeback(page);
|
||||
@ -188,8 +189,9 @@ int f2fs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
filemap_fdatawait_range(sbi->node_inode->i_mapping,
|
||||
0, LONG_MAX);
|
||||
ret = wait_on_node_pages_writeback(sbi, inode->i_ino);
|
||||
if (ret)
|
||||
goto out;
|
||||
ret = blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL, NULL);
|
||||
}
|
||||
out:
|
||||
@ -270,7 +272,7 @@ static int truncate_blocks(struct inode *inode, u64 from)
|
||||
unsigned int blocksize = inode->i_sb->s_blocksize;
|
||||
struct dnode_of_data dn;
|
||||
pgoff_t free_from;
|
||||
int count = 0, ilock = -1;
|
||||
int count = 0;
|
||||
int err;
|
||||
|
||||
trace_f2fs_truncate_blocks_enter(inode, from);
|
||||
@ -278,13 +280,13 @@ static int truncate_blocks(struct inode *inode, u64 from)
|
||||
free_from = (pgoff_t)
|
||||
((from + blocksize - 1) >> (sbi->log_blocksize));
|
||||
|
||||
ilock = mutex_lock_op(sbi);
|
||||
f2fs_lock_op(sbi);
|
||||
set_new_dnode(&dn, inode, NULL, NULL, 0);
|
||||
err = get_dnode_of_data(&dn, free_from, LOOKUP_NODE);
|
||||
if (err) {
|
||||
if (err == -ENOENT)
|
||||
goto free_next;
|
||||
mutex_unlock_op(sbi, ilock);
|
||||
f2fs_unlock_op(sbi);
|
||||
trace_f2fs_truncate_blocks_exit(inode, err);
|
||||
return err;
|
||||
}
|
||||
@ -295,7 +297,7 @@ static int truncate_blocks(struct inode *inode, u64 from)
|
||||
count = ADDRS_PER_BLOCK;
|
||||
|
||||
count -= dn.ofs_in_node;
|
||||
BUG_ON(count < 0);
|
||||
f2fs_bug_on(count < 0);
|
||||
|
||||
if (dn.ofs_in_node || IS_INODE(dn.node_page)) {
|
||||
truncate_data_blocks_range(&dn, count);
|
||||
@ -305,7 +307,7 @@ static int truncate_blocks(struct inode *inode, u64 from)
|
||||
f2fs_put_dnode(&dn);
|
||||
free_next:
|
||||
err = truncate_inode_blocks(inode, free_from);
|
||||
mutex_unlock_op(sbi, ilock);
|
||||
f2fs_unlock_op(sbi);
|
||||
|
||||
/* lastly zero out the first data page */
|
||||
truncate_partial_data_page(inode, from);
|
||||
@ -416,16 +418,15 @@ static void fill_zero(struct inode *inode, pgoff_t index,
|
||||
{
|
||||
struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
|
||||
struct page *page;
|
||||
int ilock;
|
||||
|
||||
if (!len)
|
||||
return;
|
||||
|
||||
f2fs_balance_fs(sbi);
|
||||
|
||||
ilock = mutex_lock_op(sbi);
|
||||
f2fs_lock_op(sbi);
|
||||
page = get_new_data_page(inode, NULL, index, false);
|
||||
mutex_unlock_op(sbi, ilock);
|
||||
f2fs_unlock_op(sbi);
|
||||
|
||||
if (!IS_ERR(page)) {
|
||||
wait_on_page_writeback(page);
|
||||
@ -484,7 +485,6 @@ static int punch_hole(struct inode *inode, loff_t offset, loff_t len, int mode)
|
||||
struct address_space *mapping = inode->i_mapping;
|
||||
loff_t blk_start, blk_end;
|
||||
struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
|
||||
int ilock;
|
||||
|
||||
f2fs_balance_fs(sbi);
|
||||
|
||||
@ -493,9 +493,9 @@ static int punch_hole(struct inode *inode, loff_t offset, loff_t len, int mode)
|
||||
truncate_inode_pages_range(mapping, blk_start,
|
||||
blk_end - 1);
|
||||
|
||||
ilock = mutex_lock_op(sbi);
|
||||
f2fs_lock_op(sbi);
|
||||
ret = truncate_hole(inode, pg_start, pg_end);
|
||||
mutex_unlock_op(sbi, ilock);
|
||||
f2fs_unlock_op(sbi);
|
||||
}
|
||||
}
|
||||
|
||||
@ -529,13 +529,12 @@ static int expand_inode_data(struct inode *inode, loff_t offset,
|
||||
|
||||
for (index = pg_start; index <= pg_end; index++) {
|
||||
struct dnode_of_data dn;
|
||||
int ilock;
|
||||
|
||||
ilock = mutex_lock_op(sbi);
|
||||
f2fs_lock_op(sbi);
|
||||
set_new_dnode(&dn, inode, NULL, NULL, 0);
|
||||
ret = get_dnode_of_data(&dn, index, ALLOC_NODE);
|
||||
if (ret) {
|
||||
mutex_unlock_op(sbi, ilock);
|
||||
f2fs_unlock_op(sbi);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -543,12 +542,12 @@ static int expand_inode_data(struct inode *inode, loff_t offset,
|
||||
ret = reserve_new_block(&dn);
|
||||
if (ret) {
|
||||
f2fs_put_dnode(&dn);
|
||||
mutex_unlock_op(sbi, ilock);
|
||||
f2fs_unlock_op(sbi);
|
||||
break;
|
||||
}
|
||||
}
|
||||
f2fs_put_dnode(&dn);
|
||||
mutex_unlock_op(sbi, ilock);
|
||||
f2fs_unlock_op(sbi);
|
||||
|
||||
if (pg_start == pg_end)
|
||||
new_size = offset + len;
|
||||
|
31
fs/f2fs/gc.c
31
fs/f2fs/gc.c
@ -77,13 +77,15 @@ static int gc_thread_func(void *data)
|
||||
else
|
||||
wait_ms = increase_sleep_time(gc_th, wait_ms);
|
||||
|
||||
#ifdef CONFIG_F2FS_STAT_FS
|
||||
sbi->bg_gc++;
|
||||
#endif
|
||||
stat_inc_bggc_count(sbi);
|
||||
|
||||
/* if return value is not zero, no victim was selected */
|
||||
if (f2fs_gc(sbi))
|
||||
wait_ms = gc_th->no_gc_sleep_time;
|
||||
|
||||
/* balancing f2fs's metadata periodically */
|
||||
f2fs_balance_fs_bg(sbi);
|
||||
|
||||
} while (!kthread_should_stop());
|
||||
return 0;
|
||||
}
|
||||
@ -236,8 +238,8 @@ static unsigned int get_cb_cost(struct f2fs_sb_info *sbi, unsigned int segno)
|
||||
return UINT_MAX - ((100 * (100 - u) * age) / (100 + u));
|
||||
}
|
||||
|
||||
static unsigned int get_gc_cost(struct f2fs_sb_info *sbi, unsigned int segno,
|
||||
struct victim_sel_policy *p)
|
||||
static inline unsigned int get_gc_cost(struct f2fs_sb_info *sbi,
|
||||
unsigned int segno, struct victim_sel_policy *p)
|
||||
{
|
||||
if (p->alloc_mode == SSR)
|
||||
return get_seg_entry(sbi, segno)->ckpt_valid_blocks;
|
||||
@ -293,7 +295,11 @@ static int get_victim_by_default(struct f2fs_sb_info *sbi,
|
||||
}
|
||||
break;
|
||||
}
|
||||
p.offset = ((segno / p.ofs_unit) * p.ofs_unit) + p.ofs_unit;
|
||||
|
||||
p.offset = segno + p.ofs_unit;
|
||||
if (p.ofs_unit > 1)
|
||||
p.offset -= segno % p.ofs_unit;
|
||||
|
||||
secno = GET_SECNO(sbi, segno);
|
||||
|
||||
if (sec_usage_check(sbi, secno))
|
||||
@ -306,10 +312,9 @@ static int get_victim_by_default(struct f2fs_sb_info *sbi,
|
||||
if (p.min_cost > cost) {
|
||||
p.min_segno = segno;
|
||||
p.min_cost = cost;
|
||||
}
|
||||
|
||||
if (cost == max_cost)
|
||||
} else if (unlikely(cost == max_cost)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (nsearched++ >= p.max_search) {
|
||||
sbi->last_victim[p.gc_mode] = segno;
|
||||
@ -358,12 +363,8 @@ static void add_gc_inode(struct inode *inode, struct list_head *ilist)
|
||||
iput(inode);
|
||||
return;
|
||||
}
|
||||
repeat:
|
||||
new_ie = kmem_cache_alloc(winode_slab, GFP_NOFS);
|
||||
if (!new_ie) {
|
||||
cond_resched();
|
||||
goto repeat;
|
||||
}
|
||||
|
||||
new_ie = f2fs_kmem_cache_alloc(winode_slab, GFP_NOFS);
|
||||
new_ie->inode = inode;
|
||||
list_add_tail(&new_ie->list, ilist);
|
||||
}
|
||||
|
@ -37,6 +37,31 @@ void f2fs_set_inode_flags(struct inode *inode)
|
||||
inode->i_flags |= S_DIRSYNC;
|
||||
}
|
||||
|
||||
static void __get_inode_rdev(struct inode *inode, struct f2fs_inode *ri)
|
||||
{
|
||||
if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) ||
|
||||
S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) {
|
||||
if (ri->i_addr[0])
|
||||
inode->i_rdev = old_decode_dev(le32_to_cpu(ri->i_addr[0]));
|
||||
else
|
||||
inode->i_rdev = new_decode_dev(le32_to_cpu(ri->i_addr[1]));
|
||||
}
|
||||
}
|
||||
|
||||
static void __set_inode_rdev(struct inode *inode, struct f2fs_inode *ri)
|
||||
{
|
||||
if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) {
|
||||
if (old_valid_dev(inode->i_rdev)) {
|
||||
ri->i_addr[0] = cpu_to_le32(old_encode_dev(inode->i_rdev));
|
||||
ri->i_addr[1] = 0;
|
||||
} else {
|
||||
ri->i_addr[0] = 0;
|
||||
ri->i_addr[1] = cpu_to_le32(new_encode_dev(inode->i_rdev));
|
||||
ri->i_addr[2] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int do_read_inode(struct inode *inode)
|
||||
{
|
||||
struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
|
||||
@ -73,10 +98,6 @@ static int do_read_inode(struct inode *inode)
|
||||
inode->i_ctime.tv_nsec = le32_to_cpu(ri->i_ctime_nsec);
|
||||
inode->i_mtime.tv_nsec = le32_to_cpu(ri->i_mtime_nsec);
|
||||
inode->i_generation = le32_to_cpu(ri->i_generation);
|
||||
if (ri->i_addr[0])
|
||||
inode->i_rdev = old_decode_dev(le32_to_cpu(ri->i_addr[0]));
|
||||
else
|
||||
inode->i_rdev = new_decode_dev(le32_to_cpu(ri->i_addr[1]));
|
||||
|
||||
fi->i_current_depth = le32_to_cpu(ri->i_current_depth);
|
||||
fi->i_xattr_nid = le32_to_cpu(ri->i_xattr_nid);
|
||||
@ -84,8 +105,13 @@ static int do_read_inode(struct inode *inode)
|
||||
fi->flags = 0;
|
||||
fi->i_advise = ri->i_advise;
|
||||
fi->i_pino = le32_to_cpu(ri->i_pino);
|
||||
|
||||
get_extent_info(&fi->ext, ri->i_ext);
|
||||
get_inline_info(fi, ri);
|
||||
|
||||
/* get rdev by using inline_info */
|
||||
__get_inode_rdev(inode, ri);
|
||||
|
||||
f2fs_put_page(node_page, 1);
|
||||
return 0;
|
||||
}
|
||||
@ -179,21 +205,10 @@ void update_inode(struct inode *inode, struct page *node_page)
|
||||
ri->i_pino = cpu_to_le32(F2FS_I(inode)->i_pino);
|
||||
ri->i_generation = cpu_to_le32(inode->i_generation);
|
||||
|
||||
if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) {
|
||||
if (old_valid_dev(inode->i_rdev)) {
|
||||
ri->i_addr[0] =
|
||||
cpu_to_le32(old_encode_dev(inode->i_rdev));
|
||||
ri->i_addr[1] = 0;
|
||||
} else {
|
||||
ri->i_addr[0] = 0;
|
||||
ri->i_addr[1] =
|
||||
cpu_to_le32(new_encode_dev(inode->i_rdev));
|
||||
ri->i_addr[2] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
__set_inode_rdev(inode, ri);
|
||||
set_cold_node(inode, node_page);
|
||||
set_page_dirty(node_page);
|
||||
|
||||
clear_inode_flag(F2FS_I(inode), FI_DIRTY_INODE);
|
||||
}
|
||||
|
||||
@ -214,7 +229,7 @@ int update_inode_page(struct inode *inode)
|
||||
int f2fs_write_inode(struct inode *inode, struct writeback_control *wbc)
|
||||
{
|
||||
struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
|
||||
int ret, ilock;
|
||||
int ret;
|
||||
|
||||
if (inode->i_ino == F2FS_NODE_INO(sbi) ||
|
||||
inode->i_ino == F2FS_META_INO(sbi))
|
||||
@ -227,9 +242,9 @@ int f2fs_write_inode(struct inode *inode, struct writeback_control *wbc)
|
||||
* We need to lock here to prevent from producing dirty node pages
|
||||
* during the urgent cleaning time when runing out of free sections.
|
||||
*/
|
||||
ilock = mutex_lock_op(sbi);
|
||||
f2fs_lock_op(sbi);
|
||||
ret = update_inode_page(inode);
|
||||
mutex_unlock_op(sbi, ilock);
|
||||
f2fs_unlock_op(sbi);
|
||||
|
||||
if (wbc)
|
||||
f2fs_balance_fs(sbi);
|
||||
@ -243,7 +258,6 @@ int f2fs_write_inode(struct inode *inode, struct writeback_control *wbc)
|
||||
void f2fs_evict_inode(struct inode *inode)
|
||||
{
|
||||
struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
|
||||
int ilock;
|
||||
|
||||
trace_f2fs_evict_inode(inode);
|
||||
truncate_inode_pages(&inode->i_data, 0);
|
||||
@ -252,7 +266,7 @@ void f2fs_evict_inode(struct inode *inode)
|
||||
inode->i_ino == F2FS_META_INO(sbi))
|
||||
goto no_delete;
|
||||
|
||||
BUG_ON(atomic_read(&F2FS_I(inode)->dirty_dents));
|
||||
f2fs_bug_on(atomic_read(&F2FS_I(inode)->dirty_dents));
|
||||
remove_dirty_dir_inode(inode);
|
||||
|
||||
if (inode->i_nlink || is_bad_inode(inode))
|
||||
@ -265,9 +279,9 @@ void f2fs_evict_inode(struct inode *inode)
|
||||
if (F2FS_HAS_BLOCKS(inode))
|
||||
f2fs_truncate(inode);
|
||||
|
||||
ilock = mutex_lock_op(sbi);
|
||||
f2fs_lock_op(sbi);
|
||||
remove_inode_page(inode);
|
||||
mutex_unlock_op(sbi, ilock);
|
||||
f2fs_unlock_op(sbi);
|
||||
|
||||
sb_end_intwrite(inode->i_sb);
|
||||
no_delete:
|
||||
|
@ -27,19 +27,19 @@ static struct inode *f2fs_new_inode(struct inode *dir, umode_t mode)
|
||||
nid_t ino;
|
||||
struct inode *inode;
|
||||
bool nid_free = false;
|
||||
int err, ilock;
|
||||
int err;
|
||||
|
||||
inode = new_inode(sb);
|
||||
if (!inode)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
ilock = mutex_lock_op(sbi);
|
||||
f2fs_lock_op(sbi);
|
||||
if (!alloc_nid(sbi, &ino)) {
|
||||
mutex_unlock_op(sbi, ilock);
|
||||
f2fs_unlock_op(sbi);
|
||||
err = -ENOSPC;
|
||||
goto fail;
|
||||
}
|
||||
mutex_unlock_op(sbi, ilock);
|
||||
f2fs_unlock_op(sbi);
|
||||
|
||||
inode->i_uid = current_fsuid();
|
||||
|
||||
@ -115,7 +115,7 @@ static int f2fs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
|
||||
struct f2fs_sb_info *sbi = F2FS_SB(sb);
|
||||
struct inode *inode;
|
||||
nid_t ino = 0;
|
||||
int err, ilock;
|
||||
int err;
|
||||
|
||||
f2fs_balance_fs(sbi);
|
||||
|
||||
@ -131,9 +131,9 @@ static int f2fs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
|
||||
inode->i_mapping->a_ops = &f2fs_dblock_aops;
|
||||
ino = inode->i_ino;
|
||||
|
||||
ilock = mutex_lock_op(sbi);
|
||||
f2fs_lock_op(sbi);
|
||||
err = f2fs_add_link(dentry, inode);
|
||||
mutex_unlock_op(sbi, ilock);
|
||||
f2fs_unlock_op(sbi);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
@ -157,7 +157,7 @@ static int f2fs_link(struct dentry *old_dentry, struct inode *dir,
|
||||
struct inode *inode = old_dentry->d_inode;
|
||||
struct super_block *sb = dir->i_sb;
|
||||
struct f2fs_sb_info *sbi = F2FS_SB(sb);
|
||||
int err, ilock;
|
||||
int err;
|
||||
|
||||
f2fs_balance_fs(sbi);
|
||||
|
||||
@ -165,9 +165,9 @@ static int f2fs_link(struct dentry *old_dentry, struct inode *dir,
|
||||
ihold(inode);
|
||||
|
||||
set_inode_flag(F2FS_I(inode), FI_INC_LINK);
|
||||
ilock = mutex_lock_op(sbi);
|
||||
f2fs_lock_op(sbi);
|
||||
err = f2fs_add_link(dentry, inode);
|
||||
mutex_unlock_op(sbi, ilock);
|
||||
f2fs_unlock_op(sbi);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
@ -220,7 +220,6 @@ static int f2fs_unlink(struct inode *dir, struct dentry *dentry)
|
||||
struct f2fs_dir_entry *de;
|
||||
struct page *page;
|
||||
int err = -ENOENT;
|
||||
int ilock;
|
||||
|
||||
trace_f2fs_unlink_enter(dir, dentry);
|
||||
f2fs_balance_fs(sbi);
|
||||
@ -229,16 +228,16 @@ static int f2fs_unlink(struct inode *dir, struct dentry *dentry)
|
||||
if (!de)
|
||||
goto fail;
|
||||
|
||||
f2fs_lock_op(sbi);
|
||||
err = acquire_orphan_inode(sbi);
|
||||
if (err) {
|
||||
f2fs_unlock_op(sbi);
|
||||
kunmap(page);
|
||||
f2fs_put_page(page, 0);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ilock = mutex_lock_op(sbi);
|
||||
f2fs_delete_entry(de, page, inode);
|
||||
mutex_unlock_op(sbi, ilock);
|
||||
f2fs_unlock_op(sbi);
|
||||
|
||||
/* In order to evict this inode, we set it dirty */
|
||||
mark_inode_dirty(inode);
|
||||
@ -254,7 +253,7 @@ static int f2fs_symlink(struct inode *dir, struct dentry *dentry,
|
||||
struct f2fs_sb_info *sbi = F2FS_SB(sb);
|
||||
struct inode *inode;
|
||||
size_t symlen = strlen(symname) + 1;
|
||||
int err, ilock;
|
||||
int err;
|
||||
|
||||
f2fs_balance_fs(sbi);
|
||||
|
||||
@ -265,9 +264,9 @@ static int f2fs_symlink(struct inode *dir, struct dentry *dentry,
|
||||
inode->i_op = &f2fs_symlink_inode_operations;
|
||||
inode->i_mapping->a_ops = &f2fs_dblock_aops;
|
||||
|
||||
ilock = mutex_lock_op(sbi);
|
||||
f2fs_lock_op(sbi);
|
||||
err = f2fs_add_link(dentry, inode);
|
||||
mutex_unlock_op(sbi, ilock);
|
||||
f2fs_unlock_op(sbi);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
@ -290,7 +289,7 @@ static int f2fs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
|
||||
{
|
||||
struct f2fs_sb_info *sbi = F2FS_SB(dir->i_sb);
|
||||
struct inode *inode;
|
||||
int err, ilock;
|
||||
int err;
|
||||
|
||||
f2fs_balance_fs(sbi);
|
||||
|
||||
@ -304,9 +303,9 @@ static int f2fs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
|
||||
mapping_set_gfp_mask(inode->i_mapping, GFP_F2FS_ZERO);
|
||||
|
||||
set_inode_flag(F2FS_I(inode), FI_INC_LINK);
|
||||
ilock = mutex_lock_op(sbi);
|
||||
f2fs_lock_op(sbi);
|
||||
err = f2fs_add_link(dentry, inode);
|
||||
mutex_unlock_op(sbi, ilock);
|
||||
f2fs_unlock_op(sbi);
|
||||
if (err)
|
||||
goto out_fail;
|
||||
|
||||
@ -342,7 +341,6 @@ static int f2fs_mknod(struct inode *dir, struct dentry *dentry,
|
||||
struct f2fs_sb_info *sbi = F2FS_SB(sb);
|
||||
struct inode *inode;
|
||||
int err = 0;
|
||||
int ilock;
|
||||
|
||||
if (!new_valid_dev(rdev))
|
||||
return -EINVAL;
|
||||
@ -356,9 +354,9 @@ static int f2fs_mknod(struct inode *dir, struct dentry *dentry,
|
||||
init_special_inode(inode, inode->i_mode, rdev);
|
||||
inode->i_op = &f2fs_special_inode_operations;
|
||||
|
||||
ilock = mutex_lock_op(sbi);
|
||||
f2fs_lock_op(sbi);
|
||||
err = f2fs_add_link(dentry, inode);
|
||||
mutex_unlock_op(sbi, ilock);
|
||||
f2fs_unlock_op(sbi);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
@ -387,7 +385,7 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
struct f2fs_dir_entry *old_dir_entry = NULL;
|
||||
struct f2fs_dir_entry *old_entry;
|
||||
struct f2fs_dir_entry *new_entry;
|
||||
int err = -ENOENT, ilock = -1;
|
||||
int err = -ENOENT;
|
||||
|
||||
f2fs_balance_fs(sbi);
|
||||
|
||||
@ -402,7 +400,7 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
goto out_old;
|
||||
}
|
||||
|
||||
ilock = mutex_lock_op(sbi);
|
||||
f2fs_lock_op(sbi);
|
||||
|
||||
if (new_inode) {
|
||||
|
||||
@ -467,7 +465,7 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
update_inode_page(old_dir);
|
||||
}
|
||||
|
||||
mutex_unlock_op(sbi, ilock);
|
||||
f2fs_unlock_op(sbi);
|
||||
return 0;
|
||||
|
||||
put_out_dir:
|
||||
@ -477,7 +475,7 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
kunmap(old_dir_page);
|
||||
f2fs_put_page(old_dir_page, 0);
|
||||
}
|
||||
mutex_unlock_op(sbi, ilock);
|
||||
f2fs_unlock_op(sbi);
|
||||
out_old:
|
||||
kunmap(old_page);
|
||||
f2fs_put_page(old_page, 0);
|
||||
|
142
fs/f2fs/node.c
142
fs/f2fs/node.c
@ -204,7 +204,7 @@ static void set_node_addr(struct f2fs_sb_info *sbi, struct node_info *ni,
|
||||
}
|
||||
e->ni = *ni;
|
||||
e->checkpointed = true;
|
||||
BUG_ON(ni->blk_addr == NEW_ADDR);
|
||||
f2fs_bug_on(ni->blk_addr == NEW_ADDR);
|
||||
} else if (new_blkaddr == NEW_ADDR) {
|
||||
/*
|
||||
* when nid is reallocated,
|
||||
@ -212,19 +212,19 @@ static void set_node_addr(struct f2fs_sb_info *sbi, struct node_info *ni,
|
||||
* So, reinitialize it with new information.
|
||||
*/
|
||||
e->ni = *ni;
|
||||
BUG_ON(ni->blk_addr != NULL_ADDR);
|
||||
f2fs_bug_on(ni->blk_addr != NULL_ADDR);
|
||||
}
|
||||
|
||||
if (new_blkaddr == NEW_ADDR)
|
||||
e->checkpointed = false;
|
||||
|
||||
/* sanity check */
|
||||
BUG_ON(nat_get_blkaddr(e) != ni->blk_addr);
|
||||
BUG_ON(nat_get_blkaddr(e) == NULL_ADDR &&
|
||||
f2fs_bug_on(nat_get_blkaddr(e) != ni->blk_addr);
|
||||
f2fs_bug_on(nat_get_blkaddr(e) == NULL_ADDR &&
|
||||
new_blkaddr == NULL_ADDR);
|
||||
BUG_ON(nat_get_blkaddr(e) == NEW_ADDR &&
|
||||
f2fs_bug_on(nat_get_blkaddr(e) == NEW_ADDR &&
|
||||
new_blkaddr == NEW_ADDR);
|
||||
BUG_ON(nat_get_blkaddr(e) != NEW_ADDR &&
|
||||
f2fs_bug_on(nat_get_blkaddr(e) != NEW_ADDR &&
|
||||
nat_get_blkaddr(e) != NULL_ADDR &&
|
||||
new_blkaddr == NEW_ADDR);
|
||||
|
||||
@ -240,7 +240,7 @@ static void set_node_addr(struct f2fs_sb_info *sbi, struct node_info *ni,
|
||||
write_unlock(&nm_i->nat_tree_lock);
|
||||
}
|
||||
|
||||
static int try_to_free_nats(struct f2fs_sb_info *sbi, int nr_shrink)
|
||||
int try_to_free_nats(struct f2fs_sb_info *sbi, int nr_shrink)
|
||||
{
|
||||
struct f2fs_nm_info *nm_i = NM_I(sbi);
|
||||
|
||||
@ -495,10 +495,10 @@ static void truncate_node(struct dnode_of_data *dn)
|
||||
|
||||
get_node_info(sbi, dn->nid, &ni);
|
||||
if (dn->inode->i_blocks == 0) {
|
||||
BUG_ON(ni.blk_addr != NULL_ADDR);
|
||||
f2fs_bug_on(ni.blk_addr != NULL_ADDR);
|
||||
goto invalidate;
|
||||
}
|
||||
BUG_ON(ni.blk_addr == NULL_ADDR);
|
||||
f2fs_bug_on(ni.blk_addr == NULL_ADDR);
|
||||
|
||||
/* Deallocate node address */
|
||||
invalidate_blocks(sbi, ni.blk_addr);
|
||||
@ -822,7 +822,7 @@ int remove_inode_page(struct inode *inode)
|
||||
}
|
||||
|
||||
/* 0 is possible, after f2fs_new_inode() is failed */
|
||||
BUG_ON(inode->i_blocks != 0 && inode->i_blocks != 1);
|
||||
f2fs_bug_on(inode->i_blocks != 0 && inode->i_blocks != 1);
|
||||
set_new_dnode(&dn, inode, page, page, ino);
|
||||
truncate_node(&dn);
|
||||
return 0;
|
||||
@ -863,7 +863,7 @@ struct page *new_node_page(struct dnode_of_data *dn,
|
||||
get_node_info(sbi, dn->nid, &old_ni);
|
||||
|
||||
/* Reinitialize old_ni with new node page */
|
||||
BUG_ON(old_ni.blk_addr != NULL_ADDR);
|
||||
f2fs_bug_on(old_ni.blk_addr != NULL_ADDR);
|
||||
new_ni = old_ni;
|
||||
new_ni.ino = dn->inode->i_ino;
|
||||
set_node_addr(sbi, &new_ni, NEW_ADDR);
|
||||
@ -969,7 +969,7 @@ struct page *get_node_page(struct f2fs_sb_info *sbi, pgoff_t nid)
|
||||
goto repeat;
|
||||
}
|
||||
got_it:
|
||||
BUG_ON(nid != nid_of_node(page));
|
||||
f2fs_bug_on(nid != nid_of_node(page));
|
||||
mark_page_accessed(page);
|
||||
return page;
|
||||
}
|
||||
@ -1148,6 +1148,47 @@ int sync_node_pages(struct f2fs_sb_info *sbi, nid_t ino,
|
||||
return nwritten;
|
||||
}
|
||||
|
||||
int wait_on_node_pages_writeback(struct f2fs_sb_info *sbi, nid_t ino)
|
||||
{
|
||||
struct address_space *mapping = sbi->node_inode->i_mapping;
|
||||
pgoff_t index = 0, end = LONG_MAX;
|
||||
struct pagevec pvec;
|
||||
int nr_pages;
|
||||
int ret2 = 0, ret = 0;
|
||||
|
||||
pagevec_init(&pvec, 0);
|
||||
while ((index <= end) &&
|
||||
(nr_pages = pagevec_lookup_tag(&pvec, mapping, &index,
|
||||
PAGECACHE_TAG_WRITEBACK,
|
||||
min(end - index, (pgoff_t)PAGEVEC_SIZE-1) + 1)) != 0) {
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < nr_pages; i++) {
|
||||
struct page *page = pvec.pages[i];
|
||||
|
||||
/* until radix tree lookup accepts end_index */
|
||||
if (page->index > end)
|
||||
continue;
|
||||
|
||||
if (ino && ino_of_node(page) == ino) {
|
||||
wait_on_page_writeback(page);
|
||||
if (TestClearPageError(page))
|
||||
ret = -EIO;
|
||||
}
|
||||
}
|
||||
pagevec_release(&pvec);
|
||||
cond_resched();
|
||||
}
|
||||
|
||||
if (test_and_clear_bit(AS_ENOSPC, &mapping->flags))
|
||||
ret2 = -ENOSPC;
|
||||
if (test_and_clear_bit(AS_EIO, &mapping->flags))
|
||||
ret2 = -EIO;
|
||||
if (!ret)
|
||||
ret = ret2;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int f2fs_write_node_page(struct page *page,
|
||||
struct writeback_control *wbc)
|
||||
{
|
||||
@ -1156,11 +1197,14 @@ static int f2fs_write_node_page(struct page *page,
|
||||
block_t new_addr;
|
||||
struct node_info ni;
|
||||
|
||||
if (sbi->por_doing)
|
||||
goto redirty_out;
|
||||
|
||||
wait_on_page_writeback(page);
|
||||
|
||||
/* get old block addr of this node page */
|
||||
nid = nid_of_node(page);
|
||||
BUG_ON(page->index != nid);
|
||||
f2fs_bug_on(page->index != nid);
|
||||
|
||||
get_node_info(sbi, nid, &ni);
|
||||
|
||||
@ -1171,12 +1215,8 @@ static int f2fs_write_node_page(struct page *page,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (wbc->for_reclaim) {
|
||||
dec_page_count(sbi, F2FS_DIRTY_NODES);
|
||||
wbc->pages_skipped++;
|
||||
set_page_dirty(page);
|
||||
return AOP_WRITEPAGE_ACTIVATE;
|
||||
}
|
||||
if (wbc->for_reclaim)
|
||||
goto redirty_out;
|
||||
|
||||
mutex_lock(&sbi->node_write);
|
||||
set_page_writeback(page);
|
||||
@ -1186,6 +1226,12 @@ static int f2fs_write_node_page(struct page *page,
|
||||
mutex_unlock(&sbi->node_write);
|
||||
unlock_page(page);
|
||||
return 0;
|
||||
|
||||
redirty_out:
|
||||
dec_page_count(sbi, F2FS_DIRTY_NODES);
|
||||
wbc->pages_skipped++;
|
||||
set_page_dirty(page);
|
||||
return AOP_WRITEPAGE_ACTIVATE;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1200,11 +1246,8 @@ static int f2fs_write_node_pages(struct address_space *mapping,
|
||||
struct f2fs_sb_info *sbi = F2FS_SB(mapping->host->i_sb);
|
||||
long nr_to_write = wbc->nr_to_write;
|
||||
|
||||
/* First check balancing cached NAT entries */
|
||||
if (try_to_free_nats(sbi, NAT_ENTRY_PER_BLOCK)) {
|
||||
f2fs_sync_fs(sbi->sb, true);
|
||||
return 0;
|
||||
}
|
||||
/* balancing f2fs's metadata in background */
|
||||
f2fs_balance_fs_bg(sbi);
|
||||
|
||||
/* collect a number of dirty node pages and write together */
|
||||
if (get_pages(sbi, F2FS_DIRTY_NODES) < COLLECT_DIRTY_NODES)
|
||||
@ -1223,6 +1266,8 @@ static int f2fs_set_node_page_dirty(struct page *page)
|
||||
struct address_space *mapping = page->mapping;
|
||||
struct f2fs_sb_info *sbi = F2FS_SB(mapping->host->i_sb);
|
||||
|
||||
trace_f2fs_set_page_dirty(page, NODE);
|
||||
|
||||
SetPageUptodate(page);
|
||||
if (!PageDirty(page)) {
|
||||
__set_page_dirty_nobuffers(page);
|
||||
@ -1291,23 +1336,18 @@ static int add_free_nid(struct f2fs_nm_info *nm_i, nid_t nid, bool build)
|
||||
if (nid == 0)
|
||||
return 0;
|
||||
|
||||
if (!build)
|
||||
goto retry;
|
||||
|
||||
/* do not add allocated nids */
|
||||
read_lock(&nm_i->nat_tree_lock);
|
||||
ne = __lookup_nat_cache(nm_i, nid);
|
||||
if (ne && nat_get_blkaddr(ne) != NULL_ADDR)
|
||||
allocated = true;
|
||||
read_unlock(&nm_i->nat_tree_lock);
|
||||
if (allocated)
|
||||
return 0;
|
||||
retry:
|
||||
i = kmem_cache_alloc(free_nid_slab, GFP_NOFS);
|
||||
if (!i) {
|
||||
cond_resched();
|
||||
goto retry;
|
||||
if (build) {
|
||||
/* do not add allocated nids */
|
||||
read_lock(&nm_i->nat_tree_lock);
|
||||
ne = __lookup_nat_cache(nm_i, nid);
|
||||
if (ne && nat_get_blkaddr(ne) != NULL_ADDR)
|
||||
allocated = true;
|
||||
read_unlock(&nm_i->nat_tree_lock);
|
||||
if (allocated)
|
||||
return 0;
|
||||
}
|
||||
|
||||
i = f2fs_kmem_cache_alloc(free_nid_slab, GFP_NOFS);
|
||||
i->nid = nid;
|
||||
i->state = NID_NEW;
|
||||
|
||||
@ -1350,7 +1390,7 @@ static void scan_nat_page(struct f2fs_nm_info *nm_i,
|
||||
break;
|
||||
|
||||
blk_addr = le32_to_cpu(nat_blk->entries[i].block_addr);
|
||||
BUG_ON(blk_addr == NEW_ADDR);
|
||||
f2fs_bug_on(blk_addr == NEW_ADDR);
|
||||
if (blk_addr == NULL_ADDR) {
|
||||
if (add_free_nid(nm_i, start_nid, true) < 0)
|
||||
break;
|
||||
@ -1421,14 +1461,14 @@ bool alloc_nid(struct f2fs_sb_info *sbi, nid_t *nid)
|
||||
|
||||
/* We should not use stale free nids created by build_free_nids */
|
||||
if (nm_i->fcnt && !sbi->on_build_free_nids) {
|
||||
BUG_ON(list_empty(&nm_i->free_nid_list));
|
||||
f2fs_bug_on(list_empty(&nm_i->free_nid_list));
|
||||
list_for_each(this, &nm_i->free_nid_list) {
|
||||
i = list_entry(this, struct free_nid, list);
|
||||
if (i->state == NID_NEW)
|
||||
break;
|
||||
}
|
||||
|
||||
BUG_ON(i->state != NID_NEW);
|
||||
f2fs_bug_on(i->state != NID_NEW);
|
||||
*nid = i->nid;
|
||||
i->state = NID_ALLOC;
|
||||
nm_i->fcnt--;
|
||||
@ -1439,9 +1479,9 @@ bool alloc_nid(struct f2fs_sb_info *sbi, nid_t *nid)
|
||||
|
||||
/* Let's scan nat pages and its caches to get free nids */
|
||||
mutex_lock(&nm_i->build_lock);
|
||||
sbi->on_build_free_nids = 1;
|
||||
sbi->on_build_free_nids = true;
|
||||
build_free_nids(sbi);
|
||||
sbi->on_build_free_nids = 0;
|
||||
sbi->on_build_free_nids = false;
|
||||
mutex_unlock(&nm_i->build_lock);
|
||||
goto retry;
|
||||
}
|
||||
@ -1456,7 +1496,7 @@ void alloc_nid_done(struct f2fs_sb_info *sbi, nid_t nid)
|
||||
|
||||
spin_lock(&nm_i->free_nid_list_lock);
|
||||
i = __lookup_free_nid_list(nid, &nm_i->free_nid_list);
|
||||
BUG_ON(!i || i->state != NID_ALLOC);
|
||||
f2fs_bug_on(!i || i->state != NID_ALLOC);
|
||||
__del_from_free_nid_list(i);
|
||||
spin_unlock(&nm_i->free_nid_list_lock);
|
||||
}
|
||||
@ -1474,7 +1514,7 @@ void alloc_nid_failed(struct f2fs_sb_info *sbi, nid_t nid)
|
||||
|
||||
spin_lock(&nm_i->free_nid_list_lock);
|
||||
i = __lookup_free_nid_list(nid, &nm_i->free_nid_list);
|
||||
BUG_ON(!i || i->state != NID_ALLOC);
|
||||
f2fs_bug_on(!i || i->state != NID_ALLOC);
|
||||
if (nm_i->fcnt > 2 * MAX_FREE_NIDS) {
|
||||
__del_from_free_nid_list(i);
|
||||
} else {
|
||||
@ -1677,7 +1717,7 @@ void flush_nat_entries(struct f2fs_sb_info *sbi)
|
||||
nat_blk = page_address(page);
|
||||
}
|
||||
|
||||
BUG_ON(!nat_blk);
|
||||
f2fs_bug_on(!nat_blk);
|
||||
raw_ne = nat_blk->entries[nid - start_nid];
|
||||
flush_now:
|
||||
new_blkaddr = nat_get_blkaddr(ne);
|
||||
@ -1781,11 +1821,11 @@ void destroy_node_manager(struct f2fs_sb_info *sbi)
|
||||
/* destroy free nid list */
|
||||
spin_lock(&nm_i->free_nid_list_lock);
|
||||
list_for_each_entry_safe(i, next_i, &nm_i->free_nid_list, list) {
|
||||
BUG_ON(i->state == NID_ALLOC);
|
||||
f2fs_bug_on(i->state == NID_ALLOC);
|
||||
__del_from_free_nid_list(i);
|
||||
nm_i->fcnt--;
|
||||
}
|
||||
BUG_ON(nm_i->fcnt);
|
||||
f2fs_bug_on(nm_i->fcnt);
|
||||
spin_unlock(&nm_i->free_nid_list_lock);
|
||||
|
||||
/* destroy nat cache */
|
||||
@ -1799,7 +1839,7 @@ void destroy_node_manager(struct f2fs_sb_info *sbi)
|
||||
__del_from_nat_cache(nm_i, e);
|
||||
}
|
||||
}
|
||||
BUG_ON(nm_i->nat_cnt);
|
||||
f2fs_bug_on(nm_i->nat_cnt);
|
||||
write_unlock(&nm_i->nat_tree_lock);
|
||||
|
||||
kfree(nm_i->nat_bitmap);
|
||||
|
@ -64,24 +64,31 @@ static int recover_dentry(struct page *ipage, struct inode *inode)
|
||||
name.name = raw_inode->i_name;
|
||||
retry:
|
||||
de = f2fs_find_entry(dir, &name, &page);
|
||||
if (de && inode->i_ino == le32_to_cpu(de->ino)) {
|
||||
kunmap(page);
|
||||
f2fs_put_page(page, 0);
|
||||
goto out;
|
||||
}
|
||||
if (de && inode->i_ino == le32_to_cpu(de->ino))
|
||||
goto out_unmap_put;
|
||||
if (de) {
|
||||
einode = f2fs_iget(inode->i_sb, le32_to_cpu(de->ino));
|
||||
if (IS_ERR(einode)) {
|
||||
WARN_ON(1);
|
||||
if (PTR_ERR(einode) == -ENOENT)
|
||||
err = -EEXIST;
|
||||
goto out;
|
||||
goto out_unmap_put;
|
||||
}
|
||||
err = acquire_orphan_inode(F2FS_SB(inode->i_sb));
|
||||
if (err) {
|
||||
iput(einode);
|
||||
goto out_unmap_put;
|
||||
}
|
||||
f2fs_delete_entry(de, page, einode);
|
||||
iput(einode);
|
||||
goto retry;
|
||||
}
|
||||
err = __f2fs_add_link(dir, &name, inode);
|
||||
goto out;
|
||||
|
||||
out_unmap_put:
|
||||
kunmap(page);
|
||||
f2fs_put_page(page, 0);
|
||||
out:
|
||||
f2fs_msg(inode->i_sb, KERN_NOTICE, "recover_inode and its dentry: "
|
||||
"ino = %x, name = %s, dir = %lx, err = %d",
|
||||
@ -285,7 +292,6 @@ static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode,
|
||||
struct f2fs_summary sum;
|
||||
struct node_info ni;
|
||||
int err = 0, recovered = 0;
|
||||
int ilock;
|
||||
|
||||
start = start_bidx_of_node(ofs_of_node(page), fi);
|
||||
if (IS_INODE(page))
|
||||
@ -293,20 +299,20 @@ static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode,
|
||||
else
|
||||
end = start + ADDRS_PER_BLOCK;
|
||||
|
||||
ilock = mutex_lock_op(sbi);
|
||||
f2fs_lock_op(sbi);
|
||||
set_new_dnode(&dn, inode, NULL, NULL, 0);
|
||||
|
||||
err = get_dnode_of_data(&dn, start, ALLOC_NODE);
|
||||
if (err) {
|
||||
mutex_unlock_op(sbi, ilock);
|
||||
f2fs_unlock_op(sbi);
|
||||
return err;
|
||||
}
|
||||
|
||||
wait_on_page_writeback(dn.node_page);
|
||||
|
||||
get_node_info(sbi, dn.nid, &ni);
|
||||
BUG_ON(ni.ino != ino_of_node(page));
|
||||
BUG_ON(ofs_of_node(dn.node_page) != ofs_of_node(page));
|
||||
f2fs_bug_on(ni.ino != ino_of_node(page));
|
||||
f2fs_bug_on(ofs_of_node(dn.node_page) != ofs_of_node(page));
|
||||
|
||||
for (; start < end; start++) {
|
||||
block_t src, dest;
|
||||
@ -316,9 +322,9 @@ static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode,
|
||||
|
||||
if (src != dest && dest != NEW_ADDR && dest != NULL_ADDR) {
|
||||
if (src == NULL_ADDR) {
|
||||
int err = reserve_new_block(&dn);
|
||||
err = reserve_new_block(&dn);
|
||||
/* We should not get -ENOSPC */
|
||||
BUG_ON(err);
|
||||
f2fs_bug_on(err);
|
||||
}
|
||||
|
||||
/* Check the previous node page having this index */
|
||||
@ -349,7 +355,7 @@ static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode,
|
||||
recover_node_page(sbi, dn.node_page, &sum, &ni, blkaddr);
|
||||
err:
|
||||
f2fs_put_dnode(&dn);
|
||||
mutex_unlock_op(sbi, ilock);
|
||||
f2fs_unlock_op(sbi);
|
||||
|
||||
f2fs_msg(sbi->sb, KERN_NOTICE, "recover_data: ino = %lx, "
|
||||
"recovered_data = %d blocks, err = %d",
|
||||
@ -419,6 +425,7 @@ int recover_fsync_data(struct f2fs_sb_info *sbi)
|
||||
{
|
||||
struct list_head inode_list;
|
||||
int err;
|
||||
bool need_writecp = false;
|
||||
|
||||
fsync_entry_slab = f2fs_kmem_cache_create("f2fs_fsync_inode_entry",
|
||||
sizeof(struct fsync_inode_entry), NULL);
|
||||
@ -428,7 +435,7 @@ int recover_fsync_data(struct f2fs_sb_info *sbi)
|
||||
INIT_LIST_HEAD(&inode_list);
|
||||
|
||||
/* step #1: find fsynced inode numbers */
|
||||
sbi->por_doing = 1;
|
||||
sbi->por_doing = true;
|
||||
err = find_fsync_dnodes(sbi, &inode_list);
|
||||
if (err)
|
||||
goto out;
|
||||
@ -436,14 +443,16 @@ int recover_fsync_data(struct f2fs_sb_info *sbi)
|
||||
if (list_empty(&inode_list))
|
||||
goto out;
|
||||
|
||||
need_writecp = true;
|
||||
|
||||
/* step #2: recover data */
|
||||
err = recover_data(sbi, &inode_list, CURSEG_WARM_NODE);
|
||||
BUG_ON(!list_empty(&inode_list));
|
||||
f2fs_bug_on(!list_empty(&inode_list));
|
||||
out:
|
||||
destroy_fsync_dnodes(&inode_list);
|
||||
kmem_cache_destroy(fsync_entry_slab);
|
||||
sbi->por_doing = 0;
|
||||
if (!err)
|
||||
sbi->por_doing = false;
|
||||
if (!err && need_writecp)
|
||||
write_checkpoint(sbi, false);
|
||||
return err;
|
||||
}
|
||||
|
@ -36,6 +36,14 @@ void f2fs_balance_fs(struct f2fs_sb_info *sbi)
|
||||
}
|
||||
}
|
||||
|
||||
void f2fs_balance_fs_bg(struct f2fs_sb_info *sbi)
|
||||
{
|
||||
/* check the # of cached NAT entries and prefree segments */
|
||||
if (try_to_free_nats(sbi, NAT_ENTRY_PER_BLOCK) ||
|
||||
excess_prefree_segs(sbi))
|
||||
f2fs_sync_fs(sbi->sb, true);
|
||||
}
|
||||
|
||||
static void __locate_dirty_segment(struct f2fs_sb_info *sbi, unsigned int segno,
|
||||
enum dirty_type dirty_type)
|
||||
{
|
||||
@ -50,20 +58,10 @@ static void __locate_dirty_segment(struct f2fs_sb_info *sbi, unsigned int segno,
|
||||
|
||||
if (dirty_type == DIRTY) {
|
||||
struct seg_entry *sentry = get_seg_entry(sbi, segno);
|
||||
enum dirty_type t = DIRTY_HOT_DATA;
|
||||
enum dirty_type t = sentry->type;
|
||||
|
||||
dirty_type = sentry->type;
|
||||
|
||||
if (!test_and_set_bit(segno, dirty_i->dirty_segmap[dirty_type]))
|
||||
dirty_i->nr_dirty[dirty_type]++;
|
||||
|
||||
/* Only one bitmap should be set */
|
||||
for (; t <= DIRTY_COLD_NODE; t++) {
|
||||
if (t == dirty_type)
|
||||
continue;
|
||||
if (test_and_clear_bit(segno, dirty_i->dirty_segmap[t]))
|
||||
dirty_i->nr_dirty[t]--;
|
||||
}
|
||||
if (!test_and_set_bit(segno, dirty_i->dirty_segmap[t]))
|
||||
dirty_i->nr_dirty[t]++;
|
||||
}
|
||||
}
|
||||
|
||||
@ -76,12 +74,11 @@ static void __remove_dirty_segment(struct f2fs_sb_info *sbi, unsigned int segno,
|
||||
dirty_i->nr_dirty[dirty_type]--;
|
||||
|
||||
if (dirty_type == DIRTY) {
|
||||
enum dirty_type t = DIRTY_HOT_DATA;
|
||||
struct seg_entry *sentry = get_seg_entry(sbi, segno);
|
||||
enum dirty_type t = sentry->type;
|
||||
|
||||
/* clear all the bitmaps */
|
||||
for (; t <= DIRTY_COLD_NODE; t++)
|
||||
if (test_and_clear_bit(segno, dirty_i->dirty_segmap[t]))
|
||||
dirty_i->nr_dirty[t]--;
|
||||
if (test_and_clear_bit(segno, dirty_i->dirty_segmap[t]))
|
||||
dirty_i->nr_dirty[t]--;
|
||||
|
||||
if (get_valid_blocks(sbi, segno, sbi->segs_per_sec) == 0)
|
||||
clear_bit(GET_SECNO(sbi, segno),
|
||||
@ -142,27 +139,33 @@ static void set_prefree_as_free_segments(struct f2fs_sb_info *sbi)
|
||||
void clear_prefree_segments(struct f2fs_sb_info *sbi)
|
||||
{
|
||||
struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
|
||||
unsigned int segno = -1;
|
||||
unsigned long *prefree_map = dirty_i->dirty_segmap[PRE];
|
||||
unsigned int total_segs = TOTAL_SEGS(sbi);
|
||||
unsigned int start = 0, end = -1;
|
||||
|
||||
mutex_lock(&dirty_i->seglist_lock);
|
||||
|
||||
while (1) {
|
||||
segno = find_next_bit(dirty_i->dirty_segmap[PRE], total_segs,
|
||||
segno + 1);
|
||||
if (segno >= total_segs)
|
||||
int i;
|
||||
start = find_next_bit(prefree_map, total_segs, end + 1);
|
||||
if (start >= total_segs)
|
||||
break;
|
||||
end = find_next_zero_bit(prefree_map, total_segs, start + 1);
|
||||
|
||||
if (test_and_clear_bit(segno, dirty_i->dirty_segmap[PRE]))
|
||||
dirty_i->nr_dirty[PRE]--;
|
||||
for (i = start; i < end; i++)
|
||||
clear_bit(i, prefree_map);
|
||||
|
||||
/* Let's use trim */
|
||||
if (test_opt(sbi, DISCARD))
|
||||
blkdev_issue_discard(sbi->sb->s_bdev,
|
||||
START_BLOCK(sbi, segno) <<
|
||||
sbi->log_sectors_per_block,
|
||||
1 << (sbi->log_sectors_per_block +
|
||||
sbi->log_blocks_per_seg),
|
||||
GFP_NOFS, 0);
|
||||
dirty_i->nr_dirty[PRE] -= end - start;
|
||||
|
||||
if (!test_opt(sbi, DISCARD))
|
||||
continue;
|
||||
|
||||
blkdev_issue_discard(sbi->sb->s_bdev,
|
||||
START_BLOCK(sbi, start) <<
|
||||
sbi->log_sectors_per_block,
|
||||
(1 << (sbi->log_sectors_per_block +
|
||||
sbi->log_blocks_per_seg)) * (end - start),
|
||||
GFP_NOFS, 0);
|
||||
}
|
||||
mutex_unlock(&dirty_i->seglist_lock);
|
||||
}
|
||||
@ -195,7 +198,7 @@ static void update_sit_entry(struct f2fs_sb_info *sbi, block_t blkaddr, int del)
|
||||
new_vblocks = se->valid_blocks + del;
|
||||
offset = GET_SEGOFF_FROM_SEG0(sbi, blkaddr) & (sbi->blocks_per_seg - 1);
|
||||
|
||||
BUG_ON((new_vblocks >> (sizeof(unsigned short) << 3) ||
|
||||
f2fs_bug_on((new_vblocks >> (sizeof(unsigned short) << 3) ||
|
||||
(new_vblocks > sbi->blocks_per_seg)));
|
||||
|
||||
se->valid_blocks = new_vblocks;
|
||||
@ -235,7 +238,7 @@ void invalidate_blocks(struct f2fs_sb_info *sbi, block_t addr)
|
||||
unsigned int segno = GET_SEGNO(sbi, addr);
|
||||
struct sit_info *sit_i = SIT_I(sbi);
|
||||
|
||||
BUG_ON(addr == NULL_ADDR);
|
||||
f2fs_bug_on(addr == NULL_ADDR);
|
||||
if (addr == NEW_ADDR)
|
||||
return;
|
||||
|
||||
@ -267,9 +270,8 @@ static void __add_sum_entry(struct f2fs_sb_info *sbi, int type,
|
||||
*/
|
||||
int npages_for_summary_flush(struct f2fs_sb_info *sbi)
|
||||
{
|
||||
int total_size_bytes = 0;
|
||||
int valid_sum_count = 0;
|
||||
int i, sum_space;
|
||||
int i, sum_in_page;
|
||||
|
||||
for (i = CURSEG_HOT_DATA; i <= CURSEG_COLD_DATA; i++) {
|
||||
if (sbi->ckpt->alloc_type[i] == SSR)
|
||||
@ -278,13 +280,12 @@ int npages_for_summary_flush(struct f2fs_sb_info *sbi)
|
||||
valid_sum_count += curseg_blkoff(sbi, i);
|
||||
}
|
||||
|
||||
total_size_bytes = valid_sum_count * (SUMMARY_SIZE + 1)
|
||||
+ sizeof(struct nat_journal) + 2
|
||||
+ sizeof(struct sit_journal) + 2;
|
||||
sum_space = PAGE_CACHE_SIZE - SUM_FOOTER_SIZE;
|
||||
if (total_size_bytes < sum_space)
|
||||
sum_in_page = (PAGE_CACHE_SIZE - 2 * SUM_JOURNAL_SIZE -
|
||||
SUM_FOOTER_SIZE) / SUMMARY_SIZE;
|
||||
if (valid_sum_count <= sum_in_page)
|
||||
return 1;
|
||||
else if (total_size_bytes < 2 * sum_space)
|
||||
else if ((valid_sum_count - sum_in_page) <=
|
||||
(PAGE_CACHE_SIZE - SUM_FOOTER_SIZE) / SUMMARY_SIZE)
|
||||
return 2;
|
||||
return 3;
|
||||
}
|
||||
@ -350,7 +351,7 @@ static void get_new_segment(struct f2fs_sb_info *sbi,
|
||||
if (dir == ALLOC_RIGHT) {
|
||||
secno = find_next_zero_bit(free_i->free_secmap,
|
||||
TOTAL_SECS(sbi), 0);
|
||||
BUG_ON(secno >= TOTAL_SECS(sbi));
|
||||
f2fs_bug_on(secno >= TOTAL_SECS(sbi));
|
||||
} else {
|
||||
go_left = 1;
|
||||
left_start = hint - 1;
|
||||
@ -366,7 +367,7 @@ static void get_new_segment(struct f2fs_sb_info *sbi,
|
||||
}
|
||||
left_start = find_next_zero_bit(free_i->free_secmap,
|
||||
TOTAL_SECS(sbi), 0);
|
||||
BUG_ON(left_start >= TOTAL_SECS(sbi));
|
||||
f2fs_bug_on(left_start >= TOTAL_SECS(sbi));
|
||||
break;
|
||||
}
|
||||
secno = left_start;
|
||||
@ -405,7 +406,7 @@ static void get_new_segment(struct f2fs_sb_info *sbi,
|
||||
}
|
||||
got_it:
|
||||
/* set it as dirty segment in free segmap */
|
||||
BUG_ON(test_bit(segno, free_i->free_segmap));
|
||||
f2fs_bug_on(test_bit(segno, free_i->free_segmap));
|
||||
__set_inuse(sbi, segno);
|
||||
*newseg = segno;
|
||||
write_unlock(&free_i->segmap_lock);
|
||||
@ -550,9 +551,8 @@ static void allocate_segment_by_default(struct f2fs_sb_info *sbi,
|
||||
change_curseg(sbi, type, true);
|
||||
else
|
||||
new_curseg(sbi, type, false);
|
||||
#ifdef CONFIG_F2FS_STAT_FS
|
||||
sbi->segment_count[curseg->alloc_type]++;
|
||||
#endif
|
||||
|
||||
stat_inc_seg_type(sbi, curseg);
|
||||
}
|
||||
|
||||
void allocate_new_segments(struct f2fs_sb_info *sbi)
|
||||
@ -597,6 +597,11 @@ static void f2fs_end_io_write(struct bio *bio, int err)
|
||||
|
||||
if (p->is_sync)
|
||||
complete(p->wait);
|
||||
|
||||
if (!get_pages(p->sbi, F2FS_WRITEBACK) &&
|
||||
!list_empty(&p->sbi->cp_wait.task_list))
|
||||
wake_up(&p->sbi->cp_wait);
|
||||
|
||||
kfree(p);
|
||||
bio_put(bio);
|
||||
}
|
||||
@ -657,6 +662,7 @@ static void submit_write_page(struct f2fs_sb_info *sbi, struct page *page,
|
||||
block_t blk_addr, enum page_type type)
|
||||
{
|
||||
struct block_device *bdev = sbi->sb->s_bdev;
|
||||
int bio_blocks;
|
||||
|
||||
verify_block_addr(sbi, blk_addr);
|
||||
|
||||
@ -676,7 +682,8 @@ static void submit_write_page(struct f2fs_sb_info *sbi, struct page *page,
|
||||
goto retry;
|
||||
}
|
||||
|
||||
sbi->bio[type] = f2fs_bio_alloc(bdev, max_hw_blocks(sbi));
|
||||
bio_blocks = MAX_BIO_BLOCKS(max_hw_blocks(sbi));
|
||||
sbi->bio[type] = f2fs_bio_alloc(bdev, bio_blocks);
|
||||
sbi->bio[type]->bi_sector = SECTOR_FROM_BLOCK(sbi, blk_addr);
|
||||
sbi->bio[type]->bi_private = priv;
|
||||
/*
|
||||
@ -771,7 +778,7 @@ static int __get_segment_type(struct page *page, enum page_type p_type)
|
||||
return __get_segment_type_4(page, p_type);
|
||||
}
|
||||
/* NR_CURSEG_TYPE(6) logs by default */
|
||||
BUG_ON(sbi->active_logs != NR_CURSEG_TYPE);
|
||||
f2fs_bug_on(sbi->active_logs != NR_CURSEG_TYPE);
|
||||
return __get_segment_type_6(page, p_type);
|
||||
}
|
||||
|
||||
@ -801,9 +808,8 @@ static void do_write_page(struct f2fs_sb_info *sbi, struct page *page,
|
||||
|
||||
mutex_lock(&sit_i->sentry_lock);
|
||||
__refresh_next_blkoff(sbi, curseg);
|
||||
#ifdef CONFIG_F2FS_STAT_FS
|
||||
sbi->block_count[curseg->alloc_type]++;
|
||||
#endif
|
||||
|
||||
stat_inc_block_count(sbi, curseg);
|
||||
|
||||
/*
|
||||
* SIT information should be updated before segment allocation,
|
||||
@ -849,7 +855,7 @@ void write_data_page(struct inode *inode, struct page *page,
|
||||
struct f2fs_summary sum;
|
||||
struct node_info ni;
|
||||
|
||||
BUG_ON(old_blkaddr == NULL_ADDR);
|
||||
f2fs_bug_on(old_blkaddr == NULL_ADDR);
|
||||
get_node_info(sbi, dn->nid, &ni);
|
||||
set_summary(&sum, dn->nid, dn->ofs_in_node, ni.version);
|
||||
|
||||
@ -1122,8 +1128,6 @@ static void write_compacted_summaries(struct f2fs_sb_info *sbi, block_t blkaddr)
|
||||
SUM_JOURNAL_SIZE);
|
||||
written_size += SUM_JOURNAL_SIZE;
|
||||
|
||||
set_page_dirty(page);
|
||||
|
||||
/* Step 3: write summary entries */
|
||||
for (i = CURSEG_HOT_DATA; i <= CURSEG_COLD_DATA; i++) {
|
||||
unsigned short blkoff;
|
||||
@ -1142,18 +1146,20 @@ static void write_compacted_summaries(struct f2fs_sb_info *sbi, block_t blkaddr)
|
||||
summary = (struct f2fs_summary *)(kaddr + written_size);
|
||||
*summary = seg_i->sum_blk->entries[j];
|
||||
written_size += SUMMARY_SIZE;
|
||||
set_page_dirty(page);
|
||||
|
||||
if (written_size + SUMMARY_SIZE <= PAGE_CACHE_SIZE -
|
||||
SUM_FOOTER_SIZE)
|
||||
continue;
|
||||
|
||||
set_page_dirty(page);
|
||||
f2fs_put_page(page, 1);
|
||||
page = NULL;
|
||||
}
|
||||
}
|
||||
if (page)
|
||||
if (page) {
|
||||
set_page_dirty(page);
|
||||
f2fs_put_page(page, 1);
|
||||
}
|
||||
}
|
||||
|
||||
static void write_normal_summaries(struct f2fs_sb_info *sbi,
|
||||
@ -1239,7 +1245,7 @@ static struct page *get_next_sit_page(struct f2fs_sb_info *sbi,
|
||||
/* get current sit block page without lock */
|
||||
src_page = get_meta_page(sbi, src_off);
|
||||
dst_page = grab_meta_page(sbi, dst_off);
|
||||
BUG_ON(PageDirty(src_page));
|
||||
f2fs_bug_on(PageDirty(src_page));
|
||||
|
||||
src_addr = page_address(src_page);
|
||||
dst_addr = page_address(dst_page);
|
||||
@ -1271,9 +1277,9 @@ static bool flush_sits_in_journal(struct f2fs_sb_info *sbi)
|
||||
__mark_sit_entry_dirty(sbi, segno);
|
||||
}
|
||||
update_sits_in_cursum(sum, -sits_in_cursum(sum));
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1637,6 +1643,7 @@ int build_segment_manager(struct f2fs_sb_info *sbi)
|
||||
sm_info->ovp_segments = le32_to_cpu(ckpt->overprov_segment_count);
|
||||
sm_info->main_segments = le32_to_cpu(raw_super->segment_count_main);
|
||||
sm_info->ssa_blkaddr = le32_to_cpu(raw_super->ssa_blkaddr);
|
||||
sm_info->rec_prefree_segments = DEF_RECLAIM_PREFREE_SEGMENTS;
|
||||
|
||||
err = build_sit_info(sbi);
|
||||
if (err)
|
||||
@ -1744,6 +1751,8 @@ static void destroy_sit_info(struct f2fs_sb_info *sbi)
|
||||
void destroy_segment_manager(struct f2fs_sb_info *sbi)
|
||||
{
|
||||
struct f2fs_sm_info *sm_info = SM_I(sbi);
|
||||
if (!sm_info)
|
||||
return;
|
||||
destroy_dirty_segmap(sbi);
|
||||
destroy_curseg(sbi);
|
||||
destroy_free_segmap(sbi);
|
||||
|
@ -14,6 +14,8 @@
|
||||
#define NULL_SEGNO ((unsigned int)(~0))
|
||||
#define NULL_SECNO ((unsigned int)(~0))
|
||||
|
||||
#define DEF_RECLAIM_PREFREE_SEGMENTS 100 /* 200MB of prefree segments */
|
||||
|
||||
/* L: Logical segment # in volume, R: Relative segment # in main area */
|
||||
#define GET_L2R_SEGNO(free_i, segno) (segno - free_i->start_segno)
|
||||
#define GET_R2L_SEGNO(free_i, segno) (segno + free_i->start_segno)
|
||||
@ -90,6 +92,8 @@
|
||||
(blk_addr << ((sbi)->log_blocksize - F2FS_LOG_SECTOR_SIZE))
|
||||
#define SECTOR_TO_BLOCK(sbi, sectors) \
|
||||
(sectors >> ((sbi)->log_blocksize - F2FS_LOG_SECTOR_SIZE))
|
||||
#define MAX_BIO_BLOCKS(max_hw_blocks) \
|
||||
(min((int)max_hw_blocks, BIO_MAX_PAGES))
|
||||
|
||||
/* during checkpoint, bio_private is used to synchronize the last bio */
|
||||
struct bio_private {
|
||||
@ -470,6 +474,11 @@ static inline bool has_not_enough_free_secs(struct f2fs_sb_info *sbi, int freed)
|
||||
reserved_sections(sbi)));
|
||||
}
|
||||
|
||||
static inline bool excess_prefree_segs(struct f2fs_sb_info *sbi)
|
||||
{
|
||||
return (prefree_segments(sbi) > SM_I(sbi)->rec_prefree_segments);
|
||||
}
|
||||
|
||||
static inline int utilization(struct f2fs_sb_info *sbi)
|
||||
{
|
||||
return div_u64((u64)valid_user_blocks(sbi) * 100, sbi->user_block_count);
|
||||
@ -513,16 +522,13 @@ static inline unsigned short curseg_blkoff(struct f2fs_sb_info *sbi, int type)
|
||||
return curseg->next_blkoff;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_F2FS_CHECK_FS
|
||||
static inline void check_seg_range(struct f2fs_sb_info *sbi, unsigned int segno)
|
||||
{
|
||||
unsigned int end_segno = SM_I(sbi)->segment_count - 1;
|
||||
BUG_ON(segno > end_segno);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is used for only debugging.
|
||||
* NOTE: In future, we have to remove this function.
|
||||
*/
|
||||
static inline void verify_block_addr(struct f2fs_sb_info *sbi, block_t blk_addr)
|
||||
{
|
||||
struct f2fs_sm_info *sm_info = SM_I(sbi);
|
||||
@ -541,8 +547,9 @@ static inline void check_block_count(struct f2fs_sb_info *sbi,
|
||||
{
|
||||
struct f2fs_sm_info *sm_info = SM_I(sbi);
|
||||
unsigned int end_segno = sm_info->segment_count - 1;
|
||||
bool is_valid = test_bit_le(0, raw_sit->valid_map) ? true : false;
|
||||
int valid_blocks = 0;
|
||||
int i;
|
||||
int cur_pos = 0, next_pos;
|
||||
|
||||
/* check segment usage */
|
||||
BUG_ON(GET_SIT_VBLOCKS(raw_sit) > sbi->blocks_per_seg);
|
||||
@ -551,11 +558,26 @@ static inline void check_block_count(struct f2fs_sb_info *sbi,
|
||||
BUG_ON(segno > end_segno);
|
||||
|
||||
/* check bitmap with valid block count */
|
||||
for (i = 0; i < sbi->blocks_per_seg; i++)
|
||||
if (f2fs_test_bit(i, raw_sit->valid_map))
|
||||
valid_blocks++;
|
||||
do {
|
||||
if (is_valid) {
|
||||
next_pos = find_next_zero_bit_le(&raw_sit->valid_map,
|
||||
sbi->blocks_per_seg,
|
||||
cur_pos);
|
||||
valid_blocks += next_pos - cur_pos;
|
||||
} else
|
||||
next_pos = find_next_bit_le(&raw_sit->valid_map,
|
||||
sbi->blocks_per_seg,
|
||||
cur_pos);
|
||||
cur_pos = next_pos;
|
||||
is_valid = !is_valid;
|
||||
} while (cur_pos < sbi->blocks_per_seg);
|
||||
BUG_ON(GET_SIT_VBLOCKS(raw_sit) != valid_blocks);
|
||||
}
|
||||
#else
|
||||
#define check_seg_range(sbi, segno)
|
||||
#define verify_block_addr(sbi, blk_addr)
|
||||
#define check_block_count(sbi, segno, raw_sit)
|
||||
#endif
|
||||
|
||||
static inline pgoff_t current_sit_addr(struct f2fs_sb_info *sbi,
|
||||
unsigned int start)
|
||||
|
143
fs/f2fs/super.c
143
fs/f2fs/super.c
@ -43,7 +43,9 @@ enum {
|
||||
Opt_disable_roll_forward,
|
||||
Opt_discard,
|
||||
Opt_noheap,
|
||||
Opt_user_xattr,
|
||||
Opt_nouser_xattr,
|
||||
Opt_acl,
|
||||
Opt_noacl,
|
||||
Opt_active_logs,
|
||||
Opt_disable_ext_identify,
|
||||
@ -56,7 +58,9 @@ static match_table_t f2fs_tokens = {
|
||||
{Opt_disable_roll_forward, "disable_roll_forward"},
|
||||
{Opt_discard, "discard"},
|
||||
{Opt_noheap, "no_heap"},
|
||||
{Opt_user_xattr, "user_xattr"},
|
||||
{Opt_nouser_xattr, "nouser_xattr"},
|
||||
{Opt_acl, "acl"},
|
||||
{Opt_noacl, "noacl"},
|
||||
{Opt_active_logs, "active_logs=%u"},
|
||||
{Opt_disable_ext_identify, "disable_ext_identify"},
|
||||
@ -65,24 +69,40 @@ static match_table_t f2fs_tokens = {
|
||||
};
|
||||
|
||||
/* Sysfs support for f2fs */
|
||||
enum {
|
||||
GC_THREAD, /* struct f2fs_gc_thread */
|
||||
SM_INFO, /* struct f2fs_sm_info */
|
||||
};
|
||||
|
||||
struct f2fs_attr {
|
||||
struct attribute attr;
|
||||
ssize_t (*show)(struct f2fs_attr *, struct f2fs_sb_info *, char *);
|
||||
ssize_t (*store)(struct f2fs_attr *, struct f2fs_sb_info *,
|
||||
const char *, size_t);
|
||||
int struct_type;
|
||||
int offset;
|
||||
};
|
||||
|
||||
static unsigned char *__struct_ptr(struct f2fs_sb_info *sbi, int struct_type)
|
||||
{
|
||||
if (struct_type == GC_THREAD)
|
||||
return (unsigned char *)sbi->gc_thread;
|
||||
else if (struct_type == SM_INFO)
|
||||
return (unsigned char *)SM_I(sbi);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static ssize_t f2fs_sbi_show(struct f2fs_attr *a,
|
||||
struct f2fs_sb_info *sbi, char *buf)
|
||||
{
|
||||
struct f2fs_gc_kthread *gc_kth = sbi->gc_thread;
|
||||
unsigned char *ptr = NULL;
|
||||
unsigned int *ui;
|
||||
|
||||
if (!gc_kth)
|
||||
ptr = __struct_ptr(sbi, a->struct_type);
|
||||
if (!ptr)
|
||||
return -EINVAL;
|
||||
|
||||
ui = (unsigned int *)(((char *)gc_kth) + a->offset);
|
||||
ui = (unsigned int *)(ptr + a->offset);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%u\n", *ui);
|
||||
}
|
||||
@ -91,15 +111,16 @@ static ssize_t f2fs_sbi_store(struct f2fs_attr *a,
|
||||
struct f2fs_sb_info *sbi,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct f2fs_gc_kthread *gc_kth = sbi->gc_thread;
|
||||
unsigned char *ptr;
|
||||
unsigned long t;
|
||||
unsigned int *ui;
|
||||
ssize_t ret;
|
||||
|
||||
if (!gc_kth)
|
||||
ptr = __struct_ptr(sbi, a->struct_type);
|
||||
if (!ptr)
|
||||
return -EINVAL;
|
||||
|
||||
ui = (unsigned int *)(((char *)gc_kth) + a->offset);
|
||||
ui = (unsigned int *)(ptr + a->offset);
|
||||
|
||||
ret = kstrtoul(skip_spaces(buf), 0, &t);
|
||||
if (ret < 0)
|
||||
@ -135,21 +156,25 @@ static void f2fs_sb_release(struct kobject *kobj)
|
||||
complete(&sbi->s_kobj_unregister);
|
||||
}
|
||||
|
||||
#define F2FS_ATTR_OFFSET(_name, _mode, _show, _store, _elname) \
|
||||
#define F2FS_ATTR_OFFSET(_struct_type, _name, _mode, _show, _store, _offset) \
|
||||
static struct f2fs_attr f2fs_attr_##_name = { \
|
||||
.attr = {.name = __stringify(_name), .mode = _mode }, \
|
||||
.show = _show, \
|
||||
.store = _store, \
|
||||
.offset = offsetof(struct f2fs_gc_kthread, _elname), \
|
||||
.struct_type = _struct_type, \
|
||||
.offset = _offset \
|
||||
}
|
||||
|
||||
#define F2FS_RW_ATTR(name, elname) \
|
||||
F2FS_ATTR_OFFSET(name, 0644, f2fs_sbi_show, f2fs_sbi_store, elname)
|
||||
#define F2FS_RW_ATTR(struct_type, struct_name, name, elname) \
|
||||
F2FS_ATTR_OFFSET(struct_type, name, 0644, \
|
||||
f2fs_sbi_show, f2fs_sbi_store, \
|
||||
offsetof(struct struct_name, elname))
|
||||
|
||||
F2FS_RW_ATTR(gc_min_sleep_time, min_sleep_time);
|
||||
F2FS_RW_ATTR(gc_max_sleep_time, max_sleep_time);
|
||||
F2FS_RW_ATTR(gc_no_gc_sleep_time, no_gc_sleep_time);
|
||||
F2FS_RW_ATTR(gc_idle, gc_idle);
|
||||
F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_min_sleep_time, min_sleep_time);
|
||||
F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_max_sleep_time, max_sleep_time);
|
||||
F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_no_gc_sleep_time, no_gc_sleep_time);
|
||||
F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_idle, gc_idle);
|
||||
F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, reclaim_segments, rec_prefree_segments);
|
||||
|
||||
#define ATTR_LIST(name) (&f2fs_attr_##name.attr)
|
||||
static struct attribute *f2fs_attrs[] = {
|
||||
@ -157,6 +182,7 @@ static struct attribute *f2fs_attrs[] = {
|
||||
ATTR_LIST(gc_max_sleep_time),
|
||||
ATTR_LIST(gc_no_gc_sleep_time),
|
||||
ATTR_LIST(gc_idle),
|
||||
ATTR_LIST(reclaim_segments),
|
||||
NULL,
|
||||
};
|
||||
|
||||
@ -237,6 +263,9 @@ static int parse_options(struct super_block *sb, char *options)
|
||||
set_opt(sbi, NOHEAP);
|
||||
break;
|
||||
#ifdef CONFIG_F2FS_FS_XATTR
|
||||
case Opt_user_xattr:
|
||||
set_opt(sbi, XATTR_USER);
|
||||
break;
|
||||
case Opt_nouser_xattr:
|
||||
clear_opt(sbi, XATTR_USER);
|
||||
break;
|
||||
@ -244,6 +273,10 @@ static int parse_options(struct super_block *sb, char *options)
|
||||
set_opt(sbi, INLINE_XATTR);
|
||||
break;
|
||||
#else
|
||||
case Opt_user_xattr:
|
||||
f2fs_msg(sb, KERN_INFO,
|
||||
"user_xattr options not supported");
|
||||
break;
|
||||
case Opt_nouser_xattr:
|
||||
f2fs_msg(sb, KERN_INFO,
|
||||
"nouser_xattr options not supported");
|
||||
@ -254,10 +287,16 @@ static int parse_options(struct super_block *sb, char *options)
|
||||
break;
|
||||
#endif
|
||||
#ifdef CONFIG_F2FS_FS_POSIX_ACL
|
||||
case Opt_acl:
|
||||
set_opt(sbi, POSIX_ACL);
|
||||
break;
|
||||
case Opt_noacl:
|
||||
clear_opt(sbi, POSIX_ACL);
|
||||
break;
|
||||
#else
|
||||
case Opt_acl:
|
||||
f2fs_msg(sb, KERN_INFO, "acl options not supported");
|
||||
break;
|
||||
case Opt_noacl:
|
||||
f2fs_msg(sb, KERN_INFO, "noacl options not supported");
|
||||
break;
|
||||
@ -355,7 +394,9 @@ static void f2fs_put_super(struct super_block *sb)
|
||||
f2fs_destroy_stats(sbi);
|
||||
stop_gc_thread(sbi);
|
||||
|
||||
write_checkpoint(sbi, true);
|
||||
/* We don't need to do checkpoint when it's clean */
|
||||
if (sbi->s_dirty && get_pages(sbi, F2FS_DIRTY_NODES))
|
||||
write_checkpoint(sbi, true);
|
||||
|
||||
iput(sbi->node_inode);
|
||||
iput(sbi->meta_inode);
|
||||
@ -727,30 +768,47 @@ static void init_sb_info(struct f2fs_sb_info *sbi)
|
||||
atomic_set(&sbi->nr_pages[i], 0);
|
||||
}
|
||||
|
||||
static int validate_superblock(struct super_block *sb,
|
||||
struct f2fs_super_block **raw_super,
|
||||
struct buffer_head **raw_super_buf, sector_t block)
|
||||
/*
|
||||
* Read f2fs raw super block.
|
||||
* Because we have two copies of super block, so read the first one at first,
|
||||
* if the first one is invalid, move to read the second one.
|
||||
*/
|
||||
static int read_raw_super_block(struct super_block *sb,
|
||||
struct f2fs_super_block **raw_super,
|
||||
struct buffer_head **raw_super_buf)
|
||||
{
|
||||
const char *super = (block == 0 ? "first" : "second");
|
||||
int block = 0;
|
||||
|
||||
/* read f2fs raw super block */
|
||||
retry:
|
||||
*raw_super_buf = sb_bread(sb, block);
|
||||
if (!*raw_super_buf) {
|
||||
f2fs_msg(sb, KERN_ERR, "unable to read %s superblock",
|
||||
super);
|
||||
return -EIO;
|
||||
f2fs_msg(sb, KERN_ERR, "Unable to read %dth superblock",
|
||||
block + 1);
|
||||
if (block == 0) {
|
||||
block++;
|
||||
goto retry;
|
||||
} else {
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
|
||||
*raw_super = (struct f2fs_super_block *)
|
||||
((char *)(*raw_super_buf)->b_data + F2FS_SUPER_OFFSET);
|
||||
|
||||
/* sanity checking of raw super */
|
||||
if (!sanity_check_raw_super(sb, *raw_super))
|
||||
return 0;
|
||||
if (sanity_check_raw_super(sb, *raw_super)) {
|
||||
brelse(*raw_super_buf);
|
||||
f2fs_msg(sb, KERN_ERR, "Can't find a valid F2FS filesystem "
|
||||
"in %dth superblock", block + 1);
|
||||
if(block == 0) {
|
||||
block++;
|
||||
goto retry;
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
f2fs_msg(sb, KERN_ERR, "Can't find a valid F2FS filesystem "
|
||||
"in %s superblock", super);
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
|
||||
@ -760,7 +818,6 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
|
||||
struct buffer_head *raw_super_buf;
|
||||
struct inode *root;
|
||||
long err = -EINVAL;
|
||||
int i;
|
||||
|
||||
/* allocate memory for f2fs-specific super block info */
|
||||
sbi = kzalloc(sizeof(struct f2fs_sb_info), GFP_KERNEL);
|
||||
@ -773,14 +830,10 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
|
||||
goto free_sbi;
|
||||
}
|
||||
|
||||
err = validate_superblock(sb, &raw_super, &raw_super_buf, 0);
|
||||
if (err) {
|
||||
brelse(raw_super_buf);
|
||||
/* check secondary superblock when primary failed */
|
||||
err = validate_superblock(sb, &raw_super, &raw_super_buf, 1);
|
||||
if (err)
|
||||
goto free_sb_buf;
|
||||
}
|
||||
err = read_raw_super_block(sb, &raw_super, &raw_super_buf);
|
||||
if (err)
|
||||
goto free_sbi;
|
||||
|
||||
sb->s_fs_info = sbi;
|
||||
/* init some FS parameters */
|
||||
sbi->active_logs = NR_CURSEG_TYPE;
|
||||
@ -818,12 +871,12 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
|
||||
mutex_init(&sbi->gc_mutex);
|
||||
mutex_init(&sbi->writepages);
|
||||
mutex_init(&sbi->cp_mutex);
|
||||
for (i = 0; i < NR_GLOBAL_LOCKS; i++)
|
||||
mutex_init(&sbi->fs_lock[i]);
|
||||
mutex_init(&sbi->node_write);
|
||||
sbi->por_doing = 0;
|
||||
sbi->por_doing = false;
|
||||
spin_lock_init(&sbi->stat_lock);
|
||||
init_rwsem(&sbi->bio_sem);
|
||||
init_rwsem(&sbi->cp_rwsem);
|
||||
init_waitqueue_head(&sbi->cp_wait);
|
||||
init_sb_info(sbi);
|
||||
|
||||
/* get an inode for meta space */
|
||||
@ -922,12 +975,12 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
|
||||
/* After POR, we can run background GC thread.*/
|
||||
err = start_gc_thread(sbi);
|
||||
if (err)
|
||||
goto fail;
|
||||
goto free_gc;
|
||||
}
|
||||
|
||||
err = f2fs_build_stats(sbi);
|
||||
if (err)
|
||||
goto fail;
|
||||
goto free_gc;
|
||||
|
||||
if (f2fs_proc_root)
|
||||
sbi->s_proc = proc_mkdir(sb->s_id, f2fs_proc_root);
|
||||
@ -953,6 +1006,12 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
|
||||
|
||||
return 0;
|
||||
fail:
|
||||
if (sbi->s_proc) {
|
||||
remove_proc_entry("segment_info", sbi->s_proc);
|
||||
remove_proc_entry(sb->s_id, f2fs_proc_root);
|
||||
}
|
||||
f2fs_destroy_stats(sbi);
|
||||
free_gc:
|
||||
stop_gc_thread(sbi);
|
||||
free_root_inode:
|
||||
dput(sb->s_root);
|
||||
|
@ -154,6 +154,9 @@ static int f2fs_xattr_advise_set(struct dentry *dentry, const char *name,
|
||||
}
|
||||
|
||||
#ifdef CONFIG_F2FS_FS_SECURITY
|
||||
static int __f2fs_setxattr(struct inode *inode, int name_index,
|
||||
const char *name, const void *value, size_t value_len,
|
||||
struct page *ipage);
|
||||
static int f2fs_initxattrs(struct inode *inode, const struct xattr *xattr_array,
|
||||
void *page)
|
||||
{
|
||||
@ -161,7 +164,7 @@ static int f2fs_initxattrs(struct inode *inode, const struct xattr *xattr_array,
|
||||
int err = 0;
|
||||
|
||||
for (xattr = xattr_array; xattr->name != NULL; xattr++) {
|
||||
err = f2fs_setxattr(inode, F2FS_XATTR_INDEX_SECURITY,
|
||||
err = __f2fs_setxattr(inode, F2FS_XATTR_INDEX_SECURITY,
|
||||
xattr->name, xattr->value,
|
||||
xattr->value_len, (struct page *)page);
|
||||
if (err < 0)
|
||||
@ -369,7 +372,7 @@ static inline int write_all_xattrs(struct inode *inode, __u32 hsize,
|
||||
alloc_nid_failed(sbi, new_nid);
|
||||
return PTR_ERR(xpage);
|
||||
}
|
||||
BUG_ON(new_nid);
|
||||
f2fs_bug_on(new_nid);
|
||||
} else {
|
||||
struct dnode_of_data dn;
|
||||
set_new_dnode(&dn, inode, NULL, NULL, new_nid);
|
||||
@ -469,16 +472,15 @@ ssize_t f2fs_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size)
|
||||
return error;
|
||||
}
|
||||
|
||||
int f2fs_setxattr(struct inode *inode, int name_index, const char *name,
|
||||
const void *value, size_t value_len, struct page *ipage)
|
||||
static int __f2fs_setxattr(struct inode *inode, int name_index,
|
||||
const char *name, const void *value, size_t value_len,
|
||||
struct page *ipage)
|
||||
{
|
||||
struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
|
||||
struct f2fs_inode_info *fi = F2FS_I(inode);
|
||||
struct f2fs_xattr_entry *here, *last;
|
||||
void *base_addr;
|
||||
int found, newsize;
|
||||
size_t name_len;
|
||||
int ilock;
|
||||
__u32 new_hsize;
|
||||
int error = -ENOMEM;
|
||||
|
||||
@ -493,10 +495,6 @@ int f2fs_setxattr(struct inode *inode, int name_index, const char *name,
|
||||
if (name_len > F2FS_NAME_LEN || value_len > MAX_VALUE_LEN(inode))
|
||||
return -ERANGE;
|
||||
|
||||
f2fs_balance_fs(sbi);
|
||||
|
||||
ilock = mutex_lock_op(sbi);
|
||||
|
||||
base_addr = read_all_xattrs(inode, ipage);
|
||||
if (!base_addr)
|
||||
goto exit;
|
||||
@ -522,7 +520,7 @@ int f2fs_setxattr(struct inode *inode, int name_index, const char *name,
|
||||
*/
|
||||
free = MIN_OFFSET(inode) - ((char *)last - (char *)base_addr);
|
||||
if (found)
|
||||
free = free - ENTRY_SIZE(here);
|
||||
free = free + ENTRY_SIZE(here);
|
||||
|
||||
if (free < newsize) {
|
||||
error = -ENOSPC;
|
||||
@ -578,7 +576,21 @@ int f2fs_setxattr(struct inode *inode, int name_index, const char *name,
|
||||
else
|
||||
update_inode_page(inode);
|
||||
exit:
|
||||
mutex_unlock_op(sbi, ilock);
|
||||
kzfree(base_addr);
|
||||
return error;
|
||||
}
|
||||
|
||||
int f2fs_setxattr(struct inode *inode, int name_index, const char *name,
|
||||
const void *value, size_t value_len, struct page *ipage)
|
||||
{
|
||||
struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
|
||||
int err;
|
||||
|
||||
f2fs_balance_fs(sbi);
|
||||
|
||||
f2fs_lock_op(sbi);
|
||||
err = __f2fs_setxattr(inode, name_index, name, value, value_len, ipage);
|
||||
f2fs_unlock_op(sbi);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
@ -36,6 +36,11 @@
|
||||
{ CURSEG_COLD_NODE, "Cold NODE" }, \
|
||||
{ NO_CHECK_TYPE, "No TYPE" })
|
||||
|
||||
#define show_file_type(type) \
|
||||
__print_symbolic(type, \
|
||||
{ 0, "FILE" }, \
|
||||
{ 1, "DIR" })
|
||||
|
||||
#define show_gc_type(type) \
|
||||
__print_symbolic(type, \
|
||||
{ FG_GC, "Foreground GC" }, \
|
||||
@ -623,6 +628,52 @@ TRACE_EVENT(f2fs_do_submit_bio,
|
||||
__entry->size)
|
||||
);
|
||||
|
||||
DECLARE_EVENT_CLASS(f2fs__page,
|
||||
|
||||
TP_PROTO(struct page *page, int type),
|
||||
|
||||
TP_ARGS(page, type),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__field(dev_t, dev)
|
||||
__field(ino_t, ino)
|
||||
__field(int, type)
|
||||
__field(int, dir)
|
||||
__field(pgoff_t, index)
|
||||
__field(int, dirty)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->dev = page->mapping->host->i_sb->s_dev;
|
||||
__entry->ino = page->mapping->host->i_ino;
|
||||
__entry->type = type;
|
||||
__entry->dir = S_ISDIR(page->mapping->host->i_mode);
|
||||
__entry->index = page->index;
|
||||
__entry->dirty = PageDirty(page);
|
||||
),
|
||||
|
||||
TP_printk("dev = (%d,%d), ino = %lu, %s, %s, index = %lu, dirty = %d",
|
||||
show_dev_ino(__entry),
|
||||
show_block_type(__entry->type),
|
||||
show_file_type(__entry->dir),
|
||||
(unsigned long)__entry->index,
|
||||
__entry->dirty)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(f2fs__page, f2fs_set_page_dirty,
|
||||
|
||||
TP_PROTO(struct page *page, int type),
|
||||
|
||||
TP_ARGS(page, type)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(f2fs__page, f2fs_vm_page_mkwrite,
|
||||
|
||||
TP_PROTO(struct page *page, int type),
|
||||
|
||||
TP_ARGS(page, type)
|
||||
);
|
||||
|
||||
TRACE_EVENT(f2fs_submit_write_page,
|
||||
|
||||
TP_PROTO(struct page *page, block_t blk_addr, int type),
|
||||
|
Loading…
Reference in New Issue
Block a user