Skip to content

Commit

Permalink
Merge tag 'for-f2fs-3.11' of git://git.kernel.org/pub/scm/linux/kerne…
Browse files Browse the repository at this point in the history
…l/git/jaegeuk/f2fs

Pull f2fs updates from Jaegeuk Kim:
 "This patch-set includes the following major enhancement patches:
   - remount_fs callback function
   - restore parent inode number to enhance the fsync performance
   - xattr security labels
   - reduce the number of redundant lock/unlock data pages
   - avoid frequent write_inode calls

  The other minor bug fixes are as follows.
   - endian conversion bugs
   - various bugs in the roll-forward recovery routine"

* tag 'for-f2fs-3.11' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs: (56 commits)
  f2fs: fix to recover i_size from roll-forward
  f2fs: remove the unused argument "sbi" of func destroy_fsync_dnodes()
  f2fs: remove reusing any prefree segments
  f2fs: code cleanup and simplify in func {find/add}_gc_inode
  f2fs: optimize the init_dirty_segmap function
  f2fs: fix an endian conversion bug detected by sparse
  f2fs: fix crc endian conversion
  f2fs: add remount_fs callback support
  f2fs: recover wrong pino after checkpoint during fsync
  f2fs: optimize do_write_data_page()
  f2fs: make locate_dirty_segment() as static
  f2fs: remove unnecessary parameter "offset" from __add_sum_entry()
  f2fs: avoid freqeunt write_inode calls
  f2fs: optimise the truncate_data_blocks_range() range
  f2fs: use the F2FS specific flags in f2fs_ioctl()
  f2fs: sync dir->i_size with its block allocation
  f2fs: fix i_blocks translation on various types of files
  f2fs: set sb->s_fs_info before calling parse_options()
  f2fs: support xattr security labels
  f2fs: fix iget/iput of dir during recovery
  ...
  • Loading branch information
torvalds committed Jul 2, 2013
2 parents c4eb1b0 + a1dd3c1 commit 3f490f7
Show file tree
Hide file tree
Showing 20 changed files with 750 additions and 451 deletions.
9 changes: 7 additions & 2 deletions Documentation/filesystems/f2fs.txt
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,13 @@ Cleaning Overhead
MOUNT OPTIONS
================================================================================

background_gc_off Turn off cleaning operations, namely garbage collection,
triggered in background when I/O subsystem is idle.
background_gc=%s Turn on/off cleaning operations, namely garbage
collection, triggered in background when I/O subsystem is
idle. If background_gc=on, it will turn on the garbage
collection and if background_gc=off, garbage collection
will be truned off.
Default value for this option is on. So garbage
collection is on by default.
disable_roll_forward Disable the roll-forward recovery routine
discard Issue discard/TRIM commands when a segment is cleaned.
no_heap Disable heap-style segment allocation which finds free
Expand Down
12 changes: 12 additions & 0 deletions fs/f2fs/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,15 @@ config F2FS_FS_POSIX_ACL
Linux website <http://acl.bestbits.at/>.

If you don't know what Access Control Lists are, say N

config F2FS_FS_SECURITY
bool "F2FS Security Labels"
depends on F2FS_FS_XATTR
help
Security labels provide an access control facility to support Linux
Security Models (LSMs) accepted by AppArmor, SELinux, Smack and TOMOYO
Linux. This option enables an extended attribute handler for file
security labels in the f2fs filesystem, so that it requires enabling
the extended attribute support in advance.

If you are not using a security module, say N.
2 changes: 1 addition & 1 deletion fs/f2fs/acl.c
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ static int f2fs_set_acl(struct inode *inode, int type, struct posix_acl *acl)
}
}

error = f2fs_setxattr(inode, name_index, "", value, size);
error = f2fs_setxattr(inode, name_index, "", value, size, NULL);

