Commit 64b2d1fb authored by Linus Torvalds's avatar Linus Torvalds

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

Pull f2fs updates from Jaegeuk Kim:
 "In this round, there is no special interesting feature, but we've
  investigated a couple of tuning points with respect to the I/O flow.
  Several major bug fixes and a bunch of clean-ups also have been made.

  This patch-set includes the following major enhancement patches:
   - enhance wait_on_page_writeback
   - support SEEK_DATA and SEEK_HOLE
   - enhance readahead flows
   - enhance IO flushes
   - support fiemap
   - add some tracepoints

  The other bug fixes are as follows:
   - fix to support a large volume > 2TB correctly
   - recovery bug fix wrt fallocated space
   - fix recursive lock on xattr operations
   - fix some cases on the remount flow

  And, there are a bunch of cleanups"

* tag 'for-f2fs-3.16' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs: (52 commits)
  f2fs: support f2fs_fiemap
  f2fs: avoid not to call remove_dirty_inode
  f2fs: recover fallocated space
  f2fs: fix to recover data written by dio
  f2fs: large volume support
  f2fs: avoid crash when trace f2fs_submit_page_mbio event in ra_sum_pages
  f2fs: avoid overflow when large directory feathure is enabled
  f2fs: fix recursive lock by f2fs_setxattr
  MAINTAINERS: add a co-maintainer from samsung for F2FS
  MAINTAINERS: change the email address for f2fs
  f2fs: use inode_init_owner() to simplify codes
  f2fs: avoid to use slab memory in f2fs_issue_flush for efficiency
  f2fs: add a tracepoint for f2fs_read_data_page
  f2fs: add a tracepoint for f2fs_write_{meta,node,data}_pages
  f2fs: add a tracepoint for f2fs_write_{meta,node,data}_page
  f2fs: add a tracepoint for f2fs_write_end
  f2fs: add a tracepoint for f2fs_write_begin
  f2fs: fix checkpatch warning
  f2fs: deactivate inode page if the inode is evicted
  f2fs: decrease the lock granularity during write_begin
  ...
