提交 cfcc0ad4 编写于 作者: L Linus Torvalds

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

Pull f2fs updates from Jaegeuk Kim:
 "New features:
   - per-file encryption (e.g., ext4)
   - FALLOC_FL_ZERO_RANGE
   - FALLOC_FL_COLLAPSE_RANGE
   - RENAME_WHITEOUT

  Major enhancement/fixes:
   - recovery broken superblocks
   - enhance f2fs_trim_fs with a discard_map
   - fix a race condition on dentry block allocation
   - fix a deadlock during summary operation
   - fix a missing fiemap result

  .. and many minor bug fixes and clean-ups were done"

* tag 'for-f2fs-4.2' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs: (83 commits)
  f2fs: do not trim preallocated blocks when truncating after i_size
  f2fs crypto: add alloc_bounce_page
  f2fs crypto: fix to handle errors likewise ext4
  f2fs: drop the volatile_write flag only
  f2fs: skip committing valid superblock
  f2fs: setting discard option in parse_options()
  f2fs: fix to return exact trimmed size
  f2fs: support FALLOC_FL_INSERT_RANGE
  f2fs: hide common code in f2fs_replace_block
  f2fs: disable the discard option when device doesn't support
  f2fs crypto: remove alloc_page for bounce_page
  f2fs: fix a deadlock for summary page lock vs. sentry_lock
  f2fs crypto: clean up error handling in f2fs_fname_setup_filename
  f2fs crypto: avoid f2fs_inherit_context for symlink
  f2fs crypto: do not set encryption policy for non-directory by ioctl
  f2fs crypto: allow setting encryption policy once
  f2fs crypto: check context consistent for rename2
  f2fs: avoid duplicated code by reusing f2fs_read_end_io
  f2fs crypto: use per-inode tfm structure
  f2fs: recovering broken superblock during mount
  ...
