Commit eb97a784 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'for-f2fs-3.12' 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:
   - support inline xattrs
   - add sysfs support to control GCs explicitly
   - add proc entry to show the current segment usage information
   - improve the GC/SSR performance

  The other bug fixes are as follows:
   - avoid the overflow on status calculation
   - fix some error handling routines
   - fix inconsistent xattr states after power-off-recovery
   - fix incorrect xattr node offset definition
   - fix deadlock condition in fsync
   - fix the fdatasync routine for power-off-recovery"

* tag 'for-f2fs-3.12' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs: (40 commits)
  f2fs: optimize gc for better performance
  f2fs: merge more bios of node block writes
  f2fs: avoid an overflow during utilization calculation
  f2fs: trigger GC when there are prefree segments
  f2fs: use strncasecmp() simplify the string comparison
  f2fs: fix omitting to update inode page
  f2fs: support the inline xattrs
  f2fs: add the truncate_xattr_node function
  f2fs: introduce __find_xattr for readability
  f2fs: reserve the xattr space dynamically
  f2fs: add flags for inline xattrs
  f2fs: fix error return code in init_f2fs_fs()
  f2fs: fix wrong BUG_ON condition
  f2fs: fix memory leak when init f2fs filesystem fail
  f2fs: fix a compound statement label error
  f2fs: avoid writing inode redundantly when creating a file
  f2fs: alloc_page() doesn't return an ERR_PTR
  f2fs: should cover i_xattr_nid with its xattr node page lock
  f2fs: check the free space first in new_node_page
  f2fs: clean up the needless end 'return' of void function
  ...
