f2fs fixes for v3.8-rc5
o Support swap file and link generic_file_remap_pages o Enhance the bio streaming flow and free section control o Major bug fix on recovery routine o Minor bug/warning fixes and code cleanups -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.11 (GNU/Linux) iQIcBAABAgAGBQJQ/fpIAAoJEEAUqH6CSFDS6BAP/jz/JIPoSu4NunWgVH68tzA4 xx4lsmJQJQG+1241uA9v4MMkcTzxE0QVNTOX3BpUXBhCMc00aPOPWlWjULridLI9 0vRE6LpG+NntkyKF+M5T1ydGuQoDlEvqoGs6c5p3yaI6PxzbzmBmipsmqXUA8fyu 280+OWJoAcALEMJiQ8JsHcDmvM9wdQ+BV/j3BNCm4dqBUA4dYPfDzRKUJYfwqiig qmVRseJJaekxrQ2lHG/K/WPAXa8aRcV6khP9tv/BPGRMt+I/fli/J4sWEFT6c73B +qYmhrf/RLNJ1O13dePlo3URwMu083PL8QN355GAKUJbMaX/UPjEnq0DLbBOkCS2 KBQI5O1eiFauEE6YU7p7GuvnLeVkukcXSQNVnRrnWzTUA9CMThZZ2mAgb2lz+iEP oZWNirRwnxdcTQRXjPyTCtpPTCgJi4GO1WS5s6HeLP8G8Muo4PzDzcEwMX0Mw5ih s4n4wpQ+Zp3h53cc/DxdFAK15uM3XYtUfb92kJwqaEG5VmBy6KvliXDRnNXg7WMI imCb08c0Fr0M8ZHOd+UCveICcndFj25jkjx8w7PoE1KBbGJkKf+cjpZ3OhOAliux sGtH3EZLV6jx1MjV79OpDXQGoVsvktesCbRcaxc7BbqljXYVNiap8QbzjPnmAt6z KKN0GU32eolGgK4Zd/iF =vJQc -----END PGP SIGNATURE----- Merge tag 'f2fs-for-3.8-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs Pull f2fs fixes from Jaegeuk Kim: o Support swap file and link generic_file_remap_pages o Enhance the bio streaming flow and free section control o Major bug fix on recovery routine o Minor bug/warning fixes and code cleanups * tag 'f2fs-for-3.8-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs: (22 commits) f2fs: use _safe() version of list_for_each f2fs: add comments of start_bidx_of_node f2fs: avoid issuing small bios due to several dirty node pages f2fs: support swapfile f2fs: add remap_pages as generic_file_remap_pages f2fs: add __init to functions in init_f2fs_fs f2fs: fix the debugfs entry creation path f2fs: add global mutex_lock to protect f2fs_stat_list f2fs: remove the blk_plug usage in f2fs_write_data_pages f2fs: avoid redundant time update for parent directory in f2fs_delete_entry f2fs: remove redundant call to set_blocksize in f2fs_fill_super f2fs: move f2fs_balance_fs to punch_hole f2fs: add f2fs_balance_fs in several interfaces f2fs: revisit the f2fs_gc flow f2fs: check return value during recovery f2fs: avoid null dereference in f2fs_acl_from_disk f2fs: initialize newly allocated dnode structure f2fs: update f2fs partition info about SIT/NAT layout f2fs: update f2fs document to reflect SIT/NAT layout correctly f2fs: remove unneeded INIT_LIST_HEAD at few places ...
This commit is contained in:
commit
05c2cf35c3
@ -175,9 +175,9 @@ consists of multiple segments as described below.
|
|||||||
align with the zone size <-|
|
align with the zone size <-|
|
||||||
|-> align with the segment size
|
|-> align with the segment size
|
||||||
_________________________________________________________________________
|
_________________________________________________________________________
|
||||||
| | | Node | Segment | Segment | |
|
| | | Segment | Node | Segment | |
|
||||||
| Superblock | Checkpoint | Address | Info. | Summary | Main |
|
| Superblock | Checkpoint | Info. | Address | Summary | Main |
|
||||||
| (SB) | (CP) | Table (NAT) | Table (SIT) | Area (SSA) | |
|
| (SB) | (CP) | Table (SIT) | Table (NAT) | Area (SSA) | |
|
||||||
|____________|_____2______|______N______|______N______|______N_____|__N___|
|
|____________|_____2______|______N______|______N______|______N_____|__N___|
|
||||||
. .
|
. .
|
||||||
. .
|
. .
|
||||||
@ -200,14 +200,14 @@ consists of multiple segments as described below.
|
|||||||
: It contains file system information, bitmaps for valid NAT/SIT sets, orphan
|
: It contains file system information, bitmaps for valid NAT/SIT sets, orphan
|
||||||
inode lists, and summary entries of current active segments.
|
inode lists, and summary entries of current active segments.
|
||||||
|
|
||||||
- Node Address Table (NAT)
|
|
||||||
: It is composed of a block address table for all the node blocks stored in
|
|
||||||
Main area.
|
|
||||||
|
|
||||||
- Segment Information Table (SIT)
|
- Segment Information Table (SIT)
|
||||||
: It contains segment information such as valid block count and bitmap for the
|
: It contains segment information such as valid block count and bitmap for the
|
||||||
validity of all the blocks.
|
validity of all the blocks.
|
||||||
|
|
||||||
|
- Node Address Table (NAT)
|
||||||
|
: It is composed of a block address table for all the node blocks stored in
|
||||||
|
Main area.
|
||||||
|
|
||||||
- Segment Summary Area (SSA)
|
- Segment Summary Area (SSA)
|
||||||
: It contains summary entries which contains the owner information of all the
|
: It contains summary entries which contains the owner information of all the
|
||||||
data and node blocks stored in Main area.
|
data and node blocks stored in Main area.
|
||||||
@ -236,13 +236,13 @@ For file system consistency, each CP points to which NAT and SIT copies are
|
|||||||
valid, as shown as below.
|
valid, as shown as below.
|
||||||
|
|
||||||
+--------+----------+---------+
|
+--------+----------+---------+
|
||||||
| CP | NAT | SIT |
|
| CP | SIT | NAT |
|
||||||
+--------+----------+---------+
|
+--------+----------+---------+
|
||||||
. . . .
|
. . . .
|
||||||
. . . .
|
. . . .
|
||||||
. . . .
|
. . . .
|
||||||
+-------+-------+--------+--------+--------+--------+
|
+-------+-------+--------+--------+--------+--------+
|
||||||
| CP #0 | CP #1 | NAT #0 | NAT #1 | SIT #0 | SIT #1 |
|
| CP #0 | CP #1 | SIT #0 | SIT #1 | NAT #0 | NAT #1 |
|
||||||
+-------+-------+--------+--------+--------+--------+
|
+-------+-------+--------+--------+--------+--------+
|
||||||
| ^ ^
|
| ^ ^
|
||||||
| | |
|
| | |
|
||||||
|
@ -191,15 +191,14 @@ struct posix_acl *f2fs_get_acl(struct inode *inode, int type)
|
|||||||
retval = f2fs_getxattr(inode, name_index, "", value, retval);
|
retval = f2fs_getxattr(inode, name_index, "", value, retval);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (retval < 0) {
|
if (retval > 0)
|
||||||
if (retval == -ENODATA)
|
acl = f2fs_acl_from_disk(value, retval);
|
||||||
|
else if (retval == -ENODATA)
|
||||||
acl = NULL;
|
acl = NULL;
|
||||||
else
|
else
|
||||||
acl = ERR_PTR(retval);
|
acl = ERR_PTR(retval);
|
||||||
} else {
|
|
||||||
acl = f2fs_acl_from_disk(value, retval);
|
|
||||||
}
|
|
||||||
kfree(value);
|
kfree(value);
|
||||||
|
|
||||||
if (!IS_ERR(acl))
|
if (!IS_ERR(acl))
|
||||||
set_cached_acl(inode, type, acl);
|
set_cached_acl(inode, type, acl);
|
||||||
|
|
||||||
|
@ -214,7 +214,6 @@ retry:
|
|||||||
goto retry;
|
goto retry;
|
||||||
}
|
}
|
||||||
new->ino = ino;
|
new->ino = ino;
|
||||||
INIT_LIST_HEAD(&new->list);
|
|
||||||
|
|
||||||
/* add new_oentry into list which is sorted by inode number */
|
/* add new_oentry into list which is sorted by inode number */
|
||||||
if (orphan) {
|
if (orphan) {
|
||||||
@ -772,7 +771,7 @@ void init_orphan_info(struct f2fs_sb_info *sbi)
|
|||||||
sbi->n_orphans = 0;
|
sbi->n_orphans = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int create_checkpoint_caches(void)
|
int __init create_checkpoint_caches(void)
|
||||||
{
|
{
|
||||||
orphan_entry_slab = f2fs_kmem_cache_create("f2fs_orphan_entry",
|
orphan_entry_slab = f2fs_kmem_cache_create("f2fs_orphan_entry",
|
||||||
sizeof(struct orphan_inode_entry), NULL);
|
sizeof(struct orphan_inode_entry), NULL);
|
||||||
|
@ -547,6 +547,15 @@ redirty_out:
|
|||||||
|
|
||||||
#define MAX_DESIRED_PAGES_WP 4096
|
#define MAX_DESIRED_PAGES_WP 4096
|
||||||
|
|
||||||
|
static int __f2fs_writepage(struct page *page, struct writeback_control *wbc,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
struct address_space *mapping = data;
|
||||||
|
int ret = mapping->a_ops->writepage(page, wbc);
|
||||||
|
mapping_set_error(mapping, ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static int f2fs_write_data_pages(struct address_space *mapping,
|
static int f2fs_write_data_pages(struct address_space *mapping,
|
||||||
struct writeback_control *wbc)
|
struct writeback_control *wbc)
|
||||||
{
|
{
|
||||||
@ -563,7 +572,7 @@ static int f2fs_write_data_pages(struct address_space *mapping,
|
|||||||
|
|
||||||
if (!S_ISDIR(inode->i_mode))
|
if (!S_ISDIR(inode->i_mode))
|
||||||
mutex_lock(&sbi->writepages);
|
mutex_lock(&sbi->writepages);
|
||||||
ret = generic_writepages(mapping, wbc);
|
ret = write_cache_pages(mapping, wbc, __f2fs_writepage, mapping);
|
||||||
if (!S_ISDIR(inode->i_mode))
|
if (!S_ISDIR(inode->i_mode))
|
||||||
mutex_unlock(&sbi->writepages);
|
mutex_unlock(&sbi->writepages);
|
||||||
f2fs_submit_bio(sbi, DATA, (wbc->sync_mode == WB_SYNC_ALL));
|
f2fs_submit_bio(sbi, DATA, (wbc->sync_mode == WB_SYNC_ALL));
|
||||||
@ -689,6 +698,11 @@ static int f2fs_set_data_page_dirty(struct page *page)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static sector_t f2fs_bmap(struct address_space *mapping, sector_t block)
|
||||||
|
{
|
||||||
|
return generic_block_bmap(mapping, block, get_data_block_ro);
|
||||||
|
}
|
||||||
|
|
||||||
const struct address_space_operations f2fs_dblock_aops = {
|
const struct address_space_operations f2fs_dblock_aops = {
|
||||||
.readpage = f2fs_read_data_page,
|
.readpage = f2fs_read_data_page,
|
||||||
.readpages = f2fs_read_data_pages,
|
.readpages = f2fs_read_data_pages,
|
||||||
@ -700,4 +714,5 @@ const struct address_space_operations f2fs_dblock_aops = {
|
|||||||
.invalidatepage = f2fs_invalidate_data_page,
|
.invalidatepage = f2fs_invalidate_data_page,
|
||||||
.releasepage = f2fs_release_data_page,
|
.releasepage = f2fs_release_data_page,
|
||||||
.direct_IO = f2fs_direct_IO,
|
.direct_IO = f2fs_direct_IO,
|
||||||
|
.bmap = f2fs_bmap,
|
||||||
};
|
};
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
|
|
||||||
static LIST_HEAD(f2fs_stat_list);
|
static LIST_HEAD(f2fs_stat_list);
|
||||||
static struct dentry *debugfs_root;
|
static struct dentry *debugfs_root;
|
||||||
|
static DEFINE_MUTEX(f2fs_stat_mutex);
|
||||||
|
|
||||||
static void update_general_status(struct f2fs_sb_info *sbi)
|
static void update_general_status(struct f2fs_sb_info *sbi)
|
||||||
{
|
{
|
||||||
@ -180,18 +181,14 @@ static int stat_show(struct seq_file *s, void *v)
|
|||||||
int i = 0;
|
int i = 0;
|
||||||
int j;
|
int j;
|
||||||
|
|
||||||
|
mutex_lock(&f2fs_stat_mutex);
|
||||||
list_for_each_entry_safe(si, next, &f2fs_stat_list, stat_list) {
|
list_for_each_entry_safe(si, next, &f2fs_stat_list, stat_list) {
|
||||||
|
|
||||||
mutex_lock(&si->stat_lock);
|
|
||||||
if (!si->sbi) {
|
|
||||||
mutex_unlock(&si->stat_lock);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
update_general_status(si->sbi);
|
update_general_status(si->sbi);
|
||||||
|
|
||||||
seq_printf(s, "\n=====[ partition info. #%d ]=====\n", i++);
|
seq_printf(s, "\n=====[ partition info. #%d ]=====\n", i++);
|
||||||
seq_printf(s, "[SB: 1] [CP: 2] [NAT: %d] [SIT: %d] ",
|
seq_printf(s, "[SB: 1] [CP: 2] [SIT: %d] [NAT: %d] ",
|
||||||
si->nat_area_segs, si->sit_area_segs);
|
si->sit_area_segs, si->nat_area_segs);
|
||||||
seq_printf(s, "[SSA: %d] [MAIN: %d",
|
seq_printf(s, "[SSA: %d] [MAIN: %d",
|
||||||
si->ssa_area_segs, si->main_area_segs);
|
si->ssa_area_segs, si->main_area_segs);
|
||||||
seq_printf(s, "(OverProv:%d Resv:%d)]\n\n",
|
seq_printf(s, "(OverProv:%d Resv:%d)]\n\n",
|
||||||
@ -286,8 +283,8 @@ static int stat_show(struct seq_file *s, void *v)
|
|||||||
seq_printf(s, "\nMemory: %u KB = static: %u + cached: %u\n",
|
seq_printf(s, "\nMemory: %u KB = static: %u + cached: %u\n",
|
||||||
(si->base_mem + si->cache_mem) >> 10,
|
(si->base_mem + si->cache_mem) >> 10,
|
||||||
si->base_mem >> 10, si->cache_mem >> 10);
|
si->base_mem >> 10, si->cache_mem >> 10);
|
||||||
mutex_unlock(&si->stat_lock);
|
|
||||||
}
|
}
|
||||||
|
mutex_unlock(&f2fs_stat_mutex);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -303,7 +300,7 @@ static const struct file_operations stat_fops = {
|
|||||||
.release = single_release,
|
.release = single_release,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int init_stats(struct f2fs_sb_info *sbi)
|
int f2fs_build_stats(struct f2fs_sb_info *sbi)
|
||||||
{
|
{
|
||||||
struct f2fs_super_block *raw_super = F2FS_RAW_SUPER(sbi);
|
struct f2fs_super_block *raw_super = F2FS_RAW_SUPER(sbi);
|
||||||
struct f2fs_stat_info *si;
|
struct f2fs_stat_info *si;
|
||||||
@ -313,9 +310,6 @@ static int init_stats(struct f2fs_sb_info *sbi)
|
|||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
si = sbi->stat_info;
|
si = sbi->stat_info;
|
||||||
mutex_init(&si->stat_lock);
|
|
||||||
list_add_tail(&si->stat_list, &f2fs_stat_list);
|
|
||||||
|
|
||||||
si->all_area_segs = le32_to_cpu(raw_super->segment_count);
|
si->all_area_segs = le32_to_cpu(raw_super->segment_count);
|
||||||
si->sit_area_segs = le32_to_cpu(raw_super->segment_count_sit);
|
si->sit_area_segs = le32_to_cpu(raw_super->segment_count_sit);
|
||||||
si->nat_area_segs = le32_to_cpu(raw_super->segment_count_nat);
|
si->nat_area_segs = le32_to_cpu(raw_super->segment_count_nat);
|
||||||
@ -325,21 +319,11 @@ static int init_stats(struct f2fs_sb_info *sbi)
|
|||||||
si->main_area_zones = si->main_area_sections /
|
si->main_area_zones = si->main_area_sections /
|
||||||
le32_to_cpu(raw_super->secs_per_zone);
|
le32_to_cpu(raw_super->secs_per_zone);
|
||||||
si->sbi = sbi;
|
si->sbi = sbi;
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int f2fs_build_stats(struct f2fs_sb_info *sbi)
|
mutex_lock(&f2fs_stat_mutex);
|
||||||
{
|
list_add_tail(&si->stat_list, &f2fs_stat_list);
|
||||||
int retval;
|
mutex_unlock(&f2fs_stat_mutex);
|
||||||
|
|
||||||
retval = init_stats(sbi);
|
|
||||||
if (retval)
|
|
||||||
return retval;
|
|
||||||
|
|
||||||
if (!debugfs_root)
|
|
||||||
debugfs_root = debugfs_create_dir("f2fs", NULL);
|
|
||||||
|
|
||||||
debugfs_create_file("status", S_IRUGO, debugfs_root, NULL, &stat_fops);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -347,14 +331,22 @@ void f2fs_destroy_stats(struct f2fs_sb_info *sbi)
|
|||||||
{
|
{
|
||||||
struct f2fs_stat_info *si = sbi->stat_info;
|
struct f2fs_stat_info *si = sbi->stat_info;
|
||||||
|
|
||||||
|
mutex_lock(&f2fs_stat_mutex);
|
||||||
list_del(&si->stat_list);
|
list_del(&si->stat_list);
|
||||||
mutex_lock(&si->stat_lock);
|
mutex_unlock(&f2fs_stat_mutex);
|
||||||
si->sbi = NULL;
|
|
||||||
mutex_unlock(&si->stat_lock);
|
|
||||||
kfree(sbi->stat_info);
|
kfree(sbi->stat_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
void destroy_root_stats(void)
|
void __init f2fs_create_root_stats(void)
|
||||||
|
{
|
||||||
|
debugfs_root = debugfs_create_dir("f2fs", NULL);
|
||||||
|
if (debugfs_root)
|
||||||
|
debugfs_create_file("status", S_IRUGO, debugfs_root,
|
||||||
|
NULL, &stat_fops);
|
||||||
|
}
|
||||||
|
|
||||||
|
void f2fs_destroy_root_stats(void)
|
||||||
{
|
{
|
||||||
debugfs_remove_recursive(debugfs_root);
|
debugfs_remove_recursive(debugfs_root);
|
||||||
debugfs_root = NULL;
|
debugfs_root = NULL;
|
||||||
|
@ -503,7 +503,7 @@ void f2fs_delete_entry(struct f2fs_dir_entry *dentry, struct page *page,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (inode) {
|
if (inode) {
|
||||||
inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
|
inode->i_ctime = CURRENT_TIME;
|
||||||
drop_nlink(inode);
|
drop_nlink(inode);
|
||||||
if (S_ISDIR(inode->i_mode)) {
|
if (S_ISDIR(inode->i_mode)) {
|
||||||
drop_nlink(inode);
|
drop_nlink(inode);
|
||||||
|
@ -211,11 +211,11 @@ struct dnode_of_data {
|
|||||||
static inline void set_new_dnode(struct dnode_of_data *dn, struct inode *inode,
|
static inline void set_new_dnode(struct dnode_of_data *dn, struct inode *inode,
|
||||||
struct page *ipage, struct page *npage, nid_t nid)
|
struct page *ipage, struct page *npage, nid_t nid)
|
||||||
{
|
{
|
||||||
|
memset(dn, 0, sizeof(*dn));
|
||||||
dn->inode = inode;
|
dn->inode = inode;
|
||||||
dn->inode_page = ipage;
|
dn->inode_page = ipage;
|
||||||
dn->node_page = npage;
|
dn->node_page = npage;
|
||||||
dn->nid = nid;
|
dn->nid = nid;
|
||||||
dn->inode_page_locked = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -877,6 +877,8 @@ bool f2fs_empty_dir(struct inode *);
|
|||||||
* super.c
|
* super.c
|
||||||
*/
|
*/
|
||||||
int f2fs_sync_fs(struct super_block *, int);
|
int f2fs_sync_fs(struct super_block *, int);
|
||||||
|
extern __printf(3, 4)
|
||||||
|
void f2fs_msg(struct super_block *, const char *, const char *, ...);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* hash.c
|
* hash.c
|
||||||
@ -912,7 +914,7 @@ int restore_node_summary(struct f2fs_sb_info *, unsigned int,
|
|||||||
void flush_nat_entries(struct f2fs_sb_info *);
|
void flush_nat_entries(struct f2fs_sb_info *);
|
||||||
int build_node_manager(struct f2fs_sb_info *);
|
int build_node_manager(struct f2fs_sb_info *);
|
||||||
void destroy_node_manager(struct f2fs_sb_info *);
|
void destroy_node_manager(struct f2fs_sb_info *);
|
||||||
int create_node_manager_caches(void);
|
int __init create_node_manager_caches(void);
|
||||||
void destroy_node_manager_caches(void);
|
void destroy_node_manager_caches(void);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -964,7 +966,7 @@ void sync_dirty_dir_inodes(struct f2fs_sb_info *);
|
|||||||
void block_operations(struct f2fs_sb_info *);
|
void block_operations(struct f2fs_sb_info *);
|
||||||
void write_checkpoint(struct f2fs_sb_info *, bool, bool);
|
void write_checkpoint(struct f2fs_sb_info *, bool, bool);
|
||||||
void init_orphan_info(struct f2fs_sb_info *);
|
void init_orphan_info(struct f2fs_sb_info *);
|
||||||
int create_checkpoint_caches(void);
|
int __init create_checkpoint_caches(void);
|
||||||
void destroy_checkpoint_caches(void);
|
void destroy_checkpoint_caches(void);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -984,9 +986,9 @@ int do_write_data_page(struct page *);
|
|||||||
int start_gc_thread(struct f2fs_sb_info *);
|
int start_gc_thread(struct f2fs_sb_info *);
|
||||||
void stop_gc_thread(struct f2fs_sb_info *);
|
void stop_gc_thread(struct f2fs_sb_info *);
|
||||||
block_t start_bidx_of_node(unsigned int);
|
block_t start_bidx_of_node(unsigned int);
|
||||||
int f2fs_gc(struct f2fs_sb_info *, int);
|
int f2fs_gc(struct f2fs_sb_info *);
|
||||||
void build_gc_manager(struct f2fs_sb_info *);
|
void build_gc_manager(struct f2fs_sb_info *);
|
||||||
int create_gc_caches(void);
|
int __init create_gc_caches(void);
|
||||||
void destroy_gc_caches(void);
|
void destroy_gc_caches(void);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1058,7 +1060,8 @@ struct f2fs_stat_info {
|
|||||||
|
|
||||||
int f2fs_build_stats(struct f2fs_sb_info *);
|
int f2fs_build_stats(struct f2fs_sb_info *);
|
||||||
void f2fs_destroy_stats(struct f2fs_sb_info *);
|
void f2fs_destroy_stats(struct f2fs_sb_info *);
|
||||||
void destroy_root_stats(void);
|
void __init f2fs_create_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_seg_count(si, type)
|
#define stat_inc_seg_count(si, type)
|
||||||
@ -1068,7 +1071,8 @@ void destroy_root_stats(void);
|
|||||||
|
|
||||||
static inline int f2fs_build_stats(struct f2fs_sb_info *sbi) { return 0; }
|
static inline int f2fs_build_stats(struct f2fs_sb_info *sbi) { return 0; }
|
||||||
static inline void f2fs_destroy_stats(struct f2fs_sb_info *sbi) { }
|
static inline void f2fs_destroy_stats(struct f2fs_sb_info *sbi) { }
|
||||||
static inline void destroy_root_stats(void) { }
|
static inline void __init f2fs_create_root_stats(void) { }
|
||||||
|
static inline void f2fs_destroy_root_stats(void) { }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern const struct file_operations f2fs_dir_operations;
|
extern const struct file_operations f2fs_dir_operations;
|
||||||
|
@ -98,6 +98,7 @@ out:
|
|||||||
static const struct vm_operations_struct f2fs_file_vm_ops = {
|
static const struct vm_operations_struct f2fs_file_vm_ops = {
|
||||||
.fault = filemap_fault,
|
.fault = filemap_fault,
|
||||||
.page_mkwrite = f2fs_vm_page_mkwrite,
|
.page_mkwrite = f2fs_vm_page_mkwrite,
|
||||||
|
.remap_pages = generic_file_remap_pages,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int need_to_sync_dir(struct f2fs_sb_info *sbi, struct inode *inode)
|
static int need_to_sync_dir(struct f2fs_sb_info *sbi, struct inode *inode)
|
||||||
@ -137,6 +138,9 @@ int f2fs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
|
|||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
/* guarantee free sections for fsync */
|
||||||
|
f2fs_balance_fs(sbi);
|
||||||
|
|
||||||
mutex_lock(&inode->i_mutex);
|
mutex_lock(&inode->i_mutex);
|
||||||
|
|
||||||
if (datasync && !(inode->i_state & I_DIRTY_DATASYNC))
|
if (datasync && !(inode->i_state & I_DIRTY_DATASYNC))
|
||||||
@ -407,6 +411,8 @@ int truncate_hole(struct inode *inode, pgoff_t pg_start, pgoff_t pg_end)
|
|||||||
struct dnode_of_data dn;
|
struct dnode_of_data dn;
|
||||||
struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
|
struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
|
||||||
|
|
||||||
|
f2fs_balance_fs(sbi);
|
||||||
|
|
||||||
mutex_lock_op(sbi, DATA_TRUNC);
|
mutex_lock_op(sbi, DATA_TRUNC);
|
||||||
set_new_dnode(&dn, inode, NULL, NULL, 0);
|
set_new_dnode(&dn, inode, NULL, NULL, 0);
|
||||||
err = get_dnode_of_data(&dn, index, RDONLY_NODE);
|
err = get_dnode_of_data(&dn, index, RDONLY_NODE);
|
||||||
@ -534,7 +540,6 @@ static long f2fs_fallocate(struct file *file, int mode,
|
|||||||
loff_t offset, loff_t len)
|
loff_t offset, loff_t len)
|
||||||
{
|
{
|
||||||
struct inode *inode = file->f_path.dentry->d_inode;
|
struct inode *inode = file->f_path.dentry->d_inode;
|
||||||
struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
|
|
||||||
long ret;
|
long ret;
|
||||||
|
|
||||||
if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE))
|
if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE))
|
||||||
@ -545,7 +550,10 @@ static long f2fs_fallocate(struct file *file, int mode,
|
|||||||
else
|
else
|
||||||
ret = expand_inode_data(inode, offset, len, mode);
|
ret = expand_inode_data(inode, offset, len, mode);
|
||||||
|
|
||||||
f2fs_balance_fs(sbi);
|
if (!ret) {
|
||||||
|
inode->i_mtime = inode->i_ctime = CURRENT_TIME;
|
||||||
|
mark_inode_dirty(inode);
|
||||||
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
50
fs/f2fs/gc.c
50
fs/f2fs/gc.c
@ -78,7 +78,7 @@ static int gc_thread_func(void *data)
|
|||||||
|
|
||||||
sbi->bg_gc++;
|
sbi->bg_gc++;
|
||||||
|
|
||||||
if (f2fs_gc(sbi, 1) == GC_NONE)
|
if (f2fs_gc(sbi) == GC_NONE)
|
||||||
wait_ms = GC_THREAD_NOGC_SLEEP_TIME;
|
wait_ms = GC_THREAD_NOGC_SLEEP_TIME;
|
||||||
else if (wait_ms == GC_THREAD_NOGC_SLEEP_TIME)
|
else if (wait_ms == GC_THREAD_NOGC_SLEEP_TIME)
|
||||||
wait_ms = GC_THREAD_MAX_SLEEP_TIME;
|
wait_ms = GC_THREAD_MAX_SLEEP_TIME;
|
||||||
@ -424,7 +424,11 @@ next_step:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Calculate start block index that this node page contains
|
* Calculate start block index indicating the given node offset.
|
||||||
|
* Be careful, caller should give this node offset only indicating direct node
|
||||||
|
* blocks. If any node offsets, which point the other types of node blocks such
|
||||||
|
* as indirect or double indirect node blocks, are given, it must be a caller's
|
||||||
|
* bug.
|
||||||
*/
|
*/
|
||||||
block_t start_bidx_of_node(unsigned int node_ofs)
|
block_t start_bidx_of_node(unsigned int node_ofs)
|
||||||
{
|
{
|
||||||
@ -651,37 +655,23 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi, unsigned int segno,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int f2fs_gc(struct f2fs_sb_info *sbi, int nGC)
|
int f2fs_gc(struct f2fs_sb_info *sbi)
|
||||||
{
|
{
|
||||||
unsigned int segno;
|
|
||||||
int old_free_secs, cur_free_secs;
|
|
||||||
int gc_status, nfree;
|
|
||||||
struct list_head ilist;
|
struct list_head ilist;
|
||||||
|
unsigned int segno, i;
|
||||||
int gc_type = BG_GC;
|
int gc_type = BG_GC;
|
||||||
|
int gc_status = GC_NONE;
|
||||||
|
|
||||||
INIT_LIST_HEAD(&ilist);
|
INIT_LIST_HEAD(&ilist);
|
||||||
gc_more:
|
gc_more:
|
||||||
nfree = 0;
|
if (!(sbi->sb->s_flags & MS_ACTIVE))
|
||||||
gc_status = GC_NONE;
|
goto stop;
|
||||||
|
|
||||||
if (has_not_enough_free_secs(sbi))
|
|
||||||
old_free_secs = reserved_sections(sbi);
|
|
||||||
else
|
|
||||||
old_free_secs = free_sections(sbi);
|
|
||||||
|
|
||||||
while (sbi->sb->s_flags & MS_ACTIVE) {
|
|
||||||
int i;
|
|
||||||
if (has_not_enough_free_secs(sbi))
|
if (has_not_enough_free_secs(sbi))
|
||||||
gc_type = FG_GC;
|
gc_type = FG_GC;
|
||||||
|
|
||||||
cur_free_secs = free_sections(sbi) + nfree;
|
|
||||||
|
|
||||||
/* We got free space successfully. */
|
|
||||||
if (nGC < cur_free_secs - old_free_secs)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (!__get_victim(sbi, &segno, gc_type, NO_CHECK_TYPE))
|
if (!__get_victim(sbi, &segno, gc_type, NO_CHECK_TYPE))
|
||||||
break;
|
goto stop;
|
||||||
|
|
||||||
for (i = 0; i < sbi->segs_per_sec; i++) {
|
for (i = 0; i < sbi->segs_per_sec; i++) {
|
||||||
/*
|
/*
|
||||||
@ -690,23 +680,19 @@ gc_more:
|
|||||||
* If GC is finished uncleanly, we have to return
|
* If GC is finished uncleanly, we have to return
|
||||||
* the victim to dirty segment list.
|
* the victim to dirty segment list.
|
||||||
*/
|
*/
|
||||||
gc_status = do_garbage_collect(sbi, segno + i,
|
gc_status = do_garbage_collect(sbi, segno + i, &ilist, gc_type);
|
||||||
&ilist, gc_type);
|
|
||||||
if (gc_status != GC_DONE)
|
if (gc_status != GC_DONE)
|
||||||
goto stop;
|
break;
|
||||||
nfree++;
|
|
||||||
}
|
}
|
||||||
}
|
if (has_not_enough_free_secs(sbi)) {
|
||||||
stop:
|
|
||||||
if (has_not_enough_free_secs(sbi) || gc_status == GC_BLOCKED) {
|
|
||||||
write_checkpoint(sbi, (gc_status == GC_BLOCKED), false);
|
write_checkpoint(sbi, (gc_status == GC_BLOCKED), false);
|
||||||
if (nfree)
|
if (has_not_enough_free_secs(sbi))
|
||||||
goto gc_more;
|
goto gc_more;
|
||||||
}
|
}
|
||||||
|
stop:
|
||||||
mutex_unlock(&sbi->gc_mutex);
|
mutex_unlock(&sbi->gc_mutex);
|
||||||
|
|
||||||
put_gc_inode(&ilist);
|
put_gc_inode(&ilist);
|
||||||
BUG_ON(!list_empty(&ilist));
|
|
||||||
return gc_status;
|
return gc_status;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -715,7 +701,7 @@ void build_gc_manager(struct f2fs_sb_info *sbi)
|
|||||||
DIRTY_I(sbi)->v_ops = &default_v_ops;
|
DIRTY_I(sbi)->v_ops = &default_v_ops;
|
||||||
}
|
}
|
||||||
|
|
||||||
int create_gc_caches(void)
|
int __init create_gc_caches(void)
|
||||||
{
|
{
|
||||||
winode_slab = f2fs_kmem_cache_create("f2fs_gc_inodes",
|
winode_slab = f2fs_kmem_cache_create("f2fs_gc_inodes",
|
||||||
sizeof(struct inode_entry), NULL);
|
sizeof(struct inode_entry), NULL);
|
||||||
|
@ -217,6 +217,9 @@ int f2fs_write_inode(struct inode *inode, struct writeback_control *wbc)
|
|||||||
inode->i_ino == F2FS_META_INO(sbi))
|
inode->i_ino == F2FS_META_INO(sbi))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
if (wbc)
|
||||||
|
f2fs_balance_fs(sbi);
|
||||||
|
|
||||||
node_page = get_node_page(sbi, inode->i_ino);
|
node_page = get_node_page(sbi, inode->i_ino);
|
||||||
if (IS_ERR(node_page))
|
if (IS_ERR(node_page))
|
||||||
return PTR_ERR(node_page);
|
return PTR_ERR(node_page);
|
||||||
|
@ -1124,6 +1124,12 @@ static int f2fs_write_node_page(struct page *page,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* It is very important to gather dirty pages and write at once, so that we can
|
||||||
|
* submit a big bio without interfering other data writes.
|
||||||
|
* Be default, 512 pages (2MB), a segment size, is quite reasonable.
|
||||||
|
*/
|
||||||
|
#define COLLECT_DIRTY_NODES 512
|
||||||
static int f2fs_write_node_pages(struct address_space *mapping,
|
static int f2fs_write_node_pages(struct address_space *mapping,
|
||||||
struct writeback_control *wbc)
|
struct writeback_control *wbc)
|
||||||
{
|
{
|
||||||
@ -1131,17 +1137,16 @@ static int f2fs_write_node_pages(struct address_space *mapping,
|
|||||||
struct block_device *bdev = sbi->sb->s_bdev;
|
struct block_device *bdev = sbi->sb->s_bdev;
|
||||||
long nr_to_write = wbc->nr_to_write;
|
long nr_to_write = wbc->nr_to_write;
|
||||||
|
|
||||||
if (wbc->for_kupdate)
|
/* First check balancing cached NAT entries */
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (get_pages(sbi, F2FS_DIRTY_NODES) == 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (try_to_free_nats(sbi, NAT_ENTRY_PER_BLOCK)) {
|
if (try_to_free_nats(sbi, NAT_ENTRY_PER_BLOCK)) {
|
||||||
write_checkpoint(sbi, false, false);
|
write_checkpoint(sbi, false, false);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* collect a number of dirty node pages and write together */
|
||||||
|
if (get_pages(sbi, F2FS_DIRTY_NODES) < COLLECT_DIRTY_NODES)
|
||||||
|
return 0;
|
||||||
|
|
||||||
/* if mounting is failed, skip writing node pages */
|
/* if mounting is failed, skip writing node pages */
|
||||||
wbc->nr_to_write = bio_get_nr_vecs(bdev);
|
wbc->nr_to_write = bio_get_nr_vecs(bdev);
|
||||||
sync_node_pages(sbi, 0, wbc);
|
sync_node_pages(sbi, 0, wbc);
|
||||||
@ -1732,7 +1737,7 @@ void destroy_node_manager(struct f2fs_sb_info *sbi)
|
|||||||
kfree(nm_i);
|
kfree(nm_i);
|
||||||
}
|
}
|
||||||
|
|
||||||
int create_node_manager_caches(void)
|
int __init create_node_manager_caches(void)
|
||||||
{
|
{
|
||||||
nat_entry_slab = f2fs_kmem_cache_create("nat_entry",
|
nat_entry_slab = f2fs_kmem_cache_create("nat_entry",
|
||||||
sizeof(struct nat_entry), NULL);
|
sizeof(struct nat_entry), NULL);
|
||||||
|
@ -67,7 +67,7 @@ static int recover_dentry(struct page *ipage, struct inode *inode)
|
|||||||
kunmap(page);
|
kunmap(page);
|
||||||
f2fs_put_page(page, 0);
|
f2fs_put_page(page, 0);
|
||||||
} else {
|
} else {
|
||||||
f2fs_add_link(&dent, inode);
|
err = f2fs_add_link(&dent, inode);
|
||||||
}
|
}
|
||||||
iput(dir);
|
iput(dir);
|
||||||
out:
|
out:
|
||||||
@ -151,7 +151,6 @@ static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head)
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
INIT_LIST_HEAD(&entry->list);
|
|
||||||
list_add_tail(&entry->list, head);
|
list_add_tail(&entry->list, head);
|
||||||
entry->blkaddr = blkaddr;
|
entry->blkaddr = blkaddr;
|
||||||
}
|
}
|
||||||
@ -174,10 +173,9 @@ out:
|
|||||||
static void destroy_fsync_dnodes(struct f2fs_sb_info *sbi,
|
static void destroy_fsync_dnodes(struct f2fs_sb_info *sbi,
|
||||||
struct list_head *head)
|
struct list_head *head)
|
||||||
{
|
{
|
||||||
struct list_head *this;
|
struct fsync_inode_entry *entry, *tmp;
|
||||||
struct fsync_inode_entry *entry;
|
|
||||||
list_for_each(this, head) {
|
list_for_each_entry_safe(entry, tmp, head, list) {
|
||||||
entry = list_entry(this, struct fsync_inode_entry, list);
|
|
||||||
iput(entry->inode);
|
iput(entry->inode);
|
||||||
list_del(&entry->list);
|
list_del(&entry->list);
|
||||||
kmem_cache_free(fsync_entry_slab, entry);
|
kmem_cache_free(fsync_entry_slab, entry);
|
||||||
|
@ -31,7 +31,7 @@ void f2fs_balance_fs(struct f2fs_sb_info *sbi)
|
|||||||
*/
|
*/
|
||||||
if (has_not_enough_free_secs(sbi)) {
|
if (has_not_enough_free_secs(sbi)) {
|
||||||
mutex_lock(&sbi->gc_mutex);
|
mutex_lock(&sbi->gc_mutex);
|
||||||
f2fs_gc(sbi, 1);
|
f2fs_gc(sbi);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,6 +53,18 @@ static match_table_t f2fs_tokens = {
|
|||||||
{Opt_err, NULL},
|
{Opt_err, NULL},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void f2fs_msg(struct super_block *sb, const char *level, const char *fmt, ...)
|
||||||
|
{
|
||||||
|
struct va_format vaf;
|
||||||
|
va_list args;
|
||||||
|
|
||||||
|
va_start(args, fmt);
|
||||||
|
vaf.fmt = fmt;
|
||||||
|
vaf.va = &args;
|
||||||
|
printk("%sF2FS-fs (%s): %pV\n", level, sb->s_id, &vaf);
|
||||||
|
va_end(args);
|
||||||
|
}
|
||||||
|
|
||||||
static void init_once(void *foo)
|
static void init_once(void *foo)
|
||||||
{
|
{
|
||||||
struct f2fs_inode_info *fi = (struct f2fs_inode_info *) foo;
|
struct f2fs_inode_info *fi = (struct f2fs_inode_info *) foo;
|
||||||
@ -125,6 +137,8 @@ int f2fs_sync_fs(struct super_block *sb, int sync)
|
|||||||
|
|
||||||
if (sync)
|
if (sync)
|
||||||
write_checkpoint(sbi, false, false);
|
write_checkpoint(sbi, false, false);
|
||||||
|
else
|
||||||
|
f2fs_balance_fs(sbi);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -247,7 +261,8 @@ static const struct export_operations f2fs_export_ops = {
|
|||||||
.get_parent = f2fs_get_parent,
|
.get_parent = f2fs_get_parent,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int parse_options(struct f2fs_sb_info *sbi, char *options)
|
static int parse_options(struct super_block *sb, struct f2fs_sb_info *sbi,
|
||||||
|
char *options)
|
||||||
{
|
{
|
||||||
substring_t args[MAX_OPT_ARGS];
|
substring_t args[MAX_OPT_ARGS];
|
||||||
char *p;
|
char *p;
|
||||||
@ -286,7 +301,8 @@ static int parse_options(struct f2fs_sb_info *sbi, char *options)
|
|||||||
break;
|
break;
|
||||||
#else
|
#else
|
||||||
case Opt_nouser_xattr:
|
case Opt_nouser_xattr:
|
||||||
pr_info("nouser_xattr options not supported\n");
|
f2fs_msg(sb, KERN_INFO,
|
||||||
|
"nouser_xattr options not supported");
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
#ifdef CONFIG_F2FS_FS_POSIX_ACL
|
#ifdef CONFIG_F2FS_FS_POSIX_ACL
|
||||||
@ -295,7 +311,7 @@ static int parse_options(struct f2fs_sb_info *sbi, char *options)
|
|||||||
break;
|
break;
|
||||||
#else
|
#else
|
||||||
case Opt_noacl:
|
case Opt_noacl:
|
||||||
pr_info("noacl options not supported\n");
|
f2fs_msg(sb, KERN_INFO, "noacl options not supported");
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
case Opt_active_logs:
|
case Opt_active_logs:
|
||||||
@ -309,7 +325,8 @@ static int parse_options(struct f2fs_sb_info *sbi, char *options)
|
|||||||
set_opt(sbi, DISABLE_EXT_IDENTIFY);
|
set_opt(sbi, DISABLE_EXT_IDENTIFY);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
pr_err("Unrecognized mount option \"%s\" or missing value\n",
|
f2fs_msg(sb, KERN_ERR,
|
||||||
|
"Unrecognized mount option \"%s\" or missing value",
|
||||||
p);
|
p);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
@ -337,23 +354,36 @@ static loff_t max_file_size(unsigned bits)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sanity_check_raw_super(struct f2fs_super_block *raw_super)
|
static int sanity_check_raw_super(struct super_block *sb,
|
||||||
|
struct f2fs_super_block *raw_super)
|
||||||
{
|
{
|
||||||
unsigned int blocksize;
|
unsigned int blocksize;
|
||||||
|
|
||||||
if (F2FS_SUPER_MAGIC != le32_to_cpu(raw_super->magic))
|
if (F2FS_SUPER_MAGIC != le32_to_cpu(raw_super->magic)) {
|
||||||
|
f2fs_msg(sb, KERN_INFO,
|
||||||
|
"Magic Mismatch, valid(0x%x) - read(0x%x)",
|
||||||
|
F2FS_SUPER_MAGIC, le32_to_cpu(raw_super->magic));
|
||||||
return 1;
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
/* Currently, support only 4KB block size */
|
/* Currently, support only 4KB block size */
|
||||||
blocksize = 1 << le32_to_cpu(raw_super->log_blocksize);
|
blocksize = 1 << le32_to_cpu(raw_super->log_blocksize);
|
||||||
if (blocksize != PAGE_CACHE_SIZE)
|
if (blocksize != PAGE_CACHE_SIZE) {
|
||||||
|
f2fs_msg(sb, KERN_INFO,
|
||||||
|
"Invalid blocksize (%u), supports only 4KB\n",
|
||||||
|
blocksize);
|
||||||
return 1;
|
return 1;
|
||||||
|
}
|
||||||
if (le32_to_cpu(raw_super->log_sectorsize) !=
|
if (le32_to_cpu(raw_super->log_sectorsize) !=
|
||||||
F2FS_LOG_SECTOR_SIZE)
|
F2FS_LOG_SECTOR_SIZE) {
|
||||||
|
f2fs_msg(sb, KERN_INFO, "Invalid log sectorsize");
|
||||||
return 1;
|
return 1;
|
||||||
|
}
|
||||||
if (le32_to_cpu(raw_super->log_sectors_per_block) !=
|
if (le32_to_cpu(raw_super->log_sectors_per_block) !=
|
||||||
F2FS_LOG_SECTORS_PER_BLOCK)
|
F2FS_LOG_SECTORS_PER_BLOCK) {
|
||||||
|
f2fs_msg(sb, KERN_INFO, "Invalid log sectors per block");
|
||||||
return 1;
|
return 1;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -413,14 +443,17 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
|
|||||||
if (!sbi)
|
if (!sbi)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
/* set a temporary block size */
|
/* set a block size */
|
||||||
if (!sb_set_blocksize(sb, F2FS_BLKSIZE))
|
if (!sb_set_blocksize(sb, F2FS_BLKSIZE)) {
|
||||||
|
f2fs_msg(sb, KERN_ERR, "unable to set blocksize");
|
||||||
goto free_sbi;
|
goto free_sbi;
|
||||||
|
}
|
||||||
|
|
||||||
/* read f2fs raw super block */
|
/* read f2fs raw super block */
|
||||||
raw_super_buf = sb_bread(sb, 0);
|
raw_super_buf = sb_bread(sb, 0);
|
||||||
if (!raw_super_buf) {
|
if (!raw_super_buf) {
|
||||||
err = -EIO;
|
err = -EIO;
|
||||||
|
f2fs_msg(sb, KERN_ERR, "unable to read superblock");
|
||||||
goto free_sbi;
|
goto free_sbi;
|
||||||
}
|
}
|
||||||
raw_super = (struct f2fs_super_block *)
|
raw_super = (struct f2fs_super_block *)
|
||||||
@ -438,12 +471,14 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
|
|||||||
set_opt(sbi, POSIX_ACL);
|
set_opt(sbi, POSIX_ACL);
|
||||||
#endif
|
#endif
|
||||||
/* parse mount options */
|
/* parse mount options */
|
||||||
if (parse_options(sbi, (char *)data))
|
if (parse_options(sb, sbi, (char *)data))
|
||||||
goto free_sb_buf;
|
goto free_sb_buf;
|
||||||
|
|
||||||
/* sanity checking of raw super */
|
/* sanity checking of raw super */
|
||||||
if (sanity_check_raw_super(raw_super))
|
if (sanity_check_raw_super(sb, raw_super)) {
|
||||||
|
f2fs_msg(sb, KERN_ERR, "Can't find a valid F2FS filesystem");
|
||||||
goto free_sb_buf;
|
goto free_sb_buf;
|
||||||
|
}
|
||||||
|
|
||||||
sb->s_maxbytes = max_file_size(le32_to_cpu(raw_super->log_blocksize));
|
sb->s_maxbytes = max_file_size(le32_to_cpu(raw_super->log_blocksize));
|
||||||
sb->s_max_links = F2FS_LINK_MAX;
|
sb->s_max_links = F2FS_LINK_MAX;
|
||||||
@ -477,18 +512,23 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
|
|||||||
/* get an inode for meta space */
|
/* get an inode for meta space */
|
||||||
sbi->meta_inode = f2fs_iget(sb, F2FS_META_INO(sbi));
|
sbi->meta_inode = f2fs_iget(sb, F2FS_META_INO(sbi));
|
||||||
if (IS_ERR(sbi->meta_inode)) {
|
if (IS_ERR(sbi->meta_inode)) {
|
||||||
|
f2fs_msg(sb, KERN_ERR, "Failed to read F2FS meta data inode");
|
||||||
err = PTR_ERR(sbi->meta_inode);
|
err = PTR_ERR(sbi->meta_inode);
|
||||||
goto free_sb_buf;
|
goto free_sb_buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = get_valid_checkpoint(sbi);
|
err = get_valid_checkpoint(sbi);
|
||||||
if (err)
|
if (err) {
|
||||||
|
f2fs_msg(sb, KERN_ERR, "Failed to get valid F2FS checkpoint");
|
||||||
goto free_meta_inode;
|
goto free_meta_inode;
|
||||||
|
}
|
||||||
|
|
||||||
/* sanity checking of checkpoint */
|
/* sanity checking of checkpoint */
|
||||||
err = -EINVAL;
|
err = -EINVAL;
|
||||||
if (sanity_check_ckpt(raw_super, sbi->ckpt))
|
if (sanity_check_ckpt(raw_super, sbi->ckpt)) {
|
||||||
|
f2fs_msg(sb, KERN_ERR, "Invalid F2FS checkpoint");
|
||||||
goto free_cp;
|
goto free_cp;
|
||||||
|
}
|
||||||
|
|
||||||
sbi->total_valid_node_count =
|
sbi->total_valid_node_count =
|
||||||
le32_to_cpu(sbi->ckpt->valid_node_count);
|
le32_to_cpu(sbi->ckpt->valid_node_count);
|
||||||
@ -502,25 +542,28 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
|
|||||||
INIT_LIST_HEAD(&sbi->dir_inode_list);
|
INIT_LIST_HEAD(&sbi->dir_inode_list);
|
||||||
spin_lock_init(&sbi->dir_inode_lock);
|
spin_lock_init(&sbi->dir_inode_lock);
|
||||||
|
|
||||||
/* init super block */
|
|
||||||
if (!sb_set_blocksize(sb, sbi->blocksize))
|
|
||||||
goto free_cp;
|
|
||||||
|
|
||||||
init_orphan_info(sbi);
|
init_orphan_info(sbi);
|
||||||
|
|
||||||
/* setup f2fs internal modules */
|
/* setup f2fs internal modules */
|
||||||
err = build_segment_manager(sbi);
|
err = build_segment_manager(sbi);
|
||||||
if (err)
|
if (err) {
|
||||||
|
f2fs_msg(sb, KERN_ERR,
|
||||||
|
"Failed to initialize F2FS segment manager");
|
||||||
goto free_sm;
|
goto free_sm;
|
||||||
|
}
|
||||||
err = build_node_manager(sbi);
|
err = build_node_manager(sbi);
|
||||||
if (err)
|
if (err) {
|
||||||
|
f2fs_msg(sb, KERN_ERR,
|
||||||
|
"Failed to initialize F2FS node manager");
|
||||||
goto free_nm;
|
goto free_nm;
|
||||||
|
}
|
||||||
|
|
||||||
build_gc_manager(sbi);
|
build_gc_manager(sbi);
|
||||||
|
|
||||||
/* get an inode for node space */
|
/* get an inode for node space */
|
||||||
sbi->node_inode = f2fs_iget(sb, F2FS_NODE_INO(sbi));
|
sbi->node_inode = f2fs_iget(sb, F2FS_NODE_INO(sbi));
|
||||||
if (IS_ERR(sbi->node_inode)) {
|
if (IS_ERR(sbi->node_inode)) {
|
||||||
|
f2fs_msg(sb, KERN_ERR, "Failed to read node inode");
|
||||||
err = PTR_ERR(sbi->node_inode);
|
err = PTR_ERR(sbi->node_inode);
|
||||||
goto free_nm;
|
goto free_nm;
|
||||||
}
|
}
|
||||||
@ -533,6 +576,7 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
|
|||||||
/* read root inode and dentry */
|
/* read root inode and dentry */
|
||||||
root = f2fs_iget(sb, F2FS_ROOT_INO(sbi));
|
root = f2fs_iget(sb, F2FS_ROOT_INO(sbi));
|
||||||
if (IS_ERR(root)) {
|
if (IS_ERR(root)) {
|
||||||
|
f2fs_msg(sb, KERN_ERR, "Failed to read root inode");
|
||||||
err = PTR_ERR(root);
|
err = PTR_ERR(root);
|
||||||
goto free_node_inode;
|
goto free_node_inode;
|
||||||
}
|
}
|
||||||
@ -596,7 +640,7 @@ static struct file_system_type f2fs_fs_type = {
|
|||||||
.fs_flags = FS_REQUIRES_DEV,
|
.fs_flags = FS_REQUIRES_DEV,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int init_inodecache(void)
|
static int __init init_inodecache(void)
|
||||||
{
|
{
|
||||||
f2fs_inode_cachep = f2fs_kmem_cache_create("f2fs_inode_cache",
|
f2fs_inode_cachep = f2fs_kmem_cache_create("f2fs_inode_cache",
|
||||||
sizeof(struct f2fs_inode_info), NULL);
|
sizeof(struct f2fs_inode_info), NULL);
|
||||||
@ -631,14 +675,17 @@ static int __init init_f2fs_fs(void)
|
|||||||
err = create_checkpoint_caches();
|
err = create_checkpoint_caches();
|
||||||
if (err)
|
if (err)
|
||||||
goto fail;
|
goto fail;
|
||||||
return register_filesystem(&f2fs_fs_type);
|
err = register_filesystem(&f2fs_fs_type);
|
||||||
|
if (err)
|
||||||
|
goto fail;
|
||||||
|
f2fs_create_root_stats();
|
||||||
fail:
|
fail:
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __exit exit_f2fs_fs(void)
|
static void __exit exit_f2fs_fs(void)
|
||||||
{
|
{
|
||||||
destroy_root_stats();
|
f2fs_destroy_root_stats();
|
||||||
unregister_filesystem(&f2fs_fs_type);
|
unregister_filesystem(&f2fs_fs_type);
|
||||||
destroy_checkpoint_caches();
|
destroy_checkpoint_caches();
|
||||||
destroy_gc_caches();
|
destroy_gc_caches();
|
||||||
|
@ -318,6 +318,8 @@ int f2fs_setxattr(struct inode *inode, int name_index, const char *name,
|
|||||||
if (name_len > 255 || value_len > MAX_VALUE_LEN)
|
if (name_len > 255 || value_len > MAX_VALUE_LEN)
|
||||||
return -ERANGE;
|
return -ERANGE;
|
||||||
|
|
||||||
|
f2fs_balance_fs(sbi);
|
||||||
|
|
||||||
mutex_lock_op(sbi, NODE_NEW);
|
mutex_lock_op(sbi, NODE_NEW);
|
||||||
if (!fi->i_xattr_nid) {
|
if (!fi->i_xattr_nid) {
|
||||||
/* Allocate new attribute block */
|
/* Allocate new attribute block */
|
||||||
|
Loading…
Reference in New Issue
Block a user