Commit f6c658df authored by Linus Torvalds's avatar Linus Torvalds

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

Pull f2fs updates from Jaegeuk Kim:
 "In this round, as Ted pointed out, fscrypto allows one more key prefix
  given by filesystem to resolve backward compatibility issues.  Other
  than that, we've fixed several error handling cases by introducing
  a fault injection facility.  We've also achieved performance
  improvement in some workloads as well as a bunch of bug fixes.

  Summary:

  Enhancements:
   - fs-specific prefix for fscrypto
   - fault injection facility
   - expose validity bitmaps for user to be aware of fragmentation
   - fallocate/rm/preallocation speed up
   - use percpu counters

  Bug fixes:
   - some inline_dentry/inline_data bugs
   - error handling for atomic/volatile/orphan inodes
   - recover broken superblock"

* tag 'for-f2fs-4.7' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs: (73 commits)
  f2fs: fix to update dirty page count correctly
  f2fs: flush pending bios right away when error occurs
  f2fs: avoid ENOSPC fault in the recovery process
  f2fs: make exit_f2fs_fs more clear
  f2fs: use percpu_counter for total_valid_inode_count
  f2fs: use percpu_counter for alloc_valid_block_count
  f2fs: use percpu_counter for # of dirty pages in inode
  f2fs: use percpu_counter for page counters
  f2fs: use bio count instead of F2FS_WRITEBACK page count
  f2fs: manipulate dirty file inodes when DATA_FLUSH is set
  f2fs: add fault injection to sysfs
  f2fs: no need inc dirty pages under inode lock
  f2fs: fix incorrect error path handling in f2fs_move_rehashed_dirents
  f2fs: fix i_current_depth during inline dentry conversion
  f2fs: correct return value type of f2fs_fill_super
  f2fs: fix deadlock when flush inline data
  f2fs: avoid f2fs_bug_on during recovery
  f2fs: show # of orphan inodes
  f2fs: support in batch fzero in dnode page
  f2fs: support in batch multi blocks preallocation
  ...