kfree(value);
if (!error)
Expand Down
99 changes: 76 additions & 23 deletions fs/f2fs/checkpoint.c
Original file line number Diff line number Diff line change
Expand Up @@ -357,8 +357,8 @@ static struct page *validate_checkpoint(struct f2fs_sb_info *sbi,
unsigned long blk_size = sbi->blocksize;
struct f2fs_checkpoint *cp_block;
unsigned long long cur_version = 0, pre_version = 0;
unsigned int crc = 0;
size_t crc_offset;
__u32 crc = 0;

/* Read the 1st cp block in this CP pack */
cp_page_1 = get_meta_page(sbi, cp_addr);
Expand All @@ -369,7 +369,7 @@ static struct page *validate_checkpoint(struct f2fs_sb_info *sbi,
if (crc_offset >= blk_size)
goto invalid_cp1;

crc = *(unsigned int *)((unsigned char *)cp_block + crc_offset);
crc = le32_to_cpu(*((__u32 *)((unsigned char *)cp_block + crc_offset)));
if (!f2fs_crc_valid(crc, cp_block, crc_offset))
goto invalid_cp1;

Expand All @@ -384,7 +384,7 @@ static struct page *validate_checkpoint(struct f2fs_sb_info *sbi,
if (crc_offset >= blk_size)
goto invalid_cp2;

crc = *(unsigned int *)((unsigned char *)cp_block + crc_offset);
crc = le32_to_cpu(*((__u32 *)((unsigned char *)cp_block + crc_offset)));
if (!f2fs_crc_valid(crc, cp_block, crc_offset))
goto invalid_cp2;

Expand Down Expand Up @@ -450,13 +450,30 @@ int get_valid_checkpoint(struct f2fs_sb_info *sbi)
return -EINVAL;
}

void set_dirty_dir_page(struct inode *inode, struct page *page)
static int __add_dirty_inode(struct inode *inode, struct dir_inode_entry *new)
{
struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
struct list_head *head = &sbi->dir_inode_list;
struct dir_inode_entry *new;
struct list_head *this;

list_for_each(this, head) {
struct dir_inode_entry *entry;
entry = list_entry(this, struct dir_inode_entry, list);
if (entry->inode == inode)
return -EEXIST;
}
list_add_tail(&new->list, head);
#ifdef CONFIG_F2FS_STAT_FS
sbi->n_dirty_dirs++;
#endif
return 0;
}

void set_dirty_dir_page(struct inode *inode, struct page *page)
{
struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
struct dir_inode_entry *new;

if (!S_ISDIR(inode->i_mode))
return;
retry:
Expand All @@ -469,23 +486,31 @@ void set_dirty_dir_page(struct inode *inode, struct page *page)
INIT_LIST_HEAD(&new->list);

spin_lock(&sbi->dir_inode_lock);
list_for_each(this, head) {
struct dir_inode_entry *entry;
entry = list_entry(this, struct dir_inode_entry, list);
if (entry->inode == inode) {
kmem_cache_free(inode_entry_slab, new);
goto out;
}
}
list_add_tail(&new->list, head);
sbi->n_dirty_dirs++;
if (__add_dirty_inode(inode, new))
kmem_cache_free(inode_entry_slab, new);

BUG_ON(!S_ISDIR(inode->i_mode));
out:
inc_page_count(sbi, F2FS_DIRTY_DENTS);
inode_inc_dirty_dents(inode);
SetPagePrivate(page);
spin_unlock(&sbi->dir_inode_lock);
}

void add_dirty_dir_inode(struct inode *inode)
{
struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
struct dir_inode_entry *new;
retry:
new = kmem_cache_alloc(inode_entry_slab, GFP_NOFS);
if (!new) {
cond_resched();
goto retry;
}
new->inode = inode;
INIT_LIST_HEAD(&new->list);

spin_lock(&sbi->dir_inode_lock);
if (__add_dirty_inode(inode, new))
kmem_cache_free(inode_entry_slab, new);
spin_unlock(&sbi->dir_inode_lock);
}

Expand All @@ -499,21 +524,49 @@ void remove_dirty_dir_inode(struct inode *inode)
return;

spin_lock(&sbi->dir_inode_lock);
if (atomic_read(&F2FS_I(inode)->dirty_dents))
goto out;
if (atomic_read(&F2FS_I(inode)->dirty_dents)) {
spin_unlock(&sbi->dir_inode_lock);
return;
}

list_for_each(this, head) {
struct dir_inode_entry *entry;
entry = list_entry(this, struct dir_inode_entry, list);
if (entry->inode == inode) {
list_del(&entry->list);
kmem_cache_free(inode_entry_slab, entry);
#ifdef CONFIG_F2FS_STAT_FS
sbi->n_dirty_dirs--;
#endif
break;
}
}
spin_unlock(&sbi->dir_inode_lock);

/* Only from the recovery routine */
if (is_inode_flag_set(F2FS_I(inode), FI_DELAY_IPUT)) {
clear_inode_flag(F2FS_I(inode), FI_DELAY_IPUT);
iput(inode);
}
}

struct inode *check_dirty_dir_inode(struct f2fs_sb_info *sbi, nid_t ino)
{
struct list_head *head = &sbi->dir_inode_list;
struct list_head *this;
struct inode *inode = NULL;

spin_lock(&sbi->dir_inode_lock);
list_for_each(this, head) {
struct dir_inode_entry *entry;
entry = list_entry(this, struct dir_inode_entry, list);
if (entry->inode->i_ino == ino) {
inode = entry->inode;
break;
}
}
out:
spin_unlock(&sbi->dir_inode_lock);
return inode;
}

void sync_dirty_dir_inodes(struct f2fs_sb_info *sbi)
Expand Down Expand Up @@ -595,7 +648,7 @@ static void do_checkpoint(struct f2fs_sb_info *sbi, bool is_umount)
block_t start_blk;
struct page *cp_page;
unsigned int data_sum_blocks, orphan_blocks;
unsigned int crc32 = 0;
__u32 crc32 = 0;
void *kaddr;
int i;

Expand Down Expand Up @@ -664,8 +717,8 @@ static void do_checkpoint(struct f2fs_sb_info *sbi, bool is_umount)
get_nat_bitmap(sbi, __bitmap_ptr(sbi, NAT_BITMAP));

crc32 = f2fs_crc32(ckpt, le32_to_cpu(ckpt->checksum_offset));
*(__le32 *)((unsigned char *)ckpt +
le32_to_cpu(ckpt->checksum_offset))
*((__le32 *)((unsigned char *)ckpt +
le32_to_cpu(ckpt->checksum_offset)))
= cpu_to_le32(crc32);

start_blk = __start_cp_addr(sbi);
Expand Down
68 changes: 53 additions & 15 deletions fs/f2fs/data.c
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,9 @@ static int check_extent_cache(struct inode *inode, pgoff_t pgofs,
struct buffer_head *bh_result)
{
struct f2fs_inode_info *fi = F2FS_I(inode);
#ifdef CONFIG_F2FS_STAT_FS
struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
#endif
pgoff_t start_fofs, end_fofs;
block_t start_blkaddr;

Expand All @@ -78,7 +80,9 @@ static int check_extent_cache(struct inode *inode, pgoff_t pgofs,
return 0;
}

#ifdef CONFIG_F2FS_STAT_FS
sbi->total_hit_ext++;
#endif
start_fofs = fi->ext.fofs;
end_fofs = fi->ext.fofs + fi->ext.len - 1;
start_blkaddr = fi->ext.blk_addr;
Expand All @@ -96,7 +100,9 @@ static int check_extent_cache(struct inode *inode, pgoff_t pgofs,
else
bh_result->b_size = UINT_MAX;

#ifdef CONFIG_F2FS_STAT_FS
sbi->read_hit_ext++;
#endif
read_unlock(&fi->ext.ext_lock);
return 1;
}
Expand Down Expand Up @@ -199,7 +205,7 @@ struct page *find_data_page(struct inode *inode, pgoff_t index, bool sync)
if (dn.data_blkaddr == NEW_ADDR)
return ERR_PTR(-EINVAL);

page = grab_cache_page(mapping, index);
page = grab_cache_page_write_begin(mapping, index, AOP_FLAG_NOFS);
if (!page)
return ERR_PTR(-ENOMEM);

Expand Down Expand Up @@ -233,18 +239,23 @@ struct page *get_lock_data_page(struct inode *inode, pgoff_t index)
struct page *page;
int err;

repeat:
page = grab_cache_page_write_begin(mapping, index, AOP_FLAG_NOFS);
if (!page)
return ERR_PTR(-ENOMEM);

set_new_dnode(&dn, inode, NULL, NULL, 0);
err = get_dnode_of_data(&dn, index, LOOKUP_NODE);
if (err)
if (err) {
f2fs_put_page(page, 1);
return ERR_PTR(err);
}
f2fs_put_dnode(&dn);

if (dn.data_blkaddr == NULL_ADDR)
if (dn.data_blkaddr == NULL_ADDR) {
f2fs_put_page(page, 1);
return ERR_PTR(-ENOENT);
repeat:
page = grab_cache_page(mapping, index);
if (!page)
return ERR_PTR(-ENOMEM);
}

if (PageUptodate(page))
return page;
Expand Down Expand Up @@ -274,28 +285,31 @@ struct page *get_lock_data_page(struct inode *inode, pgoff_t index)
*
* Also, caller should grab and release a mutex by calling mutex_lock_op() and
* mutex_unlock_op().
* Note that, npage is set only by make_empty_dir.
*/
struct page *get_new_data_page(struct inode *inode, pgoff_t index,
bool new_i_size)
struct page *get_new_data_page(struct inode *inode,
struct page *npage, pgoff_t index, bool new_i_size)
{
struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
struct address_space *mapping = inode->i_mapping;
struct page *page;
struct dnode_of_data dn;
int err;

set_new_dnode(&dn, inode, NULL, NULL, 0);
set_new_dnode(&dn, inode, npage, npage, 0);
err = get_dnode_of_data(&dn, index, ALLOC_NODE);
if (err)
return ERR_PTR(err);

if (dn.data_blkaddr == NULL_ADDR) {
if (reserve_new_block(&dn)) {
f2fs_put_dnode(&dn);
if (!npage)
f2fs_put_dnode(&dn);
return ERR_PTR(-ENOSPC);
}
}
f2fs_put_dnode(&dn);
if (!npage)
f2fs_put_dnode(&dn);
repeat:
page = grab_cache_page(mapping, index);
if (!page)
Expand Down Expand Up @@ -325,6 +339,8 @@ struct page *get_new_data_page(struct inode *inode, pgoff_t index,
if (new_i_size &&
i_size_read(inode) < ((index + 1) << PAGE_CACHE_SHIFT)) {
i_size_write(inode, ((index + 1) << PAGE_CACHE_SHIFT));
/* Only the directory inode sets new_i_size */
set_inode_flag(F2FS_I(inode), FI_UPDATE_DIR);
mark_inode_dirty_sync(inode);
}
return page;
Expand Down Expand Up @@ -481,8 +497,9 @@ int do_write_data_page(struct page *page)
* If current allocation needs SSR,
* it had better in-place writes for updated data.
*/
if (old_blk_addr != NEW_ADDR && !is_cold_data(page) &&
need_inplace_update(inode)) {
if (unlikely(old_blk_addr != NEW_ADDR &&
!is_cold_data(page) &&
need_inplace_update(inode))) {
rewrite_data_page(F2FS_SB(inode->i_sb), page,
old_blk_addr);
} else {
Expand Down Expand Up @@ -684,6 +701,27 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping,
return err;
}

static int f2fs_write_end(struct file *file,
struct address_space *mapping,
loff_t pos, unsigned len, unsigned copied,
struct page *page, void *fsdata)
{
struct inode *inode = page->mapping->host;

SetPageUptodate(page);
set_page_dirty(page);

if (pos + copied > i_size_read(inode)) {
i_size_write(inode, pos + copied);
mark_inode_dirty(inode);
update_inode_page(inode);
}

unlock_page(page);
page_cache_release(page);
return copied;
}

static ssize_t f2fs_direct_IO(int rw, struct kiocb *iocb,
const struct iovec *iov, loff_t offset, unsigned long nr_segs)
{
Expand Down Expand Up @@ -741,7 +779,7 @@ const struct address_space_operations f2fs_dblock_aops = {
.writepage = f2fs_write_data_page,
.writepages = f2fs_write_data_pages,
.write_begin = f2fs_write_begin,
.write_end = nobh_write_end,
.write_end = f2fs_write_end,
.set_page_dirty = f2fs_set_data_page_dirty,
.invalidatepage = f2fs_invalidate_data_page,
.releasepage = f2fs_release_data_page,
Expand Down
4 changes: 2 additions & 2 deletions fs/f2fs/debug.c
Original file line number Diff line number Diff line change
Expand Up @@ -175,12 +175,12 @@ static void update_mem_info(struct f2fs_sb_info *sbi)

static int stat_show(struct seq_file *s, void *v)
{
struct f2fs_stat_info *si, *next;
struct f2fs_stat_info *si;
int i = 0;
int j;

mutex_lock(&f2fs_stat_mutex);
list_for_each_entry_safe(si, next, &f2fs_stat_list, stat_list) {
list_for_each_entry(si, &f2fs_stat_list, stat_list) {
char devname[BDEVNAME_SIZE];

update_general_status(si->sbi);
Expand Down
Loading

0 comments on commit 3f490f7

Please sign in to comment.