......@@ -72,6 +72,25 @@ config F2FS_CHECK_FS
If you want to improve the performance, say N.
config F2FS_FS_ENCRYPTION
bool "F2FS Encryption"
depends on F2FS_FS
depends on F2FS_FS_XATTR
select CRYPTO_AES
select CRYPTO_CBC
select CRYPTO_ECB
select CRYPTO_XTS
select CRYPTO_CTS
select CRYPTO_CTR
select CRYPTO_SHA256
select KEYS
select ENCRYPTED_KEYS
help
Enable encryption of f2fs files and directories. This
feature is similar to ecryptfs, but it is more memory
efficient since it avoids caching the encrypted and
decrypted pages in the page cache.
config F2FS_IO_TRACE
bool "F2FS IO tracer"
depends on F2FS_FS
......
......@@ -6,3 +6,5 @@ f2fs-$(CONFIG_F2FS_STAT_FS) += debug.o
f2fs-$(CONFIG_F2FS_FS_XATTR) += xattr.o
f2fs-$(CONFIG_F2FS_FS_POSIX_ACL) += acl.o
f2fs-$(CONFIG_F2FS_IO_TRACE) += trace.o
f2fs-$(CONFIG_F2FS_FS_ENCRYPTION) += crypto_policy.o crypto.o \
crypto_key.o crypto_fname.o
......@@ -334,51 +334,45 @@ static int f2fs_acl_create(struct inode *dir, umode_t *mode,
struct page *dpage)
{
struct posix_acl *p;
struct posix_acl *clone;
int ret;
*acl = NULL;
*default_acl = NULL;
if (S_ISLNK(*mode) || !IS_POSIXACL(dir))
goto no_acl;
return 0;
p = __f2fs_get_acl(dir, ACL_TYPE_DEFAULT, dpage);
if (IS_ERR(p)) {
if (p == ERR_PTR(-EOPNOTSUPP))
goto apply_umask;
return PTR_ERR(p);
if (!p || p == ERR_PTR(-EOPNOTSUPP)) {
*mode &= ~current_umask();
return 0;
}
if (IS_ERR(p))
return PTR_ERR(p);
if (!p)
goto apply_umask;
*acl = f2fs_acl_clone(p, GFP_NOFS);
if (!*acl)
clone = f2fs_acl_clone(p, GFP_NOFS);
if (!clone)
goto no_mem;
ret = f2fs_acl_create_masq(*acl, mode);
ret = f2fs_acl_create_masq(clone, mode);
if (ret < 0)
goto no_mem_clone;
if (ret == 0) {
posix_acl_release(*acl);
*acl = NULL;
}
if (ret == 0)
posix_acl_release(clone);
else
*acl = clone;
if (!S_ISDIR(*mode)) {
if (!S_ISDIR(*mode))
posix_acl_release(p);
*default_acl = NULL;
} else {
else
*default_acl = p;
}
return 0;
apply_umask:
*mode &= ~current_umask();
no_acl:
*default_acl = NULL;
*acl = NULL;
return 0;
no_mem_clone:
posix_acl_release(*acl);
posix_acl_release(clone);
no_mem:
posix_acl_release(p);
return -ENOMEM;
......
......@@ -52,9 +52,11 @@ struct page *get_meta_page(struct f2fs_sb_info *sbi, pgoff_t index)
struct address_space *mapping = META_MAPPING(sbi);
struct page *page;
struct f2fs_io_info fio = {
.sbi = sbi,
.type = META,
.rw = READ_SYNC | REQ_META | REQ_PRIO,
.blk_addr = index,
.encrypted_page = NULL,
};
repeat:
page = grab_cache_page(mapping, index);
......@@ -65,7 +67,9 @@ struct page *get_meta_page(struct f2fs_sb_info *sbi, pgoff_t index)
if (PageUptodate(page))
goto out;
if (f2fs_submit_page_bio(sbi, page, &fio))
fio.page = page;
if (f2fs_submit_page_bio(&fio))
goto repeat;
lock_page(page);
......@@ -77,8 +81,7 @@ struct page *get_meta_page(struct f2fs_sb_info *sbi, pgoff_t index)
return page;
}
static inline bool is_valid_blkaddr(struct f2fs_sb_info *sbi,
block_t blkaddr, int type)
bool is_valid_blkaddr(struct f2fs_sb_info *sbi, block_t blkaddr, int type)
{
switch (type) {
case META_NAT:
......@@ -118,8 +121,10 @@ int ra_meta_pages(struct f2fs_sb_info *sbi, block_t start, int nrpages, int type
struct page *page;
block_t blkno = start;
struct f2fs_io_info fio = {
.sbi = sbi,
.type = META,
.rw = READ_SYNC | REQ_META | REQ_PRIO
.rw = READ_SYNC | REQ_META | REQ_PRIO,
.encrypted_page = NULL,
};
for (; nrpages-- > 0; blkno++) {
......@@ -161,7 +166,8 @@ int ra_meta_pages(struct f2fs_sb_info *sbi, block_t start, int nrpages, int type
continue;
}
f2fs_submit_page_mbio(sbi, page, &fio);
fio.page = page;
f2fs_submit_page_mbio(&fio);
f2fs_put_page(page, 0);
}
out:
......@@ -510,7 +516,12 @@ static void write_orphan_inodes(struct f2fs_sb_info *sbi, block_t start_blk)
grab_meta_page(sbi, start_blk + index);
index = 1;
spin_lock(&im->ino_lock);
/*
* we don't need to do spin_lock(&im->ino_lock) here, since all the
* orphan inode operations are covered under f2fs_lock_op().
* And, spin_lock should be avoided due to page operations below.
*/
head = &im->ino_list;
/* loop for each orphan inode entry and write them in Jornal block */
......@@ -550,8 +561,6 @@ static void write_orphan_inodes(struct f2fs_sb_info *sbi, block_t start_blk)
set_page_dirty(page);
f2fs_put_page(page, 1);
}
spin_unlock(&im->ino_lock);
}
static struct page *validate_checkpoint(struct f2fs_sb_info *sbi,
......@@ -879,10 +888,8 @@ static void do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
unsigned long orphan_num = sbi->im[ORPHAN_INO].ino_num;
nid_t last_nid = nm_i->next_scan_nid;
block_t start_blk;
struct page *cp_page;
unsigned int data_sum_blocks, orphan_blocks;
__u32 crc32 = 0;
void *kaddr;
int i;
int cp_payload_blks = __cp_payload(sbi);
......@@ -979,19 +986,11 @@ static void do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
start_blk = __start_cp_addr(sbi);
/* write out checkpoint buffer at block 0 */
cp_page = grab_meta_page(sbi, start_blk++);
kaddr = page_address(cp_page);
memcpy(kaddr, ckpt, F2FS_BLKSIZE);
set_page_dirty(cp_page);
f2fs_put_page(cp_page, 1);
for (i = 1; i < 1 + cp_payload_blks; i++) {
cp_page = grab_meta_page(sbi, start_blk++);
kaddr = page_address(cp_page);
memcpy(kaddr, (char *)ckpt + i * F2FS_BLKSIZE, F2FS_BLKSIZE);
set_page_dirty(cp_page);
f2fs_put_page(cp_page, 1);
}
update_meta_page(sbi, ckpt, start_blk++);
for (i = 1; i < 1 + cp_payload_blks; i++)
update_meta_page(sbi, (char *)ckpt + i * F2FS_BLKSIZE,
start_blk++);
if (orphan_num) {
write_orphan_inodes(sbi, start_blk);
......@@ -1006,11 +1005,7 @@ static void do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
}
/* writeout checkpoint block */
cp_page = grab_meta_page(sbi, start_blk);
kaddr = page_address(cp_page);
memcpy(kaddr, ckpt, F2FS_BLKSIZE);
set_page_dirty(cp_page);
f2fs_put_page(cp_page, 1);
update_meta_page(sbi, ckpt, start_blk);
/* wait for previous submitted node/meta pages writeback */
wait_on_all_pages_writeback(sbi);
......@@ -1036,7 +1031,7 @@ static void do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
if (unlikely(f2fs_cp_error(sbi)))
return;
clear_prefree_segments(sbi);
clear_prefree_segments(sbi, cpc);
clear_sbi_flag(sbi, SBI_IS_DIRTY);
}
......@@ -1051,7 +1046,8 @@ void write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
mutex_lock(&sbi->cp_mutex);
if (!is_sbi_flag_set(sbi, SBI_IS_DIRTY) &&
(cpc->reason == CP_FASTBOOT || cpc->reason == CP_SYNC))
(cpc->reason == CP_FASTBOOT || cpc->reason == CP_SYNC ||
(cpc->reason == CP_DISCARD && !sbi->discard_blks)))
goto out;
if (unlikely(f2fs_cp_error(sbi)))
goto out;
......
/*
* linux/fs/f2fs/crypto.c
*
* Copied from linux/fs/ext4/crypto.c
*
* Copyright (C) 2015, Google, Inc.
* Copyright (C) 2015, Motorola Mobility
*
* This contains encryption functions for f2fs
*
* Written by Michael Halcrow, 2014.
*
* Filename encryption additions
* Uday Savagaonkar, 2014
* Encryption policy handling additions
* Ildar Muslukhov, 2014
* Remove ext4_encrypted_zeroout(),
* add f2fs_restore_and_release_control_page()
* Jaegeuk Kim, 2015.
*
* This has not yet undergone a rigorous security audit.
*
* The usage of AES-XTS should conform to recommendations in NIST
* Special Publication 800-38E and IEEE P1619/D16.
*/
#include <crypto/hash.h>
#include <crypto/sha.h>
#include <keys/user-type.h>
#include <keys/encrypted-type.h>
#include <linux/crypto.h>
#include <linux/ecryptfs.h>
#include <linux/gfp.h>
#include <linux/kernel.h>
#include <linux/key.h>
#include <linux/list.h>
#include <linux/mempool.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/random.h>
#include <linux/scatterlist.h>
#include <linux/spinlock_types.h>
#include <linux/f2fs_fs.h>
#include <linux/ratelimit.h>
#include <linux/bio.h>
#include "f2fs.h"
#include "xattr.h"
/* Encryption added and removed here! (L: */
static unsigned int num_prealloc_crypto_pages = 32;
static unsigned int num_prealloc_crypto_ctxs = 128;
module_param(num_prealloc_crypto_pages, uint, 0444);
MODULE_PARM_DESC(num_prealloc_crypto_pages,
"Number of crypto pages to preallocate");
module_param(num_prealloc_crypto_ctxs, uint, 0444);
MODULE_PARM_DESC(num_prealloc_crypto_ctxs,
"Number of crypto contexts to preallocate");
static mempool_t *f2fs_bounce_page_pool;
static LIST_HEAD(f2fs_free_crypto_ctxs);
static DEFINE_SPINLOCK(f2fs_crypto_ctx_lock);
static struct workqueue_struct *f2fs_read_workqueue;
static DEFINE_MUTEX(crypto_init);
static struct kmem_cache *f2fs_crypto_ctx_cachep;
struct kmem_cache *f2fs_crypt_info_cachep;
/**
* f2fs_release_crypto_ctx() - Releases an encryption context
* @ctx: The encryption context to release.
*
* If the encryption context was allocated from the pre-allocated pool, returns
* it to that pool. Else, frees it.
*
* If there's a bounce page in the context, this frees that.
*/
void f2fs_release_crypto_ctx(struct f2fs_crypto_ctx *ctx)
{
unsigned long flags;
if (ctx->flags & F2FS_WRITE_PATH_FL && ctx->w.bounce_page) {
mempool_free(ctx->w.bounce_page, f2fs_bounce_page_pool);
ctx->w.bounce_page = NULL;
}
ctx->w.control_page = NULL;
if (ctx->flags & F2FS_CTX_REQUIRES_FREE_ENCRYPT_FL) {
kmem_cache_free(f2fs_crypto_ctx_cachep, ctx);
} else {
spin_lock_irqsave(&f2fs_crypto_ctx_lock, flags);
list_add(&ctx->free_list, &f2fs_free_crypto_ctxs);
spin_unlock_irqrestore(&f2fs_crypto_ctx_lock, flags);
}
}
/**
* f2fs_get_crypto_ctx() - Gets an encryption context
* @inode: The inode for which we are doing the crypto
*
* Allocates and initializes an encryption context.
*
* Return: An allocated and initialized encryption context on success; error
* value or NULL otherwise.
*/
struct f2fs_crypto_ctx *f2fs_get_crypto_ctx(struct inode *inode)
{
struct f2fs_crypto_ctx *ctx = NULL;
unsigned long flags;
struct f2fs_crypt_info *ci = F2FS_I(inode)->i_crypt_info;
if (ci == NULL)
return ERR_PTR(-ENOKEY);
/*
* We first try getting the ctx from a free list because in
* the common case the ctx will have an allocated and
* initialized crypto tfm, so it's probably a worthwhile
* optimization. For the bounce page, we first try getting it
* from the kernel allocator because that's just about as fast
* as getting it from a list and because a cache of free pages
* should generally be a "last resort" option for a filesystem
* to be able to do its job.
*/
spin_lock_irqsave(&f2fs_crypto_ctx_lock, flags);
ctx = list_first_entry_or_null(&f2fs_free_crypto_ctxs,
struct f2fs_crypto_ctx, free_list);
if (ctx)
list_del(&ctx->free_list);
spin_unlock_irqrestore(&f2fs_crypto_ctx_lock, flags);
if (!ctx) {
ctx = kmem_cache_zalloc(f2fs_crypto_ctx_cachep, GFP_NOFS);
if (!ctx)
return ERR_PTR(-ENOMEM);
ctx->flags |= F2FS_CTX_REQUIRES_FREE_ENCRYPT_FL;
} else {
ctx->flags &= ~F2FS_CTX_REQUIRES_FREE_ENCRYPT_FL;
}
ctx->flags &= ~F2FS_WRITE_PATH_FL;
return ctx;
}
/*
* Call f2fs_decrypt on every single page, reusing the encryption
* context.
*/
static void completion_pages(struct work_struct *work)
{
struct f2fs_crypto_ctx *ctx =
container_of(work, struct f2fs_crypto_ctx, r.work);
struct bio *bio = ctx->r.bio;
struct bio_vec *bv;
int i;
bio_for_each_segment_all(bv, bio, i) {
struct page *page = bv->bv_page;
int ret = f2fs_decrypt(ctx, page);
if (ret) {
WARN_ON_ONCE(1);
SetPageError(page);
} else
SetPageUptodate(page);
unlock_page(page);
}
f2fs_release_crypto_ctx(ctx);
bio_put(bio);
}
void f2fs_end_io_crypto_work(struct f2fs_crypto_ctx *ctx, struct bio *bio)
{
INIT_WORK(&ctx->r.work, completion_pages);
ctx->r.bio = bio;
queue_work(f2fs_read_workqueue, &ctx->r.work);
}
static void f2fs_crypto_destroy(void)
{
struct f2fs_crypto_ctx *pos, *n;
list_for_each_entry_safe(pos, n, &f2fs_free_crypto_ctxs, free_list)
kmem_cache_free(f2fs_crypto_ctx_cachep, pos);
INIT_LIST_HEAD(&f2fs_free_crypto_ctxs);
if (f2fs_bounce_page_pool)
mempool_destroy(f2fs_bounce_page_pool);
f2fs_bounce_page_pool = NULL;
}
/**
* f2fs_crypto_initialize() - Set up for f2fs encryption.
*
* We only call this when we start accessing encrypted files, since it
* results in memory getting allocated that wouldn't otherwise be used.
*
* Return: Zero on success, non-zero otherwise.
*/
int f2fs_crypto_initialize(void)
{
int i, res = -ENOMEM;
if (f2fs_bounce_page_pool)
return 0;
mutex_lock(&crypto_init);
if (f2fs_bounce_page_pool)
goto already_initialized;
for (i = 0; i < num_prealloc_crypto_ctxs; i++) {
struct f2fs_crypto_ctx *ctx;
ctx = kmem_cache_zalloc(f2fs_crypto_ctx_cachep, GFP_KERNEL);
if (!ctx)
goto fail;
list_add(&ctx->free_list, &f2fs_free_crypto_ctxs);
}
/* must be allocated at the last step to avoid race condition above */
f2fs_bounce_page_pool =
mempool_create_page_pool(num_prealloc_crypto_pages, 0);
if (!f2fs_bounce_page_pool)
goto fail;
already_initialized:
mutex_unlock(&crypto_init);
return 0;
fail:
f2fs_crypto_destroy();
mutex_unlock(&crypto_init);
return res;
}
/**
* f2fs_exit_crypto() - Shutdown the f2fs encryption system
*/
void f2fs_exit_crypto(void)
{
f2fs_crypto_destroy();
if (f2fs_read_workqueue)
destroy_workqueue(f2fs_read_workqueue);
if (f2fs_crypto_ctx_cachep)
kmem_cache_destroy(f2fs_crypto_ctx_cachep);
if (f2fs_crypt_info_cachep)
kmem_cache_destroy(f2fs_crypt_info_cachep);
}
int __init f2fs_init_crypto(void)
{
int res = -ENOMEM;
f2fs_read_workqueue = alloc_workqueue("f2fs_crypto", WQ_HIGHPRI, 0);
if (!f2fs_read_workqueue)
goto fail;
f2fs_crypto_ctx_cachep = KMEM_CACHE(f2fs_crypto_ctx,
SLAB_RECLAIM_ACCOUNT);
if (!f2fs_crypto_ctx_cachep)
goto fail;
f2fs_crypt_info_cachep = KMEM_CACHE(f2fs_crypt_info,
SLAB_RECLAIM_ACCOUNT);
if (!f2fs_crypt_info_cachep)
goto fail;
return 0;
fail:
f2fs_exit_crypto();
return res;
}
void f2fs_restore_and_release_control_page(struct page **page)
{
struct f2fs_crypto_ctx *ctx;
struct page *bounce_page;
/* The bounce data pages are unmapped. */
if ((*page)->mapping)
return;
/* The bounce data page is unmapped. */
bounce_page = *page;
ctx = (struct f2fs_crypto_ctx *)page_private(bounce_page);
/* restore control page */
*page = ctx->w.control_page;
f2fs_restore_control_page(bounce_page);
}
void f2fs_restore_control_page(struct page *data_page)
{
struct f2fs_crypto_ctx *ctx =
(struct f2fs_crypto_ctx *)page_private(data_page);
set_page_private(data_page, (unsigned long)NULL);
ClearPagePrivate(data_page);
unlock_page(data_page);
f2fs_release_crypto_ctx(ctx);
}
/**
* f2fs_crypt_complete() - The completion callback for page encryption
* @req: The asynchronous encryption request context
* @res: The result of the encryption operation
*/
static void f2fs_crypt_complete(struct crypto_async_request *req, int res)
{
struct f2fs_completion_result *ecr = req->data;
if (res == -EINPROGRESS)
return;
ecr->res = res;
complete(&ecr->completion);
}
typedef enum {
F2FS_DECRYPT = 0,
F2FS_ENCRYPT,
} f2fs_direction_t;
static int f2fs_page_crypto(struct f2fs_crypto_ctx *ctx,
struct inode *inode,
f2fs_direction_t rw,
pgoff_t index,
struct page *src_page,
struct page *dest_page)
{
u8 xts_tweak[F2FS_XTS_TWEAK_SIZE];
struct ablkcipher_request *req = NULL;
DECLARE_F2FS_COMPLETION_RESULT(ecr);
struct scatterlist dst, src;
struct f2fs_crypt_info *ci = F2FS_I(inode)->i_crypt_info;
struct crypto_ablkcipher *tfm = ci->ci_ctfm;
int res = 0;
req = ablkcipher_request_alloc(tfm, GFP_NOFS);
if (!req) {
printk_ratelimited(KERN_ERR
"%s: crypto_request_alloc() failed\n",
__func__);
return -ENOMEM;
}
ablkcipher_request_set_callback(
req, CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP,
f2fs_crypt_complete, &ecr);
BUILD_BUG_ON(F2FS_XTS_TWEAK_SIZE < sizeof(index));
memcpy(xts_tweak, &index, sizeof(index));
memset(&xts_tweak[sizeof(index)], 0,
F2FS_XTS_TWEAK_SIZE - sizeof(index));
sg_init_table(&dst, 1);
sg_set_page(&dst, dest_page, PAGE_CACHE_SIZE, 0);
sg_init_table(&src, 1);
sg_set_page(&src, src_page, PAGE_CACHE_SIZE, 0);
ablkcipher_request_set_crypt(req, &src, &dst, PAGE_CACHE_SIZE,
xts_tweak);
if (rw == F2FS_DECRYPT)
res = crypto_ablkcipher_decrypt(req);
else
res = crypto_ablkcipher_encrypt(req);
if (res == -EINPROGRESS || res == -EBUSY) {
BUG_ON(req->base.data != &ecr);
wait_for_completion(&ecr.completion);
res = ecr.res;
}
ablkcipher_request_free(req);
if (res) {
printk_ratelimited(KERN_ERR
"%s: crypto_ablkcipher_encrypt() returned %d\n",
__func__, res);
return res;
}
return 0;
}
static struct page *alloc_bounce_page(struct f2fs_crypto_ctx *ctx)
{
ctx->w.bounce_page = mempool_alloc(f2fs_bounce_page_pool, GFP_NOWAIT);
if (ctx->w.bounce_page == NULL)
return ERR_PTR(-ENOMEM);
ctx->flags |= F2FS_WRITE_PATH_FL;
return ctx->w.bounce_page;
}
/**
* f2fs_encrypt() - Encrypts a page
* @inode: The inode for which the encryption should take place
* @plaintext_page: The page to encrypt. Must be locked.
*
* Allocates a ciphertext page and encrypts plaintext_page into it using the ctx
* encryption context.
*
* Called on the page write path. The caller must call
* f2fs_restore_control_page() on the returned ciphertext page to
* release the bounce buffer and the encryption context.
*
* Return: An allocated page with the encrypted content on success. Else, an
* error value or NULL.
*/
struct page *f2fs_encrypt(struct inode *inode,
struct page *plaintext_page)
{
struct f2fs_crypto_ctx *ctx;
struct page *ciphertext_page = NULL;
int err;
BUG_ON(!PageLocked(plaintext_page));
ctx = f2fs_get_crypto_ctx(inode);
if (IS_ERR(ctx))
return (struct page *)ctx;
/* The encryption operation will require a bounce page. */
ciphertext_page = alloc_bounce_page(ctx);
if (IS_ERR(ciphertext_page))
goto err_out;
ctx->w.control_page = plaintext_page;
err = f2fs_page_crypto(ctx, inode, F2FS_ENCRYPT, plaintext_page->index,
plaintext_page, ciphertext_page);
if (err) {
ciphertext_page = ERR_PTR(err);
goto err_out;
}
SetPagePrivate(ciphertext_page);
set_page_private(ciphertext_page, (unsigned long)ctx);
lock_page(ciphertext_page);
return ciphertext_page;
err_out:
f2fs_release_crypto_ctx(ctx);
return ciphertext_page;
}
/**
* f2fs_decrypt() - Decrypts a page in-place
* @ctx: The encryption context.
* @page: The page to decrypt. Must be locked.
*
* Decrypts page in-place using the ctx encryption context.
*
* Called from the read completion callback.
*
* Return: Zero on success, non-zero otherwise.
*/
int f2fs_decrypt(struct f2fs_crypto_ctx *ctx, struct page *page)
{
BUG_ON(!PageLocked(page));
return f2fs_page_crypto(ctx, page->mapping->host,
F2FS_DECRYPT, page->index, page, page);
}
/*
* Convenience function which takes care of allocating and
* deallocating the encryption context
*/
int f2fs_decrypt_one(struct inode *inode, struct page *page)
{
struct f2fs_crypto_ctx *ctx = f2fs_get_crypto_ctx(inode);
int ret;
if (IS_ERR(ctx))
return PTR_ERR(ctx);
ret = f2fs_decrypt(ctx, page);
f2fs_release_crypto_ctx(ctx);
return ret;
}
bool f2fs_valid_contents_enc_mode(uint32_t mode)
{
return (mode == F2FS_ENCRYPTION_MODE_AES_256_XTS);
}
/**
* f2fs_validate_encryption_key_size() - Validate the encryption key size
* @mode: The key mode.
* @size: The key size to validate.
*
* Return: The validated key size for @mode. Zero if invalid.
*/
uint32_t f2fs_validate_encryption_key_size(uint32_t mode, uint32_t size)
{
if (size == f2fs_encryption_key_size(mode))
return size;
return 0;
}
/*
* linux/fs/f2fs/crypto_fname.c
*
* Copied from linux/fs/ext4/crypto.c
*
* Copyright (C) 2015, Google, Inc.
* Copyright (C) 2015, Motorola Mobility
*
* This contains functions for filename crypto management in f2fs
*
* Written by Uday Savagaonkar, 2014.
*
* Adjust f2fs dentry structure
* Jaegeuk Kim, 2015.
*
* This has not yet undergone a rigorous security audit.
*/
#include <crypto/hash.h>
#include <crypto/sha.h>
#include <keys/encrypted-type.h>
#include <keys/user-type.h>
#include <linux/crypto.h>
#include <linux/gfp.h>
#include <linux/kernel.h>
#include <linux/key.h>
#include <linux/list.h>
#include <linux/mempool.h>
#include <linux/random.h>
#include <linux/scatterlist.h>
#include <linux/spinlock_types.h>
#include <linux/f2fs_fs.h>
#include <linux/ratelimit.h>
#include "f2fs.h"
#include "f2fs_crypto.h"
#include "xattr.h"
/**
* f2fs_dir_crypt_complete() -
*/
static void f2fs_dir_crypt_complete(struct crypto_async_request *req, int res)
{
struct f2fs_completion_result *ecr = req->data;
if (res == -EINPROGRESS)
return;
ecr->res = res;
complete(&ecr->completion);
}
bool f2fs_valid_filenames_enc_mode(uint32_t mode)
{
return (mode == F2FS_ENCRYPTION_MODE_AES_256_CTS);
}
static unsigned max_name_len(struct inode *inode)
{
return S_ISLNK(inode->i_mode) ? inode->i_sb->s_blocksize :
F2FS_NAME_LEN;
}
/**
* f2fs_fname_encrypt() -
*
* This function encrypts the input filename, and returns the length of the
* ciphertext. Errors are returned as negative numbers. We trust the caller to
* allocate sufficient memory to oname string.
*/
static int f2fs_fname_encrypt(struct inode *inode,
const struct qstr *iname, struct f2fs_str *oname)
{
u32 ciphertext_len;
struct ablkcipher_request *req = NULL;
DECLARE_F2FS_COMPLETION_RESULT(ecr);
struct f2fs_crypt_info *ci = F2FS_I(inode)->i_crypt_info;
struct crypto_ablkcipher *tfm = ci->ci_ctfm;
int res = 0;
char iv[F2FS_CRYPTO_BLOCK_SIZE];
struct scatterlist src_sg, dst_sg;
int padding = 4 << (ci->ci_flags & F2FS_POLICY_FLAGS_PAD_MASK);
char *workbuf, buf[32], *alloc_buf = NULL;
unsigned lim = max_name_len(inode);
if (iname->len <= 0 || iname->len > lim)
return -EIO;
ciphertext_len = (iname->len < F2FS_CRYPTO_BLOCK_SIZE) ?
F2FS_CRYPTO_BLOCK_SIZE : iname->len;
ciphertext_len = f2fs_fname_crypto_round_up(ciphertext_len, padding);
ciphertext_len = (ciphertext_len > lim) ? lim : ciphertext_len;
if (ciphertext_len <= sizeof(buf)) {
workbuf = buf;
} else {
alloc_buf = kmalloc(ciphertext_len, GFP_NOFS);
if (!alloc_buf)
return -ENOMEM;
workbuf = alloc_buf;
}
/* Allocate request */
req = ablkcipher_request_alloc(tfm, GFP_NOFS);
if (!req) {
printk_ratelimited(KERN_ERR
"%s: crypto_request_alloc() failed\n", __func__);
kfree(alloc_buf);
return -ENOMEM;
}
ablkcipher_request_set_callback(req,
CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP,
f2fs_dir_crypt_complete, &ecr);
/* Copy the input */
memcpy(workbuf, iname->name, iname->len);
if (iname->len < ciphertext_len)
memset(workbuf + iname->len, 0, ciphertext_len - iname->len);
/* Initialize IV */
memset(iv, 0, F2FS_CRYPTO_BLOCK_SIZE);
/* Create encryption request */
sg_init_one(&src_sg, workbuf, ciphertext_len);
sg_init_one(&dst_sg, oname->name, ciphertext_len);
ablkcipher_request_set_crypt(req, &src_sg, &dst_sg, ciphertext_len, iv);
res = crypto_ablkcipher_encrypt(req);
if (res == -EINPROGRESS || res == -EBUSY) {
BUG_ON(req->base.data != &ecr);
wait_for_completion(&ecr.completion);
res = ecr.res;
}
kfree(alloc_buf);
ablkcipher_request_free(req);
if (res < 0) {
printk_ratelimited(KERN_ERR
"%s: Error (error code %d)\n", __func__, res);
}
oname->len = ciphertext_len;
return res;
}
/*
* f2fs_fname_decrypt()
* This function decrypts the input filename, and returns
* the length of the plaintext.
* Errors are returned as negative numbers.
* We trust the caller to allocate sufficient memory to oname string.
*/
static int f2fs_fname_decrypt(struct inode *inode,
const struct f2fs_str *iname, struct f2fs_str *oname)
{
struct ablkcipher_request *req = NULL;
DECLARE_F2FS_COMPLETION_RESULT(ecr);
struct scatterlist src_sg, dst_sg;
struct f2fs_crypt_info *ci = F2FS_I(inode)->i_crypt_info;
struct crypto_ablkcipher *tfm = ci->ci_ctfm;
int res = 0;
char iv[F2FS_CRYPTO_BLOCK_SIZE];
unsigned lim = max_name_len(inode);
if (iname->len <= 0 || iname->len > lim)
return -EIO;
/* Allocate request */
req = ablkcipher_request_alloc(tfm, GFP_NOFS);
if (!req) {
printk_ratelimited(KERN_ERR
"%s: crypto_request_alloc() failed\n", __func__);
return -ENOMEM;
}
ablkcipher_request_set_callback(req,
CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP,
f2fs_dir_crypt_complete, &ecr);
/* Initialize IV */
memset(iv, 0, F2FS_CRYPTO_BLOCK_SIZE);
/* Create decryption request */
sg_init_one(&src_sg, iname->name, iname->len);
sg_init_one(&dst_sg, oname->name, oname->len);
ablkcipher_request_set_crypt(req, &src_sg, &dst_sg, iname->len, iv);
res = crypto_ablkcipher_decrypt(req);
if (res == -EINPROGRESS || res == -EBUSY) {
BUG_ON(req->base.data != &ecr);
wait_for_completion(&ecr.completion);
res = ecr.res;
}
ablkcipher_request_free(req);
if (res < 0) {
printk_ratelimited(KERN_ERR
"%s: Error in f2fs_fname_decrypt (error code %d)\n",
__func__, res);
return res;
}
oname->len = strnlen(oname->name, iname->len);
return oname->len;
}
static const char *lookup_table =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+,";
/**
* f2fs_fname_encode_digest() -
*
* Encodes the input digest using characters from the set [a-zA-Z0-9_+].
* The encoded string is roughly 4/3 times the size of the input string.
*/
static int digest_encode(const char *src, int len, char *dst)
{
int i = 0, bits = 0, ac = 0;
char *cp = dst;
while (i < len) {
ac += (((unsigned char) src[i]) << bits);
bits += 8;
do {
*cp++ = lookup_table[ac & 0x3f];
ac >>= 6;
bits -= 6;
} while (bits >= 6);
i++;
}
if (bits)
*cp++ = lookup_table[ac & 0x3f];
return cp - dst;
}
static int digest_decode(const char *src, int len, char *dst)
{
int i = 0, bits = 0, ac = 0;
const char *p;
char *cp = dst;
while (i < len) {
p = strchr(lookup_table, src[i]);
if (p == NULL || src[i] == 0)
return -2;
ac += (p - lookup_table) << bits;
bits += 6;
if (bits >= 8) {
*cp++ = ac & 0xff;
ac >>= 8;
bits -= 8;
}
i++;
}
if (ac)
return -1;
return cp - dst;
}
/**
* f2fs_fname_crypto_round_up() -
*
* Return: The next multiple of block size
*/
u32 f2fs_fname_crypto_round_up(u32 size, u32 blksize)
{
return ((size + blksize - 1) / blksize) * blksize;
}
/**
* f2fs_fname_crypto_alloc_obuff() -
*
* Allocates an output buffer that is sufficient for the crypto operation
* specified by the context and the direction.
*/
int f2fs_fname_crypto_alloc_buffer(struct inode *inode,
u32 ilen, struct f2fs_str *crypto_str)
{
unsigned int olen;
int padding = 16;
struct f2fs_crypt_info *ci = F2FS_I(inode)->i_crypt_info;
if (ci)
padding = 4 << (ci->ci_flags & F2FS_POLICY_FLAGS_PAD_MASK);
if (padding < F2FS_CRYPTO_BLOCK_SIZE)
padding = F2FS_CRYPTO_BLOCK_SIZE;
olen = f2fs_fname_crypto_round_up(ilen, padding);
crypto_str->len = olen;
if (olen < F2FS_FNAME_CRYPTO_DIGEST_SIZE * 2)
olen = F2FS_FNAME_CRYPTO_DIGEST_SIZE * 2;
/* Allocated buffer can hold one more character to null-terminate the
* string */
crypto_str->name = kmalloc(olen + 1, GFP_NOFS);
if (!(crypto_str->name))
return -ENOMEM;
return 0;
}
/**
* f2fs_fname_crypto_free_buffer() -
*
* Frees the buffer allocated for crypto operation.
*/
void f2fs_fname_crypto_free_buffer(struct f2fs_str *crypto_str)
{
if (!crypto_str)
return;
kfree(crypto_str->name);
crypto_str->name = NULL;
}
/**
* f2fs_fname_disk_to_usr() - converts a filename from disk space to user space
*/
int f2fs_fname_disk_to_usr(struct inode *inode,
f2fs_hash_t *hash,
const struct f2fs_str *iname,
struct f2fs_str *oname)
{
const struct qstr qname = FSTR_TO_QSTR(iname);
char buf[24];
int ret;
if (is_dot_dotdot(&qname)) {
oname->name[0] = '.';
oname->name[iname->len - 1] = '.';
oname->len = iname->len;
return oname->len;
}
if (F2FS_I(inode)->i_crypt_info)
return f2fs_fname_decrypt(inode, iname, oname);
if (iname->len <= F2FS_FNAME_CRYPTO_DIGEST_SIZE) {
ret = digest_encode(iname->name, iname->len, oname->name);
oname->len = ret;
return ret;
}
if (hash) {
memcpy(buf, hash, 4);
memset(buf + 4, 0, 4);
} else
memset(buf, 0, 8);
memcpy(buf + 8, iname->name + iname->len - 16, 16);
oname->name[0] = '_';
ret = digest_encode(buf, 24, oname->name + 1);
oname->len = ret + 1;
return ret + 1;
}
/**
* f2fs_fname_usr_to_disk() - converts a filename from user space to disk space
*/
int f2fs_fname_usr_to_disk(struct inode *inode,
const struct qstr *iname,
struct f2fs_str *oname)
{
int res;
struct f2fs_crypt_info *ci = F2FS_I(inode)->i_crypt_info;
if (is_dot_dotdot(iname)) {
oname->name[0] = '.';
oname->name[iname->len - 1] = '.';
oname->len = iname->len;
return oname->len;
}
if (ci) {
res = f2fs_fname_encrypt(inode, iname, oname);
return res;
}
/* Without a proper key, a user is not allowed to modify the filenames
* in a directory. Consequently, a user space name cannot be mapped to
* a disk-space name */
return -EACCES;
}
int f2fs_fname_setup_filename(struct inode *dir, const struct qstr *iname,
int lookup, struct f2fs_filename *fname)
{
struct f2fs_crypt_info *ci;
int ret = 0, bigname = 0;
memset(fname, 0, sizeof(struct f2fs_filename));
fname->usr_fname = iname;
if (!f2fs_encrypted_inode(dir) || is_dot_dotdot(iname)) {
fname->disk_name.name = (unsigned char *)iname->name;
fname->disk_name.len = iname->len;
return 0;
}
ret = f2fs_get_encryption_info(dir);
if (ret)
return ret;
ci = F2FS_I(dir)->i_crypt_info;
if (ci) {
ret = f2fs_fname_crypto_alloc_buffer(dir, iname->len,
&fname->crypto_buf);
if (ret < 0)
return ret;
ret = f2fs_fname_encrypt(dir, iname, &fname->crypto_buf);
if (ret < 0)
goto errout;
fname->disk_name.name = fname->crypto_buf.name;
fname->disk_name.len = fname->crypto_buf.len;
return 0;
}
if (!lookup)
return -EACCES;
/* We don't have the key and we are doing a lookup; decode the
* user-supplied name
*/
if (iname->name[0] == '_')
bigname = 1;
if ((bigname && (iname->len != 33)) ||
(!bigname && (iname->len > 43)))
return -ENOENT;
fname->crypto_buf.name = kmalloc(32, GFP_KERNEL);
if (fname->crypto_buf.name == NULL)
return -ENOMEM;
ret = digest_decode(iname->name + bigname, iname->len - bigname,
fname->crypto_buf.name);
if (ret < 0) {
ret = -ENOENT;
goto errout;
}
fname->crypto_buf.len = ret;
if (bigname) {
memcpy(&fname->hash, fname->crypto_buf.name, 4);
} else {
fname->disk_name.name = fname->crypto_buf.name;
fname->disk_name.len = fname->crypto_buf.len;
}
return 0;
errout:
f2fs_fname_crypto_free_buffer(&fname->crypto_buf);
return ret;
}
void f2fs_fname_free_filename(struct f2fs_filename *fname)
{
kfree(fname->crypto_buf.name);
fname->crypto_buf.name = NULL;
fname->usr_fname = NULL;
fname->disk_name.name = NULL;
}
/*
* linux/fs/f2fs/crypto_key.c
*
* Copied from linux/fs/f2fs/crypto_key.c
*
* Copyright (C) 2015, Google, Inc.
*
* This contains encryption key functions for f2fs
*
* Written by Michael Halcrow, Ildar Muslukhov, and Uday Savagaonkar, 2015.
*/
#include <keys/encrypted-type.h>
#include <keys/user-type.h>
#include <linux/random.h>
#include <linux/scatterlist.h>
#include <uapi/linux/keyctl.h>
#include <crypto/hash.h>
#include <linux/f2fs_fs.h>
#include "f2fs.h"
#include "xattr.h"
static void derive_crypt_complete(struct crypto_async_request *req, int rc)
{
struct f2fs_completion_result *ecr = req->data;
if (rc == -EINPROGRESS)
return;
ecr->res = rc;
complete(&ecr->completion);
}
/**
* f2fs_derive_key_aes() - Derive a key using AES-128-ECB
* @deriving_key: Encryption key used for derivatio.
* @source_key: Source key to which to apply derivation.
* @derived_key: Derived key.
*
* Return: Zero on success; non-zero otherwise.
*/
static int f2fs_derive_key_aes(char deriving_key[F2FS_AES_128_ECB_KEY_SIZE],
char source_key[F2FS_AES_256_XTS_KEY_SIZE],
char derived_key[F2FS_AES_256_XTS_KEY_SIZE])
{
int res = 0;
struct ablkcipher_request *req = NULL;
DECLARE_F2FS_COMPLETION_RESULT(ecr);
struct scatterlist src_sg, dst_sg;
struct crypto_ablkcipher *tfm = crypto_alloc_ablkcipher("ecb(aes)", 0,
0);
if (IS_ERR(tfm)) {
res = PTR_ERR(tfm);
tfm = NULL;
goto out;
}
crypto_ablkcipher_set_flags(tfm, CRYPTO_TFM_REQ_WEAK_KEY);
req = ablkcipher_request_alloc(tfm, GFP_NOFS);
if (!req) {
res = -ENOMEM;
goto out;
}
ablkcipher_request_set_callback(req,
CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP,
derive_crypt_complete, &ecr);
res = crypto_ablkcipher_setkey(tfm, deriving_key,
F2FS_AES_128_ECB_KEY_SIZE);
if (res < 0)
goto out;
sg_init_one(&src_sg, source_key, F2FS_AES_256_XTS_KEY_SIZE);
sg_init_one(&dst_sg, derived_key, F2FS_AES_256_XTS_KEY_SIZE);
ablkcipher_request_set_crypt(req, &src_sg, &dst_sg,
F2FS_AES_256_XTS_KEY_SIZE, NULL);
res = crypto_ablkcipher_encrypt(req);
if (res == -EINPROGRESS || res == -EBUSY) {
BUG_ON(req->base.data != &ecr);
wait_for_completion(&ecr.completion);
res = ecr.res;
}
out:
if (req)
ablkcipher_request_free(req);
if (tfm)
crypto_free_ablkcipher(tfm);
return res;
}
static void f2fs_free_crypt_info(struct f2fs_crypt_info *ci)
{
if (!ci)
return;
if (ci->ci_keyring_key)
key_put(ci->ci_keyring_key);
crypto_free_ablkcipher(ci->ci_ctfm);
kmem_cache_free(f2fs_crypt_info_cachep, ci);
}
void f2fs_free_encryption_info(struct inode *inode, struct f2fs_crypt_info *ci)
{
struct f2fs_inode_info *fi = F2FS_I(inode);
struct f2fs_crypt_info *prev;
if (ci == NULL)
ci = ACCESS_ONCE(fi->i_crypt_info);
if (ci == NULL)
return;
prev = cmpxchg(&fi->i_crypt_info, ci, NULL);
if (prev != ci)
return;
f2fs_free_crypt_info(ci);
}
int _f2fs_get_encryption_info(struct inode *inode)
{
struct f2fs_inode_info *fi = F2FS_I(inode);
struct f2fs_crypt_info *crypt_info;
char full_key_descriptor[F2FS_KEY_DESC_PREFIX_SIZE +
(F2FS_KEY_DESCRIPTOR_SIZE * 2) + 1];
struct key *keyring_key = NULL;
struct f2fs_encryption_key *master_key;
struct f2fs_encryption_context ctx;
struct user_key_payload *ukp;
struct crypto_ablkcipher *ctfm;
const char *cipher_str;
char raw_key[F2FS_MAX_KEY_SIZE];
char mode;
int res;
res = f2fs_crypto_initialize();
if (res)
return res;
retry:
crypt_info = ACCESS_ONCE(fi->i_crypt_info);
if (crypt_info) {
if (!crypt_info->ci_keyring_key ||
key_validate(crypt_info->ci_keyring_key) == 0)
return 0;
f2fs_free_encryption_info(inode, crypt_info);
goto retry;
}
res = f2fs_getxattr(inode, F2FS_XATTR_INDEX_ENCRYPTION,
F2FS_XATTR_NAME_ENCRYPTION_CONTEXT,
&ctx, sizeof(ctx), NULL);
if (res < 0)
return res;
else if (res != sizeof(ctx))
return -EINVAL;
res = 0;
crypt_info = kmem_cache_alloc(f2fs_crypt_info_cachep, GFP_NOFS);
if (!crypt_info)
return -ENOMEM;
crypt_info->ci_flags = ctx.flags;
crypt_info->ci_data_mode = ctx.contents_encryption_mode;
crypt_info->ci_filename_mode = ctx.filenames_encryption_mode;
crypt_info->ci_ctfm = NULL;
crypt_info->ci_keyring_key = NULL;
memcpy(crypt_info->ci_master_key, ctx.master_key_descriptor,
sizeof(crypt_info->ci_master_key));
if (S_ISREG(inode->i_mode))
mode = crypt_info->ci_data_mode;
else if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode))
mode = crypt_info->ci_filename_mode;
else
BUG();
switch (mode) {
case F2FS_ENCRYPTION_MODE_AES_256_XTS:
cipher_str = "xts(aes)";
break;
case F2FS_ENCRYPTION_MODE_AES_256_CTS:
cipher_str = "cts(cbc(aes))";
break;
default:
printk_once(KERN_WARNING
"f2fs: unsupported key mode %d (ino %u)\n",
mode, (unsigned) inode->i_ino);
res = -ENOKEY;
goto out;
}
memcpy(full_key_descriptor, F2FS_KEY_DESC_PREFIX,
F2FS_KEY_DESC_PREFIX_SIZE);
sprintf(full_key_descriptor + F2FS_KEY_DESC_PREFIX_SIZE,
"%*phN", F2FS_KEY_DESCRIPTOR_SIZE,
ctx.master_key_descriptor);
full_key_descriptor[F2FS_KEY_DESC_PREFIX_SIZE +
(2 * F2FS_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;
BUG_ON(keyring_key->type != &key_type_logon);
ukp = ((struct user_key_payload *)keyring_key->payload.data);
if (ukp->datalen != sizeof(struct f2fs_encryption_key)) {
res = -EINVAL;
goto out;
}
master_key = (struct f2fs_encryption_key *)ukp->data;
BUILD_BUG_ON(F2FS_AES_128_ECB_KEY_SIZE !=
F2FS_KEY_DERIVATION_NONCE_SIZE);
BUG_ON(master_key->size != F2FS_AES_256_XTS_KEY_SIZE);
res = f2fs_derive_key_aes(ctx.nonce, master_key->raw,
raw_key);
if (res)
goto out;
ctfm = crypto_alloc_ablkcipher(cipher_str, 0, 0);
if (!ctfm || IS_ERR(ctfm)) {
res = ctfm ? PTR_ERR(ctfm) : -ENOMEM;
printk(KERN_DEBUG
"%s: error %d (inode %u) allocating crypto tfm\n",
__func__, res, (unsigned) inode->i_ino);
goto out;
}
crypt_info->ci_ctfm = ctfm;
crypto_ablkcipher_clear_flags(ctfm, ~0);
crypto_tfm_set_flags(crypto_ablkcipher_tfm(ctfm),
CRYPTO_TFM_REQ_WEAK_KEY);
res = crypto_ablkcipher_setkey(ctfm, raw_key,
f2fs_encryption_key_size(mode));
if (res)
goto out;
memzero_explicit(raw_key, sizeof(raw_key));
if (cmpxchg(&fi->i_crypt_info, NULL, crypt_info) != NULL) {
f2fs_free_crypt_info(crypt_info);
goto retry;
}
return 0;
out:
if (res == -ENOKEY && !S_ISREG(inode->i_mode))
res = 0;
f2fs_free_crypt_info(crypt_info);
memzero_explicit(raw_key, sizeof(raw_key));
return res;
}
int f2fs_has_encryption_key(struct inode *inode)
{
struct f2fs_inode_info *fi = F2FS_I(inode);
return (fi->i_crypt_info != NULL);
}
/*
* copied from linux/fs/ext4/crypto_policy.c
*
* Copyright (C) 2015, Google, Inc.
* Copyright (C) 2015, Motorola Mobility.
*
* This contains encryption policy functions for f2fs with some modifications
* to support f2fs-specific xattr APIs.
*
* Written by Michael Halcrow, 2015.
* Modified by Jaegeuk Kim, 2015.
*/
#include <linux/random.h>
#include <linux/string.h>
#include <linux/types.h>
#include <linux/f2fs_fs.h>
#include "f2fs.h"
#include "xattr.h"
static int f2fs_inode_has_encryption_context(struct inode *inode)
{
int res = f2fs_getxattr(inode, F2FS_XATTR_INDEX_ENCRYPTION,
F2FS_XATTR_NAME_ENCRYPTION_CONTEXT, NULL, 0, NULL);
return (res > 0);
}
/*
* check whether the policy is consistent with the encryption context
* for the inode
*/
static int f2fs_is_encryption_context_consistent_with_policy(
struct inode *inode, const struct f2fs_encryption_policy *policy)
{
struct f2fs_encryption_context ctx;
int res = f2fs_getxattr(inode, F2FS_XATTR_INDEX_ENCRYPTION,
F2FS_XATTR_NAME_ENCRYPTION_CONTEXT, &ctx,
sizeof(ctx), NULL);
if (res != sizeof(ctx))
return 0;
return (memcmp(ctx.master_key_descriptor, policy->master_key_descriptor,
F2FS_KEY_DESCRIPTOR_SIZE) == 0 &&
(ctx.flags == policy->flags) &&
(ctx.contents_encryption_mode ==
policy->contents_encryption_mode) &&
(ctx.filenames_encryption_mode ==
policy->filenames_encryption_mode));
}
static int f2fs_create_encryption_context_from_policy(
struct inode *inode, const struct f2fs_encryption_policy *policy)
{
struct f2fs_encryption_context ctx;
ctx.format = F2FS_ENCRYPTION_CONTEXT_FORMAT_V1;
memcpy(ctx.master_key_descriptor, policy->master_key_descriptor,
F2FS_KEY_DESCRIPTOR_SIZE);
if (!f2fs_valid_contents_enc_mode(policy->contents_encryption_mode)) {
printk(KERN_WARNING
"%s: Invalid contents encryption mode %d\n", __func__,
policy->contents_encryption_mode);
return -EINVAL;
}
if (!f2fs_valid_filenames_enc_mode(policy->filenames_encryption_mode)) {
printk(KERN_WARNING
"%s: Invalid filenames encryption mode %d\n", __func__,
policy->filenames_encryption_mode);
return -EINVAL;
}
if (policy->flags & ~F2FS_POLICY_FLAGS_VALID)
return -EINVAL;
ctx.contents_encryption_mode = policy->contents_encryption_mode;
ctx.filenames_encryption_mode = policy->filenames_encryption_mode;
ctx.flags = policy->flags;
BUILD_BUG_ON(sizeof(ctx.nonce) != F2FS_KEY_DERIVATION_NONCE_SIZE);
get_random_bytes(ctx.nonce, F2FS_KEY_DERIVATION_NONCE_SIZE);
return f2fs_setxattr(inode, F2FS_XATTR_INDEX_ENCRYPTION,
F2FS_XATTR_NAME_ENCRYPTION_CONTEXT, &ctx,
sizeof(ctx), NULL, XATTR_CREATE);
}
int f2fs_process_policy(const struct f2fs_encryption_policy *policy,
struct inode *inode)
{
if (policy->version != 0)
return -EINVAL;
if (!S_ISDIR(inode->i_mode))
return -EINVAL;
if (!f2fs_inode_has_encryption_context(inode)) {
if (!f2fs_empty_dir(inode))
return -ENOTEMPTY;
return f2fs_create_encryption_context_from_policy(inode,
policy);
}
if (f2fs_is_encryption_context_consistent_with_policy(inode, policy))
return 0;
printk(KERN_WARNING "%s: Policy inconsistent with encryption context\n",
__func__);
return -EINVAL;
}
int f2fs_get_policy(struct inode *inode, struct f2fs_encryption_policy *policy)
{
struct f2fs_encryption_context ctx;
int res;
if (!f2fs_encrypted_inode(inode))
return -ENODATA;
res = f2fs_getxattr(inode, F2FS_XATTR_INDEX_ENCRYPTION,
F2FS_XATTR_NAME_ENCRYPTION_CONTEXT,
&ctx, sizeof(ctx), NULL);
if (res != sizeof(ctx))
return -ENODATA;
if (ctx.format != F2FS_ENCRYPTION_CONTEXT_FORMAT_V1)
return -EINVAL;
policy->version = 0;
policy->contents_encryption_mode = ctx.contents_encryption_mode;
policy->filenames_encryption_mode = ctx.filenames_encryption_mode;
policy->flags = ctx.flags;
memcpy(&policy->master_key_descriptor, ctx.master_key_descriptor,
F2FS_KEY_DESCRIPTOR_SIZE);
return 0;
}
int f2fs_is_child_context_consistent_with_parent(struct inode *parent,
struct inode *child)
{
struct f2fs_crypt_info *parent_ci, *child_ci;
int res;
if ((parent == NULL) || (child == NULL)) {
pr_err("parent %p child %p\n", parent, child);
BUG_ON(1);
}
/* no restrictions if the parent directory is not encrypted */
if (!f2fs_encrypted_inode(parent))
return 1;
/* if the child directory is not encrypted, this is always a problem */
if (!f2fs_encrypted_inode(child))
return 0;
res = f2fs_get_encryption_info(parent);
if (res)
return 0;
res = f2fs_get_encryption_info(child);
if (res)
return 0;
parent_ci = F2FS_I(parent)->i_crypt_info;
child_ci = F2FS_I(child)->i_crypt_info;
if (!parent_ci && !child_ci)
return 1;
if (!parent_ci || !child_ci)
return 0;
return (memcmp(parent_ci->ci_master_key,
child_ci->ci_master_key,
F2FS_KEY_DESCRIPTOR_SIZE) == 0 &&
(parent_ci->ci_data_mode == child_ci->ci_data_mode) &&
(parent_ci->ci_filename_mode == child_ci->ci_filename_mode) &&
(parent_ci->ci_flags == child_ci->ci_flags));
}
/**
* f2fs_inherit_context() - Sets a child context from its parent
* @parent: Parent inode from which the context is inherited.
* @child: Child inode that inherits the context from @parent.
*
* Return: Zero on success, non-zero otherwise
*/
int f2fs_inherit_context(struct inode *parent, struct inode *child,
struct page *ipage)
{
struct f2fs_encryption_context ctx;
struct f2fs_crypt_info *ci;
int res;
res = f2fs_get_encryption_info(parent);
if (res < 0)
return res;
ci = F2FS_I(parent)->i_crypt_info;
BUG_ON(ci == NULL);
ctx.format = F2FS_ENCRYPTION_CONTEXT_FORMAT_V1;
ctx.contents_encryption_mode = ci->ci_data_mode;
ctx.filenames_encryption_mode = ci->ci_filename_mode;
ctx.flags = ci->ci_flags;
memcpy(ctx.master_key_descriptor, ci->ci_master_key,
F2FS_KEY_DESCRIPTOR_SIZE);
get_random_bytes(ctx.nonce, F2FS_KEY_DERIVATION_NONCE_SIZE);
return f2fs_setxattr(child, F2FS_XATTR_INDEX_ENCRYPTION,
F2FS_XATTR_NAME_ENCRYPTION_CONTEXT, &ctx,
sizeof(ctx), ipage, XATTR_CREATE);
}
此差异已折叠。
......@@ -94,7 +94,8 @@ static void update_general_status(struct f2fs_sb_info *sbi)
static void update_sit_info(struct f2fs_sb_info *sbi)
{
struct f2fs_stat_info *si = F2FS_STAT(sbi);
unsigned int blks_per_sec, hblks_per_sec, total_vblocks, bimodal, dist;
unsigned long long blks_per_sec, hblks_per_sec, total_vblocks;
unsigned long long bimodal, dist;
unsigned int segno, vblocks;
int ndirty = 0;
......@@ -112,10 +113,10 @@ static void update_sit_info(struct f2fs_sb_info *sbi)
ndirty++;
}
}
dist = MAIN_SECS(sbi) * hblks_per_sec * hblks_per_sec / 100;
si->bimodal = bimodal / dist;
dist = div_u64(MAIN_SECS(sbi) * hblks_per_sec * hblks_per_sec, 100);
si->bimodal = div_u64(bimodal, dist);
if (si->dirty_count)
si->avg_vblocks = total_vblocks / ndirty;
si->avg_vblocks = div_u64(total_vblocks, ndirty);
else
si->avg_vblocks = 0;
}
......@@ -143,7 +144,7 @@ static void update_mem_info(struct f2fs_sb_info *sbi)
si->base_mem += sizeof(struct sit_info);
si->base_mem += MAIN_SEGS(sbi) * sizeof(struct seg_entry);
si->base_mem += f2fs_bitmap_size(MAIN_SEGS(sbi));
si->base_mem += 2 * SIT_VBLOCK_MAP_SIZE * MAIN_SEGS(sbi);
si->base_mem += 3 * SIT_VBLOCK_MAP_SIZE * MAIN_SEGS(sbi);
si->base_mem += SIT_VBLOCK_MAP_SIZE;
if (sbi->segs_per_sec > 1)
si->base_mem += MAIN_SECS(sbi) * sizeof(struct sec_entry);
......
......@@ -76,20 +76,10 @@ static unsigned long dir_block_index(unsigned int level,
return bidx;
}
static bool early_match_name(size_t namelen, f2fs_hash_t namehash,
struct f2fs_dir_entry *de)
{
if (le16_to_cpu(de->name_len) != namelen)
return false;
if (de->hash_code != namehash)
return false;
return true;
}
static struct f2fs_dir_entry *find_in_block(struct page *dentry_page,
struct qstr *name, int *max_slots,
struct f2fs_filename *fname,
f2fs_hash_t namehash,
int *max_slots,
struct page **res_page)
{
struct f2fs_dentry_block *dentry_blk;
......@@ -98,9 +88,8 @@ static struct f2fs_dir_entry *find_in_block(struct page *dentry_page,
dentry_blk = (struct f2fs_dentry_block *)kmap(dentry_page);
make_dentry_ptr(&d, (void *)dentry_blk, 1);
de = find_target_dentry(name, max_slots, &d);
make_dentry_ptr(NULL, &d, (void *)dentry_blk, 1);
de = find_target_dentry(fname, namehash, max_slots, &d);
if (de)
*res_page = dentry_page;
else
......@@ -114,13 +103,15 @@ static struct f2fs_dir_entry *find_in_block(struct page *dentry_page,
return de;
}
struct f2fs_dir_entry *find_target_dentry(struct qstr *name, int *max_slots,
struct f2fs_dir_entry *find_target_dentry(struct f2fs_filename *fname,
f2fs_hash_t namehash, int *max_slots,
struct f2fs_dentry_ptr *d)
{
struct f2fs_dir_entry *de;
unsigned long bit_pos = 0;
f2fs_hash_t namehash = f2fs_dentry_hash(name);
int max_len = 0;
struct f2fs_str de_name = FSTR_INIT(NULL, 0);
struct f2fs_str *name = &fname->disk_name;
if (max_slots)
*max_slots = 0;
......@@ -132,8 +123,18 @@ struct f2fs_dir_entry *find_target_dentry(struct qstr *name, int *max_slots,
}
de = &d->dentry[bit_pos];
if (early_match_name(name->len, namehash, de) &&
!memcmp(d->filename[bit_pos], name->name, name->len))
/* encrypted case */
de_name.name = d->filename[bit_pos];
de_name.len = le16_to_cpu(de->name_len);
/* show encrypted name */
if (fname->hash) {
if (de->hash_code == fname->hash)
goto found;
} else if (de_name.len == name->len &&
de->hash_code == namehash &&
!memcmp(de_name.name, name->name, name->len))
goto found;
if (max_slots && max_len > *max_slots)
......@@ -155,16 +156,21 @@ struct f2fs_dir_entry *find_target_dentry(struct qstr *name, int *max_slots,
}
static struct f2fs_dir_entry *find_in_level(struct inode *dir,
unsigned int level, struct qstr *name,
f2fs_hash_t namehash, struct page **res_page)
unsigned int level,
struct f2fs_filename *fname,
struct page **res_page)
{
int s = GET_DENTRY_SLOTS(name->len);
struct qstr name = FSTR_TO_QSTR(&fname->disk_name);
int s = GET_DENTRY_SLOTS(name.len);
unsigned int nbucket, nblock;
unsigned int bidx, end_block;
struct page *dentry_page;
struct f2fs_dir_entry *de = NULL;
bool room = false;
int max_slots;
f2fs_hash_t namehash;
namehash = f2fs_dentry_hash(&name);
f2fs_bug_on(F2FS_I_SB(dir), level > MAX_DIR_HASH_DEPTH);
......@@ -177,13 +183,14 @@ static struct f2fs_dir_entry *find_in_level(struct inode *dir,
for (; bidx < end_block; bidx++) {
/* no need to allocate new dentry pages to all the indices */
dentry_page = find_data_page(dir, bidx, true);
dentry_page = find_data_page(dir, bidx);
if (IS_ERR(dentry_page)) {
room = true;
continue;
}
de = find_in_block(dentry_page, name, &max_slots, res_page);
de = find_in_block(dentry_page, fname, namehash, &max_slots,
res_page);
if (de)
break;
......@@ -211,30 +218,34 @@ struct f2fs_dir_entry *f2fs_find_entry(struct inode *dir,
{
unsigned long npages = dir_blocks(dir);
struct f2fs_dir_entry *de = NULL;
f2fs_hash_t name_hash;
unsigned int max_depth;
unsigned int level;
struct f2fs_filename fname;
int err;
*res_page = NULL;
if (f2fs_has_inline_dentry(dir))
return find_in_inline_dir(dir, child, res_page);
err = f2fs_fname_setup_filename(dir, child, 1, &fname);
if (err)
return NULL;
if (f2fs_has_inline_dentry(dir)) {
de = find_in_inline_dir(dir, &fname, res_page);
goto out;
}
if (npages == 0)
return NULL;
goto out;
name_hash = f2fs_dentry_hash(child);
max_depth = F2FS_I(dir)->i_current_depth;
for (level = 0; level < max_depth; level++) {
de = find_in_level(dir, level, child, name_hash, res_page);
de = find_in_level(dir, level, &fname, res_page);
if (de)
break;
}
if (!de && F2FS_I(dir)->chash != name_hash) {
F2FS_I(dir)->chash = name_hash;
F2FS_I(dir)->clevel = level - 1;
}
out:
f2fs_fname_free_filename(&fname);
return de;
}
......@@ -303,10 +314,14 @@ static void init_dent_inode(const struct qstr *name, struct page *ipage)
set_page_dirty(ipage);
}
int update_dent_inode(struct inode *inode, const struct qstr *name)
int update_dent_inode(struct inode *inode, struct inode *to,
const struct qstr *name)
{
struct page *page;
if (file_enc_name(to))
return 0;
page = get_node_page(F2FS_I_SB(inode), inode->i_ino);
if (IS_ERR(page))
return PTR_ERR(page);
......@@ -356,7 +371,7 @@ static int make_empty_dir(struct inode *inode,
dentry_blk = kmap_atomic(dentry_page);
make_dentry_ptr(&d, (void *)dentry_blk, 1);
make_dentry_ptr(NULL, &d, (void *)dentry_blk, 1);
do_make_empty_dir(inode, parent, &d);
kunmap_atomic(dentry_blk);
......@@ -390,6 +405,12 @@ struct page *init_inode_metadata(struct inode *inode, struct inode *dir,
err = f2fs_init_security(inode, dir, name, page);
if (err)
goto put_error;
if (f2fs_encrypted_inode(dir) && f2fs_may_encrypt(inode)) {
err = f2fs_inherit_context(dir, inode, page);
if (err)
goto put_error;
}
} else {
page = get_node_page(F2FS_I_SB(dir), inode->i_ino);
if (IS_ERR(page))
......@@ -501,24 +522,33 @@ int __f2fs_add_link(struct inode *dir, const struct qstr *name,
unsigned long bidx, block;
f2fs_hash_t dentry_hash;
unsigned int nbucket, nblock;
size_t namelen = name->len;
struct page *dentry_page = NULL;
struct f2fs_dentry_block *dentry_blk = NULL;
struct f2fs_dentry_ptr d;
int slots = GET_DENTRY_SLOTS(namelen);
struct page *page = NULL;
int err = 0;
struct f2fs_filename fname;
struct qstr new_name;
int slots, err;
err = f2fs_fname_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, name, inode, ino, mode);
err = f2fs_add_inline_entry(dir, &new_name, inode, ino, mode);
if (!err || err != -EAGAIN)
return err;
goto out;
else
err = 0;
}
dentry_hash = f2fs_dentry_hash(name);
level = 0;
slots = GET_DENTRY_SLOTS(new_name.len);
dentry_hash = f2fs_dentry_hash(&new_name);
current_depth = F2FS_I(dir)->i_current_depth;
if (F2FS_I(dir)->chash == dentry_hash) {
level = F2FS_I(dir)->clevel;
......@@ -526,8 +556,10 @@ int __f2fs_add_link(struct inode *dir, const struct qstr *name,
}
start:
if (unlikely(current_depth == MAX_DIR_HASH_DEPTH))
return -ENOSPC;
if (unlikely(current_depth == MAX_DIR_HASH_DEPTH)) {
err = -ENOSPC;
goto out;
}
/* Increase the depth, if required */
if (level == current_depth)
......@@ -541,8 +573,10 @@ int __f2fs_add_link(struct inode *dir, const struct qstr *name,
for (block = bidx; block <= (bidx + nblock - 1); block++) {
dentry_page = get_new_data_page(dir, NULL, block, true);
if (IS_ERR(dentry_page))
return PTR_ERR(dentry_page);
if (IS_ERR(dentry_page)) {
err = PTR_ERR(dentry_page);
goto out;
}
dentry_blk = kmap(dentry_page);
bit_pos = room_for_filename(&dentry_blk->dentry_bitmap,
......@@ -562,15 +596,17 @@ int __f2fs_add_link(struct inode *dir, const struct qstr *name,
if (inode) {
down_write(&F2FS_I(inode)->i_sem);
page = init_inode_metadata(inode, dir, name, NULL);
page = init_inode_metadata(inode, dir, &new_name, NULL);
if (IS_ERR(page)) {
err = PTR_ERR(page);
goto fail;
}
if (f2fs_encrypted_inode(dir))
file_set_enc_name(inode);
}
make_dentry_ptr(&d, (void *)dentry_blk, 1);
f2fs_update_dentry(ino, mode, &d, name, dentry_hash, bit_pos);
make_dentry_ptr(NULL, &d, (void *)dentry_blk, 1);
f2fs_update_dentry(ino, mode, &d, &new_name, dentry_hash, bit_pos);
set_page_dirty(dentry_page);
......@@ -592,6 +628,8 @@ int __f2fs_add_link(struct inode *dir, const struct qstr *name,
}
kunmap(dentry_page);
f2fs_put_page(dentry_page, 1);
out:
f2fs_fname_free_filename(&fname);
return err;
}
......@@ -729,11 +767,12 @@ bool f2fs_empty_dir(struct inode *dir)
}
bool f2fs_fill_dentries(struct dir_context *ctx, struct f2fs_dentry_ptr *d,
unsigned int start_pos)
unsigned int start_pos, struct f2fs_str *fstr)
{
unsigned char d_type = DT_UNKNOWN;
unsigned int bit_pos;
struct f2fs_dir_entry *de = NULL;
struct f2fs_str de_name = FSTR_INIT(NULL, 0);
bit_pos = ((unsigned long)ctx->pos % d->max);
......@@ -747,8 +786,24 @@ bool f2fs_fill_dentries(struct dir_context *ctx, struct f2fs_dentry_ptr *d,
d_type = f2fs_filetype_table[de->file_type];
else
d_type = DT_UNKNOWN;
if (!dir_emit(ctx, d->filename[bit_pos],
le16_to_cpu(de->name_len),
/* encrypted case */
de_name.name = d->filename[bit_pos];
de_name.len = le16_to_cpu(de->name_len);
if (f2fs_encrypted_inode(d->inode)) {
int save_len = fstr->len;
int ret;
ret = f2fs_fname_disk_to_usr(d->inode, &de->hash_code,
&de_name, fstr);
de_name = *fstr;
fstr->len = save_len;
if (ret < 0)
return true;
}
if (!dir_emit(ctx, de_name.name, de_name.len,
le32_to_cpu(de->ino), d_type))
return true;
......@@ -767,9 +822,24 @@ static int f2fs_readdir(struct file *file, struct dir_context *ctx)
struct file_ra_state *ra = &file->f_ra;
unsigned int n = ((unsigned long)ctx->pos / NR_DENTRY_IN_BLOCK);
struct f2fs_dentry_ptr d;
struct f2fs_str fstr = FSTR_INIT(NULL, 0);
int err = 0;
if (f2fs_has_inline_dentry(inode))
return f2fs_read_inline_dir(file, ctx);
if (f2fs_encrypted_inode(inode)) {
err = f2fs_get_encryption_info(inode);
if (err)
return err;
err = f2fs_fname_crypto_alloc_buffer(inode, F2FS_NAME_LEN,
&fstr);
if (err < 0)
return err;
}
if (f2fs_has_inline_dentry(inode)) {
err = f2fs_read_inline_dir(file, ctx, &fstr);
goto out;
}
/* readahead for multi pages of dir */
if (npages - n > 1 && !ra_has_index(ra, n))
......@@ -783,9 +853,9 @@ static int f2fs_readdir(struct file *file, struct dir_context *ctx)
dentry_blk = kmap(dentry_page);
make_dentry_ptr(&d, (void *)dentry_blk, 1);
make_dentry_ptr(inode, &d, (void *)dentry_blk, 1);
if (f2fs_fill_dentries(ctx, &d, n * NR_DENTRY_IN_BLOCK))
if (f2fs_fill_dentries(ctx, &d, n * NR_DENTRY_IN_BLOCK, &fstr))
goto stop;
ctx->pos = (n + 1) * NR_DENTRY_IN_BLOCK;
......@@ -798,8 +868,9 @@ static int f2fs_readdir(struct file *file, struct dir_context *ctx)
kunmap(dentry_page);
f2fs_put_page(dentry_page, 1);
}
return 0;
out:
f2fs_fname_crypto_free_buffer(&fstr);
return err;
}
const struct file_operations f2fs_dir_operations = {
......@@ -808,4 +879,7 @@ const struct file_operations f2fs_dir_operations = {
.iterate = f2fs_readdir,
.fsync = f2fs_sync_file,
.unlocked_ioctl = f2fs_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = f2fs_compat_ioctl,
#endif
};
......@@ -70,6 +70,15 @@ struct f2fs_mount_info {
unsigned int opt;
};
#define F2FS_FEATURE_ENCRYPT 0x0001
#define F2FS_HAS_FEATURE(sb, mask) \
((F2FS_SB(sb)->raw_super->feature & cpu_to_le32(mask)) != 0)
#define F2FS_SET_FEATURE(sb, mask) \
F2FS_SB(sb)->raw_super->feature |= cpu_to_le32(mask)
#define F2FS_CLEAR_FEATURE(sb, mask) \
F2FS_SB(sb)->raw_super->feature &= ~cpu_to_le32(mask)
#define CRCPOLY_LE 0xedb88320
static inline __u32 f2fs_crc32(void *buf, size_t len)
......@@ -110,6 +119,8 @@ enum {
#define DEF_BATCHED_TRIM_SECTIONS 32
#define BATCHED_TRIM_SEGMENTS(sbi) \
(SM_I(sbi)->trim_sections * (sbi)->segs_per_sec)
#define BATCHED_TRIM_BLOCKS(sbi) \
(BATCHED_TRIM_SEGMENTS(sbi) << (sbi)->log_blocks_per_seg)
struct cp_control {
int reason;
......@@ -218,6 +229,13 @@ static inline bool __has_cursum_space(struct f2fs_summary_block *sum, int size,
#define F2FS_IOC_RELEASE_VOLATILE_WRITE _IO(F2FS_IOCTL_MAGIC, 4)
#define F2FS_IOC_ABORT_VOLATILE_WRITE _IO(F2FS_IOCTL_MAGIC, 5)
#define F2FS_IOC_SET_ENCRYPTION_POLICY \
_IOR('f', 19, struct f2fs_encryption_policy)
#define F2FS_IOC_GET_ENCRYPTION_PWSALT \
_IOW('f', 20, __u8[16])
#define F2FS_IOC_GET_ENCRYPTION_POLICY \
_IOW('f', 21, struct f2fs_encryption_policy)
/*
* should be same as XFS_IOC_GOINGDOWN.
* Flags for going down operation used by FS_IOC_GOINGDOWN
......@@ -239,16 +257,38 @@ static inline bool __has_cursum_space(struct f2fs_summary_block *sum, int size,
* For INODE and NODE manager
*/
/* for directory operations */
struct f2fs_str {
unsigned char *name;
u32 len;
};
struct f2fs_filename {
const struct qstr *usr_fname;
struct f2fs_str disk_name;
f2fs_hash_t hash;
#ifdef CONFIG_F2FS_FS_ENCRYPTION
struct f2fs_str crypto_buf;
#endif
};
#define FSTR_INIT(n, l) { .name = n, .len = l }
#define FSTR_TO_QSTR(f) QSTR_INIT((f)->name, (f)->len)
#define fname_name(p) ((p)->disk_name.name)
#define fname_len(p) ((p)->disk_name.len)
struct f2fs_dentry_ptr {
struct inode *inode;
const void *bitmap;
struct f2fs_dir_entry *dentry;
__u8 (*filename)[F2FS_SLOT_LEN];
int max;
};
static inline void make_dentry_ptr(struct f2fs_dentry_ptr *d,
void *src, int type)
static inline void make_dentry_ptr(struct inode *inode,
struct f2fs_dentry_ptr *d, void *src, int type)
{
d->inode = inode;
if (type == 1) {
struct f2fs_dentry_block *t = (struct f2fs_dentry_block *)src;
d->max = NR_DENTRY_IN_BLOCK;
......@@ -314,11 +354,52 @@ struct extent_tree {
unsigned int count; /* # of extent node in rb-tree*/
};
/*
* This structure is taken from ext4_map_blocks.
*
* Note that, however, f2fs uses NEW and MAPPED flags for f2fs_map_blocks().
*/
#define F2FS_MAP_NEW (1 << BH_New)
#define F2FS_MAP_MAPPED (1 << BH_Mapped)
#define F2FS_MAP_UNWRITTEN (1 << BH_Unwritten)
#define F2FS_MAP_FLAGS (F2FS_MAP_NEW | F2FS_MAP_MAPPED |\
F2FS_MAP_UNWRITTEN)
struct f2fs_map_blocks {
block_t m_pblk;
block_t m_lblk;
unsigned int m_len;
unsigned int m_flags;
};
/*
* i_advise uses FADVISE_XXX_BIT. We can add additional hints later.
*/
#define FADVISE_COLD_BIT 0x01
#define FADVISE_LOST_PINO_BIT 0x02
#define FADVISE_ENCRYPT_BIT 0x04
#define FADVISE_ENC_NAME_BIT 0x08
#define file_is_cold(inode) is_file(inode, FADVISE_COLD_BIT)
#define file_wrong_pino(inode) is_file(inode, FADVISE_LOST_PINO_BIT)
#define file_set_cold(inode) set_file(inode, FADVISE_COLD_BIT)
#define file_lost_pino(inode) set_file(inode, FADVISE_LOST_PINO_BIT)
#define file_clear_cold(inode) clear_file(inode, FADVISE_COLD_BIT)
#define file_got_pino(inode) clear_file(inode, FADVISE_LOST_PINO_BIT)
#define file_is_encrypt(inode) is_file(inode, FADVISE_ENCRYPT_BIT)
#define file_set_encrypt(inode) set_file(inode, FADVISE_ENCRYPT_BIT)
#define file_clear_encrypt(inode) clear_file(inode, FADVISE_ENCRYPT_BIT)
#define file_enc_name(inode) is_file(inode, FADVISE_ENC_NAME_BIT)
#define file_set_enc_name(inode) set_file(inode, FADVISE_ENC_NAME_BIT)
/* Encryption algorithms */
#define F2FS_ENCRYPTION_MODE_INVALID 0
#define F2FS_ENCRYPTION_MODE_AES_256_XTS 1
#define F2FS_ENCRYPTION_MODE_AES_256_GCM 2
#define F2FS_ENCRYPTION_MODE_AES_256_CBC 3
#define F2FS_ENCRYPTION_MODE_AES_256_CTS 4
#include "f2fs_crypto.h"
#define DEF_DIR_LEVEL 0
......@@ -346,6 +427,11 @@ struct f2fs_inode_info {
struct radix_tree_root inmem_root; /* radix tree for inmem pages */
struct list_head inmem_pages; /* inmemory pages managed by f2fs */
struct mutex inmem_lock; /* lock for inmemory pages */
#ifdef CONFIG_F2FS_FS_ENCRYPTION
/* Encryption params */
struct f2fs_crypt_info *i_crypt_info;
#endif
};
static inline void get_extent_info(struct extent_info *ext,
......@@ -571,9 +657,12 @@ enum page_type {
};
struct f2fs_io_info {
struct f2fs_sb_info *sbi; /* f2fs_sb_info pointer */
enum page_type type; /* contains DATA/NODE/META/META_FLUSH */
int rw; /* contains R/RS/W/WS with REQ_META/REQ_PRIO */
block_t blk_addr; /* block address to be written */
struct page *page; /* page to be written */
struct page *encrypted_page; /* encrypted page */
};
#define is_read_io(rw) (((rw) & 1) == READ)
......@@ -666,6 +755,7 @@ struct f2fs_sb_info {
block_t user_block_count; /* # of user blocks */
block_t total_valid_block_count; /* # of valid blocks */
block_t alloc_valid_block_count; /* # of allocated blocks */
block_t discard_blks; /* discard command candidats */
block_t last_valid_block_count; /* for recovery */
u32 s_next_generation; /* for NFS support */
atomic_t nr_pages[NR_COUNT_TYPE]; /* # of pages, see count_type */
......@@ -1193,6 +1283,24 @@ static inline int f2fs_test_bit(unsigned int nr, char *addr)
return mask & *addr;
}
static inline void f2fs_set_bit(unsigned int nr, char *addr)
{
int mask;
addr += (nr >> 3);
mask = 1 << (7 - (nr & 0x07));
*addr |= mask;
}
static inline void f2fs_clear_bit(unsigned int nr, char *addr)
{
int mask;
addr += (nr >> 3);
mask = 1 << (7 - (nr & 0x07));
*addr &= ~mask;
}
static inline int f2fs_test_and_set_bit(unsigned int nr, char *addr)
{
int mask;
......@@ -1391,6 +1499,21 @@ static inline void f2fs_dentry_kunmap(struct inode *dir, struct page *page)
kunmap(page);
}
static inline int is_file(struct inode *inode, int type)
{
return F2FS_I(inode)->i_advise & type;
}
static inline void set_file(struct inode *inode, int type)
{
F2FS_I(inode)->i_advise |= type;
}
static inline void clear_file(struct inode *inode, int type)
{
F2FS_I(inode)->i_advise &= ~type;
}
static inline int f2fs_readonly(struct super_block *sb)
{
return sb->s_flags & MS_RDONLY;
......@@ -1407,6 +1530,17 @@ static inline void f2fs_stop_checkpoint(struct f2fs_sb_info *sbi)
sbi->sb->s_flags |= MS_RDONLY;
}
static inline bool is_dot_dotdot(const struct qstr *str)
{
if (str->len == 1 && str->name[0] == '.')
return true;
if (str->len == 2 && str->name[0] == '.' && str->name[1] == '.')
return true;
return false;
}
#define get_inode_mode(i) \
((is_inode_flag_set(F2FS_I(i), FI_ACL_MODE)) ? \
(F2FS_I(i)->i_acl_mode) : ((i)->i_mode))
......@@ -1453,10 +1587,11 @@ struct dentry *f2fs_get_parent(struct dentry *child);
*/
extern unsigned char f2fs_filetype_table[F2FS_FT_MAX];
void set_de_type(struct f2fs_dir_entry *, umode_t);
struct f2fs_dir_entry *find_target_dentry(struct qstr *, int *,
struct f2fs_dentry_ptr *);
struct f2fs_dir_entry *find_target_dentry(struct f2fs_filename *,
f2fs_hash_t, int *, struct f2fs_dentry_ptr *);
bool f2fs_fill_dentries(struct dir_context *, struct f2fs_dentry_ptr *,
unsigned int);
unsigned int, struct f2fs_str *);
void do_make_empty_dir(struct inode *, struct inode *,
struct f2fs_dentry_ptr *);
struct page *init_inode_metadata(struct inode *, struct inode *,
......@@ -1470,7 +1605,7 @@ struct f2fs_dir_entry *f2fs_parent_dir(struct inode *, struct page **);
ino_t f2fs_inode_by_name(struct inode *, struct qstr *);
void f2fs_set_link(struct inode *, struct f2fs_dir_entry *,
struct page *, struct inode *);
int update_dent_inode(struct inode *, const struct qstr *);
int update_dent_inode(struct inode *, struct inode *, const struct qstr *);
void f2fs_update_dentry(nid_t ino, umode_t mode, struct f2fs_dentry_ptr *,
const struct qstr *, f2fs_hash_t , unsigned int);
int __f2fs_add_link(struct inode *, const struct qstr *, struct inode *, nid_t,
......@@ -1478,7 +1613,6 @@ int __f2fs_add_link(struct inode *, const struct qstr *, struct inode *, nid_t,
void f2fs_delete_entry(struct f2fs_dir_entry *, struct page *, struct inode *,
struct inode *);
int f2fs_do_tmpfile(struct inode *, struct inode *);
int f2fs_make_empty(struct inode *, struct inode *);
bool f2fs_empty_dir(struct inode *);
static inline int f2fs_add_link(struct dentry *dentry, struct inode *inode)
......@@ -1490,6 +1624,7 @@ static inline int f2fs_add_link(struct dentry *dentry, struct inode *inode)
/*
* super.c
*/
int f2fs_commit_super(struct f2fs_sb_info *, bool);
int f2fs_sync_fs(struct super_block *, int);
extern __printf(3, 4)
void f2fs_msg(struct super_block *, const char *, const char *, ...);
......@@ -1506,8 +1641,8 @@ struct dnode_of_data;
struct node_info;
bool available_free_memory(struct f2fs_sb_info *, int);
int need_dentry_mark(struct f2fs_sb_info *, nid_t);
bool is_checkpointed_node(struct f2fs_sb_info *, nid_t);
bool has_fsynced_inode(struct f2fs_sb_info *, nid_t);
bool need_inode_block_update(struct f2fs_sb_info *, nid_t);
void get_node_info(struct f2fs_sb_info *, nid_t, struct node_info *);
int get_dnode_of_data(struct dnode_of_data *, pgoff_t, int);
......@@ -1548,21 +1683,20 @@ int create_flush_cmd_control(struct f2fs_sb_info *);
void destroy_flush_cmd_control(struct f2fs_sb_info *);
void invalidate_blocks(struct f2fs_sb_info *, block_t);
void refresh_sit_entry(struct f2fs_sb_info *, block_t, block_t);
void clear_prefree_segments(struct f2fs_sb_info *);
void clear_prefree_segments(struct f2fs_sb_info *, struct cp_control *);
void release_discard_addrs(struct f2fs_sb_info *);
void discard_next_dnode(struct f2fs_sb_info *, block_t);
int npages_for_summary_flush(struct f2fs_sb_info *, bool);
void allocate_new_segments(struct f2fs_sb_info *);
int f2fs_trim_fs(struct f2fs_sb_info *, struct fstrim_range *);
struct page *get_sum_page(struct f2fs_sb_info *, unsigned int);
void update_meta_page(struct f2fs_sb_info *, void *, block_t);
void write_meta_page(struct f2fs_sb_info *, struct page *);
void write_node_page(struct f2fs_sb_info *, struct page *,
unsigned int, struct f2fs_io_info *);
void write_data_page(struct page *, struct dnode_of_data *,
struct f2fs_io_info *);
void rewrite_data_page(struct page *, struct f2fs_io_info *);
void recover_data_page(struct f2fs_sb_info *, struct page *,
struct f2fs_summary *, block_t, block_t);
void write_node_page(unsigned int, struct f2fs_io_info *);
void write_data_page(struct dnode_of_data *, struct f2fs_io_info *);
void rewrite_data_page(struct f2fs_io_info *);
void f2fs_replace_block(struct f2fs_sb_info *, struct dnode_of_data *,
block_t, block_t, unsigned char, bool);
void allocate_data_block(struct f2fs_sb_info *, struct page *,
block_t, block_t *, struct f2fs_summary *, int);
void f2fs_wait_on_page_writeback(struct page *, enum page_type);
......@@ -1581,6 +1715,7 @@ void destroy_segment_manager_caches(void);
*/
struct page *grab_meta_page(struct f2fs_sb_info *, pgoff_t);
struct page *get_meta_page(struct f2fs_sb_info *, pgoff_t);
bool is_valid_blkaddr(struct f2fs_sb_info *, block_t, int);
int ra_meta_pages(struct f2fs_sb_info *, block_t, int, int);
void ra_meta_pages_cond(struct f2fs_sb_info *, pgoff_t);
long sync_meta_pages(struct f2fs_sb_info *, enum page_type, long);
......@@ -1607,10 +1742,8 @@ void destroy_checkpoint_caches(void);
* data.c
*/
void f2fs_submit_merged_bio(struct f2fs_sb_info *, enum page_type, int);
int f2fs_submit_page_bio(struct f2fs_sb_info *, struct page *,
struct f2fs_io_info *);
void f2fs_submit_page_mbio(struct f2fs_sb_info *, struct page *,
struct f2fs_io_info *);
int f2fs_submit_page_bio(struct f2fs_io_info *);
void f2fs_submit_page_mbio(struct f2fs_io_info *);
void set_data_blkaddr(struct dnode_of_data *);
int reserve_new_block(struct dnode_of_data *);
int f2fs_reserve_block(struct dnode_of_data *, pgoff_t);
......@@ -1619,10 +1752,11 @@ void f2fs_destroy_extent_tree(struct inode *);
void f2fs_init_extent_cache(struct inode *, struct f2fs_extent *);
void f2fs_update_extent_cache(struct dnode_of_data *);
void f2fs_preserve_extent_tree(struct inode *);
struct page *find_data_page(struct inode *, pgoff_t, bool);
struct page *get_read_data_page(struct inode *, pgoff_t, int);
struct page *find_data_page(struct inode *, pgoff_t);
struct page *get_lock_data_page(struct inode *, pgoff_t);
struct page *get_new_data_page(struct inode *, struct page *, pgoff_t, bool);
int do_write_data_page(struct page *, struct f2fs_io_info *);
int do_write_data_page(struct f2fs_io_info *);
int f2fs_fiemap(struct inode *inode, struct fiemap_extent_info *, u64, u64);
void init_extent_cache_info(struct f2fs_sb_info *);
int __init create_extent_cache(void);
......@@ -1787,13 +1921,15 @@ extern const struct address_space_operations f2fs_node_aops;
extern const struct address_space_operations f2fs_meta_aops;
extern const struct inode_operations f2fs_dir_inode_operations;
extern const struct inode_operations f2fs_symlink_inode_operations;
extern const struct inode_operations f2fs_encrypted_symlink_inode_operations;
extern const struct inode_operations f2fs_special_inode_operations;
extern struct kmem_cache *inode_entry_slab;
/*
* inline.c
*/
bool f2fs_may_inline(struct inode *);
bool f2fs_may_inline_data(struct inode *);
bool f2fs_may_inline_dentry(struct inode *);
void read_inline_data(struct page *, struct page *);
bool truncate_inline_inode(struct page *, u64);
int f2fs_read_inline_data(struct inode *, struct page *);
......@@ -1801,8 +1937,8 @@ int f2fs_convert_inline_page(struct dnode_of_data *, struct page *);
int f2fs_convert_inline_inode(struct inode *);
int f2fs_write_inline_data(struct inode *, struct page *);
bool recover_inline_data(struct inode *, struct page *);
struct f2fs_dir_entry *find_in_inline_dir(struct inode *, struct qstr *,
struct page **);
struct f2fs_dir_entry *find_in_inline_dir(struct inode *,
struct f2fs_filename *, struct page **);
struct f2fs_dir_entry *f2fs_parent_inline_dir(struct inode *, struct page **);
int make_empty_inline_dir(struct inode *inode, struct inode *, struct page *);
int f2fs_add_inline_entry(struct inode *, const struct qstr *, struct inode *,
......@@ -1810,5 +1946,137 @@ int f2fs_add_inline_entry(struct inode *, const struct qstr *, struct inode *,
void f2fs_delete_inline_entry(struct f2fs_dir_entry *, struct page *,
struct inode *, struct inode *);
bool f2fs_empty_inline_dir(struct inode *);
int f2fs_read_inline_dir(struct file *, struct dir_context *);
int f2fs_read_inline_dir(struct file *, struct dir_context *,
struct f2fs_str *);
/*
* crypto support
*/
static inline int f2fs_encrypted_inode(struct inode *inode)
{
#ifdef CONFIG_F2FS_FS_ENCRYPTION
return file_is_encrypt(inode);
#else
return 0;
#endif
}
static inline void f2fs_set_encrypted_inode(struct inode *inode)
{
#ifdef CONFIG_F2FS_FS_ENCRYPTION
file_set_encrypt(inode);
#endif
}
static inline bool f2fs_bio_encrypted(struct bio *bio)
{
#ifdef CONFIG_F2FS_FS_ENCRYPTION
return unlikely(bio->bi_private != NULL);
#else
return false;
#endif
}
static inline int f2fs_sb_has_crypto(struct super_block *sb)
{
#ifdef CONFIG_F2FS_FS_ENCRYPTION
return F2FS_HAS_FEATURE(sb, F2FS_FEATURE_ENCRYPT);
#else
return 0;
#endif
}
static inline bool f2fs_may_encrypt(struct inode *inode)
{
#ifdef CONFIG_F2FS_FS_ENCRYPTION
mode_t mode = inode->i_mode;
return (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode));
#else
return 0;
#endif
}
/* crypto_policy.c */
int f2fs_is_child_context_consistent_with_parent(struct inode *,
struct inode *);
int f2fs_inherit_context(struct inode *, struct inode *, struct page *);
int f2fs_process_policy(const struct f2fs_encryption_policy *, struct inode *);
int f2fs_get_policy(struct inode *, struct f2fs_encryption_policy *);
/* crypt.c */
extern struct kmem_cache *f2fs_crypt_info_cachep;
bool f2fs_valid_contents_enc_mode(uint32_t);
uint32_t f2fs_validate_encryption_key_size(uint32_t, uint32_t);
struct f2fs_crypto_ctx *f2fs_get_crypto_ctx(struct inode *);
void f2fs_release_crypto_ctx(struct f2fs_crypto_ctx *);
struct page *f2fs_encrypt(struct inode *, struct page *);
int f2fs_decrypt(struct f2fs_crypto_ctx *, struct page *);
int f2fs_decrypt_one(struct inode *, struct page *);
void f2fs_end_io_crypto_work(struct f2fs_crypto_ctx *, struct bio *);
/* crypto_key.c */
void f2fs_free_encryption_info(struct inode *, struct f2fs_crypt_info *);
int _f2fs_get_encryption_info(struct inode *inode);
/* crypto_fname.c */
bool f2fs_valid_filenames_enc_mode(uint32_t);
u32 f2fs_fname_crypto_round_up(u32, u32);
int f2fs_fname_crypto_alloc_buffer(struct inode *, u32, struct f2fs_str *);
int f2fs_fname_disk_to_usr(struct inode *, f2fs_hash_t *,
const struct f2fs_str *, struct f2fs_str *);
int f2fs_fname_usr_to_disk(struct inode *, const struct qstr *,
struct f2fs_str *);
#ifdef CONFIG_F2FS_FS_ENCRYPTION
void f2fs_restore_and_release_control_page(struct page **);
void f2fs_restore_control_page(struct page *);
int __init f2fs_init_crypto(void);
int f2fs_crypto_initialize(void);
void f2fs_exit_crypto(void);
int f2fs_has_encryption_key(struct inode *);
static inline int f2fs_get_encryption_info(struct inode *inode)
{
struct f2fs_crypt_info *ci = F2FS_I(inode)->i_crypt_info;
if (!ci ||
(ci->ci_keyring_key &&
(ci->ci_keyring_key->flags & ((1 << KEY_FLAG_INVALIDATED) |
(1 << KEY_FLAG_REVOKED) |
(1 << KEY_FLAG_DEAD)))))
return _f2fs_get_encryption_info(inode);
return 0;
}
void f2fs_fname_crypto_free_buffer(struct f2fs_str *);
int f2fs_fname_setup_filename(struct inode *, const struct qstr *,
int lookup, struct f2fs_filename *);
void f2fs_fname_free_filename(struct f2fs_filename *);
#else
static inline void f2fs_restore_and_release_control_page(struct page **p) { }
static inline void f2fs_restore_control_page(struct page *p) { }
static inline int __init f2fs_init_crypto(void) { return 0; }
static inline void f2fs_exit_crypto(void) { }
static inline int f2fs_has_encryption_key(struct inode *i) { return 0; }
static inline int f2fs_get_encryption_info(struct inode *i) { return 0; }
static inline void f2fs_fname_crypto_free_buffer(struct f2fs_str *p) { }
static inline int f2fs_fname_setup_filename(struct inode *dir,
const struct qstr *iname,
int lookup, struct f2fs_filename *fname)
{
memset(fname, 0, sizeof(struct f2fs_filename));
fname->usr_fname = iname;
fname->disk_name.name = (unsigned char *)iname->name;
fname->disk_name.len = iname->len;
return 0;
}
static inline void f2fs_fname_free_filename(struct f2fs_filename *fname) { }
#endif
#endif
/*
* linux/fs/f2fs/f2fs_crypto.h
*
* Copied from linux/fs/ext4/ext4_crypto.h
*
* Copyright (C) 2015, Google, Inc.
*
* This contains encryption header content for f2fs
*
* Written by Michael Halcrow, 2015.
* Modified by Jaegeuk Kim, 2015.
*/
#ifndef _F2FS_CRYPTO_H
#define _F2FS_CRYPTO_H
#include <linux/fs.h>
#define F2FS_KEY_DESCRIPTOR_SIZE 8
/* Policy provided via an ioctl on the topmost directory */
struct f2fs_encryption_policy {
char version;
char contents_encryption_mode;
char filenames_encryption_mode;
char flags;
char master_key_descriptor[F2FS_KEY_DESCRIPTOR_SIZE];
} __attribute__((__packed__));
#define F2FS_ENCRYPTION_CONTEXT_FORMAT_V1 1
#define F2FS_KEY_DERIVATION_NONCE_SIZE 16
#define F2FS_POLICY_FLAGS_PAD_4 0x00
#define F2FS_POLICY_FLAGS_PAD_8 0x01
#define F2FS_POLICY_FLAGS_PAD_16 0x02
#define F2FS_POLICY_FLAGS_PAD_32 0x03
#define F2FS_POLICY_FLAGS_PAD_MASK 0x03
#define F2FS_POLICY_FLAGS_VALID 0x03
/**
* Encryption context for inode
*
* Protector format:
* 1 byte: Protector format (1 = this version)
* 1 byte: File contents encryption mode
* 1 byte: File names encryption mode
* 1 byte: Flags
* 8 bytes: Master Key descriptor
* 16 bytes: Encryption Key derivation nonce
*/
struct f2fs_encryption_context {
char format;
char contents_encryption_mode;
char filenames_encryption_mode;
char flags;
char master_key_descriptor[F2FS_KEY_DESCRIPTOR_SIZE];
char nonce[F2FS_KEY_DERIVATION_NONCE_SIZE];
} __attribute__((__packed__));
/* Encryption parameters */
#define F2FS_XTS_TWEAK_SIZE 16
#define F2FS_AES_128_ECB_KEY_SIZE 16
#define F2FS_AES_256_GCM_KEY_SIZE 32
#define F2FS_AES_256_CBC_KEY_SIZE 32
#define F2FS_AES_256_CTS_KEY_SIZE 32
#define F2FS_AES_256_XTS_KEY_SIZE 64
#define F2FS_MAX_KEY_SIZE 64
#define F2FS_KEY_DESC_PREFIX "f2fs:"
#define F2FS_KEY_DESC_PREFIX_SIZE 5
struct f2fs_encryption_key {
__u32 mode;
char raw[F2FS_MAX_KEY_SIZE];
__u32 size;
} __attribute__((__packed__));
struct f2fs_crypt_info {
char ci_data_mode;
char ci_filename_mode;
char ci_flags;
struct crypto_ablkcipher *ci_ctfm;
struct key *ci_keyring_key;
char ci_master_key[F2FS_KEY_DESCRIPTOR_SIZE];
};
#define F2FS_CTX_REQUIRES_FREE_ENCRYPT_FL 0x00000001
#define F2FS_WRITE_PATH_FL 0x00000002
struct f2fs_crypto_ctx {
union {
struct {
struct page *bounce_page; /* Ciphertext page */
struct page *control_page; /* Original page */
} w;
struct {
struct bio *bio;
struct work_struct work;
} r;
struct list_head free_list; /* Free list */
};
char flags; /* Flags */
};
struct f2fs_completion_result {
struct completion completion;
int res;
};
#define DECLARE_F2FS_COMPLETION_RESULT(ecr) \
struct f2fs_completion_result ecr = { \
COMPLETION_INITIALIZER((ecr).completion), 0 }
static inline int f2fs_encryption_key_size(int mode)
{
switch (mode) {
case F2FS_ENCRYPTION_MODE_AES_256_XTS:
return F2FS_AES_256_XTS_KEY_SIZE;
case F2FS_ENCRYPTION_MODE_AES_256_GCM:
return F2FS_AES_256_GCM_KEY_SIZE;
case F2FS_ENCRYPTION_MODE_AES_256_CBC:
return F2FS_AES_256_CBC_KEY_SIZE;
case F2FS_ENCRYPTION_MODE_AES_256_CTS:
return F2FS_AES_256_CTS_KEY_SIZE;
default:
BUG();
}
return 0;
}
#define F2FS_FNAME_NUM_SCATTER_ENTRIES 4
#define F2FS_CRYPTO_BLOCK_SIZE 16
#define F2FS_FNAME_CRYPTO_DIGEST_SIZE 32
/**
* For encrypted symlinks, the ciphertext length is stored at the beginning
* of the string in little-endian format.
*/
struct f2fs_encrypted_symlink_data {
__le16 len;
char encrypted_path[1];
} __attribute__((__packed__));
/**
* This function is used to calculate the disk space required to
* store a filename of length l in encrypted symlink format.
*/
static inline u32 encrypted_symlink_data_len(u32 l)
{
return (l + sizeof(struct f2fs_encrypted_symlink_data) - 1);
}
#endif /* _F2FS_CRYPTO_H */
......@@ -20,6 +20,7 @@
#include <linux/uaccess.h>
#include <linux/mount.h>
#include <linux/pagevec.h>
#include <linux/random.h>
#include "f2fs.h"
#include "node.h"
......@@ -105,7 +106,7 @@ static int get_parent_ino(struct inode *inode, nid_t *pino)
if (!dentry)
return 0;
if (update_dent_inode(inode, &dentry->d_name)) {
if (update_dent_inode(inode, inode, &dentry->d_name)) {
dput(dentry);
return 0;
}
......@@ -122,6 +123,8 @@ static inline bool need_do_checkpoint(struct inode *inode)
if (!S_ISREG(inode->i_mode) || inode->i_nlink != 1)
need_cp = true;
else if (file_enc_name(inode) && need_dentry_mark(sbi, inode->i_ino))
need_cp = true;
else if (file_wrong_pino(inode))
need_cp = true;
else if (!space_for_roll_forward(sbi))
......@@ -271,7 +274,7 @@ int f2fs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
ret = f2fs_issue_flush(sbi);
out:
trace_f2fs_sync_file_exit(inode, need_cp, datasync, ret);
f2fs_trace_ios(NULL, NULL, 1);
f2fs_trace_ios(NULL, 1);
return ret;
}
......@@ -407,6 +410,12 @@ static int f2fs_file_mmap(struct file *file, struct vm_area_struct *vma)
{
struct inode *inode = file_inode(file);
if (f2fs_encrypted_inode(inode)) {
int err = f2fs_get_encryption_info(inode);
if (err)
return 0;
}
/* we don't need to use inline_data strictly */
if (f2fs_has_inline_data(inode)) {
int err = f2fs_convert_inline_inode(inode);
......@@ -419,6 +428,18 @@ static int f2fs_file_mmap(struct file *file, struct vm_area_struct *vma)
return 0;
}
static int f2fs_file_open(struct inode *inode, struct file *filp)
{
int ret = generic_file_open(inode, filp);
if (!ret && f2fs_encrypted_inode(inode)) {
ret = f2fs_get_encryption_info(inode);
if (ret)
ret = -EACCES;
}
return ret;
}
int truncate_data_blocks_range(struct dnode_of_data *dn, int count)
{
int nr_free = 0, ofs = dn->ofs_in_node;
......@@ -461,28 +482,32 @@ void truncate_data_blocks(struct dnode_of_data *dn)
}
static int truncate_partial_data_page(struct inode *inode, u64 from,
bool force)
bool cache_only)
{
unsigned offset = from & (PAGE_CACHE_SIZE - 1);
pgoff_t index = from >> PAGE_CACHE_SHIFT;
struct address_space *mapping = inode->i_mapping;
struct page *page;
if (!offset && !force)
if (!offset && !cache_only)
return 0;
page = find_data_page(inode, from >> PAGE_CACHE_SHIFT, force);
if (IS_ERR(page))
if (cache_only) {
page = grab_cache_page(mapping, index);
if (page && PageUptodate(page))
goto truncate_out;
f2fs_put_page(page, 1);
return 0;
}
lock_page(page);
if (unlikely(!PageUptodate(page) ||
page->mapping != inode->i_mapping))
goto out;
page = get_lock_data_page(inode, index);
if (IS_ERR(page))
return 0;
truncate_out:
f2fs_wait_on_page_writeback(page, DATA);
zero_user(page, offset, PAGE_CACHE_SIZE - offset);
if (!force)
if (!cache_only || !f2fs_encrypted_inode(inode) || !S_ISREG(inode->i_mode))
set_page_dirty(page);
out:
f2fs_put_page(page, 1);
return 0;
}
......@@ -560,7 +585,7 @@ void f2fs_truncate(struct inode *inode)
trace_f2fs_truncate(inode);
/* we should check inline_data size */
if (f2fs_has_inline_data(inode) && !f2fs_may_inline(inode)) {
if (f2fs_has_inline_data(inode) && !f2fs_may_inline_data(inode)) {
if (f2fs_convert_inline_inode(inode))
return;
}
......@@ -622,16 +647,20 @@ int f2fs_setattr(struct dentry *dentry, struct iattr *attr)
return err;
if (attr->ia_valid & ATTR_SIZE) {
if (attr->ia_size != i_size_read(inode)) {
if (f2fs_encrypted_inode(inode) &&
f2fs_get_encryption_info(inode))
return -EACCES;
if (attr->ia_size <= i_size_read(inode)) {
truncate_setsize(inode, attr->ia_size);
f2fs_truncate(inode);
f2fs_balance_fs(F2FS_I_SB(inode));
} else {
/*
* giving a chance to truncate blocks past EOF which
* are fallocated with FALLOC_FL_KEEP_SIZE.
* do not trim all blocks after i_size if target size is
* larger than i_size.
*/
f2fs_truncate(inode);
truncate_setsize(inode, attr->ia_size);
}
}
......@@ -718,10 +747,6 @@ static int punch_hole(struct inode *inode, loff_t offset, loff_t len)
if (!S_ISREG(inode->i_mode))
return -EOPNOTSUPP;
/* skip punching hole beyond i_size */
if (offset >= inode->i_size)
return ret;
if (f2fs_has_inline_data(inode)) {
ret = f2fs_convert_inline_inode(inode);
if (ret)
......@@ -765,6 +790,320 @@ static int punch_hole(struct inode *inode, loff_t offset, loff_t len)
return ret;
}
static int f2fs_do_collapse(struct inode *inode, pgoff_t start, pgoff_t end)
{
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
struct dnode_of_data dn;
pgoff_t nrpages = (i_size_read(inode) + PAGE_SIZE - 1) / PAGE_SIZE;
int ret = 0;
f2fs_lock_op(sbi);
for (; end < nrpages; start++, end++) {
block_t new_addr, old_addr;
set_new_dnode(&dn, inode, NULL, NULL, 0);
ret = get_dnode_of_data(&dn, end, LOOKUP_NODE_RA);
if (ret && ret != -ENOENT) {
goto out;
} else if (ret == -ENOENT) {
new_addr = NULL_ADDR;
} else {
new_addr = dn.data_blkaddr;
truncate_data_blocks_range(&dn, 1);
f2fs_put_dnode(&dn);
}
if (new_addr == NULL_ADDR) {
set_new_dnode(&dn, inode, NULL, NULL, 0);
ret = get_dnode_of_data(&dn, start, LOOKUP_NODE_RA);
if (ret && ret != -ENOENT)
goto out;
else if (ret == -ENOENT)
continue;
if (dn.data_blkaddr == NULL_ADDR) {
f2fs_put_dnode(&dn);
continue;
} else {
truncate_data_blocks_range(&dn, 1);
}
f2fs_put_dnode(&dn);
} else {
struct page *ipage;
ipage = get_node_page(sbi, inode->i_ino);
if (IS_ERR(ipage)) {
ret = PTR_ERR(ipage);
goto out;
}
set_new_dnode(&dn, inode, ipage, NULL, 0);
ret = f2fs_reserve_block(&dn, start);
if (ret)
goto out;
old_addr = dn.data_blkaddr;
if (old_addr != NEW_ADDR && new_addr == NEW_ADDR) {
dn.data_blkaddr = NULL_ADDR;
f2fs_update_extent_cache(&dn);
invalidate_blocks(sbi, old_addr);
dn.data_blkaddr = new_addr;
set_data_blkaddr(&dn);
} else if (new_addr != NEW_ADDR) {
struct node_info ni;
get_node_info(sbi, dn.nid, &ni);
f2fs_replace_block(sbi, &dn, old_addr, new_addr,
ni.version, true);
}
f2fs_put_dnode(&dn);
}
}
ret = 0;
out:
f2fs_unlock_op(sbi);
return ret;
}
static int f2fs_collapse_range(struct inode *inode, loff_t offset, loff_t len)
{
pgoff_t pg_start, pg_end;
loff_t new_size;
int ret;
if (!S_ISREG(inode->i_mode))
return -EINVAL;
if (offset + len >= i_size_read(inode))
return -EINVAL;
/* collapse range should be aligned to block size of f2fs. */
if (offset & (F2FS_BLKSIZE - 1) || len & (F2FS_BLKSIZE - 1))
return -EINVAL;
pg_start = offset >> PAGE_CACHE_SHIFT;
pg_end = (offset + len) >> PAGE_CACHE_SHIFT;
/* write out all dirty pages from offset */
ret = filemap_write_and_wait_range(inode->i_mapping, offset, LLONG_MAX);
if (ret)
return ret;
truncate_pagecache(inode, offset);
ret = f2fs_do_collapse(inode, pg_start, pg_end);
if (ret)
return ret;
new_size = i_size_read(inode) - len;
ret = truncate_blocks(inode, new_size, true);
if (!ret)
i_size_write(inode, new_size);
return ret;
}
static int f2fs_zero_range(struct inode *inode, loff_t offset, loff_t len,
int mode)
{
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
struct address_space *mapping = inode->i_mapping;
pgoff_t index, pg_start, pg_end;
loff_t new_size = i_size_read(inode);
loff_t off_start, off_end;
int ret = 0;
if (!S_ISREG(inode->i_mode))
return -EINVAL;
ret = inode_newsize_ok(inode, (len + offset));
if (ret)
return ret;
f2fs_balance_fs(sbi);
if (f2fs_has_inline_data(inode)) {
ret = f2fs_convert_inline_inode(inode);
if (ret)
return ret;
}
ret = filemap_write_and_wait_range(mapping, offset, offset + len - 1);
if (ret)
return ret;
truncate_pagecache_range(inode, offset, offset + len - 1);
pg_start = ((unsigned long long) offset) >> PAGE_CACHE_SHIFT;
pg_end = ((unsigned long long) offset + len) >> PAGE_CACHE_SHIFT;
off_start = offset & (PAGE_CACHE_SIZE - 1);
off_end = (offset + len) & (PAGE_CACHE_SIZE - 1);
if (pg_start == pg_end) {
fill_zero(inode, pg_start, off_start, off_end - off_start);
if (offset + len > new_size)
new_size = offset + len;
new_size = max_t(loff_t, new_size, offset + len);
} else {
if (off_start) {
fill_zero(inode, pg_start++, off_start,
PAGE_CACHE_SIZE - off_start);
new_size = max_t(loff_t, new_size,
pg_start << PAGE_CACHE_SHIFT);
}
for (index = pg_start; index < pg_end; index++) {
struct dnode_of_data dn;
struct page *ipage;
f2fs_lock_op(sbi);
ipage = get_node_page(sbi, inode->i_ino);
if (IS_ERR(ipage)) {
ret = PTR_ERR(ipage);
f2fs_unlock_op(sbi);
goto out;
}
set_new_dnode(&dn, inode, ipage, NULL, 0);
ret = f2fs_reserve_block(&dn, index);
if (ret) {
f2fs_unlock_op(sbi);
goto out;
}
if (dn.data_blkaddr != NEW_ADDR) {
invalidate_blocks(sbi, dn.data_blkaddr);
dn.data_blkaddr = NEW_ADDR;
set_data_blkaddr(&dn);
dn.data_blkaddr = NULL_ADDR;
f2fs_update_extent_cache(&dn);
}
f2fs_put_dnode(&dn);
f2fs_unlock_op(sbi);
new_size = max_t(loff_t, new_size,
(index + 1) << PAGE_CACHE_SHIFT);
}
if (off_end) {
fill_zero(inode, pg_end, 0, off_end);
new_size = max_t(loff_t, new_size, offset + len);
}
}
out:
if (!(mode & FALLOC_FL_KEEP_SIZE) && i_size_read(inode) < new_size) {
i_size_write(inode, new_size);
mark_inode_dirty(inode);
update_inode_page(inode);
}
return ret;
}
static int f2fs_insert_range(struct inode *inode, loff_t offset, loff_t len)
{
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
pgoff_t pg_start, pg_end, delta, nrpages, idx;
loff_t new_size;
int ret;
if (!S_ISREG(inode->i_mode))
return -EINVAL;
new_size = i_size_read(inode) + len;
if (new_size > inode->i_sb->s_maxbytes)
return -EFBIG;
if (offset >= i_size_read(inode))
return -EINVAL;
/* insert range should be aligned to block size of f2fs. */
if (offset & (F2FS_BLKSIZE - 1) || len & (F2FS_BLKSIZE - 1))
return -EINVAL;
f2fs_balance_fs(sbi);
ret = truncate_blocks(inode, i_size_read(inode), true);
if (ret)
return ret;
/* write out all dirty pages from offset */
ret = filemap_write_and_wait_range(inode->i_mapping, offset, LLONG_MAX);
if (ret)
return ret;
truncate_pagecache(inode, offset);
pg_start = offset >> PAGE_CACHE_SHIFT;
pg_end = (offset + len) >> PAGE_CACHE_SHIFT;
delta = pg_end - pg_start;
nrpages = (i_size_read(inode) + PAGE_SIZE - 1) / PAGE_SIZE;
for (idx = nrpages - 1; idx >= pg_start && idx != -1; idx--) {
struct dnode_of_data dn;
struct page *ipage;
block_t new_addr, old_addr;
f2fs_lock_op(sbi);
set_new_dnode(&dn, inode, NULL, NULL, 0);
ret = get_dnode_of_data(&dn, idx, LOOKUP_NODE_RA);
if (ret && ret != -ENOENT) {
goto out;
} else if (ret == -ENOENT) {
goto next;
} else if (dn.data_blkaddr == NULL_ADDR) {
f2fs_put_dnode(&dn);
goto next;
} else {
new_addr = dn.data_blkaddr;
truncate_data_blocks_range(&dn, 1);
f2fs_put_dnode(&dn);
}
ipage = get_node_page(sbi, inode->i_ino);
if (IS_ERR(ipage)) {
ret = PTR_ERR(ipage);
goto out;
}
set_new_dnode(&dn, inode, ipage, NULL, 0);
ret = f2fs_reserve_block(&dn, idx + delta);
if (ret)
goto out;
old_addr = dn.data_blkaddr;
f2fs_bug_on(sbi, old_addr != NEW_ADDR);
if (new_addr != NEW_ADDR) {
struct node_info ni;
get_node_info(sbi, dn.nid, &ni);
f2fs_replace_block(sbi, &dn, old_addr, new_addr,
ni.version, true);
}
f2fs_put_dnode(&dn);
next:
f2fs_unlock_op(sbi);
}
i_size_write(inode, new_size);
return 0;
out:
f2fs_unlock_op(sbi);
return ret;
}
static int expand_inode_data(struct inode *inode, loff_t offset,
loff_t len, int mode)
{
......@@ -830,23 +1169,40 @@ static long f2fs_fallocate(struct file *file, int mode,
loff_t offset, loff_t len)
{
struct inode *inode = file_inode(file);
long ret;
long ret = 0;
if (f2fs_encrypted_inode(inode) &&
(mode & (FALLOC_FL_COLLAPSE_RANGE | FALLOC_FL_INSERT_RANGE)))
return -EOPNOTSUPP;
if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE))
if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE |
FALLOC_FL_COLLAPSE_RANGE | FALLOC_FL_ZERO_RANGE |
FALLOC_FL_INSERT_RANGE))
return -EOPNOTSUPP;
mutex_lock(&inode->i_mutex);
if (mode & FALLOC_FL_PUNCH_HOLE)
if (mode & FALLOC_FL_PUNCH_HOLE) {
if (offset >= inode->i_size)
goto out;
ret = punch_hole(inode, offset, len);
else
} else if (mode & FALLOC_FL_COLLAPSE_RANGE) {
ret = f2fs_collapse_range(inode, offset, len);
} else if (mode & FALLOC_FL_ZERO_RANGE) {
ret = f2fs_zero_range(inode, offset, len, mode);
} else if (mode & FALLOC_FL_INSERT_RANGE) {
ret = f2fs_insert_range(inode, offset, len);
} else {
ret = expand_inode_data(inode, offset, len, mode);
}
if (!ret) {
inode->i_mtime = inode->i_ctime = CURRENT_TIME;
mark_inode_dirty(inode);
}
out:
mutex_unlock(&inode->i_mutex);
trace_f2fs_fallocate(inode, mode, offset, len, ret);
......@@ -1035,11 +1391,9 @@ static int f2fs_ioc_abort_volatile_write(struct file *filp)
clear_inode_flag(F2FS_I(inode), FI_ATOMIC_FILE);
}
if (f2fs_is_volatile_file(inode)) {
if (f2fs_is_volatile_file(inode))
clear_inode_flag(F2FS_I(inode), FI_VOLATILE_FILE);
filemap_fdatawrite(inode->i_mapping);
set_inode_flag(F2FS_I(inode), FI_VOLATILE_FILE);
}
mnt_drop_write_file(filp);
return ret;
}
......@@ -1109,6 +1463,86 @@ static int f2fs_ioc_fitrim(struct file *filp, unsigned long arg)
return 0;
}
static bool uuid_is_nonzero(__u8 u[16])
{
int i;
for (i = 0; i < 16; i++)
if (u[i])
return true;
return false;
}
static int f2fs_ioc_set_encryption_policy(struct file *filp, unsigned long arg)
{
#ifdef CONFIG_F2FS_FS_ENCRYPTION
struct f2fs_encryption_policy policy;
struct inode *inode = file_inode(filp);
if (copy_from_user(&policy, (struct f2fs_encryption_policy __user *)arg,
sizeof(policy)))
return -EFAULT;
return f2fs_process_policy(&policy, inode);
#else
return -EOPNOTSUPP;
#endif
}
static int f2fs_ioc_get_encryption_policy(struct file *filp, unsigned long arg)
{
#ifdef CONFIG_F2FS_FS_ENCRYPTION
struct f2fs_encryption_policy policy;
struct inode *inode = file_inode(filp);
int err;
err = f2fs_get_policy(inode, &policy);
if (err)
return err;
if (copy_to_user((struct f2fs_encryption_policy __user *)arg, &policy,
sizeof(policy)))
return -EFAULT;
return 0;
#else
return -EOPNOTSUPP;
#endif
}
static int f2fs_ioc_get_encryption_pwsalt(struct file *filp, unsigned long arg)
{
struct inode *inode = file_inode(filp);
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
int err;
if (!f2fs_sb_has_crypto(inode->i_sb))
return -EOPNOTSUPP;
if (uuid_is_nonzero(sbi->raw_super->encrypt_pw_salt))
goto got_it;
err = mnt_want_write_file(filp);
if (err)
return err;
/* update superblock with uuid */
generate_random_uuid(sbi->raw_super->encrypt_pw_salt);
err = f2fs_commit_super(sbi, false);
mnt_drop_write_file(filp);
if (err) {
/* undo new data */
memset(sbi->raw_super->encrypt_pw_salt, 0, 16);
return err;
}
got_it:
if (copy_to_user((__u8 __user *)arg, sbi->raw_super->encrypt_pw_salt,
16))
return -EFAULT;
return 0;
}
long f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
switch (cmd) {
......@@ -1132,11 +1566,29 @@ long f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
return f2fs_ioc_shutdown(filp, arg);
case FITRIM:
return f2fs_ioc_fitrim(filp, arg);
case F2FS_IOC_SET_ENCRYPTION_POLICY:
return f2fs_ioc_set_encryption_policy(filp, arg);
case F2FS_IOC_GET_ENCRYPTION_POLICY:
return f2fs_ioc_get_encryption_policy(filp, arg);
case F2FS_IOC_GET_ENCRYPTION_PWSALT:
return f2fs_ioc_get_encryption_pwsalt(filp, arg);
default:
return -ENOTTY;
}
}
static ssize_t f2fs_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
{
struct inode *inode = file_inode(iocb->ki_filp);
if (f2fs_encrypted_inode(inode) &&
!f2fs_has_encryption_key(inode) &&
f2fs_get_encryption_info(inode))
return -EACCES;
return generic_file_write_iter(iocb, from);
}
#ifdef CONFIG_COMPAT
long f2fs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
......@@ -1157,8 +1609,8 @@ long f2fs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
const struct file_operations f2fs_file_operations = {
.llseek = f2fs_llseek,
.read_iter = generic_file_read_iter,
.write_iter = generic_file_write_iter,
.open = generic_file_open,
.write_iter = f2fs_file_write_iter,
.open = f2fs_file_open,
.release = f2fs_release_file,
.mmap = f2fs_file_mmap,
.fsync = f2fs_sync_file,
......
......@@ -518,12 +518,79 @@ static int check_dnode(struct f2fs_sb_info *sbi, struct f2fs_summary *sum,
return 1;
}
static void move_data_page(struct inode *inode, struct page *page, int gc_type)
static void move_encrypted_block(struct inode *inode, block_t bidx)
{
struct f2fs_io_info fio = {
.sbi = F2FS_I_SB(inode),
.type = DATA,
.rw = WRITE_SYNC,
.rw = READ_SYNC,
.encrypted_page = NULL,
};
struct dnode_of_data dn;
struct f2fs_summary sum;
struct node_info ni;
struct page *page;
int err;
/* do not read out */
page = grab_cache_page(inode->i_mapping, bidx);
if (!page)
return;
set_new_dnode(&dn, inode, NULL, NULL, 0);
err = get_dnode_of_data(&dn, bidx, LOOKUP_NODE);
if (err)
goto out;
if (unlikely(dn.data_blkaddr == NULL_ADDR))
goto put_out;
get_node_info(fio.sbi, dn.nid, &ni);
set_summary(&sum, dn.nid, dn.ofs_in_node, ni.version);
/* read page */
fio.page = page;
fio.blk_addr = dn.data_blkaddr;
fio.encrypted_page = grab_cache_page(META_MAPPING(fio.sbi), fio.blk_addr);
if (!fio.encrypted_page)
goto put_out;
f2fs_submit_page_bio(&fio);
/* allocate block address */
f2fs_wait_on_page_writeback(dn.node_page, NODE);
allocate_data_block(fio.sbi, NULL, fio.blk_addr,
&fio.blk_addr, &sum, CURSEG_COLD_DATA);
dn.data_blkaddr = fio.blk_addr;
/* write page */
lock_page(fio.encrypted_page);
set_page_writeback(fio.encrypted_page);
fio.rw = WRITE_SYNC;
f2fs_submit_page_mbio(&fio);
set_data_blkaddr(&dn);
f2fs_update_extent_cache(&dn);
set_inode_flag(F2FS_I(inode), FI_APPEND_WRITE);
if (page->index == 0)
set_inode_flag(F2FS_I(inode), FI_FIRST_BLOCK_WRITTEN);
f2fs_put_page(fio.encrypted_page, 1);
put_out:
f2fs_put_dnode(&dn);
out:
f2fs_put_page(page, 1);
}
static void move_data_page(struct inode *inode, block_t bidx, int gc_type)
{
struct page *page;
page = get_lock_data_page(inode, bidx);
if (IS_ERR(page))
return;
if (gc_type == BG_GC) {
if (PageWriteback(page))
......@@ -531,12 +598,19 @@ static void move_data_page(struct inode *inode, struct page *page, int gc_type)
set_page_dirty(page);
set_cold_data(page);
} else {
struct f2fs_io_info fio = {
.sbi = F2FS_I_SB(inode),
.type = DATA,
.rw = WRITE_SYNC,
.page = page,
.encrypted_page = NULL,
};
f2fs_wait_on_page_writeback(page, DATA);
if (clear_page_dirty_for_io(page))
inode_dec_dirty_pages(inode);
set_cold_data(page);
do_write_data_page(page, &fio);
do_write_data_page(&fio);
clear_cold_data(page);
}
out:
......@@ -599,10 +673,16 @@ static void gc_data_segment(struct f2fs_sb_info *sbi, struct f2fs_summary *sum,
if (IS_ERR(inode) || is_bad_inode(inode))
continue;
start_bidx = start_bidx_of_node(nofs, F2FS_I(inode));
/* if encrypted inode, let's go phase 3 */
if (f2fs_encrypted_inode(inode) &&
S_ISREG(inode->i_mode)) {
add_gc_inode(gc_list, inode);
continue;
}
data_page = find_data_page(inode,
start_bidx + ofs_in_node, false);
start_bidx = start_bidx_of_node(nofs, F2FS_I(inode));
data_page = get_read_data_page(inode,
start_bidx + ofs_in_node, READA);
if (IS_ERR(data_page)) {
iput(inode);
continue;
......@@ -616,12 +696,12 @@ static void gc_data_segment(struct f2fs_sb_info *sbi, struct f2fs_summary *sum,
/* phase 3 */
inode = find_gc_inode(gc_list, dni.ino);
if (inode) {
start_bidx = start_bidx_of_node(nofs, F2FS_I(inode));
data_page = get_lock_data_page(inode,
start_bidx + ofs_in_node);
if (IS_ERR(data_page))
continue;
move_data_page(inode, data_page, gc_type);
start_bidx = start_bidx_of_node(nofs, F2FS_I(inode))
+ ofs_in_node;
if (f2fs_encrypted_inode(inode) && S_ISREG(inode->i_mode))
move_encrypted_block(inode, start_bidx);
else
move_data_page(inode, start_bidx, gc_type);
stat_inc_data_blk_count(sbi, 1, gc_type);
}
}
......@@ -670,6 +750,15 @@ static void do_garbage_collect(struct f2fs_sb_info *sbi, unsigned int segno,
sum = page_address(sum_page);
/*
* this is to avoid deadlock:
* - lock_page(sum_page) - f2fs_replace_block
* - check_valid_map() - mutex_lock(sentry_lock)
* - mutex_lock(sentry_lock) - change_curseg()
* - lock_page(sum_page)
*/
unlock_page(sum_page);
switch (GET_SUM_TYPE((&sum->footer))) {
case SUM_TYPE_NODE:
gc_node_segment(sbi, sum->entries, segno, gc_type);
......@@ -683,7 +772,7 @@ static void do_garbage_collect(struct f2fs_sb_info *sbi, unsigned int segno,
stat_inc_seg_count(sbi, GET_SUM_TYPE((&sum->footer)), gc_type);
stat_inc_call_count(sbi->stat_info);
f2fs_put_page(sum_page, 1);
f2fs_put_page(sum_page, 0);
}
int f2fs_gc(struct f2fs_sb_info *sbi)
......
......@@ -79,8 +79,7 @@ f2fs_hash_t f2fs_dentry_hash(const struct qstr *name_info)
const unsigned char *name = name_info->name;
size_t len = name_info->len;
if ((len <= 2) && (name[0] == '.') &&
(name[1] == '.' || name[1] == '\0'))
if (is_dot_dotdot(name_info))
return 0;
/* Initialize the default seed for the hash checksum functions */
......
......@@ -13,7 +13,7 @@
#include "f2fs.h"
bool f2fs_may_inline(struct inode *inode)
bool f2fs_may_inline_data(struct inode *inode)
{
if (!test_opt(F2FS_I_SB(inode), INLINE_DATA))
return false;
......@@ -27,6 +27,20 @@ bool f2fs_may_inline(struct inode *inode)
if (i_size_read(inode) > MAX_INLINE_DATA)
return false;
if (f2fs_encrypted_inode(inode) && S_ISREG(inode->i_mode))
return false;
return true;
}
bool f2fs_may_inline_dentry(struct inode *inode)
{
if (!test_opt(F2FS_I_SB(inode), INLINE_DENTRY))
return false;
if (!S_ISDIR(inode->i_mode))
return false;
return true;
}
......@@ -95,8 +109,11 @@ int f2fs_convert_inline_page(struct dnode_of_data *dn, struct page *page)
{
void *src_addr, *dst_addr;
struct f2fs_io_info fio = {
.sbi = F2FS_I_SB(dn->inode),
.type = DATA,
.rw = WRITE_SYNC | REQ_PRIO,
.page = page,
.encrypted_page = NULL,
};
int dirty, err;
......@@ -130,7 +147,7 @@ int f2fs_convert_inline_page(struct dnode_of_data *dn, struct page *page)
/* write data page to try to make data consistent */
set_page_writeback(page);
fio.blk_addr = dn->data_blkaddr;
write_data_page(page, dn, &fio);
write_data_page(dn, &fio);
set_data_blkaddr(dn);
f2fs_update_extent_cache(dn);
f2fs_wait_on_page_writeback(page, DATA);
......@@ -267,23 +284,26 @@ bool recover_inline_data(struct inode *inode, struct page *npage)
}
struct f2fs_dir_entry *find_in_inline_dir(struct inode *dir,
struct qstr *name, struct page **res_page)
struct f2fs_filename *fname, struct page **res_page)
{
struct f2fs_sb_info *sbi = F2FS_SB(dir->i_sb);
struct f2fs_inline_dentry *inline_dentry;
struct qstr name = FSTR_TO_QSTR(&fname->disk_name);
struct f2fs_dir_entry *de;
struct f2fs_dentry_ptr d;
struct page *ipage;
f2fs_hash_t namehash;
ipage = get_node_page(sbi, dir->i_ino);
if (IS_ERR(ipage))
return NULL;
inline_dentry = inline_data_addr(ipage);
namehash = f2fs_dentry_hash(&name);
make_dentry_ptr(&d, (void *)inline_dentry, 2);
de = find_target_dentry(name, NULL, &d);
inline_dentry = inline_data_addr(ipage);
make_dentry_ptr(NULL, &d, (void *)inline_dentry, 2);
de = find_target_dentry(fname, namehash, NULL, &d);
unlock_page(ipage);
if (de)
*res_page = ipage;
......@@ -325,7 +345,7 @@ int make_empty_inline_dir(struct inode *inode, struct inode *parent,
dentry_blk = inline_data_addr(ipage);
make_dentry_ptr(&d, (void *)dentry_blk, 2);
make_dentry_ptr(NULL, &d, (void *)dentry_blk, 2);
do_make_empty_dir(inode, parent, &d);
set_page_dirty(ipage);
......@@ -429,7 +449,7 @@ int f2fs_add_inline_entry(struct inode *dir, const struct qstr *name,
f2fs_wait_on_page_writeback(ipage, NODE);
name_hash = f2fs_dentry_hash(name);
make_dentry_ptr(&d, (void *)dentry_blk, 2);
make_dentry_ptr(NULL, &d, (void *)dentry_blk, 2);
f2fs_update_dentry(ino, mode, &d, name, name_hash, bit_pos);
set_page_dirty(ipage);
......@@ -506,7 +526,8 @@ bool f2fs_empty_inline_dir(struct inode *dir)
return true;
}
int f2fs_read_inline_dir(struct file *file, struct dir_context *ctx)
int f2fs_read_inline_dir(struct file *file, struct dir_context *ctx,
struct f2fs_str *fstr)
{
struct inode *inode = file_inode(file);
struct f2fs_inline_dentry *inline_dentry = NULL;
......@@ -522,9 +543,9 @@ int f2fs_read_inline_dir(struct file *file, struct dir_context *ctx)
inline_dentry = inline_data_addr(ipage);
make_dentry_ptr(&d, (void *)inline_dentry, 2);
make_dentry_ptr(inode, &d, (void *)inline_dentry, 2);
if (!f2fs_fill_dentries(ctx, &d, 0))
if (!f2fs_fill_dentries(ctx, &d, 0, fstr))
ctx->pos = NR_INLINE_DENTRY;
f2fs_put_page(ipage, 1);
......
......@@ -198,6 +198,9 @@ struct inode *f2fs_iget(struct super_block *sb, unsigned long ino)
inode->i_mapping->a_ops = &f2fs_dblock_aops;
mapping_set_gfp_mask(inode->i_mapping, GFP_F2FS_HIGH_ZERO);
} else if (S_ISLNK(inode->i_mode)) {
if (f2fs_encrypted_inode(inode))
inode->i_op = &f2fs_encrypted_symlink_inode_operations;
else
inode->i_op = &f2fs_symlink_inode_operations;
inode->i_mapping->a_ops = &f2fs_dblock_aops;
} else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) ||
......@@ -359,6 +362,10 @@ void f2fs_evict_inode(struct inode *inode)
if (is_inode_flag_set(F2FS_I(inode), FI_UPDATE_WRITE))
add_dirty_inode(sbi, inode->i_ino, UPDATE_INO);
out_clear:
#ifdef CONFIG_F2FS_FS_ENCRYPTION
if (F2FS_I(inode)->i_crypt_info)
f2fs_free_encryption_info(inode, F2FS_I(inode)->i_crypt_info);
#endif
clear_inode(inode);
}
......
此差异已折叠。
......@@ -195,32 +195,35 @@ static unsigned int __gang_lookup_nat_set(struct f2fs_nm_info *nm_i,
start, nr);
}
bool is_checkpointed_node(struct f2fs_sb_info *sbi, nid_t nid)
int need_dentry_mark(struct f2fs_sb_info *sbi, nid_t nid)
{
struct f2fs_nm_info *nm_i = NM_I(sbi);
struct nat_entry *e;
bool is_cp = true;
bool need = false;
down_read(&nm_i->nat_tree_lock);
e = __lookup_nat_cache(nm_i, nid);
if (e && !get_nat_flag(e, IS_CHECKPOINTED))
is_cp = false;
if (e) {
if (!get_nat_flag(e, IS_CHECKPOINTED) &&
!get_nat_flag(e, HAS_FSYNCED_INODE))
need = true;
}
up_read(&nm_i->nat_tree_lock);
return is_cp;
return need;
}
bool has_fsynced_inode(struct f2fs_sb_info *sbi, nid_t ino)
bool is_checkpointed_node(struct f2fs_sb_info *sbi, nid_t nid)
{
struct f2fs_nm_info *nm_i = NM_I(sbi);
struct nat_entry *e;
bool fsynced = false;
bool is_cp = true;
down_read(&nm_i->nat_tree_lock);
e = __lookup_nat_cache(nm_i, ino);
if (e && get_nat_flag(e, HAS_FSYNCED_INODE))
fsynced = true;
e = __lookup_nat_cache(nm_i, nid);
if (e && !get_nat_flag(e, IS_CHECKPOINTED))
is_cp = false;
up_read(&nm_i->nat_tree_lock);
return fsynced;
return is_cp;
}
bool need_inode_block_update(struct f2fs_sb_info *sbi, nid_t ino)
......@@ -312,6 +315,7 @@ static void set_node_addr(struct f2fs_sb_info *sbi, struct node_info *ni,
__set_nat_cache_dirty(nm_i, e);
/* update fsync_mark if its inode nat entry is still alive */
if (ni->nid != ni->ino)
e = __lookup_nat_cache(nm_i, ni->ino);
if (e) {
if (fsync_done && ni->nid == ni->ino)
......@@ -995,8 +999,11 @@ static int read_node_page(struct page *page, int rw)
struct f2fs_sb_info *sbi = F2FS_P_SB(page);
struct node_info ni;
struct f2fs_io_info fio = {
.sbi = sbi,
.type = NODE,
.rw = rw,
.page = page,
.encrypted_page = NULL,
};
get_node_info(sbi, page->index, &ni);
......@@ -1011,7 +1018,7 @@ static int read_node_page(struct page *page, int rw)
return LOCKED_PAGE;
fio.blk_addr = ni.blk_addr;
return f2fs_submit_page_bio(sbi, page, &fio);
return f2fs_submit_page_bio(&fio);
}
/*
......@@ -1204,13 +1211,9 @@ int sync_node_pages(struct f2fs_sb_info *sbi, nid_t ino,
/* called by fsync() */
if (ino && IS_DNODE(page)) {
set_fsync_mark(page, 1);
if (IS_INODE(page)) {
if (!is_checkpointed_node(sbi, ino) &&
!has_fsynced_inode(sbi, ino))
set_dentry_mark(page, 1);
else
set_dentry_mark(page, 0);
}
if (IS_INODE(page))
set_dentry_mark(page,
need_dentry_mark(sbi, ino));
nwritten++;
} else {
set_fsync_mark(page, 0);
......@@ -1293,8 +1296,11 @@ static int f2fs_write_node_page(struct page *page,
nid_t nid;
struct node_info ni;
struct f2fs_io_info fio = {
.sbi = sbi,
.type = NODE,
.rw = (wbc->sync_mode == WB_SYNC_ALL) ? WRITE_SYNC : WRITE,
.page = page,
.encrypted_page = NULL,
};
trace_f2fs_writepage(page, NODE);
......@@ -1329,7 +1335,7 @@ static int f2fs_write_node_page(struct page *page,
set_page_writeback(page);
fio.blk_addr = ni.blk_addr;
write_node_page(sbi, page, nid, &fio);
write_node_page(nid, &fio);
set_node_addr(sbi, &ni, fio.blk_addr, is_fsync_dnode(page));
dec_page_count(sbi, F2FS_DIRTY_NODES);
up_read(&sbi->node_write);
......
......@@ -343,28 +343,6 @@ static inline nid_t get_nid(struct page *p, int off, bool i)
* - Mark cold node blocks in their node footer
* - Mark cold data pages in page cache
*/
static inline int is_file(struct inode *inode, int type)
{
return F2FS_I(inode)->i_advise & type;
}
static inline void set_file(struct inode *inode, int type)
{
F2FS_I(inode)->i_advise |= type;
}
static inline void clear_file(struct inode *inode, int type)
{
F2FS_I(inode)->i_advise &= ~type;
}
#define file_is_cold(inode) is_file(inode, FADVISE_COLD_BIT)
#define file_wrong_pino(inode) is_file(inode, FADVISE_LOST_PINO_BIT)
#define file_set_cold(inode) set_file(inode, FADVISE_COLD_BIT)
#define file_lost_pino(inode) set_file(inode, FADVISE_LOST_PINO_BIT)
#define file_clear_cold(inode) clear_file(inode, FADVISE_COLD_BIT)
#define file_got_pino(inode) clear_file(inode, FADVISE_LOST_PINO_BIT)
static inline int is_cold_data(struct page *page)
{
return PageChecked(page);
......
......@@ -83,6 +83,11 @@ static int recover_dentry(struct inode *inode, struct page *ipage)
goto out;
}
if (file_enc_name(inode)) {
iput(dir);
return 0;
}
name.len = le32_to_cpu(raw_inode->i_namelen);
name.name = raw_inode->i_name;
......@@ -143,6 +148,7 @@ static int recover_dentry(struct inode *inode, struct page *ipage)
static void recover_inode(struct inode *inode, struct page *page)
{
struct f2fs_inode *raw = F2FS_INODE(page);
char *name;
inode->i_mode = le16_to_cpu(raw->i_mode);
i_size_write(inode, le64_to_cpu(raw->i_size));
......@@ -153,8 +159,13 @@ static void recover_inode(struct inode *inode, struct page *page)
inode->i_ctime.tv_nsec = le32_to_cpu(raw->i_ctime_nsec);
inode->i_mtime.tv_nsec = le32_to_cpu(raw->i_mtime_nsec);
if (file_enc_name(inode))
name = "<encrypted>";
else
name = F2FS_INODE(page)->i_name;
f2fs_msg(inode->i_sb, KERN_NOTICE, "recover_inode: ino = %x, name = %s",
ino_of_node(page), F2FS_INODE(page)->i_name);
ino_of_node(page), name);
}
static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head)
......@@ -174,7 +185,7 @@ static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head)
while (1) {
struct fsync_inode_entry *entry;
if (blkaddr < MAIN_BLKADDR(sbi) || blkaddr >= MAX_BLKADDR(sbi))
if (!is_valid_blkaddr(sbi, blkaddr, META_POR))
return 0;
page = get_meta_page(sbi, blkaddr);
......@@ -349,7 +360,6 @@ static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode,
struct f2fs_inode_info *fi = F2FS_I(inode);
unsigned int start, end;
struct dnode_of_data dn;
struct f2fs_summary sum;
struct node_info ni;
int err = 0, recovered = 0;
......@@ -396,7 +406,7 @@ static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode,
dest = datablock_addr(page, dn.ofs_in_node);
if (src != dest && dest != NEW_ADDR && dest != NULL_ADDR &&
dest >= MAIN_BLKADDR(sbi) && dest < MAX_BLKADDR(sbi)) {
is_valid_blkaddr(sbi, dest, META_POR)) {
if (src == NULL_ADDR) {
err = reserve_new_block(&dn);
......@@ -409,13 +419,9 @@ static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode,
if (err)
goto err;
set_summary(&sum, dn.nid, dn.ofs_in_node, ni.version);
/* write dummy data page */
recover_data_page(sbi, NULL, &sum, src, dest);
dn.data_blkaddr = dest;
set_data_blkaddr(&dn);
f2fs_update_extent_cache(&dn);
f2fs_replace_block(sbi, &dn, src, dest,
ni.version, false);
recovered++;
}
dn.ofs_in_node++;
......@@ -454,7 +460,7 @@ static int recover_data(struct f2fs_sb_info *sbi,
while (1) {
struct fsync_inode_entry *entry;
if (blkaddr < MAIN_BLKADDR(sbi) || blkaddr >= MAX_BLKADDR(sbi))
if (!is_valid_blkaddr(sbi, blkaddr, META_POR))
break;
ra_meta_pages_cond(sbi, blkaddr);
......
此差异已折叠。
......@@ -163,6 +163,7 @@ struct seg_entry {
*/
unsigned short ckpt_valid_blocks;
unsigned char *ckpt_valid_map;
unsigned char *discard_map;
unsigned char type; /* segment type like CURSEG_XXX_TYPE */
unsigned long long mtime; /* modification time of the segment */
};
......
此差异已折叠。
......@@ -80,7 +80,7 @@ void f2fs_trace_pid(struct page *page)
radix_tree_preload_end();
}
void f2fs_trace_ios(struct page *page, struct f2fs_io_info *fio, int flush)
void f2fs_trace_ios(struct f2fs_io_info *fio, int flush)
{
struct inode *inode;
pid_t pid;
......@@ -91,8 +91,8 @@ void f2fs_trace_ios(struct page *page, struct f2fs_io_info *fio, int flush)
return;
}
inode = page->mapping->host;
pid = page_private(page);
inode = fio->page->mapping->host;
pid = page_private(fio->page);
major = MAJOR(inode->i_sb->s_dev);
minor = MINOR(inode->i_sb->s_dev);
......
......@@ -33,12 +33,12 @@ struct last_io_info {
};
extern void f2fs_trace_pid(struct page *);
extern void f2fs_trace_ios(struct page *, struct f2fs_io_info *, int);
extern void f2fs_trace_ios(struct f2fs_io_info *, int);
extern void f2fs_build_trace_ios(void);
extern void f2fs_destroy_trace_ios(void);
#else
#define f2fs_trace_pid(p)
#define f2fs_trace_ios(p, i, n)
#define f2fs_trace_ios(i, n)
#define f2fs_build_trace_ios()
#define f2fs_destroy_trace_ios()
......
......@@ -584,6 +584,9 @@ static int __f2fs_setxattr(struct inode *inode, int index,
inode->i_ctime = CURRENT_TIME;
clear_inode_flag(fi, FI_ACL_MODE);
}
if (index == F2FS_XATTR_INDEX_ENCRYPTION &&
!strcmp(name, F2FS_XATTR_NAME_ENCRYPTION_CONTEXT))
f2fs_set_encrypted_inode(inode);
if (ipage)
update_inode(inode, ipage);
......
......@@ -35,6 +35,10 @@
#define F2FS_XATTR_INDEX_LUSTRE 5
#define F2FS_XATTR_INDEX_SECURITY 6
#define F2FS_XATTR_INDEX_ADVISE 7
/* Should be same as EXT4_XATTR_INDEX_ENCRYPTION */
#define F2FS_XATTR_INDEX_ENCRYPTION 9
#define F2FS_XATTR_NAME_ENCRYPTION_CONTEXT "c"
struct f2fs_xattr_header {
__le32 h_magic; /* magic number for identification */
......
......@@ -50,6 +50,8 @@
#define MAX_ACTIVE_NODE_LOGS 8
#define MAX_ACTIVE_DATA_LOGS 8
#define VERSION_LEN 256
/*
* For superblock
*/
......@@ -86,6 +88,12 @@ struct f2fs_super_block {
__le32 extension_count; /* # of extensions below */
__u8 extension_list[F2FS_MAX_EXTENSION][8]; /* extension array */
__le32 cp_payload;
__u8 version[VERSION_LEN]; /* the kernel version */
__u8 init_version[VERSION_LEN]; /* the initial kernel version */
__le32 feature; /* defined features */
__u8 encryption_level; /* versioning level for encryption */
__u8 encrypt_pw_salt[16]; /* Salt used for string2key algorithm */
__u8 reserved[871]; /* valid reserved region */
} __packed;
/*
......
......@@ -13,6 +13,10 @@ TRACE_DEFINE_ENUM(NODE);
TRACE_DEFINE_ENUM(DATA);
TRACE_DEFINE_ENUM(META);
TRACE_DEFINE_ENUM(META_FLUSH);
TRACE_DEFINE_ENUM(INMEM);
TRACE_DEFINE_ENUM(INMEM_DROP);
TRACE_DEFINE_ENUM(IPU);
TRACE_DEFINE_ENUM(OPU);
TRACE_DEFINE_ENUM(CURSEG_HOT_DATA);
TRACE_DEFINE_ENUM(CURSEG_WARM_DATA);
TRACE_DEFINE_ENUM(CURSEG_COLD_DATA);
......@@ -37,6 +41,7 @@ TRACE_DEFINE_ENUM(__REQ_META);
TRACE_DEFINE_ENUM(CP_UMOUNT);
TRACE_DEFINE_ENUM(CP_FASTBOOT);
TRACE_DEFINE_ENUM(CP_SYNC);
TRACE_DEFINE_ENUM(CP_RECOVERY);
TRACE_DEFINE_ENUM(CP_DISCARD);
#define show_block_type(type) \
......@@ -112,6 +117,7 @@ TRACE_DEFINE_ENUM(CP_DISCARD);
{ CP_DISCARD, "Discard" })
struct victim_sel_policy;
struct f2fs_map_blocks;
DECLARE_EVENT_CLASS(f2fs__inode,
......@@ -476,36 +482,35 @@ TRACE_EVENT(f2fs_truncate_partial_nodes,
__entry->err)
);
TRACE_EVENT(f2fs_get_data_block,
TP_PROTO(struct inode *inode, sector_t iblock,
struct buffer_head *bh, int ret),
TRACE_EVENT(f2fs_map_blocks,
TP_PROTO(struct inode *inode, struct f2fs_map_blocks *map, int ret),
TP_ARGS(inode, iblock, bh, ret),
TP_ARGS(inode, map, ret),
TP_STRUCT__entry(
__field(dev_t, dev)
__field(ino_t, ino)
__field(sector_t, iblock)
__field(sector_t, bh_start)
__field(size_t, bh_size)
__field(block_t, m_lblk)
__field(block_t, m_pblk)
__field(unsigned int, m_len)
__field(int, ret)
),
TP_fast_assign(
__entry->dev = inode->i_sb->s_dev;
__entry->ino = inode->i_ino;
__entry->iblock = iblock;
__entry->bh_start = bh->b_blocknr;
__entry->bh_size = bh->b_size;
__entry->m_lblk = map->m_lblk;
__entry->m_pblk = map->m_pblk;
__entry->m_len = map->m_len;
__entry->ret = ret;
),
TP_printk("dev = (%d,%d), ino = %lu, file offset = %llu, "
"start blkaddr = 0x%llx, len = 0x%llx bytes, err = %d",
"start blkaddr = 0x%llx, len = 0x%llx, err = %d",
show_dev_ino(__entry),
(unsigned long long)__entry->iblock,
(unsigned long long)__entry->bh_start,
(unsigned long long)__entry->bh_size,
(unsigned long long)__entry->m_lblk,
(unsigned long long)__entry->m_pblk,
(unsigned long long)__entry->m_len,
__entry->ret)
);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册