parents 07be1337 0f3311a8
...@@ -4793,7 +4793,7 @@ F: include/linux/fscache*.h ...@@ -4793,7 +4793,7 @@ F: include/linux/fscache*.h
F2FS FILE SYSTEM F2FS FILE SYSTEM
M: Jaegeuk Kim <jaegeuk@kernel.org> M: Jaegeuk Kim <jaegeuk@kernel.org>
M: Changman Lee <cm224.lee@samsung.com> M: Changman Lee <cm224.lee@samsung.com>
R: Chao Yu <chao2.yu@samsung.com> R: Chao Yu <yuchao0@huawei.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
......
...@@ -78,6 +78,67 @@ static int derive_key_aes(u8 deriving_key[FS_AES_128_ECB_KEY_SIZE], ...@@ -78,6 +78,67 @@ static int derive_key_aes(u8 deriving_key[FS_AES_128_ECB_KEY_SIZE],
return res; return res;
} }
static int validate_user_key(struct fscrypt_info *crypt_info,
struct fscrypt_context *ctx, u8 *raw_key,
u8 *prefix, int prefix_size)
{
u8 *full_key_descriptor;
struct key *keyring_key;
struct fscrypt_key *master_key;
const struct user_key_payload *ukp;
int full_key_len = prefix_size + (FS_KEY_DESCRIPTOR_SIZE * 2) + 1;
int res;
full_key_descriptor = kmalloc(full_key_len, GFP_NOFS);
if (!full_key_descriptor)
return -ENOMEM;
memcpy(full_key_descriptor, prefix, prefix_size);
sprintf(full_key_descriptor + prefix_size,
"%*phN", FS_KEY_DESCRIPTOR_SIZE,
ctx->master_key_descriptor);
full_key_descriptor[full_key_len - 1] = '\0';
keyring_key = request_key(&key_type_logon, full_key_descriptor, NULL);
kfree(full_key_descriptor);
if (IS_ERR(keyring_key))
return PTR_ERR(keyring_key);
if (keyring_key->type != &key_type_logon) {
printk_once(KERN_WARNING
"%s: key type must be logon\n", __func__);
res = -ENOKEY;
goto out;
}
down_read(&keyring_key->sem);
ukp = user_key_payload(keyring_key);
if (ukp->datalen != sizeof(struct fscrypt_key)) {
res = -EINVAL;
up_read(&keyring_key->sem);
goto out;
}
master_key = (struct fscrypt_key *)ukp->data;
BUILD_BUG_ON(FS_AES_128_ECB_KEY_SIZE != FS_KEY_DERIVATION_NONCE_SIZE);
if (master_key->size != FS_AES_256_XTS_KEY_SIZE) {
printk_once(KERN_WARNING
"%s: key size incorrect: %d\n",
__func__, master_key->size);
res = -ENOKEY;
up_read(&keyring_key->sem);
goto out;
}
res = derive_key_aes(ctx->nonce, master_key->raw, raw_key);
up_read(&keyring_key->sem);
if (res)
goto out;
crypt_info->ci_keyring_key = keyring_key;
return 0;
out:
key_put(keyring_key);
return res;
}
static void put_crypt_info(struct fscrypt_info *ci) static void put_crypt_info(struct fscrypt_info *ci)
{ {
if (!ci) if (!ci)
...@@ -91,12 +152,7 @@ static void put_crypt_info(struct fscrypt_info *ci) ...@@ -91,12 +152,7 @@ static void put_crypt_info(struct fscrypt_info *ci)
int get_crypt_info(struct inode *inode) int get_crypt_info(struct inode *inode)
{ {
struct fscrypt_info *crypt_info; struct fscrypt_info *crypt_info;
u8 full_key_descriptor[FS_KEY_DESC_PREFIX_SIZE +
(FS_KEY_DESCRIPTOR_SIZE * 2) + 1];
struct key *keyring_key = NULL;
struct fscrypt_key *master_key;
struct fscrypt_context ctx; struct fscrypt_context ctx;
const struct user_key_payload *ukp;
struct crypto_skcipher *ctfm; struct crypto_skcipher *ctfm;
const char *cipher_str; const char *cipher_str;
u8 raw_key[FS_MAX_KEY_SIZE]; u8 raw_key[FS_MAX_KEY_SIZE];
...@@ -167,48 +223,24 @@ int get_crypt_info(struct inode *inode) ...@@ -167,48 +223,24 @@ int get_crypt_info(struct inode *inode)
memset(raw_key, 0x42, FS_AES_256_XTS_KEY_SIZE); memset(raw_key, 0x42, FS_AES_256_XTS_KEY_SIZE);
goto got_key; goto got_key;
} }
memcpy(full_key_descriptor, FS_KEY_DESC_PREFIX,
FS_KEY_DESC_PREFIX_SIZE);
sprintf(full_key_descriptor + FS_KEY_DESC_PREFIX_SIZE,
"%*phN", FS_KEY_DESCRIPTOR_SIZE,
ctx.master_key_descriptor);
full_key_descriptor[FS_KEY_DESC_PREFIX_SIZE +
(2 * FS_KEY_DESCRIPTOR_SIZE)] = '\0';
keyring_key = request_key(&key_type_logon, full_key_descriptor, NULL);
if (IS_ERR(keyring_key)) {
res = PTR_ERR(keyring_key);
keyring_key = NULL;
goto out;
}
crypt_info->ci_keyring_key = keyring_key;
if (keyring_key->type != &key_type_logon) {
printk_once(KERN_WARNING
"%s: key type must be logon\n", __func__);
res = -ENOKEY;
goto out;
}
down_read(&keyring_key->sem);
ukp = user_key_payload(keyring_key);
if (ukp->datalen != sizeof(struct fscrypt_key)) {
res = -EINVAL;
up_read(&keyring_key->sem);
goto out;
}
master_key = (struct fscrypt_key *)ukp->data;
BUILD_BUG_ON(FS_AES_128_ECB_KEY_SIZE != FS_KEY_DERIVATION_NONCE_SIZE);
if (master_key->size != FS_AES_256_XTS_KEY_SIZE) { res = validate_user_key(crypt_info, &ctx, raw_key,
printk_once(KERN_WARNING FS_KEY_DESC_PREFIX, FS_KEY_DESC_PREFIX_SIZE);
"%s: key size incorrect: %d\n", if (res && inode->i_sb->s_cop->key_prefix) {
__func__, master_key->size); u8 *prefix = NULL;
res = -ENOKEY; int prefix_size, res2;
up_read(&keyring_key->sem);
prefix_size = inode->i_sb->s_cop->key_prefix(inode, &prefix);
res2 = validate_user_key(crypt_info, &ctx, raw_key,
prefix, prefix_size);
if (res2) {
if (res2 == -ENOKEY)
res = -ENOKEY;
goto out;
}
} else if (res) {
goto out; goto out;
} }
res = derive_key_aes(ctx.nonce, master_key->raw, raw_key);
up_read(&keyring_key->sem);
if (res)
goto out;
got_key: got_key:
ctfm = crypto_alloc_skcipher(cipher_str, 0, 0); ctfm = crypto_alloc_skcipher(cipher_str, 0, 0);
if (!ctfm || IS_ERR(ctfm)) { if (!ctfm || IS_ERR(ctfm)) {
......
...@@ -94,3 +94,11 @@ config F2FS_IO_TRACE ...@@ -94,3 +94,11 @@ config F2FS_IO_TRACE
information and block IO patterns in the filesystem level. information and block IO patterns in the filesystem level.
If unsure, say N. If unsure, say N.
config F2FS_FAULT_INJECTION
bool "F2FS fault injection facility"
depends on F2FS_FS
help
Test F2FS to inject faults such as ENOMEM, ENOSPC, and so on.
If unsure, say N.
...@@ -115,7 +115,7 @@ static void *f2fs_acl_to_disk(const struct posix_acl *acl, size_t *size) ...@@ -115,7 +115,7 @@ static void *f2fs_acl_to_disk(const struct posix_acl *acl, size_t *size)
struct f2fs_acl_entry *entry; struct f2fs_acl_entry *entry;
int i; int i;
f2fs_acl = kmalloc(sizeof(struct f2fs_acl_header) + acl->a_count * f2fs_acl = f2fs_kmalloc(sizeof(struct f2fs_acl_header) + acl->a_count *
sizeof(struct f2fs_acl_entry), GFP_NOFS); sizeof(struct f2fs_acl_entry), GFP_NOFS);
if (!f2fs_acl) if (!f2fs_acl)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
...@@ -175,7 +175,7 @@ static struct posix_acl *__f2fs_get_acl(struct inode *inode, int type, ...@@ -175,7 +175,7 @@ static struct posix_acl *__f2fs_get_acl(struct inode *inode, int type,
retval = f2fs_getxattr(inode, name_index, "", NULL, 0, dpage); retval = f2fs_getxattr(inode, name_index, "", NULL, 0, dpage);
if (retval > 0) { if (retval > 0) {
value = kmalloc(retval, GFP_F2FS_ZERO); value = f2fs_kmalloc(retval, GFP_F2FS_ZERO);
if (!value) if (!value)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
retval = f2fs_getxattr(inode, name_index, "", value, retval = f2fs_getxattr(inode, name_index, "", value,
......
...@@ -26,6 +26,14 @@ ...@@ -26,6 +26,14 @@
static struct kmem_cache *ino_entry_slab; static struct kmem_cache *ino_entry_slab;
struct kmem_cache *inode_entry_slab; struct kmem_cache *inode_entry_slab;
void f2fs_stop_checkpoint(struct f2fs_sb_info *sbi, bool end_io)
{
set_ckpt_flags(sbi->ckpt, CP_ERROR_FLAG);
sbi->sb->s_flags |= MS_RDONLY;
if (!end_io)
f2fs_flush_merged_bios(sbi);
}
/* /*
* We guarantee no failure on the returned page. * We guarantee no failure on the returned page.
*/ */
...@@ -34,7 +42,7 @@ struct page *grab_meta_page(struct f2fs_sb_info *sbi, pgoff_t index) ...@@ -34,7 +42,7 @@ 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(mapping, index); page = f2fs_grab_cache_page(mapping, index, false);
if (!page) { if (!page) {
cond_resched(); cond_resched();
goto repeat; goto repeat;
...@@ -64,7 +72,7 @@ static struct page *__get_meta_page(struct f2fs_sb_info *sbi, pgoff_t index, ...@@ -64,7 +72,7 @@ static struct page *__get_meta_page(struct f2fs_sb_info *sbi, pgoff_t index,
if (unlikely(!is_meta)) if (unlikely(!is_meta))
fio.rw &= ~REQ_META; fio.rw &= ~REQ_META;
repeat: repeat:
page = grab_cache_page(mapping, index); page = f2fs_grab_cache_page(mapping, index, false);
if (!page) { if (!page) {
cond_resched(); cond_resched();
goto repeat; goto repeat;
...@@ -91,7 +99,7 @@ static struct page *__get_meta_page(struct f2fs_sb_info *sbi, pgoff_t index, ...@@ -91,7 +99,7 @@ static struct page *__get_meta_page(struct f2fs_sb_info *sbi, pgoff_t index,
* meta page. * meta page.
*/ */
if (unlikely(!PageUptodate(page))) if (unlikely(!PageUptodate(page)))
f2fs_stop_checkpoint(sbi); f2fs_stop_checkpoint(sbi, false);
out: out:
return page; return page;
} }
...@@ -186,7 +194,8 @@ int ra_meta_pages(struct f2fs_sb_info *sbi, block_t start, int nrpages, ...@@ -186,7 +194,8 @@ int ra_meta_pages(struct f2fs_sb_info *sbi, block_t start, int nrpages,
BUG(); BUG();
} }
page = grab_cache_page(META_MAPPING(sbi), fio.new_blkaddr); page = f2fs_grab_cache_page(META_MAPPING(sbi),
fio.new_blkaddr, false);
if (!page) if (!page)
continue; continue;
if (PageUptodate(page)) { if (PageUptodate(page)) {
...@@ -211,7 +220,7 @@ void ra_meta_pages_cond(struct f2fs_sb_info *sbi, pgoff_t index) ...@@ -211,7 +220,7 @@ void ra_meta_pages_cond(struct f2fs_sb_info *sbi, pgoff_t index)
bool readahead = false; bool readahead = false;
page = find_get_page(META_MAPPING(sbi), index); page = find_get_page(META_MAPPING(sbi), index);
if (!page || (page && !PageUptodate(page))) if (!page || !PageUptodate(page))
readahead = true; readahead = true;
f2fs_put_page(page, 0); f2fs_put_page(page, 0);
...@@ -448,12 +457,12 @@ bool exist_written_data(struct f2fs_sb_info *sbi, nid_t ino, int mode) ...@@ -448,12 +457,12 @@ bool exist_written_data(struct f2fs_sb_info *sbi, nid_t ino, int mode)
return e ? true : false; return e ? true : false;
} }
void release_ino_entry(struct f2fs_sb_info *sbi) void release_ino_entry(struct f2fs_sb_info *sbi, bool all)
{ {
struct ino_entry *e, *tmp; struct ino_entry *e, *tmp;
int i; int i;
for (i = APPEND_INO; i <= UPDATE_INO; i++) { for (i = all ? ORPHAN_INO: APPEND_INO; i <= UPDATE_INO; i++) {
struct inode_management *im = &sbi->im[i]; struct inode_management *im = &sbi->im[i];
spin_lock(&im->ino_lock); spin_lock(&im->ino_lock);
...@@ -473,6 +482,13 @@ int acquire_orphan_inode(struct f2fs_sb_info *sbi) ...@@ -473,6 +482,13 @@ int acquire_orphan_inode(struct f2fs_sb_info *sbi)
int err = 0; int err = 0;
spin_lock(&im->ino_lock); spin_lock(&im->ino_lock);
#ifdef CONFIG_F2FS_FAULT_INJECTION
if (time_to_inject(FAULT_ORPHAN)) {
spin_unlock(&im->ino_lock);
return -ENOSPC;
}
#endif
if (unlikely(im->ino_num >= sbi->max_orphans)) if (unlikely(im->ino_num >= sbi->max_orphans))
err = -ENOSPC; err = -ENOSPC;
else else
...@@ -777,43 +793,32 @@ void update_dirty_page(struct inode *inode, struct page *page) ...@@ -777,43 +793,32 @@ void update_dirty_page(struct inode *inode, struct page *page)
!S_ISLNK(inode->i_mode)) !S_ISLNK(inode->i_mode))
return; return;
spin_lock(&sbi->inode_lock[type]); if (type != FILE_INODE || test_opt(sbi, DATA_FLUSH)) {
__add_dirty_inode(inode, type); spin_lock(&sbi->inode_lock[type]);
inode_inc_dirty_pages(inode); __add_dirty_inode(inode, type);
spin_unlock(&sbi->inode_lock[type]); spin_unlock(&sbi->inode_lock[type]);
}
inode_inc_dirty_pages(inode);
SetPagePrivate(page); SetPagePrivate(page);
f2fs_trace_pid(page); f2fs_trace_pid(page);
} }
void add_dirty_dir_inode(struct inode *inode)
{
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
spin_lock(&sbi->inode_lock[DIR_INODE]);
__add_dirty_inode(inode, DIR_INODE);
spin_unlock(&sbi->inode_lock[DIR_INODE]);
}
void remove_dirty_inode(struct inode *inode) void remove_dirty_inode(struct inode *inode)
{ {
struct f2fs_sb_info *sbi = F2FS_I_SB(inode); struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
struct f2fs_inode_info *fi = F2FS_I(inode);
enum inode_type type = S_ISDIR(inode->i_mode) ? DIR_INODE : FILE_INODE; enum inode_type type = S_ISDIR(inode->i_mode) ? DIR_INODE : FILE_INODE;
if (!S_ISDIR(inode->i_mode) && !S_ISREG(inode->i_mode) && if (!S_ISDIR(inode->i_mode) && !S_ISREG(inode->i_mode) &&
!S_ISLNK(inode->i_mode)) !S_ISLNK(inode->i_mode))
return; return;
if (type == FILE_INODE && !test_opt(sbi, DATA_FLUSH))
return;
spin_lock(&sbi->inode_lock[type]); spin_lock(&sbi->inode_lock[type]);
__remove_dirty_inode(inode, type); __remove_dirty_inode(inode, type);
spin_unlock(&sbi->inode_lock[type]); spin_unlock(&sbi->inode_lock[type]);
/* Only from the recovery routine */
if (is_inode_flag_set(fi, FI_DELAY_IPUT)) {
clear_inode_flag(fi, FI_DELAY_IPUT);
iput(inode);
}
} }
int sync_dirty_inodes(struct f2fs_sb_info *sbi, enum inode_type type) int sync_dirty_inodes(struct f2fs_sb_info *sbi, enum inode_type type)
...@@ -892,7 +897,7 @@ static int block_operations(struct f2fs_sb_info *sbi) ...@@ -892,7 +897,7 @@ static int block_operations(struct f2fs_sb_info *sbi)
if (get_pages(sbi, F2FS_DIRTY_NODES)) { if (get_pages(sbi, F2FS_DIRTY_NODES)) {
up_write(&sbi->node_write); up_write(&sbi->node_write);
err = sync_node_pages(sbi, 0, &wbc); err = sync_node_pages(sbi, &wbc);
if (err) { if (err) {
f2fs_unlock_all(sbi); f2fs_unlock_all(sbi);
goto out; goto out;
...@@ -917,7 +922,7 @@ static void wait_on_all_pages_writeback(struct f2fs_sb_info *sbi) ...@@ -917,7 +922,7 @@ static void wait_on_all_pages_writeback(struct f2fs_sb_info *sbi)
for (;;) { for (;;) {
prepare_to_wait(&sbi->cp_wait, &wait, TASK_UNINTERRUPTIBLE); prepare_to_wait(&sbi->cp_wait, &wait, TASK_UNINTERRUPTIBLE);
if (!get_pages(sbi, F2FS_WRITEBACK)) if (!atomic_read(&sbi->nr_wb_bios))
break; break;
io_schedule_timeout(5*HZ); io_schedule_timeout(5*HZ);
...@@ -1082,7 +1087,7 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) ...@@ -1082,7 +1087,7 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
/* update user_block_counts */ /* update user_block_counts */
sbi->last_valid_block_count = sbi->total_valid_block_count; sbi->last_valid_block_count = sbi->total_valid_block_count;
sbi->alloc_valid_block_count = 0; percpu_counter_set(&sbi->alloc_valid_block_count, 0);
/* Here, we only have one bio having CP pack */ /* Here, we only have one bio having CP pack */
sync_meta_pages(sbi, META_FLUSH, LONG_MAX); sync_meta_pages(sbi, META_FLUSH, LONG_MAX);
...@@ -1098,7 +1103,7 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) ...@@ -1098,7 +1103,7 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
invalidate_mapping_pages(META_MAPPING(sbi), discard_blk, invalidate_mapping_pages(META_MAPPING(sbi), discard_blk,
discard_blk); discard_blk);
release_ino_entry(sbi); release_ino_entry(sbi, false);
if (unlikely(f2fs_cp_error(sbi))) if (unlikely(f2fs_cp_error(sbi)))
return -EIO; return -EIO;
......
This diff is collapsed.
...@@ -48,7 +48,7 @@ static void update_general_status(struct f2fs_sb_info *sbi) ...@@ -48,7 +48,7 @@ static void update_general_status(struct f2fs_sb_info *sbi)
si->ndirty_dirs = sbi->ndirty_inode[DIR_INODE]; si->ndirty_dirs = sbi->ndirty_inode[DIR_INODE];
si->ndirty_files = sbi->ndirty_inode[FILE_INODE]; si->ndirty_files = sbi->ndirty_inode[FILE_INODE];
si->inmem_pages = get_pages(sbi, F2FS_INMEM_PAGES); si->inmem_pages = get_pages(sbi, F2FS_INMEM_PAGES);
si->wb_pages = get_pages(sbi, F2FS_WRITEBACK); si->wb_bios = atomic_read(&sbi->nr_wb_bios);
si->total_count = (int)sbi->user_block_count / sbi->blocks_per_seg; si->total_count = (int)sbi->user_block_count / sbi->blocks_per_seg;
si->rsvd_segs = reserved_segments(sbi); si->rsvd_segs = reserved_segments(sbi);
si->overp_segs = overprovision_segments(sbi); si->overp_segs = overprovision_segments(sbi);
...@@ -58,6 +58,7 @@ static void update_general_status(struct f2fs_sb_info *sbi) ...@@ -58,6 +58,7 @@ static void update_general_status(struct f2fs_sb_info *sbi)
si->inline_xattr = atomic_read(&sbi->inline_xattr); si->inline_xattr = atomic_read(&sbi->inline_xattr);
si->inline_inode = atomic_read(&sbi->inline_inode); si->inline_inode = atomic_read(&sbi->inline_inode);
si->inline_dir = atomic_read(&sbi->inline_dir); si->inline_dir = atomic_read(&sbi->inline_dir);
si->orphans = sbi->im[ORPHAN_INO].ino_num;
si->utilization = utilization(sbi); si->utilization = utilization(sbi);
si->free_segs = free_segments(sbi); si->free_segs = free_segments(sbi);
...@@ -143,6 +144,7 @@ static void update_mem_info(struct f2fs_sb_info *sbi) ...@@ -143,6 +144,7 @@ static void update_mem_info(struct f2fs_sb_info *sbi)
si->base_mem = sizeof(struct f2fs_sb_info) + sbi->sb->s_blocksize; si->base_mem = sizeof(struct f2fs_sb_info) + sbi->sb->s_blocksize;
si->base_mem += 2 * sizeof(struct f2fs_inode_info); si->base_mem += 2 * sizeof(struct f2fs_inode_info);
si->base_mem += sizeof(*sbi->ckpt); si->base_mem += sizeof(*sbi->ckpt);
si->base_mem += sizeof(struct percpu_counter) * NR_COUNT_TYPE;
/* build sm */ /* build sm */
si->base_mem += sizeof(struct f2fs_sm_info); si->base_mem += sizeof(struct f2fs_sm_info);
...@@ -192,7 +194,7 @@ static void update_mem_info(struct f2fs_sb_info *sbi) ...@@ -192,7 +194,7 @@ static void update_mem_info(struct f2fs_sb_info *sbi)
si->cache_mem += NM_I(sbi)->dirty_nat_cnt * si->cache_mem += NM_I(sbi)->dirty_nat_cnt *
sizeof(struct nat_entry_set); sizeof(struct nat_entry_set);
si->cache_mem += si->inmem_pages * sizeof(struct inmem_pages); si->cache_mem += si->inmem_pages * sizeof(struct inmem_pages);
for (i = 0; i <= UPDATE_INO; i++) for (i = 0; i <= ORPHAN_INO; i++)
si->cache_mem += sbi->im[i].ino_num * sizeof(struct ino_entry); si->cache_mem += sbi->im[i].ino_num * sizeof(struct ino_entry);
si->cache_mem += atomic_read(&sbi->total_ext_tree) * si->cache_mem += atomic_read(&sbi->total_ext_tree) *
sizeof(struct extent_tree); sizeof(struct extent_tree);
...@@ -216,8 +218,9 @@ static int stat_show(struct seq_file *s, void *v) ...@@ -216,8 +218,9 @@ static int stat_show(struct seq_file *s, void *v)
list_for_each_entry(si, &f2fs_stat_list, stat_list) { list_for_each_entry(si, &f2fs_stat_list, stat_list) {
update_general_status(si->sbi); update_general_status(si->sbi);
seq_printf(s, "\n=====[ partition info(%pg). #%d ]=====\n", seq_printf(s, "\n=====[ partition info(%pg). #%d, %s]=====\n",
si->sbi->sb->s_bdev, i++); si->sbi->sb->s_bdev, i++,
f2fs_readonly(si->sbi->sb) ? "RO": "RW");
seq_printf(s, "[SB: 1] [CP: 2] [SIT: %d] [NAT: %d] ", seq_printf(s, "[SB: 1] [CP: 2] [SIT: %d] [NAT: %d] ",
si->sit_area_segs, si->nat_area_segs); si->sit_area_segs, si->nat_area_segs);
seq_printf(s, "[SSA: %d] [MAIN: %d", seq_printf(s, "[SSA: %d] [MAIN: %d",
...@@ -237,6 +240,8 @@ static int stat_show(struct seq_file *s, void *v) ...@@ -237,6 +240,8 @@ static int stat_show(struct seq_file *s, void *v)
si->inline_inode); si->inline_inode);
seq_printf(s, " - Inline_dentry Inode: %u\n", seq_printf(s, " - Inline_dentry Inode: %u\n",
si->inline_dir); si->inline_dir);
seq_printf(s, " - Orphan Inode: %u\n",
si->orphans);
seq_printf(s, "\nMain area: %d segs, %d secs %d zones\n", seq_printf(s, "\nMain area: %d segs, %d secs %d zones\n",
si->main_area_segs, si->main_area_sections, si->main_area_segs, si->main_area_sections,
si->main_area_zones); si->main_area_zones);
...@@ -295,15 +300,15 @@ static int stat_show(struct seq_file *s, void *v) ...@@ -295,15 +300,15 @@ static int stat_show(struct seq_file *s, void *v)
seq_printf(s, " - Inner Struct Count: tree: %d(%d), node: %d\n", seq_printf(s, " - Inner Struct Count: tree: %d(%d), node: %d\n",
si->ext_tree, si->zombie_tree, si->ext_node); si->ext_tree, si->zombie_tree, si->ext_node);
seq_puts(s, "\nBalancing F2FS Async:\n"); seq_puts(s, "\nBalancing F2FS Async:\n");
seq_printf(s, " - inmem: %4d, wb: %4d\n", seq_printf(s, " - inmem: %4lld, wb_bios: %4d\n",
si->inmem_pages, si->wb_pages); si->inmem_pages, si->wb_bios);
seq_printf(s, " - nodes: %4d in %4d\n", seq_printf(s, " - nodes: %4lld in %4d\n",
si->ndirty_node, si->node_pages); si->ndirty_node, si->node_pages);
seq_printf(s, " - dents: %4d in dirs:%4d\n", seq_printf(s, " - dents: %4lld in dirs:%4d\n",
si->ndirty_dent, si->ndirty_dirs); si->ndirty_dent, si->ndirty_dirs);
seq_printf(s, " - datas: %4d in files:%4d\n", seq_printf(s, " - datas: %4lld in files:%4d\n",
si->ndirty_data, si->ndirty_files); si->ndirty_data, si->ndirty_files);
seq_printf(s, " - meta: %4d in %4d\n", seq_printf(s, " - meta: %4lld in %4d\n",
si->ndirty_meta, si->meta_pages); si->ndirty_meta, si->meta_pages);
seq_printf(s, " - NATs: %9d/%9d\n - SITs: %9d/%9d\n", seq_printf(s, " - NATs: %9d/%9d\n - SITs: %9d/%9d\n",
si->dirty_nats, si->nats, si->dirty_sits, si->sits); si->dirty_nats, si->nats, si->dirty_sits, si->sits);
......
...@@ -48,7 +48,6 @@ unsigned char f2fs_filetype_table[F2FS_FT_MAX] = { ...@@ -48,7 +48,6 @@ unsigned char f2fs_filetype_table[F2FS_FT_MAX] = {
[F2FS_FT_SYMLINK] = DT_LNK, [F2FS_FT_SYMLINK] = DT_LNK,
}; };
#define S_SHIFT 12
static unsigned char f2fs_type_by_mode[S_IFMT >> S_SHIFT] = { static unsigned char f2fs_type_by_mode[S_IFMT >> S_SHIFT] = {
[S_IFREG >> S_SHIFT] = F2FS_FT_REG_FILE, [S_IFREG >> S_SHIFT] = F2FS_FT_REG_FILE,
[S_IFDIR >> S_SHIFT] = F2FS_FT_DIR, [S_IFDIR >> S_SHIFT] = F2FS_FT_DIR,
...@@ -64,6 +63,13 @@ void set_de_type(struct f2fs_dir_entry *de, umode_t mode) ...@@ -64,6 +63,13 @@ void set_de_type(struct f2fs_dir_entry *de, umode_t mode)
de->file_type = f2fs_type_by_mode[(mode & S_IFMT) >> S_SHIFT]; de->file_type = f2fs_type_by_mode[(mode & S_IFMT) >> S_SHIFT];
} }
unsigned char get_de_type(struct f2fs_dir_entry *de)
{
if (de->file_type < F2FS_FT_MAX)
return f2fs_filetype_table[de->file_type];
return DT_UNKNOWN;
}
static unsigned long dir_block_index(unsigned int level, static unsigned long dir_block_index(unsigned int level,
int dir_level, unsigned int idx) int dir_level, unsigned int idx)
{ {
...@@ -95,11 +101,6 @@ static struct f2fs_dir_entry *find_in_block(struct page *dentry_page, ...@@ -95,11 +101,6 @@ static struct f2fs_dir_entry *find_in_block(struct page *dentry_page,
else else
kunmap(dentry_page); kunmap(dentry_page);
/*
* For the most part, it should be a bug when name_len is zero.
* We stop here for figuring out where the bugs has occurred.
*/
f2fs_bug_on(F2FS_P_SB(dentry_page), d.max < 0);
return de; return de;
} }
...@@ -124,6 +125,11 @@ struct f2fs_dir_entry *find_target_dentry(struct fscrypt_name *fname, ...@@ -124,6 +125,11 @@ struct f2fs_dir_entry *find_target_dentry(struct fscrypt_name *fname,
de = &d->dentry[bit_pos]; de = &d->dentry[bit_pos];
if (unlikely(!de->name_len)) {
bit_pos++;
continue;
}
/* encrypted case */ /* encrypted case */
de_name.name = d->filename[bit_pos]; de_name.name = d->filename[bit_pos];
de_name.len = le16_to_cpu(de->name_len); de_name.len = le16_to_cpu(de->name_len);
...@@ -141,10 +147,6 @@ struct f2fs_dir_entry *find_target_dentry(struct fscrypt_name *fname, ...@@ -141,10 +147,6 @@ struct f2fs_dir_entry *find_target_dentry(struct fscrypt_name *fname,
*max_slots = max_len; *max_slots = max_len;
max_len = 0; max_len = 0;
/* remain bug on condition */
if (unlikely(!de->name_len))
d->max = -1;
bit_pos += GET_DENTRY_SLOTS(le16_to_cpu(de->name_len)); bit_pos += GET_DENTRY_SLOTS(le16_to_cpu(de->name_len));
} }
...@@ -389,9 +391,14 @@ struct page *init_inode_metadata(struct inode *inode, struct inode *dir, ...@@ -389,9 +391,14 @@ struct page *init_inode_metadata(struct inode *inode, struct inode *dir,
return page; return page;
if (S_ISDIR(inode->i_mode)) { if (S_ISDIR(inode->i_mode)) {
/* in order to handle error case */
get_page(page);
err = make_empty_dir(inode, dir, page); err = make_empty_dir(inode, dir, page);
if (err) if (err) {
goto error; lock_page(page);
goto put_error;
}
put_page(page);
} }
err = f2fs_init_acl(inode, dir, page, dpage); err = f2fs_init_acl(inode, dir, page, dpage);
...@@ -435,13 +442,12 @@ struct page *init_inode_metadata(struct inode *inode, struct inode *dir, ...@@ -435,13 +442,12 @@ struct page *init_inode_metadata(struct inode *inode, struct inode *dir,
return page; return page;
put_error: put_error:
f2fs_put_page(page, 1); /* truncate empty dir pages */
error:
/* once the failed inode becomes a bad inode, i_mode is S_IFREG */
truncate_inode_pages(&inode->i_data, 0); truncate_inode_pages(&inode->i_data, 0);
truncate_blocks(inode, 0, false);
remove_dirty_inode(inode); clear_nlink(inode);
remove_inode_page(inode); update_inode(inode, page);
f2fs_put_page(page, 1);
return ERR_PTR(err); return ERR_PTR(err);
} }
...@@ -509,11 +515,7 @@ void f2fs_update_dentry(nid_t ino, umode_t mode, struct f2fs_dentry_ptr *d, ...@@ -509,11 +515,7 @@ void f2fs_update_dentry(nid_t ino, umode_t mode, struct f2fs_dentry_ptr *d,
} }
} }
/* int f2fs_add_regular_entry(struct inode *dir, const struct qstr *new_name,
* Caller should grab and release a rwsem by calling f2fs_lock_op() and
* f2fs_unlock_op().
*/
int __f2fs_add_link(struct inode *dir, const struct qstr *name,
struct inode *inode, nid_t ino, umode_t mode) struct inode *inode, nid_t ino, umode_t mode)
{ {
unsigned int bit_pos; unsigned int bit_pos;
...@@ -526,28 +528,11 @@ int __f2fs_add_link(struct inode *dir, const struct qstr *name, ...@@ -526,28 +528,11 @@ int __f2fs_add_link(struct inode *dir, const struct qstr *name,
struct f2fs_dentry_block *dentry_blk = NULL; struct f2fs_dentry_block *dentry_blk = NULL;
struct f2fs_dentry_ptr d; struct f2fs_dentry_ptr d;
struct page *page = NULL; struct page *page = NULL;
struct fscrypt_name fname; int slots, err = 0;
struct qstr new_name;
int slots, err;
err = fscrypt_setup_filename(dir, name, 0, &fname);
if (err)
return err;
new_name.name = fname_name(&fname);
new_name.len = fname_len(&fname);
if (f2fs_has_inline_dentry(dir)) {
err = f2fs_add_inline_entry(dir, &new_name, inode, ino, mode);
if (!err || err != -EAGAIN)
goto out;
else
err = 0;
}
level = 0; level = 0;
slots = GET_DENTRY_SLOTS(new_name.len); slots = GET_DENTRY_SLOTS(new_name->len);
dentry_hash = f2fs_dentry_hash(&new_name); dentry_hash = f2fs_dentry_hash(new_name);
current_depth = F2FS_I(dir)->i_current_depth; current_depth = F2FS_I(dir)->i_current_depth;
if (F2FS_I(dir)->chash == dentry_hash) { if (F2FS_I(dir)->chash == dentry_hash) {
...@@ -556,10 +541,12 @@ int __f2fs_add_link(struct inode *dir, const struct qstr *name, ...@@ -556,10 +541,12 @@ int __f2fs_add_link(struct inode *dir, const struct qstr *name,
} }
start: start:
if (unlikely(current_depth == MAX_DIR_HASH_DEPTH)) { #ifdef CONFIG_F2FS_FAULT_INJECTION
err = -ENOSPC; if (time_to_inject(FAULT_DIR_DEPTH))
goto out; return -ENOSPC;
} #endif
if (unlikely(current_depth == MAX_DIR_HASH_DEPTH))
return -ENOSPC;
/* Increase the depth, if required */ /* Increase the depth, if required */
if (level == current_depth) if (level == current_depth)
...@@ -573,10 +560,8 @@ int __f2fs_add_link(struct inode *dir, const struct qstr *name, ...@@ -573,10 +560,8 @@ int __f2fs_add_link(struct inode *dir, const struct qstr *name,
for (block = bidx; block <= (bidx + nblock - 1); block++) { for (block = bidx; block <= (bidx + nblock - 1); block++) {
dentry_page = get_new_data_page(dir, NULL, block, true); dentry_page = get_new_data_page(dir, NULL, block, true);
if (IS_ERR(dentry_page)) { if (IS_ERR(dentry_page))
err = PTR_ERR(dentry_page); return PTR_ERR(dentry_page);
goto out;
}
dentry_blk = kmap(dentry_page); dentry_blk = kmap(dentry_page);
bit_pos = room_for_filename(&dentry_blk->dentry_bitmap, bit_pos = room_for_filename(&dentry_blk->dentry_bitmap,
...@@ -596,7 +581,7 @@ int __f2fs_add_link(struct inode *dir, const struct qstr *name, ...@@ -596,7 +581,7 @@ int __f2fs_add_link(struct inode *dir, const struct qstr *name,
if (inode) { if (inode) {
down_write(&F2FS_I(inode)->i_sem); down_write(&F2FS_I(inode)->i_sem);
page = init_inode_metadata(inode, dir, &new_name, NULL); page = init_inode_metadata(inode, dir, new_name, NULL);
if (IS_ERR(page)) { if (IS_ERR(page)) {
err = PTR_ERR(page); err = PTR_ERR(page);
goto fail; goto fail;
...@@ -606,7 +591,7 @@ int __f2fs_add_link(struct inode *dir, const struct qstr *name, ...@@ -606,7 +591,7 @@ int __f2fs_add_link(struct inode *dir, const struct qstr *name,
} }
make_dentry_ptr(NULL, &d, (void *)dentry_blk, 1); make_dentry_ptr(NULL, &d, (void *)dentry_blk, 1);
f2fs_update_dentry(ino, mode, &d, &new_name, dentry_hash, bit_pos); f2fs_update_dentry(ino, mode, &d, new_name, dentry_hash, bit_pos);
set_page_dirty(dentry_page); set_page_dirty(dentry_page);
...@@ -628,7 +613,34 @@ int __f2fs_add_link(struct inode *dir, const struct qstr *name, ...@@ -628,7 +613,34 @@ int __f2fs_add_link(struct inode *dir, const struct qstr *name,
} }
kunmap(dentry_page); kunmap(dentry_page);
f2fs_put_page(dentry_page, 1); f2fs_put_page(dentry_page, 1);
out:
return err;
}
/*
* Caller should grab and release a rwsem by calling f2fs_lock_op() and
* f2fs_unlock_op().
*/
int __f2fs_add_link(struct inode *dir, const struct qstr *name,
struct inode *inode, nid_t ino, umode_t mode)
{
struct fscrypt_name fname;
struct qstr new_name;
int err;
err = fscrypt_setup_filename(dir, name, 0, &fname);
if (err)
return err;
new_name.name = fname_name(&fname);
new_name.len = fname_len(&fname);
err = -EAGAIN;
if (f2fs_has_inline_dentry(dir))
err = f2fs_add_inline_entry(dir, &new_name, inode, ino, mode);
if (err == -EAGAIN)
err = f2fs_add_regular_entry(dir, &new_name, inode, ino, mode);
fscrypt_free_filename(&fname); fscrypt_free_filename(&fname);
f2fs_update_time(F2FS_I_SB(dir), REQ_TIME); f2fs_update_time(F2FS_I_SB(dir), REQ_TIME);
return err; return err;
...@@ -792,10 +804,7 @@ bool f2fs_fill_dentries(struct dir_context *ctx, struct f2fs_dentry_ptr *d, ...@@ -792,10 +804,7 @@ bool f2fs_fill_dentries(struct dir_context *ctx, struct f2fs_dentry_ptr *d,
continue; continue;
} }
if (de->file_type < F2FS_FT_MAX) d_type = get_de_type(de);
d_type = f2fs_filetype_table[de->file_type];
else
d_type = DT_UNKNOWN;
de_name.name = d->filename[bit_pos]; de_name.name = d->filename[bit_pos];
de_name.len = le16_to_cpu(de->name_len); de_name.len = le16_to_cpu(de->name_len);
...@@ -804,7 +813,7 @@ bool f2fs_fill_dentries(struct dir_context *ctx, struct f2fs_dentry_ptr *d, ...@@ -804,7 +813,7 @@ bool f2fs_fill_dentries(struct dir_context *ctx, struct f2fs_dentry_ptr *d,
int save_len = fstr->len; int save_len = fstr->len;
int ret; int ret;
de_name.name = kmalloc(de_name.len, GFP_NOFS); de_name.name = f2fs_kmalloc(de_name.len, GFP_NOFS);
if (!de_name.name) if (!de_name.name)
return false; return false;
...@@ -887,6 +896,7 @@ static int f2fs_readdir(struct file *file, struct dir_context *ctx) ...@@ -887,6 +896,7 @@ static int f2fs_readdir(struct file *file, struct dir_context *ctx)
kunmap(dentry_page); kunmap(dentry_page);
f2fs_put_page(dentry_page, 1); f2fs_put_page(dentry_page, 1);
} }
err = 0;
out: out:
fscrypt_fname_free_buffer(&fstr); fscrypt_fname_free_buffer(&fstr);
return err; return err;
......
...@@ -196,8 +196,7 @@ bool f2fs_init_extent_tree(struct inode *inode, struct f2fs_extent *i_ext) ...@@ -196,8 +196,7 @@ bool f2fs_init_extent_tree(struct inode *inode, struct f2fs_extent *i_ext)
if (!i_ext || !i_ext->len) if (!i_ext || !i_ext->len)
return false; return false;
set_extent_info(&ei, le32_to_cpu(i_ext->fofs), get_extent_info(&ei, i_ext);
le32_to_cpu(i_ext->blk), le32_to_cpu(i_ext->len));
write_lock(&et->lock); write_lock(&et->lock);
if (atomic_read(&et->node_cnt)) if (atomic_read(&et->node_cnt))
......
This diff is collapsed.
This diff is collapsed.
...@@ -96,7 +96,7 @@ int start_gc_thread(struct f2fs_sb_info *sbi) ...@@ -96,7 +96,7 @@ int start_gc_thread(struct f2fs_sb_info *sbi)
dev_t dev = sbi->sb->s_bdev->bd_dev; dev_t dev = sbi->sb->s_bdev->bd_dev;
int err = 0; int err = 0;
gc_th = kmalloc(sizeof(struct f2fs_gc_kthread), GFP_KERNEL); gc_th = f2fs_kmalloc(sizeof(struct f2fs_gc_kthread), GFP_KERNEL);
if (!gc_th) { if (!gc_th) {
err = -ENOMEM; err = -ENOMEM;
goto out; goto out;
...@@ -465,15 +465,7 @@ static void gc_node_segment(struct f2fs_sb_info *sbi, ...@@ -465,15 +465,7 @@ static void gc_node_segment(struct f2fs_sb_info *sbi,
continue; continue;
} }
/* set page dirty and write it */ move_node_page(node_page, gc_type);
if (gc_type == FG_GC) {
f2fs_wait_on_page_writeback(node_page, NODE, true);
set_page_dirty(node_page);
} else {
if (!PageWriteback(node_page))
set_page_dirty(node_page);
}
f2fs_put_page(node_page, 1);
stat_inc_node_blk_count(sbi, 1, gc_type); stat_inc_node_blk_count(sbi, 1, gc_type);
} }
...@@ -834,18 +826,9 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi, ...@@ -834,18 +826,9 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi,
f2fs_put_page(sum_page, 0); f2fs_put_page(sum_page, 0);
} }
if (gc_type == FG_GC) { if (gc_type == FG_GC)
if (type == SUM_TYPE_NODE) { f2fs_submit_merged_bio(sbi,
struct writeback_control wbc = { (type == SUM_TYPE_NODE) ? NODE : DATA, WRITE);
.sync_mode = WB_SYNC_ALL,
.nr_to_write = LONG_MAX,
.for_reclaim = 0,
};
sync_node_pages(sbi, 0, &wbc);
} else {
f2fs_submit_merged_bio(sbi, DATA, WRITE);
}
}
blk_finish_plug(&plug); blk_finish_plug(&plug);
......
...@@ -161,7 +161,7 @@ int f2fs_convert_inline_inode(struct inode *inode) ...@@ -161,7 +161,7 @@ int f2fs_convert_inline_inode(struct inode *inode)
if (!f2fs_has_inline_data(inode)) if (!f2fs_has_inline_data(inode))
return 0; return 0;
page = grab_cache_page(inode->i_mapping, 0); page = f2fs_grab_cache_page(inode->i_mapping, 0, false);
if (!page) if (!page)
return -ENOMEM; return -ENOMEM;
...@@ -303,11 +303,6 @@ struct f2fs_dir_entry *find_in_inline_dir(struct inode *dir, ...@@ -303,11 +303,6 @@ struct f2fs_dir_entry *find_in_inline_dir(struct inode *dir,
else else
f2fs_put_page(ipage, 0); f2fs_put_page(ipage, 0);
/*
* For the most part, it should be a bug when name_len is zero.
* We stop here for figuring out where the bugs has occurred.
*/
f2fs_bug_on(sbi, d.max < 0);
return de; return de;
} }
...@@ -355,7 +350,7 @@ int make_empty_inline_dir(struct inode *inode, struct inode *parent, ...@@ -355,7 +350,7 @@ int make_empty_inline_dir(struct inode *inode, struct inode *parent,
* NOTE: ipage is grabbed by caller, but if any error occurs, we should * NOTE: ipage is grabbed by caller, but if any error occurs, we should
* release ipage in this function. * release ipage in this function.
*/ */
static int f2fs_convert_inline_dir(struct inode *dir, struct page *ipage, static int f2fs_move_inline_dirents(struct inode *dir, struct page *ipage,
struct f2fs_inline_dentry *inline_dentry) struct f2fs_inline_dentry *inline_dentry)
{ {
struct page *page; struct page *page;
...@@ -363,7 +358,7 @@ static int f2fs_convert_inline_dir(struct inode *dir, struct page *ipage, ...@@ -363,7 +358,7 @@ static int f2fs_convert_inline_dir(struct inode *dir, struct page *ipage,
struct f2fs_dentry_block *dentry_blk; struct f2fs_dentry_block *dentry_blk;
int err; int err;
page = grab_cache_page(dir->i_mapping, 0); page = f2fs_grab_cache_page(dir->i_mapping, 0, false);
if (!page) { if (!page) {
f2fs_put_page(ipage, 1); f2fs_put_page(ipage, 1);
return -ENOMEM; return -ENOMEM;
...@@ -405,6 +400,7 @@ static int f2fs_convert_inline_dir(struct inode *dir, struct page *ipage, ...@@ -405,6 +400,7 @@ static int f2fs_convert_inline_dir(struct inode *dir, struct page *ipage,
stat_dec_inline_dir(dir); stat_dec_inline_dir(dir);
clear_inode_flag(F2FS_I(dir), FI_INLINE_DENTRY); clear_inode_flag(F2FS_I(dir), FI_INLINE_DENTRY);
F2FS_I(dir)->i_current_depth = 1;
if (i_size_read(dir) < PAGE_SIZE) { if (i_size_read(dir) < PAGE_SIZE) {
i_size_write(dir, PAGE_SIZE); i_size_write(dir, PAGE_SIZE);
set_inode_flag(F2FS_I(dir), FI_UPDATE_DIR); set_inode_flag(F2FS_I(dir), FI_UPDATE_DIR);
...@@ -416,6 +412,105 @@ static int f2fs_convert_inline_dir(struct inode *dir, struct page *ipage, ...@@ -416,6 +412,105 @@ static int f2fs_convert_inline_dir(struct inode *dir, struct page *ipage,
return err; return err;
} }
static int f2fs_add_inline_entries(struct inode *dir,
struct f2fs_inline_dentry *inline_dentry)
{
struct f2fs_dentry_ptr d;
unsigned long bit_pos = 0;
int err = 0;
make_dentry_ptr(NULL, &d, (void *)inline_dentry, 2);
while (bit_pos < d.max) {
struct f2fs_dir_entry *de;
struct qstr new_name;
nid_t ino;
umode_t fake_mode;
if (!test_bit_le(bit_pos, d.bitmap)) {
bit_pos++;
continue;
}
de = &d.dentry[bit_pos];
if (unlikely(!de->name_len)) {
bit_pos++;
continue;
}
new_name.name = d.filename[bit_pos];
new_name.len = de->name_len;
ino = le32_to_cpu(de->ino);
fake_mode = get_de_type(de) << S_SHIFT;
err = f2fs_add_regular_entry(dir, &new_name, NULL,
ino, fake_mode);
if (err)
goto punch_dentry_pages;
bit_pos += GET_DENTRY_SLOTS(le16_to_cpu(de->name_len));
}
return 0;
punch_dentry_pages:
truncate_inode_pages(&dir->i_data, 0);
truncate_blocks(dir, 0, false);
remove_dirty_inode(dir);
return err;
}
static int f2fs_move_rehashed_dirents(struct inode *dir, struct page *ipage,
struct f2fs_inline_dentry *inline_dentry)
{
struct f2fs_inline_dentry *backup_dentry;
struct f2fs_inode_info *fi = F2FS_I(dir);
int err;
backup_dentry = f2fs_kmalloc(sizeof(struct f2fs_inline_dentry),
GFP_F2FS_ZERO);
if (!backup_dentry) {
f2fs_put_page(ipage, 1);
return -ENOMEM;
}
memcpy(backup_dentry, inline_dentry, MAX_INLINE_DATA);
truncate_inline_inode(ipage, 0);
unlock_page(ipage);
err = f2fs_add_inline_entries(dir, backup_dentry);
if (err)
goto recover;
lock_page(ipage);
stat_dec_inline_dir(dir);
clear_inode_flag(fi, FI_INLINE_DENTRY);
update_inode(dir, ipage);
kfree(backup_dentry);
return 0;
recover:
lock_page(ipage);
memcpy(inline_dentry, backup_dentry, MAX_INLINE_DATA);
fi->i_current_depth = 0;
i_size_write(dir, MAX_INLINE_DATA);
update_inode(dir, ipage);
f2fs_put_page(ipage, 1);
kfree(backup_dentry);
return err;
}
static int f2fs_convert_inline_dir(struct inode *dir, struct page *ipage,
struct f2fs_inline_dentry *inline_dentry)
{
if (!F2FS_I(dir)->i_dir_level)
return f2fs_move_inline_dirents(dir, ipage, inline_dentry);
else
return f2fs_move_rehashed_dirents(dir, ipage, inline_dentry);
}
int f2fs_add_inline_entry(struct inode *dir, const struct qstr *name, int f2fs_add_inline_entry(struct inode *dir, const struct qstr *name,
struct inode *inode, nid_t ino, umode_t mode) struct inode *inode, nid_t ino, umode_t mode)
{ {
......
...@@ -283,7 +283,7 @@ int update_inode_page(struct inode *inode) ...@@ -283,7 +283,7 @@ int update_inode_page(struct inode *inode)
cond_resched(); cond_resched();
goto retry; goto retry;
} else if (err != -ENOENT) { } else if (err != -ENOENT) {
f2fs_stop_checkpoint(sbi); f2fs_stop_checkpoint(sbi, false);
} }
return 0; return 0;
} }
...@@ -344,7 +344,7 @@ void f2fs_evict_inode(struct inode *inode) ...@@ -344,7 +344,7 @@ void f2fs_evict_inode(struct inode *inode)
sb_start_intwrite(inode->i_sb); sb_start_intwrite(inode->i_sb);
set_inode_flag(fi, FI_NO_ALLOC); set_inode_flag(fi, FI_NO_ALLOC);
i_size_write(inode, 0); i_size_write(inode, 0);
retry:
if (F2FS_HAS_BLOCKS(inode)) if (F2FS_HAS_BLOCKS(inode))
err = f2fs_truncate(inode, true); err = f2fs_truncate(inode, true);
...@@ -354,6 +354,12 @@ void f2fs_evict_inode(struct inode *inode) ...@@ -354,6 +354,12 @@ void f2fs_evict_inode(struct inode *inode)
f2fs_unlock_op(sbi); f2fs_unlock_op(sbi);
} }
/* give more chances, if ENOMEM case */
if (err == -ENOMEM) {
err = 0;
goto retry;
}
sb_end_intwrite(inode->i_sb); sb_end_intwrite(inode->i_sb);
no_delete: no_delete:
stat_dec_inline_xattr(inode); stat_dec_inline_xattr(inode);
...@@ -368,26 +374,11 @@ void f2fs_evict_inode(struct inode *inode) ...@@ -368,26 +374,11 @@ void f2fs_evict_inode(struct inode *inode)
if (is_inode_flag_set(fi, FI_UPDATE_WRITE)) if (is_inode_flag_set(fi, FI_UPDATE_WRITE))
add_ino_entry(sbi, inode->i_ino, UPDATE_INO); add_ino_entry(sbi, inode->i_ino, UPDATE_INO);
if (is_inode_flag_set(fi, FI_FREE_NID)) { if (is_inode_flag_set(fi, FI_FREE_NID)) {
if (err && err != -ENOENT) alloc_nid_failed(sbi, inode->i_ino);
alloc_nid_done(sbi, inode->i_ino);
else
alloc_nid_failed(sbi, inode->i_ino);
clear_inode_flag(fi, FI_FREE_NID); clear_inode_flag(fi, FI_FREE_NID);
} }
f2fs_bug_on(sbi, err &&
if (err && err != -ENOENT) { !exist_written_data(sbi, inode->i_ino, ORPHAN_INO));
if (!exist_written_data(sbi, inode->i_ino, ORPHAN_INO)) {
/*
* get here because we failed to release resource
* of inode previously, reminder our user to run fsck
* for fixing.
*/
set_sbi_flag(sbi, SBI_NEED_FSCK);
f2fs_msg(sbi->sb, KERN_WARNING,
"inode (ino:%lu) resource leak, run fsck "
"to fix this issue!", inode->i_ino);
}
}
out_clear: out_clear:
fscrypt_put_encryption_info(inode, NULL); fscrypt_put_encryption_info(inode, NULL);
clear_inode(inode); clear_inode(inode);
...@@ -397,37 +388,32 @@ void f2fs_evict_inode(struct inode *inode) ...@@ -397,37 +388,32 @@ void f2fs_evict_inode(struct inode *inode)
void handle_failed_inode(struct inode *inode) void handle_failed_inode(struct inode *inode)
{ {
struct f2fs_sb_info *sbi = F2FS_I_SB(inode); struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
int err = 0; struct node_info ni;
clear_nlink(inode); /* don't make bad inode, since it becomes a regular file. */
make_bad_inode(inode);
unlock_new_inode(inode); unlock_new_inode(inode);
i_size_write(inode, 0);
if (F2FS_HAS_BLOCKS(inode))
err = f2fs_truncate(inode, false);
if (!err)
err = remove_inode_page(inode);
/* /*
* if we skip truncate_node in remove_inode_page bacause we failed
* before, it's better to find another way to release resource of
* this inode (e.g. valid block count, node block or nid). Here we
* choose to add this inode to orphan list, so that we can call iput
* for releasing in orphan recovery flow.
*
* Note: we should add inode to orphan list before f2fs_unlock_op() * Note: we should add inode to orphan list before f2fs_unlock_op()
* so we can prevent losing this orphan when encoutering checkpoint * so we can prevent losing this orphan when encoutering checkpoint
* and following suddenly power-off. * and following suddenly power-off.
*/ */
if (err && err != -ENOENT) { get_node_info(sbi, inode->i_ino, &ni);
err = acquire_orphan_inode(sbi);
if (!err) if (ni.blk_addr != NULL_ADDR) {
int err = acquire_orphan_inode(sbi);
if (err) {
set_sbi_flag(sbi, SBI_NEED_FSCK);
f2fs_msg(sbi->sb, KERN_WARNING,
"Too many orphan inodes, run fsck to fix.");
} else {
add_orphan_inode(sbi, inode->i_ino); add_orphan_inode(sbi, inode->i_ino);
}
alloc_nid_done(sbi, inode->i_ino);
} else {
set_inode_flag(F2FS_I(inode), FI_FREE_NID);
} }
set_inode_flag(F2FS_I(inode), FI_FREE_NID);
f2fs_unlock_op(sbi); f2fs_unlock_op(sbi);
/* iput will drop the inode object */ /* iput will drop the inode object */
......
This diff is collapsed.
...@@ -49,8 +49,9 @@ static struct kmem_cache *fsync_entry_slab; ...@@ -49,8 +49,9 @@ static struct kmem_cache *fsync_entry_slab;
bool space_for_roll_forward(struct f2fs_sb_info *sbi) bool space_for_roll_forward(struct f2fs_sb_info *sbi)
{ {
if (sbi->last_valid_block_count + sbi->alloc_valid_block_count s64 nalloc = percpu_counter_sum_positive(&sbi->alloc_valid_block_count);
> sbi->user_block_count)
if (sbi->last_valid_block_count + nalloc > sbi->user_block_count)
return false; return false;
return true; return true;
} }
...@@ -67,7 +68,30 @@ static struct fsync_inode_entry *get_fsync_inode(struct list_head *head, ...@@ -67,7 +68,30 @@ static struct fsync_inode_entry *get_fsync_inode(struct list_head *head,
return NULL; return NULL;
} }
static int recover_dentry(struct inode *inode, struct page *ipage) static struct fsync_inode_entry *add_fsync_inode(struct list_head *head,
struct inode *inode)
{
struct fsync_inode_entry *entry;
entry = kmem_cache_alloc(fsync_entry_slab, GFP_F2FS_ZERO);
if (!entry)
return NULL;
entry->inode = inode;
list_add_tail(&entry->list, head);
return entry;
}
static void del_fsync_inode(struct fsync_inode_entry *entry)
{
iput(entry->inode);
list_del(&entry->list);
kmem_cache_free(fsync_entry_slab, entry);
}
static int recover_dentry(struct inode *inode, struct page *ipage,
struct list_head *dir_list)
{ {
struct f2fs_inode *raw_inode = F2FS_INODE(ipage); struct f2fs_inode *raw_inode = F2FS_INODE(ipage);
nid_t pino = le32_to_cpu(raw_inode->i_pino); nid_t pino = le32_to_cpu(raw_inode->i_pino);
...@@ -75,18 +99,29 @@ static int recover_dentry(struct inode *inode, struct page *ipage) ...@@ -75,18 +99,29 @@ static int recover_dentry(struct inode *inode, struct page *ipage)
struct qstr name; struct qstr name;
struct page *page; struct page *page;
struct inode *dir, *einode; struct inode *dir, *einode;
struct fsync_inode_entry *entry;
int err = 0; int err = 0;
dir = f2fs_iget(inode->i_sb, pino); entry = get_fsync_inode(dir_list, pino);
if (IS_ERR(dir)) { if (!entry) {
err = PTR_ERR(dir); dir = f2fs_iget(inode->i_sb, pino);
goto out; if (IS_ERR(dir)) {
err = PTR_ERR(dir);
goto out;
}
entry = add_fsync_inode(dir_list, dir);
if (!entry) {
err = -ENOMEM;
iput(dir);
goto out;
}
} }
if (file_enc_name(inode)) { dir = entry->inode;
iput(dir);
if (file_enc_name(inode))
return 0; return 0;
}
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;
...@@ -94,7 +129,7 @@ static int recover_dentry(struct inode *inode, struct page *ipage) ...@@ -94,7 +129,7 @@ static int recover_dentry(struct inode *inode, struct page *ipage)
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_err; goto out;
} }
retry: retry:
de = f2fs_find_entry(dir, &name, &page); de = f2fs_find_entry(dir, &name, &page);
...@@ -120,23 +155,12 @@ static int recover_dentry(struct inode *inode, struct page *ipage) ...@@ -120,23 +155,12 @@ static int recover_dentry(struct inode *inode, struct page *ipage)
goto retry; goto retry;
} }
err = __f2fs_add_link(dir, &name, inode, inode->i_ino, inode->i_mode); err = __f2fs_add_link(dir, &name, inode, inode->i_ino, inode->i_mode);
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:
f2fs_dentry_kunmap(dir, page); f2fs_dentry_kunmap(dir, 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",
...@@ -198,6 +222,7 @@ static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head) ...@@ -198,6 +222,7 @@ static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head)
{ {
unsigned long long cp_ver = cur_cp_version(F2FS_CKPT(sbi)); unsigned long long cp_ver = cur_cp_version(F2FS_CKPT(sbi));
struct curseg_info *curseg; struct curseg_info *curseg;
struct inode *inode;
struct page *page = NULL; struct page *page = NULL;
block_t blkaddr; block_t blkaddr;
int err = 0; int err = 0;
...@@ -206,8 +231,6 @@ static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head) ...@@ -206,8 +231,6 @@ static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head)
curseg = CURSEG_I(sbi, CURSEG_WARM_NODE); curseg = CURSEG_I(sbi, CURSEG_WARM_NODE);
blkaddr = NEXT_FREE_BLKADDR(sbi, curseg); blkaddr = NEXT_FREE_BLKADDR(sbi, curseg);
ra_meta_pages(sbi, blkaddr, 1, META_POR, true);
while (1) { while (1) {
struct fsync_inode_entry *entry; struct fsync_inode_entry *entry;
...@@ -233,35 +256,32 @@ static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head) ...@@ -233,35 +256,32 @@ static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head)
break; break;
} }
/* add this fsync inode to the list */
entry = kmem_cache_alloc(fsync_entry_slab, GFP_F2FS_ZERO);
if (!entry) {
err = -ENOMEM;
break;
}
/* /*
* CP | dnode(F) | inode(DF) * CP | dnode(F) | inode(DF)
* For this case, we should not give up now. * For this case, we should not give up now.
*/ */
entry->inode = f2fs_iget(sbi->sb, ino_of_node(page)); inode = f2fs_iget(sbi->sb, ino_of_node(page));
if (IS_ERR(entry->inode)) { if (IS_ERR(inode)) {
err = PTR_ERR(entry->inode); err = PTR_ERR(inode);
kmem_cache_free(fsync_entry_slab, entry);
if (err == -ENOENT) { if (err == -ENOENT) {
err = 0; err = 0;
goto next; goto next;
} }
break; break;
} }
list_add_tail(&entry->list, head);
/* add this fsync inode to the list */
entry = add_fsync_inode(head, inode);
if (!entry) {
err = -ENOMEM;
iput(inode);
break;
}
} }
entry->blkaddr = blkaddr; entry->blkaddr = blkaddr;
if (IS_INODE(page)) { if (IS_INODE(page) && is_dent_dnode(page))
entry->last_inode = blkaddr; entry->last_dentry = blkaddr;
if (is_dent_dnode(page))
entry->last_dentry = blkaddr;
}
next: next:
/* check next segment */ /* check next segment */
blkaddr = next_blkaddr_of_node(page); blkaddr = next_blkaddr_of_node(page);
...@@ -277,11 +297,8 @@ static void destroy_fsync_dnodes(struct list_head *head) ...@@ -277,11 +297,8 @@ static void destroy_fsync_dnodes(struct list_head *head)
{ {
struct fsync_inode_entry *entry, *tmp; struct fsync_inode_entry *entry, *tmp;
list_for_each_entry_safe(entry, tmp, head, list) { list_for_each_entry_safe(entry, tmp, head, list)
iput(entry->inode); del_fsync_inode(entry);
list_del(&entry->list);
kmem_cache_free(fsync_entry_slab, entry);
}
} }
static int check_index_in_prev_nodes(struct f2fs_sb_info *sbi, static int check_index_in_prev_nodes(struct f2fs_sb_info *sbi,
...@@ -444,8 +461,7 @@ static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode, ...@@ -444,8 +461,7 @@ static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode,
*/ */
if (dest == NEW_ADDR) { if (dest == NEW_ADDR) {
truncate_data_blocks_range(&dn, 1); truncate_data_blocks_range(&dn, 1);
err = reserve_new_block(&dn); reserve_new_block(&dn);
f2fs_bug_on(sbi, err);
continue; continue;
} }
...@@ -454,6 +470,10 @@ static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode, ...@@ -454,6 +470,10 @@ static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode,
if (src == NULL_ADDR) { if (src == NULL_ADDR) {
err = reserve_new_block(&dn); err = reserve_new_block(&dn);
#ifdef CONFIG_F2FS_FAULT_INJECTION
while (err)
err = reserve_new_block(&dn);
#endif
/* We should not get -ENOSPC */ /* We should not get -ENOSPC */
f2fs_bug_on(sbi, err); f2fs_bug_on(sbi, err);
} }
...@@ -486,7 +506,8 @@ static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode, ...@@ -486,7 +506,8 @@ static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode,
return err; return err;
} }
static int recover_data(struct f2fs_sb_info *sbi, struct list_head *head) static int recover_data(struct f2fs_sb_info *sbi, struct list_head *inode_list,
struct list_head *dir_list)
{ {
unsigned long long cp_ver = cur_cp_version(F2FS_CKPT(sbi)); unsigned long long cp_ver = cur_cp_version(F2FS_CKPT(sbi));
struct curseg_info *curseg; struct curseg_info *curseg;
...@@ -513,7 +534,7 @@ static int recover_data(struct f2fs_sb_info *sbi, struct list_head *head) ...@@ -513,7 +534,7 @@ static int recover_data(struct f2fs_sb_info *sbi, struct list_head *head)
break; break;
} }
entry = get_fsync_inode(head, ino_of_node(page)); entry = get_fsync_inode(inode_list, ino_of_node(page));
if (!entry) if (!entry)
goto next; goto next;
/* /*
...@@ -521,10 +542,10 @@ static int recover_data(struct f2fs_sb_info *sbi, struct list_head *head) ...@@ -521,10 +542,10 @@ static int recover_data(struct f2fs_sb_info *sbi, struct list_head *head)
* In this case, we can lose the latest inode(x). * In this case, we can lose the latest inode(x).
* So, call recover_inode for the inode update. * So, call recover_inode for the inode update.
*/ */
if (entry->last_inode == blkaddr) if (IS_INODE(page))
recover_inode(entry->inode, page); recover_inode(entry->inode, page);
if (entry->last_dentry == blkaddr) { if (entry->last_dentry == blkaddr) {
err = recover_dentry(entry->inode, page); err = recover_dentry(entry->inode, page, dir_list);
if (err) { if (err) {
f2fs_put_page(page, 1); f2fs_put_page(page, 1);
break; break;
...@@ -536,11 +557,8 @@ static int recover_data(struct f2fs_sb_info *sbi, struct list_head *head) ...@@ -536,11 +557,8 @@ static int recover_data(struct f2fs_sb_info *sbi, struct list_head *head)
break; break;
} }
if (entry->blkaddr == blkaddr) { if (entry->blkaddr == blkaddr)
iput(entry->inode); del_fsync_inode(entry);
list_del(&entry->list);
kmem_cache_free(fsync_entry_slab, entry);
}
next: next:
/* check next segment */ /* check next segment */
blkaddr = next_blkaddr_of_node(page); blkaddr = next_blkaddr_of_node(page);
...@@ -551,12 +569,14 @@ static int recover_data(struct f2fs_sb_info *sbi, struct list_head *head) ...@@ -551,12 +569,14 @@ static int recover_data(struct f2fs_sb_info *sbi, struct list_head *head)
return err; return err;
} }
int recover_fsync_data(struct f2fs_sb_info *sbi) int recover_fsync_data(struct f2fs_sb_info *sbi, bool check_only)
{ {
struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_WARM_NODE); struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_WARM_NODE);
struct list_head inode_list; struct list_head inode_list;
struct list_head dir_list;
block_t blkaddr; block_t blkaddr;
int err; int err;
int ret = 0;
bool need_writecp = false; bool need_writecp = false;
fsync_entry_slab = f2fs_kmem_cache_create("f2fs_fsync_inode_entry", fsync_entry_slab = f2fs_kmem_cache_create("f2fs_fsync_inode_entry",
...@@ -565,6 +585,7 @@ int recover_fsync_data(struct f2fs_sb_info *sbi) ...@@ -565,6 +585,7 @@ int recover_fsync_data(struct f2fs_sb_info *sbi)
return -ENOMEM; return -ENOMEM;
INIT_LIST_HEAD(&inode_list); INIT_LIST_HEAD(&inode_list);
INIT_LIST_HEAD(&dir_list);
/* prevent checkpoint */ /* prevent checkpoint */
mutex_lock(&sbi->cp_mutex); mutex_lock(&sbi->cp_mutex);
...@@ -573,21 +594,22 @@ int recover_fsync_data(struct f2fs_sb_info *sbi) ...@@ -573,21 +594,22 @@ int recover_fsync_data(struct f2fs_sb_info *sbi)
/* step #1: find fsynced inode numbers */ /* step #1: find fsynced inode numbers */
err = find_fsync_dnodes(sbi, &inode_list); err = find_fsync_dnodes(sbi, &inode_list);
if (err) if (err || list_empty(&inode_list))
goto out; goto out;
if (list_empty(&inode_list)) if (check_only) {
ret = 1;
goto out; goto out;
}
need_writecp = true; need_writecp = true;
/* step #2: recover data */ /* step #2: recover data */
err = recover_data(sbi, &inode_list); err = recover_data(sbi, &inode_list, &dir_list);
if (!err) if (!err)
f2fs_bug_on(sbi, !list_empty(&inode_list)); f2fs_bug_on(sbi, !list_empty(&inode_list));
out: out:
destroy_fsync_dnodes(&inode_list); destroy_fsync_dnodes(&inode_list);
kmem_cache_destroy(fsync_entry_slab);
/* truncate meta pages to be used by the recovery */ /* truncate meta pages to be used by the recovery */
truncate_inode_pages_range(META_MAPPING(sbi), truncate_inode_pages_range(META_MAPPING(sbi),
...@@ -625,5 +647,8 @@ int recover_fsync_data(struct f2fs_sb_info *sbi) ...@@ -625,5 +647,8 @@ int recover_fsync_data(struct f2fs_sb_info *sbi)
} else { } else {
mutex_unlock(&sbi->cp_mutex); mutex_unlock(&sbi->cp_mutex);
} }
return err;
destroy_fsync_dnodes(&dir_list);
kmem_cache_destroy(fsync_entry_slab);
return ret ? ret: err;
} }
...@@ -223,9 +223,11 @@ static int __revoke_inmem_pages(struct inode *inode, ...@@ -223,9 +223,11 @@ static int __revoke_inmem_pages(struct inode *inode,
f2fs_put_dnode(&dn); f2fs_put_dnode(&dn);
} }
next: next:
ClearPageUptodate(page); /* we don't need to invalidate this in the sccessful status */
if (drop || recover)
ClearPageUptodate(page);
set_page_private(page, 0); set_page_private(page, 0);
ClearPageUptodate(page); ClearPagePrivate(page);
f2fs_put_page(page, 1); f2fs_put_page(page, 1);
list_del(&cur->list); list_del(&cur->list);
...@@ -239,6 +241,8 @@ void drop_inmem_pages(struct inode *inode) ...@@ -239,6 +241,8 @@ void drop_inmem_pages(struct inode *inode)
{ {
struct f2fs_inode_info *fi = F2FS_I(inode); struct f2fs_inode_info *fi = F2FS_I(inode);
clear_inode_flag(F2FS_I(inode), FI_ATOMIC_FILE);
mutex_lock(&fi->inmem_lock); mutex_lock(&fi->inmem_lock);
__revoke_inmem_pages(inode, &fi->inmem_pages, true, false); __revoke_inmem_pages(inode, &fi->inmem_pages, true, false);
mutex_unlock(&fi->inmem_lock); mutex_unlock(&fi->inmem_lock);
......
...@@ -158,16 +158,17 @@ struct victim_sel_policy { ...@@ -158,16 +158,17 @@ struct victim_sel_policy {
}; };
struct seg_entry { struct seg_entry {
unsigned short valid_blocks; /* # of valid blocks */ unsigned int type:6; /* segment type like CURSEG_XXX_TYPE */
unsigned int valid_blocks:10; /* # of valid blocks */
unsigned int ckpt_valid_blocks:10; /* # of valid blocks last cp */
unsigned int padding:6; /* padding */
unsigned char *cur_valid_map; /* validity bitmap of blocks */ unsigned char *cur_valid_map; /* validity bitmap of blocks */
/* /*
* # of valid blocks and the validity bitmap stored in the the last * # of valid blocks and the validity bitmap stored in the the last
* checkpoint pack. This information is used by the SSR mode. * checkpoint pack. This information is used by the SSR mode.
*/ */
unsigned short ckpt_valid_blocks; unsigned char *ckpt_valid_map; /* validity bitmap of blocks last cp */
unsigned char *ckpt_valid_map;
unsigned char *discard_map; unsigned char *discard_map;
unsigned char type; /* segment type like CURSEG_XXX_TYPE */
unsigned long long mtime; /* modification time of the segment */ unsigned long long mtime; /* modification time of the segment */
}; };
......
This diff is collapsed.
...@@ -498,7 +498,7 @@ static int __f2fs_setxattr(struct inode *inode, int index, ...@@ -498,7 +498,7 @@ static int __f2fs_setxattr(struct inode *inode, int index,
free = free + ENTRY_SIZE(here); free = free + ENTRY_SIZE(here);
if (unlikely(free < newsize)) { if (unlikely(free < newsize)) {
error = -ENOSPC; error = -E2BIG;
goto exit; goto exit;
} }
} }
...@@ -526,7 +526,6 @@ static int __f2fs_setxattr(struct inode *inode, int index, ...@@ -526,7 +526,6 @@ static int __f2fs_setxattr(struct inode *inode, int index,
* Before we come here, old entry is removed. * Before we come here, old entry is removed.
* We just write new entry. * We just write new entry.
*/ */
memset(last, 0, newsize);
last->e_name_index = index; last->e_name_index = index;
last->e_name_len = len; last->e_name_len = len;
memcpy(last->e_name, name, len); memcpy(last->e_name, name, len);
......
...@@ -508,4 +508,6 @@ enum { ...@@ -508,4 +508,6 @@ enum {
F2FS_FT_MAX F2FS_FT_MAX
}; };
#define S_SHIFT 12
#endif /* _LINUX_F2FS_FS_H */ #endif /* _LINUX_F2FS_FS_H */
...@@ -175,6 +175,7 @@ struct fscrypt_name { ...@@ -175,6 +175,7 @@ struct fscrypt_name {
*/ */
struct fscrypt_operations { struct fscrypt_operations {
int (*get_context)(struct inode *, void *, size_t); int (*get_context)(struct inode *, void *, size_t);
int (*key_prefix)(struct inode *, u8 **);
int (*prepare_context)(struct inode *); int (*prepare_context)(struct inode *);
int (*set_context)(struct inode *, const void *, size_t, void *); int (*set_context)(struct inode *, const void *, size_t, void *);
int (*dummy_context)(struct inode *); int (*dummy_context)(struct inode *);
......
...@@ -694,28 +694,32 @@ TRACE_EVENT(f2fs_direct_IO_exit, ...@@ -694,28 +694,32 @@ TRACE_EVENT(f2fs_direct_IO_exit,
__entry->ret) __entry->ret)
); );
TRACE_EVENT(f2fs_reserve_new_block, TRACE_EVENT(f2fs_reserve_new_blocks,
TP_PROTO(struct inode *inode, nid_t nid, unsigned int ofs_in_node), TP_PROTO(struct inode *inode, nid_t nid, unsigned int ofs_in_node,
blkcnt_t count),
TP_ARGS(inode, nid, ofs_in_node), TP_ARGS(inode, nid, ofs_in_node, count),
TP_STRUCT__entry( TP_STRUCT__entry(
__field(dev_t, dev) __field(dev_t, dev)
__field(nid_t, nid) __field(nid_t, nid)
__field(unsigned int, ofs_in_node) __field(unsigned int, ofs_in_node)
__field(blkcnt_t, count)
), ),
TP_fast_assign( TP_fast_assign(
__entry->dev = inode->i_sb->s_dev; __entry->dev = inode->i_sb->s_dev;
__entry->nid = nid; __entry->nid = nid;
__entry->ofs_in_node = ofs_in_node; __entry->ofs_in_node = ofs_in_node;
__entry->count = count;
), ),
TP_printk("dev = (%d,%d), nid = %u, ofs_in_node = %u", TP_printk("dev = (%d,%d), nid = %u, ofs_in_node = %u, count = %llu",
show_dev(__entry), show_dev(__entry),
(unsigned int)__entry->nid, (unsigned int)__entry->nid,
__entry->ofs_in_node) __entry->ofs_in_node,
(unsigned long long)__entry->count)
); );
DECLARE_EVENT_CLASS(f2fs__submit_page_bio, DECLARE_EVENT_CLASS(f2fs__submit_page_bio,
...@@ -1271,14 +1275,14 @@ TRACE_EVENT(f2fs_destroy_extent_tree, ...@@ -1271,14 +1275,14 @@ TRACE_EVENT(f2fs_destroy_extent_tree,
DECLARE_EVENT_CLASS(f2fs_sync_dirty_inodes, DECLARE_EVENT_CLASS(f2fs_sync_dirty_inodes,
TP_PROTO(struct super_block *sb, int type, int count), TP_PROTO(struct super_block *sb, int type, s64 count),
TP_ARGS(sb, type, count), TP_ARGS(sb, type, count),
TP_STRUCT__entry( TP_STRUCT__entry(
__field(dev_t, dev) __field(dev_t, dev)
__field(int, type) __field(int, type)
__field(int, count) __field(s64, count)
), ),
TP_fast_assign( TP_fast_assign(
...@@ -1287,7 +1291,7 @@ DECLARE_EVENT_CLASS(f2fs_sync_dirty_inodes, ...@@ -1287,7 +1291,7 @@ DECLARE_EVENT_CLASS(f2fs_sync_dirty_inodes,
__entry->count = count; __entry->count = count;
), ),
TP_printk("dev = (%d,%d), %s, dirty count = %d", TP_printk("dev = (%d,%d), %s, dirty count = %lld",
show_dev(__entry), show_dev(__entry),
show_file_type(__entry->type), show_file_type(__entry->type),
__entry->count) __entry->count)
...@@ -1295,14 +1299,14 @@ DECLARE_EVENT_CLASS(f2fs_sync_dirty_inodes, ...@@ -1295,14 +1299,14 @@ DECLARE_EVENT_CLASS(f2fs_sync_dirty_inodes,
DEFINE_EVENT(f2fs_sync_dirty_inodes, f2fs_sync_dirty_inodes_enter, DEFINE_EVENT(f2fs_sync_dirty_inodes, f2fs_sync_dirty_inodes_enter,
TP_PROTO(struct super_block *sb, int type, int count), TP_PROTO(struct super_block *sb, int type, s64 count),
TP_ARGS(sb, type, count) TP_ARGS(sb, type, count)
); );
DEFINE_EVENT(f2fs_sync_dirty_inodes, f2fs_sync_dirty_inodes_exit, DEFINE_EVENT(f2fs_sync_dirty_inodes, f2fs_sync_dirty_inodes_exit,
TP_PROTO(struct super_block *sb, int type, int count), TP_PROTO(struct super_block *sb, int type, s64 count),
TP_ARGS(sb, type, count) TP_ARGS(sb, type, count)
); );
......
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