parents 2e032852 a26b7c8a
What: /sys/fs/f2fs/<disk>/gc_max_sleep_time
Date: July 2013
Contact: "Namjae Jeon" <namjae.jeon@samsung.com>
Description:
Controls the maximun sleep time for gc_thread. Time
is in milliseconds.
What: /sys/fs/f2fs/<disk>/gc_min_sleep_time
Date: July 2013
Contact: "Namjae Jeon" <namjae.jeon@samsung.com>
Description:
Controls the minimum sleep time for gc_thread. Time
is in milliseconds.
What: /sys/fs/f2fs/<disk>/gc_no_gc_sleep_time
Date: July 2013
Contact: "Namjae Jeon" <namjae.jeon@samsung.com>
Description:
Controls the default sleep time for gc_thread. Time
is in milliseconds.
What: /sys/fs/f2fs/<disk>/gc_idle
Date: July 2013
Contact: "Namjae Jeon" <namjae.jeon@samsung.com>
Description:
Controls the victim selection policy for garbage collection.
...@@ -18,8 +18,8 @@ according to its internal geometry or flash memory management scheme, namely FTL ...@@ -18,8 +18,8 @@ according to its internal geometry or flash memory management scheme, namely FTL
F2FS and its tools support various parameters not only for configuring on-disk F2FS and its tools support various parameters not only for configuring on-disk
layout, but also for selecting allocation and cleaning algorithms. layout, but also for selecting allocation and cleaning algorithms.
The file system formatting tool, "mkfs.f2fs", is available from the following The following git tree provides the file system formatting tool (mkfs.f2fs),
git tree: a consistency checking tool (fsck.f2fs), and a debugging tool (dump.f2fs).
>> git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs-tools.git >> git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs-tools.git
For reporting bugs and sending patches, please use the following mailing list: For reporting bugs and sending patches, please use the following mailing list:
...@@ -132,6 +132,38 @@ f2fs. Each file shows the whole f2fs information. ...@@ -132,6 +132,38 @@ f2fs. Each file shows the whole f2fs information.
- average SIT information about whole segments - average SIT information about whole segments
- current memory footprint consumed by f2fs. - current memory footprint consumed by f2fs.
================================================================================
SYSFS ENTRIES
================================================================================
Information about mounted f2f2 file systems can be found in
/sys/fs/f2fs. Each mounted filesystem will have a directory in
/sys/fs/f2fs based on its device name (i.e., /sys/fs/f2fs/sda).
The files in each per-device directory are shown in table below.
Files in /sys/fs/f2fs/<devname>
(see also Documentation/ABI/testing/sysfs-fs-f2fs)
..............................................................................
File Content
gc_max_sleep_time This tuning parameter controls the maximum sleep
time for the garbage collection thread. Time is
in milliseconds.
gc_min_sleep_time This tuning parameter controls the minimum sleep
time for the garbage collection thread. Time is
in milliseconds.
gc_no_gc_sleep_time This tuning parameter controls the default sleep
time for the garbage collection thread. Time is
in milliseconds.
gc_idle This parameter controls the selection of victim
policy for garbage collection. Setting gc_idle = 0
(default) will disable this option. Setting
gc_idle = 1 will select the Cost Benefit approach
& setting gc_idle = 2 will select the greedy aproach.
================================================================================ ================================================================================
USAGE USAGE
================================================================================ ================================================================================
...@@ -149,8 +181,12 @@ USAGE ...@@ -149,8 +181,12 @@ USAGE
# mkfs.f2fs -l label /dev/block_device # mkfs.f2fs -l label /dev/block_device
# mount -t f2fs /dev/block_device /mnt/f2fs # mount -t f2fs /dev/block_device /mnt/f2fs
Format options mkfs.f2fs
-------------- ---------
The mkfs.f2fs is for the use of formatting a partition as the f2fs filesystem,
which builds a basic on-disk layout.
The options consist of:
-l [label] : Give a volume label, up to 512 unicode name. -l [label] : Give a volume label, up to 512 unicode name.
-a [0 or 1] : Split start location of each area for heap-based allocation. -a [0 or 1] : Split start location of each area for heap-based allocation.
1 is set by default, which performs this. 1 is set by default, which performs this.
...@@ -164,6 +200,37 @@ Format options ...@@ -164,6 +200,37 @@ Format options
-t [0 or 1] : Disable discard command or not. -t [0 or 1] : Disable discard command or not.
1 is set by default, which conducts discard. 1 is set by default, which conducts discard.
fsck.f2fs
---------
The fsck.f2fs is a tool to check the consistency of an f2fs-formatted
partition, which examines whether the filesystem metadata and user-made data
are cross-referenced correctly or not.
Note that, initial version of the tool does not fix any inconsistency.
The options consist of:
-d debug level [default:0]
dump.f2fs
---------
The dump.f2fs shows the information of specific inode and dumps SSA and SIT to
file. Each file is dump_ssa and dump_sit.
The dump.f2fs is used to debug on-disk data structures of the f2fs filesystem.
It shows on-disk inode information reconized by a given inode number, and is
able to dump all the SSA and SIT entries into predefined files, ./dump_ssa and
./dump_sit respectively.
The options consist of:
-d debug level [default:0]
-i inode no (hex)
-s [SIT dump segno from #1~#2 (decimal), for all 0~-1]
-a [SSA dump segno from #1~#2 (decimal), for all 0~-1]
Examples:
# dump.f2fs -i [ino] /dev/sdx
# dump.f2fs -s 0~-1 /dev/sdx (SIT dump)
# dump.f2fs -a 0~-1 /dev/sdx (SSA dump)
================================================================================ ================================================================================
DESIGN DESIGN
================================================================================ ================================================================================
......
...@@ -182,7 +182,7 @@ const struct address_space_operations f2fs_meta_aops = { ...@@ -182,7 +182,7 @@ const struct address_space_operations f2fs_meta_aops = {
.set_page_dirty = f2fs_set_meta_page_dirty, .set_page_dirty = f2fs_set_meta_page_dirty,
}; };
int check_orphan_space(struct f2fs_sb_info *sbi) int acquire_orphan_inode(struct f2fs_sb_info *sbi)
{ {
unsigned int max_orphans; unsigned int max_orphans;
int err = 0; int err = 0;
...@@ -197,10 +197,19 @@ int check_orphan_space(struct f2fs_sb_info *sbi) ...@@ -197,10 +197,19 @@ int check_orphan_space(struct f2fs_sb_info *sbi)
mutex_lock(&sbi->orphan_inode_mutex); mutex_lock(&sbi->orphan_inode_mutex);
if (sbi->n_orphans >= max_orphans) if (sbi->n_orphans >= max_orphans)
err = -ENOSPC; err = -ENOSPC;
else
sbi->n_orphans++;
mutex_unlock(&sbi->orphan_inode_mutex); mutex_unlock(&sbi->orphan_inode_mutex);
return err; return err;
} }
void release_orphan_inode(struct f2fs_sb_info *sbi)
{
mutex_lock(&sbi->orphan_inode_mutex);
sbi->n_orphans--;
mutex_unlock(&sbi->orphan_inode_mutex);
}
void add_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino) void add_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino)
{ {
struct list_head *head, *this; struct list_head *head, *this;
...@@ -229,21 +238,18 @@ void add_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino) ...@@ -229,21 +238,18 @@ void add_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino)
list_add(&new->list, this->prev); list_add(&new->list, this->prev);
else else
list_add_tail(&new->list, head); list_add_tail(&new->list, head);
sbi->n_orphans++;
out: out:
mutex_unlock(&sbi->orphan_inode_mutex); mutex_unlock(&sbi->orphan_inode_mutex);
} }
void remove_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino) void remove_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino)
{ {
struct list_head *this, *next, *head; struct list_head *head;
struct orphan_inode_entry *orphan; struct orphan_inode_entry *orphan;
mutex_lock(&sbi->orphan_inode_mutex); mutex_lock(&sbi->orphan_inode_mutex);
head = &sbi->orphan_inode_list; head = &sbi->orphan_inode_list;
list_for_each_safe(this, next, head) { list_for_each_entry(orphan, head, list) {
orphan = list_entry(this, struct orphan_inode_entry, list);
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);
...@@ -373,7 +379,7 @@ static struct page *validate_checkpoint(struct f2fs_sb_info *sbi, ...@@ -373,7 +379,7 @@ static struct page *validate_checkpoint(struct f2fs_sb_info *sbi,
if (!f2fs_crc_valid(crc, cp_block, crc_offset)) if (!f2fs_crc_valid(crc, cp_block, crc_offset))
goto invalid_cp1; goto invalid_cp1;
pre_version = le64_to_cpu(cp_block->checkpoint_ver); pre_version = cur_cp_version(cp_block);
/* Read the 2nd cp block in this CP pack */ /* Read the 2nd cp block in this CP pack */
cp_addr += le32_to_cpu(cp_block->cp_pack_total_block_count) - 1; cp_addr += le32_to_cpu(cp_block->cp_pack_total_block_count) - 1;
...@@ -388,7 +394,7 @@ static struct page *validate_checkpoint(struct f2fs_sb_info *sbi, ...@@ -388,7 +394,7 @@ static struct page *validate_checkpoint(struct f2fs_sb_info *sbi,
if (!f2fs_crc_valid(crc, cp_block, crc_offset)) if (!f2fs_crc_valid(crc, cp_block, crc_offset))
goto invalid_cp2; goto invalid_cp2;
cur_version = le64_to_cpu(cp_block->checkpoint_ver); cur_version = cur_cp_version(cp_block);
if (cur_version == pre_version) { if (cur_version == pre_version) {
*version = cur_version; *version = cur_version;
...@@ -793,7 +799,7 @@ void write_checkpoint(struct f2fs_sb_info *sbi, bool is_umount) ...@@ -793,7 +799,7 @@ void write_checkpoint(struct f2fs_sb_info *sbi, bool is_umount)
* Increase the version number so that * Increase the version number so that
* SIT entries and seg summaries are written at correct place * SIT entries and seg summaries are written at correct place
*/ */
ckpt_ver = le64_to_cpu(ckpt->checkpoint_ver); ckpt_ver = cur_cp_version(ckpt);
ckpt->checkpoint_ver = cpu_to_le64(++ckpt_ver); ckpt->checkpoint_ver = cpu_to_le64(++ckpt_ver);
/* write cached NAT/SIT entries to NAT/SIT area */ /* write cached NAT/SIT entries to NAT/SIT area */
......
...@@ -37,9 +37,9 @@ static void __set_data_blkaddr(struct dnode_of_data *dn, block_t new_addr) ...@@ -37,9 +37,9 @@ static void __set_data_blkaddr(struct dnode_of_data *dn, block_t new_addr)
struct page *node_page = dn->node_page; struct page *node_page = dn->node_page;
unsigned int ofs_in_node = dn->ofs_in_node; unsigned int ofs_in_node = dn->ofs_in_node;
wait_on_page_writeback(node_page); f2fs_wait_on_page_writeback(node_page, NODE, false);
rn = (struct f2fs_node *)page_address(node_page); rn = F2FS_NODE(node_page);
/* Get physical address of data block */ /* Get physical address of data block */
addr_array = blkaddr_in_node(rn); addr_array = blkaddr_in_node(rn);
...@@ -117,7 +117,8 @@ void update_extent_cache(block_t blk_addr, struct dnode_of_data *dn) ...@@ -117,7 +117,8 @@ void update_extent_cache(block_t blk_addr, struct dnode_of_data *dn)
block_t start_blkaddr, end_blkaddr; block_t start_blkaddr, end_blkaddr;
BUG_ON(blk_addr == NEW_ADDR); BUG_ON(blk_addr == NEW_ADDR);
fofs = start_bidx_of_node(ofs_of_node(dn->node_page)) + dn->ofs_in_node; fofs = start_bidx_of_node(ofs_of_node(dn->node_page), fi) +
dn->ofs_in_node;
/* Update the page address in the parent node */ /* Update the page address in the parent node */
__set_data_blkaddr(dn, blk_addr); __set_data_blkaddr(dn, blk_addr);
...@@ -176,7 +177,6 @@ void update_extent_cache(block_t blk_addr, struct dnode_of_data *dn) ...@@ -176,7 +177,6 @@ void update_extent_cache(block_t blk_addr, struct dnode_of_data *dn)
end_update: end_update:
write_unlock(&fi->ext.ext_lock); write_unlock(&fi->ext.ext_lock);
sync_inode_page(dn); sync_inode_page(dn);
return;
} }
struct page *find_data_page(struct inode *inode, pgoff_t index, bool sync) struct page *find_data_page(struct inode *inode, pgoff_t index, bool sync)
...@@ -260,8 +260,17 @@ struct page *get_lock_data_page(struct inode *inode, pgoff_t index) ...@@ -260,8 +260,17 @@ struct page *get_lock_data_page(struct inode *inode, pgoff_t index)
if (PageUptodate(page)) if (PageUptodate(page))
return page; return page;
BUG_ON(dn.data_blkaddr == NEW_ADDR); /*
BUG_ON(dn.data_blkaddr == NULL_ADDR); * A new dentry page is allocated but not able to be written, since its
* new inode page couldn't be allocated due to -ENOSPC.
* In such the case, its blkaddr can be remained as NEW_ADDR.
* see, f2fs_add_link -> get_new_data_page -> init_inode_metadata.
*/
if (dn.data_blkaddr == NEW_ADDR) {
zero_user_segment(page, 0, PAGE_CACHE_SIZE);
SetPageUptodate(page);
return page;
}
err = f2fs_readpage(sbi, page, dn.data_blkaddr, READ_SYNC); err = f2fs_readpage(sbi, page, dn.data_blkaddr, READ_SYNC);
if (err) if (err)
...@@ -365,7 +374,6 @@ static void read_end_io(struct bio *bio, int err) ...@@ -365,7 +374,6 @@ static void read_end_io(struct bio *bio, int err)
} }
unlock_page(page); unlock_page(page);
} while (bvec >= bio->bi_io_vec); } while (bvec >= bio->bi_io_vec);
kfree(bio->bi_private);
bio_put(bio); bio_put(bio);
} }
...@@ -391,7 +399,6 @@ int f2fs_readpage(struct f2fs_sb_info *sbi, struct page *page, ...@@ -391,7 +399,6 @@ int f2fs_readpage(struct f2fs_sb_info *sbi, struct page *page,
bio->bi_end_io = read_end_io; bio->bi_end_io = read_end_io;
if (bio_add_page(bio, page, PAGE_CACHE_SIZE, 0) < PAGE_CACHE_SIZE) { if (bio_add_page(bio, page, PAGE_CACHE_SIZE, 0) < PAGE_CACHE_SIZE) {
kfree(bio->bi_private);
bio_put(bio); bio_put(bio);
up_read(&sbi->bio_sem); up_read(&sbi->bio_sem);
f2fs_put_page(page, 1); f2fs_put_page(page, 1);
...@@ -442,7 +449,7 @@ static int get_data_block_ro(struct inode *inode, sector_t iblock, ...@@ -442,7 +449,7 @@ static int get_data_block_ro(struct inode *inode, sector_t iblock,
unsigned int end_offset; unsigned int end_offset;
end_offset = IS_INODE(dn.node_page) ? end_offset = IS_INODE(dn.node_page) ?
ADDRS_PER_INODE : ADDRS_PER_INODE(F2FS_I(inode)) :
ADDRS_PER_BLOCK; ADDRS_PER_BLOCK;
clear_buffer_new(bh_result); clear_buffer_new(bh_result);
...@@ -636,9 +643,6 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping, ...@@ -636,9 +643,6 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping,
int err = 0; int err = 0;
int ilock; int ilock;
/* for nobh_write_end */
*fsdata = NULL;
f2fs_balance_fs(sbi); f2fs_balance_fs(sbi);
repeat: repeat:
page = grab_cache_page_write_begin(mapping, index, flags); page = grab_cache_page_write_begin(mapping, index, flags);
......
...@@ -29,7 +29,7 @@ static DEFINE_MUTEX(f2fs_stat_mutex); ...@@ -29,7 +29,7 @@ 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)
{ {
struct f2fs_stat_info *si = sbi->stat_info; struct f2fs_stat_info *si = F2FS_STAT(sbi);
int i; int i;
/* valid check of the segment numbers */ /* valid check of the segment numbers */
...@@ -83,7 +83,7 @@ static void update_general_status(struct f2fs_sb_info *sbi) ...@@ -83,7 +83,7 @@ static void update_general_status(struct f2fs_sb_info *sbi)
*/ */
static void update_sit_info(struct f2fs_sb_info *sbi) static void update_sit_info(struct f2fs_sb_info *sbi)
{ {
struct f2fs_stat_info *si = sbi->stat_info; struct f2fs_stat_info *si = F2FS_STAT(sbi);
unsigned int blks_per_sec, hblks_per_sec, total_vblocks, bimodal, dist; unsigned int blks_per_sec, hblks_per_sec, total_vblocks, bimodal, dist;
struct sit_info *sit_i = SIT_I(sbi); struct sit_info *sit_i = SIT_I(sbi);
unsigned int segno, vblocks; unsigned int segno, vblocks;
...@@ -118,7 +118,7 @@ static void update_sit_info(struct f2fs_sb_info *sbi) ...@@ -118,7 +118,7 @@ static void update_sit_info(struct f2fs_sb_info *sbi)
*/ */
static void update_mem_info(struct f2fs_sb_info *sbi) static void update_mem_info(struct f2fs_sb_info *sbi)
{ {
struct f2fs_stat_info *si = sbi->stat_info; struct f2fs_stat_info *si = F2FS_STAT(sbi);
unsigned npages; unsigned npages;
if (si->base_mem) if (si->base_mem)
...@@ -253,21 +253,21 @@ static int stat_show(struct seq_file *s, void *v) ...@@ -253,21 +253,21 @@ static int stat_show(struct seq_file *s, void *v)
si->nats, NM_WOUT_THRESHOLD); si->nats, NM_WOUT_THRESHOLD);
seq_printf(s, " - SITs: %5d\n - free_nids: %5d\n", seq_printf(s, " - SITs: %5d\n - free_nids: %5d\n",
si->sits, si->fnids); si->sits, si->fnids);
seq_printf(s, "\nDistribution of User Blocks:"); seq_puts(s, "\nDistribution of User Blocks:");
seq_printf(s, " [ valid | invalid | free ]\n"); seq_puts(s, " [ valid | invalid | free ]\n");
seq_printf(s, " ["); seq_puts(s, " [");
for (j = 0; j < si->util_valid; j++) for (j = 0; j < si->util_valid; j++)
seq_printf(s, "-"); seq_putc(s, '-');
seq_printf(s, "|"); seq_putc(s, '|');
for (j = 0; j < si->util_invalid; j++) for (j = 0; j < si->util_invalid; j++)
seq_printf(s, "-"); seq_putc(s, '-');
seq_printf(s, "|"); seq_putc(s, '|');
for (j = 0; j < si->util_free; j++) for (j = 0; j < si->util_free; j++)
seq_printf(s, "-"); seq_putc(s, '-');
seq_printf(s, "]\n\n"); seq_puts(s, "]\n\n");
seq_printf(s, "SSR: %u blocks in %u segments\n", seq_printf(s, "SSR: %u blocks in %u segments\n",
si->block_count[SSR], si->segment_count[SSR]); si->block_count[SSR], si->segment_count[SSR]);
seq_printf(s, "LFS: %u blocks in %u segments\n", seq_printf(s, "LFS: %u blocks in %u segments\n",
...@@ -305,11 +305,10 @@ int f2fs_build_stats(struct f2fs_sb_info *sbi) ...@@ -305,11 +305,10 @@ 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;
sbi->stat_info = kzalloc(sizeof(struct f2fs_stat_info), GFP_KERNEL); si = kzalloc(sizeof(struct f2fs_stat_info), GFP_KERNEL);
if (!sbi->stat_info) if (!si)
return -ENOMEM; return -ENOMEM;
si = sbi->stat_info;
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);
...@@ -319,6 +318,7 @@ int f2fs_build_stats(struct f2fs_sb_info *sbi) ...@@ -319,6 +318,7 @@ int f2fs_build_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;
sbi->stat_info = si;
mutex_lock(&f2fs_stat_mutex); mutex_lock(&f2fs_stat_mutex);
list_add_tail(&si->stat_list, &f2fs_stat_list); list_add_tail(&si->stat_list, &f2fs_stat_list);
...@@ -329,13 +329,13 @@ int f2fs_build_stats(struct f2fs_sb_info *sbi) ...@@ -329,13 +329,13 @@ int f2fs_build_stats(struct f2fs_sb_info *sbi)
void f2fs_destroy_stats(struct f2fs_sb_info *sbi) void f2fs_destroy_stats(struct f2fs_sb_info *sbi)
{ {
struct f2fs_stat_info *si = sbi->stat_info; struct f2fs_stat_info *si = F2FS_STAT(sbi);
mutex_lock(&f2fs_stat_mutex); mutex_lock(&f2fs_stat_mutex);
list_del(&si->stat_list); list_del(&si->stat_list);
mutex_unlock(&f2fs_stat_mutex); mutex_unlock(&f2fs_stat_mutex);
kfree(sbi->stat_info); kfree(si);
} }
void __init f2fs_create_root_stats(void) void __init f2fs_create_root_stats(void)
......
...@@ -270,12 +270,27 @@ static void init_dent_inode(const struct qstr *name, struct page *ipage) ...@@ -270,12 +270,27 @@ static void init_dent_inode(const struct qstr *name, struct page *ipage)
struct f2fs_node *rn; struct f2fs_node *rn;
/* copy name info. to this inode page */ /* copy name info. to this inode page */
rn = (struct f2fs_node *)page_address(ipage); rn = F2FS_NODE(ipage);
rn->i.i_namelen = cpu_to_le32(name->len); rn->i.i_namelen = cpu_to_le32(name->len);
memcpy(rn->i.i_name, name->name, name->len); memcpy(rn->i.i_name, name->name, name->len);
set_page_dirty(ipage); set_page_dirty(ipage);
} }
int update_dent_inode(struct inode *inode, const struct qstr *name)
{
struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
struct page *page;
page = get_node_page(sbi, inode->i_ino);
if (IS_ERR(page))
return PTR_ERR(page);
init_dent_inode(name, page);
f2fs_put_page(page, 1);
return 0;
}
static int make_empty_dir(struct inode *inode, static int make_empty_dir(struct inode *inode,
struct inode *parent, struct page *page) struct inode *parent, struct page *page)
{ {
...@@ -557,6 +572,8 @@ void f2fs_delete_entry(struct f2fs_dir_entry *dentry, struct page *page, ...@@ -557,6 +572,8 @@ void f2fs_delete_entry(struct f2fs_dir_entry *dentry, struct page *page,
if (inode->i_nlink == 0) if (inode->i_nlink == 0)
add_orphan_inode(sbi, inode->i_ino); add_orphan_inode(sbi, inode->i_ino);
else
release_orphan_inode(sbi);
} }
if (bit_pos == NR_DENTRY_IN_BLOCK) { if (bit_pos == NR_DENTRY_IN_BLOCK) {
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/crc32.h> #include <linux/crc32.h>
#include <linux/magic.h> #include <linux/magic.h>
#include <linux/kobject.h>
/* /*
* For mount options * For mount options
...@@ -28,6 +29,7 @@ ...@@ -28,6 +29,7 @@
#define F2FS_MOUNT_XATTR_USER 0x00000010 #define F2FS_MOUNT_XATTR_USER 0x00000010
#define F2FS_MOUNT_POSIX_ACL 0x00000020 #define F2FS_MOUNT_POSIX_ACL 0x00000020
#define F2FS_MOUNT_DISABLE_EXT_IDENTIFY 0x00000040 #define F2FS_MOUNT_DISABLE_EXT_IDENTIFY 0x00000040
#define F2FS_MOUNT_INLINE_XATTR 0x00000080
#define clear_opt(sbi, option) (sbi->mount_opt.opt &= ~F2FS_MOUNT_##option) #define clear_opt(sbi, option) (sbi->mount_opt.opt &= ~F2FS_MOUNT_##option)
#define set_opt(sbi, option) (sbi->mount_opt.opt |= F2FS_MOUNT_##option) #define set_opt(sbi, option) (sbi->mount_opt.opt |= F2FS_MOUNT_##option)
...@@ -134,11 +136,13 @@ static inline int update_sits_in_cursum(struct f2fs_summary_block *rs, int i) ...@@ -134,11 +136,13 @@ static inline int update_sits_in_cursum(struct f2fs_summary_block *rs, int i)
/* /*
* For INODE and NODE manager * For INODE and NODE manager
*/ */
#define XATTR_NODE_OFFSET (-1) /* /*
* store xattrs to one node block per * XATTR_NODE_OFFSET stores xattrs to one node block per file keeping -1
* file keeping -1 as its node offset to * as its node offset to distinguish from index node blocks.
* distinguish from index node blocks. * But some bits are used to mark the node block.
*/ */
#define XATTR_NODE_OFFSET ((((unsigned int)-1) << OFFSET_BIT_SHIFT) \
>> OFFSET_BIT_SHIFT)
enum { enum {
ALLOC_NODE, /* allocate a new node page if needed */ ALLOC_NODE, /* allocate a new node page if needed */
LOOKUP_NODE, /* look up a node without readahead */ LOOKUP_NODE, /* look up a node without readahead */
...@@ -178,6 +182,7 @@ struct f2fs_inode_info { ...@@ -178,6 +182,7 @@ struct f2fs_inode_info {
f2fs_hash_t chash; /* hash value of given file name */ f2fs_hash_t chash; /* hash value of given file name */
unsigned int clevel; /* maximum level of given file name */ unsigned int clevel; /* maximum level of given file name */
nid_t i_xattr_nid; /* node id that contains xattrs */ nid_t i_xattr_nid; /* node id that contains xattrs */
unsigned long long xattr_ver; /* cp version of xattr modification */
struct extent_info ext; /* in-memory extent cache entry */ struct extent_info ext; /* in-memory extent cache entry */
}; };
...@@ -295,15 +300,6 @@ struct f2fs_sm_info { ...@@ -295,15 +300,6 @@ struct f2fs_sm_info {
unsigned int ovp_segments; /* # of overprovision segments */ unsigned int ovp_segments; /* # of overprovision segments */
}; };
/*
* For directory operation
*/
#define NODE_DIR1_BLOCK (ADDRS_PER_INODE + 1)
#define NODE_DIR2_BLOCK (ADDRS_PER_INODE + 2)
#define NODE_IND1_BLOCK (ADDRS_PER_INODE + 3)
#define NODE_IND2_BLOCK (ADDRS_PER_INODE + 4)
#define NODE_DIND_BLOCK (ADDRS_PER_INODE + 5)
/* /*
* For superblock * For superblock
*/ */
...@@ -350,6 +346,7 @@ enum page_type { ...@@ -350,6 +346,7 @@ enum page_type {
struct f2fs_sb_info { struct f2fs_sb_info {
struct super_block *sb; /* pointer to VFS super block */ struct super_block *sb; /* pointer to VFS super block */
struct proc_dir_entry *s_proc; /* proc entry */
struct buffer_head *raw_super_buf; /* buffer head of raw sb */ struct buffer_head *raw_super_buf; /* buffer head of raw sb */
struct f2fs_super_block *raw_super; /* raw super block pointer */ struct f2fs_super_block *raw_super; /* raw super block pointer */
int s_dirty; /* dirty flag for checkpoint */ int s_dirty; /* dirty flag for checkpoint */
...@@ -429,6 +426,10 @@ struct f2fs_sb_info { ...@@ -429,6 +426,10 @@ struct f2fs_sb_info {
#endif #endif
unsigned int last_victim[2]; /* last victim segment # */ unsigned int last_victim[2]; /* last victim segment # */
spinlock_t stat_lock; /* lock for stat operations */ spinlock_t stat_lock; /* lock for stat operations */
/* For sysfs suppport */
struct kobject s_kobj;
struct completion s_kobj_unregister;
}; };
/* /*
...@@ -454,6 +455,11 @@ static inline struct f2fs_checkpoint *F2FS_CKPT(struct f2fs_sb_info *sbi) ...@@ -454,6 +455,11 @@ static inline struct f2fs_checkpoint *F2FS_CKPT(struct f2fs_sb_info *sbi)
return (struct f2fs_checkpoint *)(sbi->ckpt); return (struct f2fs_checkpoint *)(sbi->ckpt);
} }
static inline struct f2fs_node *F2FS_NODE(struct page *page)
{
return (struct f2fs_node *)page_address(page);
}
static inline struct f2fs_nm_info *NM_I(struct f2fs_sb_info *sbi) static inline struct f2fs_nm_info *NM_I(struct f2fs_sb_info *sbi)
{ {
return (struct f2fs_nm_info *)(sbi->nm_info); return (struct f2fs_nm_info *)(sbi->nm_info);
...@@ -489,6 +495,11 @@ static inline void F2FS_RESET_SB_DIRT(struct f2fs_sb_info *sbi) ...@@ -489,6 +495,11 @@ static inline void F2FS_RESET_SB_DIRT(struct f2fs_sb_info *sbi)
sbi->s_dirty = 0; sbi->s_dirty = 0;
} }
static inline unsigned long long cur_cp_version(struct f2fs_checkpoint *cp)
{
return le64_to_cpu(cp->checkpoint_ver);
}
static inline bool is_set_ckpt_flags(struct f2fs_checkpoint *cp, unsigned int f) static inline bool is_set_ckpt_flags(struct f2fs_checkpoint *cp, unsigned int f)
{ {
unsigned int ckpt_flags = le32_to_cpu(cp->ckpt_flags); unsigned int ckpt_flags = le32_to_cpu(cp->ckpt_flags);
...@@ -677,7 +688,7 @@ static inline block_t __start_cp_addr(struct f2fs_sb_info *sbi) ...@@ -677,7 +688,7 @@ static inline block_t __start_cp_addr(struct f2fs_sb_info *sbi)
{ {
block_t start_addr; block_t start_addr;
struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
unsigned long long ckpt_version = le64_to_cpu(ckpt->checkpoint_ver); unsigned long long ckpt_version = cur_cp_version(ckpt);
start_addr = le32_to_cpu(F2FS_RAW_SUPER(sbi)->cp_blkaddr); start_addr = le32_to_cpu(F2FS_RAW_SUPER(sbi)->cp_blkaddr);
...@@ -812,7 +823,7 @@ static inline struct kmem_cache *f2fs_kmem_cache_create(const char *name, ...@@ -812,7 +823,7 @@ static inline struct kmem_cache *f2fs_kmem_cache_create(const char *name,
static inline bool IS_INODE(struct page *page) static inline bool IS_INODE(struct page *page)
{ {
struct f2fs_node *p = (struct f2fs_node *)page_address(page); struct f2fs_node *p = F2FS_NODE(page);
return RAW_IS_INODE(p); return RAW_IS_INODE(p);
} }
...@@ -826,7 +837,7 @@ static inline block_t datablock_addr(struct page *node_page, ...@@ -826,7 +837,7 @@ static inline block_t datablock_addr(struct page *node_page,
{ {
struct f2fs_node *raw_node; struct f2fs_node *raw_node;
__le32 *addr_array; __le32 *addr_array;
raw_node = (struct f2fs_node *)page_address(node_page); raw_node = F2FS_NODE(node_page);
addr_array = blkaddr_in_node(raw_node); addr_array = blkaddr_in_node(raw_node);
return le32_to_cpu(addr_array[offset]); return le32_to_cpu(addr_array[offset]);
} }
...@@ -873,6 +884,7 @@ enum { ...@@ -873,6 +884,7 @@ enum {
FI_NO_ALLOC, /* should not allocate any blocks */ FI_NO_ALLOC, /* should not allocate any blocks */
FI_UPDATE_DIR, /* should update inode block for consistency */ FI_UPDATE_DIR, /* should update inode block for consistency */
FI_DELAY_IPUT, /* used for the recovery */ FI_DELAY_IPUT, /* used for the recovery */
FI_INLINE_XATTR, /* used for inline xattr */
}; };
static inline void set_inode_flag(struct f2fs_inode_info *fi, int flag) static inline void set_inode_flag(struct f2fs_inode_info *fi, int flag)
...@@ -905,6 +917,45 @@ static inline int cond_clear_inode_flag(struct f2fs_inode_info *fi, int flag) ...@@ -905,6 +917,45 @@ static inline int cond_clear_inode_flag(struct f2fs_inode_info *fi, int flag)
return 0; return 0;
} }
static inline void get_inline_info(struct f2fs_inode_info *fi,
struct f2fs_inode *ri)
{
if (ri->i_inline & F2FS_INLINE_XATTR)
set_inode_flag(fi, FI_INLINE_XATTR);
}
static inline void set_raw_inline(struct f2fs_inode_info *fi,
struct f2fs_inode *ri)
{
ri->i_inline = 0;
if (is_inode_flag_set(fi, FI_INLINE_XATTR))
ri->i_inline |= F2FS_INLINE_XATTR;
}
static inline unsigned int addrs_per_inode(struct f2fs_inode_info *fi)
{
if (is_inode_flag_set(fi, FI_INLINE_XATTR))
return DEF_ADDRS_PER_INODE - F2FS_INLINE_XATTR_ADDRS;
return DEF_ADDRS_PER_INODE;
}
static inline void *inline_xattr_addr(struct page *page)
{
struct f2fs_inode *ri;
ri = (struct f2fs_inode *)page_address(page);
return (void *)&(ri->i_addr[DEF_ADDRS_PER_INODE -
F2FS_INLINE_XATTR_ADDRS]);
}
static inline int inline_xattr_size(struct inode *inode)
{
if (is_inode_flag_set(F2FS_I(inode), FI_INLINE_XATTR))
return F2FS_INLINE_XATTR_ADDRS << 2;
else
return 0;
}
static inline int f2fs_readonly(struct super_block *sb) static inline int f2fs_readonly(struct super_block *sb)
{ {
return sb->s_flags & MS_RDONLY; return sb->s_flags & MS_RDONLY;
...@@ -947,6 +998,7 @@ struct f2fs_dir_entry *f2fs_parent_dir(struct inode *, struct page **); ...@@ -947,6 +998,7 @@ struct f2fs_dir_entry *f2fs_parent_dir(struct inode *, struct page **);
ino_t f2fs_inode_by_name(struct inode *, struct qstr *); ino_t f2fs_inode_by_name(struct inode *, struct qstr *);
void f2fs_set_link(struct inode *, struct f2fs_dir_entry *, void f2fs_set_link(struct inode *, struct f2fs_dir_entry *,
struct page *, struct inode *); struct page *, struct inode *);
int update_dent_inode(struct inode *, const struct qstr *);
int __f2fs_add_link(struct inode *, const struct qstr *, struct inode *); int __f2fs_add_link(struct inode *, const struct qstr *, struct inode *);
void f2fs_delete_entry(struct f2fs_dir_entry *, struct page *, struct inode *); void f2fs_delete_entry(struct f2fs_dir_entry *, struct page *, struct inode *);
int f2fs_make_empty(struct inode *, struct inode *); int f2fs_make_empty(struct inode *, struct inode *);
...@@ -980,6 +1032,7 @@ int is_checkpointed_node(struct f2fs_sb_info *, nid_t); ...@@ -980,6 +1032,7 @@ int is_checkpointed_node(struct f2fs_sb_info *, nid_t);
void get_node_info(struct f2fs_sb_info *, nid_t, struct node_info *); 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 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 *);
...@@ -1012,7 +1065,8 @@ int npages_for_summary_flush(struct f2fs_sb_info *); ...@@ -1012,7 +1065,8 @@ int npages_for_summary_flush(struct f2fs_sb_info *);
void allocate_new_segments(struct f2fs_sb_info *); void allocate_new_segments(struct f2fs_sb_info *);
struct page *get_sum_page(struct f2fs_sb_info *, unsigned int); struct page *get_sum_page(struct f2fs_sb_info *, unsigned int);
struct bio *f2fs_bio_alloc(struct block_device *, int); struct bio *f2fs_bio_alloc(struct block_device *, int);
void f2fs_submit_bio(struct f2fs_sb_info *, enum page_type, bool sync); void f2fs_submit_bio(struct f2fs_sb_info *, enum page_type, bool);
void f2fs_wait_on_page_writeback(struct page *, enum page_type, bool);
void write_meta_page(struct f2fs_sb_info *, struct page *); void write_meta_page(struct f2fs_sb_info *, struct page *);
void write_node_page(struct f2fs_sb_info *, struct page *, unsigned int, void write_node_page(struct f2fs_sb_info *, struct page *, unsigned int,
block_t, block_t *); block_t, block_t *);
...@@ -1037,7 +1091,8 @@ void destroy_segment_manager(struct f2fs_sb_info *); ...@@ -1037,7 +1091,8 @@ void destroy_segment_manager(struct f2fs_sb_info *);
struct page *grab_meta_page(struct f2fs_sb_info *, pgoff_t); struct page *grab_meta_page(struct f2fs_sb_info *, pgoff_t);
struct page *get_meta_page(struct f2fs_sb_info *, pgoff_t); struct page *get_meta_page(struct f2fs_sb_info *, pgoff_t);
long sync_meta_pages(struct f2fs_sb_info *, enum page_type, long); long sync_meta_pages(struct f2fs_sb_info *, enum page_type, long);
int check_orphan_space(struct f2fs_sb_info *); int acquire_orphan_inode(struct f2fs_sb_info *);
void release_orphan_inode(struct f2fs_sb_info *);
void add_orphan_inode(struct f2fs_sb_info *, nid_t); void add_orphan_inode(struct f2fs_sb_info *, nid_t);
void remove_orphan_inode(struct f2fs_sb_info *, nid_t); void remove_orphan_inode(struct f2fs_sb_info *, nid_t);
int recover_orphan_inodes(struct f2fs_sb_info *); int recover_orphan_inodes(struct f2fs_sb_info *);
...@@ -1068,7 +1123,7 @@ int do_write_data_page(struct page *); ...@@ -1068,7 +1123,7 @@ 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, struct f2fs_inode_info *);
int f2fs_gc(struct f2fs_sb_info *); int f2fs_gc(struct f2fs_sb_info *);
void build_gc_manager(struct f2fs_sb_info *); void build_gc_manager(struct f2fs_sb_info *);
int __init create_gc_caches(void); int __init create_gc_caches(void);
...@@ -1112,11 +1167,16 @@ struct f2fs_stat_info { ...@@ -1112,11 +1167,16 @@ struct f2fs_stat_info {
unsigned base_mem, cache_mem; unsigned base_mem, cache_mem;
}; };
static inline struct f2fs_stat_info *F2FS_STAT(struct f2fs_sb_info *sbi)
{
return (struct f2fs_stat_info*)sbi->stat_info;
}
#define stat_inc_call_count(si) ((si)->call_count++) #define stat_inc_call_count(si) ((si)->call_count++)
#define stat_inc_seg_count(sbi, type) \ #define stat_inc_seg_count(sbi, type) \
do { \ do { \
struct f2fs_stat_info *si = sbi->stat_info; \ struct f2fs_stat_info *si = F2FS_STAT(sbi); \
(si)->tot_segs++; \ (si)->tot_segs++; \
if (type == SUM_TYPE_DATA) \ if (type == SUM_TYPE_DATA) \
si->data_segs++; \ si->data_segs++; \
...@@ -1129,14 +1189,14 @@ struct f2fs_stat_info { ...@@ -1129,14 +1189,14 @@ struct f2fs_stat_info {
#define stat_inc_data_blk_count(sbi, blks) \ #define stat_inc_data_blk_count(sbi, blks) \
do { \ do { \
struct f2fs_stat_info *si = sbi->stat_info; \ struct f2fs_stat_info *si = F2FS_STAT(sbi); \
stat_inc_tot_blk_count(si, blks); \ stat_inc_tot_blk_count(si, blks); \
si->data_blks += (blks); \ si->data_blks += (blks); \
} while (0) } while (0)
#define stat_inc_node_blk_count(sbi, blks) \ #define stat_inc_node_blk_count(sbi, blks) \
do { \ do { \
struct f2fs_stat_info *si = sbi->stat_info; \ struct f2fs_stat_info *si = F2FS_STAT(sbi); \
stat_inc_tot_blk_count(si, blks); \ stat_inc_tot_blk_count(si, blks); \
si->node_blks += (blks); \ si->node_blks += (blks); \
} while (0) } while (0)
......
...@@ -112,11 +112,13 @@ static int get_parent_ino(struct inode *inode, nid_t *pino) ...@@ -112,11 +112,13 @@ static int get_parent_ino(struct inode *inode, nid_t *pino)
if (!dentry) if (!dentry)
return 0; return 0;
inode = igrab(dentry->d_parent->d_inode); if (update_dent_inode(inode, &dentry->d_name)) {
dput(dentry); dput(dentry);
return 0;
}
*pino = inode->i_ino; *pino = parent_ino(dentry);
iput(inode); dput(dentry);
return 1; return 1;
} }
...@@ -147,9 +149,10 @@ int f2fs_sync_file(struct file *file, loff_t start, loff_t end, int datasync) ...@@ -147,9 +149,10 @@ int f2fs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
mutex_lock(&inode->i_mutex); mutex_lock(&inode->i_mutex);
if (datasync && !(inode->i_state & I_DIRTY_DATASYNC)) /*
goto out; * Both of fdatasync() and fsync() are able to be recovered from
* sudden-power-off.
*/
if (!S_ISREG(inode->i_mode) || inode->i_nlink != 1) if (!S_ISREG(inode->i_mode) || inode->i_nlink != 1)
need_cp = true; need_cp = true;
else if (file_wrong_pino(inode)) else if (file_wrong_pino(inode))
...@@ -158,10 +161,14 @@ int f2fs_sync_file(struct file *file, loff_t start, loff_t end, int datasync) ...@@ -158,10 +161,14 @@ int f2fs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
need_cp = true; need_cp = true;
else if (!is_checkpointed_node(sbi, F2FS_I(inode)->i_pino)) else if (!is_checkpointed_node(sbi, F2FS_I(inode)->i_pino))
need_cp = true; need_cp = true;
else if (F2FS_I(inode)->xattr_ver == cur_cp_version(F2FS_CKPT(sbi)))
need_cp = true;
if (need_cp) { if (need_cp) {
nid_t pino; nid_t pino;
F2FS_I(inode)->xattr_ver = 0;
/* all the dirty node pages should be flushed for POR */ /* all the dirty node pages should be flushed for POR */
ret = f2fs_sync_fs(inode->i_sb, 1); ret = f2fs_sync_fs(inode->i_sb, 1);
if (file_wrong_pino(inode) && inode->i_nlink == 1 && if (file_wrong_pino(inode) && inode->i_nlink == 1 &&
...@@ -205,7 +212,7 @@ int truncate_data_blocks_range(struct dnode_of_data *dn, int count) ...@@ -205,7 +212,7 @@ int truncate_data_blocks_range(struct dnode_of_data *dn, int count)
struct f2fs_node *raw_node; struct f2fs_node *raw_node;
__le32 *addr; __le32 *addr;
raw_node = page_address(dn->node_page); raw_node = F2FS_NODE(dn->node_page);
addr = blkaddr_in_node(raw_node) + ofs; addr = blkaddr_in_node(raw_node) + ofs;
for ( ; count > 0; count--, addr++, dn->ofs_in_node++) { for ( ; count > 0; count--, addr++, dn->ofs_in_node++) {
...@@ -283,7 +290,7 @@ static int truncate_blocks(struct inode *inode, u64 from) ...@@ -283,7 +290,7 @@ static int truncate_blocks(struct inode *inode, u64 from)
} }
if (IS_INODE(dn.node_page)) if (IS_INODE(dn.node_page))
count = ADDRS_PER_INODE; count = ADDRS_PER_INODE(F2FS_I(inode));
else else
count = ADDRS_PER_BLOCK; count = ADDRS_PER_BLOCK;
......
...@@ -29,10 +29,11 @@ static struct kmem_cache *winode_slab; ...@@ -29,10 +29,11 @@ static struct kmem_cache *winode_slab;
static int gc_thread_func(void *data) static int gc_thread_func(void *data)
{ {
struct f2fs_sb_info *sbi = data; struct f2fs_sb_info *sbi = data;
struct f2fs_gc_kthread *gc_th = sbi->gc_thread;
wait_queue_head_t *wq = &sbi->gc_thread->gc_wait_queue_head; wait_queue_head_t *wq = &sbi->gc_thread->gc_wait_queue_head;
long wait_ms; long wait_ms;
wait_ms = GC_THREAD_MIN_SLEEP_TIME; wait_ms = gc_th->min_sleep_time;
do { do {
if (try_to_freeze()) if (try_to_freeze())
...@@ -45,7 +46,7 @@ static int gc_thread_func(void *data) ...@@ -45,7 +46,7 @@ static int gc_thread_func(void *data)
break; break;
if (sbi->sb->s_writers.frozen >= SB_FREEZE_WRITE) { if (sbi->sb->s_writers.frozen >= SB_FREEZE_WRITE) {
wait_ms = GC_THREAD_MAX_SLEEP_TIME; wait_ms = increase_sleep_time(gc_th, wait_ms);
continue; continue;
} }
...@@ -66,15 +67,15 @@ static int gc_thread_func(void *data) ...@@ -66,15 +67,15 @@ static int gc_thread_func(void *data)
continue; continue;
if (!is_idle(sbi)) { if (!is_idle(sbi)) {
wait_ms = increase_sleep_time(wait_ms); wait_ms = increase_sleep_time(gc_th, wait_ms);
mutex_unlock(&sbi->gc_mutex); mutex_unlock(&sbi->gc_mutex);
continue; continue;
} }
if (has_enough_invalid_blocks(sbi)) if (has_enough_invalid_blocks(sbi))
wait_ms = decrease_sleep_time(wait_ms); wait_ms = decrease_sleep_time(gc_th, wait_ms);
else else
wait_ms = increase_sleep_time(wait_ms); wait_ms = increase_sleep_time(gc_th, wait_ms);
#ifdef CONFIG_F2FS_STAT_FS #ifdef CONFIG_F2FS_STAT_FS
sbi->bg_gc++; sbi->bg_gc++;
...@@ -82,7 +83,7 @@ static int gc_thread_func(void *data) ...@@ -82,7 +83,7 @@ static int gc_thread_func(void *data)
/* 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_THREAD_NOGC_SLEEP_TIME; wait_ms = gc_th->no_gc_sleep_time;
} while (!kthread_should_stop()); } while (!kthread_should_stop());
return 0; return 0;
} }
...@@ -101,6 +102,12 @@ int start_gc_thread(struct f2fs_sb_info *sbi) ...@@ -101,6 +102,12 @@ int start_gc_thread(struct f2fs_sb_info *sbi)
goto out; goto out;
} }
gc_th->min_sleep_time = DEF_GC_THREAD_MIN_SLEEP_TIME;
gc_th->max_sleep_time = DEF_GC_THREAD_MAX_SLEEP_TIME;
gc_th->no_gc_sleep_time = DEF_GC_THREAD_NOGC_SLEEP_TIME;
gc_th->gc_idle = 0;
sbi->gc_thread = gc_th; sbi->gc_thread = gc_th;
init_waitqueue_head(&sbi->gc_thread->gc_wait_queue_head); init_waitqueue_head(&sbi->gc_thread->gc_wait_queue_head);
sbi->gc_thread->f2fs_gc_task = kthread_run(gc_thread_func, sbi, sbi->gc_thread->f2fs_gc_task = kthread_run(gc_thread_func, sbi,
...@@ -125,9 +132,17 @@ void stop_gc_thread(struct f2fs_sb_info *sbi) ...@@ -125,9 +132,17 @@ void stop_gc_thread(struct f2fs_sb_info *sbi)
sbi->gc_thread = NULL; sbi->gc_thread = NULL;
} }
static int select_gc_type(int gc_type) static int select_gc_type(struct f2fs_gc_kthread *gc_th, int gc_type)
{ {
return (gc_type == BG_GC) ? GC_CB : GC_GREEDY; int gc_mode = (gc_type == BG_GC) ? GC_CB : GC_GREEDY;
if (gc_th && gc_th->gc_idle) {
if (gc_th->gc_idle == 1)
gc_mode = GC_CB;
else if (gc_th->gc_idle == 2)
gc_mode = GC_GREEDY;
}
return gc_mode;
} }
static void select_policy(struct f2fs_sb_info *sbi, int gc_type, static void select_policy(struct f2fs_sb_info *sbi, int gc_type,
...@@ -138,12 +153,18 @@ static void select_policy(struct f2fs_sb_info *sbi, int gc_type, ...@@ -138,12 +153,18 @@ static void select_policy(struct f2fs_sb_info *sbi, int gc_type,
if (p->alloc_mode == SSR) { if (p->alloc_mode == SSR) {
p->gc_mode = GC_GREEDY; p->gc_mode = GC_GREEDY;
p->dirty_segmap = dirty_i->dirty_segmap[type]; p->dirty_segmap = dirty_i->dirty_segmap[type];
p->max_search = dirty_i->nr_dirty[type];
p->ofs_unit = 1; p->ofs_unit = 1;
} else { } else {
p->gc_mode = select_gc_type(gc_type); p->gc_mode = select_gc_type(sbi->gc_thread, gc_type);
p->dirty_segmap = dirty_i->dirty_segmap[DIRTY]; p->dirty_segmap = dirty_i->dirty_segmap[DIRTY];
p->max_search = dirty_i->nr_dirty[DIRTY];
p->ofs_unit = sbi->segs_per_sec; p->ofs_unit = sbi->segs_per_sec;
} }
if (p->max_search > MAX_VICTIM_SEARCH)
p->max_search = MAX_VICTIM_SEARCH;
p->offset = sbi->last_victim[p->gc_mode]; p->offset = sbi->last_victim[p->gc_mode];
} }
...@@ -290,7 +311,7 @@ static int get_victim_by_default(struct f2fs_sb_info *sbi, ...@@ -290,7 +311,7 @@ static int get_victim_by_default(struct f2fs_sb_info *sbi,
if (cost == max_cost) if (cost == max_cost)
continue; continue;
if (nsearched++ >= MAX_VICTIM_SEARCH) { if (nsearched++ >= p.max_search) {
sbi->last_victim[p.gc_mode] = segno; sbi->last_victim[p.gc_mode] = segno;
break; break;
} }
...@@ -407,8 +428,7 @@ static void gc_node_segment(struct f2fs_sb_info *sbi, ...@@ -407,8 +428,7 @@ static void gc_node_segment(struct f2fs_sb_info *sbi,
/* set page dirty and write it */ /* set page dirty and write it */
if (gc_type == FG_GC) { if (gc_type == FG_GC) {
f2fs_submit_bio(sbi, NODE, true); f2fs_wait_on_page_writeback(node_page, NODE, true);
wait_on_page_writeback(node_page);
set_page_dirty(node_page); set_page_dirty(node_page);
} else { } else {
if (!PageWriteback(node_page)) if (!PageWriteback(node_page))
...@@ -447,7 +467,7 @@ static void gc_node_segment(struct f2fs_sb_info *sbi, ...@@ -447,7 +467,7 @@ static void gc_node_segment(struct f2fs_sb_info *sbi,
* as indirect or double indirect node blocks, are given, it must be a caller's * as indirect or double indirect node blocks, are given, it must be a caller's
* bug. * bug.
*/ */
block_t start_bidx_of_node(unsigned int node_ofs) block_t start_bidx_of_node(unsigned int node_ofs, struct f2fs_inode_info *fi)
{ {
unsigned int indirect_blks = 2 * NIDS_PER_BLOCK + 4; unsigned int indirect_blks = 2 * NIDS_PER_BLOCK + 4;
unsigned int bidx; unsigned int bidx;
...@@ -464,7 +484,7 @@ block_t start_bidx_of_node(unsigned int node_ofs) ...@@ -464,7 +484,7 @@ block_t start_bidx_of_node(unsigned int node_ofs)
int dec = (node_ofs - indirect_blks - 3) / (NIDS_PER_BLOCK + 1); int dec = (node_ofs - indirect_blks - 3) / (NIDS_PER_BLOCK + 1);
bidx = node_ofs - 5 - dec; bidx = node_ofs - 5 - dec;
} }
return bidx * ADDRS_PER_BLOCK + ADDRS_PER_INODE; return bidx * ADDRS_PER_BLOCK + ADDRS_PER_INODE(fi);
} }
static int check_dnode(struct f2fs_sb_info *sbi, struct f2fs_summary *sum, static int check_dnode(struct f2fs_sb_info *sbi, struct f2fs_summary *sum,
...@@ -508,10 +528,7 @@ static void move_data_page(struct inode *inode, struct page *page, int gc_type) ...@@ -508,10 +528,7 @@ static void move_data_page(struct inode *inode, struct page *page, int gc_type)
} else { } else {
struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
if (PageWriteback(page)) { f2fs_wait_on_page_writeback(page, DATA, true);
f2fs_submit_bio(sbi, DATA, true);
wait_on_page_writeback(page);
}
if (clear_page_dirty_for_io(page) && if (clear_page_dirty_for_io(page) &&
S_ISDIR(inode->i_mode)) { S_ISDIR(inode->i_mode)) {
...@@ -575,7 +592,6 @@ static void gc_data_segment(struct f2fs_sb_info *sbi, struct f2fs_summary *sum, ...@@ -575,7 +592,6 @@ static void gc_data_segment(struct f2fs_sb_info *sbi, struct f2fs_summary *sum,
continue; continue;
} }
start_bidx = start_bidx_of_node(nofs);
ofs_in_node = le16_to_cpu(entry->ofs_in_node); ofs_in_node = le16_to_cpu(entry->ofs_in_node);
if (phase == 2) { if (phase == 2) {
...@@ -583,6 +599,8 @@ static void gc_data_segment(struct f2fs_sb_info *sbi, struct f2fs_summary *sum, ...@@ -583,6 +599,8 @@ static void gc_data_segment(struct f2fs_sb_info *sbi, struct f2fs_summary *sum,
if (IS_ERR(inode)) if (IS_ERR(inode))
continue; continue;
start_bidx = start_bidx_of_node(nofs, F2FS_I(inode));
data_page = find_data_page(inode, data_page = find_data_page(inode,
start_bidx + ofs_in_node, false); start_bidx + ofs_in_node, false);
if (IS_ERR(data_page)) if (IS_ERR(data_page))
...@@ -593,6 +611,8 @@ static void gc_data_segment(struct f2fs_sb_info *sbi, struct f2fs_summary *sum, ...@@ -593,6 +611,8 @@ static void gc_data_segment(struct f2fs_sb_info *sbi, struct f2fs_summary *sum,
} else { } else {
inode = find_gc_inode(dni.ino, ilist); inode = find_gc_inode(dni.ino, ilist);
if (inode) { if (inode) {
start_bidx = start_bidx_of_node(nofs,
F2FS_I(inode));
data_page = get_lock_data_page(inode, data_page = get_lock_data_page(inode,
start_bidx + ofs_in_node); start_bidx + ofs_in_node);
if (IS_ERR(data_page)) if (IS_ERR(data_page))
......
...@@ -13,18 +13,26 @@ ...@@ -13,18 +13,26 @@
* whether IO subsystem is idle * whether IO subsystem is idle
* or not * or not
*/ */
#define GC_THREAD_MIN_SLEEP_TIME 30000 /* milliseconds */ #define DEF_GC_THREAD_MIN_SLEEP_TIME 30000 /* milliseconds */
#define GC_THREAD_MAX_SLEEP_TIME 60000 #define DEF_GC_THREAD_MAX_SLEEP_TIME 60000
#define GC_THREAD_NOGC_SLEEP_TIME 300000 /* wait 5 min */ #define DEF_GC_THREAD_NOGC_SLEEP_TIME 300000 /* wait 5 min */
#define LIMIT_INVALID_BLOCK 40 /* percentage over total user space */ #define LIMIT_INVALID_BLOCK 40 /* percentage over total user space */
#define LIMIT_FREE_BLOCK 40 /* percentage over invalid + free space */ #define LIMIT_FREE_BLOCK 40 /* percentage over invalid + free space */
/* Search max. number of dirty segments to select a victim segment */ /* Search max. number of dirty segments to select a victim segment */
#define MAX_VICTIM_SEARCH 20 #define MAX_VICTIM_SEARCH 4096 /* covers 8GB */
struct f2fs_gc_kthread { struct f2fs_gc_kthread {
struct task_struct *f2fs_gc_task; struct task_struct *f2fs_gc_task;
wait_queue_head_t gc_wait_queue_head; wait_queue_head_t gc_wait_queue_head;
/* for gc sleep time */
unsigned int min_sleep_time;
unsigned int max_sleep_time;
unsigned int no_gc_sleep_time;
/* for changing gc mode */
unsigned int gc_idle;
}; };
struct inode_entry { struct inode_entry {
...@@ -56,25 +64,25 @@ static inline block_t limit_free_user_blocks(struct f2fs_sb_info *sbi) ...@@ -56,25 +64,25 @@ static inline block_t limit_free_user_blocks(struct f2fs_sb_info *sbi)
return (long)(reclaimable_user_blocks * LIMIT_FREE_BLOCK) / 100; return (long)(reclaimable_user_blocks * LIMIT_FREE_BLOCK) / 100;
} }
static inline long increase_sleep_time(long wait) static inline long increase_sleep_time(struct f2fs_gc_kthread *gc_th, long wait)
{ {
if (wait == GC_THREAD_NOGC_SLEEP_TIME) if (wait == gc_th->no_gc_sleep_time)
return wait; return wait;
wait += GC_THREAD_MIN_SLEEP_TIME; wait += gc_th->min_sleep_time;
if (wait > GC_THREAD_MAX_SLEEP_TIME) if (wait > gc_th->max_sleep_time)
wait = GC_THREAD_MAX_SLEEP_TIME; wait = gc_th->max_sleep_time;
return wait; return wait;
} }
static inline long decrease_sleep_time(long wait) static inline long decrease_sleep_time(struct f2fs_gc_kthread *gc_th, long wait)
{ {
if (wait == GC_THREAD_NOGC_SLEEP_TIME) if (wait == gc_th->no_gc_sleep_time)
wait = GC_THREAD_MAX_SLEEP_TIME; wait = gc_th->max_sleep_time;
wait -= GC_THREAD_MIN_SLEEP_TIME; wait -= gc_th->min_sleep_time;
if (wait <= GC_THREAD_MIN_SLEEP_TIME) if (wait <= gc_th->min_sleep_time)
wait = GC_THREAD_MIN_SLEEP_TIME; wait = gc_th->min_sleep_time;
return wait; return wait;
} }
......
...@@ -56,7 +56,7 @@ static int do_read_inode(struct inode *inode) ...@@ -56,7 +56,7 @@ static int do_read_inode(struct inode *inode)
if (IS_ERR(node_page)) if (IS_ERR(node_page))
return PTR_ERR(node_page); return PTR_ERR(node_page);
rn = page_address(node_page); rn = F2FS_NODE(node_page);
ri = &(rn->i); ri = &(rn->i);
inode->i_mode = le16_to_cpu(ri->i_mode); inode->i_mode = le16_to_cpu(ri->i_mode);
...@@ -85,6 +85,7 @@ static int do_read_inode(struct inode *inode) ...@@ -85,6 +85,7 @@ static int do_read_inode(struct inode *inode)
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);
f2fs_put_page(node_page, 1); f2fs_put_page(node_page, 1);
return 0; return 0;
} }
...@@ -151,9 +152,9 @@ void update_inode(struct inode *inode, struct page *node_page) ...@@ -151,9 +152,9 @@ void update_inode(struct inode *inode, struct page *node_page)
struct f2fs_node *rn; struct f2fs_node *rn;
struct f2fs_inode *ri; struct f2fs_inode *ri;
wait_on_page_writeback(node_page); f2fs_wait_on_page_writeback(node_page, NODE, false);
rn = page_address(node_page); rn = F2FS_NODE(node_page);
ri = &(rn->i); ri = &(rn->i);
ri->i_mode = cpu_to_le16(inode->i_mode); ri->i_mode = cpu_to_le16(inode->i_mode);
...@@ -164,6 +165,7 @@ void update_inode(struct inode *inode, struct page *node_page) ...@@ -164,6 +165,7 @@ void update_inode(struct inode *inode, struct page *node_page)
ri->i_size = cpu_to_le64(i_size_read(inode)); ri->i_size = cpu_to_le64(i_size_read(inode));
ri->i_blocks = cpu_to_le64(inode->i_blocks); ri->i_blocks = cpu_to_le64(inode->i_blocks);
set_raw_extent(&F2FS_I(inode)->ext, &ri->i_ext); set_raw_extent(&F2FS_I(inode)->ext, &ri->i_ext);
set_raw_inline(F2FS_I(inode), ri);
ri->i_atime = cpu_to_le64(inode->i_atime.tv_sec); ri->i_atime = cpu_to_le64(inode->i_atime.tv_sec);
ri->i_ctime = cpu_to_le64(inode->i_ctime.tv_sec); ri->i_ctime = cpu_to_le64(inode->i_ctime.tv_sec);
...@@ -221,9 +223,6 @@ int f2fs_write_inode(struct inode *inode, struct writeback_control *wbc) ...@@ -221,9 +223,6 @@ int f2fs_write_inode(struct inode *inode, struct writeback_control *wbc)
if (!is_inode_flag_set(F2FS_I(inode), FI_DIRTY_INODE)) if (!is_inode_flag_set(F2FS_I(inode), FI_DIRTY_INODE))
return 0; return 0;
if (wbc)
f2fs_balance_fs(sbi);
/* /*
* 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.
...@@ -231,6 +230,10 @@ int f2fs_write_inode(struct inode *inode, struct writeback_control *wbc) ...@@ -231,6 +230,10 @@ int f2fs_write_inode(struct inode *inode, struct writeback_control *wbc)
ilock = mutex_lock_op(sbi); ilock = mutex_lock_op(sbi);
ret = update_inode_page(inode); ret = update_inode_page(inode);
mutex_unlock_op(sbi, ilock); mutex_unlock_op(sbi, ilock);
if (wbc)
f2fs_balance_fs(sbi);
return ret; return ret;
} }
......
...@@ -83,21 +83,11 @@ static int is_multimedia_file(const unsigned char *s, const char *sub) ...@@ -83,21 +83,11 @@ static int is_multimedia_file(const unsigned char *s, const char *sub)
{ {
size_t slen = strlen(s); size_t slen = strlen(s);
size_t sublen = strlen(sub); size_t sublen = strlen(sub);
int ret;
if (sublen > slen) if (sublen > slen)
return 0; return 0;
ret = memcmp(s + slen - sublen, sub, sublen); return !strncasecmp(s + slen - sublen, sub, sublen);
if (ret) { /* compare upper case */
int i;
char upper_sub[8];
for (i = 0; i < sublen && i < sizeof(upper_sub); i++)
upper_sub[i] = toupper(sub[i]);
return !memcmp(s + slen - sublen, upper_sub, sublen);
}
return !ret;
} }
/* /*
...@@ -239,7 +229,7 @@ static int f2fs_unlink(struct inode *dir, struct dentry *dentry) ...@@ -239,7 +229,7 @@ static int f2fs_unlink(struct inode *dir, struct dentry *dentry)
if (!de) if (!de)
goto fail; goto fail;
err = check_orphan_space(sbi); err = acquire_orphan_inode(sbi);
if (err) { if (err) {
kunmap(page); kunmap(page);
f2fs_put_page(page, 0); f2fs_put_page(page, 0);
...@@ -393,7 +383,7 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -393,7 +383,7 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
struct inode *old_inode = old_dentry->d_inode; struct inode *old_inode = old_dentry->d_inode;
struct inode *new_inode = new_dentry->d_inode; struct inode *new_inode = new_dentry->d_inode;
struct page *old_dir_page; struct page *old_dir_page;
struct page *old_page; struct page *old_page, *new_page;
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;
...@@ -415,7 +405,6 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -415,7 +405,6 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
ilock = mutex_lock_op(sbi); ilock = mutex_lock_op(sbi);
if (new_inode) { if (new_inode) {
struct page *new_page;
err = -ENOTEMPTY; err = -ENOTEMPTY;
if (old_dir_entry && !f2fs_empty_dir(new_inode)) if (old_dir_entry && !f2fs_empty_dir(new_inode))
...@@ -427,14 +416,28 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -427,14 +416,28 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
if (!new_entry) if (!new_entry)
goto out_dir; goto out_dir;
err = acquire_orphan_inode(sbi);
if (err)
goto put_out_dir;
if (update_dent_inode(old_inode, &new_dentry->d_name)) {
release_orphan_inode(sbi);
goto put_out_dir;
}
f2fs_set_link(new_dir, new_entry, new_page, old_inode); f2fs_set_link(new_dir, new_entry, new_page, old_inode);
new_inode->i_ctime = CURRENT_TIME; new_inode->i_ctime = CURRENT_TIME;
if (old_dir_entry) if (old_dir_entry)
drop_nlink(new_inode); drop_nlink(new_inode);
drop_nlink(new_inode); drop_nlink(new_inode);
if (!new_inode->i_nlink) if (!new_inode->i_nlink)
add_orphan_inode(sbi, new_inode->i_ino); add_orphan_inode(sbi, new_inode->i_ino);
else
release_orphan_inode(sbi);
update_inode_page(old_inode);
update_inode_page(new_inode); update_inode_page(new_inode);
} else { } else {
err = f2fs_add_link(new_dentry, old_inode); err = f2fs_add_link(new_dentry, old_inode);
...@@ -467,6 +470,8 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -467,6 +470,8 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
mutex_unlock_op(sbi, ilock); mutex_unlock_op(sbi, ilock);
return 0; return 0;
put_out_dir:
f2fs_put_page(new_page, 1);
out_dir: out_dir:
if (old_dir_entry) { if (old_dir_entry) {
kunmap(old_dir_page); kunmap(old_dir_page);
......
...@@ -315,9 +315,10 @@ void get_node_info(struct f2fs_sb_info *sbi, nid_t nid, struct node_info *ni) ...@@ -315,9 +315,10 @@ void get_node_info(struct f2fs_sb_info *sbi, nid_t nid, struct node_info *ni)
* The maximum depth is four. * The maximum depth is four.
* Offset[0] will have raw inode offset. * Offset[0] will have raw inode offset.
*/ */
static int get_node_path(long block, int offset[4], unsigned int noffset[4]) static int get_node_path(struct f2fs_inode_info *fi, long block,
int offset[4], unsigned int noffset[4])
{ {
const long direct_index = ADDRS_PER_INODE; const long direct_index = ADDRS_PER_INODE(fi);
const long direct_blks = ADDRS_PER_BLOCK; const long direct_blks = ADDRS_PER_BLOCK;
const long dptrs_per_blk = NIDS_PER_BLOCK; const long dptrs_per_blk = NIDS_PER_BLOCK;
const long indirect_blks = ADDRS_PER_BLOCK * NIDS_PER_BLOCK; const long indirect_blks = ADDRS_PER_BLOCK * NIDS_PER_BLOCK;
...@@ -405,7 +406,7 @@ int get_dnode_of_data(struct dnode_of_data *dn, pgoff_t index, int mode) ...@@ -405,7 +406,7 @@ int get_dnode_of_data(struct dnode_of_data *dn, pgoff_t index, int mode)
int level, i; int level, i;
int err = 0; int err = 0;
level = get_node_path(index, offset, noffset); level = get_node_path(F2FS_I(dn->inode), index, offset, noffset);
nids[0] = dn->inode->i_ino; nids[0] = dn->inode->i_ino;
npage[0] = dn->inode_page; npage[0] = dn->inode_page;
...@@ -565,7 +566,7 @@ static int truncate_nodes(struct dnode_of_data *dn, unsigned int nofs, ...@@ -565,7 +566,7 @@ static int truncate_nodes(struct dnode_of_data *dn, unsigned int nofs,
return PTR_ERR(page); return PTR_ERR(page);
} }
rn = (struct f2fs_node *)page_address(page); rn = F2FS_NODE(page);
if (depth < 3) { if (depth < 3) {
for (i = ofs; i < NIDS_PER_BLOCK; i++, freed++) { for (i = ofs; i < NIDS_PER_BLOCK; i++, freed++) {
child_nid = le32_to_cpu(rn->in.nid[i]); child_nid = le32_to_cpu(rn->in.nid[i]);
...@@ -687,7 +688,7 @@ int truncate_inode_blocks(struct inode *inode, pgoff_t from) ...@@ -687,7 +688,7 @@ int truncate_inode_blocks(struct inode *inode, pgoff_t from)
trace_f2fs_truncate_inode_blocks_enter(inode, from); trace_f2fs_truncate_inode_blocks_enter(inode, from);
level = get_node_path(from, offset, noffset); level = get_node_path(F2FS_I(inode), from, offset, noffset);
restart: restart:
page = get_node_page(sbi, inode->i_ino); page = get_node_page(sbi, inode->i_ino);
if (IS_ERR(page)) { if (IS_ERR(page)) {
...@@ -698,7 +699,7 @@ int truncate_inode_blocks(struct inode *inode, pgoff_t from) ...@@ -698,7 +699,7 @@ int truncate_inode_blocks(struct inode *inode, pgoff_t from)
set_new_dnode(&dn, inode, page, NULL, 0); set_new_dnode(&dn, inode, page, NULL, 0);
unlock_page(page); unlock_page(page);
rn = page_address(page); rn = F2FS_NODE(page);
switch (level) { switch (level) {
case 0: case 0:
case 1: case 1:
...@@ -771,6 +772,33 @@ int truncate_inode_blocks(struct inode *inode, pgoff_t from) ...@@ -771,6 +772,33 @@ int truncate_inode_blocks(struct inode *inode, pgoff_t from)
return err > 0 ? 0 : err; return err > 0 ? 0 : err;
} }
int truncate_xattr_node(struct inode *inode, struct page *page)
{
struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
nid_t nid = F2FS_I(inode)->i_xattr_nid;
struct dnode_of_data dn;
struct page *npage;
if (!nid)
return 0;
npage = get_node_page(sbi, nid);
if (IS_ERR(npage))
return PTR_ERR(npage);
F2FS_I(inode)->i_xattr_nid = 0;
/* need to do checkpoint during fsync */
F2FS_I(inode)->xattr_ver = cur_cp_version(F2FS_CKPT(sbi));
set_new_dnode(&dn, inode, page, npage, nid);
if (page)
dn.inode_page_locked = 1;
truncate_node(&dn);
return 0;
}
/* /*
* Caller should grab and release a mutex by calling mutex_lock_op() and * Caller should grab and release a mutex by calling mutex_lock_op() and
* mutex_unlock_op(). * mutex_unlock_op().
...@@ -781,22 +809,16 @@ int remove_inode_page(struct inode *inode) ...@@ -781,22 +809,16 @@ int remove_inode_page(struct inode *inode)
struct page *page; struct page *page;
nid_t ino = inode->i_ino; nid_t ino = inode->i_ino;
struct dnode_of_data dn; struct dnode_of_data dn;
int err;
page = get_node_page(sbi, ino); page = get_node_page(sbi, ino);
if (IS_ERR(page)) if (IS_ERR(page))
return PTR_ERR(page); return PTR_ERR(page);
if (F2FS_I(inode)->i_xattr_nid) { err = truncate_xattr_node(inode, page);
nid_t nid = F2FS_I(inode)->i_xattr_nid; if (err) {
struct page *npage = get_node_page(sbi, nid); f2fs_put_page(page, 1);
return err;
if (IS_ERR(npage))
return PTR_ERR(npage);
F2FS_I(inode)->i_xattr_nid = 0;
set_new_dnode(&dn, inode, page, npage, nid);
dn.inode_page_locked = 1;
truncate_node(&dn);
} }
/* 0 is possible, after f2fs_new_inode() is failed */ /* 0 is possible, after f2fs_new_inode() is failed */
...@@ -833,29 +855,32 @@ struct page *new_node_page(struct dnode_of_data *dn, ...@@ -833,29 +855,32 @@ struct page *new_node_page(struct dnode_of_data *dn,
if (!page) if (!page)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
get_node_info(sbi, dn->nid, &old_ni); if (!inc_valid_node_count(sbi, dn->inode, 1)) {
err = -ENOSPC;
goto fail;
}
SetPageUptodate(page); get_node_info(sbi, dn->nid, &old_ni);
fill_node_footer(page, dn->nid, dn->inode->i_ino, ofs, true);
/* Reinitialize old_ni with new node page */ /* Reinitialize old_ni with new node page */
BUG_ON(old_ni.blk_addr != NULL_ADDR); 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;
if (!inc_valid_node_count(sbi, dn->inode, 1)) {
err = -ENOSPC;
goto fail;
}
set_node_addr(sbi, &new_ni, NEW_ADDR); set_node_addr(sbi, &new_ni, NEW_ADDR);
fill_node_footer(page, dn->nid, dn->inode->i_ino, ofs, true);
set_cold_node(dn->inode, page); set_cold_node(dn->inode, page);
SetPageUptodate(page);
set_page_dirty(page);
if (ofs == XATTR_NODE_OFFSET)
F2FS_I(dn->inode)->i_xattr_nid = dn->nid;
dn->node_page = page; dn->node_page = page;
if (ipage) if (ipage)
update_inode(dn->inode, ipage); update_inode(dn->inode, ipage);
else else
sync_inode_page(dn); sync_inode_page(dn);
set_page_dirty(page);
if (ofs == 0) if (ofs == 0)
inc_valid_inode_count(sbi); inc_valid_inode_count(sbi);
...@@ -916,7 +941,6 @@ void ra_node_page(struct f2fs_sb_info *sbi, nid_t nid) ...@@ -916,7 +941,6 @@ void ra_node_page(struct f2fs_sb_info *sbi, nid_t nid)
f2fs_put_page(apage, 0); f2fs_put_page(apage, 0);
else if (err == LOCKED_PAGE) else if (err == LOCKED_PAGE)
f2fs_put_page(apage, 1); f2fs_put_page(apage, 1);
return;
} }
struct page *get_node_page(struct f2fs_sb_info *sbi, pgoff_t nid) struct page *get_node_page(struct f2fs_sb_info *sbi, pgoff_t nid)
...@@ -1167,9 +1191,9 @@ static int f2fs_write_node_page(struct page *page, ...@@ -1167,9 +1191,9 @@ static int f2fs_write_node_page(struct page *page,
/* /*
* It is very important to gather dirty pages and write at once, so that we can * 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. * submit a big bio without interfering other data writes.
* Be default, 512 pages (2MB), a segment size, is quite reasonable. * Be default, 512 pages (2MB) * 3 node types, is more reasonable.
*/ */
#define COLLECT_DIRTY_NODES 512 #define COLLECT_DIRTY_NODES 1536
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)
{ {
...@@ -1187,9 +1211,10 @@ static int f2fs_write_node_pages(struct address_space *mapping, ...@@ -1187,9 +1211,10 @@ static int f2fs_write_node_pages(struct address_space *mapping,
return 0; return 0;
/* if mounting is failed, skip writing node pages */ /* if mounting is failed, skip writing node pages */
wbc->nr_to_write = max_hw_blocks(sbi); wbc->nr_to_write = 3 * max_hw_blocks(sbi);
sync_node_pages(sbi, 0, wbc); sync_node_pages(sbi, 0, wbc);
wbc->nr_to_write = nr_to_write - (max_hw_blocks(sbi) - wbc->nr_to_write); wbc->nr_to_write = nr_to_write - (3 * max_hw_blocks(sbi) -
wbc->nr_to_write);
return 0; return 0;
} }
...@@ -1444,6 +1469,9 @@ void alloc_nid_failed(struct f2fs_sb_info *sbi, nid_t nid) ...@@ -1444,6 +1469,9 @@ void alloc_nid_failed(struct f2fs_sb_info *sbi, nid_t nid)
struct f2fs_nm_info *nm_i = NM_I(sbi); struct f2fs_nm_info *nm_i = NM_I(sbi);
struct free_nid *i; struct free_nid *i;
if (!nid)
return;
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); BUG_ON(!i || i->state != NID_ALLOC);
...@@ -1484,8 +1512,8 @@ int recover_inode_page(struct f2fs_sb_info *sbi, struct page *page) ...@@ -1484,8 +1512,8 @@ int recover_inode_page(struct f2fs_sb_info *sbi, struct page *page)
SetPageUptodate(ipage); SetPageUptodate(ipage);
fill_node_footer(ipage, ino, ino, 0, true); fill_node_footer(ipage, ino, ino, 0, true);
src = (struct f2fs_node *)page_address(page); src = F2FS_NODE(page);
dst = (struct f2fs_node *)page_address(ipage); dst = F2FS_NODE(ipage);
memcpy(dst, src, (unsigned long)&src->i.i_ext - (unsigned long)&src->i); memcpy(dst, src, (unsigned long)&src->i.i_ext - (unsigned long)&src->i);
dst->i.i_size = 0; dst->i.i_size = 0;
...@@ -1515,8 +1543,8 @@ int restore_node_summary(struct f2fs_sb_info *sbi, ...@@ -1515,8 +1543,8 @@ int restore_node_summary(struct f2fs_sb_info *sbi,
/* alloc temporal page for read node */ /* alloc temporal page for read node */
page = alloc_page(GFP_NOFS | __GFP_ZERO); page = alloc_page(GFP_NOFS | __GFP_ZERO);
if (IS_ERR(page)) if (!page)
return PTR_ERR(page); return -ENOMEM;
lock_page(page); lock_page(page);
/* scan the node segment */ /* scan the node segment */
...@@ -1535,7 +1563,7 @@ int restore_node_summary(struct f2fs_sb_info *sbi, ...@@ -1535,7 +1563,7 @@ int restore_node_summary(struct f2fs_sb_info *sbi,
goto out; goto out;
lock_page(page); lock_page(page);
rn = (struct f2fs_node *)page_address(page); rn = F2FS_NODE(page);
sum_entry->nid = rn->footer.nid; sum_entry->nid = rn->footer.nid;
sum_entry->version = 0; sum_entry->version = 0;
sum_entry->ofs_in_node = 0; sum_entry->ofs_in_node = 0;
......
...@@ -155,8 +155,7 @@ static inline void set_to_next_nat(struct f2fs_nm_info *nm_i, nid_t start_nid) ...@@ -155,8 +155,7 @@ static inline void set_to_next_nat(struct f2fs_nm_info *nm_i, nid_t start_nid)
static inline void fill_node_footer(struct page *page, nid_t nid, static inline void fill_node_footer(struct page *page, nid_t nid,
nid_t ino, unsigned int ofs, bool reset) nid_t ino, unsigned int ofs, bool reset)
{ {
void *kaddr = page_address(page); struct f2fs_node *rn = F2FS_NODE(page);
struct f2fs_node *rn = (struct f2fs_node *)kaddr;
if (reset) if (reset)
memset(rn, 0, sizeof(*rn)); memset(rn, 0, sizeof(*rn));
rn->footer.nid = cpu_to_le32(nid); rn->footer.nid = cpu_to_le32(nid);
...@@ -166,10 +165,8 @@ static inline void fill_node_footer(struct page *page, nid_t nid, ...@@ -166,10 +165,8 @@ static inline void fill_node_footer(struct page *page, nid_t nid,
static inline void copy_node_footer(struct page *dst, struct page *src) static inline void copy_node_footer(struct page *dst, struct page *src)
{ {
void *src_addr = page_address(src); struct f2fs_node *src_rn = F2FS_NODE(src);
void *dst_addr = page_address(dst); struct f2fs_node *dst_rn = F2FS_NODE(dst);
struct f2fs_node *src_rn = (struct f2fs_node *)src_addr;
struct f2fs_node *dst_rn = (struct f2fs_node *)dst_addr;
memcpy(&dst_rn->footer, &src_rn->footer, sizeof(struct node_footer)); memcpy(&dst_rn->footer, &src_rn->footer, sizeof(struct node_footer));
} }
...@@ -177,45 +174,40 @@ static inline void fill_node_footer_blkaddr(struct page *page, block_t blkaddr) ...@@ -177,45 +174,40 @@ static inline void fill_node_footer_blkaddr(struct page *page, block_t blkaddr)
{ {
struct f2fs_sb_info *sbi = F2FS_SB(page->mapping->host->i_sb); struct f2fs_sb_info *sbi = F2FS_SB(page->mapping->host->i_sb);
struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
void *kaddr = page_address(page); struct f2fs_node *rn = F2FS_NODE(page);
struct f2fs_node *rn = (struct f2fs_node *)kaddr;
rn->footer.cp_ver = ckpt->checkpoint_ver; rn->footer.cp_ver = ckpt->checkpoint_ver;
rn->footer.next_blkaddr = cpu_to_le32(blkaddr); rn->footer.next_blkaddr = cpu_to_le32(blkaddr);
} }
static inline nid_t ino_of_node(struct page *node_page) static inline nid_t ino_of_node(struct page *node_page)
{ {
void *kaddr = page_address(node_page); struct f2fs_node *rn = F2FS_NODE(node_page);
struct f2fs_node *rn = (struct f2fs_node *)kaddr;
return le32_to_cpu(rn->footer.ino); return le32_to_cpu(rn->footer.ino);
} }
static inline nid_t nid_of_node(struct page *node_page) static inline nid_t nid_of_node(struct page *node_page)
{ {
void *kaddr = page_address(node_page); struct f2fs_node *rn = F2FS_NODE(node_page);
struct f2fs_node *rn = (struct f2fs_node *)kaddr;
return le32_to_cpu(rn->footer.nid); return le32_to_cpu(rn->footer.nid);
} }
static inline unsigned int ofs_of_node(struct page *node_page) static inline unsigned int ofs_of_node(struct page *node_page)
{ {
void *kaddr = page_address(node_page); struct f2fs_node *rn = F2FS_NODE(node_page);
struct f2fs_node *rn = (struct f2fs_node *)kaddr;
unsigned flag = le32_to_cpu(rn->footer.flag); unsigned flag = le32_to_cpu(rn->footer.flag);
return flag >> OFFSET_BIT_SHIFT; return flag >> OFFSET_BIT_SHIFT;
} }
static inline unsigned long long cpver_of_node(struct page *node_page) static inline unsigned long long cpver_of_node(struct page *node_page)
{ {
void *kaddr = page_address(node_page); struct f2fs_node *rn = F2FS_NODE(node_page);
struct f2fs_node *rn = (struct f2fs_node *)kaddr;
return le64_to_cpu(rn->footer.cp_ver); return le64_to_cpu(rn->footer.cp_ver);
} }
static inline block_t next_blkaddr_of_node(struct page *node_page) static inline block_t next_blkaddr_of_node(struct page *node_page)
{ {
void *kaddr = page_address(node_page); struct f2fs_node *rn = F2FS_NODE(node_page);
struct f2fs_node *rn = (struct f2fs_node *)kaddr;
return le32_to_cpu(rn->footer.next_blkaddr); return le32_to_cpu(rn->footer.next_blkaddr);
} }
...@@ -237,6 +229,10 @@ static inline block_t next_blkaddr_of_node(struct page *node_page) ...@@ -237,6 +229,10 @@ static inline block_t next_blkaddr_of_node(struct page *node_page)
static inline bool IS_DNODE(struct page *node_page) static inline bool IS_DNODE(struct page *node_page)
{ {
unsigned int ofs = ofs_of_node(node_page); unsigned int ofs = ofs_of_node(node_page);
if (ofs == XATTR_NODE_OFFSET)
return false;
if (ofs == 3 || ofs == 4 + NIDS_PER_BLOCK || if (ofs == 3 || ofs == 4 + NIDS_PER_BLOCK ||
ofs == 5 + 2 * NIDS_PER_BLOCK) ofs == 5 + 2 * NIDS_PER_BLOCK)
return false; return false;
...@@ -250,7 +246,7 @@ static inline bool IS_DNODE(struct page *node_page) ...@@ -250,7 +246,7 @@ static inline bool IS_DNODE(struct page *node_page)
static inline void set_nid(struct page *p, int off, nid_t nid, bool i) static inline void set_nid(struct page *p, int off, nid_t nid, bool i)
{ {
struct f2fs_node *rn = (struct f2fs_node *)page_address(p); struct f2fs_node *rn = F2FS_NODE(p);
wait_on_page_writeback(p); wait_on_page_writeback(p);
...@@ -263,7 +259,8 @@ static inline void set_nid(struct page *p, int off, nid_t nid, bool i) ...@@ -263,7 +259,8 @@ static inline void set_nid(struct page *p, int off, nid_t nid, bool i)
static inline nid_t get_nid(struct page *p, int off, bool i) static inline nid_t get_nid(struct page *p, int off, bool i)
{ {
struct f2fs_node *rn = (struct f2fs_node *)page_address(p); struct f2fs_node *rn = F2FS_NODE(p);
if (i) if (i)
return le32_to_cpu(rn->i.i_nid[off - NODE_DIR1_BLOCK]); return le32_to_cpu(rn->i.i_nid[off - NODE_DIR1_BLOCK]);
return le32_to_cpu(rn->in.nid[off]); return le32_to_cpu(rn->in.nid[off]);
...@@ -314,8 +311,7 @@ static inline void clear_cold_data(struct page *page) ...@@ -314,8 +311,7 @@ static inline void clear_cold_data(struct page *page)
static inline int is_node(struct page *page, int type) static inline int is_node(struct page *page, int type)
{ {
void *kaddr = page_address(page); struct f2fs_node *rn = F2FS_NODE(page);
struct f2fs_node *rn = (struct f2fs_node *)kaddr;
return le32_to_cpu(rn->footer.flag) & (1 << type); return le32_to_cpu(rn->footer.flag) & (1 << type);
} }
...@@ -325,7 +321,7 @@ static inline int is_node(struct page *page, int type) ...@@ -325,7 +321,7 @@ static inline int is_node(struct page *page, int type)
static inline void set_cold_node(struct inode *inode, struct page *page) static inline void set_cold_node(struct inode *inode, struct page *page)
{ {
struct f2fs_node *rn = (struct f2fs_node *)page_address(page); struct f2fs_node *rn = F2FS_NODE(page);
unsigned int flag = le32_to_cpu(rn->footer.flag); unsigned int flag = le32_to_cpu(rn->footer.flag);
if (S_ISDIR(inode->i_mode)) if (S_ISDIR(inode->i_mode))
...@@ -337,7 +333,7 @@ static inline void set_cold_node(struct inode *inode, struct page *page) ...@@ -337,7 +333,7 @@ static inline void set_cold_node(struct inode *inode, struct page *page)
static inline void set_mark(struct page *page, int mark, int type) static inline void set_mark(struct page *page, int mark, int type)
{ {
struct f2fs_node *rn = (struct f2fs_node *)page_address(page); struct f2fs_node *rn = F2FS_NODE(page);
unsigned int flag = le32_to_cpu(rn->footer.flag); unsigned int flag = le32_to_cpu(rn->footer.flag);
if (mark) if (mark)
flag |= (0x1 << type); flag |= (0x1 << type);
......
...@@ -40,8 +40,7 @@ static struct fsync_inode_entry *get_fsync_inode(struct list_head *head, ...@@ -40,8 +40,7 @@ static struct fsync_inode_entry *get_fsync_inode(struct list_head *head,
static int recover_dentry(struct page *ipage, struct inode *inode) static int recover_dentry(struct page *ipage, struct inode *inode)
{ {
void *kaddr = page_address(ipage); struct f2fs_node *raw_node = F2FS_NODE(ipage);
struct f2fs_node *raw_node = (struct f2fs_node *)kaddr;
struct f2fs_inode *raw_inode = &(raw_node->i); struct f2fs_inode *raw_inode = &(raw_node->i);
nid_t pino = le32_to_cpu(raw_inode->i_pino); nid_t pino = le32_to_cpu(raw_inode->i_pino);
struct f2fs_dir_entry *de; struct f2fs_dir_entry *de;
...@@ -93,8 +92,7 @@ static int recover_dentry(struct page *ipage, struct inode *inode) ...@@ -93,8 +92,7 @@ static int recover_dentry(struct page *ipage, struct inode *inode)
static int recover_inode(struct inode *inode, struct page *node_page) static int recover_inode(struct inode *inode, struct page *node_page)
{ {
void *kaddr = page_address(node_page); struct f2fs_node *raw_node = F2FS_NODE(node_page);
struct f2fs_node *raw_node = (struct f2fs_node *)kaddr;
struct f2fs_inode *raw_inode = &(raw_node->i); struct f2fs_inode *raw_inode = &(raw_node->i);
if (!IS_INODE(node_page)) if (!IS_INODE(node_page))
...@@ -119,7 +117,7 @@ static int recover_inode(struct inode *inode, struct page *node_page) ...@@ -119,7 +117,7 @@ static int recover_inode(struct inode *inode, struct page *node_page)
static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head) static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head)
{ {
unsigned long long cp_ver = le64_to_cpu(sbi->ckpt->checkpoint_ver); unsigned long long cp_ver = cur_cp_version(F2FS_CKPT(sbi));
struct curseg_info *curseg; struct curseg_info *curseg;
struct page *page; struct page *page;
block_t blkaddr; block_t blkaddr;
...@@ -131,8 +129,8 @@ static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head) ...@@ -131,8 +129,8 @@ static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head)
/* read node page */ /* read node page */
page = alloc_page(GFP_F2FS_ZERO); page = alloc_page(GFP_F2FS_ZERO);
if (IS_ERR(page)) if (!page)
return PTR_ERR(page); return -ENOMEM;
lock_page(page); lock_page(page);
while (1) { while (1) {
...@@ -215,6 +213,7 @@ static int check_index_in_prev_nodes(struct f2fs_sb_info *sbi, ...@@ -215,6 +213,7 @@ static int check_index_in_prev_nodes(struct f2fs_sb_info *sbi,
void *kaddr; void *kaddr;
struct inode *inode; struct inode *inode;
struct page *node_page; struct page *node_page;
unsigned int offset;
block_t bidx; block_t bidx;
int i; int i;
...@@ -259,8 +258,8 @@ static int check_index_in_prev_nodes(struct f2fs_sb_info *sbi, ...@@ -259,8 +258,8 @@ static int check_index_in_prev_nodes(struct f2fs_sb_info *sbi,
node_page = get_node_page(sbi, nid); node_page = get_node_page(sbi, nid);
if (IS_ERR(node_page)) if (IS_ERR(node_page))
return PTR_ERR(node_page); return PTR_ERR(node_page);
bidx = start_bidx_of_node(ofs_of_node(node_page)) +
le16_to_cpu(sum.ofs_in_node); offset = ofs_of_node(node_page);
ino = ino_of_node(node_page); ino = ino_of_node(node_page);
f2fs_put_page(node_page, 1); f2fs_put_page(node_page, 1);
...@@ -269,6 +268,9 @@ static int check_index_in_prev_nodes(struct f2fs_sb_info *sbi, ...@@ -269,6 +268,9 @@ static int check_index_in_prev_nodes(struct f2fs_sb_info *sbi,
if (IS_ERR(inode)) if (IS_ERR(inode))
return PTR_ERR(inode); return PTR_ERR(inode);
bidx = start_bidx_of_node(offset, F2FS_I(inode)) +
le16_to_cpu(sum.ofs_in_node);
truncate_hole(inode, bidx, bidx + 1); truncate_hole(inode, bidx, bidx + 1);
iput(inode); iput(inode);
return 0; return 0;
...@@ -277,6 +279,7 @@ static int check_index_in_prev_nodes(struct f2fs_sb_info *sbi, ...@@ -277,6 +279,7 @@ static int check_index_in_prev_nodes(struct f2fs_sb_info *sbi,
static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode, static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode,
struct page *page, block_t blkaddr) struct page *page, block_t blkaddr)
{ {
struct f2fs_inode_info *fi = F2FS_I(inode);
unsigned int start, end; unsigned int start, end;
struct dnode_of_data dn; struct dnode_of_data dn;
struct f2fs_summary sum; struct f2fs_summary sum;
...@@ -284,9 +287,9 @@ static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode, ...@@ -284,9 +287,9 @@ static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode,
int err = 0, recovered = 0; int err = 0, recovered = 0;
int ilock; int ilock;
start = start_bidx_of_node(ofs_of_node(page)); start = start_bidx_of_node(ofs_of_node(page), fi);
if (IS_INODE(page)) if (IS_INODE(page))
end = start + ADDRS_PER_INODE; end = start + ADDRS_PER_INODE(fi);
else else
end = start + ADDRS_PER_BLOCK; end = start + ADDRS_PER_BLOCK;
...@@ -357,7 +360,7 @@ static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode, ...@@ -357,7 +360,7 @@ static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode,
static int recover_data(struct f2fs_sb_info *sbi, static int recover_data(struct f2fs_sb_info *sbi,
struct list_head *head, int type) struct list_head *head, int type)
{ {
unsigned long long cp_ver = le64_to_cpu(sbi->ckpt->checkpoint_ver); unsigned long long cp_ver = cur_cp_version(F2FS_CKPT(sbi));
struct curseg_info *curseg; struct curseg_info *curseg;
struct page *page; struct page *page;
int err = 0; int err = 0;
...@@ -369,7 +372,7 @@ static int recover_data(struct f2fs_sb_info *sbi, ...@@ -369,7 +372,7 @@ static int recover_data(struct f2fs_sb_info *sbi,
/* read node page */ /* read node page */
page = alloc_page(GFP_NOFS | __GFP_ZERO); page = alloc_page(GFP_NOFS | __GFP_ZERO);
if (IS_ERR(page)) if (!page)
return -ENOMEM; return -ENOMEM;
lock_page(page); lock_page(page);
......
...@@ -117,7 +117,6 @@ static void locate_dirty_segment(struct f2fs_sb_info *sbi, unsigned int segno) ...@@ -117,7 +117,6 @@ static void locate_dirty_segment(struct f2fs_sb_info *sbi, unsigned int segno)
} }
mutex_unlock(&dirty_i->seglist_lock); mutex_unlock(&dirty_i->seglist_lock);
return;
} }
/* /*
...@@ -261,7 +260,6 @@ static void __add_sum_entry(struct f2fs_sb_info *sbi, int type, ...@@ -261,7 +260,6 @@ static void __add_sum_entry(struct f2fs_sb_info *sbi, int type,
void *addr = curseg->sum_blk; void *addr = curseg->sum_blk;
addr += curseg->next_blkoff * sizeof(struct f2fs_summary); addr += curseg->next_blkoff * sizeof(struct f2fs_summary);
memcpy(addr, sum, sizeof(struct f2fs_summary)); memcpy(addr, sum, sizeof(struct f2fs_summary));
return;
} }
/* /*
...@@ -542,12 +540,9 @@ static void allocate_segment_by_default(struct f2fs_sb_info *sbi, ...@@ -542,12 +540,9 @@ static void allocate_segment_by_default(struct f2fs_sb_info *sbi,
{ {
struct curseg_info *curseg = CURSEG_I(sbi, type); struct curseg_info *curseg = CURSEG_I(sbi, type);
if (force) { if (force)
new_curseg(sbi, type, true); new_curseg(sbi, type, true);
goto out; else if (type == CURSEG_WARM_NODE)
}
if (type == CURSEG_WARM_NODE)
new_curseg(sbi, type, false); new_curseg(sbi, type, false);
else if (curseg->alloc_type == LFS && is_next_segment_free(sbi, type)) else if (curseg->alloc_type == LFS && is_next_segment_free(sbi, type))
new_curseg(sbi, type, false); new_curseg(sbi, type, false);
...@@ -555,11 +550,9 @@ static void allocate_segment_by_default(struct f2fs_sb_info *sbi, ...@@ -555,11 +550,9 @@ 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);
out:
#ifdef CONFIG_F2FS_STAT_FS #ifdef CONFIG_F2FS_STAT_FS
sbi->segment_count[curseg->alloc_type]++; sbi->segment_count[curseg->alloc_type]++;
#endif #endif
return;
} }
void allocate_new_segments(struct f2fs_sb_info *sbi) void allocate_new_segments(struct f2fs_sb_info *sbi)
...@@ -611,18 +604,12 @@ static void f2fs_end_io_write(struct bio *bio, int err) ...@@ -611,18 +604,12 @@ static void f2fs_end_io_write(struct bio *bio, int err)
struct bio *f2fs_bio_alloc(struct block_device *bdev, int npages) struct bio *f2fs_bio_alloc(struct block_device *bdev, int npages)
{ {
struct bio *bio; struct bio *bio;
struct bio_private *priv;
retry:
priv = kmalloc(sizeof(struct bio_private), GFP_NOFS);
if (!priv) {
cond_resched();
goto retry;
}
/* No failure on bio allocation */ /* No failure on bio allocation */
bio = bio_alloc(GFP_NOIO, npages); bio = bio_alloc(GFP_NOIO, npages);
bio->bi_bdev = bdev; bio->bi_bdev = bdev;
bio->bi_private = priv; bio->bi_private = NULL;
return bio; return bio;
} }
...@@ -681,8 +668,17 @@ static void submit_write_page(struct f2fs_sb_info *sbi, struct page *page, ...@@ -681,8 +668,17 @@ static void submit_write_page(struct f2fs_sb_info *sbi, struct page *page,
do_submit_bio(sbi, type, false); do_submit_bio(sbi, type, false);
alloc_new: alloc_new:
if (sbi->bio[type] == NULL) { if (sbi->bio[type] == NULL) {
struct bio_private *priv;
retry:
priv = kmalloc(sizeof(struct bio_private), GFP_NOFS);
if (!priv) {
cond_resched();
goto retry;
}
sbi->bio[type] = f2fs_bio_alloc(bdev, max_hw_blocks(sbi)); sbi->bio[type] = f2fs_bio_alloc(bdev, max_hw_blocks(sbi));
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;
/* /*
* The end_io will be assigned at the sumbission phase. * The end_io will be assigned at the sumbission phase.
* Until then, let bio_add_page() merge consecutive IOs as much * Until then, let bio_add_page() merge consecutive IOs as much
...@@ -702,6 +698,16 @@ static void submit_write_page(struct f2fs_sb_info *sbi, struct page *page, ...@@ -702,6 +698,16 @@ static void submit_write_page(struct f2fs_sb_info *sbi, struct page *page,
trace_f2fs_submit_write_page(page, blk_addr, type); trace_f2fs_submit_write_page(page, blk_addr, type);
} }
void f2fs_wait_on_page_writeback(struct page *page,
enum page_type type, bool sync)
{
struct f2fs_sb_info *sbi = F2FS_SB(page->mapping->host->i_sb);
if (PageWriteback(page)) {
f2fs_submit_bio(sbi, type, sync);
wait_on_page_writeback(page);
}
}
static bool __has_curseg_space(struct f2fs_sb_info *sbi, int type) static bool __has_curseg_space(struct f2fs_sb_info *sbi, int type)
{ {
struct curseg_info *curseg = CURSEG_I(sbi, type); struct curseg_info *curseg = CURSEG_I(sbi, type);
...@@ -1179,7 +1185,6 @@ void write_node_summaries(struct f2fs_sb_info *sbi, block_t start_blk) ...@@ -1179,7 +1185,6 @@ void write_node_summaries(struct f2fs_sb_info *sbi, block_t start_blk)
{ {
if (is_set_ckpt_flags(F2FS_CKPT(sbi), CP_UMOUNT_FLAG)) if (is_set_ckpt_flags(F2FS_CKPT(sbi), CP_UMOUNT_FLAG))
write_normal_summaries(sbi, start_blk, CURSEG_HOT_NODE); write_normal_summaries(sbi, start_blk, CURSEG_HOT_NODE);
return;
} }
int lookup_journal_in_cursum(struct f2fs_summary_block *sum, int type, int lookup_journal_in_cursum(struct f2fs_summary_block *sum, int type,
......
...@@ -142,6 +142,7 @@ struct victim_sel_policy { ...@@ -142,6 +142,7 @@ struct victim_sel_policy {
int alloc_mode; /* LFS or SSR */ int alloc_mode; /* LFS or SSR */
int gc_mode; /* GC_CB or GC_GREEDY */ int gc_mode; /* GC_CB or GC_GREEDY */
unsigned long *dirty_segmap; /* dirty segment bitmap */ unsigned long *dirty_segmap; /* dirty segment bitmap */
unsigned int max_search; /* maximum # of segments to search */
unsigned int offset; /* last scanned bitmap offset */ unsigned int offset; /* last scanned bitmap offset */
unsigned int ofs_unit; /* bitmap search unit */ unsigned int ofs_unit; /* bitmap search unit */
unsigned int min_cost; /* minimum cost */ unsigned int min_cost; /* minimum cost */
...@@ -453,7 +454,8 @@ static inline int reserved_sections(struct f2fs_sb_info *sbi) ...@@ -453,7 +454,8 @@ static inline int reserved_sections(struct f2fs_sb_info *sbi)
static inline bool need_SSR(struct f2fs_sb_info *sbi) static inline bool need_SSR(struct f2fs_sb_info *sbi)
{ {
return (free_sections(sbi) < overprovision_sections(sbi)); return ((prefree_segments(sbi) / sbi->segs_per_sec)
+ free_sections(sbi) < overprovision_sections(sbi));
} }
static inline bool has_not_enough_free_secs(struct f2fs_sb_info *sbi, int freed) static inline bool has_not_enough_free_secs(struct f2fs_sb_info *sbi, int freed)
...@@ -470,7 +472,7 @@ static inline bool has_not_enough_free_secs(struct f2fs_sb_info *sbi, int freed) ...@@ -470,7 +472,7 @@ static inline bool has_not_enough_free_secs(struct f2fs_sb_info *sbi, int freed)
static inline int utilization(struct f2fs_sb_info *sbi) static inline int utilization(struct f2fs_sb_info *sbi)
{ {
return div_u64(valid_user_blocks(sbi) * 100, sbi->user_block_count); return div_u64((u64)valid_user_blocks(sbi) * 100, sbi->user_block_count);
} }
/* /*
......
...@@ -18,20 +18,25 @@ ...@@ -18,20 +18,25 @@
#include <linux/parser.h> #include <linux/parser.h>
#include <linux/mount.h> #include <linux/mount.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/proc_fs.h>
#include <linux/random.h> #include <linux/random.h>
#include <linux/exportfs.h> #include <linux/exportfs.h>
#include <linux/blkdev.h> #include <linux/blkdev.h>
#include <linux/f2fs_fs.h> #include <linux/f2fs_fs.h>
#include <linux/sysfs.h>
#include "f2fs.h" #include "f2fs.h"
#include "node.h" #include "node.h"
#include "segment.h" #include "segment.h"
#include "xattr.h" #include "xattr.h"
#include "gc.h"
#define CREATE_TRACE_POINTS #define CREATE_TRACE_POINTS
#include <trace/events/f2fs.h> #include <trace/events/f2fs.h>
static struct proc_dir_entry *f2fs_proc_root;
static struct kmem_cache *f2fs_inode_cachep; static struct kmem_cache *f2fs_inode_cachep;
static struct kset *f2fs_kset;
enum { enum {
Opt_gc_background, Opt_gc_background,
...@@ -42,6 +47,7 @@ enum { ...@@ -42,6 +47,7 @@ enum {
Opt_noacl, Opt_noacl,
Opt_active_logs, Opt_active_logs,
Opt_disable_ext_identify, Opt_disable_ext_identify,
Opt_inline_xattr,
Opt_err, Opt_err,
}; };
...@@ -54,9 +60,117 @@ static match_table_t f2fs_tokens = { ...@@ -54,9 +60,117 @@ static match_table_t f2fs_tokens = {
{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"},
{Opt_inline_xattr, "inline_xattr"},
{Opt_err, NULL}, {Opt_err, NULL},
}; };
/* Sysfs support for f2fs */
struct f2fs_attr {
struct attribute attr;
ssize_t (*show)(struct f2fs_attr *, struct f2fs_sb_info *, char *);
ssize_t (*store)(struct f2fs_attr *, struct f2fs_sb_info *,
const char *, size_t);
int offset;
};
static ssize_t f2fs_sbi_show(struct f2fs_attr *a,
struct f2fs_sb_info *sbi, char *buf)
{
struct f2fs_gc_kthread *gc_kth = sbi->gc_thread;
unsigned int *ui;
if (!gc_kth)
return -EINVAL;
ui = (unsigned int *)(((char *)gc_kth) + a->offset);
return snprintf(buf, PAGE_SIZE, "%u\n", *ui);
}
static ssize_t f2fs_sbi_store(struct f2fs_attr *a,
struct f2fs_sb_info *sbi,
const char *buf, size_t count)
{
struct f2fs_gc_kthread *gc_kth = sbi->gc_thread;
unsigned long t;
unsigned int *ui;
ssize_t ret;
if (!gc_kth)
return -EINVAL;
ui = (unsigned int *)(((char *)gc_kth) + a->offset);
ret = kstrtoul(skip_spaces(buf), 0, &t);
if (ret < 0)
return ret;
*ui = t;
return count;
}
static ssize_t f2fs_attr_show(struct kobject *kobj,
struct attribute *attr, char *buf)
{
struct f2fs_sb_info *sbi = container_of(kobj, struct f2fs_sb_info,
s_kobj);
struct f2fs_attr *a = container_of(attr, struct f2fs_attr, attr);
return a->show ? a->show(a, sbi, buf) : 0;
}
static ssize_t f2fs_attr_store(struct kobject *kobj, struct attribute *attr,
const char *buf, size_t len)
{
struct f2fs_sb_info *sbi = container_of(kobj, struct f2fs_sb_info,
s_kobj);
struct f2fs_attr *a = container_of(attr, struct f2fs_attr, attr);
return a->store ? a->store(a, sbi, buf, len) : 0;
}
static void f2fs_sb_release(struct kobject *kobj)
{
struct f2fs_sb_info *sbi = container_of(kobj, struct f2fs_sb_info,
s_kobj);
complete(&sbi->s_kobj_unregister);
}
#define F2FS_ATTR_OFFSET(_name, _mode, _show, _store, _elname) \
static struct f2fs_attr f2fs_attr_##_name = { \
.attr = {.name = __stringify(_name), .mode = _mode }, \
.show = _show, \
.store = _store, \
.offset = offsetof(struct f2fs_gc_kthread, _elname), \
}
#define F2FS_RW_ATTR(name, elname) \
F2FS_ATTR_OFFSET(name, 0644, f2fs_sbi_show, f2fs_sbi_store, elname)
F2FS_RW_ATTR(gc_min_sleep_time, min_sleep_time);
F2FS_RW_ATTR(gc_max_sleep_time, max_sleep_time);
F2FS_RW_ATTR(gc_no_gc_sleep_time, no_gc_sleep_time);
F2FS_RW_ATTR(gc_idle, gc_idle);
#define ATTR_LIST(name) (&f2fs_attr_##name.attr)
static struct attribute *f2fs_attrs[] = {
ATTR_LIST(gc_min_sleep_time),
ATTR_LIST(gc_max_sleep_time),
ATTR_LIST(gc_no_gc_sleep_time),
ATTR_LIST(gc_idle),
NULL,
};
static const struct sysfs_ops f2fs_attr_ops = {
.show = f2fs_attr_show,
.store = f2fs_attr_store,
};
static struct kobj_type f2fs_ktype = {
.default_attrs = f2fs_attrs,
.sysfs_ops = &f2fs_attr_ops,
.release = f2fs_sb_release,
};
void f2fs_msg(struct super_block *sb, const char *level, const char *fmt, ...) void f2fs_msg(struct super_block *sb, const char *level, const char *fmt, ...)
{ {
struct va_format vaf; struct va_format vaf;
...@@ -126,11 +240,18 @@ static int parse_options(struct super_block *sb, char *options) ...@@ -126,11 +240,18 @@ static int parse_options(struct super_block *sb, char *options)
case Opt_nouser_xattr: case Opt_nouser_xattr:
clear_opt(sbi, XATTR_USER); clear_opt(sbi, XATTR_USER);
break; break;
case Opt_inline_xattr:
set_opt(sbi, INLINE_XATTR);
break;
#else #else
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");
break; break;
case Opt_inline_xattr:
f2fs_msg(sb, KERN_INFO,
"inline_xattr options not supported");
break;
#endif #endif
#ifdef CONFIG_F2FS_FS_POSIX_ACL #ifdef CONFIG_F2FS_FS_POSIX_ACL
case Opt_noacl: case Opt_noacl:
...@@ -180,6 +301,9 @@ static struct inode *f2fs_alloc_inode(struct super_block *sb) ...@@ -180,6 +301,9 @@ static struct inode *f2fs_alloc_inode(struct super_block *sb)
set_inode_flag(fi, FI_NEW_INODE); set_inode_flag(fi, FI_NEW_INODE);
if (test_opt(F2FS_SB(sb), INLINE_XATTR))
set_inode_flag(fi, FI_INLINE_XATTR);
return &fi->vfs_inode; return &fi->vfs_inode;
} }
...@@ -205,7 +329,6 @@ static int f2fs_drop_inode(struct inode *inode) ...@@ -205,7 +329,6 @@ static int f2fs_drop_inode(struct inode *inode)
static void f2fs_dirty_inode(struct inode *inode, int flags) static void f2fs_dirty_inode(struct inode *inode, int flags)
{ {
set_inode_flag(F2FS_I(inode), FI_DIRTY_INODE); set_inode_flag(F2FS_I(inode), FI_DIRTY_INODE);
return;
} }
static void f2fs_i_callback(struct rcu_head *head) static void f2fs_i_callback(struct rcu_head *head)
...@@ -223,6 +346,12 @@ static void f2fs_put_super(struct super_block *sb) ...@@ -223,6 +346,12 @@ static void f2fs_put_super(struct super_block *sb)
{ {
struct f2fs_sb_info *sbi = F2FS_SB(sb); struct f2fs_sb_info *sbi = F2FS_SB(sb);
if (sbi->s_proc) {
remove_proc_entry("segment_info", sbi->s_proc);
remove_proc_entry(sb->s_id, f2fs_proc_root);
}
kobject_del(&sbi->s_kobj);
f2fs_destroy_stats(sbi); f2fs_destroy_stats(sbi);
stop_gc_thread(sbi); stop_gc_thread(sbi);
...@@ -236,6 +365,8 @@ static void f2fs_put_super(struct super_block *sb) ...@@ -236,6 +365,8 @@ static void f2fs_put_super(struct super_block *sb)
destroy_segment_manager(sbi); destroy_segment_manager(sbi);
kfree(sbi->ckpt); kfree(sbi->ckpt);
kobject_put(&sbi->s_kobj);
wait_for_completion(&sbi->s_kobj_unregister);
sb->s_fs_info = NULL; sb->s_fs_info = NULL;
brelse(sbi->raw_super_buf); brelse(sbi->raw_super_buf);
...@@ -325,6 +456,8 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root) ...@@ -325,6 +456,8 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root)
seq_puts(seq, ",user_xattr"); seq_puts(seq, ",user_xattr");
else else
seq_puts(seq, ",nouser_xattr"); seq_puts(seq, ",nouser_xattr");
if (test_opt(sbi, INLINE_XATTR))
seq_puts(seq, ",inline_xattr");
#endif #endif
#ifdef CONFIG_F2FS_FS_POSIX_ACL #ifdef CONFIG_F2FS_FS_POSIX_ACL
if (test_opt(sbi, POSIX_ACL)) if (test_opt(sbi, POSIX_ACL))
...@@ -340,6 +473,36 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root) ...@@ -340,6 +473,36 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root)
return 0; return 0;
} }
static int segment_info_seq_show(struct seq_file *seq, void *offset)
{
struct super_block *sb = seq->private;
struct f2fs_sb_info *sbi = F2FS_SB(sb);
unsigned int total_segs = le32_to_cpu(sbi->raw_super->segment_count_main);
int i;
for (i = 0; i < total_segs; i++) {
seq_printf(seq, "%u", get_valid_blocks(sbi, i, 1));
if (i != 0 && (i % 10) == 0)
seq_puts(seq, "\n");
else
seq_puts(seq, " ");
}
return 0;
}
static int segment_info_open_fs(struct inode *inode, struct file *file)
{
return single_open(file, segment_info_seq_show, PDE_DATA(inode));
}
static const struct file_operations f2fs_seq_segment_info_fops = {
.owner = THIS_MODULE,
.open = segment_info_open_fs,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
static int f2fs_remount(struct super_block *sb, int *flags, char *data) static int f2fs_remount(struct super_block *sb, int *flags, char *data)
{ {
struct f2fs_sb_info *sbi = F2FS_SB(sb); struct f2fs_sb_info *sbi = F2FS_SB(sb);
...@@ -455,7 +618,7 @@ static const struct export_operations f2fs_export_ops = { ...@@ -455,7 +618,7 @@ static const struct export_operations f2fs_export_ops = {
static loff_t max_file_size(unsigned bits) static loff_t max_file_size(unsigned bits)
{ {
loff_t result = ADDRS_PER_INODE; loff_t result = (DEF_ADDRS_PER_INODE - F2FS_INLINE_XATTR_ADDRS);
loff_t leaf_count = ADDRS_PER_BLOCK; loff_t leaf_count = ADDRS_PER_BLOCK;
/* two direct node blocks */ /* two direct node blocks */
...@@ -766,6 +929,13 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) ...@@ -766,6 +929,13 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
if (err) if (err)
goto fail; goto fail;
if (f2fs_proc_root)
sbi->s_proc = proc_mkdir(sb->s_id, f2fs_proc_root);
if (sbi->s_proc)
proc_create_data("segment_info", S_IRUGO, sbi->s_proc,
&f2fs_seq_segment_info_fops, sb);
if (test_opt(sbi, DISCARD)) { if (test_opt(sbi, DISCARD)) {
struct request_queue *q = bdev_get_queue(sb->s_bdev); struct request_queue *q = bdev_get_queue(sb->s_bdev);
if (!blk_queue_discard(q)) if (!blk_queue_discard(q))
...@@ -774,6 +944,13 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) ...@@ -774,6 +944,13 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
"the device does not support discard"); "the device does not support discard");
} }
sbi->s_kobj.kset = f2fs_kset;
init_completion(&sbi->s_kobj_unregister);
err = kobject_init_and_add(&sbi->s_kobj, &f2fs_ktype, NULL,
"%s", sb->s_id);
if (err)
goto fail;
return 0; return 0;
fail: fail:
stop_gc_thread(sbi); stop_gc_thread(sbi);
...@@ -841,29 +1018,49 @@ static int __init init_f2fs_fs(void) ...@@ -841,29 +1018,49 @@ static int __init init_f2fs_fs(void)
goto fail; goto fail;
err = create_node_manager_caches(); err = create_node_manager_caches();
if (err) if (err)
goto fail; goto free_inodecache;
err = create_gc_caches(); err = create_gc_caches();
if (err) if (err)
goto fail; goto free_node_manager_caches;
err = create_checkpoint_caches(); err = create_checkpoint_caches();
if (err) if (err)
goto fail; goto free_gc_caches;
f2fs_kset = kset_create_and_add("f2fs", NULL, fs_kobj);
if (!f2fs_kset) {
err = -ENOMEM;
goto free_checkpoint_caches;
}
err = register_filesystem(&f2fs_fs_type); err = register_filesystem(&f2fs_fs_type);
if (err) if (err)
goto fail; goto free_kset;
f2fs_create_root_stats(); f2fs_create_root_stats();
f2fs_proc_root = proc_mkdir("fs/f2fs", NULL);
return 0;
free_kset:
kset_unregister(f2fs_kset);
free_checkpoint_caches:
destroy_checkpoint_caches();
free_gc_caches:
destroy_gc_caches();
free_node_manager_caches:
destroy_node_manager_caches();
free_inodecache:
destroy_inodecache();
fail: fail:
return err; return err;
} }
static void __exit exit_f2fs_fs(void) static void __exit exit_f2fs_fs(void)
{ {
remove_proc_entry("fs/f2fs", NULL);
f2fs_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();
destroy_node_manager_caches(); destroy_node_manager_caches();
destroy_inodecache(); destroy_inodecache();
kset_unregister(f2fs_kset);
} }
module_init(init_f2fs_fs) module_init(init_f2fs_fs)
......
This diff is collapsed.
...@@ -51,7 +51,7 @@ struct f2fs_xattr_entry { ...@@ -51,7 +51,7 @@ struct f2fs_xattr_entry {
#define XATTR_HDR(ptr) ((struct f2fs_xattr_header *)(ptr)) #define XATTR_HDR(ptr) ((struct f2fs_xattr_header *)(ptr))
#define XATTR_ENTRY(ptr) ((struct f2fs_xattr_entry *)(ptr)) #define XATTR_ENTRY(ptr) ((struct f2fs_xattr_entry *)(ptr))
#define XATTR_FIRST_ENTRY(ptr) (XATTR_ENTRY(XATTR_HDR(ptr)+1)) #define XATTR_FIRST_ENTRY(ptr) (XATTR_ENTRY(XATTR_HDR(ptr) + 1))
#define XATTR_ROUND (3) #define XATTR_ROUND (3)
#define XATTR_ALIGN(size) ((size + XATTR_ROUND) & ~XATTR_ROUND) #define XATTR_ALIGN(size) ((size + XATTR_ROUND) & ~XATTR_ROUND)
...@@ -69,17 +69,16 @@ struct f2fs_xattr_entry { ...@@ -69,17 +69,16 @@ struct f2fs_xattr_entry {
!IS_XATTR_LAST_ENTRY(entry);\ !IS_XATTR_LAST_ENTRY(entry);\
entry = XATTR_NEXT_ENTRY(entry)) entry = XATTR_NEXT_ENTRY(entry))
#define MIN_OFFSET(i) XATTR_ALIGN(inline_xattr_size(i) + PAGE_SIZE - \
sizeof(struct node_footer) - sizeof(__u32))
#define MIN_OFFSET XATTR_ALIGN(PAGE_SIZE - \ #define MAX_VALUE_LEN(i) (MIN_OFFSET(i) - \
sizeof(struct node_footer) - \ sizeof(struct f2fs_xattr_header) - \
sizeof(__u32)) sizeof(struct f2fs_xattr_entry))
#define MAX_VALUE_LEN (MIN_OFFSET - sizeof(struct f2fs_xattr_header) - \
sizeof(struct f2fs_xattr_entry))
/* /*
* On-disk structure of f2fs_xattr * On-disk structure of f2fs_xattr
* We use only 1 block for xattr. * We use inline xattrs space + 1 block for xattr.
* *
* +--------------------+ * +--------------------+
* | f2fs_xattr_header | * | f2fs_xattr_header |
......
...@@ -140,14 +140,24 @@ struct f2fs_extent { ...@@ -140,14 +140,24 @@ struct f2fs_extent {
} __packed; } __packed;
#define F2FS_NAME_LEN 255 #define F2FS_NAME_LEN 255
#define ADDRS_PER_INODE 923 /* Address Pointers in an Inode */ #define F2FS_INLINE_XATTR_ADDRS 50 /* 200 bytes for inline xattrs */
#define ADDRS_PER_BLOCK 1018 /* Address Pointers in a Direct Block */ #define DEF_ADDRS_PER_INODE 923 /* Address Pointers in an Inode */
#define NIDS_PER_BLOCK 1018 /* Node IDs in an Indirect Block */ #define ADDRS_PER_INODE(fi) addrs_per_inode(fi)
#define ADDRS_PER_BLOCK 1018 /* Address Pointers in a Direct Block */
#define NIDS_PER_BLOCK 1018 /* Node IDs in an Indirect Block */
#define NODE_DIR1_BLOCK (DEF_ADDRS_PER_INODE + 1)
#define NODE_DIR2_BLOCK (DEF_ADDRS_PER_INODE + 2)
#define NODE_IND1_BLOCK (DEF_ADDRS_PER_INODE + 3)
#define NODE_IND2_BLOCK (DEF_ADDRS_PER_INODE + 4)
#define NODE_DIND_BLOCK (DEF_ADDRS_PER_INODE + 5)
#define F2FS_INLINE_XATTR 0x01 /* file inline xattr flag */
struct f2fs_inode { struct f2fs_inode {
__le16 i_mode; /* file mode */ __le16 i_mode; /* file mode */
__u8 i_advise; /* file hints */ __u8 i_advise; /* file hints */
__u8 i_reserved; /* reserved */ __u8 i_inline; /* file inline flags */
__le32 i_uid; /* user ID */ __le32 i_uid; /* user ID */
__le32 i_gid; /* group ID */ __le32 i_gid; /* group ID */
__le32 i_links; /* links count */ __le32 i_links; /* links count */
...@@ -170,7 +180,7 @@ struct f2fs_inode { ...@@ -170,7 +180,7 @@ struct f2fs_inode {
struct f2fs_extent i_ext; /* caching a largest extent */ struct f2fs_extent i_ext; /* caching a largest extent */
__le32 i_addr[ADDRS_PER_INODE]; /* Pointers to data blocks */ __le32 i_addr[DEF_ADDRS_PER_INODE]; /* Pointers to data blocks */
__le32 i_nid[5]; /* direct(2), indirect(2), __le32 i_nid[5]; /* direct(2), indirect(2),
double_indirect(1) node id */ double_indirect(1) node id */
......
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