Commit dd1d1399 authored by Linus Torvalds's avatar Linus Torvalds

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
  ...
parents a9986464 29e59c14
...@@ -119,6 +119,7 @@ active_logs=%u Support configuring the number of active logs. In the ...@@ -119,6 +119,7 @@ active_logs=%u Support configuring the number of active logs. In the
Default number is 6. Default number is 6.
disable_ext_identify Disable the extension list configured by mkfs, so f2fs disable_ext_identify Disable the extension list configured by mkfs, so f2fs
does not aware of cold files such as media files. does not aware of cold files such as media files.
inline_xattr Enable the inline xattrs feature.
================================================================================ ================================================================================
DEBUGFS ENTRIES DEBUGFS ENTRIES
...@@ -164,6 +165,12 @@ Files in /sys/fs/f2fs/<devname> ...@@ -164,6 +165,12 @@ Files in /sys/fs/f2fs/<devname>
gc_idle = 1 will select the Cost Benefit approach gc_idle = 1 will select the Cost Benefit approach
& setting gc_idle = 2 will select the greedy aproach. & 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 USAGE
================================================================================ ================================================================================
......
...@@ -63,3 +63,11 @@ config F2FS_FS_SECURITY ...@@ -63,3 +63,11 @@ config F2FS_FS_SECURITY
the extended attribute support in advance. the extended attribute support in advance.
If you are not using a security module, say N. 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) ...@@ -205,7 +205,8 @@ struct posix_acl *f2fs_get_acl(struct inode *inode, int type)
return acl; 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_sb_info *sbi = F2FS_SB(inode->i_sb);
struct f2fs_inode_info *fi = F2FS_I(inode); 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) ...@@ -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); kfree(value);
if (!error) if (!error)
...@@ -260,10 +261,10 @@ static int f2fs_set_acl(struct inode *inode, int type, struct posix_acl *acl) ...@@ -260,10 +261,10 @@ static int f2fs_set_acl(struct inode *inode, int type, struct posix_acl *acl)
return error; 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 f2fs_sb_info *sbi = F2FS_SB(dir->i_sb);
struct posix_acl *acl = NULL;
int error = 0; int error = 0;
if (!S_ISLNK(inode->i_mode)) { if (!S_ISLNK(inode->i_mode)) {
...@@ -276,10 +277,11 @@ int f2fs_init_acl(struct inode *inode, struct inode *dir) ...@@ -276,10 +277,11 @@ int f2fs_init_acl(struct inode *inode, struct inode *dir)
inode->i_mode &= ~current_umask(); 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)) { if (S_ISDIR(inode->i_mode)) {
error = f2fs_set_acl(inode, ACL_TYPE_DEFAULT, acl); error = f2fs_set_acl(inode, ACL_TYPE_DEFAULT, acl, ipage);
if (error) if (error)
goto cleanup; goto cleanup;
} }
...@@ -287,8 +289,7 @@ int f2fs_init_acl(struct inode *inode, struct inode *dir) ...@@ -287,8 +289,7 @@ int f2fs_init_acl(struct inode *inode, struct inode *dir)
if (error < 0) if (error < 0)
return error; return error;
if (error > 0) if (error > 0)
error = f2fs_set_acl(inode, ACL_TYPE_ACCESS, acl); error = f2fs_set_acl(inode, ACL_TYPE_ACCESS, acl, ipage);
}
cleanup: cleanup:
posix_acl_release(acl); posix_acl_release(acl);
return error; return error;
...@@ -313,7 +314,8 @@ int f2fs_acl_chmod(struct inode *inode) ...@@ -313,7 +314,8 @@ int f2fs_acl_chmod(struct inode *inode)
error = posix_acl_chmod(&acl, GFP_KERNEL, mode); error = posix_acl_chmod(&acl, GFP_KERNEL, mode);
if (error) if (error)
return 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); posix_acl_release(acl);
return error; return error;
} }
...@@ -388,7 +390,7 @@ static int f2fs_xattr_set_acl(struct dentry *dentry, const char *name, ...@@ -388,7 +390,7 @@ static int f2fs_xattr_set_acl(struct dentry *dentry, const char *name,
acl = NULL; acl = NULL;
} }
error = f2fs_set_acl(inode, type, acl); error = f2fs_set_acl(inode, type, acl, NULL);
release_and_out: release_and_out:
posix_acl_release(acl); posix_acl_release(acl);
......
...@@ -36,9 +36,9 @@ struct f2fs_acl_header { ...@@ -36,9 +36,9 @@ struct f2fs_acl_header {
#ifdef CONFIG_F2FS_FS_POSIX_ACL #ifdef CONFIG_F2FS_FS_POSIX_ACL
extern struct posix_acl *f2fs_get_acl(struct inode *inode, int type); extern struct posix_acl *f2fs_get_acl(struct inode *, int);
extern int f2fs_acl_chmod(struct inode *inode); extern int f2fs_acl_chmod(struct inode *);
extern int f2fs_init_acl(struct inode *inode, struct inode *dir); extern int f2fs_init_acl(struct inode *, struct inode *, struct page *);
#else #else
#define f2fs_check_acl NULL #define f2fs_check_acl NULL
#define f2fs_get_acl NULL #define f2fs_get_acl NULL
...@@ -49,7 +49,8 @@ static inline int f2fs_acl_chmod(struct inode *inode) ...@@ -49,7 +49,8 @@ static inline int f2fs_acl_chmod(struct inode *inode)
return 0; 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; return 0;
} }
......
...@@ -81,7 +81,7 @@ static int f2fs_write_meta_page(struct page *page, ...@@ -81,7 +81,7 @@ static int f2fs_write_meta_page(struct page *page,
struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
/* Should not write any meta pages, if any IO error was occurred */ /* 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)) { is_set_ckpt_flags(F2FS_CKPT(sbi), CP_ERROR_FLAG)) {
dec_page_count(sbi, F2FS_DIRTY_META); dec_page_count(sbi, F2FS_DIRTY_META);
wbc->pages_skipped++; wbc->pages_skipped++;
...@@ -142,8 +142,8 @@ long sync_meta_pages(struct f2fs_sb_info *sbi, enum page_type type, ...@@ -142,8 +142,8 @@ long sync_meta_pages(struct f2fs_sb_info *sbi, enum page_type type,
for (i = 0; i < nr_pages; i++) { for (i = 0; i < nr_pages; i++) {
struct page *page = pvec.pages[i]; struct page *page = pvec.pages[i];
lock_page(page); lock_page(page);
BUG_ON(page->mapping != mapping); f2fs_bug_on(page->mapping != mapping);
BUG_ON(!PageDirty(page)); f2fs_bug_on(!PageDirty(page));
clear_page_dirty_for_io(page); clear_page_dirty_for_io(page);
if (f2fs_write_meta_page(page, &wbc)) { if (f2fs_write_meta_page(page, &wbc)) {
unlock_page(page); unlock_page(page);
...@@ -167,6 +167,8 @@ static int f2fs_set_meta_page_dirty(struct page *page) ...@@ -167,6 +167,8 @@ static int f2fs_set_meta_page_dirty(struct page *page)
struct address_space *mapping = page->mapping; struct address_space *mapping = page->mapping;
struct f2fs_sb_info *sbi = F2FS_SB(mapping->host->i_sb); struct f2fs_sb_info *sbi = F2FS_SB(mapping->host->i_sb);
trace_f2fs_set_page_dirty(page, META);
SetPageUptodate(page); SetPageUptodate(page);
if (!PageDirty(page)) { if (!PageDirty(page)) {
__set_page_dirty_nobuffers(page); __set_page_dirty_nobuffers(page);
...@@ -206,6 +208,7 @@ int acquire_orphan_inode(struct f2fs_sb_info *sbi) ...@@ -206,6 +208,7 @@ int acquire_orphan_inode(struct f2fs_sb_info *sbi)
void release_orphan_inode(struct f2fs_sb_info *sbi) void release_orphan_inode(struct f2fs_sb_info *sbi)
{ {
mutex_lock(&sbi->orphan_inode_mutex); mutex_lock(&sbi->orphan_inode_mutex);
f2fs_bug_on(sbi->n_orphans == 0);
sbi->n_orphans--; sbi->n_orphans--;
mutex_unlock(&sbi->orphan_inode_mutex); mutex_unlock(&sbi->orphan_inode_mutex);
} }
...@@ -225,12 +228,8 @@ void add_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino) ...@@ -225,12 +228,8 @@ void add_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino)
break; break;
orphan = NULL; orphan = NULL;
} }
retry:
new = kmem_cache_alloc(orphan_entry_slab, GFP_ATOMIC); new = f2fs_kmem_cache_alloc(orphan_entry_slab, GFP_ATOMIC);
if (!new) {
cond_resched();
goto retry;
}
new->ino = ino; new->ino = ino;
/* add new_oentry into list which is sorted by inode number */ /* 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) ...@@ -253,6 +252,7 @@ void remove_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino)
if (orphan->ino == ino) { if (orphan->ino == ino) {
list_del(&orphan->list); list_del(&orphan->list);
kmem_cache_free(orphan_entry_slab, orphan); kmem_cache_free(orphan_entry_slab, orphan);
f2fs_bug_on(sbi->n_orphans == 0);
sbi->n_orphans--; sbi->n_orphans--;
break; break;
} }
...@@ -263,7 +263,7 @@ void remove_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino) ...@@ -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) static void recover_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino)
{ {
struct inode *inode = f2fs_iget(sbi->sb, ino); struct inode *inode = f2fs_iget(sbi->sb, ino);
BUG_ON(IS_ERR(inode)); f2fs_bug_on(IS_ERR(inode));
clear_nlink(inode); clear_nlink(inode);
/* truncate all the data during iput */ /* truncate all the data during iput */
...@@ -277,7 +277,7 @@ int recover_orphan_inodes(struct f2fs_sb_info *sbi) ...@@ -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)) if (!is_set_ckpt_flags(F2FS_CKPT(sbi), CP_ORPHAN_PRESENT_FLAG))
return 0; return 0;
sbi->por_doing = 1; sbi->por_doing = true;
start_blk = __start_cp_addr(sbi) + 1; start_blk = __start_cp_addr(sbi) + 1;
orphan_blkaddr = __start_sum_addr(sbi) - 1; orphan_blkaddr = __start_sum_addr(sbi) - 1;
...@@ -294,7 +294,7 @@ int recover_orphan_inodes(struct f2fs_sb_info *sbi) ...@@ -294,7 +294,7 @@ int recover_orphan_inodes(struct f2fs_sb_info *sbi)
} }
/* clear Orphan Flag */ /* clear Orphan Flag */
clear_ckpt_flags(F2FS_CKPT(sbi), CP_ORPHAN_PRESENT_FLAG); clear_ckpt_flags(F2FS_CKPT(sbi), CP_ORPHAN_PRESENT_FLAG);
sbi->por_doing = 0; sbi->por_doing = false;
return 0; return 0;
} }
...@@ -469,9 +469,7 @@ static int __add_dirty_inode(struct inode *inode, struct dir_inode_entry *new) ...@@ -469,9 +469,7 @@ static int __add_dirty_inode(struct inode *inode, struct dir_inode_entry *new)
return -EEXIST; return -EEXIST;
} }
list_add_tail(&new->list, head); list_add_tail(&new->list, head);
#ifdef CONFIG_F2FS_STAT_FS stat_inc_dirty_dir(sbi);
sbi->n_dirty_dirs++;
#endif
return 0; return 0;
} }
...@@ -482,12 +480,8 @@ void set_dirty_dir_page(struct inode *inode, struct page *page) ...@@ -482,12 +480,8 @@ void set_dirty_dir_page(struct inode *inode, struct page *page)
if (!S_ISDIR(inode->i_mode)) if (!S_ISDIR(inode->i_mode))
return; return;
retry:
new = kmem_cache_alloc(inode_entry_slab, GFP_NOFS); new = f2fs_kmem_cache_alloc(inode_entry_slab, GFP_NOFS);
if (!new) {
cond_resched();
goto retry;
}
new->inode = inode; new->inode = inode;
INIT_LIST_HEAD(&new->list); INIT_LIST_HEAD(&new->list);
...@@ -504,13 +498,9 @@ void set_dirty_dir_page(struct inode *inode, struct page *page) ...@@ -504,13 +498,9 @@ void set_dirty_dir_page(struct inode *inode, struct page *page)
void add_dirty_dir_inode(struct inode *inode) void add_dirty_dir_inode(struct inode *inode)
{ {
struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
struct dir_inode_entry *new; struct dir_inode_entry *new =
retry: f2fs_kmem_cache_alloc(inode_entry_slab, GFP_NOFS);
new = kmem_cache_alloc(inode_entry_slab, GFP_NOFS);
if (!new) {
cond_resched();
goto retry;
}
new->inode = inode; new->inode = inode;
INIT_LIST_HEAD(&new->list); INIT_LIST_HEAD(&new->list);
...@@ -541,9 +531,7 @@ void remove_dirty_dir_inode(struct inode *inode) ...@@ -541,9 +531,7 @@ void remove_dirty_dir_inode(struct inode *inode)
if (entry->inode == inode) { if (entry->inode == inode) {
list_del(&entry->list); list_del(&entry->list);
kmem_cache_free(inode_entry_slab, entry); kmem_cache_free(inode_entry_slab, entry);
#ifdef CONFIG_F2FS_STAT_FS stat_dec_dirty_dir(sbi);
sbi->n_dirty_dirs--;
#endif
break; break;
} }
} }
...@@ -617,11 +605,10 @@ static void block_operations(struct f2fs_sb_info *sbi) ...@@ -617,11 +605,10 @@ static void block_operations(struct f2fs_sb_info *sbi)
blk_start_plug(&plug); blk_start_plug(&plug);
retry_flush_dents: retry_flush_dents:
mutex_lock_all(sbi); f2fs_lock_all(sbi);
/* write all the dirty dentry pages */ /* write all the dirty dentry pages */
if (get_pages(sbi, F2FS_DIRTY_DENTS)) { if (get_pages(sbi, F2FS_DIRTY_DENTS)) {
mutex_unlock_all(sbi); f2fs_unlock_all(sbi);
sync_dirty_dir_inodes(sbi); sync_dirty_dir_inodes(sbi);
goto retry_flush_dents; goto retry_flush_dents;
} }
...@@ -644,7 +631,22 @@ static void block_operations(struct f2fs_sb_info *sbi) ...@@ -644,7 +631,22 @@ static void block_operations(struct f2fs_sb_info *sbi)
static void unblock_operations(struct f2fs_sb_info *sbi) static void unblock_operations(struct f2fs_sb_info *sbi)
{ {
mutex_unlock(&sbi->node_write); 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) 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) ...@@ -756,8 +758,7 @@ static void do_checkpoint(struct f2fs_sb_info *sbi, bool is_umount)
f2fs_put_page(cp_page, 1); f2fs_put_page(cp_page, 1);
/* wait for previous submitted node/meta pages writeback */ /* wait for previous submitted node/meta pages writeback */
while (get_pages(sbi, F2FS_WRITEBACK)) wait_on_all_pages_writeback(sbi);
congestion_wait(BLK_RW_ASYNC, HZ / 50);
filemap_fdatawait_range(sbi->node_inode->i_mapping, 0, LONG_MAX); filemap_fdatawait_range(sbi->node_inode->i_mapping, 0, LONG_MAX);
filemap_fdatawait_range(sbi->meta_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, ...@@ -68,9 +68,6 @@ static int check_extent_cache(struct inode *inode, pgoff_t pgofs,
struct buffer_head *bh_result) struct buffer_head *bh_result)
{ {
struct f2fs_inode_info *fi = F2FS_I(inode); 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; pgoff_t start_fofs, end_fofs;
block_t start_blkaddr; block_t start_blkaddr;
...@@ -80,9 +77,8 @@ static int check_extent_cache(struct inode *inode, pgoff_t pgofs, ...@@ -80,9 +77,8 @@ static int check_extent_cache(struct inode *inode, pgoff_t pgofs,
return 0; return 0;
} }
#ifdef CONFIG_F2FS_STAT_FS stat_inc_total_hit(inode->i_sb);
sbi->total_hit_ext++;
#endif
start_fofs = fi->ext.fofs; start_fofs = fi->ext.fofs;
end_fofs = fi->ext.fofs + fi->ext.len - 1; end_fofs = fi->ext.fofs + fi->ext.len - 1;
start_blkaddr = fi->ext.blk_addr; start_blkaddr = fi->ext.blk_addr;
...@@ -100,9 +96,7 @@ static int check_extent_cache(struct inode *inode, pgoff_t pgofs, ...@@ -100,9 +96,7 @@ static int check_extent_cache(struct inode *inode, pgoff_t pgofs,
else else
bh_result->b_size = UINT_MAX; bh_result->b_size = UINT_MAX;
#ifdef CONFIG_F2FS_STAT_FS stat_inc_read_hit(inode->i_sb);
sbi->read_hit_ext++;
#endif
read_unlock(&fi->ext.ext_lock); read_unlock(&fi->ext.ext_lock);
return 1; return 1;
} }
...@@ -116,7 +110,7 @@ void update_extent_cache(block_t blk_addr, struct dnode_of_data *dn) ...@@ -116,7 +110,7 @@ void update_extent_cache(block_t blk_addr, struct dnode_of_data *dn)
pgoff_t fofs, start_fofs, end_fofs; pgoff_t fofs, start_fofs, end_fofs;
block_t start_blkaddr, end_blkaddr; 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) + fofs = start_bidx_of_node(ofs_of_node(dn->node_page), fi) +
dn->ofs_in_node; dn->ofs_in_node;
...@@ -442,7 +436,7 @@ static int get_data_block_ro(struct inode *inode, sector_t iblock, ...@@ -442,7 +436,7 @@ static int get_data_block_ro(struct inode *inode, sector_t iblock,
} }
/* It does not support data allocation */ /* It does not support data allocation */
BUG_ON(create); f2fs_bug_on(create);
if (dn.data_blkaddr != NEW_ADDR && dn.data_blkaddr != NULL_ADDR) { if (dn.data_blkaddr != NEW_ADDR && dn.data_blkaddr != NULL_ADDR) {
int i; int i;
...@@ -560,9 +554,9 @@ static int f2fs_write_data_page(struct page *page, ...@@ -560,9 +554,9 @@ static int f2fs_write_data_page(struct page *page,
inode_dec_dirty_dents(inode); inode_dec_dirty_dents(inode);
err = do_write_data_page(page); err = do_write_data_page(page);
} else { } else {
int ilock = mutex_lock_op(sbi); f2fs_lock_op(sbi);
err = do_write_data_page(page); err = do_write_data_page(page);
mutex_unlock_op(sbi, ilock); f2fs_unlock_op(sbi);
need_balance_fs = true; need_balance_fs = true;
} }
if (err == -ENOENT) if (err == -ENOENT)
...@@ -641,7 +635,6 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping, ...@@ -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; pgoff_t index = ((unsigned long long) pos) >> PAGE_CACHE_SHIFT;
struct dnode_of_data dn; struct dnode_of_data dn;
int err = 0; int err = 0;
int ilock;
f2fs_balance_fs(sbi); f2fs_balance_fs(sbi);
repeat: repeat:
...@@ -650,7 +643,7 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping, ...@@ -650,7 +643,7 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping,
return -ENOMEM; return -ENOMEM;
*pagep = page; *pagep = page;
ilock = mutex_lock_op(sbi); f2fs_lock_op(sbi);
set_new_dnode(&dn, inode, NULL, NULL, 0); set_new_dnode(&dn, inode, NULL, NULL, 0);
err = get_dnode_of_data(&dn, index, ALLOC_NODE); 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, ...@@ -664,7 +657,7 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping,
if (err) if (err)
goto err; goto err;
mutex_unlock_op(sbi, ilock); f2fs_unlock_op(sbi);
if ((len == PAGE_CACHE_SIZE) || PageUptodate(page)) if ((len == PAGE_CACHE_SIZE) || PageUptodate(page))
return 0; return 0;
...@@ -700,7 +693,7 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping, ...@@ -700,7 +693,7 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping,
return 0; return 0;
err: err:
mutex_unlock_op(sbi, ilock); f2fs_unlock_op(sbi);
f2fs_put_page(page, 1); f2fs_put_page(page, 1);
return err; return err;
} }
...@@ -763,6 +756,8 @@ static int f2fs_set_data_page_dirty(struct page *page) ...@@ -763,6 +756,8 @@ static int f2fs_set_data_page_dirty(struct page *page)
struct address_space *mapping = page->mapping; struct address_space *mapping = page->mapping;
struct inode *inode = mapping->host; struct inode *inode = mapping->host;
trace_f2fs_set_page_dirty(page, DATA);
SetPageUptodate(page); SetPageUptodate(page);
if (!PageDirty(page)) { if (!PageDirty(page)) {
__set_page_dirty_nobuffers(page); __set_page_dirty_nobuffers(page);
......
...@@ -139,7 +139,7 @@ static struct f2fs_dir_entry *find_in_level(struct inode *dir, ...@@ -139,7 +139,7 @@ static struct f2fs_dir_entry *find_in_level(struct inode *dir,
bool room = false; bool room = false;
int max_slots = 0; int max_slots = 0;
BUG_ON(level > MAX_DIR_HASH_DEPTH); f2fs_bug_on(level > MAX_DIR_HASH_DEPTH);
nbucket = dir_buckets(level); nbucket = dir_buckets(level);
nblock = bucket_blocks(level); nblock = bucket_blocks(level);
...@@ -346,7 +346,7 @@ static struct page *init_inode_metadata(struct inode *inode, ...@@ -346,7 +346,7 @@ static struct page *init_inode_metadata(struct inode *inode,
goto error; goto error;
} }
err = f2fs_init_acl(inode, dir); err = f2fs_init_acl(inode, dir, page);
if (err) if (err)
goto error; goto error;
......
...@@ -18,6 +18,13 @@ ...@@ -18,6 +18,13 @@
#include <linux/crc32.h> #include <linux/crc32.h>
#include <linux/magic.h> #include <linux/magic.h>
#include <linux/kobject.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 * For mount options
...@@ -298,6 +305,9 @@ struct f2fs_sm_info { ...@@ -298,6 +305,9 @@ struct f2fs_sm_info {
unsigned int main_segments; /* # of segments in main area */ unsigned int main_segments; /* # of segments in main area */
unsigned int reserved_segments; /* # of reserved segments */ unsigned int reserved_segments; /* # of reserved segments */
unsigned int ovp_segments; /* # of overprovision 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 { ...@@ -317,14 +327,6 @@ enum count_type {
NR_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 below are the page types of bios used in submti_bio().
* The available types are: * The available types are:
...@@ -365,12 +367,12 @@ struct f2fs_sb_info { ...@@ -365,12 +367,12 @@ struct f2fs_sb_info {
struct f2fs_checkpoint *ckpt; /* raw checkpoint pointer */ struct f2fs_checkpoint *ckpt; /* raw checkpoint pointer */
struct inode *meta_inode; /* cache meta blocks */ struct inode *meta_inode; /* cache meta blocks */
struct mutex cp_mutex; /* checkpoint procedure lock */ 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 node_write; /* locking node writes */
struct mutex writepages; /* mutex for writepages() */ struct mutex writepages; /* mutex for writepages() */
unsigned char next_lock_num; /* round-robin global locks */ bool por_doing; /* recovery is doing or not */
int por_doing; /* recovery is doing or not */ bool on_build_free_nids; /* build_free_nids is doing */
int on_build_free_nids; /* build_free_nids is doing */ wait_queue_head_t cp_wait;
/* for orphan inode management */ /* for orphan inode management */
struct list_head orphan_inode_list; /* orphan inode list */ 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) ...@@ -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); 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; down_read(&sbi->cp_rwsem);
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);
}
} }
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; up_read(&sbi->cp_rwsem);
for (; i < NR_GLOBAL_LOCKS; i++)
mutex_unlock(&sbi->fs_lock[i]);
} }
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; down_write_nest_lock(&sbi->cp_rwsem, &sbi->cp_mutex);
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;
} }
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) up_write(&sbi->cp_rwsem);
return;
BUG_ON(ilock >= NR_GLOBAL_LOCKS);
mutex_unlock(&sbi->fs_lock[ilock]);
} }
/* /*
...@@ -612,8 +590,8 @@ static inline int dec_valid_block_count(struct f2fs_sb_info *sbi, ...@@ -612,8 +590,8 @@ static inline int dec_valid_block_count(struct f2fs_sb_info *sbi,
blkcnt_t count) blkcnt_t count)
{ {
spin_lock(&sbi->stat_lock); spin_lock(&sbi->stat_lock);
BUG_ON(sbi->total_valid_block_count < (block_t) count); f2fs_bug_on(sbi->total_valid_block_count < (block_t) count);
BUG_ON(inode->i_blocks < count); f2fs_bug_on(inode->i_blocks < count);
inode->i_blocks -= count; inode->i_blocks -= count;
sbi->total_valid_block_count -= (block_t)count; sbi->total_valid_block_count -= (block_t)count;
spin_unlock(&sbi->stat_lock); spin_unlock(&sbi->stat_lock);
...@@ -745,9 +723,9 @@ static inline void dec_valid_node_count(struct f2fs_sb_info *sbi, ...@@ -745,9 +723,9 @@ static inline void dec_valid_node_count(struct f2fs_sb_info *sbi,
{ {
spin_lock(&sbi->stat_lock); spin_lock(&sbi->stat_lock);
BUG_ON(sbi->total_valid_block_count < count); f2fs_bug_on(sbi->total_valid_block_count < count);
BUG_ON(sbi->total_valid_node_count < count); f2fs_bug_on(sbi->total_valid_node_count < count);
BUG_ON(inode->i_blocks < count); f2fs_bug_on(inode->i_blocks < count);
inode->i_blocks -= count; inode->i_blocks -= count;
sbi->total_valid_node_count -= count; sbi->total_valid_node_count -= count;
...@@ -768,7 +746,7 @@ static inline unsigned int valid_node_count(struct f2fs_sb_info *sbi) ...@@ -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) static inline void inc_valid_inode_count(struct f2fs_sb_info *sbi)
{ {
spin_lock(&sbi->stat_lock); 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++; sbi->total_valid_inode_count++;
spin_unlock(&sbi->stat_lock); spin_unlock(&sbi->stat_lock);
} }
...@@ -776,7 +754,7 @@ static inline void inc_valid_inode_count(struct f2fs_sb_info *sbi) ...@@ -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) static inline int dec_valid_inode_count(struct f2fs_sb_info *sbi)
{ {
spin_lock(&sbi->stat_lock); 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--; sbi->total_valid_inode_count--;
spin_unlock(&sbi->stat_lock); spin_unlock(&sbi->stat_lock);
return 0; return 0;
...@@ -797,7 +775,7 @@ static inline void f2fs_put_page(struct page *page, int unlock) ...@@ -797,7 +775,7 @@ static inline void f2fs_put_page(struct page *page, int unlock)
return; return;
if (unlock) { if (unlock) {
BUG_ON(!PageLocked(page)); f2fs_bug_on(!PageLocked(page));
unlock_page(page); unlock_page(page);
} }
page_cache_release(page); page_cache_release(page);
...@@ -819,6 +797,20 @@ static inline struct kmem_cache *f2fs_kmem_cache_create(const char *name, ...@@ -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); 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) #define RAW_IS_INODE(p) ((p)->footer.nid == (p)->footer.ino)
static inline bool IS_INODE(struct page *page) static inline bool IS_INODE(struct page *page)
...@@ -979,6 +971,7 @@ long f2fs_compat_ioctl(struct file *, unsigned int, unsigned long); ...@@ -979,6 +971,7 @@ long f2fs_compat_ioctl(struct file *, unsigned int, unsigned long);
*/ */
void f2fs_set_inode_flags(struct inode *); void f2fs_set_inode_flags(struct inode *);
struct inode *f2fs_iget(struct super_block *, unsigned long); 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 *); void update_inode(struct inode *, struct page *);
int update_inode_page(struct inode *); int update_inode_page(struct inode *);
int f2fs_write_inode(struct inode *, struct writeback_control *); 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 *); ...@@ -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 get_dnode_of_data(struct dnode_of_data *, pgoff_t, int);
int truncate_inode_blocks(struct inode *, pgoff_t); int truncate_inode_blocks(struct inode *, pgoff_t);
int truncate_xattr_node(struct inode *, struct page *); 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 *); int remove_inode_page(struct inode *);
struct page *new_inode_page(struct inode *, const struct qstr *); struct page *new_inode_page(struct inode *, const struct qstr *);
struct page *new_node_page(struct dnode_of_data *, unsigned int, struct page *); struct page *new_node_page(struct dnode_of_data *, unsigned int, struct page *);
...@@ -1059,6 +1053,7 @@ void destroy_node_manager_caches(void); ...@@ -1059,6 +1053,7 @@ void destroy_node_manager_caches(void);
* segment.c * segment.c
*/ */
void f2fs_balance_fs(struct f2fs_sb_info *); 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 invalidate_blocks(struct f2fs_sb_info *, block_t);
void clear_prefree_segments(struct f2fs_sb_info *); void clear_prefree_segments(struct f2fs_sb_info *);
int npages_for_summary_flush(struct f2fs_sb_info *); int npages_for_summary_flush(struct f2fs_sb_info *);
...@@ -1173,6 +1168,15 @@ static inline struct f2fs_stat_info *F2FS_STAT(struct f2fs_sb_info *sbi) ...@@ -1173,6 +1168,15 @@ static inline struct f2fs_stat_info *F2FS_STAT(struct f2fs_sb_info *sbi)
} }
#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) \ #define stat_inc_seg_count(sbi, type) \
do { \ do { \
...@@ -1207,6 +1211,13 @@ void __init f2fs_create_root_stats(void); ...@@ -1207,6 +1211,13 @@ void __init f2fs_create_root_stats(void);
void f2fs_destroy_root_stats(void); void f2fs_destroy_root_stats(void);
#else #else
#define stat_inc_call_count(si) #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_seg_count(si, type)
#define stat_inc_tot_blk_count(si, blks) #define stat_inc_tot_blk_count(si, blks)
#define stat_inc_data_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, ...@@ -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); struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
block_t old_blk_addr; block_t old_blk_addr;
struct dnode_of_data dn; struct dnode_of_data dn;
int err, ilock; int err;
f2fs_balance_fs(sbi); f2fs_balance_fs(sbi);
sb_start_pagefault(inode->i_sb); sb_start_pagefault(inode->i_sb);
/* block allocation */ /* block allocation */
ilock = mutex_lock_op(sbi); f2fs_lock_op(sbi);
set_new_dnode(&dn, inode, NULL, NULL, 0); set_new_dnode(&dn, inode, NULL, NULL, 0);
err = get_dnode_of_data(&dn, page->index, ALLOC_NODE); err = get_dnode_of_data(&dn, page->index, ALLOC_NODE);
if (err) { if (err) {
mutex_unlock_op(sbi, ilock); f2fs_unlock_op(sbi);
goto out; goto out;
} }
...@@ -56,12 +56,12 @@ static int f2fs_vm_page_mkwrite(struct vm_area_struct *vma, ...@@ -56,12 +56,12 @@ static int f2fs_vm_page_mkwrite(struct vm_area_struct *vma,
err = reserve_new_block(&dn); err = reserve_new_block(&dn);
if (err) { if (err) {
f2fs_put_dnode(&dn); f2fs_put_dnode(&dn);
mutex_unlock_op(sbi, ilock); f2fs_unlock_op(sbi);
goto out; goto out;
} }
} }
f2fs_put_dnode(&dn); f2fs_put_dnode(&dn);
mutex_unlock_op(sbi, ilock); f2fs_unlock_op(sbi);
file_update_time(vma->vm_file); file_update_time(vma->vm_file);
lock_page(page); lock_page(page);
...@@ -88,6 +88,7 @@ static int f2fs_vm_page_mkwrite(struct vm_area_struct *vma, ...@@ -88,6 +88,7 @@ static int f2fs_vm_page_mkwrite(struct vm_area_struct *vma,
set_page_dirty(page); set_page_dirty(page);
SetPageUptodate(page); SetPageUptodate(page);
trace_f2fs_vm_page_mkwrite(page, DATA);
mapped: mapped:
/* fill the page */ /* fill the page */
wait_on_page_writeback(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) ...@@ -188,8 +189,9 @@ int f2fs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
if (ret) if (ret)
goto out; goto out;
} }
filemap_fdatawait_range(sbi->node_inode->i_mapping, ret = wait_on_node_pages_writeback(sbi, inode->i_ino);
0, LONG_MAX); if (ret)
goto out;
ret = blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL, NULL); ret = blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL, NULL);
} }
out: out:
...@@ -270,7 +272,7 @@ static int truncate_blocks(struct inode *inode, u64 from) ...@@ -270,7 +272,7 @@ static int truncate_blocks(struct inode *inode, u64 from)
unsigned int blocksize = inode->i_sb->s_blocksize; unsigned int blocksize = inode->i_sb->s_blocksize;
struct dnode_of_data dn; struct dnode_of_data dn;
pgoff_t free_from; pgoff_t free_from;
int count = 0, ilock = -1; int count = 0;
int err; int err;
trace_f2fs_truncate_blocks_enter(inode, from); trace_f2fs_truncate_blocks_enter(inode, from);
...@@ -278,13 +280,13 @@ static int truncate_blocks(struct inode *inode, u64 from) ...@@ -278,13 +280,13 @@ static int truncate_blocks(struct inode *inode, u64 from)
free_from = (pgoff_t) free_from = (pgoff_t)
((from + blocksize - 1) >> (sbi->log_blocksize)); ((from + blocksize - 1) >> (sbi->log_blocksize));
ilock = mutex_lock_op(sbi); f2fs_lock_op(sbi);
set_new_dnode(&dn, inode, NULL, NULL, 0); set_new_dnode(&dn, inode, NULL, NULL, 0);
err = get_dnode_of_data(&dn, free_from, LOOKUP_NODE); err = get_dnode_of_data(&dn, free_from, LOOKUP_NODE);
if (err) { if (err) {
if (err == -ENOENT) if (err == -ENOENT)
goto free_next; goto free_next;
mutex_unlock_op(sbi, ilock); f2fs_unlock_op(sbi);
trace_f2fs_truncate_blocks_exit(inode, err); trace_f2fs_truncate_blocks_exit(inode, err);
return err; return err;
} }
...@@ -295,7 +297,7 @@ static int truncate_blocks(struct inode *inode, u64 from) ...@@ -295,7 +297,7 @@ static int truncate_blocks(struct inode *inode, u64 from)
count = ADDRS_PER_BLOCK; count = ADDRS_PER_BLOCK;
count -= dn.ofs_in_node; count -= dn.ofs_in_node;
BUG_ON(count < 0); f2fs_bug_on(count < 0);
if (dn.ofs_in_node || IS_INODE(dn.node_page)) { if (dn.ofs_in_node || IS_INODE(dn.node_page)) {
truncate_data_blocks_range(&dn, count); truncate_data_blocks_range(&dn, count);
...@@ -305,7 +307,7 @@ static int truncate_blocks(struct inode *inode, u64 from) ...@@ -305,7 +307,7 @@ static int truncate_blocks(struct inode *inode, u64 from)
f2fs_put_dnode(&dn); f2fs_put_dnode(&dn);
free_next: free_next:
err = truncate_inode_blocks(inode, free_from); err = truncate_inode_blocks(inode, free_from);
mutex_unlock_op(sbi, ilock); f2fs_unlock_op(sbi);
/* lastly zero out the first data page */ /* lastly zero out the first data page */
truncate_partial_data_page(inode, from); truncate_partial_data_page(inode, from);
...@@ -416,16 +418,15 @@ static void fill_zero(struct inode *inode, pgoff_t index, ...@@ -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 f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
struct page *page; struct page *page;
int ilock;
if (!len) if (!len)
return; return;
f2fs_balance_fs(sbi); f2fs_balance_fs(sbi);
ilock = mutex_lock_op(sbi); f2fs_lock_op(sbi);
page = get_new_data_page(inode, NULL, index, false); page = get_new_data_page(inode, NULL, index, false);
mutex_unlock_op(sbi, ilock); f2fs_unlock_op(sbi);
if (!IS_ERR(page)) { if (!IS_ERR(page)) {
wait_on_page_writeback(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) ...@@ -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; struct address_space *mapping = inode->i_mapping;
loff_t blk_start, blk_end; loff_t blk_start, blk_end;
struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
int ilock;
f2fs_balance_fs(sbi); f2fs_balance_fs(sbi);
...@@ -493,9 +493,9 @@ static int punch_hole(struct inode *inode, loff_t offset, loff_t len, int mode) ...@@ -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, truncate_inode_pages_range(mapping, blk_start,
blk_end - 1); blk_end - 1);
ilock = mutex_lock_op(sbi); f2fs_lock_op(sbi);
ret = truncate_hole(inode, pg_start, pg_end); 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, ...@@ -529,13 +529,12 @@ static int expand_inode_data(struct inode *inode, loff_t offset,
for (index = pg_start; index <= pg_end; index++) { for (index = pg_start; index <= pg_end; index++) {
struct dnode_of_data dn; struct dnode_of_data dn;
int ilock;
ilock = mutex_lock_op(sbi); f2fs_lock_op(sbi);
set_new_dnode(&dn, inode, NULL, NULL, 0); set_new_dnode(&dn, inode, NULL, NULL, 0);
ret = get_dnode_of_data(&dn, index, ALLOC_NODE); ret = get_dnode_of_data(&dn, index, ALLOC_NODE);
if (ret) { if (ret) {
mutex_unlock_op(sbi, ilock); f2fs_unlock_op(sbi);
break; break;
} }
...@@ -543,12 +542,12 @@ static int expand_inode_data(struct inode *inode, loff_t offset, ...@@ -543,12 +542,12 @@ static int expand_inode_data(struct inode *inode, loff_t offset,
ret = reserve_new_block(&dn); ret = reserve_new_block(&dn);
if (ret) { if (ret) {
f2fs_put_dnode(&dn); f2fs_put_dnode(&dn);
mutex_unlock_op(sbi, ilock); f2fs_unlock_op(sbi);
break; break;
} }
} }
f2fs_put_dnode(&dn); f2fs_put_dnode(&dn);
mutex_unlock_op(sbi, ilock); f2fs_unlock_op(sbi);
if (pg_start == pg_end) if (pg_start == pg_end)
new_size = offset + len; new_size = offset + len;
......
...@@ -77,13 +77,15 @@ static int gc_thread_func(void *data) ...@@ -77,13 +77,15 @@ static int gc_thread_func(void *data)
else else
wait_ms = increase_sleep_time(gc_th, wait_ms); wait_ms = increase_sleep_time(gc_th, wait_ms);
#ifdef CONFIG_F2FS_STAT_FS stat_inc_bggc_count(sbi);
sbi->bg_gc++;
#endif
/* if return value is not zero, no victim was selected */ /* if return value is not zero, no victim was selected */
if (f2fs_gc(sbi)) if (f2fs_gc(sbi))
wait_ms = gc_th->no_gc_sleep_time; wait_ms = gc_th->no_gc_sleep_time;
/* balancing f2fs's metadata periodically */
f2fs_balance_fs_bg(sbi);
} while (!kthread_should_stop()); } while (!kthread_should_stop());
return 0; return 0;
} }
...@@ -236,8 +238,8 @@ static unsigned int get_cb_cost(struct f2fs_sb_info *sbi, unsigned int segno) ...@@ -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)); return UINT_MAX - ((100 * (100 - u) * age) / (100 + u));
} }
static unsigned int get_gc_cost(struct f2fs_sb_info *sbi, unsigned int segno, static inline unsigned int get_gc_cost(struct f2fs_sb_info *sbi,
struct victim_sel_policy *p) unsigned int segno, struct victim_sel_policy *p)
{ {
if (p->alloc_mode == SSR) if (p->alloc_mode == SSR)
return get_seg_entry(sbi, segno)->ckpt_valid_blocks; return get_seg_entry(sbi, segno)->ckpt_valid_blocks;
...@@ -293,7 +295,11 @@ static int get_victim_by_default(struct f2fs_sb_info *sbi, ...@@ -293,7 +295,11 @@ static int get_victim_by_default(struct f2fs_sb_info *sbi,
} }
break; 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); secno = GET_SECNO(sbi, segno);
if (sec_usage_check(sbi, secno)) if (sec_usage_check(sbi, secno))
...@@ -306,10 +312,9 @@ static int get_victim_by_default(struct f2fs_sb_info *sbi, ...@@ -306,10 +312,9 @@ static int get_victim_by_default(struct f2fs_sb_info *sbi,
if (p.min_cost > cost) { if (p.min_cost > cost) {
p.min_segno = segno; p.min_segno = segno;
p.min_cost = cost; p.min_cost = cost;
} } else if (unlikely(cost == max_cost)) {
if (cost == max_cost)
continue; continue;
}
if (nsearched++ >= p.max_search) { if (nsearched++ >= p.max_search) {
sbi->last_victim[p.gc_mode] = segno; sbi->last_victim[p.gc_mode] = segno;
...@@ -358,12 +363,8 @@ static void add_gc_inode(struct inode *inode, struct list_head *ilist) ...@@ -358,12 +363,8 @@ static void add_gc_inode(struct inode *inode, struct list_head *ilist)
iput(inode); iput(inode);
return; return;
} }
repeat:
new_ie = kmem_cache_alloc(winode_slab, GFP_NOFS); new_ie = f2fs_kmem_cache_alloc(winode_slab, GFP_NOFS);
if (!new_ie) {
cond_resched();
goto repeat;
}
new_ie->inode = inode; new_ie->inode = inode;
list_add_tail(&new_ie->list, ilist); list_add_tail(&new_ie->list, ilist);
} }
......
...@@ -37,6 +37,31 @@ void f2fs_set_inode_flags(struct inode *inode) ...@@ -37,6 +37,31 @@ void f2fs_set_inode_flags(struct inode *inode)
inode->i_flags |= S_DIRSYNC; 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) static int do_read_inode(struct inode *inode)
{ {
struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
...@@ -73,10 +98,6 @@ static int do_read_inode(struct inode *inode) ...@@ -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_ctime.tv_nsec = le32_to_cpu(ri->i_ctime_nsec);
inode->i_mtime.tv_nsec = le32_to_cpu(ri->i_mtime_nsec); inode->i_mtime.tv_nsec = le32_to_cpu(ri->i_mtime_nsec);
inode->i_generation = le32_to_cpu(ri->i_generation); 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_current_depth = le32_to_cpu(ri->i_current_depth);
fi->i_xattr_nid = le32_to_cpu(ri->i_xattr_nid); fi->i_xattr_nid = le32_to_cpu(ri->i_xattr_nid);
...@@ -84,8 +105,13 @@ static int do_read_inode(struct inode *inode) ...@@ -84,8 +105,13 @@ static int do_read_inode(struct inode *inode)
fi->flags = 0; fi->flags = 0;
fi->i_advise = ri->i_advise; fi->i_advise = ri->i_advise;
fi->i_pino = le32_to_cpu(ri->i_pino); fi->i_pino = le32_to_cpu(ri->i_pino);
get_extent_info(&fi->ext, ri->i_ext); get_extent_info(&fi->ext, ri->i_ext);
get_inline_info(fi, ri); get_inline_info(fi, ri);
/* get rdev by using inline_info */
__get_inode_rdev(inode, ri);
f2fs_put_page(node_page, 1); f2fs_put_page(node_page, 1);
return 0; return 0;
} }
...@@ -179,21 +205,10 @@ void update_inode(struct inode *inode, struct page *node_page) ...@@ -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_pino = cpu_to_le32(F2FS_I(inode)->i_pino);
ri->i_generation = cpu_to_le32(inode->i_generation); ri->i_generation = cpu_to_le32(inode->i_generation);
if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) { __set_inode_rdev(inode, ri);
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_cold_node(inode, node_page); set_cold_node(inode, node_page);
set_page_dirty(node_page); set_page_dirty(node_page);
clear_inode_flag(F2FS_I(inode), FI_DIRTY_INODE); clear_inode_flag(F2FS_I(inode), FI_DIRTY_INODE);
} }
...@@ -214,7 +229,7 @@ int update_inode_page(struct inode *inode) ...@@ -214,7 +229,7 @@ int update_inode_page(struct inode *inode)
int f2fs_write_inode(struct inode *inode, struct writeback_control *wbc) int f2fs_write_inode(struct inode *inode, struct writeback_control *wbc)
{ {
struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
int ret, ilock; int ret;
if (inode->i_ino == F2FS_NODE_INO(sbi) || if (inode->i_ino == F2FS_NODE_INO(sbi) ||
inode->i_ino == F2FS_META_INO(sbi)) inode->i_ino == F2FS_META_INO(sbi))
...@@ -227,9 +242,9 @@ int f2fs_write_inode(struct inode *inode, struct writeback_control *wbc) ...@@ -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 * We need to lock here to prevent from producing dirty node pages
* during the urgent cleaning time when runing out of free sections. * 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); ret = update_inode_page(inode);
mutex_unlock_op(sbi, ilock); f2fs_unlock_op(sbi);
if (wbc) if (wbc)
f2fs_balance_fs(sbi); f2fs_balance_fs(sbi);
...@@ -243,7 +258,6 @@ int f2fs_write_inode(struct inode *inode, struct writeback_control *wbc) ...@@ -243,7 +258,6 @@ int f2fs_write_inode(struct inode *inode, struct writeback_control *wbc)
void f2fs_evict_inode(struct inode *inode) void f2fs_evict_inode(struct inode *inode)
{ {
struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
int ilock;
trace_f2fs_evict_inode(inode); trace_f2fs_evict_inode(inode);
truncate_inode_pages(&inode->i_data, 0); truncate_inode_pages(&inode->i_data, 0);
...@@ -252,7 +266,7 @@ void f2fs_evict_inode(struct inode *inode) ...@@ -252,7 +266,7 @@ void f2fs_evict_inode(struct inode *inode)
inode->i_ino == F2FS_META_INO(sbi)) inode->i_ino == F2FS_META_INO(sbi))
goto no_delete; 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); remove_dirty_dir_inode(inode);
if (inode->i_nlink || is_bad_inode(inode)) if (inode->i_nlink || is_bad_inode(inode))
...@@ -265,9 +279,9 @@ void f2fs_evict_inode(struct inode *inode) ...@@ -265,9 +279,9 @@ void f2fs_evict_inode(struct inode *inode)
if (F2FS_HAS_BLOCKS(inode)) if (F2FS_HAS_BLOCKS(inode))
f2fs_truncate(inode); f2fs_truncate(inode);
ilock = mutex_lock_op(sbi); f2fs_lock_op(sbi);
remove_inode_page(inode); remove_inode_page(inode);
mutex_unlock_op(sbi, ilock); f2fs_unlock_op(sbi);
sb_end_intwrite(inode->i_sb); sb_end_intwrite(inode->i_sb);
no_delete: no_delete:
......
...@@ -27,19 +27,19 @@ static struct inode *f2fs_new_inode(struct inode *dir, umode_t mode) ...@@ -27,19 +27,19 @@ static struct inode *f2fs_new_inode(struct inode *dir, umode_t mode)
nid_t ino; nid_t ino;
struct inode *inode; struct inode *inode;
bool nid_free = false; bool nid_free = false;
int err, ilock; int err;
inode = new_inode(sb); inode = new_inode(sb);
if (!inode) if (!inode)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
ilock = mutex_lock_op(sbi); f2fs_lock_op(sbi);
if (!alloc_nid(sbi, &ino)) { if (!alloc_nid(sbi, &ino)) {
mutex_unlock_op(sbi, ilock); f2fs_unlock_op(sbi);
err = -ENOSPC; err = -ENOSPC;
goto fail; goto fail;
} }
mutex_unlock_op(sbi, ilock); f2fs_unlock_op(sbi);
inode->i_uid = current_fsuid(); inode->i_uid = current_fsuid();
...@@ -115,7 +115,7 @@ static int f2fs_create(struct inode *dir, struct dentry *dentry, umode_t mode, ...@@ -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 f2fs_sb_info *sbi = F2FS_SB(sb);
struct inode *inode; struct inode *inode;
nid_t ino = 0; nid_t ino = 0;
int err, ilock; int err;
f2fs_balance_fs(sbi); f2fs_balance_fs(sbi);
...@@ -131,9 +131,9 @@ static int f2fs_create(struct inode *dir, struct dentry *dentry, umode_t mode, ...@@ -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; inode->i_mapping->a_ops = &f2fs_dblock_aops;
ino = inode->i_ino; ino = inode->i_ino;
ilock = mutex_lock_op(sbi); f2fs_lock_op(sbi);
err = f2fs_add_link(dentry, inode); err = f2fs_add_link(dentry, inode);
mutex_unlock_op(sbi, ilock); f2fs_unlock_op(sbi);
if (err) if (err)
goto out; goto out;
...@@ -157,7 +157,7 @@ static int f2fs_link(struct dentry *old_dentry, struct inode *dir, ...@@ -157,7 +157,7 @@ static int f2fs_link(struct dentry *old_dentry, struct inode *dir,
struct inode *inode = old_dentry->d_inode; struct inode *inode = old_dentry->d_inode;
struct super_block *sb = dir->i_sb; struct super_block *sb = dir->i_sb;
struct f2fs_sb_info *sbi = F2FS_SB(sb); struct f2fs_sb_info *sbi = F2FS_SB(sb);
int err, ilock; int err;
f2fs_balance_fs(sbi); f2fs_balance_fs(sbi);
...@@ -165,9 +165,9 @@ static int f2fs_link(struct dentry *old_dentry, struct inode *dir, ...@@ -165,9 +165,9 @@ static int f2fs_link(struct dentry *old_dentry, struct inode *dir,
ihold(inode); ihold(inode);
set_inode_flag(F2FS_I(inode), FI_INC_LINK); set_inode_flag(F2FS_I(inode), FI_INC_LINK);
ilock = mutex_lock_op(sbi); f2fs_lock_op(sbi);
err = f2fs_add_link(dentry, inode); err = f2fs_add_link(dentry, inode);
mutex_unlock_op(sbi, ilock); f2fs_unlock_op(sbi);
if (err) if (err)
goto out; goto out;
...@@ -220,7 +220,6 @@ static int f2fs_unlink(struct inode *dir, struct dentry *dentry) ...@@ -220,7 +220,6 @@ static int f2fs_unlink(struct inode *dir, struct dentry *dentry)
struct f2fs_dir_entry *de; struct f2fs_dir_entry *de;
struct page *page; struct page *page;
int err = -ENOENT; int err = -ENOENT;
int ilock;
trace_f2fs_unlink_enter(dir, dentry); trace_f2fs_unlink_enter(dir, dentry);
f2fs_balance_fs(sbi); f2fs_balance_fs(sbi);
...@@ -229,16 +228,16 @@ static int f2fs_unlink(struct inode *dir, struct dentry *dentry) ...@@ -229,16 +228,16 @@ static int f2fs_unlink(struct inode *dir, struct dentry *dentry)
if (!de) if (!de)
goto fail; goto fail;
f2fs_lock_op(sbi);
err = acquire_orphan_inode(sbi); err = acquire_orphan_inode(sbi);
if (err) { if (err) {
f2fs_unlock_op(sbi);
kunmap(page); kunmap(page);
f2fs_put_page(page, 0); f2fs_put_page(page, 0);
goto fail; goto fail;
} }
ilock = mutex_lock_op(sbi);
f2fs_delete_entry(de, page, inode); 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 */ /* In order to evict this inode, we set it dirty */
mark_inode_dirty(inode); mark_inode_dirty(inode);
...@@ -254,7 +253,7 @@ static int f2fs_symlink(struct inode *dir, struct dentry *dentry, ...@@ -254,7 +253,7 @@ static int f2fs_symlink(struct inode *dir, struct dentry *dentry,
struct f2fs_sb_info *sbi = F2FS_SB(sb); struct f2fs_sb_info *sbi = F2FS_SB(sb);
struct inode *inode; struct inode *inode;
size_t symlen = strlen(symname) + 1; size_t symlen = strlen(symname) + 1;
int err, ilock; int err;
f2fs_balance_fs(sbi); f2fs_balance_fs(sbi);
...@@ -265,9 +264,9 @@ static int f2fs_symlink(struct inode *dir, struct dentry *dentry, ...@@ -265,9 +264,9 @@ static int f2fs_symlink(struct inode *dir, struct dentry *dentry,
inode->i_op = &f2fs_symlink_inode_operations; inode->i_op = &f2fs_symlink_inode_operations;
inode->i_mapping->a_ops = &f2fs_dblock_aops; inode->i_mapping->a_ops = &f2fs_dblock_aops;
ilock = mutex_lock_op(sbi); f2fs_lock_op(sbi);
err = f2fs_add_link(dentry, inode); err = f2fs_add_link(dentry, inode);
mutex_unlock_op(sbi, ilock); f2fs_unlock_op(sbi);
if (err) if (err)
goto out; goto out;
...@@ -290,7 +289,7 @@ static int f2fs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) ...@@ -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 f2fs_sb_info *sbi = F2FS_SB(dir->i_sb);
struct inode *inode; struct inode *inode;
int err, ilock; int err;
f2fs_balance_fs(sbi); f2fs_balance_fs(sbi);
...@@ -304,9 +303,9 @@ static int f2fs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) ...@@ -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); mapping_set_gfp_mask(inode->i_mapping, GFP_F2FS_ZERO);
set_inode_flag(F2FS_I(inode), FI_INC_LINK); set_inode_flag(F2FS_I(inode), FI_INC_LINK);
ilock = mutex_lock_op(sbi); f2fs_lock_op(sbi);
err = f2fs_add_link(dentry, inode); err = f2fs_add_link(dentry, inode);
mutex_unlock_op(sbi, ilock); f2fs_unlock_op(sbi);
if (err) if (err)
goto out_fail; goto out_fail;
...@@ -342,7 +341,6 @@ static int f2fs_mknod(struct inode *dir, struct dentry *dentry, ...@@ -342,7 +341,6 @@ static int f2fs_mknod(struct inode *dir, struct dentry *dentry,
struct f2fs_sb_info *sbi = F2FS_SB(sb); struct f2fs_sb_info *sbi = F2FS_SB(sb);
struct inode *inode; struct inode *inode;
int err = 0; int err = 0;
int ilock;
if (!new_valid_dev(rdev)) if (!new_valid_dev(rdev))
return -EINVAL; return -EINVAL;
...@@ -356,9 +354,9 @@ static int f2fs_mknod(struct inode *dir, struct dentry *dentry, ...@@ -356,9 +354,9 @@ static int f2fs_mknod(struct inode *dir, struct dentry *dentry,
init_special_inode(inode, inode->i_mode, rdev); init_special_inode(inode, inode->i_mode, rdev);
inode->i_op = &f2fs_special_inode_operations; inode->i_op = &f2fs_special_inode_operations;
ilock = mutex_lock_op(sbi); f2fs_lock_op(sbi);
err = f2fs_add_link(dentry, inode); err = f2fs_add_link(dentry, inode);
mutex_unlock_op(sbi, ilock); f2fs_unlock_op(sbi);
if (err) if (err)
goto out; goto out;
...@@ -387,7 +385,7 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -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_dir_entry = NULL;
struct f2fs_dir_entry *old_entry; struct f2fs_dir_entry *old_entry;
struct f2fs_dir_entry *new_entry; struct f2fs_dir_entry *new_entry;
int err = -ENOENT, ilock = -1; int err = -ENOENT;
f2fs_balance_fs(sbi); f2fs_balance_fs(sbi);
...@@ -402,7 +400,7 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -402,7 +400,7 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
goto out_old; goto out_old;
} }
ilock = mutex_lock_op(sbi); f2fs_lock_op(sbi);
if (new_inode) { if (new_inode) {
...@@ -467,7 +465,7 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -467,7 +465,7 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
update_inode_page(old_dir); update_inode_page(old_dir);
} }
mutex_unlock_op(sbi, ilock); f2fs_unlock_op(sbi);
return 0; return 0;
put_out_dir: put_out_dir:
...@@ -477,7 +475,7 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -477,7 +475,7 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
kunmap(old_dir_page); kunmap(old_dir_page);
f2fs_put_page(old_dir_page, 0); f2fs_put_page(old_dir_page, 0);
} }
mutex_unlock_op(sbi, ilock); f2fs_unlock_op(sbi);
out_old: out_old:
kunmap(old_page); kunmap(old_page);
f2fs_put_page(old_page, 0); f2fs_put_page(old_page, 0);
......
...@@ -204,7 +204,7 @@ static void set_node_addr(struct f2fs_sb_info *sbi, struct node_info *ni, ...@@ -204,7 +204,7 @@ static void set_node_addr(struct f2fs_sb_info *sbi, struct node_info *ni,
} }
e->ni = *ni; e->ni = *ni;
e->checkpointed = true; e->checkpointed = true;
BUG_ON(ni->blk_addr == NEW_ADDR); f2fs_bug_on(ni->blk_addr == NEW_ADDR);
} else if (new_blkaddr == NEW_ADDR) { } else if (new_blkaddr == NEW_ADDR) {
/* /*
* when nid is reallocated, * when nid is reallocated,
...@@ -212,19 +212,19 @@ static void set_node_addr(struct f2fs_sb_info *sbi, struct node_info *ni, ...@@ -212,19 +212,19 @@ static void set_node_addr(struct f2fs_sb_info *sbi, struct node_info *ni,
* So, reinitialize it with new information. * So, reinitialize it with new information.
*/ */
e->ni = *ni; e->ni = *ni;
BUG_ON(ni->blk_addr != NULL_ADDR); f2fs_bug_on(ni->blk_addr != NULL_ADDR);
} }
if (new_blkaddr == NEW_ADDR) if (new_blkaddr == NEW_ADDR)
e->checkpointed = false; e->checkpointed = false;
/* sanity check */ /* sanity check */
BUG_ON(nat_get_blkaddr(e) != ni->blk_addr); f2fs_bug_on(nat_get_blkaddr(e) != ni->blk_addr);
BUG_ON(nat_get_blkaddr(e) == NULL_ADDR && f2fs_bug_on(nat_get_blkaddr(e) == NULL_ADDR &&
new_blkaddr == 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); 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 && nat_get_blkaddr(e) != NULL_ADDR &&
new_blkaddr == NEW_ADDR); new_blkaddr == NEW_ADDR);
...@@ -240,7 +240,7 @@ static void set_node_addr(struct f2fs_sb_info *sbi, struct node_info *ni, ...@@ -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); 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); struct f2fs_nm_info *nm_i = NM_I(sbi);
...@@ -495,10 +495,10 @@ static void truncate_node(struct dnode_of_data *dn) ...@@ -495,10 +495,10 @@ static void truncate_node(struct dnode_of_data *dn)
get_node_info(sbi, dn->nid, &ni); get_node_info(sbi, dn->nid, &ni);
if (dn->inode->i_blocks == 0) { if (dn->inode->i_blocks == 0) {
BUG_ON(ni.blk_addr != NULL_ADDR); f2fs_bug_on(ni.blk_addr != NULL_ADDR);
goto invalidate; goto invalidate;
} }
BUG_ON(ni.blk_addr == NULL_ADDR); f2fs_bug_on(ni.blk_addr == NULL_ADDR);
/* Deallocate node address */ /* Deallocate node address */
invalidate_blocks(sbi, ni.blk_addr); invalidate_blocks(sbi, ni.blk_addr);
...@@ -822,7 +822,7 @@ int remove_inode_page(struct inode *inode) ...@@ -822,7 +822,7 @@ int remove_inode_page(struct inode *inode)
} }
/* 0 is possible, after f2fs_new_inode() is failed */ /* 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); set_new_dnode(&dn, inode, page, page, ino);
truncate_node(&dn); truncate_node(&dn);
return 0; return 0;
...@@ -863,7 +863,7 @@ struct page *new_node_page(struct dnode_of_data *dn, ...@@ -863,7 +863,7 @@ struct page *new_node_page(struct dnode_of_data *dn,
get_node_info(sbi, dn->nid, &old_ni); get_node_info(sbi, dn->nid, &old_ni);
/* Reinitialize old_ni with new node page */ /* 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 = old_ni;
new_ni.ino = dn->inode->i_ino; new_ni.ino = dn->inode->i_ino;
set_node_addr(sbi, &new_ni, NEW_ADDR); 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) ...@@ -969,7 +969,7 @@ struct page *get_node_page(struct f2fs_sb_info *sbi, pgoff_t nid)
goto repeat; goto repeat;
} }
got_it: got_it:
BUG_ON(nid != nid_of_node(page)); f2fs_bug_on(nid != nid_of_node(page));
mark_page_accessed(page); mark_page_accessed(page);
return page; return page;
} }
...@@ -1148,6 +1148,47 @@ int sync_node_pages(struct f2fs_sb_info *sbi, nid_t ino, ...@@ -1148,6 +1148,47 @@ int sync_node_pages(struct f2fs_sb_info *sbi, nid_t ino,
return nwritten; 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, static int f2fs_write_node_page(struct page *page,
struct writeback_control *wbc) struct writeback_control *wbc)
{ {
...@@ -1156,11 +1197,14 @@ static int f2fs_write_node_page(struct page *page, ...@@ -1156,11 +1197,14 @@ static int f2fs_write_node_page(struct page *page,
block_t new_addr; block_t new_addr;
struct node_info ni; struct node_info ni;
if (sbi->por_doing)
goto redirty_out;
wait_on_page_writeback(page); wait_on_page_writeback(page);
/* get old block addr of this node page */ /* get old block addr of this node page */
nid = nid_of_node(page); nid = nid_of_node(page);
BUG_ON(page->index != nid); f2fs_bug_on(page->index != nid);
get_node_info(sbi, nid, &ni); get_node_info(sbi, nid, &ni);
...@@ -1171,12 +1215,8 @@ static int f2fs_write_node_page(struct page *page, ...@@ -1171,12 +1215,8 @@ static int f2fs_write_node_page(struct page *page,
return 0; return 0;
} }
if (wbc->for_reclaim) { if (wbc->for_reclaim)
dec_page_count(sbi, F2FS_DIRTY_NODES); goto redirty_out;
wbc->pages_skipped++;
set_page_dirty(page);
return AOP_WRITEPAGE_ACTIVATE;
}
mutex_lock(&sbi->node_write); mutex_lock(&sbi->node_write);
set_page_writeback(page); set_page_writeback(page);
...@@ -1186,6 +1226,12 @@ static int f2fs_write_node_page(struct page *page, ...@@ -1186,6 +1226,12 @@ static int f2fs_write_node_page(struct page *page,
mutex_unlock(&sbi->node_write); mutex_unlock(&sbi->node_write);
unlock_page(page); unlock_page(page);
return 0; 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, ...@@ -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); struct f2fs_sb_info *sbi = F2FS_SB(mapping->host->i_sb);
long nr_to_write = wbc->nr_to_write; long nr_to_write = wbc->nr_to_write;
/* First check balancing cached NAT entries */ /* balancing f2fs's metadata in background */
if (try_to_free_nats(sbi, NAT_ENTRY_PER_BLOCK)) { f2fs_balance_fs_bg(sbi);
f2fs_sync_fs(sbi->sb, true);
return 0;
}
/* collect a number of dirty node pages and write together */ /* collect a number of dirty node pages and write together */
if (get_pages(sbi, F2FS_DIRTY_NODES) < COLLECT_DIRTY_NODES) if (get_pages(sbi, F2FS_DIRTY_NODES) < COLLECT_DIRTY_NODES)
...@@ -1223,6 +1266,8 @@ static int f2fs_set_node_page_dirty(struct page *page) ...@@ -1223,6 +1266,8 @@ static int f2fs_set_node_page_dirty(struct page *page)
struct address_space *mapping = page->mapping; struct address_space *mapping = page->mapping;
struct f2fs_sb_info *sbi = F2FS_SB(mapping->host->i_sb); struct f2fs_sb_info *sbi = F2FS_SB(mapping->host->i_sb);
trace_f2fs_set_page_dirty(page, NODE);
SetPageUptodate(page); SetPageUptodate(page);
if (!PageDirty(page)) { if (!PageDirty(page)) {
__set_page_dirty_nobuffers(page); __set_page_dirty_nobuffers(page);
...@@ -1291,9 +1336,7 @@ static int add_free_nid(struct f2fs_nm_info *nm_i, nid_t nid, bool build) ...@@ -1291,9 +1336,7 @@ static int add_free_nid(struct f2fs_nm_info *nm_i, nid_t nid, bool build)
if (nid == 0) if (nid == 0)
return 0; return 0;
if (!build) if (build) {
goto retry;
/* do not add allocated nids */ /* do not add allocated nids */
read_lock(&nm_i->nat_tree_lock); read_lock(&nm_i->nat_tree_lock);
ne = __lookup_nat_cache(nm_i, nid); ne = __lookup_nat_cache(nm_i, nid);
...@@ -1302,12 +1345,9 @@ static int add_free_nid(struct f2fs_nm_info *nm_i, nid_t nid, bool build) ...@@ -1302,12 +1345,9 @@ static int add_free_nid(struct f2fs_nm_info *nm_i, nid_t nid, bool build)
read_unlock(&nm_i->nat_tree_lock); read_unlock(&nm_i->nat_tree_lock);
if (allocated) if (allocated)
return 0; return 0;
retry:
i = kmem_cache_alloc(free_nid_slab, GFP_NOFS);
if (!i) {
cond_resched();
goto retry;
} }
i = f2fs_kmem_cache_alloc(free_nid_slab, GFP_NOFS);
i->nid = nid; i->nid = nid;
i->state = NID_NEW; i->state = NID_NEW;
...@@ -1350,7 +1390,7 @@ static void scan_nat_page(struct f2fs_nm_info *nm_i, ...@@ -1350,7 +1390,7 @@ static void scan_nat_page(struct f2fs_nm_info *nm_i,
break; break;
blk_addr = le32_to_cpu(nat_blk->entries[i].block_addr); 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 (blk_addr == NULL_ADDR) {
if (add_free_nid(nm_i, start_nid, true) < 0) if (add_free_nid(nm_i, start_nid, true) < 0)
break; break;
...@@ -1421,14 +1461,14 @@ bool alloc_nid(struct f2fs_sb_info *sbi, nid_t *nid) ...@@ -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 */ /* We should not use stale free nids created by build_free_nids */
if (nm_i->fcnt && !sbi->on_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) { list_for_each(this, &nm_i->free_nid_list) {
i = list_entry(this, struct free_nid, list); i = list_entry(this, struct free_nid, list);
if (i->state == NID_NEW) if (i->state == NID_NEW)
break; break;
} }
BUG_ON(i->state != NID_NEW); f2fs_bug_on(i->state != NID_NEW);
*nid = i->nid; *nid = i->nid;
i->state = NID_ALLOC; i->state = NID_ALLOC;
nm_i->fcnt--; nm_i->fcnt--;
...@@ -1439,9 +1479,9 @@ bool alloc_nid(struct f2fs_sb_info *sbi, nid_t *nid) ...@@ -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 */ /* Let's scan nat pages and its caches to get free nids */
mutex_lock(&nm_i->build_lock); mutex_lock(&nm_i->build_lock);
sbi->on_build_free_nids = 1; sbi->on_build_free_nids = true;
build_free_nids(sbi); build_free_nids(sbi);
sbi->on_build_free_nids = 0; sbi->on_build_free_nids = false;
mutex_unlock(&nm_i->build_lock); mutex_unlock(&nm_i->build_lock);
goto retry; goto retry;
} }
...@@ -1456,7 +1496,7 @@ void alloc_nid_done(struct f2fs_sb_info *sbi, nid_t nid) ...@@ -1456,7 +1496,7 @@ void alloc_nid_done(struct f2fs_sb_info *sbi, nid_t nid)
spin_lock(&nm_i->free_nid_list_lock); spin_lock(&nm_i->free_nid_list_lock);
i = __lookup_free_nid_list(nid, &nm_i->free_nid_list); 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); __del_from_free_nid_list(i);
spin_unlock(&nm_i->free_nid_list_lock); spin_unlock(&nm_i->free_nid_list_lock);
} }
...@@ -1474,7 +1514,7 @@ void alloc_nid_failed(struct f2fs_sb_info *sbi, nid_t nid) ...@@ -1474,7 +1514,7 @@ void alloc_nid_failed(struct f2fs_sb_info *sbi, nid_t nid)
spin_lock(&nm_i->free_nid_list_lock); spin_lock(&nm_i->free_nid_list_lock);
i = __lookup_free_nid_list(nid, &nm_i->free_nid_list); 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) { if (nm_i->fcnt > 2 * MAX_FREE_NIDS) {
__del_from_free_nid_list(i); __del_from_free_nid_list(i);
} else { } else {
...@@ -1677,7 +1717,7 @@ void flush_nat_entries(struct f2fs_sb_info *sbi) ...@@ -1677,7 +1717,7 @@ void flush_nat_entries(struct f2fs_sb_info *sbi)
nat_blk = page_address(page); nat_blk = page_address(page);
} }
BUG_ON(!nat_blk); f2fs_bug_on(!nat_blk);
raw_ne = nat_blk->entries[nid - start_nid]; raw_ne = nat_blk->entries[nid - start_nid];
flush_now: flush_now:
new_blkaddr = nat_get_blkaddr(ne); new_blkaddr = nat_get_blkaddr(ne);
...@@ -1781,11 +1821,11 @@ void destroy_node_manager(struct f2fs_sb_info *sbi) ...@@ -1781,11 +1821,11 @@ void destroy_node_manager(struct f2fs_sb_info *sbi)
/* destroy free nid list */ /* destroy free nid list */
spin_lock(&nm_i->free_nid_list_lock); spin_lock(&nm_i->free_nid_list_lock);
list_for_each_entry_safe(i, next_i, &nm_i->free_nid_list, list) { 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); __del_from_free_nid_list(i);
nm_i->fcnt--; nm_i->fcnt--;
} }
BUG_ON(nm_i->fcnt); f2fs_bug_on(nm_i->fcnt);
spin_unlock(&nm_i->free_nid_list_lock); spin_unlock(&nm_i->free_nid_list_lock);
/* destroy nat cache */ /* destroy nat cache */
...@@ -1799,7 +1839,7 @@ void destroy_node_manager(struct f2fs_sb_info *sbi) ...@@ -1799,7 +1839,7 @@ void destroy_node_manager(struct f2fs_sb_info *sbi)
__del_from_nat_cache(nm_i, e); __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); write_unlock(&nm_i->nat_tree_lock);
kfree(nm_i->nat_bitmap); kfree(nm_i->nat_bitmap);
......
...@@ -64,24 +64,31 @@ static int recover_dentry(struct page *ipage, struct inode *inode) ...@@ -64,24 +64,31 @@ static int recover_dentry(struct page *ipage, struct inode *inode)
name.name = raw_inode->i_name; name.name = raw_inode->i_name;
retry: retry:
de = f2fs_find_entry(dir, &name, &page); de = f2fs_find_entry(dir, &name, &page);
if (de && inode->i_ino == le32_to_cpu(de->ino)) { if (de && inode->i_ino == le32_to_cpu(de->ino))
kunmap(page); goto out_unmap_put;
f2fs_put_page(page, 0);
goto out;
}
if (de) { if (de) {
einode = f2fs_iget(inode->i_sb, le32_to_cpu(de->ino)); einode = f2fs_iget(inode->i_sb, le32_to_cpu(de->ino));
if (IS_ERR(einode)) { if (IS_ERR(einode)) {
WARN_ON(1); WARN_ON(1);
if (PTR_ERR(einode) == -ENOENT) if (PTR_ERR(einode) == -ENOENT)
err = -EEXIST; 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); f2fs_delete_entry(de, page, einode);
iput(einode); iput(einode);
goto retry; goto retry;
} }
err = __f2fs_add_link(dir, &name, inode); err = __f2fs_add_link(dir, &name, inode);
goto out;
out_unmap_put:
kunmap(page);
f2fs_put_page(page, 0);
out: out:
f2fs_msg(inode->i_sb, KERN_NOTICE, "recover_inode and its dentry: " f2fs_msg(inode->i_sb, KERN_NOTICE, "recover_inode and its dentry: "
"ino = %x, name = %s, dir = %lx, err = %d", "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, ...@@ -285,7 +292,6 @@ static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode,
struct f2fs_summary sum; struct f2fs_summary sum;
struct node_info ni; struct node_info ni;
int err = 0, recovered = 0; int err = 0, recovered = 0;
int ilock;
start = start_bidx_of_node(ofs_of_node(page), fi); start = start_bidx_of_node(ofs_of_node(page), fi);
if (IS_INODE(page)) if (IS_INODE(page))
...@@ -293,20 +299,20 @@ static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode, ...@@ -293,20 +299,20 @@ static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode,
else else
end = start + ADDRS_PER_BLOCK; end = start + ADDRS_PER_BLOCK;
ilock = mutex_lock_op(sbi); f2fs_lock_op(sbi);
set_new_dnode(&dn, inode, NULL, NULL, 0); set_new_dnode(&dn, inode, NULL, NULL, 0);
err = get_dnode_of_data(&dn, start, ALLOC_NODE); err = get_dnode_of_data(&dn, start, ALLOC_NODE);
if (err) { if (err) {
mutex_unlock_op(sbi, ilock); f2fs_unlock_op(sbi);
return err; return err;
} }
wait_on_page_writeback(dn.node_page); wait_on_page_writeback(dn.node_page);
get_node_info(sbi, dn.nid, &ni); get_node_info(sbi, dn.nid, &ni);
BUG_ON(ni.ino != ino_of_node(page)); f2fs_bug_on(ni.ino != ino_of_node(page));
BUG_ON(ofs_of_node(dn.node_page) != ofs_of_node(page)); f2fs_bug_on(ofs_of_node(dn.node_page) != ofs_of_node(page));
for (; start < end; start++) { for (; start < end; start++) {
block_t src, dest; block_t src, dest;
...@@ -316,9 +322,9 @@ static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode, ...@@ -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 != dest && dest != NEW_ADDR && dest != NULL_ADDR) {
if (src == NULL_ADDR) { if (src == NULL_ADDR) {
int err = reserve_new_block(&dn); err = reserve_new_block(&dn);
/* We should not get -ENOSPC */ /* We should not get -ENOSPC */
BUG_ON(err); f2fs_bug_on(err);
} }
/* Check the previous node page having this index */ /* 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, ...@@ -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); recover_node_page(sbi, dn.node_page, &sum, &ni, blkaddr);
err: err:
f2fs_put_dnode(&dn); f2fs_put_dnode(&dn);
mutex_unlock_op(sbi, ilock); f2fs_unlock_op(sbi);
f2fs_msg(sbi->sb, KERN_NOTICE, "recover_data: ino = %lx, " f2fs_msg(sbi->sb, KERN_NOTICE, "recover_data: ino = %lx, "
"recovered_data = %d blocks, err = %d", "recovered_data = %d blocks, err = %d",
...@@ -419,6 +425,7 @@ int recover_fsync_data(struct f2fs_sb_info *sbi) ...@@ -419,6 +425,7 @@ int recover_fsync_data(struct f2fs_sb_info *sbi)
{ {
struct list_head inode_list; struct list_head inode_list;
int err; int err;
bool need_writecp = false;
fsync_entry_slab = f2fs_kmem_cache_create("f2fs_fsync_inode_entry", fsync_entry_slab = f2fs_kmem_cache_create("f2fs_fsync_inode_entry",
sizeof(struct fsync_inode_entry), NULL); sizeof(struct fsync_inode_entry), NULL);
...@@ -428,7 +435,7 @@ int recover_fsync_data(struct f2fs_sb_info *sbi) ...@@ -428,7 +435,7 @@ int recover_fsync_data(struct f2fs_sb_info *sbi)
INIT_LIST_HEAD(&inode_list); INIT_LIST_HEAD(&inode_list);
/* step #1: find fsynced inode numbers */ /* step #1: find fsynced inode numbers */
sbi->por_doing = 1; sbi->por_doing = true;
err = find_fsync_dnodes(sbi, &inode_list); err = find_fsync_dnodes(sbi, &inode_list);
if (err) if (err)
goto out; goto out;
...@@ -436,14 +443,16 @@ int recover_fsync_data(struct f2fs_sb_info *sbi) ...@@ -436,14 +443,16 @@ int recover_fsync_data(struct f2fs_sb_info *sbi)
if (list_empty(&inode_list)) if (list_empty(&inode_list))
goto out; goto out;
need_writecp = true;
/* step #2: recover data */ /* step #2: recover data */
err = recover_data(sbi, &inode_list, CURSEG_WARM_NODE); err = recover_data(sbi, &inode_list, CURSEG_WARM_NODE);
BUG_ON(!list_empty(&inode_list)); f2fs_bug_on(!list_empty(&inode_list));
out: out:
destroy_fsync_dnodes(&inode_list); destroy_fsync_dnodes(&inode_list);
kmem_cache_destroy(fsync_entry_slab); kmem_cache_destroy(fsync_entry_slab);
sbi->por_doing = 0; sbi->por_doing = false;
if (!err) if (!err && need_writecp)
write_checkpoint(sbi, false); write_checkpoint(sbi, false);
return err; return err;
} }
...@@ -36,6 +36,14 @@ void f2fs_balance_fs(struct f2fs_sb_info *sbi) ...@@ -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, static void __locate_dirty_segment(struct f2fs_sb_info *sbi, unsigned int segno,
enum dirty_type dirty_type) enum dirty_type dirty_type)
{ {
...@@ -50,20 +58,10 @@ static void __locate_dirty_segment(struct f2fs_sb_info *sbi, unsigned int segno, ...@@ -50,20 +58,10 @@ static void __locate_dirty_segment(struct f2fs_sb_info *sbi, unsigned int segno,
if (dirty_type == DIRTY) { if (dirty_type == DIRTY) {
struct seg_entry *sentry = get_seg_entry(sbi, segno); 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 */ if (!test_and_set_bit(segno, dirty_i->dirty_segmap[t]))
for (; t <= DIRTY_COLD_NODE; t++) { dirty_i->nr_dirty[t]++;
if (t == dirty_type)
continue;
if (test_and_clear_bit(segno, dirty_i->dirty_segmap[t]))
dirty_i->nr_dirty[t]--;
}
} }
} }
...@@ -76,10 +74,9 @@ static void __remove_dirty_segment(struct f2fs_sb_info *sbi, unsigned int segno, ...@@ -76,10 +74,9 @@ static void __remove_dirty_segment(struct f2fs_sb_info *sbi, unsigned int segno,
dirty_i->nr_dirty[dirty_type]--; dirty_i->nr_dirty[dirty_type]--;
if (dirty_type == DIRTY) { 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])) if (test_and_clear_bit(segno, dirty_i->dirty_segmap[t]))
dirty_i->nr_dirty[t]--; dirty_i->nr_dirty[t]--;
...@@ -142,26 +139,32 @@ static void set_prefree_as_free_segments(struct f2fs_sb_info *sbi) ...@@ -142,26 +139,32 @@ static void set_prefree_as_free_segments(struct f2fs_sb_info *sbi)
void clear_prefree_segments(struct f2fs_sb_info *sbi) void clear_prefree_segments(struct f2fs_sb_info *sbi)
{ {
struct dirty_seglist_info *dirty_i = DIRTY_I(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 total_segs = TOTAL_SEGS(sbi);
unsigned int start = 0, end = -1;
mutex_lock(&dirty_i->seglist_lock); mutex_lock(&dirty_i->seglist_lock);
while (1) { while (1) {
segno = find_next_bit(dirty_i->dirty_segmap[PRE], total_segs, int i;
segno + 1); start = find_next_bit(prefree_map, total_segs, end + 1);
if (segno >= total_segs) if (start >= total_segs)
break; break;
end = find_next_zero_bit(prefree_map, total_segs, start + 1);
for (i = start; i < end; i++)
clear_bit(i, prefree_map);
if (test_and_clear_bit(segno, dirty_i->dirty_segmap[PRE])) dirty_i->nr_dirty[PRE] -= end - start;
dirty_i->nr_dirty[PRE]--;
if (!test_opt(sbi, DISCARD))
continue;
/* Let's use trim */
if (test_opt(sbi, DISCARD))
blkdev_issue_discard(sbi->sb->s_bdev, blkdev_issue_discard(sbi->sb->s_bdev,
START_BLOCK(sbi, segno) << START_BLOCK(sbi, start) <<
sbi->log_sectors_per_block, sbi->log_sectors_per_block,
1 << (sbi->log_sectors_per_block + (1 << (sbi->log_sectors_per_block +
sbi->log_blocks_per_seg), sbi->log_blocks_per_seg)) * (end - start),
GFP_NOFS, 0); GFP_NOFS, 0);
} }
mutex_unlock(&dirty_i->seglist_lock); 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) ...@@ -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; new_vblocks = se->valid_blocks + del;
offset = GET_SEGOFF_FROM_SEG0(sbi, blkaddr) & (sbi->blocks_per_seg - 1); 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))); (new_vblocks > sbi->blocks_per_seg)));
se->valid_blocks = new_vblocks; se->valid_blocks = new_vblocks;
...@@ -235,7 +238,7 @@ void invalidate_blocks(struct f2fs_sb_info *sbi, block_t addr) ...@@ -235,7 +238,7 @@ void invalidate_blocks(struct f2fs_sb_info *sbi, block_t addr)
unsigned int segno = GET_SEGNO(sbi, addr); unsigned int segno = GET_SEGNO(sbi, addr);
struct sit_info *sit_i = SIT_I(sbi); struct sit_info *sit_i = SIT_I(sbi);
BUG_ON(addr == NULL_ADDR); f2fs_bug_on(addr == NULL_ADDR);
if (addr == NEW_ADDR) if (addr == NEW_ADDR)
return; return;
...@@ -267,9 +270,8 @@ static void __add_sum_entry(struct f2fs_sb_info *sbi, int type, ...@@ -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 npages_for_summary_flush(struct f2fs_sb_info *sbi)
{ {
int total_size_bytes = 0;
int valid_sum_count = 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++) { for (i = CURSEG_HOT_DATA; i <= CURSEG_COLD_DATA; i++) {
if (sbi->ckpt->alloc_type[i] == SSR) if (sbi->ckpt->alloc_type[i] == SSR)
...@@ -278,13 +280,12 @@ int npages_for_summary_flush(struct f2fs_sb_info *sbi) ...@@ -278,13 +280,12 @@ int npages_for_summary_flush(struct f2fs_sb_info *sbi)
valid_sum_count += curseg_blkoff(sbi, i); valid_sum_count += curseg_blkoff(sbi, i);
} }
total_size_bytes = valid_sum_count * (SUMMARY_SIZE + 1) sum_in_page = (PAGE_CACHE_SIZE - 2 * SUM_JOURNAL_SIZE -
+ sizeof(struct nat_journal) + 2 SUM_FOOTER_SIZE) / SUMMARY_SIZE;
+ sizeof(struct sit_journal) + 2; if (valid_sum_count <= sum_in_page)
sum_space = PAGE_CACHE_SIZE - SUM_FOOTER_SIZE;
if (total_size_bytes < sum_space)
return 1; 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 2;
return 3; return 3;
} }
...@@ -350,7 +351,7 @@ static void get_new_segment(struct f2fs_sb_info *sbi, ...@@ -350,7 +351,7 @@ static void get_new_segment(struct f2fs_sb_info *sbi,
if (dir == ALLOC_RIGHT) { if (dir == ALLOC_RIGHT) {
secno = find_next_zero_bit(free_i->free_secmap, secno = find_next_zero_bit(free_i->free_secmap,
TOTAL_SECS(sbi), 0); TOTAL_SECS(sbi), 0);
BUG_ON(secno >= TOTAL_SECS(sbi)); f2fs_bug_on(secno >= TOTAL_SECS(sbi));
} else { } else {
go_left = 1; go_left = 1;
left_start = hint - 1; left_start = hint - 1;
...@@ -366,7 +367,7 @@ static void get_new_segment(struct f2fs_sb_info *sbi, ...@@ -366,7 +367,7 @@ static void get_new_segment(struct f2fs_sb_info *sbi,
} }
left_start = find_next_zero_bit(free_i->free_secmap, left_start = find_next_zero_bit(free_i->free_secmap,
TOTAL_SECS(sbi), 0); TOTAL_SECS(sbi), 0);
BUG_ON(left_start >= TOTAL_SECS(sbi)); f2fs_bug_on(left_start >= TOTAL_SECS(sbi));
break; break;
} }
secno = left_start; secno = left_start;
...@@ -405,7 +406,7 @@ static void get_new_segment(struct f2fs_sb_info *sbi, ...@@ -405,7 +406,7 @@ static void get_new_segment(struct f2fs_sb_info *sbi,
} }
got_it: got_it:
/* set it as dirty segment in free segmap */ /* 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); __set_inuse(sbi, segno);
*newseg = segno; *newseg = segno;
write_unlock(&free_i->segmap_lock); write_unlock(&free_i->segmap_lock);
...@@ -550,9 +551,8 @@ static void allocate_segment_by_default(struct f2fs_sb_info *sbi, ...@@ -550,9 +551,8 @@ static void allocate_segment_by_default(struct f2fs_sb_info *sbi,
change_curseg(sbi, type, true); change_curseg(sbi, type, true);
else else
new_curseg(sbi, type, false); new_curseg(sbi, type, false);
#ifdef CONFIG_F2FS_STAT_FS
sbi->segment_count[curseg->alloc_type]++; stat_inc_seg_type(sbi, curseg);
#endif
} }
void allocate_new_segments(struct f2fs_sb_info *sbi) void allocate_new_segments(struct f2fs_sb_info *sbi)
...@@ -597,6 +597,11 @@ static void f2fs_end_io_write(struct bio *bio, int err) ...@@ -597,6 +597,11 @@ static void f2fs_end_io_write(struct bio *bio, int err)
if (p->is_sync) if (p->is_sync)
complete(p->wait); 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); kfree(p);
bio_put(bio); bio_put(bio);
} }
...@@ -657,6 +662,7 @@ static void submit_write_page(struct f2fs_sb_info *sbi, struct page *page, ...@@ -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) block_t blk_addr, enum page_type type)
{ {
struct block_device *bdev = sbi->sb->s_bdev; struct block_device *bdev = sbi->sb->s_bdev;
int bio_blocks;
verify_block_addr(sbi, blk_addr); verify_block_addr(sbi, blk_addr);
...@@ -676,7 +682,8 @@ static void submit_write_page(struct f2fs_sb_info *sbi, struct page *page, ...@@ -676,7 +682,8 @@ static void submit_write_page(struct f2fs_sb_info *sbi, struct page *page,
goto retry; 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_sector = SECTOR_FROM_BLOCK(sbi, blk_addr);
sbi->bio[type]->bi_private = priv; sbi->bio[type]->bi_private = priv;
/* /*
...@@ -771,7 +778,7 @@ static int __get_segment_type(struct page *page, enum page_type p_type) ...@@ -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); return __get_segment_type_4(page, p_type);
} }
/* NR_CURSEG_TYPE(6) logs by default */ /* 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); 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, ...@@ -801,9 +808,8 @@ static void do_write_page(struct f2fs_sb_info *sbi, struct page *page,
mutex_lock(&sit_i->sentry_lock); mutex_lock(&sit_i->sentry_lock);
__refresh_next_blkoff(sbi, curseg); __refresh_next_blkoff(sbi, curseg);
#ifdef CONFIG_F2FS_STAT_FS
sbi->block_count[curseg->alloc_type]++; stat_inc_block_count(sbi, curseg);
#endif
/* /*
* SIT information should be updated before segment allocation, * SIT information should be updated before segment allocation,
...@@ -849,7 +855,7 @@ void write_data_page(struct inode *inode, struct page *page, ...@@ -849,7 +855,7 @@ void write_data_page(struct inode *inode, struct page *page,
struct f2fs_summary sum; struct f2fs_summary sum;
struct node_info ni; struct node_info ni;
BUG_ON(old_blkaddr == NULL_ADDR); f2fs_bug_on(old_blkaddr == NULL_ADDR);
get_node_info(sbi, dn->nid, &ni); get_node_info(sbi, dn->nid, &ni);
set_summary(&sum, dn->nid, dn->ofs_in_node, ni.version); 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) ...@@ -1122,8 +1128,6 @@ static void write_compacted_summaries(struct f2fs_sb_info *sbi, block_t blkaddr)
SUM_JOURNAL_SIZE); SUM_JOURNAL_SIZE);
written_size += SUM_JOURNAL_SIZE; written_size += SUM_JOURNAL_SIZE;
set_page_dirty(page);
/* Step 3: write summary entries */ /* Step 3: write summary entries */
for (i = CURSEG_HOT_DATA; i <= CURSEG_COLD_DATA; i++) { for (i = CURSEG_HOT_DATA; i <= CURSEG_COLD_DATA; i++) {
unsigned short blkoff; unsigned short blkoff;
...@@ -1142,18 +1146,20 @@ static void write_compacted_summaries(struct f2fs_sb_info *sbi, block_t blkaddr) ...@@ -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 = (struct f2fs_summary *)(kaddr + written_size);
*summary = seg_i->sum_blk->entries[j]; *summary = seg_i->sum_blk->entries[j];
written_size += SUMMARY_SIZE; written_size += SUMMARY_SIZE;
set_page_dirty(page);
if (written_size + SUMMARY_SIZE <= PAGE_CACHE_SIZE - if (written_size + SUMMARY_SIZE <= PAGE_CACHE_SIZE -
SUM_FOOTER_SIZE) SUM_FOOTER_SIZE)
continue; continue;
set_page_dirty(page);
f2fs_put_page(page, 1); f2fs_put_page(page, 1);
page = NULL; page = NULL;
} }
} }
if (page) if (page) {
set_page_dirty(page);
f2fs_put_page(page, 1); f2fs_put_page(page, 1);
}
} }
static void write_normal_summaries(struct f2fs_sb_info *sbi, 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, ...@@ -1239,7 +1245,7 @@ static struct page *get_next_sit_page(struct f2fs_sb_info *sbi,
/* get current sit block page without lock */ /* get current sit block page without lock */
src_page = get_meta_page(sbi, src_off); src_page = get_meta_page(sbi, src_off);
dst_page = grab_meta_page(sbi, dst_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); src_addr = page_address(src_page);
dst_addr = page_address(dst_page); dst_addr = page_address(dst_page);
...@@ -1271,9 +1277,9 @@ static bool flush_sits_in_journal(struct f2fs_sb_info *sbi) ...@@ -1271,9 +1277,9 @@ static bool flush_sits_in_journal(struct f2fs_sb_info *sbi)
__mark_sit_entry_dirty(sbi, segno); __mark_sit_entry_dirty(sbi, segno);
} }
update_sits_in_cursum(sum, -sits_in_cursum(sum)); 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) ...@@ -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->ovp_segments = le32_to_cpu(ckpt->overprov_segment_count);
sm_info->main_segments = le32_to_cpu(raw_super->segment_count_main); 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->ssa_blkaddr = le32_to_cpu(raw_super->ssa_blkaddr);
sm_info->rec_prefree_segments = DEF_RECLAIM_PREFREE_SEGMENTS;
err = build_sit_info(sbi); err = build_sit_info(sbi);
if (err) if (err)
...@@ -1744,6 +1751,8 @@ static void destroy_sit_info(struct f2fs_sb_info *sbi) ...@@ -1744,6 +1751,8 @@ static void destroy_sit_info(struct f2fs_sb_info *sbi)
void destroy_segment_manager(struct f2fs_sb_info *sbi) void destroy_segment_manager(struct f2fs_sb_info *sbi)
{ {
struct f2fs_sm_info *sm_info = SM_I(sbi); struct f2fs_sm_info *sm_info = SM_I(sbi);
if (!sm_info)
return;
destroy_dirty_segmap(sbi); destroy_dirty_segmap(sbi);
destroy_curseg(sbi); destroy_curseg(sbi);
destroy_free_segmap(sbi); destroy_free_segmap(sbi);
......
...@@ -14,6 +14,8 @@ ...@@ -14,6 +14,8 @@
#define NULL_SEGNO ((unsigned int)(~0)) #define NULL_SEGNO ((unsigned int)(~0))
#define NULL_SECNO ((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 */ /* 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_L2R_SEGNO(free_i, segno) (segno - free_i->start_segno)
#define GET_R2L_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 @@ ...@@ -90,6 +92,8 @@
(blk_addr << ((sbi)->log_blocksize - F2FS_LOG_SECTOR_SIZE)) (blk_addr << ((sbi)->log_blocksize - F2FS_LOG_SECTOR_SIZE))
#define SECTOR_TO_BLOCK(sbi, sectors) \ #define SECTOR_TO_BLOCK(sbi, sectors) \
(sectors >> ((sbi)->log_blocksize - F2FS_LOG_SECTOR_SIZE)) (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 */ /* during checkpoint, bio_private is used to synchronize the last bio */
struct bio_private { struct bio_private {
...@@ -470,6 +474,11 @@ static inline bool has_not_enough_free_secs(struct f2fs_sb_info *sbi, int freed) ...@@ -470,6 +474,11 @@ static inline bool has_not_enough_free_secs(struct f2fs_sb_info *sbi, int freed)
reserved_sections(sbi))); 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) static inline int utilization(struct f2fs_sb_info *sbi)
{ {
return div_u64((u64)valid_user_blocks(sbi) * 100, sbi->user_block_count); 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) ...@@ -513,16 +522,13 @@ static inline unsigned short curseg_blkoff(struct f2fs_sb_info *sbi, int type)
return curseg->next_blkoff; return curseg->next_blkoff;
} }
#ifdef CONFIG_F2FS_CHECK_FS
static inline void check_seg_range(struct f2fs_sb_info *sbi, unsigned int segno) static inline void check_seg_range(struct f2fs_sb_info *sbi, unsigned int segno)
{ {
unsigned int end_segno = SM_I(sbi)->segment_count - 1; unsigned int end_segno = SM_I(sbi)->segment_count - 1;
BUG_ON(segno > end_segno); 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) static inline void verify_block_addr(struct f2fs_sb_info *sbi, block_t blk_addr)
{ {
struct f2fs_sm_info *sm_info = SM_I(sbi); struct f2fs_sm_info *sm_info = SM_I(sbi);
...@@ -541,8 +547,9 @@ static inline void check_block_count(struct f2fs_sb_info *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); struct f2fs_sm_info *sm_info = SM_I(sbi);
unsigned int end_segno = sm_info->segment_count - 1; 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 valid_blocks = 0;
int i; int cur_pos = 0, next_pos;
/* check segment usage */ /* check segment usage */
BUG_ON(GET_SIT_VBLOCKS(raw_sit) > sbi->blocks_per_seg); 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, ...@@ -551,11 +558,26 @@ static inline void check_block_count(struct f2fs_sb_info *sbi,
BUG_ON(segno > end_segno); BUG_ON(segno > end_segno);
/* check bitmap with valid block count */ /* check bitmap with valid block count */
for (i = 0; i < sbi->blocks_per_seg; i++) do {
if (f2fs_test_bit(i, raw_sit->valid_map)) if (is_valid) {
valid_blocks++; 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); 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, static inline pgoff_t current_sit_addr(struct f2fs_sb_info *sbi,
unsigned int start) unsigned int start)
......
...@@ -43,7 +43,9 @@ enum { ...@@ -43,7 +43,9 @@ enum {
Opt_disable_roll_forward, Opt_disable_roll_forward,
Opt_discard, Opt_discard,
Opt_noheap, Opt_noheap,
Opt_user_xattr,
Opt_nouser_xattr, Opt_nouser_xattr,
Opt_acl,
Opt_noacl, Opt_noacl,
Opt_active_logs, Opt_active_logs,
Opt_disable_ext_identify, Opt_disable_ext_identify,
...@@ -56,7 +58,9 @@ static match_table_t f2fs_tokens = { ...@@ -56,7 +58,9 @@ static match_table_t f2fs_tokens = {
{Opt_disable_roll_forward, "disable_roll_forward"}, {Opt_disable_roll_forward, "disable_roll_forward"},
{Opt_discard, "discard"}, {Opt_discard, "discard"},
{Opt_noheap, "no_heap"}, {Opt_noheap, "no_heap"},
{Opt_user_xattr, "user_xattr"},
{Opt_nouser_xattr, "nouser_xattr"}, {Opt_nouser_xattr, "nouser_xattr"},
{Opt_acl, "acl"},
{Opt_noacl, "noacl"}, {Opt_noacl, "noacl"},
{Opt_active_logs, "active_logs=%u"}, {Opt_active_logs, "active_logs=%u"},
{Opt_disable_ext_identify, "disable_ext_identify"}, {Opt_disable_ext_identify, "disable_ext_identify"},
...@@ -65,24 +69,40 @@ static match_table_t f2fs_tokens = { ...@@ -65,24 +69,40 @@ static match_table_t f2fs_tokens = {
}; };
/* Sysfs support for f2fs */ /* Sysfs support for f2fs */
enum {
GC_THREAD, /* struct f2fs_gc_thread */
SM_INFO, /* struct f2fs_sm_info */
};
struct f2fs_attr { struct f2fs_attr {
struct attribute attr; struct attribute attr;
ssize_t (*show)(struct f2fs_attr *, struct f2fs_sb_info *, char *); ssize_t (*show)(struct f2fs_attr *, struct f2fs_sb_info *, char *);
ssize_t (*store)(struct f2fs_attr *, struct f2fs_sb_info *, ssize_t (*store)(struct f2fs_attr *, struct f2fs_sb_info *,
const char *, size_t); const char *, size_t);
int struct_type;
int offset; 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, static ssize_t f2fs_sbi_show(struct f2fs_attr *a,
struct f2fs_sb_info *sbi, char *buf) struct f2fs_sb_info *sbi, char *buf)
{ {
struct f2fs_gc_kthread *gc_kth = sbi->gc_thread; unsigned char *ptr = NULL;
unsigned int *ui; unsigned int *ui;
if (!gc_kth) ptr = __struct_ptr(sbi, a->struct_type);
if (!ptr)
return -EINVAL; return -EINVAL;
ui = (unsigned int *)(((char *)gc_kth) + a->offset); ui = (unsigned int *)(ptr + a->offset);
return snprintf(buf, PAGE_SIZE, "%u\n", *ui); return snprintf(buf, PAGE_SIZE, "%u\n", *ui);
} }
...@@ -91,15 +111,16 @@ static ssize_t f2fs_sbi_store(struct f2fs_attr *a, ...@@ -91,15 +111,16 @@ static ssize_t f2fs_sbi_store(struct f2fs_attr *a,
struct f2fs_sb_info *sbi, struct f2fs_sb_info *sbi,
const char *buf, size_t count) const char *buf, size_t count)
{ {
struct f2fs_gc_kthread *gc_kth = sbi->gc_thread; unsigned char *ptr;
unsigned long t; unsigned long t;
unsigned int *ui; unsigned int *ui;
ssize_t ret; ssize_t ret;
if (!gc_kth) ptr = __struct_ptr(sbi, a->struct_type);
if (!ptr)
return -EINVAL; return -EINVAL;
ui = (unsigned int *)(((char *)gc_kth) + a->offset); ui = (unsigned int *)(ptr + a->offset);
ret = kstrtoul(skip_spaces(buf), 0, &t); ret = kstrtoul(skip_spaces(buf), 0, &t);
if (ret < 0) if (ret < 0)
...@@ -135,21 +156,25 @@ static void f2fs_sb_release(struct kobject *kobj) ...@@ -135,21 +156,25 @@ static void f2fs_sb_release(struct kobject *kobj)
complete(&sbi->s_kobj_unregister); 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 = { \ static struct f2fs_attr f2fs_attr_##_name = { \
.attr = {.name = __stringify(_name), .mode = _mode }, \ .attr = {.name = __stringify(_name), .mode = _mode }, \
.show = _show, \ .show = _show, \
.store = _store, \ .store = _store, \
.offset = offsetof(struct f2fs_gc_kthread, _elname), \ .struct_type = _struct_type, \
.offset = _offset \
} }
#define F2FS_RW_ATTR(name, elname) \ #define F2FS_RW_ATTR(struct_type, struct_name, name, elname) \
F2FS_ATTR_OFFSET(name, 0644, f2fs_sbi_show, f2fs_sbi_store, 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_THREAD, f2fs_gc_kthread, gc_min_sleep_time, min_sleep_time);
F2FS_RW_ATTR(gc_max_sleep_time, max_sleep_time); F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_max_sleep_time, max_sleep_time);
F2FS_RW_ATTR(gc_no_gc_sleep_time, no_gc_sleep_time); F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, 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_idle, gc_idle);
F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, reclaim_segments, rec_prefree_segments);
#define ATTR_LIST(name) (&f2fs_attr_##name.attr) #define ATTR_LIST(name) (&f2fs_attr_##name.attr)
static struct attribute *f2fs_attrs[] = { static struct attribute *f2fs_attrs[] = {
...@@ -157,6 +182,7 @@ static struct attribute *f2fs_attrs[] = { ...@@ -157,6 +182,7 @@ static struct attribute *f2fs_attrs[] = {
ATTR_LIST(gc_max_sleep_time), ATTR_LIST(gc_max_sleep_time),
ATTR_LIST(gc_no_gc_sleep_time), ATTR_LIST(gc_no_gc_sleep_time),
ATTR_LIST(gc_idle), ATTR_LIST(gc_idle),
ATTR_LIST(reclaim_segments),
NULL, NULL,
}; };
...@@ -237,6 +263,9 @@ static int parse_options(struct super_block *sb, char *options) ...@@ -237,6 +263,9 @@ static int parse_options(struct super_block *sb, char *options)
set_opt(sbi, NOHEAP); set_opt(sbi, NOHEAP);
break; break;
#ifdef CONFIG_F2FS_FS_XATTR #ifdef CONFIG_F2FS_FS_XATTR
case Opt_user_xattr:
set_opt(sbi, XATTR_USER);
break;
case Opt_nouser_xattr: case Opt_nouser_xattr:
clear_opt(sbi, XATTR_USER); clear_opt(sbi, XATTR_USER);
break; break;
...@@ -244,6 +273,10 @@ static int parse_options(struct super_block *sb, char *options) ...@@ -244,6 +273,10 @@ static int parse_options(struct super_block *sb, char *options)
set_opt(sbi, INLINE_XATTR); set_opt(sbi, INLINE_XATTR);
break; break;
#else #else
case Opt_user_xattr:
f2fs_msg(sb, KERN_INFO,
"user_xattr options not supported");
break;
case Opt_nouser_xattr: case Opt_nouser_xattr:
f2fs_msg(sb, KERN_INFO, f2fs_msg(sb, KERN_INFO,
"nouser_xattr options not supported"); "nouser_xattr options not supported");
...@@ -254,10 +287,16 @@ static int parse_options(struct super_block *sb, char *options) ...@@ -254,10 +287,16 @@ static int parse_options(struct super_block *sb, char *options)
break; break;
#endif #endif
#ifdef CONFIG_F2FS_FS_POSIX_ACL #ifdef CONFIG_F2FS_FS_POSIX_ACL
case Opt_acl:
set_opt(sbi, POSIX_ACL);
break;
case Opt_noacl: case Opt_noacl:
clear_opt(sbi, POSIX_ACL); clear_opt(sbi, POSIX_ACL);
break; break;
#else #else
case Opt_acl:
f2fs_msg(sb, KERN_INFO, "acl options not supported");
break;
case Opt_noacl: case Opt_noacl:
f2fs_msg(sb, KERN_INFO, "noacl options not supported"); f2fs_msg(sb, KERN_INFO, "noacl options not supported");
break; break;
...@@ -355,6 +394,8 @@ static void f2fs_put_super(struct super_block *sb) ...@@ -355,6 +394,8 @@ static void f2fs_put_super(struct super_block *sb)
f2fs_destroy_stats(sbi); f2fs_destroy_stats(sbi);
stop_gc_thread(sbi); stop_gc_thread(sbi);
/* 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); write_checkpoint(sbi, true);
iput(sbi->node_inode); iput(sbi->node_inode);
...@@ -727,30 +768,47 @@ static void init_sb_info(struct f2fs_sb_info *sbi) ...@@ -727,30 +768,47 @@ static void init_sb_info(struct f2fs_sb_info *sbi)
atomic_set(&sbi->nr_pages[i], 0); atomic_set(&sbi->nr_pages[i], 0);
} }
static int validate_superblock(struct super_block *sb, /*
* 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 f2fs_super_block **raw_super,
struct buffer_head **raw_super_buf, sector_t block) 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); *raw_super_buf = sb_bread(sb, block);
if (!*raw_super_buf) { if (!*raw_super_buf) {
f2fs_msg(sb, KERN_ERR, "unable to read %s superblock", f2fs_msg(sb, KERN_ERR, "Unable to read %dth superblock",
super); block + 1);
if (block == 0) {
block++;
goto retry;
} else {
return -EIO; return -EIO;
} }
}
*raw_super = (struct f2fs_super_block *) *raw_super = (struct f2fs_super_block *)
((char *)(*raw_super_buf)->b_data + F2FS_SUPER_OFFSET); ((char *)(*raw_super_buf)->b_data + F2FS_SUPER_OFFSET);
/* sanity checking of raw super */ /* sanity checking of raw super */
if (!sanity_check_raw_super(sb, *raw_super)) if (sanity_check_raw_super(sb, *raw_super)) {
return 0; brelse(*raw_super_buf);
f2fs_msg(sb, KERN_ERR, "Can't find a valid F2FS filesystem " f2fs_msg(sb, KERN_ERR, "Can't find a valid F2FS filesystem "
"in %s superblock", super); "in %dth superblock", block + 1);
if(block == 0) {
block++;
goto retry;
} else {
return -EINVAL; return -EINVAL;
}
}
return 0;
} }
static int f2fs_fill_super(struct super_block *sb, void *data, int silent) 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) ...@@ -760,7 +818,6 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
struct buffer_head *raw_super_buf; struct buffer_head *raw_super_buf;
struct inode *root; struct inode *root;
long err = -EINVAL; long err = -EINVAL;
int i;
/* allocate memory for f2fs-specific super block info */ /* allocate memory for f2fs-specific super block info */
sbi = kzalloc(sizeof(struct f2fs_sb_info), GFP_KERNEL); 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) ...@@ -773,14 +830,10 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
goto free_sbi; goto free_sbi;
} }
err = validate_superblock(sb, &raw_super, &raw_super_buf, 0); err = read_raw_super_block(sb, &raw_super, &raw_super_buf);
if (err) {
brelse(raw_super_buf);
/* check secondary superblock when primary failed */
err = validate_superblock(sb, &raw_super, &raw_super_buf, 1);
if (err) if (err)
goto free_sb_buf; goto free_sbi;
}
sb->s_fs_info = sbi; sb->s_fs_info = sbi;
/* init some FS parameters */ /* init some FS parameters */
sbi->active_logs = NR_CURSEG_TYPE; sbi->active_logs = NR_CURSEG_TYPE;
...@@ -818,12 +871,12 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) ...@@ -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->gc_mutex);
mutex_init(&sbi->writepages); mutex_init(&sbi->writepages);
mutex_init(&sbi->cp_mutex); mutex_init(&sbi->cp_mutex);
for (i = 0; i < NR_GLOBAL_LOCKS; i++)
mutex_init(&sbi->fs_lock[i]);
mutex_init(&sbi->node_write); mutex_init(&sbi->node_write);
sbi->por_doing = 0; sbi->por_doing = false;
spin_lock_init(&sbi->stat_lock); spin_lock_init(&sbi->stat_lock);
init_rwsem(&sbi->bio_sem); init_rwsem(&sbi->bio_sem);
init_rwsem(&sbi->cp_rwsem);
init_waitqueue_head(&sbi->cp_wait);
init_sb_info(sbi); init_sb_info(sbi);
/* get an inode for meta space */ /* get an inode for meta space */
...@@ -922,12 +975,12 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) ...@@ -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.*/ /* After POR, we can run background GC thread.*/
err = start_gc_thread(sbi); err = start_gc_thread(sbi);
if (err) if (err)
goto fail; goto free_gc;
} }
err = f2fs_build_stats(sbi); err = f2fs_build_stats(sbi);
if (err) if (err)
goto fail; goto free_gc;
if (f2fs_proc_root) if (f2fs_proc_root)
sbi->s_proc = proc_mkdir(sb->s_id, 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) ...@@ -953,6 +1006,12 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
return 0; return 0;
fail: 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); stop_gc_thread(sbi);
free_root_inode: free_root_inode:
dput(sb->s_root); dput(sb->s_root);
......
...@@ -154,6 +154,9 @@ static int f2fs_xattr_advise_set(struct dentry *dentry, const char *name, ...@@ -154,6 +154,9 @@ static int f2fs_xattr_advise_set(struct dentry *dentry, const char *name,
} }
#ifdef CONFIG_F2FS_FS_SECURITY #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, static int f2fs_initxattrs(struct inode *inode, const struct xattr *xattr_array,
void *page) void *page)
{ {
...@@ -161,7 +164,7 @@ static int f2fs_initxattrs(struct inode *inode, const struct xattr *xattr_array, ...@@ -161,7 +164,7 @@ static int f2fs_initxattrs(struct inode *inode, const struct xattr *xattr_array,
int err = 0; int err = 0;
for (xattr = xattr_array; xattr->name != NULL; xattr++) { 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->name, xattr->value,
xattr->value_len, (struct page *)page); xattr->value_len, (struct page *)page);
if (err < 0) if (err < 0)
...@@ -369,7 +372,7 @@ static inline int write_all_xattrs(struct inode *inode, __u32 hsize, ...@@ -369,7 +372,7 @@ static inline int write_all_xattrs(struct inode *inode, __u32 hsize,
alloc_nid_failed(sbi, new_nid); alloc_nid_failed(sbi, new_nid);
return PTR_ERR(xpage); return PTR_ERR(xpage);
} }
BUG_ON(new_nid); f2fs_bug_on(new_nid);
} else { } else {
struct dnode_of_data dn; struct dnode_of_data dn;
set_new_dnode(&dn, inode, NULL, NULL, new_nid); 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) ...@@ -469,16 +472,15 @@ ssize_t f2fs_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size)
return error; return error;
} }
int f2fs_setxattr(struct inode *inode, int name_index, const char *name, static int __f2fs_setxattr(struct inode *inode, int name_index,
const void *value, size_t value_len, struct page *ipage) 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_inode_info *fi = F2FS_I(inode);
struct f2fs_xattr_entry *here, *last; struct f2fs_xattr_entry *here, *last;
void *base_addr; void *base_addr;
int found, newsize; int found, newsize;
size_t name_len; size_t name_len;
int ilock;
__u32 new_hsize; __u32 new_hsize;
int error = -ENOMEM; int error = -ENOMEM;
...@@ -493,10 +495,6 @@ int f2fs_setxattr(struct inode *inode, int name_index, const char *name, ...@@ -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)) if (name_len > F2FS_NAME_LEN || value_len > MAX_VALUE_LEN(inode))
return -ERANGE; return -ERANGE;
f2fs_balance_fs(sbi);
ilock = mutex_lock_op(sbi);
base_addr = read_all_xattrs(inode, ipage); base_addr = read_all_xattrs(inode, ipage);
if (!base_addr) if (!base_addr)
goto exit; goto exit;
...@@ -522,7 +520,7 @@ int f2fs_setxattr(struct inode *inode, int name_index, const char *name, ...@@ -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); free = MIN_OFFSET(inode) - ((char *)last - (char *)base_addr);
if (found) if (found)
free = free - ENTRY_SIZE(here); free = free + ENTRY_SIZE(here);
if (free < newsize) { if (free < newsize) {
error = -ENOSPC; error = -ENOSPC;
...@@ -578,7 +576,21 @@ int f2fs_setxattr(struct inode *inode, int name_index, const char *name, ...@@ -578,7 +576,21 @@ int f2fs_setxattr(struct inode *inode, int name_index, const char *name,
else else
update_inode_page(inode); update_inode_page(inode);
exit: exit:
mutex_unlock_op(sbi, ilock);
kzfree(base_addr); kzfree(base_addr);
return error; 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 @@ ...@@ -36,6 +36,11 @@
{ CURSEG_COLD_NODE, "Cold NODE" }, \ { CURSEG_COLD_NODE, "Cold NODE" }, \
{ NO_CHECK_TYPE, "No TYPE" }) { NO_CHECK_TYPE, "No TYPE" })
#define show_file_type(type) \
__print_symbolic(type, \
{ 0, "FILE" }, \
{ 1, "DIR" })
#define show_gc_type(type) \ #define show_gc_type(type) \
__print_symbolic(type, \ __print_symbolic(type, \
{ FG_GC, "Foreground GC" }, \ { FG_GC, "Foreground GC" }, \
...@@ -623,6 +628,52 @@ TRACE_EVENT(f2fs_do_submit_bio, ...@@ -623,6 +628,52 @@ TRACE_EVENT(f2fs_do_submit_bio,
__entry->size) __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, TRACE_EVENT(f2fs_submit_write_page,
TP_PROTO(struct page *page, block_t blk_addr, int type), TP_PROTO(struct page *page, block_t blk_addr, int type),
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment