Skip to content

Commit

Permalink
Merge tag 'for-f2fs-4.7' of git://git.kernel.org/pub/scm/linux/kernel…
Browse files Browse the repository at this point in the history
…/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
  ...
  • Loading branch information
torvalds committed May 22, 2016
2 parents 07be133 + 0f3311a commit f6c658d
Show file tree
Hide file tree
Showing 23 changed files with 1,449 additions and 615 deletions.
2 changes: 1 addition & 1 deletion MAINTAINERS
Original file line number Diff line number Diff line change
Expand Up @@ -4793,7 +4793,7 @@ F: include/linux/fscache*.h
F2FS FILE SYSTEM
M: Jaegeuk Kim <[email protected]>
M: Changman Lee <[email protected]>
R: Chao Yu <chao2.yu@samsung.com>
R: Chao Yu <yuchao0@huawei.com>
L: [email protected]
W: http://en.wikipedia.org/wiki/F2FS
T: git git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs.git
Expand Down
120 changes: 76 additions & 44 deletions fs/crypto/keyinfo.c
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,67 @@ static int derive_key_aes(u8 deriving_key[FS_AES_128_ECB_KEY_SIZE],
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)
{
if (!ci)
Expand All @@ -91,12 +152,7 @@ static void put_crypt_info(struct fscrypt_info *ci)
int get_crypt_info(struct inode *inode)
{
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;
const struct user_key_payload *ukp;
struct crypto_skcipher *ctfm;
const char *cipher_str;
u8 raw_key[FS_MAX_KEY_SIZE];
Expand Down Expand Up @@ -167,48 +223,24 @@ int get_crypt_info(struct inode *inode)
memset(raw_key, 0x42, FS_AES_256_XTS_KEY_SIZE);
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) {
printk_once(KERN_WARNING
"%s: key size incorrect: %d\n",
__func__, master_key->size);
res = -ENOKEY;
up_read(&keyring_key->sem);
res = validate_user_key(crypt_info, &ctx, raw_key,
FS_KEY_DESC_PREFIX, FS_KEY_DESC_PREFIX_SIZE);
if (res && inode->i_sb->s_cop->key_prefix) {
u8 *prefix = NULL;
int prefix_size, res2;

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;
}
res = derive_key_aes(ctx.nonce, master_key->raw, raw_key);
up_read(&keyring_key->sem);
if (res)
goto out;
got_key:
ctfm = crypto_alloc_skcipher(cipher_str, 0, 0);
if (!ctfm || IS_ERR(ctfm)) {
Expand Down
8 changes: 8 additions & 0 deletions fs/f2fs/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -94,3 +94,11 @@ config F2FS_IO_TRACE
information and block IO patterns in the filesystem level.

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.
4 changes: 2 additions & 2 deletions fs/f2fs/acl.c
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ static void *f2fs_acl_to_disk(const struct posix_acl *acl, size_t *size)
struct f2fs_acl_entry *entry;
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);
if (!f2fs_acl)
return ERR_PTR(-ENOMEM);
Expand Down Expand Up @@ -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);
if (retval > 0) {
value = kmalloc(retval, GFP_F2FS_ZERO);
value = f2fs_kmalloc(retval, GFP_F2FS_ZERO);
if (!value)
return ERR_PTR(-ENOMEM);
retval = f2fs_getxattr(inode, name_index, "", value,
Expand Down
67 changes: 36 additions & 31 deletions fs/f2fs/checkpoint.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,14 @@
static struct kmem_cache *ino_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.
*/
Expand All @@ -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 page *page = NULL;
repeat:
page = grab_cache_page(mapping, index);
page = f2fs_grab_cache_page(mapping, index, false);
if (!page) {
cond_resched();
goto repeat;
Expand Down Expand Up @@ -64,7 +72,7 @@ static struct page *__get_meta_page(struct f2fs_sb_info *sbi, pgoff_t index,
if (unlikely(!is_meta))
fio.rw &= ~REQ_META;
repeat:
page = grab_cache_page(mapping, index);
page = f2fs_grab_cache_page(mapping, index, false);
if (!page) {
cond_resched();
goto repeat;
Expand All @@ -91,7 +99,7 @@ static struct page *__get_meta_page(struct f2fs_sb_info *sbi, pgoff_t index,
* meta page.
*/
if (unlikely(!PageUptodate(page)))
f2fs_stop_checkpoint(sbi);
f2fs_stop_checkpoint(sbi, false);
out:
return page;
}
Expand Down Expand Up @@ -186,7 +194,8 @@ int ra_meta_pages(struct f2fs_sb_info *sbi, block_t start, int nrpages,
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)
continue;
if (PageUptodate(page)) {
Expand All @@ -211,7 +220,7 @@ void ra_meta_pages_cond(struct f2fs_sb_info *sbi, pgoff_t index)
bool readahead = false;

page = find_get_page(META_MAPPING(sbi), index);
if (!page || (page && !PageUptodate(page)))
if (!page || !PageUptodate(page))
readahead = true;
f2fs_put_page(page, 0);

Expand Down Expand Up @@ -448,12 +457,12 @@ bool exist_written_data(struct f2fs_sb_info *sbi, nid_t ino, int mode)
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;
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];

spin_lock(&im->ino_lock);
Expand All @@ -473,6 +482,13 @@ int acquire_orphan_inode(struct f2fs_sb_info *sbi)
int err = 0;

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))
err = -ENOSPC;
else
Expand Down Expand Up @@ -777,43 +793,32 @@ void update_dirty_page(struct inode *inode, struct page *page)
!S_ISLNK(inode->i_mode))
return;

spin_lock(&sbi->inode_lock[type]);
__add_dirty_inode(inode, type);
inode_inc_dirty_pages(inode);
spin_unlock(&sbi->inode_lock[type]);
if (type != FILE_INODE || test_opt(sbi, DATA_FLUSH)) {
spin_lock(&sbi->inode_lock[type]);
__add_dirty_inode(inode, type);
spin_unlock(&sbi->inode_lock[type]);
}

inode_inc_dirty_pages(inode);
SetPagePrivate(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)
{
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;

if (!S_ISDIR(inode->i_mode) && !S_ISREG(inode->i_mode) &&
!S_ISLNK(inode->i_mode))
return;

if (type == FILE_INODE && !test_opt(sbi, DATA_FLUSH))
return;

spin_lock(&sbi->inode_lock[type]);
__remove_dirty_inode(inode, 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)
Expand Down Expand Up @@ -892,7 +897,7 @@ static int block_operations(struct f2fs_sb_info *sbi)

if (get_pages(sbi, F2FS_DIRTY_NODES)) {
up_write(&sbi->node_write);
err = sync_node_pages(sbi, 0, &wbc);
err = sync_node_pages(sbi, &wbc);
if (err) {
f2fs_unlock_all(sbi);
goto out;
Expand All @@ -917,7 +922,7 @@ static void wait_on_all_pages_writeback(struct f2fs_sb_info *sbi)
for (;;) {
prepare_to_wait(&sbi->cp_wait, &wait, TASK_UNINTERRUPTIBLE);

if (!get_pages(sbi, F2FS_WRITEBACK))
if (!atomic_read(&sbi->nr_wb_bios))
break;

io_schedule_timeout(5*HZ);
Expand Down Expand Up @@ -1082,7 +1087,7 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)

/* update user_block_counts */
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 */
sync_meta_pages(sbi, META_FLUSH, LONG_MAX);
Expand All @@ -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,
discard_blk);

release_ino_entry(sbi);
release_ino_entry(sbi, false);

if (unlikely(f2fs_cp_error(sbi)))
return -EIO;
Expand Down
Loading

0 comments on commit f6c658d

Please sign in to comment.