parents b1cce803 9ab70134
...@@ -461,10 +461,10 @@ The number of blocks and buckets are determined by, ...@@ -461,10 +461,10 @@ The number of blocks and buckets are determined by,
# of blocks in level #n = | # of blocks in level #n = |
`- 4, Otherwise `- 4, Otherwise
,- 2^ (n + dir_level), ,- 2^(n + dir_level),
| if n < MAX_DIR_HASH_DEPTH / 2, | if n + dir_level < MAX_DIR_HASH_DEPTH / 2,
# of buckets in level #n = | # of buckets in level #n = |
`- 2^((MAX_DIR_HASH_DEPTH / 2 + dir_level) - 1), `- 2^((MAX_DIR_HASH_DEPTH / 2) - 1),
Otherwise Otherwise
When F2FS finds a file name in a directory, at first a hash value of the file When F2FS finds a file name in a directory, at first a hash value of the file
......
...@@ -3792,7 +3792,8 @@ F: fs/fscache/ ...@@ -3792,7 +3792,8 @@ F: fs/fscache/
F: include/linux/fscache*.h F: include/linux/fscache*.h
F2FS FILE SYSTEM F2FS FILE SYSTEM
M: Jaegeuk Kim <jaegeuk.kim@samsung.com> M: Jaegeuk Kim <jaegeuk@kernel.org>
M: Changman Lee <cm224.lee@samsung.com>
L: linux-f2fs-devel@lists.sourceforge.net L: linux-f2fs-devel@lists.sourceforge.net
W: http://en.wikipedia.org/wiki/F2FS W: http://en.wikipedia.org/wiki/F2FS
T: git git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs.git T: git git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs.git
......
...@@ -240,7 +240,7 @@ static int __f2fs_set_acl(struct inode *inode, int type, ...@@ -240,7 +240,7 @@ static int __f2fs_set_acl(struct inode *inode, int type,
} }
} }
error = f2fs_setxattr(inode, name_index, "", value, size, ipage); error = f2fs_setxattr(inode, name_index, "", value, size, ipage, 0);
kfree(value); kfree(value);
if (!error) if (!error)
......
...@@ -33,12 +33,12 @@ struct page *grab_meta_page(struct f2fs_sb_info *sbi, pgoff_t index) ...@@ -33,12 +33,12 @@ struct page *grab_meta_page(struct f2fs_sb_info *sbi, pgoff_t index)
struct address_space *mapping = META_MAPPING(sbi); struct address_space *mapping = META_MAPPING(sbi);
struct page *page = NULL; struct page *page = NULL;
repeat: repeat:
page = grab_cache_page_write_begin(mapping, index, AOP_FLAG_NOFS); page = grab_cache_page(mapping, index);
if (!page) { if (!page) {
cond_resched(); cond_resched();
goto repeat; goto repeat;
} }
f2fs_wait_on_page_writeback(page, META);
SetPageUptodate(page); SetPageUptodate(page);
return page; return page;
} }
...@@ -72,7 +72,7 @@ struct page *get_meta_page(struct f2fs_sb_info *sbi, pgoff_t index) ...@@ -72,7 +72,7 @@ struct page *get_meta_page(struct f2fs_sb_info *sbi, pgoff_t index)
return page; return page;
} }
inline int get_max_meta_blks(struct f2fs_sb_info *sbi, int type) static inline int get_max_meta_blks(struct f2fs_sb_info *sbi, int type)
{ {
switch (type) { switch (type) {
case META_NAT: case META_NAT:
...@@ -154,6 +154,8 @@ static int f2fs_write_meta_page(struct page *page, ...@@ -154,6 +154,8 @@ static int f2fs_write_meta_page(struct page *page,
struct inode *inode = page->mapping->host; struct inode *inode = page->mapping->host;
struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
trace_f2fs_writepage(page, META);
if (unlikely(sbi->por_doing)) if (unlikely(sbi->por_doing))
goto redirty_out; goto redirty_out;
if (wbc->for_reclaim) if (wbc->for_reclaim)
...@@ -171,10 +173,7 @@ static int f2fs_write_meta_page(struct page *page, ...@@ -171,10 +173,7 @@ static int f2fs_write_meta_page(struct page *page,
return 0; return 0;
redirty_out: redirty_out:
dec_page_count(sbi, F2FS_DIRTY_META); redirty_page_for_writepage(wbc, page);
wbc->pages_skipped++;
account_page_redirty(page);
set_page_dirty(page);
return AOP_WRITEPAGE_ACTIVATE; return AOP_WRITEPAGE_ACTIVATE;
} }
...@@ -184,6 +183,8 @@ static int f2fs_write_meta_pages(struct address_space *mapping, ...@@ -184,6 +183,8 @@ static int f2fs_write_meta_pages(struct address_space *mapping,
struct f2fs_sb_info *sbi = F2FS_SB(mapping->host->i_sb); struct f2fs_sb_info *sbi = F2FS_SB(mapping->host->i_sb);
long diff, written; long diff, written;
trace_f2fs_writepages(mapping->host, wbc, META);
/* collect a number of dirty meta pages and write together */ /* collect a number of dirty meta pages and write together */
if (wbc->for_kupdate || if (wbc->for_kupdate ||
get_pages(sbi, F2FS_DIRTY_META) < nr_pages_to_skip(sbi, META)) get_pages(sbi, F2FS_DIRTY_META) < nr_pages_to_skip(sbi, META))
...@@ -367,7 +368,9 @@ void recover_orphan_inodes(struct f2fs_sb_info *sbi) ...@@ -367,7 +368,9 @@ void recover_orphan_inodes(struct f2fs_sb_info *sbi)
return; return;
sbi->por_doing = true; sbi->por_doing = true;
start_blk = __start_cp_addr(sbi) + 1;
start_blk = __start_cp_addr(sbi) + 1 +
le32_to_cpu(F2FS_RAW_SUPER(sbi)->cp_payload);
orphan_blkaddr = __start_sum_addr(sbi) - 1; orphan_blkaddr = __start_sum_addr(sbi) - 1;
ra_meta_pages(sbi, start_blk, orphan_blkaddr, META_CP); ra_meta_pages(sbi, start_blk, orphan_blkaddr, META_CP);
...@@ -508,8 +511,11 @@ int get_valid_checkpoint(struct f2fs_sb_info *sbi) ...@@ -508,8 +511,11 @@ int get_valid_checkpoint(struct f2fs_sb_info *sbi)
unsigned long blk_size = sbi->blocksize; unsigned long blk_size = sbi->blocksize;
unsigned long long cp1_version = 0, cp2_version = 0; unsigned long long cp1_version = 0, cp2_version = 0;
unsigned long long cp_start_blk_no; unsigned long long cp_start_blk_no;
unsigned int cp_blks = 1 + le32_to_cpu(F2FS_RAW_SUPER(sbi)->cp_payload);
block_t cp_blk_no;
int i;
sbi->ckpt = kzalloc(blk_size, GFP_KERNEL); sbi->ckpt = kzalloc(cp_blks * blk_size, GFP_KERNEL);
if (!sbi->ckpt) if (!sbi->ckpt)
return -ENOMEM; return -ENOMEM;
/* /*
...@@ -540,6 +546,23 @@ int get_valid_checkpoint(struct f2fs_sb_info *sbi) ...@@ -540,6 +546,23 @@ int get_valid_checkpoint(struct f2fs_sb_info *sbi)
cp_block = (struct f2fs_checkpoint *)page_address(cur_page); cp_block = (struct f2fs_checkpoint *)page_address(cur_page);
memcpy(sbi->ckpt, cp_block, blk_size); memcpy(sbi->ckpt, cp_block, blk_size);
if (cp_blks <= 1)
goto done;
cp_blk_no = le32_to_cpu(fsb->cp_blkaddr);
if (cur_page == cp2)
cp_blk_no += 1 << le32_to_cpu(fsb->log_blocks_per_seg);
for (i = 1; i < cp_blks; i++) {
void *sit_bitmap_ptr;
unsigned char *ckpt = (unsigned char *)sbi->ckpt;
cur_page = get_meta_page(sbi, cp_blk_no + i);
sit_bitmap_ptr = page_address(cur_page);
memcpy(ckpt + i * blk_size, sit_bitmap_ptr, blk_size);
f2fs_put_page(cur_page, 1);
}
done:
f2fs_put_page(cp1, 1); f2fs_put_page(cp1, 1);
f2fs_put_page(cp2, 1); f2fs_put_page(cp2, 1);
return 0; return 0;
...@@ -552,14 +575,13 @@ int get_valid_checkpoint(struct f2fs_sb_info *sbi) ...@@ -552,14 +575,13 @@ int get_valid_checkpoint(struct f2fs_sb_info *sbi)
static int __add_dirty_inode(struct inode *inode, struct dir_inode_entry *new) static int __add_dirty_inode(struct inode *inode, struct dir_inode_entry *new)
{ {
struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
struct list_head *head = &sbi->dir_inode_list;
struct dir_inode_entry *entry;
list_for_each_entry(entry, head, list) if (is_inode_flag_set(F2FS_I(inode), FI_DIRTY_DIR))
if (unlikely(entry->inode == inode))
return -EEXIST; return -EEXIST;
list_add_tail(&new->list, head); set_inode_flag(F2FS_I(inode), FI_DIRTY_DIR);
F2FS_I(inode)->dirty_dir = new;
list_add_tail(&new->list, &sbi->dir_inode_list);
stat_inc_dirty_dir(sbi); stat_inc_dirty_dir(sbi);
return 0; return 0;
} }
...@@ -608,31 +630,26 @@ void add_dirty_dir_inode(struct inode *inode) ...@@ -608,31 +630,26 @@ void add_dirty_dir_inode(struct inode *inode)
void remove_dirty_dir_inode(struct inode *inode) void remove_dirty_dir_inode(struct inode *inode)
{ {
struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
struct list_head *head;
struct dir_inode_entry *entry; struct dir_inode_entry *entry;
if (!S_ISDIR(inode->i_mode)) if (!S_ISDIR(inode->i_mode))
return; return;
spin_lock(&sbi->dir_inode_lock); spin_lock(&sbi->dir_inode_lock);
if (get_dirty_dents(inode)) { if (get_dirty_dents(inode) ||
!is_inode_flag_set(F2FS_I(inode), FI_DIRTY_DIR)) {
spin_unlock(&sbi->dir_inode_lock); spin_unlock(&sbi->dir_inode_lock);
return; return;
} }
head = &sbi->dir_inode_list; entry = F2FS_I(inode)->dirty_dir;
list_for_each_entry(entry, head, list) {
if (entry->inode == inode) {
list_del(&entry->list); list_del(&entry->list);
F2FS_I(inode)->dirty_dir = NULL;
clear_inode_flag(F2FS_I(inode), FI_DIRTY_DIR);
stat_dec_dirty_dir(sbi); stat_dec_dirty_dir(sbi);
spin_unlock(&sbi->dir_inode_lock); spin_unlock(&sbi->dir_inode_lock);
kmem_cache_free(inode_entry_slab, entry); kmem_cache_free(inode_entry_slab, entry);
goto done;
}
}
spin_unlock(&sbi->dir_inode_lock);
done:
/* Only from the recovery routine */ /* Only from the recovery routine */
if (is_inode_flag_set(F2FS_I(inode), FI_DELAY_IPUT)) { if (is_inode_flag_set(F2FS_I(inode), FI_DELAY_IPUT)) {
clear_inode_flag(F2FS_I(inode), FI_DELAY_IPUT); clear_inode_flag(F2FS_I(inode), FI_DELAY_IPUT);
...@@ -640,26 +657,6 @@ void remove_dirty_dir_inode(struct inode *inode) ...@@ -640,26 +657,6 @@ void remove_dirty_dir_inode(struct inode *inode)
} }
} }
struct inode *check_dirty_dir_inode(struct f2fs_sb_info *sbi, nid_t ino)
{
struct list_head *head;
struct inode *inode = NULL;
struct dir_inode_entry *entry;
spin_lock(&sbi->dir_inode_lock);
head = &sbi->dir_inode_list;
list_for_each_entry(entry, head, list) {
if (entry->inode->i_ino == ino) {
inode = entry->inode;
break;
}
}
spin_unlock(&sbi->dir_inode_lock);
return inode;
}
void sync_dirty_dir_inodes(struct f2fs_sb_info *sbi) void sync_dirty_dir_inodes(struct f2fs_sb_info *sbi)
{ {
struct list_head *head; struct list_head *head;
...@@ -758,6 +755,13 @@ static void do_checkpoint(struct f2fs_sb_info *sbi, bool is_umount) ...@@ -758,6 +755,13 @@ static void do_checkpoint(struct f2fs_sb_info *sbi, bool is_umount)
__u32 crc32 = 0; __u32 crc32 = 0;
void *kaddr; void *kaddr;
int i; int i;
int cp_payload_blks = le32_to_cpu(F2FS_RAW_SUPER(sbi)->cp_payload);
/*
* This avoids to conduct wrong roll-forward operations and uses
* metapages, so should be called prior to sync_meta_pages below.
*/
discard_next_dnode(sbi);
/* Flush all the NAT/SIT pages */ /* Flush all the NAT/SIT pages */
while (get_pages(sbi, F2FS_DIRTY_META)) while (get_pages(sbi, F2FS_DIRTY_META))
...@@ -802,16 +806,19 @@ static void do_checkpoint(struct f2fs_sb_info *sbi, bool is_umount) ...@@ -802,16 +806,19 @@ static void do_checkpoint(struct f2fs_sb_info *sbi, bool is_umount)
orphan_blocks = (sbi->n_orphans + F2FS_ORPHANS_PER_BLOCK - 1) orphan_blocks = (sbi->n_orphans + F2FS_ORPHANS_PER_BLOCK - 1)
/ F2FS_ORPHANS_PER_BLOCK; / F2FS_ORPHANS_PER_BLOCK;
ckpt->cp_pack_start_sum = cpu_to_le32(1 + orphan_blocks); ckpt->cp_pack_start_sum = cpu_to_le32(1 + cp_payload_blks +
orphan_blocks);
if (is_umount) { if (is_umount) {
set_ckpt_flags(ckpt, CP_UMOUNT_FLAG); set_ckpt_flags(ckpt, CP_UMOUNT_FLAG);
ckpt->cp_pack_total_block_count = cpu_to_le32(2 + ckpt->cp_pack_total_block_count = cpu_to_le32(2 +
data_sum_blocks + orphan_blocks + NR_CURSEG_NODE_TYPE); cp_payload_blks + data_sum_blocks +
orphan_blocks + NR_CURSEG_NODE_TYPE);
} else { } else {
clear_ckpt_flags(ckpt, CP_UMOUNT_FLAG); clear_ckpt_flags(ckpt, CP_UMOUNT_FLAG);
ckpt->cp_pack_total_block_count = cpu_to_le32(2 + ckpt->cp_pack_total_block_count = cpu_to_le32(2 +
data_sum_blocks + orphan_blocks); cp_payload_blks + data_sum_blocks +
orphan_blocks);
} }
if (sbi->n_orphans) if (sbi->n_orphans)
...@@ -837,6 +844,15 @@ static void do_checkpoint(struct f2fs_sb_info *sbi, bool is_umount) ...@@ -837,6 +844,15 @@ static void do_checkpoint(struct f2fs_sb_info *sbi, bool is_umount)
set_page_dirty(cp_page); set_page_dirty(cp_page);
f2fs_put_page(cp_page, 1); f2fs_put_page(cp_page, 1);
for (i = 1; i < 1 + cp_payload_blks; i++) {
cp_page = grab_meta_page(sbi, start_blk++);
kaddr = page_address(cp_page);
memcpy(kaddr, (char *)ckpt + i * F2FS_BLKSIZE,
(1 << sbi->log_blocksize));
set_page_dirty(cp_page);
f2fs_put_page(cp_page, 1);
}
if (sbi->n_orphans) { if (sbi->n_orphans) {
write_orphan_inodes(sbi, start_blk); write_orphan_inodes(sbi, start_blk);
start_blk += orphan_blocks; start_blk += orphan_blocks;
......
...@@ -417,7 +417,7 @@ struct page *find_data_page(struct inode *inode, pgoff_t index, bool sync) ...@@ -417,7 +417,7 @@ struct page *find_data_page(struct inode *inode, pgoff_t index, bool sync)
if (unlikely(dn.data_blkaddr == NEW_ADDR)) if (unlikely(dn.data_blkaddr == NEW_ADDR))
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
page = grab_cache_page_write_begin(mapping, index, AOP_FLAG_NOFS); page = grab_cache_page(mapping, index);
if (!page) if (!page)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
...@@ -455,7 +455,7 @@ struct page *get_lock_data_page(struct inode *inode, pgoff_t index) ...@@ -455,7 +455,7 @@ struct page *get_lock_data_page(struct inode *inode, pgoff_t index)
int err; int err;
repeat: repeat:
page = grab_cache_page_write_begin(mapping, index, AOP_FLAG_NOFS); page = grab_cache_page(mapping, index);
if (!page) if (!page)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
...@@ -652,8 +652,7 @@ static int get_data_block(struct inode *inode, sector_t iblock, ...@@ -652,8 +652,7 @@ static int get_data_block(struct inode *inode, sector_t iblock,
goto put_out; goto put_out;
} }
end_offset = IS_INODE(dn.node_page) ? end_offset = ADDRS_PER_PAGE(dn.node_page, F2FS_I(inode));
ADDRS_PER_INODE(F2FS_I(inode)) : ADDRS_PER_BLOCK;
bh_result->b_size = (((size_t)1) << blkbits); bh_result->b_size = (((size_t)1) << blkbits);
dn.ofs_in_node++; dn.ofs_in_node++;
pgofs++; pgofs++;
...@@ -675,8 +674,7 @@ static int get_data_block(struct inode *inode, sector_t iblock, ...@@ -675,8 +674,7 @@ static int get_data_block(struct inode *inode, sector_t iblock,
if (dn.data_blkaddr == NEW_ADDR) if (dn.data_blkaddr == NEW_ADDR)
goto put_out; goto put_out;
end_offset = IS_INODE(dn.node_page) ? end_offset = ADDRS_PER_PAGE(dn.node_page, F2FS_I(inode));
ADDRS_PER_INODE(F2FS_I(inode)) : ADDRS_PER_BLOCK;
} }
if (maxblocks > (bh_result->b_size >> blkbits)) { if (maxblocks > (bh_result->b_size >> blkbits)) {
...@@ -710,11 +708,19 @@ static int get_data_block(struct inode *inode, sector_t iblock, ...@@ -710,11 +708,19 @@ static int get_data_block(struct inode *inode, sector_t iblock,
return err; return err;
} }
int f2fs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
u64 start, u64 len)
{
return generic_block_fiemap(inode, fieinfo, start, len, get_data_block);
}
static int f2fs_read_data_page(struct file *file, struct page *page) static int f2fs_read_data_page(struct file *file, struct page *page)
{ {
struct inode *inode = page->mapping->host; struct inode *inode = page->mapping->host;
int ret; int ret;
trace_f2fs_readpage(page, DATA);
/* If the file has inline data, try to read it directlly */ /* If the file has inline data, try to read it directlly */
if (f2fs_has_inline_data(inode)) if (f2fs_has_inline_data(inode))
ret = f2fs_read_inline_data(inode, page); ret = f2fs_read_inline_data(inode, page);
...@@ -790,6 +796,8 @@ static int f2fs_write_data_page(struct page *page, ...@@ -790,6 +796,8 @@ static int f2fs_write_data_page(struct page *page,
.rw = (wbc->sync_mode == WB_SYNC_ALL) ? WRITE_SYNC : WRITE, .rw = (wbc->sync_mode == WB_SYNC_ALL) ? WRITE_SYNC : WRITE,
}; };
trace_f2fs_writepage(page, DATA);
if (page->index < end_index) if (page->index < end_index)
goto write; goto write;
...@@ -798,10 +806,8 @@ static int f2fs_write_data_page(struct page *page, ...@@ -798,10 +806,8 @@ static int f2fs_write_data_page(struct page *page,
* this page does not have to be written to disk. * this page does not have to be written to disk.
*/ */
offset = i_size & (PAGE_CACHE_SIZE - 1); offset = i_size & (PAGE_CACHE_SIZE - 1);
if ((page->index >= end_index + 1) || !offset) { if ((page->index >= end_index + 1) || !offset)
inode_dec_dirty_dents(inode);
goto out; goto out;
}
zero_user_segment(page, offset, PAGE_CACHE_SIZE); zero_user_segment(page, offset, PAGE_CACHE_SIZE);
write: write:
...@@ -810,7 +816,6 @@ static int f2fs_write_data_page(struct page *page, ...@@ -810,7 +816,6 @@ static int f2fs_write_data_page(struct page *page,
/* Dentry blocks are controlled by checkpoint */ /* Dentry blocks are controlled by checkpoint */
if (S_ISDIR(inode->i_mode)) { if (S_ISDIR(inode->i_mode)) {
inode_dec_dirty_dents(inode);
err = do_write_data_page(page, &fio); err = do_write_data_page(page, &fio);
goto done; goto done;
} }
...@@ -832,15 +837,16 @@ static int f2fs_write_data_page(struct page *page, ...@@ -832,15 +837,16 @@ static int f2fs_write_data_page(struct page *page,
clear_cold_data(page); clear_cold_data(page);
out: out:
inode_dec_dirty_dents(inode);
unlock_page(page); unlock_page(page);
if (need_balance_fs) if (need_balance_fs)
f2fs_balance_fs(sbi); f2fs_balance_fs(sbi);
if (wbc->for_reclaim)
f2fs_submit_merged_bio(sbi, DATA, WRITE);
return 0; return 0;
redirty_out: redirty_out:
wbc->pages_skipped++; redirty_page_for_writepage(wbc, page);
account_page_redirty(page);
set_page_dirty(page);
return AOP_WRITEPAGE_ACTIVATE; return AOP_WRITEPAGE_ACTIVATE;
} }
...@@ -862,12 +868,15 @@ static int f2fs_write_data_pages(struct address_space *mapping, ...@@ -862,12 +868,15 @@ static int f2fs_write_data_pages(struct address_space *mapping,
int ret; int ret;
long diff; long diff;
trace_f2fs_writepages(mapping->host, wbc, DATA);
/* deal with chardevs and other special file */ /* deal with chardevs and other special file */
if (!mapping->a_ops->writepage) if (!mapping->a_ops->writepage)
return 0; return 0;
if (S_ISDIR(inode->i_mode) && wbc->sync_mode == WB_SYNC_NONE && if (S_ISDIR(inode->i_mode) && wbc->sync_mode == WB_SYNC_NONE &&
get_dirty_dents(inode) < nr_pages_to_skip(sbi, DATA)) get_dirty_dents(inode) < nr_pages_to_skip(sbi, DATA) &&
available_free_memory(sbi, DIRTY_DENTS))
goto skip_write; goto skip_write;
diff = nr_pages_to_write(sbi, DATA, wbc); diff = nr_pages_to_write(sbi, DATA, wbc);
...@@ -903,6 +912,8 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping, ...@@ -903,6 +912,8 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping,
struct dnode_of_data dn; struct dnode_of_data dn;
int err = 0; int err = 0;
trace_f2fs_write_begin(inode, pos, len, flags);
f2fs_balance_fs(sbi); f2fs_balance_fs(sbi);
repeat: repeat:
err = f2fs_convert_inline_data(inode, pos + len); err = f2fs_convert_inline_data(inode, pos + len);
...@@ -912,6 +923,10 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping, ...@@ -912,6 +923,10 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping,
page = grab_cache_page_write_begin(mapping, index, flags); page = grab_cache_page_write_begin(mapping, index, flags);
if (!page) if (!page)
return -ENOMEM; return -ENOMEM;
/* to avoid latency during memory pressure */
unlock_page(page);
*pagep = page; *pagep = page;
if (f2fs_has_inline_data(inode) && (pos + len) <= MAX_INLINE_DATA) if (f2fs_has_inline_data(inode) && (pos + len) <= MAX_INLINE_DATA)
...@@ -923,10 +938,18 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping, ...@@ -923,10 +938,18 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping,
f2fs_unlock_op(sbi); f2fs_unlock_op(sbi);
if (err) { if (err) {
f2fs_put_page(page, 1); f2fs_put_page(page, 0);
return err; return err;
} }
inline_data: inline_data:
lock_page(page);
if (unlikely(page->mapping != mapping)) {
f2fs_put_page(page, 1);
goto repeat;
}
f2fs_wait_on_page_writeback(page, DATA);
if ((len == PAGE_CACHE_SIZE) || PageUptodate(page)) if ((len == PAGE_CACHE_SIZE) || PageUptodate(page))
return 0; return 0;
...@@ -978,6 +1001,8 @@ static int f2fs_write_end(struct file *file, ...@@ -978,6 +1001,8 @@ static int f2fs_write_end(struct file *file,
{ {
struct inode *inode = page->mapping->host; struct inode *inode = page->mapping->host;
trace_f2fs_write_end(inode, pos, len, copied);
SetPageUptodate(page); SetPageUptodate(page);
set_page_dirty(page); set_page_dirty(page);
...@@ -1022,6 +1047,9 @@ static ssize_t f2fs_direct_IO(int rw, struct kiocb *iocb, ...@@ -1022,6 +1047,9 @@ static ssize_t f2fs_direct_IO(int rw, struct kiocb *iocb,
if (check_direct_IO(inode, rw, iov, offset, nr_segs)) if (check_direct_IO(inode, rw, iov, offset, nr_segs))
return 0; return 0;
/* clear fsync mark to recover these blocks */
fsync_mark_clear(F2FS_SB(inode->i_sb), inode->i_ino);
return blockdev_direct_IO(rw, iocb, inode, iov, offset, nr_segs, return blockdev_direct_IO(rw, iocb, inode, iov, offset, nr_segs,
get_data_block); get_data_block);
} }
...@@ -1061,6 +1089,11 @@ static int f2fs_set_data_page_dirty(struct page *page) ...@@ -1061,6 +1089,11 @@ static int f2fs_set_data_page_dirty(struct page *page)
static sector_t f2fs_bmap(struct address_space *mapping, sector_t block) static sector_t f2fs_bmap(struct address_space *mapping, sector_t block)
{ {
struct inode *inode = mapping->host;
if (f2fs_has_inline_data(inode))
return 0;
return generic_block_bmap(mapping, block, get_data_block); return generic_block_bmap(mapping, block, get_data_block);
} }
......
...@@ -23,10 +23,10 @@ static unsigned long dir_blocks(struct inode *inode) ...@@ -23,10 +23,10 @@ static unsigned long dir_blocks(struct inode *inode)
static unsigned int dir_buckets(unsigned int level, int dir_level) static unsigned int dir_buckets(unsigned int level, int dir_level)
{ {
if (level < MAX_DIR_HASH_DEPTH / 2) if (level + dir_level < MAX_DIR_HASH_DEPTH / 2)
return 1 << (level + dir_level); return 1 << (level + dir_level);
else else
return 1 << ((MAX_DIR_HASH_DEPTH / 2 + dir_level) - 1); return MAX_DIR_BUCKETS;
} }
static unsigned int bucket_blocks(unsigned int level) static unsigned int bucket_blocks(unsigned int level)
...@@ -268,6 +268,8 @@ static void init_dent_inode(const struct qstr *name, struct page *ipage) ...@@ -268,6 +268,8 @@ static void init_dent_inode(const struct qstr *name, struct page *ipage)
{ {
struct f2fs_inode *ri; struct f2fs_inode *ri;
f2fs_wait_on_page_writeback(ipage, NODE);
/* copy name info. to this inode page */ /* copy name info. to this inode page */
ri = F2FS_INODE(ipage); ri = F2FS_INODE(ipage);
ri->i_namelen = cpu_to_le32(name->len); ri->i_namelen = cpu_to_le32(name->len);
...@@ -637,11 +639,17 @@ static int f2fs_readdir(struct file *file, struct dir_context *ctx) ...@@ -637,11 +639,17 @@ static int f2fs_readdir(struct file *file, struct dir_context *ctx)
struct f2fs_dentry_block *dentry_blk = NULL; struct f2fs_dentry_block *dentry_blk = NULL;
struct f2fs_dir_entry *de = NULL; struct f2fs_dir_entry *de = NULL;
struct page *dentry_page = NULL; struct page *dentry_page = NULL;
struct file_ra_state *ra = &file->f_ra;
unsigned int n = ((unsigned long)ctx->pos / NR_DENTRY_IN_BLOCK); unsigned int n = ((unsigned long)ctx->pos / NR_DENTRY_IN_BLOCK);
unsigned char d_type = DT_UNKNOWN; unsigned char d_type = DT_UNKNOWN;
bit_pos = ((unsigned long)ctx->pos % NR_DENTRY_IN_BLOCK); bit_pos = ((unsigned long)ctx->pos % NR_DENTRY_IN_BLOCK);
/* readahead for multi pages of dir */
if (npages - n > 1 && !ra_has_index(ra, n))
page_cache_sync_readahead(inode->i_mapping, ra, file, n,
min(npages - n, (pgoff_t)MAX_DIR_RA_PAGES));
for (; n < npages; n++) { for (; n < npages; n++) {
dentry_page = get_lock_data_page(inode, n); dentry_page = get_lock_data_page(inode, n);
if (IS_ERR(dentry_page)) if (IS_ERR(dentry_page))
......
...@@ -182,6 +182,8 @@ enum { ...@@ -182,6 +182,8 @@ enum {
#define F2FS_LINK_MAX 32000 /* maximum link count per file */ #define F2FS_LINK_MAX 32000 /* maximum link count per file */
#define MAX_DIR_RA_PAGES 4 /* maximum ra pages of dir */
/* for in-memory extent cache entry */ /* for in-memory extent cache entry */
#define F2FS_MIN_EXTENT_LEN 16 /* minimum extent length */ #define F2FS_MIN_EXTENT_LEN 16 /* minimum extent length */
...@@ -218,6 +220,7 @@ struct f2fs_inode_info { ...@@ -218,6 +220,7 @@ struct f2fs_inode_info {
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 */ 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 */
struct dir_inode_entry *dirty_dir; /* the pointer of dirty dir */
}; };
static inline void get_extent_info(struct extent_info *ext, static inline void get_extent_info(struct extent_info *ext,
...@@ -243,6 +246,7 @@ static inline void set_raw_extent(struct extent_info *ext, ...@@ -243,6 +246,7 @@ static inline void set_raw_extent(struct extent_info *ext,
struct f2fs_nm_info { struct f2fs_nm_info {
block_t nat_blkaddr; /* base disk address of NAT */ block_t nat_blkaddr; /* base disk address of NAT */
nid_t max_nid; /* maximum possible node ids */ nid_t max_nid; /* maximum possible node ids */
nid_t available_nids; /* maximum available node ids */
nid_t next_scan_nid; /* the next nid to be scanned */ nid_t next_scan_nid; /* the next nid to be scanned */
unsigned int ram_thresh; /* control the memory footprint */ unsigned int ram_thresh; /* control the memory footprint */
...@@ -323,6 +327,15 @@ struct flush_cmd { ...@@ -323,6 +327,15 @@ struct flush_cmd {
int ret; int ret;
}; };
struct flush_cmd_control {
struct task_struct *f2fs_issue_flush; /* flush thread */
wait_queue_head_t flush_wait_queue; /* waiting queue for wake-up */
struct flush_cmd *issue_list; /* list for command issue */
struct flush_cmd *dispatch_list; /* list for command dispatch */
spinlock_t issue_lock; /* for issue list lock */
struct flush_cmd *issue_tail; /* list tail of issue list */
};
struct f2fs_sm_info { struct f2fs_sm_info {
struct sit_info *sit_info; /* whole segment information */ struct sit_info *sit_info; /* whole segment information */
struct free_segmap_info *free_info; /* free segment information */ struct free_segmap_info *free_info; /* free segment information */
...@@ -353,12 +366,8 @@ struct f2fs_sm_info { ...@@ -353,12 +366,8 @@ struct f2fs_sm_info {
unsigned int min_ipu_util; /* in-place-update threshold */ unsigned int min_ipu_util; /* in-place-update threshold */
/* for flush command control */ /* for flush command control */
struct task_struct *f2fs_issue_flush; /* flush thread */ struct flush_cmd_control *cmd_control_info;
wait_queue_head_t flush_wait_queue; /* waiting queue for wake-up */
struct flush_cmd *issue_list; /* list for command issue */
struct flush_cmd *dispatch_list; /* list for command dispatch */
spinlock_t issue_lock; /* for issue list lock */
struct flush_cmd *issue_tail; /* list tail of issue list */
}; };
/* /*
...@@ -755,9 +764,18 @@ static inline unsigned long __bitmap_size(struct f2fs_sb_info *sbi, int flag) ...@@ -755,9 +764,18 @@ static inline unsigned long __bitmap_size(struct f2fs_sb_info *sbi, int flag)
static inline void *__bitmap_ptr(struct f2fs_sb_info *sbi, int flag) static inline void *__bitmap_ptr(struct f2fs_sb_info *sbi, int flag)
{ {
struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
int offset = (flag == NAT_BITMAP) ? int offset;
if (le32_to_cpu(F2FS_RAW_SUPER(sbi)->cp_payload) > 0) {
if (flag == NAT_BITMAP)
return &ckpt->sit_nat_version_bitmap;
else
return ((unsigned char *)ckpt + F2FS_BLKSIZE);
} else {
offset = (flag == NAT_BITMAP) ?
le32_to_cpu(ckpt->sit_ver_bitmap_bytesize) : 0; le32_to_cpu(ckpt->sit_ver_bitmap_bytesize) : 0;
return &ckpt->sit_nat_version_bitmap + offset; return &ckpt->sit_nat_version_bitmap + offset;
}
} }
static inline block_t __start_cp_addr(struct f2fs_sb_info *sbi) static inline block_t __start_cp_addr(struct f2fs_sb_info *sbi)
...@@ -958,6 +976,7 @@ static inline int f2fs_clear_bit(unsigned int nr, char *addr) ...@@ -958,6 +976,7 @@ static inline int f2fs_clear_bit(unsigned int nr, char *addr)
enum { enum {
FI_NEW_INODE, /* indicate newly allocated inode */ FI_NEW_INODE, /* indicate newly allocated inode */
FI_DIRTY_INODE, /* indicate inode is dirty or not */ FI_DIRTY_INODE, /* indicate inode is dirty or not */
FI_DIRTY_DIR, /* indicate directory has dirty pages */
FI_INC_LINK, /* need to increment i_nlink */ FI_INC_LINK, /* need to increment i_nlink */
FI_ACL_MODE, /* indicate acl mode */ FI_ACL_MODE, /* indicate acl mode */
FI_NO_ALLOC, /* should not allocate any blocks */ FI_NO_ALLOC, /* should not allocate any blocks */
...@@ -1071,6 +1090,12 @@ static inline void f2fs_stop_checkpoint(struct f2fs_sb_info *sbi) ...@@ -1071,6 +1090,12 @@ static inline void f2fs_stop_checkpoint(struct f2fs_sb_info *sbi)
((is_inode_flag_set(F2FS_I(i), FI_ACL_MODE)) ? \ ((is_inode_flag_set(F2FS_I(i), FI_ACL_MODE)) ? \
(F2FS_I(i)->i_acl_mode) : ((i)->i_mode)) (F2FS_I(i)->i_acl_mode) : ((i)->i_mode))
/* get offset of first page in next direct node */
#define PGOFS_OF_NEXT_DNODE(pgofs, fi) \
((pgofs < ADDRS_PER_INODE(fi)) ? ADDRS_PER_INODE(fi) : \
(pgofs - ADDRS_PER_INODE(fi) + ADDRS_PER_BLOCK) / \
ADDRS_PER_BLOCK * ADDRS_PER_BLOCK + ADDRS_PER_INODE(fi))
/* /*
* file.c * file.c
*/ */
...@@ -1140,8 +1165,10 @@ f2fs_hash_t f2fs_dentry_hash(const char *, size_t); ...@@ -1140,8 +1165,10 @@ f2fs_hash_t f2fs_dentry_hash(const char *, size_t);
struct dnode_of_data; struct dnode_of_data;
struct node_info; struct node_info;
bool available_free_memory(struct f2fs_sb_info *, int);
int is_checkpointed_node(struct f2fs_sb_info *, nid_t); int is_checkpointed_node(struct f2fs_sb_info *, nid_t);
bool fsync_mark_done(struct f2fs_sb_info *, nid_t); bool fsync_mark_done(struct f2fs_sb_info *, nid_t);
void fsync_mark_clear(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);
...@@ -1176,9 +1203,12 @@ void destroy_node_manager_caches(void); ...@@ -1176,9 +1203,12 @@ void destroy_node_manager_caches(void);
void f2fs_balance_fs(struct f2fs_sb_info *); void f2fs_balance_fs(struct f2fs_sb_info *);
void f2fs_balance_fs_bg(struct f2fs_sb_info *); void f2fs_balance_fs_bg(struct f2fs_sb_info *);
int f2fs_issue_flush(struct f2fs_sb_info *); int f2fs_issue_flush(struct f2fs_sb_info *);
int create_flush_cmd_control(struct f2fs_sb_info *);
void destroy_flush_cmd_control(struct f2fs_sb_info *);
void invalidate_blocks(struct f2fs_sb_info *, block_t); void invalidate_blocks(struct f2fs_sb_info *, block_t);
void refresh_sit_entry(struct f2fs_sb_info *, block_t, block_t); void refresh_sit_entry(struct f2fs_sb_info *, block_t, block_t);
void clear_prefree_segments(struct f2fs_sb_info *); void clear_prefree_segments(struct f2fs_sb_info *);
void discard_next_dnode(struct f2fs_sb_info *);
int npages_for_summary_flush(struct f2fs_sb_info *); 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);
...@@ -1221,7 +1251,6 @@ int get_valid_checkpoint(struct f2fs_sb_info *); ...@@ -1221,7 +1251,6 @@ int get_valid_checkpoint(struct f2fs_sb_info *);
void set_dirty_dir_page(struct inode *, struct page *); void set_dirty_dir_page(struct inode *, struct page *);
void add_dirty_dir_inode(struct inode *); void add_dirty_dir_inode(struct inode *);
void remove_dirty_dir_inode(struct inode *); void remove_dirty_dir_inode(struct inode *);
struct inode *check_dirty_dir_inode(struct f2fs_sb_info *, nid_t);
void sync_dirty_dir_inodes(struct f2fs_sb_info *); void sync_dirty_dir_inodes(struct f2fs_sb_info *);
void write_checkpoint(struct f2fs_sb_info *, bool); void write_checkpoint(struct f2fs_sb_info *, bool);
void init_orphan_info(struct f2fs_sb_info *); void init_orphan_info(struct f2fs_sb_info *);
...@@ -1242,6 +1271,7 @@ struct page *find_data_page(struct inode *, pgoff_t, bool); ...@@ -1242,6 +1271,7 @@ struct page *find_data_page(struct inode *, pgoff_t, bool);
struct page *get_lock_data_page(struct inode *, pgoff_t); struct page *get_lock_data_page(struct inode *, pgoff_t);
struct page *get_new_data_page(struct inode *, struct page *, pgoff_t, bool); struct page *get_new_data_page(struct inode *, struct page *, pgoff_t, bool);
int do_write_data_page(struct page *, struct f2fs_io_info *); int do_write_data_page(struct page *, struct f2fs_io_info *);
int f2fs_fiemap(struct inode *inode, struct fiemap_extent_info *, u64, u64);
/* /*
* gc.c * gc.c
...@@ -1391,5 +1421,6 @@ bool f2fs_may_inline(struct inode *); ...@@ -1391,5 +1421,6 @@ bool f2fs_may_inline(struct inode *);
int f2fs_read_inline_data(struct inode *, struct page *); int f2fs_read_inline_data(struct inode *, struct page *);
int f2fs_convert_inline_data(struct inode *, pgoff_t); int f2fs_convert_inline_data(struct inode *, pgoff_t);
int f2fs_write_inline_data(struct inode *, struct page *, unsigned int); int f2fs_write_inline_data(struct inode *, struct page *, unsigned int);
void truncate_inline_data(struct inode *, u64);
int recover_inline_data(struct inode *, struct page *); int recover_inline_data(struct inode *, struct page *);
#endif #endif
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <linux/compat.h> #include <linux/compat.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <linux/mount.h> #include <linux/mount.h>
#include <linux/pagevec.h>
#include "f2fs.h" #include "f2fs.h"
#include "node.h" #include "node.h"
...@@ -194,6 +195,132 @@ int f2fs_sync_file(struct file *file, loff_t start, loff_t end, int datasync) ...@@ -194,6 +195,132 @@ int f2fs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
return ret; return ret;
} }
static pgoff_t __get_first_dirty_index(struct address_space *mapping,
pgoff_t pgofs, int whence)
{
struct pagevec pvec;
int nr_pages;
if (whence != SEEK_DATA)
return 0;
/* find first dirty page index */
pagevec_init(&pvec, 0);
nr_pages = pagevec_lookup_tag(&pvec, mapping, &pgofs, PAGECACHE_TAG_DIRTY, 1);
pgofs = nr_pages ? pvec.pages[0]->index: LONG_MAX;
pagevec_release(&pvec);
return pgofs;
}
static bool __found_offset(block_t blkaddr, pgoff_t dirty, pgoff_t pgofs,
int whence)
{
switch (whence) {
case SEEK_DATA:
if ((blkaddr == NEW_ADDR && dirty == pgofs) ||
(blkaddr != NEW_ADDR && blkaddr != NULL_ADDR))
return true;
break;
case SEEK_HOLE:
if (blkaddr == NULL_ADDR)
return true;
break;
}
return false;
}
static loff_t f2fs_seek_block(struct file *file, loff_t offset, int whence)
{
struct inode *inode = file->f_mapping->host;
loff_t maxbytes = inode->i_sb->s_maxbytes;
struct dnode_of_data dn;
pgoff_t pgofs, end_offset, dirty;
loff_t data_ofs = offset;
loff_t isize;
int err = 0;
mutex_lock(&inode->i_mutex);
isize = i_size_read(inode);
if (offset >= isize)
goto fail;
/* handle inline data case */
if (f2fs_has_inline_data(inode)) {
if (whence == SEEK_HOLE)
data_ofs = isize;
goto found;
}
pgofs = (pgoff_t)(offset >> PAGE_CACHE_SHIFT);
dirty = __get_first_dirty_index(inode->i_mapping, pgofs, whence);
for (; data_ofs < isize; data_ofs = pgofs << PAGE_CACHE_SHIFT) {
set_new_dnode(&dn, inode, NULL, NULL, 0);
err = get_dnode_of_data(&dn, pgofs, LOOKUP_NODE_RA);
if (err && err != -ENOENT) {
goto fail;
} else if (err == -ENOENT) {
/* direct node is not exist */
if (whence == SEEK_DATA) {
pgofs = PGOFS_OF_NEXT_DNODE(pgofs,
F2FS_I(inode));
continue;
} else {
goto found;
}
}
end_offset = IS_INODE(dn.node_page) ?
ADDRS_PER_INODE(F2FS_I(inode)) : ADDRS_PER_BLOCK;
/* find data/hole in dnode block */
for (; dn.ofs_in_node < end_offset;
dn.ofs_in_node++, pgofs++,
data_ofs = pgofs << PAGE_CACHE_SHIFT) {
block_t blkaddr;
blkaddr = datablock_addr(dn.node_page, dn.ofs_in_node);
if (__found_offset(blkaddr, dirty, pgofs, whence)) {
f2fs_put_dnode(&dn);
goto found;
}
}
f2fs_put_dnode(&dn);
}
if (whence == SEEK_DATA)
goto fail;
found:
if (whence == SEEK_HOLE && data_ofs > isize)
data_ofs = isize;
mutex_unlock(&inode->i_mutex);
return vfs_setpos(file, data_ofs, maxbytes);
fail:
mutex_unlock(&inode->i_mutex);
return -ENXIO;
}
static loff_t f2fs_llseek(struct file *file, loff_t offset, int whence)
{
struct inode *inode = file->f_mapping->host;
loff_t maxbytes = inode->i_sb->s_maxbytes;
switch (whence) {
case SEEK_SET:
case SEEK_CUR:
case SEEK_END:
return generic_file_llseek_size(file, offset, whence,
maxbytes, i_size_read(inode));
case SEEK_DATA:
case SEEK_HOLE:
return f2fs_seek_block(file, offset, whence);
}
return -EINVAL;
}
static int f2fs_file_mmap(struct file *file, struct vm_area_struct *vma) static int f2fs_file_mmap(struct file *file, struct vm_area_struct *vma)
{ {
file_accessed(file); file_accessed(file);
...@@ -242,6 +369,9 @@ static void truncate_partial_data_page(struct inode *inode, u64 from) ...@@ -242,6 +369,9 @@ static void truncate_partial_data_page(struct inode *inode, u64 from)
unsigned offset = from & (PAGE_CACHE_SIZE - 1); unsigned offset = from & (PAGE_CACHE_SIZE - 1);
struct page *page; struct page *page;
if (f2fs_has_inline_data(inode))
return truncate_inline_data(inode, from);
if (!offset) if (!offset)
return; return;
...@@ -288,10 +418,7 @@ int truncate_blocks(struct inode *inode, u64 from) ...@@ -288,10 +418,7 @@ int truncate_blocks(struct inode *inode, u64 from)
return err; return err;
} }
if (IS_INODE(dn.node_page)) count = ADDRS_PER_PAGE(dn.node_page, F2FS_I(inode));
count = ADDRS_PER_INODE(F2FS_I(inode));
else
count = ADDRS_PER_BLOCK;
count -= dn.ofs_in_node; count -= dn.ofs_in_node;
f2fs_bug_on(count < 0); f2fs_bug_on(count < 0);
...@@ -413,6 +540,7 @@ const struct inode_operations f2fs_file_inode_operations = { ...@@ -413,6 +540,7 @@ const struct inode_operations f2fs_file_inode_operations = {
.listxattr = f2fs_listxattr, .listxattr = f2fs_listxattr,
.removexattr = generic_removexattr, .removexattr = generic_removexattr,
#endif #endif
.fiemap = f2fs_fiemap,
}; };
static void fill_zero(struct inode *inode, pgoff_t index, static void fill_zero(struct inode *inode, pgoff_t index,
...@@ -555,6 +683,7 @@ static int expand_inode_data(struct inode *inode, loff_t offset, ...@@ -555,6 +683,7 @@ static int expand_inode_data(struct inode *inode, loff_t offset,
i_size_read(inode) < new_size) { i_size_read(inode) < new_size) {
i_size_write(inode, new_size); i_size_write(inode, new_size);
mark_inode_dirty(inode); mark_inode_dirty(inode);
f2fs_write_inode(inode, NULL);
} }
return ret; return ret;
...@@ -678,7 +807,7 @@ long f2fs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ...@@ -678,7 +807,7 @@ long f2fs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
#endif #endif
const struct file_operations f2fs_file_operations = { const struct file_operations f2fs_file_operations = {
.llseek = generic_file_llseek, .llseek = f2fs_llseek,
.read = do_sync_read, .read = do_sync_read,
.write = do_sync_write, .write = do_sync_write,
.aio_read = generic_file_aio_read, .aio_read = generic_file_aio_read,
......
...@@ -81,8 +81,10 @@ static int __f2fs_convert_inline_data(struct inode *inode, struct page *page) ...@@ -81,8 +81,10 @@ static int __f2fs_convert_inline_data(struct inode *inode, struct page *page)
f2fs_lock_op(sbi); f2fs_lock_op(sbi);
ipage = get_node_page(sbi, inode->i_ino); ipage = get_node_page(sbi, inode->i_ino);
if (IS_ERR(ipage)) if (IS_ERR(ipage)) {
return PTR_ERR(ipage); err = PTR_ERR(ipage);
goto out;
}
/* /*
* i_addr[0] is not used for inline data, * i_addr[0] is not used for inline data,
...@@ -90,11 +92,10 @@ static int __f2fs_convert_inline_data(struct inode *inode, struct page *page) ...@@ -90,11 +92,10 @@ static int __f2fs_convert_inline_data(struct inode *inode, struct page *page)
*/ */
set_new_dnode(&dn, inode, ipage, NULL, 0); set_new_dnode(&dn, inode, ipage, NULL, 0);
err = f2fs_reserve_block(&dn, 0); err = f2fs_reserve_block(&dn, 0);
if (err) { if (err)
f2fs_unlock_op(sbi); goto out;
return err;
}
f2fs_wait_on_page_writeback(page, DATA);
zero_user_segment(page, MAX_INLINE_DATA, PAGE_CACHE_SIZE); zero_user_segment(page, MAX_INLINE_DATA, PAGE_CACHE_SIZE);
/* Copy the whole inline data block */ /* Copy the whole inline data block */
...@@ -118,6 +119,7 @@ static int __f2fs_convert_inline_data(struct inode *inode, struct page *page) ...@@ -118,6 +119,7 @@ static int __f2fs_convert_inline_data(struct inode *inode, struct page *page)
sync_inode_page(&dn); sync_inode_page(&dn);
f2fs_put_dnode(&dn); f2fs_put_dnode(&dn);
out:
f2fs_unlock_op(sbi); f2fs_unlock_op(sbi);
return err; return err;
} }
...@@ -132,7 +134,7 @@ int f2fs_convert_inline_data(struct inode *inode, pgoff_t to_size) ...@@ -132,7 +134,7 @@ int f2fs_convert_inline_data(struct inode *inode, pgoff_t to_size)
else if (to_size <= MAX_INLINE_DATA) else if (to_size <= MAX_INLINE_DATA)
return 0; return 0;
page = grab_cache_page_write_begin(inode->i_mapping, 0, AOP_FLAG_NOFS); page = grab_cache_page(inode->i_mapping, 0);
if (!page) if (!page)
return -ENOMEM; return -ENOMEM;
...@@ -155,6 +157,7 @@ int f2fs_write_inline_data(struct inode *inode, ...@@ -155,6 +157,7 @@ int f2fs_write_inline_data(struct inode *inode,
return err; return err;
ipage = dn.inode_page; ipage = dn.inode_page;
f2fs_wait_on_page_writeback(ipage, NODE);
zero_user_segment(ipage, INLINE_DATA_OFFSET, zero_user_segment(ipage, INLINE_DATA_OFFSET,
INLINE_DATA_OFFSET + MAX_INLINE_DATA); INLINE_DATA_OFFSET + MAX_INLINE_DATA);
src_addr = kmap(page); src_addr = kmap(page);
...@@ -175,6 +178,26 @@ int f2fs_write_inline_data(struct inode *inode, ...@@ -175,6 +178,26 @@ int f2fs_write_inline_data(struct inode *inode,
return 0; return 0;
} }
void truncate_inline_data(struct inode *inode, u64 from)
{
struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
struct page *ipage;
if (from >= MAX_INLINE_DATA)
return;
ipage = get_node_page(sbi, inode->i_ino);
if (IS_ERR(ipage))
return;
f2fs_wait_on_page_writeback(ipage, NODE);
zero_user_segment(ipage, INLINE_DATA_OFFSET + from,
INLINE_DATA_OFFSET + MAX_INLINE_DATA);
set_page_dirty(ipage);
f2fs_put_page(ipage, 1);
}
int recover_inline_data(struct inode *inode, struct page *npage) int recover_inline_data(struct inode *inode, struct page *npage)
{ {
struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
...@@ -199,6 +222,8 @@ int recover_inline_data(struct inode *inode, struct page *npage) ...@@ -199,6 +222,8 @@ int recover_inline_data(struct inode *inode, struct page *npage)
ipage = get_node_page(sbi, inode->i_ino); ipage = get_node_page(sbi, inode->i_ino);
f2fs_bug_on(IS_ERR(ipage)); f2fs_bug_on(IS_ERR(ipage));
f2fs_wait_on_page_writeback(ipage, NODE);
src_addr = inline_data_addr(npage); src_addr = inline_data_addr(npage);
dst_addr = inline_data_addr(ipage); dst_addr = inline_data_addr(ipage);
memcpy(dst_addr, src_addr, MAX_INLINE_DATA); memcpy(dst_addr, src_addr, MAX_INLINE_DATA);
...@@ -210,6 +235,7 @@ int recover_inline_data(struct inode *inode, struct page *npage) ...@@ -210,6 +235,7 @@ int recover_inline_data(struct inode *inode, struct page *npage)
if (f2fs_has_inline_data(inode)) { if (f2fs_has_inline_data(inode)) {
ipage = get_node_page(sbi, inode->i_ino); ipage = get_node_page(sbi, inode->i_ino);
f2fs_bug_on(IS_ERR(ipage)); f2fs_bug_on(IS_ERR(ipage));
f2fs_wait_on_page_writeback(ipage, NODE);
zero_user_segment(ipage, INLINE_DATA_OFFSET, zero_user_segment(ipage, INLINE_DATA_OFFSET,
INLINE_DATA_OFFSET + MAX_INLINE_DATA); INLINE_DATA_OFFSET + MAX_INLINE_DATA);
clear_inode_flag(F2FS_I(inode), FI_INLINE_DATA); clear_inode_flag(F2FS_I(inode), FI_INLINE_DATA);
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include <linux/f2fs_fs.h> #include <linux/f2fs_fs.h>
#include <linux/buffer_head.h> #include <linux/buffer_head.h>
#include <linux/writeback.h> #include <linux/writeback.h>
#include <linux/bitops.h>
#include "f2fs.h" #include "f2fs.h"
#include "node.h" #include "node.h"
...@@ -21,20 +22,20 @@ ...@@ -21,20 +22,20 @@
void f2fs_set_inode_flags(struct inode *inode) void f2fs_set_inode_flags(struct inode *inode)
{ {
unsigned int flags = F2FS_I(inode)->i_flags; unsigned int flags = F2FS_I(inode)->i_flags;
unsigned int new_fl = 0;
inode->i_flags &= ~(S_SYNC | S_APPEND | S_IMMUTABLE |
S_NOATIME | S_DIRSYNC);
if (flags & FS_SYNC_FL) if (flags & FS_SYNC_FL)
inode->i_flags |= S_SYNC; new_fl |= S_SYNC;
if (flags & FS_APPEND_FL) if (flags & FS_APPEND_FL)
inode->i_flags |= S_APPEND; new_fl |= S_APPEND;
if (flags & FS_IMMUTABLE_FL) if (flags & FS_IMMUTABLE_FL)
inode->i_flags |= S_IMMUTABLE; new_fl |= S_IMMUTABLE;
if (flags & FS_NOATIME_FL) if (flags & FS_NOATIME_FL)
inode->i_flags |= S_NOATIME; new_fl |= S_NOATIME;
if (flags & FS_DIRSYNC_FL) if (flags & FS_DIRSYNC_FL)
inode->i_flags |= S_DIRSYNC; new_fl |= S_DIRSYNC;
set_mask_bits(&inode->i_flags,
S_SYNC|S_APPEND|S_IMMUTABLE|S_NOATIME|S_DIRSYNC, new_fl);
} }
static void __get_inode_rdev(struct inode *inode, struct f2fs_inode *ri) static void __get_inode_rdev(struct inode *inode, struct f2fs_inode *ri)
...@@ -294,4 +295,5 @@ void f2fs_evict_inode(struct inode *inode) ...@@ -294,4 +295,5 @@ void f2fs_evict_inode(struct inode *inode)
sb_end_intwrite(inode->i_sb); sb_end_intwrite(inode->i_sb);
no_delete: no_delete:
clear_inode(inode); clear_inode(inode);
invalidate_mapping_pages(NODE_MAPPING(sbi), inode->i_ino, inode->i_ino);
} }
...@@ -41,18 +41,9 @@ static struct inode *f2fs_new_inode(struct inode *dir, umode_t mode) ...@@ -41,18 +41,9 @@ static struct inode *f2fs_new_inode(struct inode *dir, umode_t mode)
} }
f2fs_unlock_op(sbi); f2fs_unlock_op(sbi);
inode->i_uid = current_fsuid(); inode_init_owner(inode, dir, mode);
if (dir->i_mode & S_ISGID) {
inode->i_gid = dir->i_gid;
if (S_ISDIR(mode))
mode |= S_ISGID;
} else {
inode->i_gid = current_fsgid();
}
inode->i_ino = ino; inode->i_ino = ino;
inode->i_mode = mode;
inode->i_blocks = 0; inode->i_blocks = 0;
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
inode->i_generation = sbi->s_next_generation++; inode->i_generation = sbi->s_next_generation++;
......
This diff is collapsed.
...@@ -59,12 +59,12 @@ struct nat_entry { ...@@ -59,12 +59,12 @@ struct nat_entry {
do { \ do { \
ne->checkpointed = false; \ ne->checkpointed = false; \
list_move_tail(&ne->list, &nm_i->dirty_nat_entries); \ list_move_tail(&ne->list, &nm_i->dirty_nat_entries); \
} while (0); } while (0)
#define __clear_nat_cache_dirty(nm_i, ne) \ #define __clear_nat_cache_dirty(nm_i, ne) \
do { \ do { \
ne->checkpointed = true; \ ne->checkpointed = true; \
list_move_tail(&ne->list, &nm_i->nat_entries); \ list_move_tail(&ne->list, &nm_i->nat_entries); \
} while (0); } while (0)
#define inc_node_version(version) (++version) #define inc_node_version(version) (++version)
static inline void node_info_from_raw_nat(struct node_info *ni, static inline void node_info_from_raw_nat(struct node_info *ni,
...@@ -75,9 +75,18 @@ static inline void node_info_from_raw_nat(struct node_info *ni, ...@@ -75,9 +75,18 @@ static inline void node_info_from_raw_nat(struct node_info *ni,
ni->version = raw_ne->version; ni->version = raw_ne->version;
} }
enum nid_type { static inline void raw_nat_from_node_info(struct f2fs_nat_entry *raw_ne,
struct node_info *ni)
{
raw_ne->ino = cpu_to_le32(ni->ino);
raw_ne->block_addr = cpu_to_le32(ni->blk_addr);
raw_ne->version = ni->version;
}
enum mem_type {
FREE_NIDS, /* indicates the free nid list */ FREE_NIDS, /* indicates the free nid list */
NAT_ENTRIES /* indicates the cached nat entry */ NAT_ENTRIES, /* indicates the cached nat entry */
DIRTY_DENTS /* indicates dirty dentry pages */
}; };
/* /*
...@@ -263,7 +272,7 @@ static inline void set_nid(struct page *p, int off, nid_t nid, bool i) ...@@ -263,7 +272,7 @@ static inline void set_nid(struct page *p, int off, nid_t nid, bool i)
{ {
struct f2fs_node *rn = F2FS_NODE(p); struct f2fs_node *rn = F2FS_NODE(p);
wait_on_page_writeback(p); f2fs_wait_on_page_writeback(p, NODE);
if (i) if (i)
rn->i.i_nid[off - NODE_DIR1_BLOCK] = cpu_to_le32(nid); rn->i.i_nid[off - NODE_DIR1_BLOCK] = cpu_to_le32(nid);
......
...@@ -46,16 +46,11 @@ static int recover_dentry(struct page *ipage, struct inode *inode) ...@@ -46,16 +46,11 @@ static int recover_dentry(struct page *ipage, struct inode *inode)
struct inode *dir, *einode; struct inode *dir, *einode;
int err = 0; int err = 0;
dir = check_dirty_dir_inode(F2FS_SB(inode->i_sb), pino);
if (!dir) {
dir = f2fs_iget(inode->i_sb, pino); dir = f2fs_iget(inode->i_sb, pino);
if (IS_ERR(dir)) { if (IS_ERR(dir)) {
err = PTR_ERR(dir); err = PTR_ERR(dir);
goto out; goto out;
} }
set_inode_flag(F2FS_I(dir), FI_DELAY_IPUT);
add_dirty_dir_inode(dir);
}
name.len = le32_to_cpu(raw_inode->i_namelen); name.len = le32_to_cpu(raw_inode->i_namelen);
name.name = raw_inode->i_name; name.name = raw_inode->i_name;
...@@ -63,7 +58,7 @@ static int recover_dentry(struct page *ipage, struct inode *inode) ...@@ -63,7 +58,7 @@ static int recover_dentry(struct page *ipage, struct inode *inode)
if (unlikely(name.len > F2FS_NAME_LEN)) { if (unlikely(name.len > F2FS_NAME_LEN)) {
WARN_ON(1); WARN_ON(1);
err = -ENAMETOOLONG; err = -ENAMETOOLONG;
goto out; goto out_err;
} }
retry: retry:
de = f2fs_find_entry(dir, &name, &page); de = f2fs_find_entry(dir, &name, &page);
...@@ -73,7 +68,8 @@ static int recover_dentry(struct page *ipage, struct inode *inode) ...@@ -73,7 +68,8 @@ static int recover_dentry(struct page *ipage, struct inode *inode)
einode = f2fs_iget(inode->i_sb, le32_to_cpu(de->ino)); einode = f2fs_iget(inode->i_sb, le32_to_cpu(de->ino));
if (IS_ERR(einode)) { if (IS_ERR(einode)) {
WARN_ON(1); WARN_ON(1);
if (PTR_ERR(einode) == -ENOENT) err = PTR_ERR(einode);
if (err == -ENOENT)
err = -EEXIST; err = -EEXIST;
goto out_unmap_put; goto out_unmap_put;
} }
...@@ -87,11 +83,23 @@ static int recover_dentry(struct page *ipage, struct inode *inode) ...@@ -87,11 +83,23 @@ static int recover_dentry(struct page *ipage, struct inode *inode)
goto retry; goto retry;
} }
err = __f2fs_add_link(dir, &name, inode); err = __f2fs_add_link(dir, &name, inode);
if (err)
goto out_err;
if (is_inode_flag_set(F2FS_I(dir), FI_DELAY_IPUT)) {
iput(dir);
} else {
add_dirty_dir_inode(dir);
set_inode_flag(F2FS_I(dir), FI_DELAY_IPUT);
}
goto out; goto out;
out_unmap_put: out_unmap_put:
kunmap(page); kunmap(page);
f2fs_put_page(page, 0); f2fs_put_page(page, 0);
out_err:
iput(dir);
out: out:
f2fs_msg(inode->i_sb, KERN_NOTICE, f2fs_msg(inode->i_sb, KERN_NOTICE,
"%s: ino = %x, name = %s, dir = %lx, err = %d", "%s: ino = %x, name = %s, dir = %lx, err = %d",
...@@ -299,10 +307,7 @@ static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode, ...@@ -299,10 +307,7 @@ static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode,
goto out; goto out;
start = start_bidx_of_node(ofs_of_node(page), fi); start = start_bidx_of_node(ofs_of_node(page), fi);
if (IS_INODE(page)) end = start + ADDRS_PER_PAGE(page, fi);
end = start + ADDRS_PER_INODE(fi);
else
end = start + ADDRS_PER_BLOCK;
f2fs_lock_op(sbi); f2fs_lock_op(sbi);
......
...@@ -25,7 +25,6 @@ ...@@ -25,7 +25,6 @@
#define __reverse_ffz(x) __reverse_ffs(~(x)) #define __reverse_ffz(x) __reverse_ffs(~(x))
static struct kmem_cache *discard_entry_slab; static struct kmem_cache *discard_entry_slab;
static struct kmem_cache *flush_cmd_slab;
/* /*
* __reverse_ffs is copied from include/asm-generic/bitops/__ffs.h since * __reverse_ffs is copied from include/asm-generic/bitops/__ffs.h since
...@@ -200,20 +199,20 @@ void f2fs_balance_fs_bg(struct f2fs_sb_info *sbi) ...@@ -200,20 +199,20 @@ void f2fs_balance_fs_bg(struct f2fs_sb_info *sbi)
static int issue_flush_thread(void *data) static int issue_flush_thread(void *data)
{ {
struct f2fs_sb_info *sbi = data; struct f2fs_sb_info *sbi = data;
struct f2fs_sm_info *sm_i = SM_I(sbi); struct flush_cmd_control *fcc = SM_I(sbi)->cmd_control_info;
wait_queue_head_t *q = &sm_i->flush_wait_queue; wait_queue_head_t *q = &fcc->flush_wait_queue;
repeat: repeat:
if (kthread_should_stop()) if (kthread_should_stop())
return 0; return 0;
spin_lock(&sm_i->issue_lock); spin_lock(&fcc->issue_lock);
if (sm_i->issue_list) { if (fcc->issue_list) {
sm_i->dispatch_list = sm_i->issue_list; fcc->dispatch_list = fcc->issue_list;
sm_i->issue_list = sm_i->issue_tail = NULL; fcc->issue_list = fcc->issue_tail = NULL;
} }
spin_unlock(&sm_i->issue_lock); spin_unlock(&fcc->issue_lock);
if (sm_i->dispatch_list) { if (fcc->dispatch_list) {
struct bio *bio = bio_alloc(GFP_NOIO, 0); struct bio *bio = bio_alloc(GFP_NOIO, 0);
struct flush_cmd *cmd, *next; struct flush_cmd *cmd, *next;
int ret; int ret;
...@@ -221,47 +220,79 @@ static int issue_flush_thread(void *data) ...@@ -221,47 +220,79 @@ static int issue_flush_thread(void *data)
bio->bi_bdev = sbi->sb->s_bdev; bio->bi_bdev = sbi->sb->s_bdev;
ret = submit_bio_wait(WRITE_FLUSH, bio); ret = submit_bio_wait(WRITE_FLUSH, bio);
for (cmd = sm_i->dispatch_list; cmd; cmd = next) { for (cmd = fcc->dispatch_list; cmd; cmd = next) {
cmd->ret = ret; cmd->ret = ret;
next = cmd->next; next = cmd->next;
complete(&cmd->wait); complete(&cmd->wait);
} }
sm_i->dispatch_list = NULL; bio_put(bio);
fcc->dispatch_list = NULL;
} }
wait_event_interruptible(*q, kthread_should_stop() || sm_i->issue_list); wait_event_interruptible(*q,
kthread_should_stop() || fcc->issue_list);
goto repeat; goto repeat;
} }
int f2fs_issue_flush(struct f2fs_sb_info *sbi) int f2fs_issue_flush(struct f2fs_sb_info *sbi)
{ {
struct f2fs_sm_info *sm_i = SM_I(sbi); struct flush_cmd_control *fcc = SM_I(sbi)->cmd_control_info;
struct flush_cmd *cmd; struct flush_cmd cmd;
int ret;
if (!test_opt(sbi, FLUSH_MERGE)) if (!test_opt(sbi, FLUSH_MERGE))
return blkdev_issue_flush(sbi->sb->s_bdev, GFP_KERNEL, NULL); return blkdev_issue_flush(sbi->sb->s_bdev, GFP_KERNEL, NULL);
cmd = f2fs_kmem_cache_alloc(flush_cmd_slab, GFP_ATOMIC); init_completion(&cmd.wait);
cmd->next = NULL; cmd.next = NULL;
cmd->ret = 0;
init_completion(&cmd->wait);
spin_lock(&sm_i->issue_lock); spin_lock(&fcc->issue_lock);
if (sm_i->issue_list) if (fcc->issue_list)
sm_i->issue_tail->next = cmd; fcc->issue_tail->next = &cmd;
else else
sm_i->issue_list = cmd; fcc->issue_list = &cmd;
sm_i->issue_tail = cmd; fcc->issue_tail = &cmd;
spin_unlock(&sm_i->issue_lock); spin_unlock(&fcc->issue_lock);
if (!fcc->dispatch_list)
wake_up(&fcc->flush_wait_queue);
wait_for_completion(&cmd.wait);
return cmd.ret;
}
if (!sm_i->dispatch_list) int create_flush_cmd_control(struct f2fs_sb_info *sbi)
wake_up(&sm_i->flush_wait_queue); {
dev_t dev = sbi->sb->s_bdev->bd_dev;
struct flush_cmd_control *fcc;
int err = 0;
fcc = kzalloc(sizeof(struct flush_cmd_control), GFP_KERNEL);
if (!fcc)
return -ENOMEM;
spin_lock_init(&fcc->issue_lock);
init_waitqueue_head(&fcc->flush_wait_queue);
fcc->f2fs_issue_flush = kthread_run(issue_flush_thread, sbi,
"f2fs_flush-%u:%u", MAJOR(dev), MINOR(dev));
if (IS_ERR(fcc->f2fs_issue_flush)) {
err = PTR_ERR(fcc->f2fs_issue_flush);
kfree(fcc);
return err;
}
sbi->sm_info->cmd_control_info = fcc;
return err;
}
void destroy_flush_cmd_control(struct f2fs_sb_info *sbi)
{
struct flush_cmd_control *fcc =
sbi->sm_info->cmd_control_info;
wait_for_completion(&cmd->wait); if (fcc && fcc->f2fs_issue_flush)
ret = cmd->ret; kthread_stop(fcc->f2fs_issue_flush);
kmem_cache_free(flush_cmd_slab, cmd); kfree(fcc);
return ret; sbi->sm_info->cmd_control_info = NULL;
} }
static void __locate_dirty_segment(struct f2fs_sb_info *sbi, unsigned int segno, static void __locate_dirty_segment(struct f2fs_sb_info *sbi, unsigned int segno,
...@@ -336,13 +367,26 @@ static void locate_dirty_segment(struct f2fs_sb_info *sbi, unsigned int segno) ...@@ -336,13 +367,26 @@ 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);
} }
static void f2fs_issue_discard(struct f2fs_sb_info *sbi, static int f2fs_issue_discard(struct f2fs_sb_info *sbi,
block_t blkstart, block_t blklen) block_t blkstart, block_t blklen)
{ {
sector_t start = SECTOR_FROM_BLOCK(sbi, blkstart); sector_t start = SECTOR_FROM_BLOCK(sbi, blkstart);
sector_t len = SECTOR_FROM_BLOCK(sbi, blklen); sector_t len = SECTOR_FROM_BLOCK(sbi, blklen);
blkdev_issue_discard(sbi->sb->s_bdev, start, len, GFP_NOFS, 0);
trace_f2fs_issue_discard(sbi->sb, blkstart, blklen); trace_f2fs_issue_discard(sbi->sb, blkstart, blklen);
return blkdev_issue_discard(sbi->sb->s_bdev, start, len, GFP_NOFS, 0);
}
void discard_next_dnode(struct f2fs_sb_info *sbi)
{
struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_WARM_NODE);
block_t blkaddr = NEXT_FREE_BLKADDR(sbi, curseg);
if (f2fs_issue_discard(sbi, blkaddr, 1)) {
struct page *page = grab_meta_page(sbi, blkaddr);
/* zero-filled page */
set_page_dirty(page);
f2fs_put_page(page, 1);
}
} }
static void add_discard_addrs(struct f2fs_sb_info *sbi, static void add_discard_addrs(struct f2fs_sb_info *sbi,
...@@ -1832,7 +1876,6 @@ int build_segment_manager(struct f2fs_sb_info *sbi) ...@@ -1832,7 +1876,6 @@ int build_segment_manager(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_checkpoint *ckpt = F2FS_CKPT(sbi); struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
dev_t dev = sbi->sb->s_bdev->bd_dev;
struct f2fs_sm_info *sm_info; struct f2fs_sm_info *sm_info;
int err; int err;
...@@ -1860,14 +1903,10 @@ int build_segment_manager(struct f2fs_sb_info *sbi) ...@@ -1860,14 +1903,10 @@ int build_segment_manager(struct f2fs_sb_info *sbi)
sm_info->nr_discards = 0; sm_info->nr_discards = 0;
sm_info->max_discards = 0; sm_info->max_discards = 0;
if (test_opt(sbi, FLUSH_MERGE)) { if (test_opt(sbi, FLUSH_MERGE) && !f2fs_readonly(sbi->sb)) {
spin_lock_init(&sm_info->issue_lock); err = create_flush_cmd_control(sbi);
init_waitqueue_head(&sm_info->flush_wait_queue); if (err)
return err;
sm_info->f2fs_issue_flush = kthread_run(issue_flush_thread, sbi,
"f2fs_flush-%u:%u", MAJOR(dev), MINOR(dev));
if (IS_ERR(sm_info->f2fs_issue_flush))
return PTR_ERR(sm_info->f2fs_issue_flush);
} }
err = build_sit_info(sbi); err = build_sit_info(sbi);
...@@ -1976,10 +2015,10 @@ static void destroy_sit_info(struct f2fs_sb_info *sbi) ...@@ -1976,10 +2015,10 @@ static void destroy_sit_info(struct f2fs_sb_info *sbi)
void destroy_segment_manager(struct f2fs_sb_info *sbi) void destroy_segment_manager(struct f2fs_sb_info *sbi)
{ {
struct f2fs_sm_info *sm_info = SM_I(sbi); struct f2fs_sm_info *sm_info = SM_I(sbi);
if (!sm_info) if (!sm_info)
return; return;
if (sm_info->f2fs_issue_flush) destroy_flush_cmd_control(sbi);
kthread_stop(sm_info->f2fs_issue_flush);
destroy_dirty_segmap(sbi); destroy_dirty_segmap(sbi);
destroy_curseg(sbi); destroy_curseg(sbi);
destroy_free_segmap(sbi); destroy_free_segmap(sbi);
...@@ -1994,17 +2033,10 @@ int __init create_segment_manager_caches(void) ...@@ -1994,17 +2033,10 @@ int __init create_segment_manager_caches(void)
sizeof(struct discard_entry)); sizeof(struct discard_entry));
if (!discard_entry_slab) if (!discard_entry_slab)
return -ENOMEM; return -ENOMEM;
flush_cmd_slab = f2fs_kmem_cache_create("flush_command",
sizeof(struct flush_cmd));
if (!flush_cmd_slab) {
kmem_cache_destroy(discard_entry_slab);
return -ENOMEM;
}
return 0; return 0;
} }
void destroy_segment_manager_caches(void) void destroy_segment_manager_caches(void)
{ {
kmem_cache_destroy(discard_entry_slab); kmem_cache_destroy(discard_entry_slab);
kmem_cache_destroy(flush_cmd_slab);
} }
...@@ -514,7 +514,7 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root) ...@@ -514,7 +514,7 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root)
{ {
struct f2fs_sb_info *sbi = F2FS_SB(root->d_sb); struct f2fs_sb_info *sbi = F2FS_SB(root->d_sb);
if (!(root->d_sb->s_flags & MS_RDONLY) && test_opt(sbi, BG_GC)) if (!f2fs_readonly(sbi->sb) && test_opt(sbi, BG_GC))
seq_printf(seq, ",background_gc=%s", "on"); seq_printf(seq, ",background_gc=%s", "on");
else else
seq_printf(seq, ",background_gc=%s", "off"); seq_printf(seq, ",background_gc=%s", "off");
...@@ -542,7 +542,7 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root) ...@@ -542,7 +542,7 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root)
seq_puts(seq, ",disable_ext_identify"); seq_puts(seq, ",disable_ext_identify");
if (test_opt(sbi, INLINE_DATA)) if (test_opt(sbi, INLINE_DATA))
seq_puts(seq, ",inline_data"); seq_puts(seq, ",inline_data");
if (test_opt(sbi, FLUSH_MERGE)) if (!f2fs_readonly(sbi->sb) && test_opt(sbi, FLUSH_MERGE))
seq_puts(seq, ",flush_merge"); seq_puts(seq, ",flush_merge");
seq_printf(seq, ",active_logs=%u", sbi->active_logs); seq_printf(seq, ",active_logs=%u", sbi->active_logs);
...@@ -594,6 +594,8 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data) ...@@ -594,6 +594,8 @@ 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);
struct f2fs_mount_info org_mount_opt; struct f2fs_mount_info org_mount_opt;
int err, active_logs; int err, active_logs;
bool need_restart_gc = false;
bool need_stop_gc = false;
sync_filesystem(sb); sync_filesystem(sb);
...@@ -611,7 +613,7 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data) ...@@ -611,7 +613,7 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data)
/* /*
* Previous and new state of filesystem is RO, * Previous and new state of filesystem is RO,
* so no point in checking GC conditions. * so skip checking GC and FLUSH_MERGE conditions.
*/ */
if ((sb->s_flags & MS_RDONLY) && (*flags & MS_RDONLY)) if ((sb->s_flags & MS_RDONLY) && (*flags & MS_RDONLY))
goto skip; goto skip;
...@@ -625,18 +627,40 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data) ...@@ -625,18 +627,40 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data)
if (sbi->gc_thread) { if (sbi->gc_thread) {
stop_gc_thread(sbi); stop_gc_thread(sbi);
f2fs_sync_fs(sb, 1); f2fs_sync_fs(sb, 1);
need_restart_gc = true;
} }
} else if (test_opt(sbi, BG_GC) && !sbi->gc_thread) { } else if (test_opt(sbi, BG_GC) && !sbi->gc_thread) {
err = start_gc_thread(sbi); err = start_gc_thread(sbi);
if (err) if (err)
goto restore_opts; goto restore_opts;
need_stop_gc = true;
}
/*
* We stop issue flush thread if FS is mounted as RO
* or if flush_merge is not passed in mount option.
*/
if ((*flags & MS_RDONLY) || !test_opt(sbi, FLUSH_MERGE)) {
destroy_flush_cmd_control(sbi);
} else if (test_opt(sbi, FLUSH_MERGE) &&
!sbi->sm_info->cmd_control_info) {
err = create_flush_cmd_control(sbi);
if (err)
goto restore_gc;
} }
skip: skip:
/* Update the POSIXACL Flag */ /* Update the POSIXACL Flag */
sb->s_flags = (sb->s_flags & ~MS_POSIXACL) | sb->s_flags = (sb->s_flags & ~MS_POSIXACL) |
(test_opt(sbi, POSIX_ACL) ? MS_POSIXACL : 0); (test_opt(sbi, POSIX_ACL) ? MS_POSIXACL : 0);
return 0; return 0;
restore_gc:
if (need_restart_gc) {
if (start_gc_thread(sbi))
f2fs_msg(sbi->sb, KERN_WARNING,
"background gc thread is stop");
} else if (need_stop_gc) {
stop_gc_thread(sbi);
}
restore_opts: restore_opts:
sbi->mount_opt = org_mount_opt; sbi->mount_opt = org_mount_opt;
sbi->active_logs = active_logs; sbi->active_logs = active_logs;
......
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
#include "xattr.h" #include "xattr.h"
static size_t f2fs_xattr_generic_list(struct dentry *dentry, char *list, static size_t f2fs_xattr_generic_list(struct dentry *dentry, char *list,
size_t list_size, const char *name, size_t name_len, int type) size_t list_size, const char *name, size_t len, int type)
{ {
struct f2fs_sb_info *sbi = F2FS_SB(dentry->d_sb); struct f2fs_sb_info *sbi = F2FS_SB(dentry->d_sb);
int total_len, prefix_len = 0; int total_len, prefix_len = 0;
...@@ -53,11 +53,11 @@ static size_t f2fs_xattr_generic_list(struct dentry *dentry, char *list, ...@@ -53,11 +53,11 @@ static size_t f2fs_xattr_generic_list(struct dentry *dentry, char *list,
return -EINVAL; return -EINVAL;
} }
total_len = prefix_len + name_len + 1; total_len = prefix_len + len + 1;
if (list && total_len <= list_size) { if (list && total_len <= list_size) {
memcpy(list, prefix, prefix_len); memcpy(list, prefix, prefix_len);
memcpy(list + prefix_len, name, name_len); memcpy(list + prefix_len, name, len);
list[prefix_len + name_len] = '\0'; list[prefix_len + len] = '\0';
} }
return total_len; return total_len;
} }
...@@ -108,11 +108,12 @@ static int f2fs_xattr_generic_set(struct dentry *dentry, const char *name, ...@@ -108,11 +108,12 @@ static int f2fs_xattr_generic_set(struct dentry *dentry, const char *name,
if (strcmp(name, "") == 0) if (strcmp(name, "") == 0)
return -EINVAL; return -EINVAL;
return f2fs_setxattr(dentry->d_inode, type, name, value, size, NULL); return f2fs_setxattr(dentry->d_inode, type, name,
value, size, NULL, flags);
} }
static size_t f2fs_xattr_advise_list(struct dentry *dentry, char *list, static size_t f2fs_xattr_advise_list(struct dentry *dentry, char *list,
size_t list_size, const char *name, size_t name_len, int type) size_t list_size, const char *name, size_t len, int type)
{ {
const char *xname = F2FS_SYSTEM_ADVISE_PREFIX; const char *xname = F2FS_SYSTEM_ADVISE_PREFIX;
size_t size; size_t size;
...@@ -155,9 +156,6 @@ static int f2fs_xattr_advise_set(struct dentry *dentry, const char *name, ...@@ -155,9 +156,6 @@ static int f2fs_xattr_advise_set(struct dentry *dentry, const char *name,
} }
#ifdef CONFIG_F2FS_FS_SECURITY #ifdef CONFIG_F2FS_FS_SECURITY
static int __f2fs_setxattr(struct inode *inode, int name_index,
const char *name, const void *value, size_t value_len,
struct page *ipage);
static int f2fs_initxattrs(struct inode *inode, const struct xattr *xattr_array, static int f2fs_initxattrs(struct inode *inode, const struct xattr *xattr_array,
void *page) void *page)
{ {
...@@ -165,9 +163,9 @@ static int f2fs_initxattrs(struct inode *inode, const struct xattr *xattr_array, ...@@ -165,9 +163,9 @@ static int f2fs_initxattrs(struct inode *inode, const struct xattr *xattr_array,
int err = 0; int err = 0;
for (xattr = xattr_array; xattr->name != NULL; xattr++) { for (xattr = xattr_array; xattr->name != NULL; xattr++) {
err = __f2fs_setxattr(inode, F2FS_XATTR_INDEX_SECURITY, err = f2fs_setxattr(inode, F2FS_XATTR_INDEX_SECURITY,
xattr->name, xattr->value, xattr->name, xattr->value,
xattr->value_len, (struct page *)page); xattr->value_len, (struct page *)page, 0);
if (err < 0) if (err < 0)
break; break;
} }
...@@ -241,26 +239,26 @@ const struct xattr_handler *f2fs_xattr_handlers[] = { ...@@ -241,26 +239,26 @@ const struct xattr_handler *f2fs_xattr_handlers[] = {
NULL, NULL,
}; };
static inline const struct xattr_handler *f2fs_xattr_handler(int name_index) static inline const struct xattr_handler *f2fs_xattr_handler(int index)
{ {
const struct xattr_handler *handler = NULL; const struct xattr_handler *handler = NULL;
if (name_index > 0 && name_index < ARRAY_SIZE(f2fs_xattr_handler_map)) if (index > 0 && index < ARRAY_SIZE(f2fs_xattr_handler_map))
handler = f2fs_xattr_handler_map[name_index]; handler = f2fs_xattr_handler_map[index];
return handler; return handler;
} }
static struct f2fs_xattr_entry *__find_xattr(void *base_addr, int name_index, static struct f2fs_xattr_entry *__find_xattr(void *base_addr, int index,
size_t name_len, const char *name) size_t len, const char *name)
{ {
struct f2fs_xattr_entry *entry; struct f2fs_xattr_entry *entry;
list_for_each_xattr(entry, base_addr) { list_for_each_xattr(entry, base_addr) {
if (entry->e_name_index != name_index) if (entry->e_name_index != index)
continue; continue;
if (entry->e_name_len != name_len) if (entry->e_name_len != len)
continue; continue;
if (!memcmp(entry->e_name, name, name_len)) if (!memcmp(entry->e_name, name, len))
break; break;
} }
return entry; return entry;
...@@ -347,6 +345,7 @@ static inline int write_all_xattrs(struct inode *inode, __u32 hsize, ...@@ -347,6 +345,7 @@ static inline int write_all_xattrs(struct inode *inode, __u32 hsize,
if (ipage) { if (ipage) {
inline_addr = inline_xattr_addr(ipage); inline_addr = inline_xattr_addr(ipage);
f2fs_wait_on_page_writeback(ipage, NODE);
} else { } else {
page = get_node_page(sbi, inode->i_ino); page = get_node_page(sbi, inode->i_ino);
if (IS_ERR(page)) { if (IS_ERR(page)) {
...@@ -354,6 +353,7 @@ static inline int write_all_xattrs(struct inode *inode, __u32 hsize, ...@@ -354,6 +353,7 @@ static inline int write_all_xattrs(struct inode *inode, __u32 hsize,
return PTR_ERR(page); return PTR_ERR(page);
} }
inline_addr = inline_xattr_addr(page); inline_addr = inline_xattr_addr(page);
f2fs_wait_on_page_writeback(page, NODE);
} }
memcpy(inline_addr, txattr_addr, inline_size); memcpy(inline_addr, txattr_addr, inline_size);
f2fs_put_page(page, 1); f2fs_put_page(page, 1);
...@@ -374,6 +374,7 @@ static inline int write_all_xattrs(struct inode *inode, __u32 hsize, ...@@ -374,6 +374,7 @@ static inline int write_all_xattrs(struct inode *inode, __u32 hsize,
return PTR_ERR(xpage); return PTR_ERR(xpage);
} }
f2fs_bug_on(new_nid); f2fs_bug_on(new_nid);
f2fs_wait_on_page_writeback(xpage, NODE);
} else { } else {
struct dnode_of_data dn; struct dnode_of_data dn;
set_new_dnode(&dn, inode, NULL, NULL, new_nid); set_new_dnode(&dn, inode, NULL, NULL, new_nid);
...@@ -396,42 +397,43 @@ static inline int write_all_xattrs(struct inode *inode, __u32 hsize, ...@@ -396,42 +397,43 @@ static inline int write_all_xattrs(struct inode *inode, __u32 hsize,
return 0; return 0;
} }
int f2fs_getxattr(struct inode *inode, int name_index, const char *name, int f2fs_getxattr(struct inode *inode, int index, const char *name,
void *buffer, size_t buffer_size) void *buffer, size_t buffer_size)
{ {
struct f2fs_xattr_entry *entry; struct f2fs_xattr_entry *entry;
void *base_addr; void *base_addr;
int error = 0; int error = 0;
size_t value_len, name_len; size_t size, len;
if (name == NULL) if (name == NULL)
return -EINVAL; return -EINVAL;
name_len = strlen(name);
if (name_len > F2FS_NAME_LEN) len = strlen(name);
if (len > F2FS_NAME_LEN)
return -ERANGE; return -ERANGE;
base_addr = read_all_xattrs(inode, NULL); base_addr = read_all_xattrs(inode, NULL);
if (!base_addr) if (!base_addr)
return -ENOMEM; return -ENOMEM;
entry = __find_xattr(base_addr, name_index, name_len, name); entry = __find_xattr(base_addr, index, len, name);
if (IS_XATTR_LAST_ENTRY(entry)) { if (IS_XATTR_LAST_ENTRY(entry)) {
error = -ENODATA; error = -ENODATA;
goto cleanup; goto cleanup;
} }
value_len = le16_to_cpu(entry->e_value_size); size = le16_to_cpu(entry->e_value_size);
if (buffer && value_len > buffer_size) { if (buffer && size > buffer_size) {
error = -ERANGE; error = -ERANGE;
goto cleanup; goto cleanup;
} }
if (buffer) { if (buffer) {
char *pval = entry->e_name + entry->e_name_len; char *pval = entry->e_name + entry->e_name_len;
memcpy(buffer, pval, value_len); memcpy(buffer, pval, size);
} }
error = value_len; error = size;
cleanup: cleanup:
kzfree(base_addr); kzfree(base_addr);
...@@ -475,15 +477,15 @@ ssize_t f2fs_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size) ...@@ -475,15 +477,15 @@ ssize_t f2fs_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size)
return error; return error;
} }
static int __f2fs_setxattr(struct inode *inode, int name_index, static int __f2fs_setxattr(struct inode *inode, int index,
const char *name, const void *value, size_t value_len, const char *name, const void *value, size_t size,
struct page *ipage) struct page *ipage, int flags)
{ {
struct f2fs_inode_info *fi = F2FS_I(inode); struct f2fs_inode_info *fi = F2FS_I(inode);
struct f2fs_xattr_entry *here, *last; struct f2fs_xattr_entry *here, *last;
void *base_addr; void *base_addr;
int found, newsize; int found, newsize;
size_t name_len; size_t len;
__u32 new_hsize; __u32 new_hsize;
int error = -ENOMEM; int error = -ENOMEM;
...@@ -491,11 +493,11 @@ static int __f2fs_setxattr(struct inode *inode, int name_index, ...@@ -491,11 +493,11 @@ static int __f2fs_setxattr(struct inode *inode, int name_index,
return -EINVAL; return -EINVAL;
if (value == NULL) if (value == NULL)
value_len = 0; size = 0;
name_len = strlen(name); len = strlen(name);
if (name_len > F2FS_NAME_LEN || value_len > MAX_VALUE_LEN(inode)) if (len > F2FS_NAME_LEN || size > MAX_VALUE_LEN(inode))
return -ERANGE; return -ERANGE;
base_addr = read_all_xattrs(inode, ipage); base_addr = read_all_xattrs(inode, ipage);
...@@ -503,16 +505,23 @@ static int __f2fs_setxattr(struct inode *inode, int name_index, ...@@ -503,16 +505,23 @@ static int __f2fs_setxattr(struct inode *inode, int name_index,
goto exit; goto exit;
/* find entry with wanted name. */ /* find entry with wanted name. */
here = __find_xattr(base_addr, name_index, name_len, name); here = __find_xattr(base_addr, index, len, name);
found = IS_XATTR_LAST_ENTRY(here) ? 0 : 1; found = IS_XATTR_LAST_ENTRY(here) ? 0 : 1;
last = here;
if ((flags & XATTR_REPLACE) && !found) {
error = -ENODATA;
goto exit;
} else if ((flags & XATTR_CREATE) && found) {
error = -EEXIST;
goto exit;
}
last = here;
while (!IS_XATTR_LAST_ENTRY(last)) while (!IS_XATTR_LAST_ENTRY(last))
last = XATTR_NEXT_ENTRY(last); last = XATTR_NEXT_ENTRY(last);
newsize = XATTR_ALIGN(sizeof(struct f2fs_xattr_entry) + newsize = XATTR_ALIGN(sizeof(struct f2fs_xattr_entry) + len + size);
name_len + value_len);
/* 1. Check space */ /* 1. Check space */
if (value) { if (value) {
...@@ -555,12 +564,12 @@ static int __f2fs_setxattr(struct inode *inode, int name_index, ...@@ -555,12 +564,12 @@ static int __f2fs_setxattr(struct inode *inode, int name_index,
* We just write new entry. * We just write new entry.
*/ */
memset(last, 0, newsize); memset(last, 0, newsize);
last->e_name_index = name_index; last->e_name_index = index;
last->e_name_len = name_len; last->e_name_len = len;
memcpy(last->e_name, name, name_len); memcpy(last->e_name, name, len);
pval = last->e_name + name_len; pval = last->e_name + len;
memcpy(pval, value, value_len); memcpy(pval, value, size);
last->e_value_size = cpu_to_le16(value_len); last->e_value_size = cpu_to_le16(size);
new_hsize += newsize; new_hsize += newsize;
} }
...@@ -583,18 +592,23 @@ static int __f2fs_setxattr(struct inode *inode, int name_index, ...@@ -583,18 +592,23 @@ static int __f2fs_setxattr(struct inode *inode, int name_index,
return error; return error;
} }
int f2fs_setxattr(struct inode *inode, int name_index, const char *name, int f2fs_setxattr(struct inode *inode, int index, const char *name,
const void *value, size_t value_len, struct page *ipage) const void *value, size_t size,
struct page *ipage, int flags)
{ {
struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
int err; int err;
/* this case is only from init_inode_metadata */
if (ipage)
return __f2fs_setxattr(inode, index, name, value,
size, ipage, flags);
f2fs_balance_fs(sbi); f2fs_balance_fs(sbi);
f2fs_lock_op(sbi); f2fs_lock_op(sbi);
/* protect xattr_ver */ /* protect xattr_ver */
down_write(&F2FS_I(inode)->i_sem); down_write(&F2FS_I(inode)->i_sem);
err = __f2fs_setxattr(inode, name_index, name, value, value_len, ipage); err = __f2fs_setxattr(inode, index, name, value, size, ipage, flags);
up_write(&F2FS_I(inode)->i_sem); up_write(&F2FS_I(inode)->i_sem);
f2fs_unlock_op(sbi); f2fs_unlock_op(sbi);
......
...@@ -114,18 +114,18 @@ extern const struct xattr_handler f2fs_xattr_security_handler; ...@@ -114,18 +114,18 @@ extern const struct xattr_handler f2fs_xattr_security_handler;
extern const struct xattr_handler *f2fs_xattr_handlers[]; extern const struct xattr_handler *f2fs_xattr_handlers[];
extern int f2fs_setxattr(struct inode *, int, const char *, extern int f2fs_setxattr(struct inode *, int, const char *,
const void *, size_t, struct page *); const void *, size_t, struct page *, int);
extern int f2fs_getxattr(struct inode *, int, const char *, void *, size_t); extern int f2fs_getxattr(struct inode *, int, const char *, void *, size_t);
extern ssize_t f2fs_listxattr(struct dentry *, char *, size_t); extern ssize_t f2fs_listxattr(struct dentry *, char *, size_t);
#else #else
#define f2fs_xattr_handlers NULL #define f2fs_xattr_handlers NULL
static inline int f2fs_setxattr(struct inode *inode, int name_index, static inline int f2fs_setxattr(struct inode *inode, int index,
const char *name, const void *value, size_t value_len) const char *name, const void *value, size_t size, int flags)
{ {
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
static inline int f2fs_getxattr(struct inode *inode, int name_index, static inline int f2fs_getxattr(struct inode *inode, int index,
const char *name, void *buffer, size_t buffer_size) const char *name, void *buffer, size_t buffer_size)
{ {
return -EOPNOTSUPP; return -EOPNOTSUPP;
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#define F2FS_LOG_SECTORS_PER_BLOCK 3 /* 4KB: F2FS_BLKSIZE */ #define F2FS_LOG_SECTORS_PER_BLOCK 3 /* 4KB: F2FS_BLKSIZE */
#define F2FS_BLKSIZE 4096 /* support only 4KB block */ #define F2FS_BLKSIZE 4096 /* support only 4KB block */
#define F2FS_MAX_EXTENSION 64 /* # of extension entries */ #define F2FS_MAX_EXTENSION 64 /* # of extension entries */
#define F2FS_BLK_ALIGN(x) (((x) + F2FS_BLKSIZE - 1) / F2FS_BLKSIZE)
#define NULL_ADDR ((block_t)0) /* used as block_t addresses */ #define NULL_ADDR ((block_t)0) /* used as block_t addresses */
#define NEW_ADDR ((block_t)-1) /* used as block_t addresses */ #define NEW_ADDR ((block_t)-1) /* used as block_t addresses */
...@@ -75,6 +76,7 @@ struct f2fs_super_block { ...@@ -75,6 +76,7 @@ struct f2fs_super_block {
__le16 volume_name[512]; /* volume name */ __le16 volume_name[512]; /* volume name */
__le32 extension_count; /* # of extensions below */ __le32 extension_count; /* # of extensions below */
__u8 extension_list[F2FS_MAX_EXTENSION][8]; /* extension array */ __u8 extension_list[F2FS_MAX_EXTENSION][8]; /* extension array */
__le32 cp_payload;
} __packed; } __packed;
/* /*
...@@ -146,6 +148,9 @@ struct f2fs_extent { ...@@ -146,6 +148,9 @@ struct f2fs_extent {
#define ADDRS_PER_BLOCK 1018 /* Address Pointers in a Direct Block */ #define ADDRS_PER_BLOCK 1018 /* Address Pointers in a Direct Block */
#define NIDS_PER_BLOCK 1018 /* Node IDs in an Indirect Block */ #define NIDS_PER_BLOCK 1018 /* Node IDs in an Indirect Block */
#define ADDRS_PER_PAGE(page, fi) \
(IS_INODE(page) ? ADDRS_PER_INODE(fi) : ADDRS_PER_BLOCK)
#define NODE_DIR1_BLOCK (DEF_ADDRS_PER_INODE + 1) #define NODE_DIR1_BLOCK (DEF_ADDRS_PER_INODE + 1)
#define NODE_DIR2_BLOCK (DEF_ADDRS_PER_INODE + 2) #define NODE_DIR2_BLOCK (DEF_ADDRS_PER_INODE + 2)
#define NODE_IND1_BLOCK (DEF_ADDRS_PER_INODE + 3) #define NODE_IND1_BLOCK (DEF_ADDRS_PER_INODE + 3)
...@@ -391,6 +396,9 @@ typedef __le32 f2fs_hash_t; ...@@ -391,6 +396,9 @@ typedef __le32 f2fs_hash_t;
/* MAX level for dir lookup */ /* MAX level for dir lookup */
#define MAX_DIR_HASH_DEPTH 63 #define MAX_DIR_HASH_DEPTH 63
/* MAX buckets in one level of dir */
#define MAX_DIR_BUCKETS (1 << ((MAX_DIR_HASH_DEPTH / 2) - 1))
#define SIZE_OF_DIR_ENTRY 11 /* by byte */ #define SIZE_OF_DIR_ENTRY 11 /* by byte */
#define SIZE_OF_DENTRY_BITMAP ((NR_DENTRY_IN_BLOCK + BITS_PER_BYTE - 1) / \ #define SIZE_OF_DENTRY_BITMAP ((NR_DENTRY_IN_BLOCK + BITS_PER_BYTE - 1) / \
BITS_PER_BYTE) BITS_PER_BYTE)
......
...@@ -659,6 +659,66 @@ DEFINE_EVENT_CONDITION(f2fs__submit_bio, f2fs_submit_read_bio, ...@@ -659,6 +659,66 @@ DEFINE_EVENT_CONDITION(f2fs__submit_bio, f2fs_submit_read_bio,
TP_CONDITION(bio) TP_CONDITION(bio)
); );
TRACE_EVENT(f2fs_write_begin,
TP_PROTO(struct inode *inode, loff_t pos, unsigned int len,
unsigned int flags),
TP_ARGS(inode, pos, len, flags),
TP_STRUCT__entry(
__field(dev_t, dev)
__field(ino_t, ino)
__field(loff_t, pos)
__field(unsigned int, len)
__field(unsigned int, flags)
),
TP_fast_assign(
__entry->dev = inode->i_sb->s_dev;
__entry->ino = inode->i_ino;
__entry->pos = pos;
__entry->len = len;
__entry->flags = flags;
),
TP_printk("dev = (%d,%d), ino = %lu, pos = %llu, len = %u, flags = %u",
show_dev_ino(__entry),
(unsigned long long)__entry->pos,
__entry->len,
__entry->flags)
);
TRACE_EVENT(f2fs_write_end,
TP_PROTO(struct inode *inode, loff_t pos, unsigned int len,
unsigned int copied),
TP_ARGS(inode, pos, len, copied),
TP_STRUCT__entry(
__field(dev_t, dev)
__field(ino_t, ino)
__field(loff_t, pos)
__field(unsigned int, len)
__field(unsigned int, copied)
),
TP_fast_assign(
__entry->dev = inode->i_sb->s_dev;
__entry->ino = inode->i_ino;
__entry->pos = pos;
__entry->len = len;
__entry->copied = copied;
),
TP_printk("dev = (%d,%d), ino = %lu, pos = %llu, len = %u, copied = %u",
show_dev_ino(__entry),
(unsigned long long)__entry->pos,
__entry->len,
__entry->copied)
);
DECLARE_EVENT_CLASS(f2fs__page, DECLARE_EVENT_CLASS(f2fs__page,
TP_PROTO(struct page *page, int type), TP_PROTO(struct page *page, int type),
...@@ -672,6 +732,7 @@ DECLARE_EVENT_CLASS(f2fs__page, ...@@ -672,6 +732,7 @@ DECLARE_EVENT_CLASS(f2fs__page,
__field(int, dir) __field(int, dir)
__field(pgoff_t, index) __field(pgoff_t, index)
__field(int, dirty) __field(int, dirty)
__field(int, uptodate)
), ),
TP_fast_assign( TP_fast_assign(
...@@ -681,14 +742,31 @@ DECLARE_EVENT_CLASS(f2fs__page, ...@@ -681,14 +742,31 @@ DECLARE_EVENT_CLASS(f2fs__page,
__entry->dir = S_ISDIR(page->mapping->host->i_mode); __entry->dir = S_ISDIR(page->mapping->host->i_mode);
__entry->index = page->index; __entry->index = page->index;
__entry->dirty = PageDirty(page); __entry->dirty = PageDirty(page);
__entry->uptodate = PageUptodate(page);
), ),
TP_printk("dev = (%d,%d), ino = %lu, %s, %s, index = %lu, dirty = %d", TP_printk("dev = (%d,%d), ino = %lu, %s, %s, index = %lu, "
"dirty = %d, uptodate = %d",
show_dev_ino(__entry), show_dev_ino(__entry),
show_block_type(__entry->type), show_block_type(__entry->type),
show_file_type(__entry->dir), show_file_type(__entry->dir),
(unsigned long)__entry->index, (unsigned long)__entry->index,
__entry->dirty) __entry->dirty,
__entry->uptodate)
);
DEFINE_EVENT(f2fs__page, f2fs_writepage,
TP_PROTO(struct page *page, int type),
TP_ARGS(page, type)
);
DEFINE_EVENT(f2fs__page, f2fs_readpage,
TP_PROTO(struct page *page, int type),
TP_ARGS(page, type)
); );
DEFINE_EVENT(f2fs__page, f2fs_set_page_dirty, DEFINE_EVENT(f2fs__page, f2fs_set_page_dirty,
...@@ -705,6 +783,70 @@ DEFINE_EVENT(f2fs__page, f2fs_vm_page_mkwrite, ...@@ -705,6 +783,70 @@ DEFINE_EVENT(f2fs__page, f2fs_vm_page_mkwrite,
TP_ARGS(page, type) TP_ARGS(page, type)
); );
TRACE_EVENT(f2fs_writepages,
TP_PROTO(struct inode *inode, struct writeback_control *wbc, int type),
TP_ARGS(inode, wbc, type),
TP_STRUCT__entry(
__field(dev_t, dev)
__field(ino_t, ino)
__field(int, type)
__field(int, dir)
__field(long, nr_to_write)
__field(long, pages_skipped)
__field(loff_t, range_start)
__field(loff_t, range_end)
__field(pgoff_t, writeback_index)
__field(int, sync_mode)
__field(char, for_kupdate)
__field(char, for_background)
__field(char, tagged_writepages)
__field(char, for_reclaim)
__field(char, range_cyclic)
__field(char, for_sync)
),
TP_fast_assign(
__entry->dev = inode->i_sb->s_dev;
__entry->ino = inode->i_ino;
__entry->type = type;
__entry->dir = S_ISDIR(inode->i_mode);
__entry->nr_to_write = wbc->nr_to_write;
__entry->pages_skipped = wbc->pages_skipped;
__entry->range_start = wbc->range_start;
__entry->range_end = wbc->range_end;
__entry->writeback_index = inode->i_mapping->writeback_index;
__entry->sync_mode = wbc->sync_mode;
__entry->for_kupdate = wbc->for_kupdate;
__entry->for_background = wbc->for_background;
__entry->tagged_writepages = wbc->tagged_writepages;
__entry->for_reclaim = wbc->for_reclaim;
__entry->range_cyclic = wbc->range_cyclic;
__entry->for_sync = wbc->for_sync;
),
TP_printk("dev = (%d,%d), ino = %lu, %s, %s, nr_to_write %ld, "
"skipped %ld, start %lld, end %lld, wb_idx %lu, sync_mode %d, "
"kupdate %u background %u tagged %u reclaim %u cyclic %u sync %u",
show_dev_ino(__entry),
show_block_type(__entry->type),
show_file_type(__entry->dir),
__entry->nr_to_write,
__entry->pages_skipped,
__entry->range_start,
__entry->range_end,
(unsigned long)__entry->writeback_index,
__entry->sync_mode,
__entry->for_kupdate,
__entry->for_background,
__entry->tagged_writepages,
__entry->for_reclaim,
__entry->range_cyclic,
__entry->for_sync)
);
TRACE_EVENT(f2fs_submit_page_mbio, TRACE_EVENT(f2fs_submit_page_mbio,
TP_PROTO(struct page *page, int rw, int type, block_t blk_addr), TP_PROTO(struct page *page, int rw, int type, block_t blk_addr),
......
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