Merge tag 'for-f2fs-4.6' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk...
authorLinus Torvalds <torvalds@linux-foundation.org>
Mon, 21 Mar 2016 18:03:02 +0000 (11:03 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 21 Mar 2016 18:03:02 +0000 (11:03 -0700)
Pull f2fs updates from Jaegeuk Kim:
 "New Features:
   - uplift filesystem encryption into fs/crypto/
   - give sysfs entries to control memroy consumption

  Enhancements:
   - aio performance by preallocating blocks in ->write_iter
   - use writepages lock for only WB_SYNC_ALL
   - avoid redundant inline_data conversion
   - enhance forground GC
   - use wait_for_stable_page as possible
   - speed up SEEK_DATA and fiiemap

  Bug Fixes:
   - corner case in terms of -ENOSPC for inline_data
   - hung task caused by long latency in shrinker
   - corruption between atomic write and f2fs_trace_pid
   - avoid garbage lengths in dentries
   - revoke atomicly written pages if an error occurs

  In addition, there are various minor bug fixes and clean-ups"

* tag 'for-f2fs-4.6' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs: (81 commits)
  f2fs: submit node page write bios when really required
  f2fs: add missing argument to f2fs_setxattr stub
  f2fs: fix to avoid unneeded unlock_new_inode
  f2fs: clean up opened code with f2fs_update_dentry
  f2fs: declare static functions
  f2fs: use cryptoapi crc32 functions
  f2fs: modify the readahead method in ra_node_page()
  f2fs crypto: sync ext4_lookup and ext4_file_open
  fs crypto: move per-file encryption from f2fs tree to fs/crypto
  f2fs: mutex can't be used by down_write_nest_lock()
  f2fs: recovery missing dot dentries in root directory
  f2fs: fix to avoid deadlock when merging inline data
  f2fs: introduce f2fs_flush_merged_bios for cleanup
  f2fs: introduce f2fs_update_data_blkaddr for cleanup
  f2fs crypto: fix incorrect positioning for GCing encrypted data page
  f2fs: fix incorrect upper bound when iterating inode mapping tree
  f2fs: avoid hungtask problem caused by losing wake_up
  f2fs: trace old block address for CoWed page
  f2fs: try to flush inode after merging inline data
  f2fs: show more info about superblock recovery
  ...

40 files changed:
Documentation/ABI/testing/sysfs-fs-f2fs
fs/Kconfig
fs/Makefile
fs/crypto/Kconfig [new file with mode: 0644]
fs/crypto/Makefile [new file with mode: 0644]
fs/crypto/crypto.c [new file with mode: 0644]
fs/crypto/fname.c [moved from fs/f2fs/crypto_fname.c with 59% similarity]
fs/crypto/keyinfo.c [new file with mode: 0644]
fs/crypto/policy.c [new file with mode: 0644]
fs/f2fs/Kconfig
fs/f2fs/Makefile
fs/f2fs/checkpoint.c
fs/f2fs/crypto.c [deleted file]
fs/f2fs/crypto_key.c [deleted file]
fs/f2fs/crypto_policy.c [deleted file]
fs/f2fs/data.c
fs/f2fs/dir.c
fs/f2fs/extent_cache.c
fs/f2fs/f2fs.h
fs/f2fs/f2fs_crypto.h [deleted file]
fs/f2fs/file.c
fs/f2fs/gc.c
fs/f2fs/inline.c
fs/f2fs/inode.c
fs/f2fs/namei.c
fs/f2fs/node.c
fs/f2fs/node.h
fs/f2fs/recovery.c
fs/f2fs/segment.c
fs/f2fs/segment.h
fs/f2fs/super.c
fs/f2fs/trace.c
fs/f2fs/xattr.c
fs/f2fs/xattr.h
include/linux/dcache.h
include/linux/f2fs_fs.h
include/linux/fs.h
include/linux/fscrypto.h [new file with mode: 0644]
include/trace/events/f2fs.h
include/uapi/linux/fs.h

index e5200f3..a809f60 100644 (file)
@@ -98,3 +98,17 @@ Date:                October 2015
 Contact:       "Chao Yu" <chao2.yu@samsung.com>
 Description:
                 Controls the count of nid pages to be readaheaded.
+
+What:          /sys/fs/f2fs/<disk>/dirty_nats_ratio
+Date:          January 2016
+Contact:       "Chao Yu" <chao2.yu@samsung.com>
+Description:
+                Controls dirty nat entries ratio threshold, if current
+                ratio exceeds configured threshold, checkpoint will
+                be triggered for flushing dirty nat entries.
+
+What:          /sys/fs/f2fs/<disk>/lifetime_write_kbytes
+Date:          January 2016
+Contact:       "Shuoran Liu" <liushuoran@huawei.com>
+Description:
+                Shows total written kbytes issued to disk.
index 9adee0d..9d75767 100644 (file)
@@ -84,6 +84,8 @@ config MANDATORY_FILE_LOCKING
 
          To the best of my knowledge this is dead code that no one cares about.
 
+source "fs/crypto/Kconfig"
+
 source "fs/notify/Kconfig"
 
 source "fs/quota/Kconfig"
index 79f5225..252c968 100644 (file)
@@ -30,6 +30,7 @@ obj-$(CONFIG_EVENTFD)         += eventfd.o
 obj-$(CONFIG_USERFAULTFD)      += userfaultfd.o
 obj-$(CONFIG_AIO)               += aio.o
 obj-$(CONFIG_FS_DAX)           += dax.o
+obj-$(CONFIG_FS_ENCRYPTION)    += crypto/
 obj-$(CONFIG_FILE_LOCKING)      += locks.o
 obj-$(CONFIG_COMPAT)           += compat.o compat_ioctl.o
 obj-$(CONFIG_BINFMT_AOUT)      += binfmt_aout.o
diff --git a/fs/crypto/Kconfig b/fs/crypto/Kconfig
new file mode 100644 (file)
index 0000000..92348fa
--- /dev/null
@@ -0,0 +1,18 @@
+config FS_ENCRYPTION
+       tristate "FS Encryption (Per-file encryption)"
+       depends on BLOCK
+       select CRYPTO
+       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 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.
diff --git a/fs/crypto/Makefile b/fs/crypto/Makefile
new file mode 100644 (file)
index 0000000..f17684c
--- /dev/null
@@ -0,0 +1,3 @@
+obj-$(CONFIG_FS_ENCRYPTION)    += fscrypto.o
+
+fscrypto-y := crypto.o fname.o policy.o keyinfo.o
diff --git a/fs/crypto/crypto.c b/fs/crypto/crypto.c
new file mode 100644 (file)
index 0000000..aed9ccc
--- /dev/null
@@ -0,0 +1,555 @@
+/*
+ * This contains encryption functions for per-file encryption.
+ *
+ * Copyright (C) 2015, Google, Inc.
+ * Copyright (C) 2015, Motorola Mobility
+ *
+ * Written by Michael Halcrow, 2014.
+ *
+ * Filename encryption additions
+ *     Uday Savagaonkar, 2014
+ * Encryption policy handling additions
+ *     Ildar Muslukhov, 2014
+ * Add fscrypt_pullback_bio_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 <linux/pagemap.h>
+#include <linux/mempool.h>
+#include <linux/module.h>
+#include <linux/scatterlist.h>
+#include <linux/ratelimit.h>
+#include <linux/bio.h>
+#include <linux/dcache.h>
+#include <linux/fscrypto.h>
+#include <linux/ecryptfs.h>
+
+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 *fscrypt_bounce_page_pool = NULL;
+
+static LIST_HEAD(fscrypt_free_ctxs);
+static DEFINE_SPINLOCK(fscrypt_ctx_lock);
+
+static struct workqueue_struct *fscrypt_read_workqueue;
+static DEFINE_MUTEX(fscrypt_init_mutex);
+
+static struct kmem_cache *fscrypt_ctx_cachep;
+struct kmem_cache *fscrypt_info_cachep;
+
+/**
+ * fscrypt_release_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 fscrypt_release_ctx(struct fscrypt_ctx *ctx)
+{
+       unsigned long flags;
+
+       if (ctx->flags & FS_WRITE_PATH_FL && ctx->w.bounce_page) {
+               mempool_free(ctx->w.bounce_page, fscrypt_bounce_page_pool);
+               ctx->w.bounce_page = NULL;
+       }
+       ctx->w.control_page = NULL;
+       if (ctx->flags & FS_CTX_REQUIRES_FREE_ENCRYPT_FL) {
+               kmem_cache_free(fscrypt_ctx_cachep, ctx);
+       } else {
+               spin_lock_irqsave(&fscrypt_ctx_lock, flags);
+               list_add(&ctx->free_list, &fscrypt_free_ctxs);
+               spin_unlock_irqrestore(&fscrypt_ctx_lock, flags);
+       }
+}
+EXPORT_SYMBOL(fscrypt_release_ctx);
+
+/**
+ * fscrypt_get_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 fscrypt_ctx *fscrypt_get_ctx(struct inode *inode)
+{
+       struct fscrypt_ctx *ctx = NULL;
+       struct fscrypt_info *ci = inode->i_crypt_info;
+       unsigned long flags;
+
+       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(&fscrypt_ctx_lock, flags);
+       ctx = list_first_entry_or_null(&fscrypt_free_ctxs,
+                                       struct fscrypt_ctx, free_list);
+       if (ctx)
+               list_del(&ctx->free_list);
+       spin_unlock_irqrestore(&fscrypt_ctx_lock, flags);
+       if (!ctx) {
+               ctx = kmem_cache_zalloc(fscrypt_ctx_cachep, GFP_NOFS);
+               if (!ctx)
+                       return ERR_PTR(-ENOMEM);
+               ctx->flags |= FS_CTX_REQUIRES_FREE_ENCRYPT_FL;
+       } else {
+               ctx->flags &= ~FS_CTX_REQUIRES_FREE_ENCRYPT_FL;
+       }
+       ctx->flags &= ~FS_WRITE_PATH_FL;
+       return ctx;
+}
+EXPORT_SYMBOL(fscrypt_get_ctx);
+
+/**
+ * fscrypt_complete() - The completion callback for page encryption
+ * @req: The asynchronous encryption request context
+ * @res: The result of the encryption operation
+ */
+static void fscrypt_complete(struct crypto_async_request *req, int res)
+{
+       struct fscrypt_completion_result *ecr = req->data;
+
+       if (res == -EINPROGRESS)
+               return;
+       ecr->res = res;
+       complete(&ecr->completion);
+}
+
+typedef enum {
+       FS_DECRYPT = 0,
+       FS_ENCRYPT,
+} fscrypt_direction_t;
+
+static int do_page_crypto(struct inode *inode,
+                       fscrypt_direction_t rw, pgoff_t index,
+                       struct page *src_page, struct page *dest_page)
+{
+       u8 xts_tweak[FS_XTS_TWEAK_SIZE];
+       struct skcipher_request *req = NULL;
+       DECLARE_FS_COMPLETION_RESULT(ecr);
+       struct scatterlist dst, src;
+       struct fscrypt_info *ci = inode->i_crypt_info;
+       struct crypto_skcipher *tfm = ci->ci_ctfm;
+       int res = 0;
+
+       req = skcipher_request_alloc(tfm, GFP_NOFS);
+       if (!req) {
+               printk_ratelimited(KERN_ERR
+                               "%s: crypto_request_alloc() failed\n",
+                               __func__);
+               return -ENOMEM;
+       }
+
+       skcipher_request_set_callback(
+               req, CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP,
+               fscrypt_complete, &ecr);
+
+       BUILD_BUG_ON(FS_XTS_TWEAK_SIZE < sizeof(index));
+       memcpy(xts_tweak, &inode->i_ino, sizeof(index));
+       memset(&xts_tweak[sizeof(index)], 0,
+                       FS_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);
+       skcipher_request_set_crypt(req, &src, &dst, PAGE_CACHE_SIZE,
+                                       xts_tweak);
+       if (rw == FS_DECRYPT)
+               res = crypto_skcipher_decrypt(req);
+       else
+               res = crypto_skcipher_encrypt(req);
+       if (res == -EINPROGRESS || res == -EBUSY) {
+               BUG_ON(req->base.data != &ecr);
+               wait_for_completion(&ecr.completion);
+               res = ecr.res;
+       }
+       skcipher_request_free(req);
+       if (res) {
+               printk_ratelimited(KERN_ERR
+                       "%s: crypto_skcipher_encrypt() returned %d\n",
+                       __func__, res);
+               return res;
+       }
+       return 0;
+}
+
+static struct page *alloc_bounce_page(struct fscrypt_ctx *ctx)
+{
+       ctx->w.bounce_page = mempool_alloc(fscrypt_bounce_page_pool,
+                                                       GFP_NOWAIT);
+       if (ctx->w.bounce_page == NULL)
+               return ERR_PTR(-ENOMEM);
+       ctx->flags |= FS_WRITE_PATH_FL;
+       return ctx->w.bounce_page;
+}
+
+/**
+ * fscypt_encrypt_page() - 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
+ * fscrypt_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 *fscrypt_encrypt_page(struct inode *inode,
+                               struct page *plaintext_page)
+{
+       struct fscrypt_ctx *ctx;
+       struct page *ciphertext_page = NULL;
+       int err;
+
+       BUG_ON(!PageLocked(plaintext_page));
+
+       ctx = fscrypt_get_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 errout;
+
+       ctx->w.control_page = plaintext_page;
+       err = do_page_crypto(inode, FS_ENCRYPT, plaintext_page->index,
+                                       plaintext_page, ciphertext_page);
+       if (err) {
+               ciphertext_page = ERR_PTR(err);
+               goto errout;
+       }
+       SetPagePrivate(ciphertext_page);
+       set_page_private(ciphertext_page, (unsigned long)ctx);
+       lock_page(ciphertext_page);
+       return ciphertext_page;
+
+errout:
+       fscrypt_release_ctx(ctx);
+       return ciphertext_page;
+}
+EXPORT_SYMBOL(fscrypt_encrypt_page);
+
+/**
+ * f2crypt_decrypt_page() - Decrypts a page in-place
+ * @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 fscrypt_decrypt_page(struct page *page)
+{
+       BUG_ON(!PageLocked(page));
+
+       return do_page_crypto(page->mapping->host,
+                       FS_DECRYPT, page->index, page, page);
+}
+EXPORT_SYMBOL(fscrypt_decrypt_page);
+
+int fscrypt_zeroout_range(struct inode *inode, pgoff_t lblk,
+                               sector_t pblk, unsigned int len)
+{
+       struct fscrypt_ctx *ctx;
+       struct page *ciphertext_page = NULL;
+       struct bio *bio;
+       int ret, err = 0;
+
+       BUG_ON(inode->i_sb->s_blocksize != PAGE_CACHE_SIZE);
+
+       ctx = fscrypt_get_ctx(inode);
+       if (IS_ERR(ctx))
+               return PTR_ERR(ctx);
+
+       ciphertext_page = alloc_bounce_page(ctx);
+       if (IS_ERR(ciphertext_page)) {
+               err = PTR_ERR(ciphertext_page);
+               goto errout;
+       }
+
+       while (len--) {
+               err = do_page_crypto(inode, FS_ENCRYPT, lblk,
+                                               ZERO_PAGE(0), ciphertext_page);
+               if (err)
+                       goto errout;
+
+               bio = bio_alloc(GFP_KERNEL, 1);
+               if (!bio) {
+                       err = -ENOMEM;
+                       goto errout;
+               }
+               bio->bi_bdev = inode->i_sb->s_bdev;
+               bio->bi_iter.bi_sector =
+                       pblk << (inode->i_sb->s_blocksize_bits - 9);
+               ret = bio_add_page(bio, ciphertext_page,
+                                       inode->i_sb->s_blocksize, 0);
+               if (ret != inode->i_sb->s_blocksize) {
+                       /* should never happen! */
+                       WARN_ON(1);
+                       bio_put(bio);
+                       err = -EIO;
+                       goto errout;
+               }
+               err = submit_bio_wait(WRITE, bio);
+               if ((err == 0) && bio->bi_error)
+                       err = -EIO;
+               bio_put(bio);
+               if (err)
+                       goto errout;
+               lblk++;
+               pblk++;
+       }
+       err = 0;
+errout:
+       fscrypt_release_ctx(ctx);
+       return err;
+}
+EXPORT_SYMBOL(fscrypt_zeroout_range);
+
+/*
+ * Validate dentries for encrypted directories to make sure we aren't
+ * potentially caching stale data after a key has been added or
+ * removed.
+ */
+static int fscrypt_d_revalidate(struct dentry *dentry, unsigned int flags)
+{
+       struct inode *dir = d_inode(dentry->d_parent);
+       struct fscrypt_info *ci = dir->i_crypt_info;
+       int dir_has_key, cached_with_key;
+
+       if (!dir->i_sb->s_cop->is_encrypted(dir))
+               return 0;
+
+       if (ci && ci->ci_keyring_key &&
+           (ci->ci_keyring_key->flags & ((1 << KEY_FLAG_INVALIDATED) |
+                                         (1 << KEY_FLAG_REVOKED) |
+                                         (1 << KEY_FLAG_DEAD))))
+               ci = NULL;
+
+       /* this should eventually be an flag in d_flags */
+       spin_lock(&dentry->d_lock);
+       cached_with_key = dentry->d_flags & DCACHE_ENCRYPTED_WITH_KEY;
+       spin_unlock(&dentry->d_lock);
+       dir_has_key = (ci != NULL);
+
+       /*
+        * If the dentry was cached without the key, and it is a
+        * negative dentry, it might be a valid name.  We can't check
+        * if the key has since been made available due to locking
+        * reasons, so we fail the validation so ext4_lookup() can do
+        * this check.
+        *
+        * We also fail the validation if the dentry was created with
+        * the key present, but we no longer have the key, or vice versa.
+        */
+       if ((!cached_with_key && d_is_negative(dentry)) ||
+                       (!cached_with_key && dir_has_key) ||
+                       (cached_with_key && !dir_has_key))
+               return 0;
+       return 1;
+}
+
+const struct dentry_operations fscrypt_d_ops = {
+       .d_revalidate = fscrypt_d_revalidate,
+};
+EXPORT_SYMBOL(fscrypt_d_ops);
+
+/*
+ * Call fscrypt_decrypt_page on every single page, reusing the encryption
+ * context.
+ */
+static void completion_pages(struct work_struct *work)
+{
+       struct fscrypt_ctx *ctx =
+               container_of(work, struct fscrypt_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 = fscrypt_decrypt_page(page);
+
+               if (ret) {
+                       WARN_ON_ONCE(1);
+                       SetPageError(page);
+               } else {
+                       SetPageUptodate(page);
+               }
+               unlock_page(page);
+       }
+       fscrypt_release_ctx(ctx);
+       bio_put(bio);
+}
+
+void fscrypt_decrypt_bio_pages(struct fscrypt_ctx *ctx, struct bio *bio)
+{
+       INIT_WORK(&ctx->r.work, completion_pages);
+       ctx->r.bio = bio;
+       queue_work(fscrypt_read_workqueue, &ctx->r.work);
+}
+EXPORT_SYMBOL(fscrypt_decrypt_bio_pages);
+
+void fscrypt_pullback_bio_page(struct page **page, bool restore)
+{
+       struct fscrypt_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 fscrypt_ctx *)page_private(bounce_page);
+
+       /* restore control page */
+       *page = ctx->w.control_page;
+
+       if (restore)
+               fscrypt_restore_control_page(bounce_page);
+}
+EXPORT_SYMBOL(fscrypt_pullback_bio_page);
+
+void fscrypt_restore_control_page(struct page *page)
+{
+       struct fscrypt_ctx *ctx;
+
+       ctx = (struct fscrypt_ctx *)page_private(page);
+       set_page_private(page, (unsigned long)NULL);
+       ClearPagePrivate(page);
+       unlock_page(page);
+       fscrypt_release_ctx(ctx);
+}
+EXPORT_SYMBOL(fscrypt_restore_control_page);
+
+static void fscrypt_destroy(void)
+{
+       struct fscrypt_ctx *pos, *n;
+
+       list_for_each_entry_safe(pos, n, &fscrypt_free_ctxs, free_list)
+               kmem_cache_free(fscrypt_ctx_cachep, pos);
+       INIT_LIST_HEAD(&fscrypt_free_ctxs);
+       mempool_destroy(fscrypt_bounce_page_pool);
+       fscrypt_bounce_page_pool = NULL;
+}
+
+/**
+ * fscrypt_initialize() - allocate major buffers for fs 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 fscrypt_initialize(void)
+{
+       int i, res = -ENOMEM;
+
+       if (fscrypt_bounce_page_pool)
+               return 0;
+
+       mutex_lock(&fscrypt_init_mutex);
+       if (fscrypt_bounce_page_pool)
+               goto already_initialized;
+
+       for (i = 0; i < num_prealloc_crypto_ctxs; i++) {
+               struct fscrypt_ctx *ctx;
+
+               ctx = kmem_cache_zalloc(fscrypt_ctx_cachep, GFP_NOFS);
+               if (!ctx)
+                       goto fail;
+               list_add(&ctx->free_list, &fscrypt_free_ctxs);
+       }
+
+       fscrypt_bounce_page_pool =
+               mempool_create_page_pool(num_prealloc_crypto_pages, 0);
+       if (!fscrypt_bounce_page_pool)
+               goto fail;
+
+already_initialized:
+       mutex_unlock(&fscrypt_init_mutex);
+       return 0;
+fail:
+       fscrypt_destroy();
+       mutex_unlock(&fscrypt_init_mutex);
+       return res;
+}
+EXPORT_SYMBOL(fscrypt_initialize);
+
+/**
+ * fscrypt_init() - Set up for fs encryption.
+ */
+static int __init fscrypt_init(void)
+{
+       fscrypt_read_workqueue = alloc_workqueue("fscrypt_read_queue",
+                                                       WQ_HIGHPRI, 0);
+       if (!fscrypt_read_workqueue)
+               goto fail;
+
+       fscrypt_ctx_cachep = KMEM_CACHE(fscrypt_ctx, SLAB_RECLAIM_ACCOUNT);
+       if (!fscrypt_ctx_cachep)
+               goto fail_free_queue;
+
+       fscrypt_info_cachep = KMEM_CACHE(fscrypt_info, SLAB_RECLAIM_ACCOUNT);
+       if (!fscrypt_info_cachep)
+               goto fail_free_ctx;
+
+       return 0;
+
+fail_free_ctx:
+       kmem_cache_destroy(fscrypt_ctx_cachep);
+fail_free_queue:
+       destroy_workqueue(fscrypt_read_workqueue);
+fail:
+       return -ENOMEM;
+}
+module_init(fscrypt_init)
+
+/**
+ * fscrypt_exit() - Shutdown the fs encryption system
+ */
+static void __exit fscrypt_exit(void)
+{
+       fscrypt_destroy();
+
+       if (fscrypt_read_workqueue)
+               destroy_workqueue(fscrypt_read_workqueue);
+       kmem_cache_destroy(fscrypt_ctx_cachep);
+       kmem_cache_destroy(fscrypt_info_cachep);
+}
+module_exit(fscrypt_exit);
+
+MODULE_LICENSE("GPL");
similarity index 59%
rename from fs/f2fs/crypto_fname.c
rename to fs/crypto/fname.c
index 16aec66..5d6d491 100644 (file)
@@ -1,44 +1,32 @@
 /*
- * linux/fs/f2fs/crypto_fname.c
- *
- * Copied from linux/fs/ext4/crypto.c
+ * This contains functions for filename crypto management
  *
  * 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.
+ * Modified by Jaegeuk Kim, 2015.
  *
  * This has not yet undergone a rigorous security audit.
  */
-#include <crypto/skcipher.h>
+
 #include <keys/encrypted-type.h>
 #include <keys/user-type.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 <linux/fscrypto.h>
 
-#include "f2fs.h"
-#include "f2fs_crypto.h"
-#include "xattr.h"
+static u32 size_round_up(size_t size, size_t blksize)
+{
+       return ((size + blksize - 1) / blksize) * blksize;
+}
 
 /**
- * f2fs_dir_crypt_complete() -
+ * dir_crypt_complete() -
  */
-static void f2fs_dir_crypt_complete(struct crypto_async_request *req, int res)
+static void dir_crypt_complete(struct crypto_async_request *req, int res)
 {
-       struct f2fs_completion_result *ecr = req->data;
+       struct fscrypt_completion_result *ecr = req->data;
 
        if (res == -EINPROGRESS)
                return;
@@ -46,45 +34,35 @@ static void f2fs_dir_crypt_complete(struct crypto_async_request *req, int 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() -
+ * 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)
+static int fname_encrypt(struct inode *inode,
+                       const struct qstr *iname, struct fscrypt_str *oname)
 {
        u32 ciphertext_len;
        struct skcipher_request *req = NULL;
-       DECLARE_F2FS_COMPLETION_RESULT(ecr);
-       struct f2fs_crypt_info *ci = F2FS_I(inode)->i_crypt_info;
+       DECLARE_FS_COMPLETION_RESULT(ecr);
+       struct fscrypt_info *ci = inode->i_crypt_info;
        struct crypto_skcipher *tfm = ci->ci_ctfm;
        int res = 0;
-       char iv[F2FS_CRYPTO_BLOCK_SIZE];
+       char iv[FS_CRYPTO_BLOCK_SIZE];
        struct scatterlist src_sg, dst_sg;
-       int padding = 4 << (ci->ci_flags & F2FS_POLICY_FLAGS_PAD_MASK);
+       int padding = 4 << (ci->ci_flags & FS_POLICY_FLAGS_PAD_MASK);
        char *workbuf, buf[32], *alloc_buf = NULL;
-       unsigned lim = max_name_len(inode);
+       unsigned lim;
 
+       lim = inode->i_sb->s_cop->max_namelen(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 = (iname->len < FS_CRYPTO_BLOCK_SIZE) ?
+                                       FS_CRYPTO_BLOCK_SIZE : iname->len;
+       ciphertext_len = size_round_up(ciphertext_len, padding);
        ciphertext_len = (ciphertext_len > lim) ? lim : ciphertext_len;
 
        if (ciphertext_len <= sizeof(buf)) {
@@ -106,7 +84,7 @@ static int f2fs_fname_encrypt(struct inode *inode,
        }
        skcipher_request_set_callback(req,
                        CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP,
-                       f2fs_dir_crypt_complete, &ecr);
+                       dir_crypt_complete, &ecr);
 
        /* Copy the input */
        memcpy(workbuf, iname->name, iname->len);
@@ -114,7 +92,7 @@ static int f2fs_fname_encrypt(struct inode *inode,
                memset(workbuf + iname->len, 0, ciphertext_len - iname->len);
 
        /* Initialize IV */
-       memset(iv, 0, F2FS_CRYPTO_BLOCK_SIZE);
+       memset(iv, 0, FS_CRYPTO_BLOCK_SIZE);
 
        /* Create encryption request */
        sg_init_one(&src_sg, workbuf, ciphertext_len);
@@ -122,39 +100,40 @@ static int f2fs_fname_encrypt(struct inode *inode,
        skcipher_request_set_crypt(req, &src_sg, &dst_sg, ciphertext_len, iv);
        res = crypto_skcipher_encrypt(req);
        if (res == -EINPROGRESS || res == -EBUSY) {
-               BUG_ON(req->base.data != &ecr);
                wait_for_completion(&ecr.completion);
                res = ecr.res;
        }
        kfree(alloc_buf);
        skcipher_request_free(req);
-       if (res < 0) {
+       if (res < 0)
                printk_ratelimited(KERN_ERR
                                "%s: Error (error code %d)\n", __func__, res);
-       }
+
        oname->len = ciphertext_len;
        return res;
 }
 
 /*
- * f2fs_fname_decrypt()
+ * 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)
+static int fname_decrypt(struct inode *inode,
+                               const struct fscrypt_str *iname,
+                               struct fscrypt_str *oname)
 {
        struct skcipher_request *req = NULL;
-       DECLARE_F2FS_COMPLETION_RESULT(ecr);
+       DECLARE_FS_COMPLETION_RESULT(ecr);
        struct scatterlist src_sg, dst_sg;
-       struct f2fs_crypt_info *ci = F2FS_I(inode)->i_crypt_info;
+       struct fscrypt_info *ci = inode->i_crypt_info;
        struct crypto_skcipher *tfm = ci->ci_ctfm;
        int res = 0;
-       char iv[F2FS_CRYPTO_BLOCK_SIZE];
-       unsigned lim = max_name_len(inode);
+       char iv[FS_CRYPTO_BLOCK_SIZE];
+       unsigned lim;
 
+       lim = inode->i_sb->s_cop->max_namelen(inode);
        if (iname->len <= 0 || iname->len > lim)
                return -EIO;
 
@@ -167,10 +146,10 @@ static int f2fs_fname_decrypt(struct inode *inode,
        }
        skcipher_request_set_callback(req,
                CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP,
-               f2fs_dir_crypt_complete, &ecr);
+               dir_crypt_complete, &ecr);
 
        /* Initialize IV */
-       memset(iv, 0, F2FS_CRYPTO_BLOCK_SIZE);
+       memset(iv, 0, FS_CRYPTO_BLOCK_SIZE);
 
        /* Create decryption request */
        sg_init_one(&src_sg, iname->name, iname->len);
@@ -178,15 +157,13 @@ static int f2fs_fname_decrypt(struct inode *inode,
        skcipher_request_set_crypt(req, &src_sg, &dst_sg, iname->len, iv);
        res = crypto_skcipher_decrypt(req);
        if (res == -EINPROGRESS || res == -EBUSY) {
-               BUG_ON(req->base.data != &ecr);
                wait_for_completion(&ecr.completion);
                res = ecr.res;
        }
        skcipher_request_free(req);
        if (res < 0) {
                printk_ratelimited(KERN_ERR
-                       "%s: Error in f2fs_fname_decrypt (error code %d)\n",
-                       __func__, res);
+                               "%s: Error (error code %d)\n", __func__, res);
                return res;
        }
 
@@ -198,7 +175,7 @@ static const char *lookup_table =
        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+,";
 
 /**
- * f2fs_fname_encode_digest() -
+ * digest_encode() -
  *
  * 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.
@@ -247,148 +224,152 @@ static int digest_decode(const char *src, int len, char *dst)
        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)
+u32 fscrypt_fname_encrypted_size(struct inode *inode, u32 ilen)
 {
-       return ((size + blksize - 1) / blksize) * blksize;
+       int padding = 32;
+       struct fscrypt_info *ci = inode->i_crypt_info;
+
+       if (ci)
+               padding = 4 << (ci->ci_flags & FS_POLICY_FLAGS_PAD_MASK);
+       if (ilen < FS_CRYPTO_BLOCK_SIZE)
+               ilen = FS_CRYPTO_BLOCK_SIZE;
+       return size_round_up(ilen, padding);
 }
+EXPORT_SYMBOL(fscrypt_fname_encrypted_size);
 
 /**
- * f2fs_fname_crypto_alloc_obuff() -
+ * fscrypt_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)
+int fscrypt_fname_alloc_buffer(struct inode *inode,
+                               u32 ilen, struct fscrypt_str *crypto_str)
 {
-       unsigned int olen;
-       int padding = 16;
-       struct f2fs_crypt_info *ci = F2FS_I(inode)->i_crypt_info;
+       unsigned int olen = fscrypt_fname_encrypted_size(inode, ilen);
 
-       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 */
+       if (olen < FS_FNAME_CRYPTO_DIGEST_SIZE * 2)
+               olen = FS_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;
 }
+EXPORT_SYMBOL(fscrypt_fname_alloc_buffer);
 
 /**
- * f2fs_fname_crypto_free_buffer() -
+ * fscrypt_fname_crypto_free_buffer() -
  *
  * Frees the buffer allocated for crypto operation.
  */
-void f2fs_fname_crypto_free_buffer(struct f2fs_str *crypto_str)
+void fscrypt_fname_free_buffer(struct fscrypt_str *crypto_str)
 {
        if (!crypto_str)
                return;
        kfree(crypto_str->name);
        crypto_str->name = NULL;
 }
+EXPORT_SYMBOL(fscrypt_fname_free_buffer);
 
 /**
- * f2fs_fname_disk_to_usr() - converts a filename from disk space to user space
+ * fscrypt_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)
+int fscrypt_fname_disk_to_usr(struct inode *inode,
+                       u32 hash, u32 minor_hash,
+                       const struct fscrypt_str *iname,
+                       struct fscrypt_str *oname)
 {
        const struct qstr qname = FSTR_TO_QSTR(iname);
        char buf[24];
        int ret;
 
-       if (is_dot_dotdot(&qname)) {
+       if (fscrypt_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 < FS_CRYPTO_BLOCK_SIZE)
+               return -EUCLEAN;
 
-       if (iname->len <= F2FS_FNAME_CRYPTO_DIGEST_SIZE) {
+       if (inode->i_crypt_info)
+               return fname_decrypt(inode, iname, oname);
+
+       if (iname->len <= FS_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
+               memcpy(buf, &hash, 4);
+               memcpy(buf + 4, &minor_hash, 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;
 }
+EXPORT_SYMBOL(fscrypt_fname_disk_to_usr);
 
 /**
- * f2fs_fname_usr_to_disk() - converts a filename from user space to disk space
+ * fscrypt_fname_usr_to_disk() - converts a filename from user space to disk
+ * space
  */
-int f2fs_fname_usr_to_disk(struct inode *inode,
+int fscrypt_fname_usr_to_disk(struct inode *inode,
                        const struct qstr *iname,
-                       struct f2fs_str *oname)
+                       struct fscrypt_str *oname)
 {
-       int res;
-       struct f2fs_crypt_info *ci = F2FS_I(inode)->i_crypt_info;
-
-       if (is_dot_dotdot(iname)) {
+       if (fscrypt_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
+       if (inode->i_crypt_info)
+               return fname_encrypt(inode, iname, oname);
+       /*
+        * 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 */
+        * a disk-space name
+        */
        return -EACCES;
 }
+EXPORT_SYMBOL(fscrypt_fname_usr_to_disk);
 
-int f2fs_fname_setup_filename(struct inode *dir, const struct qstr *iname,
-                             int lookup, struct f2fs_filename *fname)
+int fscrypt_setup_filename(struct inode *dir, const struct qstr *iname,
+                             int lookup, struct fscrypt_name *fname)
 {
-       struct f2fs_crypt_info *ci;
        int ret = 0, bigname = 0;
 
-       memset(fname, 0, sizeof(struct f2fs_filename));
+       memset(fname, 0, sizeof(struct fscrypt_name));
        fname->usr_fname = iname;
 
-       if (!f2fs_encrypted_inode(dir) || is_dot_dotdot(iname)) {
+       if (!dir->i_sb->s_cop->is_encrypted(dir) ||
+                               fscrypt_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)
+       ret = get_crypt_info(dir);
+       if (ret && ret != -EOPNOTSUPP)
                return ret;
-       ci = F2FS_I(dir)->i_crypt_info;
-       if (ci) {
-               ret = f2fs_fname_crypto_alloc_buffer(dir, iname->len,
-                                                    &fname->crypto_buf);
+
+       if (dir->i_crypt_info) {
+               ret = fscrypt_fname_alloc_buffer(dir, iname->len,
+                                                       &fname->crypto_buf);
                if (ret < 0)
                        return ret;
-               ret = f2fs_fname_encrypt(dir, iname, &fname->crypto_buf);
+               ret = fname_encrypt(dir, iname, &fname->crypto_buf);
                if (ret < 0)
                        goto errout;
                fname->disk_name.name = fname->crypto_buf.name;
@@ -398,18 +379,19 @@ int f2fs_fname_setup_filename(struct inode *dir, const struct qstr *iname,
        if (!lookup)
                return -EACCES;
 
-       /* We don't have the key and we are doing a lookup; decode the
+       /*
+        * 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)))
+       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) {
@@ -419,20 +401,24 @@ int f2fs_fname_setup_filename(struct inode *dir, const struct qstr *iname,
        fname->crypto_buf.len = ret;
        if (bigname) {
                memcpy(&fname->hash, fname->crypto_buf.name, 4);
+               memcpy(&fname->minor_hash, fname->crypto_buf.name + 4, 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);
+       fscrypt_fname_free_buffer(&fname->crypto_buf);
        return ret;
 }
+EXPORT_SYMBOL(fscrypt_setup_filename);
 
-void f2fs_fname_free_filename(struct f2fs_filename *fname)
+void fscrypt_free_filename(struct fscrypt_name *fname)
 {
        kfree(fname->crypto_buf.name);
        fname->crypto_buf.name = NULL;
        fname->usr_fname = NULL;
        fname->disk_name.name = NULL;
 }
+EXPORT_SYMBOL(fscrypt_free_filename);
diff --git a/fs/crypto/keyinfo.c b/fs/crypto/keyinfo.c
new file mode 100644 (file)
index 0000000..06f5aa4
--- /dev/null
@@ -0,0 +1,272 @@
+/*
+ * key management facility for FS encryption support.
+ *
+ * Copyright (C) 2015, Google, Inc.
+ *
+ * This contains encryption key functions.
+ *
+ * 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 <linux/fscrypto.h>
+
+static void derive_crypt_complete(struct crypto_async_request *req, int rc)
+{
+       struct fscrypt_completion_result *ecr = req->data;
+
+       if (rc == -EINPROGRESS)
+               return;
+
+       ecr->res = rc;
+       complete(&ecr->completion);
+}
+
+/**
+ * derive_key_aes() - Derive a key using AES-128-ECB
+ * @deriving_key: Encryption key used for derivation.
+ * @source_key:   Source key to which to apply derivation.
+ * @derived_key:  Derived key.
+ *
+ * Return: Zero on success; non-zero otherwise.
+ */
+static int derive_key_aes(u8 deriving_key[FS_AES_128_ECB_KEY_SIZE],
+                               u8 source_key[FS_AES_256_XTS_KEY_SIZE],
+                               u8 derived_key[FS_AES_256_XTS_KEY_SIZE])
+{
+       int res = 0;
+       struct skcipher_request *req = NULL;
+       DECLARE_FS_COMPLETION_RESULT(ecr);
+       struct scatterlist src_sg, dst_sg;
+       struct crypto_skcipher *tfm = crypto_alloc_skcipher("ecb(aes)", 0, 0);
+
+       if (IS_ERR(tfm)) {
+               res = PTR_ERR(tfm);
+               tfm = NULL;
+               goto out;
+       }
+       crypto_skcipher_set_flags(tfm, CRYPTO_TFM_REQ_WEAK_KEY);
+       req = skcipher_request_alloc(tfm, GFP_NOFS);
+       if (!req) {
+               res = -ENOMEM;
+               goto out;
+       }
+       skcipher_request_set_callback(req,
+                       CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP,
+                       derive_crypt_complete, &ecr);
+       res = crypto_skcipher_setkey(tfm, deriving_key,
+                                       FS_AES_128_ECB_KEY_SIZE);
+       if (res < 0)
+               goto out;
+
+       sg_init_one(&src_sg, source_key, FS_AES_256_XTS_KEY_SIZE);
+       sg_init_one(&dst_sg, derived_key, FS_AES_256_XTS_KEY_SIZE);
+       skcipher_request_set_crypt(req, &src_sg, &dst_sg,
+                                       FS_AES_256_XTS_KEY_SIZE, NULL);
+       res = crypto_skcipher_encrypt(req);
+       if (res == -EINPROGRESS || res == -EBUSY) {
+               wait_for_completion(&ecr.completion);
+               res = ecr.res;
+       }
+out:
+       skcipher_request_free(req);
+       crypto_free_skcipher(tfm);
+       return res;
+}
+
+static void put_crypt_info(struct fscrypt_info *ci)
+{
+       if (!ci)
+               return;
+
+       key_put(ci->ci_keyring_key);
+       crypto_free_skcipher(ci->ci_ctfm);
+       kmem_cache_free(fscrypt_info_cachep, ci);
+}
+
+int get_crypt_info(struct inode *inode)
+{
+       struct fscrypt_info *crypt_info;
+       u8 full_key_descriptor[FS_KEY_DESC_PREFIX_SIZE +
+                               (FS_KEY_DESCRIPTOR_SIZE * 2) + 1];
+       struct key *keyring_key = NULL;
+       struct fscrypt_key *master_key;
+       struct fscrypt_context ctx;
+       const struct user_key_payload *ukp;
+       struct crypto_skcipher *ctfm;
+       const char *cipher_str;
+       u8 raw_key[FS_MAX_KEY_SIZE];
+       u8 mode;
+       int res;
+
+       res = fscrypt_initialize();
+       if (res)
+               return res;
+
+       if (!inode->i_sb->s_cop->get_context)
+               return -EOPNOTSUPP;
+retry:
+       crypt_info = ACCESS_ONCE(inode->i_crypt_info);
+       if (crypt_info) {
+               if (!crypt_info->ci_keyring_key ||
+                               key_validate(crypt_info->ci_keyring_key) == 0)
+                       return 0;
+               fscrypt_put_encryption_info(inode, crypt_info);
+               goto retry;
+       }
+
+       res = inode->i_sb->s_cop->get_context(inode, &ctx, sizeof(ctx));
+       if (res < 0) {
+               if (!fscrypt_dummy_context_enabled(inode))
+                       return res;
+               ctx.contents_encryption_mode = FS_ENCRYPTION_MODE_AES_256_XTS;
+               ctx.filenames_encryption_mode = FS_ENCRYPTION_MODE_AES_256_CTS;
+               ctx.flags = 0;
+       } else if (res != sizeof(ctx)) {
+               return -EINVAL;
+       }
+       res = 0;
+
+       crypt_info = kmem_cache_alloc(fscrypt_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 FS_ENCRYPTION_MODE_AES_256_XTS:
+               cipher_str = "xts(aes)";
+               break;
+       case FS_ENCRYPTION_MODE_AES_256_CTS:
+               cipher_str = "cts(cbc(aes))";
+               break;
+       default:
+               printk_once(KERN_WARNING
+                           "%s: unsupported key mode %d (ino %u)\n",
+                           __func__, mode, (unsigned) inode->i_ino);
+               res = -ENOKEY;
+               goto out;
+       }
+       if (fscrypt_dummy_context_enabled(inode)) {
+               memset(raw_key, 0x42, FS_AES_256_XTS_KEY_SIZE);
+               goto got_key;
+       }
+       memcpy(full_key_descriptor, FS_KEY_DESC_PREFIX,
+                                       FS_KEY_DESC_PREFIX_SIZE);
+       sprintf(full_key_descriptor + FS_KEY_DESC_PREFIX_SIZE,
+                                       "%*phN", FS_KEY_DESCRIPTOR_SIZE,
+                                       ctx.master_key_descriptor);
+       full_key_descriptor[FS_KEY_DESC_PREFIX_SIZE +
+                                       (2 * FS_KEY_DESCRIPTOR_SIZE)] = '\0';
+       keyring_key = request_key(&key_type_logon, full_key_descriptor, NULL);
+       if (IS_ERR(keyring_key)) {
+               res = PTR_ERR(keyring_key);
+               keyring_key = NULL;
+               goto out;
+       }
+       crypt_info->ci_keyring_key = keyring_key;
+       if (keyring_key->type != &key_type_logon) {
+               printk_once(KERN_WARNING
+                               "%s: key type must be logon\n", __func__);
+               res = -ENOKEY;
+               goto out;
+       }
+       down_read(&keyring_key->sem);
+       ukp = user_key_payload(keyring_key);
+       if (ukp->datalen != sizeof(struct fscrypt_key)) {
+               res = -EINVAL;
+               up_read(&keyring_key->sem);
+               goto out;
+       }
+       master_key = (struct fscrypt_key *)ukp->data;
+       BUILD_BUG_ON(FS_AES_128_ECB_KEY_SIZE != FS_KEY_DERIVATION_NONCE_SIZE);
+
+       if (master_key->size != FS_AES_256_XTS_KEY_SIZE) {
+               printk_once(KERN_WARNING
+                               "%s: key size incorrect: %d\n",
+                               __func__, master_key->size);
+               res = -ENOKEY;
+               up_read(&keyring_key->sem);
+               goto out;
+       }
+       res = derive_key_aes(ctx.nonce, master_key->raw, raw_key);
+       up_read(&keyring_key->sem);
+       if (res)
+               goto out;
+got_key:
+       ctfm = crypto_alloc_skcipher(cipher_str, 0, 0);
+       if (!ctfm || IS_ERR(ctfm)) {
+               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_skcipher_clear_flags(ctfm, ~0);
+       crypto_skcipher_set_flags(ctfm, CRYPTO_TFM_REQ_WEAK_KEY);
+       res = crypto_skcipher_setkey(ctfm, raw_key, fscrypt_key_size(mode));
+       if (res)
+               goto out;
+
+       memzero_explicit(raw_key, sizeof(raw_key));
+       if (cmpxchg(&inode->i_crypt_info, NULL, crypt_info) != NULL) {
+               put_crypt_info(crypt_info);
+               goto retry;
+       }
+       return 0;
+
+out:
+       if (res == -ENOKEY)
+               res = 0;
+       put_crypt_info(crypt_info);
+       memzero_explicit(raw_key, sizeof(raw_key));
+       return res;
+}
+
+void fscrypt_put_encryption_info(struct inode *inode, struct fscrypt_info *ci)
+{
+       struct fscrypt_info *prev;
+
+       if (ci == NULL)
+               ci = ACCESS_ONCE(inode->i_crypt_info);
+       if (ci == NULL)
+               return;
+
+       prev = cmpxchg(&inode->i_crypt_info, ci, NULL);
+       if (prev != ci)
+               return;
+
+       put_crypt_info(ci);
+}
+EXPORT_SYMBOL(fscrypt_put_encryption_info);
+
+int fscrypt_get_encryption_info(struct inode *inode)
+{
+       struct fscrypt_info *ci = 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 get_crypt_info(inode);
+       return 0;
+}
+EXPORT_SYMBOL(fscrypt_get_encryption_info);
diff --git a/fs/crypto/policy.c b/fs/crypto/policy.c
new file mode 100644 (file)
index 0000000..0f9961e
--- /dev/null
@@ -0,0 +1,229 @@
+/*
+ * Encryption policy functions for per-file encryption support.
+ *
+ * Copyright (C) 2015, Google, Inc.
+ * Copyright (C) 2015, Motorola Mobility.
+ *
+ * Written by Michael Halcrow, 2015.
+ * Modified by Jaegeuk Kim, 2015.
+ */
+
+#include <linux/random.h>
+#include <linux/string.h>
+#include <linux/fscrypto.h>
+
+static int inode_has_encryption_context(struct inode *inode)
+{
+       if (!inode->i_sb->s_cop->get_context)
+               return 0;
+       return (inode->i_sb->s_cop->get_context(inode, NULL, 0L) > 0);
+}
+
+/*
+ * check whether the policy is consistent with the encryption context
+ * for the inode
+ */
+static int is_encryption_context_consistent_with_policy(struct inode *inode,
+                               const struct fscrypt_policy *policy)
+{
+       struct fscrypt_context ctx;
+       int res;
+
+       if (!inode->i_sb->s_cop->get_context)
+               return 0;
+
+       res = inode->i_sb->s_cop->get_context(inode, &ctx, sizeof(ctx));
+       if (res != sizeof(ctx))
+               return 0;
+
+       return (memcmp(ctx.master_key_descriptor, policy->master_key_descriptor,
+                       FS_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 create_encryption_context_from_policy(struct inode *inode,
+                               const struct fscrypt_policy *policy)
+{
+       struct fscrypt_context ctx;
+       int res;
+
+       if (!inode->i_sb->s_cop->set_context)
+               return -EOPNOTSUPP;
+
+       if (inode->i_sb->s_cop->prepare_context) {
+               res = inode->i_sb->s_cop->prepare_context(inode);
+               if (res)
+                       return res;
+       }
+
+       ctx.format = FS_ENCRYPTION_CONTEXT_FORMAT_V1;
+       memcpy(ctx.master_key_descriptor, policy->master_key_descriptor,
+                                       FS_KEY_DESCRIPTOR_SIZE);
+
+       if (!fscrypt_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 (!fscrypt_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 & ~FS_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) != FS_KEY_DERIVATION_NONCE_SIZE);
+       get_random_bytes(ctx.nonce, FS_KEY_DERIVATION_NONCE_SIZE);
+
+       return inode->i_sb->s_cop->set_context(inode, &ctx, sizeof(ctx), NULL);
+}
+
+int fscrypt_process_policy(struct inode *inode,
+                               const struct fscrypt_policy *policy)
+{
+       if (policy->version != 0)
+               return -EINVAL;
+
+       if (!inode_has_encryption_context(inode)) {
+               if (!inode->i_sb->s_cop->empty_dir)
+                       return -EOPNOTSUPP;
+               if (!inode->i_sb->s_cop->empty_dir(inode))
+                       return -ENOTEMPTY;
+               return create_encryption_context_from_policy(inode, policy);
+       }
+
+       if (is_encryption_context_consistent_with_policy(inode, policy))
+               return 0;
+
+       printk(KERN_WARNING "%s: Policy inconsistent with encryption context\n",
+              __func__);
+       return -EINVAL;
+}
+EXPORT_SYMBOL(fscrypt_process_policy);
+
+int fscrypt_get_policy(struct inode *inode, struct fscrypt_policy *policy)
+{
+       struct fscrypt_context ctx;
+       int res;
+
+       if (!inode->i_sb->s_cop->get_context ||
+                       !inode->i_sb->s_cop->is_encrypted(inode))
+               return -ENODATA;
+
+       res = inode->i_sb->s_cop->get_context(inode, &ctx, sizeof(ctx));
+       if (res != sizeof(ctx))
+               return -ENODATA;
+       if (ctx.format != FS_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,
+                               FS_KEY_DESCRIPTOR_SIZE);
+       return 0;
+}
+EXPORT_SYMBOL(fscrypt_get_policy);
+
+int fscrypt_has_permitted_context(struct inode *parent, struct inode *child)
+{
+       struct fscrypt_info *parent_ci, *child_ci;
+       int res;
+
+       if ((parent == NULL) || (child == NULL)) {
+               printk(KERN_ERR "parent %p child %p\n", parent, child);
+               BUG_ON(1);
+       }
+
+       /* no restrictions if the parent directory is not encrypted */
+       if (!parent->i_sb->s_cop->is_encrypted(parent))
+               return 1;
+       /* if the child directory is not encrypted, this is always a problem */
+       if (!parent->i_sb->s_cop->is_encrypted(child))
+               return 0;
+       res = fscrypt_get_encryption_info(parent);
+       if (res)
+               return 0;
+       res = fscrypt_get_encryption_info(child);
+       if (res)
+               return 0;
+       parent_ci = parent->i_crypt_info;
+       child_ci = 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,
+                       FS_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));
+}
+EXPORT_SYMBOL(fscrypt_has_permitted_context);
+
+/**
+ * fscrypt_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.
+ * @fs_data:  private data given by FS.
+ * @preload:  preload child i_crypt_info
+ *
+ * Return: Zero on success, non-zero otherwise
+ */
+int fscrypt_inherit_context(struct inode *parent, struct inode *child,
+                                               void *fs_data, bool preload)
+{
+       struct fscrypt_context ctx;
+       struct fscrypt_info *ci;
+       int res;
+
+       if (!parent->i_sb->s_cop->set_context)
+               return -EOPNOTSUPP;
+
+       res = fscrypt_get_encryption_info(parent);
+       if (res < 0)
+               return res;
+
+       ci = parent->i_crypt_info;
+       if (ci == NULL)
+               return -ENOKEY;
+
+       ctx.format = FS_ENCRYPTION_CONTEXT_FORMAT_V1;
+       if (fscrypt_dummy_context_enabled(parent)) {
+               ctx.contents_encryption_mode = FS_ENCRYPTION_MODE_AES_256_XTS;
+               ctx.filenames_encryption_mode = FS_ENCRYPTION_MODE_AES_256_CTS;
+               ctx.flags = 0;
+               memset(ctx.master_key_descriptor, 0x42, FS_KEY_DESCRIPTOR_SIZE);
+               res = 0;
+       } else {
+               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,
+                               FS_KEY_DESCRIPTOR_SIZE);
+       }
+       get_random_bytes(ctx.nonce, FS_KEY_DERIVATION_NONCE_SIZE);
+       res = parent->i_sb->s_cop->set_context(child, &ctx,
+                                               sizeof(ctx), fs_data);
+       if (res)
+               return res;
+       return preload ? fscrypt_get_encryption_info(child): 0;
+}
+EXPORT_SYMBOL(fscrypt_inherit_context);
index b0a9dc9..1f8982a 100644 (file)
@@ -1,6 +1,8 @@
 config F2FS_FS
        tristate "F2FS filesystem support"
        depends on BLOCK
+       select CRYPTO
+       select CRYPTO_CRC32
        help
          F2FS is based on Log-structured File System (LFS), which supports
          versatile "flash-friendly" features. The design has been focused on
@@ -76,15 +78,7 @@ 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
+       select FS_ENCRYPTION
        help
          Enable encryption of f2fs files and directories.  This
          feature is similar to ecryptfs, but it is more memory
index 08e101e..ca949ea 100644 (file)
@@ -7,5 +7,3 @@ 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
index 3842af9..0955312 100644 (file)
@@ -39,7 +39,7 @@ repeat:
                cond_resched();
                goto repeat;
        }
-       f2fs_wait_on_page_writeback(page, META);
+       f2fs_wait_on_page_writeback(page, META, true);
        SetPageUptodate(page);
        return page;
 }
@@ -56,7 +56,8 @@ static struct page *__get_meta_page(struct f2fs_sb_info *sbi, pgoff_t index,
                .sbi = sbi,
                .type = META,
                .rw = READ_SYNC | REQ_META | REQ_PRIO,
-               .blk_addr = index,
+               .old_blkaddr = index,
+               .new_blkaddr = index,
                .encrypted_page = NULL,
        };
 
@@ -143,7 +144,6 @@ bool is_valid_blkaddr(struct f2fs_sb_info *sbi, block_t blkaddr, int type)
 int ra_meta_pages(struct f2fs_sb_info *sbi, block_t start, int nrpages,
                                                        int type, bool sync)
 {
-       block_t prev_blk_addr = 0;
        struct page *page;
        block_t blkno = start;
        struct f2fs_io_info fio = {
@@ -152,10 +152,12 @@ int ra_meta_pages(struct f2fs_sb_info *sbi, block_t start, int nrpages,
                .rw = sync ? (READ_SYNC | REQ_META | REQ_PRIO) : READA,
                .encrypted_page = NULL,
        };
+       struct blk_plug plug;
 
        if (unlikely(type == META_POR))
                fio.rw &= ~REQ_META;
 
+       blk_start_plug(&plug);
        for (; nrpages-- > 0; blkno++) {
 
                if (!is_valid_blkaddr(sbi, blkno, type))
@@ -167,27 +169,24 @@ int ra_meta_pages(struct f2fs_sb_info *sbi, block_t start, int nrpages,
                                        NAT_BLOCK_OFFSET(NM_I(sbi)->max_nid)))
                                blkno = 0;
                        /* get nat block addr */
-                       fio.blk_addr = current_nat_addr(sbi,
+                       fio.new_blkaddr = current_nat_addr(sbi,
                                        blkno * NAT_ENTRY_PER_BLOCK);
                        break;
                case META_SIT:
                        /* get sit block addr */
-                       fio.blk_addr = current_sit_addr(sbi,
+                       fio.new_blkaddr = current_sit_addr(sbi,
                                        blkno * SIT_ENTRY_PER_BLOCK);
-                       if (blkno != start && prev_blk_addr + 1 != fio.blk_addr)
-                               goto out;
-                       prev_blk_addr = fio.blk_addr;
                        break;
                case META_SSA:
                case META_CP:
                case META_POR:
-                       fio.blk_addr = blkno;
+                       fio.new_blkaddr = blkno;
                        break;
                default:
                        BUG();
                }
 
-               page = grab_cache_page(META_MAPPING(sbi), fio.blk_addr);
+               page = grab_cache_page(META_MAPPING(sbi), fio.new_blkaddr);
                if (!page)
                        continue;
                if (PageUptodate(page)) {
@@ -196,11 +195,13 @@ int ra_meta_pages(struct f2fs_sb_info *sbi, block_t start, int nrpages,
                }
 
                fio.page = page;
+               fio.old_blkaddr = fio.new_blkaddr;
                f2fs_submit_page_mbio(&fio);
                f2fs_put_page(page, 0);
        }
 out:
        f2fs_submit_merged_bio(sbi, META, READ);
+       blk_finish_plug(&plug);
        return blkno - start;
 }
 
@@ -232,13 +233,17 @@ static int f2fs_write_meta_page(struct page *page,
        if (unlikely(f2fs_cp_error(sbi)))
                goto redirty_out;
 
-       f2fs_wait_on_page_writeback(page, META);
        write_meta_page(sbi, page);
        dec_page_count(sbi, F2FS_DIRTY_META);
+
+       if (wbc->for_reclaim)
+               f2fs_submit_merged_bio_cond(sbi, NULL, page, 0, META, WRITE);
+
        unlock_page(page);
 
-       if (wbc->for_reclaim || unlikely(f2fs_cp_error(sbi)))
+       if (unlikely(f2fs_cp_error(sbi)))
                f2fs_submit_merged_bio(sbi, META, WRITE);
+
        return 0;
 
 redirty_out:
@@ -252,13 +257,13 @@ static int f2fs_write_meta_pages(struct address_space *mapping,
        struct f2fs_sb_info *sbi = F2FS_M_SB(mapping);
        long diff, written;
 
-       trace_f2fs_writepages(mapping->host, wbc, META);
-
        /* collect a number of dirty meta pages and write together */
        if (wbc->for_kupdate ||
                get_pages(sbi, F2FS_DIRTY_META) < nr_pages_to_skip(sbi, META))
                goto skip_write;
 
+       trace_f2fs_writepages(mapping->host, wbc, META);
+
        /* if mounting is failed, skip writing node pages */
        mutex_lock(&sbi->cp_mutex);
        diff = nr_pages_to_write(sbi, META, wbc);
@@ -269,6 +274,7 @@ static int f2fs_write_meta_pages(struct address_space *mapping,
 
 skip_write:
        wbc->pages_skipped += get_pages(sbi, F2FS_DIRTY_META);
+       trace_f2fs_writepages(mapping->host, wbc, META);
        return 0;
 }
 
@@ -276,15 +282,18 @@ long sync_meta_pages(struct f2fs_sb_info *sbi, enum page_type type,
                                                long nr_to_write)
 {
        struct address_space *mapping = META_MAPPING(sbi);
-       pgoff_t index = 0, end = LONG_MAX, prev = LONG_MAX;
+       pgoff_t index = 0, end = ULONG_MAX, prev = ULONG_MAX;
        struct pagevec pvec;
        long nwritten = 0;
        struct writeback_control wbc = {
                .for_reclaim = 0,
        };
+       struct blk_plug plug;
 
        pagevec_init(&pvec, 0);
 
+       blk_start_plug(&plug);
+
        while (index <= end) {
                int i, nr_pages;
                nr_pages = pagevec_lookup_tag(&pvec, mapping, &index,
@@ -296,7 +305,7 @@ long sync_meta_pages(struct f2fs_sb_info *sbi, enum page_type type,
                for (i = 0; i < nr_pages; i++) {
                        struct page *page = pvec.pages[i];
 
-                       if (prev == LONG_MAX)
+                       if (prev == ULONG_MAX)
                                prev = page->index - 1;
                        if (nr_to_write != LONG_MAX && page->index != prev + 1) {
                                pagevec_release(&pvec);
@@ -315,6 +324,9 @@ continue_unlock:
                                goto continue_unlock;
                        }
 
+                       f2fs_wait_on_page_writeback(page, META, true);
+
+                       BUG_ON(PageWriteback(page));
                        if (!clear_page_dirty_for_io(page))
                                goto continue_unlock;
 
@@ -334,6 +346,8 @@ stop:
        if (nwritten)
                f2fs_submit_merged_bio(sbi, type, WRITE);
 
+       blk_finish_plug(&plug);
+
        return nwritten;
 }
 
@@ -621,7 +635,7 @@ static struct page *validate_checkpoint(struct f2fs_sb_info *sbi,
                goto invalid_cp1;
 
        crc = le32_to_cpu(*((__le32 *)((unsigned char *)cp_block + crc_offset)));
-       if (!f2fs_crc_valid(crc, cp_block, crc_offset))
+       if (!f2fs_crc_valid(sbi, crc, cp_block, crc_offset))
                goto invalid_cp1;
 
        pre_version = cur_cp_version(cp_block);
@@ -636,7 +650,7 @@ static struct page *validate_checkpoint(struct f2fs_sb_info *sbi,
                goto invalid_cp2;
 
        crc = le32_to_cpu(*((__le32 *)((unsigned char *)cp_block + crc_offset)));
-       if (!f2fs_crc_valid(crc, cp_block, crc_offset))
+       if (!f2fs_crc_valid(sbi, crc, cp_block, crc_offset))
                goto invalid_cp2;
 
        cur_version = cur_cp_version(cp_block);
@@ -696,6 +710,10 @@ int get_valid_checkpoint(struct f2fs_sb_info *sbi)
        cp_block = (struct f2fs_checkpoint *)page_address(cur_page);
        memcpy(sbi->ckpt, cp_block, blk_size);
 
+       /* Sanity checking of checkpoint */
+       if (sanity_check_ckpt(sbi))
+               goto fail_no_cp;
+
        if (cp_blks <= 1)
                goto done;
 
@@ -902,7 +920,7 @@ static void wait_on_all_pages_writeback(struct f2fs_sb_info *sbi)
                if (!get_pages(sbi, F2FS_WRITEBACK))
                        break;
 
-               io_schedule();
+               io_schedule_timeout(5*HZ);
        }
        finish_wait(&sbi->cp_wait, &wait);
 }
@@ -921,6 +939,9 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
        int cp_payload_blks = __cp_payload(sbi);
        block_t discard_blk = NEXT_FREE_BLKADDR(sbi, curseg);
        bool invalidate = false;
+       struct super_block *sb = sbi->sb;
+       struct curseg_info *seg_i = CURSEG_I(sbi, CURSEG_HOT_NODE);
+       u64 kbytes_written;
 
        /*
         * This avoids to conduct wrong roll-forward operations and uses
@@ -1008,7 +1029,7 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
        get_sit_bitmap(sbi, __bitmap_ptr(sbi, SIT_BITMAP));
        get_nat_bitmap(sbi, __bitmap_ptr(sbi, NAT_BITMAP));
 
-       crc32 = f2fs_crc32(ckpt, le32_to_cpu(ckpt->checksum_offset));
+       crc32 = f2fs_crc32(sbi, ckpt, le32_to_cpu(ckpt->checksum_offset));
        *((__le32 *)((unsigned char *)ckpt +
                                le32_to_cpu(ckpt->checksum_offset)))
                                = cpu_to_le32(crc32);
@@ -1034,6 +1055,14 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
 
        write_data_summaries(sbi, start_blk);
        start_blk += data_sum_blocks;
+
+       /* Record write statistics in the hot node summary */
+       kbytes_written = sbi->kbytes_written;
+       if (sb->s_bdev->bd_part)
+               kbytes_written += BD_PART_WRITTEN(sbi);
+
+       seg_i->journal->info.kbytes_written = cpu_to_le64(kbytes_written);
+
        if (__remain_node_summaries(cpc->reason)) {
                write_node_summaries(sbi, start_blk);
                start_blk += NR_CURSEG_NODE_TYPE;
@@ -1048,8 +1077,8 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
        if (unlikely(f2fs_cp_error(sbi)))
                return -EIO;
 
-       filemap_fdatawait_range(NODE_MAPPING(sbi), 0, LONG_MAX);
-       filemap_fdatawait_range(META_MAPPING(sbi), 0, LONG_MAX);
+       filemap_fdatawait_range(NODE_MAPPING(sbi), 0, LLONG_MAX);
+       filemap_fdatawait_range(META_MAPPING(sbi), 0, LLONG_MAX);
 
        /* update user_block_counts */
        sbi->last_valid_block_count = sbi->total_valid_block_count;
@@ -1112,9 +1141,7 @@ int write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
 
        trace_f2fs_write_checkpoint(sbi->sb, cpc->reason, "finish block_ops");
 
-       f2fs_submit_merged_bio(sbi, DATA, WRITE);
-       f2fs_submit_merged_bio(sbi, NODE, WRITE);
-       f2fs_submit_merged_bio(sbi, META, WRITE);
+       f2fs_flush_merged_bios(sbi);
 
        /*
         * update checkpoint pack index
diff --git a/fs/f2fs/crypto.c b/fs/f2fs/crypto.c
deleted file mode 100644 (file)
index 95c5cf0..0000000
+++ /dev/null
@@ -1,489 +0,0 @@
-/*
- * 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/skcipher.h>
-#include <keys/user-type.h>
-#include <keys/encrypted-type.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 skcipher_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_skcipher *tfm = ci->ci_ctfm;
-       int res = 0;
-
-       req = skcipher_request_alloc(tfm, GFP_NOFS);
-       if (!req) {
-               printk_ratelimited(KERN_ERR
-                               "%s: crypto_request_alloc() failed\n",
-                               __func__);
-               return -ENOMEM;
-       }
-       skcipher_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);
-       skcipher_request_set_crypt(req, &src, &dst, PAGE_CACHE_SIZE,
-                                  xts_tweak);
-       if (rw == F2FS_DECRYPT)
-               res = crypto_skcipher_decrypt(req);
-       else
-               res = crypto_skcipher_encrypt(req);
-       if (res == -EINPROGRESS || res == -EBUSY) {
-               BUG_ON(req->base.data != &ecr);
-               wait_for_completion(&ecr.completion);
-               res = ecr.res;
-       }
-       skcipher_request_free(req);
-       if (res) {
-               printk_ratelimited(KERN_ERR
-                       "%s: crypto_skcipher_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;
-}
diff --git a/fs/f2fs/crypto_key.c b/fs/f2fs/crypto_key.c
deleted file mode 100644 (file)
index 2aeb627..0000000
+++ /dev/null
@@ -1,250 +0,0 @@
-/*
- * 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/skcipher.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 skcipher_request *req = NULL;
-       DECLARE_F2FS_COMPLETION_RESULT(ecr);
-       struct scatterlist src_sg, dst_sg;
-       struct crypto_skcipher *tfm = crypto_alloc_skcipher("ecb(aes)", 0, 0);
-
-       if (IS_ERR(tfm)) {
-               res = PTR_ERR(tfm);
-               tfm = NULL;
-               goto out;
-       }
-       crypto_skcipher_set_flags(tfm, CRYPTO_TFM_REQ_WEAK_KEY);
-       req = skcipher_request_alloc(tfm, GFP_NOFS);
-       if (!req) {
-               res = -ENOMEM;
-               goto out;
-       }
-       skcipher_request_set_callback(req,
-                       CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP,
-                       derive_crypt_complete, &ecr);
-       res = crypto_skcipher_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);
-       skcipher_request_set_crypt(req, &src_sg, &dst_sg,
-                                       F2FS_AES_256_XTS_KEY_SIZE, NULL);
-       res = crypto_skcipher_encrypt(req);
-       if (res == -EINPROGRESS || res == -EBUSY) {
-               BUG_ON(req->base.data != &ecr);
-               wait_for_completion(&ecr.completion);
-               res = ecr.res;
-       }
-out:
-       skcipher_request_free(req);
-       crypto_free_skcipher(tfm);
-       return res;
-}
-
-static void f2fs_free_crypt_info(struct f2fs_crypt_info *ci)
-{
-       if (!ci)
-               return;
-
-       key_put(ci->ci_keyring_key);
-       crypto_free_skcipher(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;
-       const struct user_key_payload *ukp;
-       struct crypto_skcipher *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 = user_key_payload(keyring_key);
-       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_skcipher(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_skcipher_clear_flags(ctfm, ~0);
-       crypto_skcipher_set_flags(ctfm, CRYPTO_TFM_REQ_WEAK_KEY);
-       res = crypto_skcipher_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);
-}
diff --git a/fs/f2fs/crypto_policy.c b/fs/f2fs/crypto_policy.c
deleted file mode 100644 (file)
index d4a96af..0000000
+++ /dev/null
@@ -1,209 +0,0 @@
-/*
- * 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);
-}
index 5c06db1..e5c762b 100644 (file)
@@ -34,9 +34,9 @@ static void f2fs_read_end_io(struct bio *bio)
 
        if (f2fs_bio_encrypted(bio)) {
                if (bio->bi_error) {
-                       f2fs_release_crypto_ctx(bio->bi_private);
+                       fscrypt_release_ctx(bio->bi_private);
                } else {
-                       f2fs_end_io_crypto_work(bio->bi_private, bio);
+                       fscrypt_decrypt_bio_pages(bio->bi_private, bio);
                        return;
                }
        }
@@ -64,10 +64,9 @@ static void f2fs_write_end_io(struct bio *bio)
        bio_for_each_segment_all(bvec, bio, i) {
                struct page *page = bvec->bv_page;
 
-               f2fs_restore_and_release_control_page(&page);
+               fscrypt_pullback_bio_page(&page, true);
 
                if (unlikely(bio->bi_error)) {
-                       set_page_dirty(page);
                        set_bit(AS_EIO, &page->mapping->flags);
                        f2fs_stop_checkpoint(sbi);
                }
@@ -75,8 +74,7 @@ static void f2fs_write_end_io(struct bio *bio)
                dec_page_count(sbi, F2FS_WRITEBACK);
        }
 
-       if (!get_pages(sbi, F2FS_WRITEBACK) &&
-                       !list_empty(&sbi->cp_wait.task_list))
+       if (!get_pages(sbi, F2FS_WRITEBACK) && wq_has_sleeper(&sbi->cp_wait))
                wake_up(&sbi->cp_wait);
 
        bio_put(bio);
@@ -116,8 +114,54 @@ static void __submit_merged_bio(struct f2fs_bio_info *io)
        io->bio = NULL;
 }
 
-void f2fs_submit_merged_bio(struct f2fs_sb_info *sbi,
-                               enum page_type type, int rw)
+static bool __has_merged_page(struct f2fs_bio_info *io, struct inode *inode,
+                                               struct page *page, nid_t ino)
+{
+       struct bio_vec *bvec;
+       struct page *target;
+       int i;
+
+       if (!io->bio)
+               return false;
+
+       if (!inode && !page && !ino)
+               return true;
+
+       bio_for_each_segment_all(bvec, io->bio, i) {
+
+               if (bvec->bv_page->mapping)
+                       target = bvec->bv_page;
+               else
+                       target = fscrypt_control_page(bvec->bv_page);
+
+               if (inode && inode == target->mapping->host)
+                       return true;
+               if (page && page == target)
+                       return true;
+               if (ino && ino == ino_of_node(target))
+                       return true;
+       }
+
+       return false;
+}
+
+static bool has_merged_page(struct f2fs_sb_info *sbi, struct inode *inode,
+                                               struct page *page, nid_t ino,
+                                               enum page_type type)
+{
+       enum page_type btype = PAGE_TYPE_OF_BIO(type);
+       struct f2fs_bio_info *io = &sbi->write_io[btype];
+       bool ret;
+
+       down_read(&io->io_rwsem);
+       ret = __has_merged_page(io, inode, page, ino);
+       up_read(&io->io_rwsem);
+       return ret;
+}
+
+static void __f2fs_submit_merged_bio(struct f2fs_sb_info *sbi,
+                               struct inode *inode, struct page *page,
+                               nid_t ino, enum page_type type, int rw)
 {
        enum page_type btype = PAGE_TYPE_OF_BIO(type);
        struct f2fs_bio_info *io;
@@ -126,6 +170,9 @@ void f2fs_submit_merged_bio(struct f2fs_sb_info *sbi,
 
        down_write(&io->io_rwsem);
 
+       if (!__has_merged_page(io, inode, page, ino))
+               goto out;
+
        /* change META to META_FLUSH in the checkpoint procedure */
        if (type >= META_FLUSH) {
                io->fio.type = META_FLUSH;
@@ -135,9 +182,31 @@ void f2fs_submit_merged_bio(struct f2fs_sb_info *sbi,
                        io->fio.rw = WRITE_FLUSH_FUA | REQ_META | REQ_PRIO;
        }
        __submit_merged_bio(io);
+out:
        up_write(&io->io_rwsem);
 }
 
+void f2fs_submit_merged_bio(struct f2fs_sb_info *sbi, enum page_type type,
+                                                                       int rw)
+{
+       __f2fs_submit_merged_bio(sbi, NULL, NULL, 0, type, rw);
+}
+
+void f2fs_submit_merged_bio_cond(struct f2fs_sb_info *sbi,
+                               struct inode *inode, struct page *page,
+                               nid_t ino, enum page_type type, int rw)
+{
+       if (has_merged_page(sbi, inode, page, ino, type))
+               __f2fs_submit_merged_bio(sbi, inode, page, ino, type, rw);
+}
+
+void f2fs_flush_merged_bios(struct f2fs_sb_info *sbi)
+{
+       f2fs_submit_merged_bio(sbi, DATA, WRITE);
+       f2fs_submit_merged_bio(sbi, NODE, WRITE);
+       f2fs_submit_merged_bio(sbi, META, WRITE);
+}
+
 /*
  * Fill the locked page with data located in the block address.
  * Return unlocked page.
@@ -145,13 +214,14 @@ void f2fs_submit_merged_bio(struct f2fs_sb_info *sbi,
 int f2fs_submit_page_bio(struct f2fs_io_info *fio)
 {
        struct bio *bio;
-       struct page *page = fio->encrypted_page ? fio->encrypted_page : fio->page;
+       struct page *page = fio->encrypted_page ?
+                       fio->encrypted_page : fio->page;
 
        trace_f2fs_submit_page_bio(page, fio);
        f2fs_trace_ios(fio, 0);
 
        /* Allocate a new bio */
-       bio = __bio_alloc(fio->sbi, fio->blk_addr, 1, is_read_io(fio->rw));
+       bio = __bio_alloc(fio->sbi, fio->new_blkaddr, 1, is_read_io(fio->rw));
 
        if (bio_add_page(bio, page, PAGE_CACHE_SIZE, 0) < PAGE_CACHE_SIZE) {
                bio_put(bio);
@@ -172,21 +242,24 @@ void f2fs_submit_page_mbio(struct f2fs_io_info *fio)
 
        io = is_read ? &sbi->read_io : &sbi->write_io[btype];
 
-       verify_block_addr(sbi, fio->blk_addr);
+       if (fio->old_blkaddr != NEW_ADDR)
+               verify_block_addr(sbi, fio->old_blkaddr);
+       verify_block_addr(sbi, fio->new_blkaddr);
 
        down_write(&io->io_rwsem);
 
        if (!is_read)
                inc_page_count(sbi, F2FS_WRITEBACK);
 
-       if (io->bio && (io->last_block_in_bio != fio->blk_addr - 1 ||
+       if (io->bio && (io->last_block_in_bio != fio->new_blkaddr - 1 ||
                                                io->fio.rw != fio->rw))
                __submit_merged_bio(io);
 alloc_new:
        if (io->bio == NULL) {
                int bio_blocks = MAX_BIO_BLOCKS(sbi);
 
-               io->bio = __bio_alloc(sbi, fio->blk_addr, bio_blocks, is_read);
+               io->bio = __bio_alloc(sbi, fio->new_blkaddr,
+                                               bio_blocks, is_read);
                io->fio = *fio;
        }
 
@@ -198,7 +271,7 @@ alloc_new:
                goto alloc_new;
        }
 
-       io->last_block_in_bio = fio->blk_addr;
+       io->last_block_in_bio = fio->new_blkaddr;
        f2fs_trace_ios(fio, 0);
 
        up_write(&io->io_rwsem);
@@ -218,7 +291,7 @@ void set_data_blkaddr(struct dnode_of_data *dn)
        struct page *node_page = dn->node_page;
        unsigned int ofs_in_node = dn->ofs_in_node;
 
-       f2fs_wait_on_page_writeback(node_page, NODE);
+       f2fs_wait_on_page_writeback(node_page, NODE, true);
 
        rn = F2FS_NODE(node_page);
 
@@ -229,6 +302,13 @@ void set_data_blkaddr(struct dnode_of_data *dn)
                dn->node_changed = true;
 }
 
+void f2fs_update_data_blkaddr(struct dnode_of_data *dn, block_t blkaddr)
+{
+       dn->data_blkaddr = blkaddr;
+       set_data_blkaddr(dn);
+       f2fs_update_extent_cache(dn);
+}
+
 int reserve_new_block(struct dnode_of_data *dn)
 {
        struct f2fs_sb_info *sbi = F2FS_I_SB(dn->inode);
@@ -332,7 +412,7 @@ got_it:
                return page;
        }
 
-       fio.blk_addr = dn.data_blkaddr;
+       fio.new_blkaddr = fio.old_blkaddr = dn.data_blkaddr;
        fio.page = page;
        err = f2fs_submit_page_bio(&fio);
        if (err)
@@ -461,7 +541,6 @@ got_it:
 static int __allocate_data_block(struct dnode_of_data *dn)
 {
        struct f2fs_sb_info *sbi = F2FS_I_SB(dn->inode);
-       struct f2fs_inode_info *fi = F2FS_I(dn->inode);
        struct f2fs_summary sum;
        struct node_info ni;
        int seg = CURSEG_WARM_DATA;
@@ -489,7 +568,7 @@ alloc:
        set_data_blkaddr(dn);
 
        /* update i_size */
-       fofs = start_bidx_of_node(ofs_of_node(dn->node_page), fi) +
+       fofs = start_bidx_of_node(ofs_of_node(dn->node_page), dn->inode) +
                                                        dn->ofs_in_node;
        if (i_size_read(dn->inode) < ((loff_t)(fofs + 1) << PAGE_CACHE_SHIFT))
                i_size_write(dn->inode,
@@ -497,67 +576,33 @@ alloc:
        return 0;
 }
 
-static int __allocate_data_blocks(struct inode *inode, loff_t offset,
-                                                       size_t count)
+ssize_t f2fs_preallocate_blocks(struct kiocb *iocb, struct iov_iter *from)
 {
-       struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
-       struct dnode_of_data dn;
-       u64 start = F2FS_BYTES_TO_BLK(offset);
-       u64 len = F2FS_BYTES_TO_BLK(count);
-       bool allocated;
-       u64 end_offset;
-       int err = 0;
-
-       while (len) {
-               f2fs_lock_op(sbi);
-
-               /* When reading holes, we need its node page */
-               set_new_dnode(&dn, inode, NULL, NULL, 0);
-               err = get_dnode_of_data(&dn, start, ALLOC_NODE);
-               if (err)
-                       goto out;
-
-               allocated = false;
-               end_offset = ADDRS_PER_PAGE(dn.node_page, F2FS_I(inode));
-
-               while (dn.ofs_in_node < end_offset && len) {
-                       block_t blkaddr;
-
-                       if (unlikely(f2fs_cp_error(sbi))) {
-                               err = -EIO;
-                               goto sync_out;
-                       }
-
-                       blkaddr = datablock_addr(dn.node_page, dn.ofs_in_node);
-                       if (blkaddr == NULL_ADDR || blkaddr == NEW_ADDR) {
-                               err = __allocate_data_block(&dn);
-                               if (err)
-                                       goto sync_out;
-                               allocated = true;
-                       }
-                       len--;
-                       start++;
-                       dn.ofs_in_node++;
-               }
+       struct inode *inode = file_inode(iocb->ki_filp);
+       struct f2fs_map_blocks map;
+       ssize_t ret = 0;
 
-               if (allocated)
-                       sync_inode_page(&dn);
+       map.m_lblk = F2FS_BYTES_TO_BLK(iocb->ki_pos);
+       map.m_len = F2FS_BLK_ALIGN(iov_iter_count(from));
+       map.m_next_pgofs = NULL;
 
-               f2fs_put_dnode(&dn);
-               f2fs_unlock_op(sbi);
+       if (f2fs_encrypted_inode(inode))
+               return 0;
 
-               f2fs_balance_fs(sbi, dn.node_changed);
+       if (iocb->ki_flags & IOCB_DIRECT) {
+               ret = f2fs_convert_inline_inode(inode);
+               if (ret)
+                       return ret;
+               return f2fs_map_blocks(inode, &map, 1, F2FS_GET_BLOCK_PRE_DIO);
        }
-       return err;
-
-sync_out:
-       if (allocated)
-               sync_inode_page(&dn);
-       f2fs_put_dnode(&dn);
-out:
-       f2fs_unlock_op(sbi);
-       f2fs_balance_fs(sbi, dn.node_changed);
-       return err;
+       if (iocb->ki_pos + iov_iter_count(from) > MAX_INLINE_DATA) {
+               ret = f2fs_convert_inline_inode(inode);
+               if (ret)
+                       return ret;
+       }
+       if (!f2fs_has_inline_data(inode))
+               return f2fs_map_blocks(inode, &map, 1, F2FS_GET_BLOCK_PRE_AIO);
+       return ret;
 }
 
 /*
@@ -588,13 +633,14 @@ int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map,
        /* it only supports block size == page size */
        pgofs = (pgoff_t)map->m_lblk;
 
-       if (f2fs_lookup_extent_cache(inode, pgofs, &ei)) {
+       if (!create && f2fs_lookup_extent_cache(inode, pgofs, &ei)) {
                map->m_pblk = ei.blk + pgofs - ei.fofs;
                map->m_len = min((pgoff_t)maxblocks, ei.fofs + ei.len - pgofs);
                map->m_flags = F2FS_MAP_MAPPED;
                goto out;
        }
 
+next_dnode:
        if (create)
                f2fs_lock_op(sbi);
 
@@ -602,120 +648,98 @@ int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map,
        set_new_dnode(&dn, inode, NULL, NULL, 0);
        err = get_dnode_of_data(&dn, pgofs, mode);
        if (err) {
-               if (err == -ENOENT)
+               if (err == -ENOENT) {
                        err = 0;
+                       if (map->m_next_pgofs)
+                               *map->m_next_pgofs =
+                                       get_next_page_offset(&dn, pgofs);
+               }
                goto unlock_out;
        }
 
-       if (dn.data_blkaddr == NEW_ADDR || dn.data_blkaddr == NULL_ADDR) {
+       end_offset = ADDRS_PER_PAGE(dn.node_page, inode);
+
+next_block:
+       blkaddr = datablock_addr(dn.node_page, dn.ofs_in_node);
+
+       if (blkaddr == NEW_ADDR || blkaddr == NULL_ADDR) {
                if (create) {
                        if (unlikely(f2fs_cp_error(sbi))) {
                                err = -EIO;
-                               goto put_out;
+                               goto sync_out;
+                       }
+                       if (flag == F2FS_GET_BLOCK_PRE_AIO) {
+                               if (blkaddr == NULL_ADDR)
+                                       err = reserve_new_block(&dn);
+                       } else {
+                               err = __allocate_data_block(&dn);
                        }
-                       err = __allocate_data_block(&dn);
                        if (err)
-                               goto put_out;
+                               goto sync_out;
                        allocated = true;
                        map->m_flags = F2FS_MAP_NEW;
+                       blkaddr = dn.data_blkaddr;
                } else {
+                       if (flag == F2FS_GET_BLOCK_FIEMAP &&
+                                               blkaddr == NULL_ADDR) {
+                               if (map->m_next_pgofs)
+                                       *map->m_next_pgofs = pgofs + 1;
+                       }
                        if (flag != F2FS_GET_BLOCK_FIEMAP ||
-                                               dn.data_blkaddr != NEW_ADDR) {
+                                               blkaddr != NEW_ADDR) {
                                if (flag == F2FS_GET_BLOCK_BMAP)
                                        err = -ENOENT;
-                               goto put_out;
+                               goto sync_out;
                        }
-
-                       /*
-                        * preallocated unwritten block should be mapped
-                        * for fiemap.
-                        */
-                       if (dn.data_blkaddr == NEW_ADDR)
-                               map->m_flags = F2FS_MAP_UNWRITTEN;
                }
        }
 
-       map->m_flags |= F2FS_MAP_MAPPED;
-       map->m_pblk = dn.data_blkaddr;
-       map->m_len = 1;
+       if (map->m_len == 0) {
+               /* preallocated unwritten block should be mapped for fiemap. */
+               if (blkaddr == NEW_ADDR)
+                       map->m_flags |= F2FS_MAP_UNWRITTEN;
+               map->m_flags |= F2FS_MAP_MAPPED;
+
+               map->m_pblk = blkaddr;
+               map->m_len = 1;
+       } else if ((map->m_pblk != NEW_ADDR &&
+                       blkaddr == (map->m_pblk + ofs)) ||
+                       (map->m_pblk == NEW_ADDR && blkaddr == NEW_ADDR) ||
+                       flag == F2FS_GET_BLOCK_PRE_DIO ||
+                       flag == F2FS_GET_BLOCK_PRE_AIO) {
+               ofs++;
+               map->m_len++;
+       } else {
+               goto sync_out;
+       }
 
-       end_offset = ADDRS_PER_PAGE(dn.node_page, F2FS_I(inode));
        dn.ofs_in_node++;
        pgofs++;
 
-get_next:
-       if (map->m_len >= maxblocks)
-               goto sync_out;
+       if (map->m_len < maxblocks) {
+               if (dn.ofs_in_node < end_offset)
+                       goto next_block;
 
-       if (dn.ofs_in_node >= end_offset) {
                if (allocated)
                        sync_inode_page(&dn);
-               allocated = false;
                f2fs_put_dnode(&dn);
 
                if (create) {
                        f2fs_unlock_op(sbi);
-                       f2fs_balance_fs(sbi, dn.node_changed);
-                       f2fs_lock_op(sbi);
-               }
-
-               set_new_dnode(&dn, inode, NULL, NULL, 0);
-               err = get_dnode_of_data(&dn, pgofs, mode);
-               if (err) {
-                       if (err == -ENOENT)
-                               err = 0;
-                       goto unlock_out;
-               }
-
-               end_offset = ADDRS_PER_PAGE(dn.node_page, F2FS_I(inode));
-       }
-
-       blkaddr = datablock_addr(dn.node_page, dn.ofs_in_node);
-
-       if (blkaddr == NEW_ADDR || blkaddr == NULL_ADDR) {
-               if (create) {
-                       if (unlikely(f2fs_cp_error(sbi))) {
-                               err = -EIO;
-                               goto sync_out;
-                       }
-                       err = __allocate_data_block(&dn);
-                       if (err)
-                               goto sync_out;
-                       allocated = true;
-                       map->m_flags |= F2FS_MAP_NEW;
-                       blkaddr = dn.data_blkaddr;
-               } else {
-                       /*
-                        * we only merge preallocated unwritten blocks
-                        * for fiemap.
-                        */
-                       if (flag != F2FS_GET_BLOCK_FIEMAP ||
-                                       blkaddr != NEW_ADDR)
-                               goto sync_out;
+                       f2fs_balance_fs(sbi, allocated);
                }
-       }
-
-       /* Give more consecutive addresses for the readahead */
-       if ((map->m_pblk != NEW_ADDR &&
-                       blkaddr == (map->m_pblk + ofs)) ||
-                       (map->m_pblk == NEW_ADDR &&
-                       blkaddr == NEW_ADDR)) {
-               ofs++;
-               dn.ofs_in_node++;
-               pgofs++;
-               map->m_len++;
-               goto get_next;
+               allocated = false;
+               goto next_dnode;
        }
 
 sync_out:
        if (allocated)
                sync_inode_page(&dn);
-put_out:
        f2fs_put_dnode(&dn);
 unlock_out:
        if (create) {
                f2fs_unlock_op(sbi);
-               f2fs_balance_fs(sbi, dn.node_changed);
+               f2fs_balance_fs(sbi, allocated);
        }
 out:
        trace_f2fs_map_blocks(inode, map, err);
@@ -723,13 +747,15 @@ out:
 }
 
 static int __get_data_block(struct inode *inode, sector_t iblock,
-                       struct buffer_head *bh, int create, int flag)
+                       struct buffer_head *bh, int create, int flag,
+                       pgoff_t *next_pgofs)
 {
        struct f2fs_map_blocks map;
        int ret;
 
        map.m_lblk = iblock;
        map.m_len = bh->b_size >> inode->i_blkbits;
+       map.m_next_pgofs = next_pgofs;
 
        ret = f2fs_map_blocks(inode, &map, create, flag);
        if (!ret) {
@@ -741,16 +767,18 @@ static int __get_data_block(struct inode *inode, sector_t iblock,
 }
 
 static int get_data_block(struct inode *inode, sector_t iblock,
-                       struct buffer_head *bh_result, int create, int flag)
+                       struct buffer_head *bh_result, int create, int flag,
+                       pgoff_t *next_pgofs)
 {
-       return __get_data_block(inode, iblock, bh_result, create, flag);
+       return __get_data_block(inode, iblock, bh_result, create,
+                                                       flag, next_pgofs);
 }
 
 static int get_data_block_dio(struct inode *inode, sector_t iblock,
                        struct buffer_head *bh_result, int create)
 {
        return __get_data_block(inode, iblock, bh_result, create,
-                                               F2FS_GET_BLOCK_DIO);
+                                               F2FS_GET_BLOCK_DIO, NULL);
 }
 
 static int get_data_block_bmap(struct inode *inode, sector_t iblock,
@@ -761,7 +789,7 @@ static int get_data_block_bmap(struct inode *inode, sector_t iblock,
                return -EFBIG;
 
        return __get_data_block(inode, iblock, bh_result, create,
-                                               F2FS_GET_BLOCK_BMAP);
+                                               F2FS_GET_BLOCK_BMAP, NULL);
 }
 
 static inline sector_t logical_to_blk(struct inode *inode, loff_t offset)
@@ -779,6 +807,7 @@ int f2fs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
 {
        struct buffer_head map_bh;
        sector_t start_blk, last_blk;
+       pgoff_t next_pgofs;
        loff_t isize;
        u64 logical = 0, phys = 0, size = 0;
        u32 flags = 0;
@@ -814,14 +843,15 @@ next:
        map_bh.b_size = len;
 
        ret = get_data_block(inode, start_blk, &map_bh, 0,
-                                       F2FS_GET_BLOCK_FIEMAP);
+                                       F2FS_GET_BLOCK_FIEMAP, &next_pgofs);
        if (ret)
                goto out;
 
        /* HOLE */
        if (!buffer_mapped(&map_bh)) {
+               start_blk = next_pgofs;
                /* Go through holes util pass the EOF */
-               if (blk_to_logical(inode, start_blk++) < isize)
+               if (blk_to_logical(inode, start_blk) < isize)
                        goto prep_next;
                /* Found a hole beyond isize means no more extents.
                 * Note that the premise is that filesystems don't
@@ -889,6 +919,7 @@ static int f2fs_mpage_readpages(struct address_space *mapping,
        map.m_lblk = 0;
        map.m_len = 0;
        map.m_flags = 0;
+       map.m_next_pgofs = NULL;
 
        for (page_idx = 0; nr_pages; page_idx++, nr_pages--) {
 
@@ -927,7 +958,7 @@ static int f2fs_mpage_readpages(struct address_space *mapping,
                        map.m_len = last_block - block_in_file;
 
                        if (f2fs_map_blocks(inode, &map, 0,
-                                                       F2FS_GET_BLOCK_READ))
+                                               F2FS_GET_BLOCK_READ))
                                goto set_error_page;
                }
 got_it:
@@ -956,12 +987,12 @@ submit_and_realloc:
                        bio = NULL;
                }
                if (bio == NULL) {
-                       struct f2fs_crypto_ctx *ctx = NULL;
+                       struct fscrypt_ctx *ctx = NULL;
 
                        if (f2fs_encrypted_inode(inode) &&
                                        S_ISREG(inode->i_mode)) {
 
-                               ctx = f2fs_get_crypto_ctx(inode);
+                               ctx = fscrypt_get_ctx(inode);
                                if (IS_ERR(ctx))
                                        goto set_error_page;
 
@@ -974,7 +1005,7 @@ submit_and_realloc:
                                min_t(int, nr_pages, BIO_MAX_PAGES));
                        if (!bio) {
                                if (ctx)
-                                       f2fs_release_crypto_ctx(ctx);
+                                       fscrypt_release_ctx(ctx);
                                goto set_error_page;
                        }
                        bio->bi_bdev = bdev;
@@ -1052,10 +1083,10 @@ int do_write_data_page(struct f2fs_io_info *fio)
        if (err)
                return err;
 
-       fio->blk_addr = dn.data_blkaddr;
+       fio->old_blkaddr = dn.data_blkaddr;
 
        /* This page is already truncated */
-       if (fio->blk_addr == NULL_ADDR) {
+       if (fio->old_blkaddr == NULL_ADDR) {
                ClearPageUptodate(page);
                goto out_writepage;
        }
@@ -1064,9 +1095,9 @@ int do_write_data_page(struct f2fs_io_info *fio)
 
                /* wait for GCed encrypted page writeback */
                f2fs_wait_on_encrypted_page_writeback(F2FS_I_SB(inode),
-                                                       fio->blk_addr);
+                                                       fio->old_blkaddr);
 
-               fio->encrypted_page = f2fs_encrypt(inode, fio->page);
+               fio->encrypted_page = fscrypt_encrypt_page(inode, fio->page);
                if (IS_ERR(fio->encrypted_page)) {
                        err = PTR_ERR(fio->encrypted_page);
                        goto out_writepage;
@@ -1079,7 +1110,7 @@ int do_write_data_page(struct f2fs_io_info *fio)
         * If current allocation needs SSR,
         * it had better in-place writes for updated data.
         */
-       if (unlikely(fio->blk_addr != NEW_ADDR &&
+       if (unlikely(fio->old_blkaddr != NEW_ADDR &&
                        !is_cold_data(page) &&
                        !IS_ATOMIC_WRITTEN_PAGE(page) &&
                        need_inplace_update(inode))) {
@@ -1088,8 +1119,6 @@ int do_write_data_page(struct f2fs_io_info *fio)
                trace_f2fs_do_write_data_page(page, IPU);
        } else {
                write_data_page(&dn, fio);
-               set_data_blkaddr(&dn);
-               f2fs_update_extent_cache(&dn);
                trace_f2fs_do_write_data_page(page, OPU);
                set_inode_flag(F2FS_I(inode), FI_APPEND_WRITE);
                if (page->index == 0)
@@ -1177,12 +1206,18 @@ out:
        inode_dec_dirty_pages(inode);
        if (err)
                ClearPageUptodate(page);
+
+       if (wbc->for_reclaim) {
+               f2fs_submit_merged_bio_cond(sbi, NULL, page, 0, DATA, WRITE);
+               remove_dirty_inode(inode);
+       }
+
        unlock_page(page);
        f2fs_balance_fs(sbi, need_balance_fs);
-       if (wbc->for_reclaim || unlikely(f2fs_cp_error(sbi))) {
+
+       if (unlikely(f2fs_cp_error(sbi)))
                f2fs_submit_merged_bio(sbi, DATA, WRITE);
-               remove_dirty_inode(inode);
-       }
+
        return 0;
 
 redirty_out:
@@ -1282,7 +1317,8 @@ continue_unlock:
 
                        if (PageWriteback(page)) {
                                if (wbc->sync_mode != WB_SYNC_NONE)
-                                       f2fs_wait_on_page_writeback(page, DATA);
+                                       f2fs_wait_on_page_writeback(page,
+                                                               DATA, true);
                                else
                                        goto continue_unlock;
                        }
@@ -1339,8 +1375,6 @@ static int f2fs_write_data_pages(struct address_space *mapping,
        int ret;
        long diff;
 
-       trace_f2fs_writepages(mapping->host, wbc, DATA);
-
        /* deal with chardevs and other special file */
        if (!mapping->a_ops->writepage)
                return 0;
@@ -1362,14 +1396,16 @@ static int f2fs_write_data_pages(struct address_space *mapping,
        if (unlikely(is_sbi_flag_set(sbi, SBI_POR_DOING)))
                goto skip_write;
 
+       trace_f2fs_writepages(mapping->host, wbc, DATA);
+
        diff = nr_pages_to_write(sbi, DATA, wbc);
 
-       if (!S_ISDIR(inode->i_mode)) {
+       if (!S_ISDIR(inode->i_mode) && wbc->sync_mode == WB_SYNC_ALL) {
                mutex_lock(&sbi->writepages);
                locked = true;
        }
        ret = f2fs_write_cache_pages(mapping, wbc, __f2fs_writepage, mapping);
-       f2fs_submit_merged_bio(sbi, DATA, WRITE);
+       f2fs_submit_merged_bio_cond(sbi, inode, NULL, 0, DATA, WRITE);
        if (locked)
                mutex_unlock(&sbi->writepages);
 
@@ -1380,6 +1416,7 @@ static int f2fs_write_data_pages(struct address_space *mapping,
 
 skip_write:
        wbc->pages_skipped += get_dirty_pages(inode);
+       trace_f2fs_writepages(mapping->host, wbc, DATA);
        return 0;
 }
 
@@ -1406,6 +1443,14 @@ static int prepare_write_begin(struct f2fs_sb_info *sbi,
        struct extent_info ei;
        int err = 0;
 
+       /*
+        * we already allocated all the blocks, so we don't need to get
+        * the block addresses when there is no need to fill the page.
+        */
+       if (!f2fs_has_inline_data(inode) && !f2fs_encrypted_inode(inode) &&
+                                       len == PAGE_CACHE_SIZE)
+               return 0;
+
        if (f2fs_has_inline_data(inode) ||
                        (pos & PAGE_CACHE_MASK) >= i_size_read(inode)) {
                f2fs_lock_op(sbi);
@@ -1425,7 +1470,7 @@ restart:
                if (pos + len <= MAX_INLINE_DATA) {
                        read_inline_data(page, ipage);
                        set_inode_flag(F2FS_I(inode), FI_DATA_EXIST);
-                       sync_inode_page(&dn);
+                       set_inline_node(ipage);
                } else {
                        err = f2fs_convert_inline_page(&dn, page);
                        if (err)
@@ -1439,13 +1484,9 @@ restart:
                if (f2fs_lookup_extent_cache(inode, index, &ei)) {
                        dn.data_blkaddr = ei.blk + index - ei.fofs;
                } else {
-                       bool restart = false;
-
                        /* hole case */
                        err = get_dnode_of_data(&dn, index, LOOKUP_NODE);
-                       if (err || (!err && dn.data_blkaddr == NULL_ADDR))
-                               restart = true;
-                       if (restart) {
+                       if (err || (!err && dn.data_blkaddr == NULL_ADDR)) {
                                f2fs_put_dnode(&dn);
                                f2fs_lock_op(sbi);
                                locked = true;
@@ -1514,7 +1555,7 @@ repeat:
                }
        }
 
-       f2fs_wait_on_page_writeback(page, DATA);
+       f2fs_wait_on_page_writeback(page, DATA, false);
 
        /* wait for GCed encrypted page writeback */
        if (f2fs_encrypted_inode(inode) && S_ISREG(inode->i_mode))
@@ -1541,7 +1582,8 @@ repeat:
                        .sbi = sbi,
                        .type = DATA,
                        .rw = READ_SYNC,
-                       .blk_addr = blkaddr,
+                       .old_blkaddr = blkaddr,
+                       .new_blkaddr = blkaddr,
                        .page = page,
                        .encrypted_page = NULL,
                };
@@ -1561,7 +1603,7 @@ repeat:
 
                /* avoid symlink page */
                if (f2fs_encrypted_inode(inode) && S_ISREG(inode->i_mode)) {
-                       err = f2fs_decrypt_one(inode, page);
+                       err = fscrypt_decrypt_page(page);
                        if (err)
                                goto fail;
                }
@@ -1592,7 +1634,6 @@ static int f2fs_write_end(struct file *file,
        if (pos + copied > i_size_read(inode)) {
                i_size_write(inode, pos + copied);
                mark_inode_dirty(inode);
-               update_inode_page(inode);
        }
 
        f2fs_put_page(page, 1);
@@ -1617,34 +1658,21 @@ static int check_direct_IO(struct inode *inode, struct iov_iter *iter,
 static ssize_t f2fs_direct_IO(struct kiocb *iocb, struct iov_iter *iter,
                              loff_t offset)
 {
-       struct file *file = iocb->ki_filp;
-       struct address_space *mapping = file->f_mapping;
+       struct address_space *mapping = iocb->ki_filp->f_mapping;
        struct inode *inode = mapping->host;
        size_t count = iov_iter_count(iter);
        int err;
 
-       /* we don't need to use inline_data strictly */
-       err = f2fs_convert_inline_inode(inode);
+       err = check_direct_IO(inode, iter, offset);
        if (err)
                return err;
 
        if (f2fs_encrypted_inode(inode) && S_ISREG(inode->i_mode))
                return 0;
 
-       err = check_direct_IO(inode, iter, offset);
-       if (err)
-               return err;
-
        trace_f2fs_direct_IO_enter(inode, offset, count, iov_iter_rw(iter));
 
-       if (iov_iter_rw(iter) == WRITE) {
-               err = __allocate_data_blocks(inode, offset, count);
-               if (err)
-                       goto out;
-       }
-
        err = blockdev_direct_IO(iocb, inode, iter, offset, get_data_block_dio);
-out:
        if (err < 0 && iov_iter_rw(iter) == WRITE)
                f2fs_write_failed(mapping, offset + count);
 
index faa7495..80641ad 100644 (file)
@@ -77,7 +77,7 @@ static unsigned long dir_block_index(unsigned int level,
 }
 
 static struct f2fs_dir_entry *find_in_block(struct page *dentry_page,
-                               struct f2fs_filename *fname,
+                               struct fscrypt_name *fname,
                                f2fs_hash_t namehash,
                                int *max_slots,
                                struct page **res_page)
@@ -103,15 +103,15 @@ static struct f2fs_dir_entry *find_in_block(struct page *dentry_page,
        return de;
 }
 
-struct f2fs_dir_entry *find_target_dentry(struct f2fs_filename *fname,
+struct f2fs_dir_entry *find_target_dentry(struct fscrypt_name *fname,
                        f2fs_hash_t namehash, int *max_slots,
                        struct f2fs_dentry_ptr *d)
 {
        struct f2fs_dir_entry *de;
        unsigned long bit_pos = 0;
        int max_len = 0;
-       struct f2fs_str de_name = FSTR_INIT(NULL, 0);
-       struct f2fs_str *name = &fname->disk_name;
+       struct fscrypt_str de_name = FSTR_INIT(NULL, 0);
+       struct fscrypt_str *name = &fname->disk_name;
 
        if (max_slots)
                *max_slots = 0;
@@ -157,7 +157,7 @@ found:
 
 static struct f2fs_dir_entry *find_in_level(struct inode *dir,
                                        unsigned int level,
-                                       struct f2fs_filename *fname,
+                                       struct fscrypt_name *fname,
                                        struct page **res_page)
 {
        struct qstr name = FSTR_TO_QSTR(&fname->disk_name);
@@ -218,12 +218,12 @@ struct f2fs_dir_entry *f2fs_find_entry(struct inode *dir,
        struct f2fs_dir_entry *de = NULL;
        unsigned int max_depth;
        unsigned int level;
-       struct f2fs_filename fname;
+       struct fscrypt_name fname;
        int err;
 
        *res_page = NULL;
 
-       err = f2fs_fname_setup_filename(dir, child, 1, &fname);
+       err = fscrypt_setup_filename(dir, child, 1, &fname);
        if (err)
                return NULL;
 
@@ -251,7 +251,7 @@ struct f2fs_dir_entry *f2fs_find_entry(struct inode *dir,
                        break;
        }
 out:
-       f2fs_fname_free_filename(&fname);
+       fscrypt_free_filename(&fname);
        return de;
 }
 
@@ -296,7 +296,7 @@ void f2fs_set_link(struct inode *dir, struct f2fs_dir_entry *de,
 {
        enum page_type type = f2fs_has_inline_dentry(dir) ? NODE : DATA;
        lock_page(page);
-       f2fs_wait_on_page_writeback(page, type);
+       f2fs_wait_on_page_writeback(page, type, true);
        de->ino = cpu_to_le32(inode->i_ino);
        set_de_type(de, inode->i_mode);
        f2fs_dentry_kunmap(dir, page);
@@ -311,7 +311,7 @@ static void init_dent_inode(const struct qstr *name, struct page *ipage)
 {
        struct f2fs_inode *ri;
 
-       f2fs_wait_on_page_writeback(ipage, NODE);
+       f2fs_wait_on_page_writeback(ipage, NODE, true);
 
        /* copy name info. to this inode page */
        ri = F2FS_INODE(ipage);
@@ -341,24 +341,14 @@ int update_dent_inode(struct inode *inode, struct inode *to,
 void do_make_empty_dir(struct inode *inode, struct inode *parent,
                                        struct f2fs_dentry_ptr *d)
 {
-       struct f2fs_dir_entry *de;
-
-       de = &d->dentry[0];
-       de->name_len = cpu_to_le16(1);
-       de->hash_code = 0;
-       de->ino = cpu_to_le32(inode->i_ino);
-       memcpy(d->filename[0], ".", 1);
-       set_de_type(de, inode->i_mode);
+       struct qstr dot = QSTR_INIT(".", 1);
+       struct qstr dotdot = QSTR_INIT("..", 2);
 
-       de = &d->dentry[1];
-       de->hash_code = 0;
-       de->name_len = cpu_to_le16(2);
-       de->ino = cpu_to_le32(parent->i_ino);
-       memcpy(d->filename[1], "..", 2);
-       set_de_type(de, parent->i_mode);
+       /* update dirent of "." */
+       f2fs_update_dentry(inode->i_ino, inode->i_mode, d, &dot, 0, 0);
 
-       test_and_set_bit_le(0, (void *)d->bitmap);
-       test_and_set_bit_le(1, (void *)d->bitmap);
+       /* update dirent of ".." */
+       f2fs_update_dentry(parent->i_ino, parent->i_mode, d, &dotdot, 0, 1);
 }
 
 static int make_empty_dir(struct inode *inode,
@@ -413,7 +403,7 @@ struct page *init_inode_metadata(struct inode *inode, struct inode *dir,
                        goto put_error;
 
                if (f2fs_encrypted_inode(dir) && f2fs_may_encrypt(inode)) {
-                       err = f2fs_inherit_context(dir, inode, page);
+                       err = fscrypt_inherit_context(dir, inode, page, false);
                        if (err)
                                goto put_error;
                }
@@ -511,8 +501,12 @@ void f2fs_update_dentry(nid_t ino, umode_t mode, struct f2fs_dentry_ptr *d,
        memcpy(d->filename[bit_pos], name->name, name->len);
        de->ino = cpu_to_le32(ino);
        set_de_type(de, mode);
-       for (i = 0; i < slots; i++)
+       for (i = 0; i < slots; i++) {
                test_and_set_bit_le(bit_pos + i, (void *)d->bitmap);
+               /* avoid wrong garbage data for readdir */
+               if (i)
+                       (de + i)->name_len = 0;
+       }
 }
 
 /*
@@ -532,11 +526,11 @@ int __f2fs_add_link(struct inode *dir, const struct qstr *name,
        struct f2fs_dentry_block *dentry_blk = NULL;
        struct f2fs_dentry_ptr d;
        struct page *page = NULL;
-       struct f2fs_filename fname;
+       struct fscrypt_name fname;
        struct qstr new_name;
        int slots, err;
 
-       err = f2fs_fname_setup_filename(dir, name, 0, &fname);
+       err = fscrypt_setup_filename(dir, name, 0, &fname);
        if (err)
                return err;
 
@@ -598,7 +592,7 @@ start:
        ++level;
        goto start;
 add_dentry:
-       f2fs_wait_on_page_writeback(dentry_page, DATA);
+       f2fs_wait_on_page_writeback(dentry_page, DATA, true);
 
        if (inode) {
                down_write(&F2FS_I(inode)->i_sem);
@@ -635,7 +629,7 @@ fail:
        kunmap(dentry_page);
        f2fs_put_page(dentry_page, 1);
 out:
-       f2fs_fname_free_filename(&fname);
+       fscrypt_free_filename(&fname);
        f2fs_update_time(F2FS_I_SB(dir), REQ_TIME);
        return err;
 }
@@ -709,7 +703,7 @@ void f2fs_delete_entry(struct f2fs_dir_entry *dentry, struct page *page,
                return f2fs_delete_inline_entry(dentry, page, dir, inode);
 
        lock_page(page);
-       f2fs_wait_on_page_writeback(page, DATA);
+       f2fs_wait_on_page_writeback(page, DATA, true);
 
        dentry_blk = page_address(page);
        bit_pos = dentry - dentry_blk->dentry;
@@ -777,12 +771,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, struct f2fs_str *fstr)
+                       unsigned int start_pos, struct fscrypt_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);
+       struct fscrypt_str de_name = FSTR_INIT(NULL, 0);
 
        bit_pos = ((unsigned long)ctx->pos % d->max);
 
@@ -792,6 +786,12 @@ bool f2fs_fill_dentries(struct dir_context *ctx, struct f2fs_dentry_ptr *d,
                        break;
 
                de = &d->dentry[bit_pos];
+               if (de->name_len == 0) {
+                       bit_pos++;
+                       ctx->pos = start_pos + bit_pos;
+                       continue;
+               }
+
                if (de->file_type < F2FS_FT_MAX)
                        d_type = f2fs_filetype_table[de->file_type];
                else
@@ -810,8 +810,9 @@ bool f2fs_fill_dentries(struct dir_context *ctx, struct f2fs_dentry_ptr *d,
 
                        memcpy(de_name.name, d->filename[bit_pos], de_name.len);
 
-                       ret = f2fs_fname_disk_to_usr(d->inode, &de->hash_code,
-                                                       &de_name, fstr);
+                       ret = fscrypt_fname_disk_to_usr(d->inode,
+                                               (u32)de->hash_code, 0,
+                                               &de_name, fstr);
                        kfree(de_name.name);
                        if (ret < 0)
                                return true;
@@ -839,16 +840,15 @@ 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);
+       struct fscrypt_str fstr = FSTR_INIT(NULL, 0);
        int err = 0;
 
        if (f2fs_encrypted_inode(inode)) {
-               err = f2fs_get_encryption_info(inode);
-               if (err)
+               err = fscrypt_get_encryption_info(inode);
+               if (err && err != -ENOKEY)
                        return err;
 
-               err = f2fs_fname_crypto_alloc_buffer(inode, F2FS_NAME_LEN,
-                                                               &fstr);
+               err = fscrypt_fname_alloc_buffer(inode, F2FS_NAME_LEN, &fstr);
                if (err < 0)
                        return err;
        }
@@ -888,15 +888,23 @@ static int f2fs_readdir(struct file *file, struct dir_context *ctx)
                f2fs_put_page(dentry_page, 1);
        }
 out:
-       f2fs_fname_crypto_free_buffer(&fstr);
+       fscrypt_fname_free_buffer(&fstr);
        return err;
 }
 
+static int f2fs_dir_open(struct inode *inode, struct file *filp)
+{
+       if (f2fs_encrypted_inode(inode))
+               return fscrypt_get_encryption_info(inode) ? -EACCES : 0;
+       return 0;
+}
+
 const struct file_operations f2fs_dir_operations = {
        .llseek         = generic_file_llseek,
        .read           = generic_read_dir,
        .iterate        = f2fs_readdir,
        .fsync          = f2fs_sync_file,
+       .open           = f2fs_dir_open,
        .unlocked_ioctl = f2fs_ioctl,
 #ifdef CONFIG_COMPAT
        .compat_ioctl   = f2fs_compat_ioctl,
index ccd5c63..c859bb0 100644 (file)
@@ -33,6 +33,7 @@ static struct extent_node *__attach_extent_node(struct f2fs_sb_info *sbi,
 
        en->ei = *ei;
        INIT_LIST_HEAD(&en->list);
+       en->et = et;
 
        rb_link_node(&en->rb_node, parent, p);
        rb_insert_color(&en->rb_node, &et->root);
@@ -50,6 +51,24 @@ static void __detach_extent_node(struct f2fs_sb_info *sbi,
 
        if (et->cached_en == en)
                et->cached_en = NULL;
+       kmem_cache_free(extent_node_slab, en);
+}
+
+/*
+ * Flow to release an extent_node:
+ * 1. list_del_init
+ * 2. __detach_extent_node
+ * 3. kmem_cache_free.
+ */
+static void __release_extent_node(struct f2fs_sb_info *sbi,
+                       struct extent_tree *et, struct extent_node *en)
+{
+       spin_lock(&sbi->extent_lock);
+       f2fs_bug_on(sbi, list_empty(&en->list));
+       list_del_init(&en->list);
+       spin_unlock(&sbi->extent_lock);
+
+       __detach_extent_node(sbi, et, en);
 }
 
 static struct extent_tree *__grab_extent_tree(struct inode *inode)
@@ -129,7 +148,7 @@ static struct extent_node *__init_extent_tree(struct f2fs_sb_info *sbi,
 }
 
 static unsigned int __free_extent_tree(struct f2fs_sb_info *sbi,
-                                       struct extent_tree *et, bool free_all)
+                                       struct extent_tree *et)
 {
        struct rb_node *node, *next;
        struct extent_node *en;
@@ -139,18 +158,7 @@ static unsigned int __free_extent_tree(struct f2fs_sb_info *sbi,
        while (node) {
                next = rb_next(node);
                en = rb_entry(node, struct extent_node, rb_node);
-
-               if (free_all) {
-                       spin_lock(&sbi->extent_lock);
-                       if (!list_empty(&en->list))
-                               list_del_init(&en->list);
-                       spin_unlock(&sbi->extent_lock);
-               }
-
-               if (free_all || list_empty(&en->list)) {
-                       __detach_extent_node(sbi, et, en);
-                       kmem_cache_free(extent_node_slab, en);
-               }
+               __release_extent_node(sbi, et, en);
                node = next;
        }
 
@@ -232,9 +240,10 @@ static bool f2fs_lookup_extent_tree(struct inode *inode, pgoff_t pgofs,
        if (en) {
                *ei = en->ei;
                spin_lock(&sbi->extent_lock);
-               if (!list_empty(&en->list))
+               if (!list_empty(&en->list)) {
                        list_move_tail(&en->list, &sbi->extent_list);
-               et->cached_en = en;
+                       et->cached_en = en;
+               }
                spin_unlock(&sbi->extent_lock);
                ret = true;
        }
@@ -329,7 +338,6 @@ lookup_neighbors:
 
 static struct extent_node *__try_merge_extent_node(struct f2fs_sb_info *sbi,
                                struct extent_tree *et, struct extent_info *ei,
-                               struct extent_node **den,
                                struct extent_node *prev_ex,
                                struct extent_node *next_ex)
 {
@@ -342,20 +350,25 @@ static struct extent_node *__try_merge_extent_node(struct f2fs_sb_info *sbi,
        }
 
        if (next_ex && __is_front_mergeable(ei, &next_ex->ei)) {
-               if (en) {
-                       __detach_extent_node(sbi, et, prev_ex);
-                       *den = prev_ex;
-               }
+               if (en)
+                       __release_extent_node(sbi, et, prev_ex);
                next_ex->ei.fofs = ei->fofs;
                next_ex->ei.blk = ei->blk;
                next_ex->ei.len += ei->len;
                en = next_ex;
        }
 
-       if (en) {
-               __try_update_largest_extent(et, en);
+       if (!en)
+               return NULL;
+
+       __try_update_largest_extent(et, en);
+
+       spin_lock(&sbi->extent_lock);
+       if (!list_empty(&en->list)) {
+               list_move_tail(&en->list, &sbi->extent_list);
                et->cached_en = en;
        }
+       spin_unlock(&sbi->extent_lock);
        return en;
 }
 
@@ -391,7 +404,12 @@ do_insert:
                return NULL;
 
        __try_update_largest_extent(et, en);
+
+       /* update in global extent list */
+       spin_lock(&sbi->extent_lock);
+       list_add_tail(&en->list, &sbi->extent_list);
        et->cached_en = en;
+       spin_unlock(&sbi->extent_lock);
        return en;
 }
 
@@ -479,7 +497,7 @@ static unsigned int f2fs_update_extent_tree_range(struct inode *inode,
                if (parts)
                        __try_update_largest_extent(et, en);
                else
-                       __detach_extent_node(sbi, et, en);
+                       __release_extent_node(sbi, et, en);
 
                /*
                 * if original extent is split into zero or two parts, extent
@@ -490,31 +508,15 @@ static unsigned int f2fs_update_extent_tree_range(struct inode *inode,
                        insert_p = NULL;
                        insert_parent = NULL;
                }
-
-               /* update in global extent list */
-               spin_lock(&sbi->extent_lock);
-               if (!parts && !list_empty(&en->list))
-                       list_del(&en->list);
-               if (en1)
-                       list_add_tail(&en1->list, &sbi->extent_list);
-               spin_unlock(&sbi->extent_lock);
-
-               /* release extent node */
-               if (!parts)
-                       kmem_cache_free(extent_node_slab, en);
-
                en = next_en;
        }
 
        /* 3. update extent in extent cache */
        if (blkaddr) {
-               struct extent_node *den = NULL;
 
                set_extent_info(&ei, fofs, blkaddr, len);
-               en1 = __try_merge_extent_node(sbi, et, &ei, &den,
-                                                       prev_en, next_en);
-               if (!en1)
-                       en1 = __insert_extent_tree(sbi, et, &ei,
+               if (!__try_merge_extent_node(sbi, et, &ei, prev_en, next_en))
+                       __insert_extent_tree(sbi, et, &ei,
                                                insert_p, insert_parent);
 
                /* give up extent_cache, if split and small updates happen */
@@ -524,24 +526,10 @@ static unsigned int f2fs_update_extent_tree_range(struct inode *inode,
                        et->largest.len = 0;
                        set_inode_flag(F2FS_I(inode), FI_NO_EXTENT);
                }
-
-               spin_lock(&sbi->extent_lock);
-               if (en1) {
-                       if (list_empty(&en1->list))
-                               list_add_tail(&en1->list, &sbi->extent_list);
-                       else
-                               list_move_tail(&en1->list, &sbi->extent_list);
-               }
-               if (den && !list_empty(&den->list))
-                       list_del(&den->list);
-               spin_unlock(&sbi->extent_lock);
-
-               if (den)
-                       kmem_cache_free(extent_node_slab, den);
        }
 
        if (is_inode_flag_set(F2FS_I(inode), FI_NO_EXTENT))
-               __free_extent_tree(sbi, et, true);
+               __free_extent_tree(sbi, et);
 
        write_unlock(&et->lock);
 
@@ -550,14 +538,10 @@ static unsigned int f2fs_update_extent_tree_range(struct inode *inode,
 
 unsigned int f2fs_shrink_extent_tree(struct f2fs_sb_info *sbi, int nr_shrink)
 {
-       struct extent_tree *treevec[EXT_TREE_VEC_SIZE];
        struct extent_tree *et, *next;
-       struct extent_node *en, *tmp;
-       unsigned long ino = F2FS_ROOT_INO(sbi);
-       unsigned int found;
+       struct extent_node *en;
        unsigned int node_cnt = 0, tree_cnt = 0;
        int remained;
-       bool do_free = false;
 
        if (!test_opt(sbi, EXTENT_CACHE))
                return 0;
@@ -572,10 +556,10 @@ unsigned int f2fs_shrink_extent_tree(struct f2fs_sb_info *sbi, int nr_shrink)
        list_for_each_entry_safe(et, next, &sbi->zombie_list, list) {
                if (atomic_read(&et->node_cnt)) {
                        write_lock(&et->lock);
-                       node_cnt += __free_extent_tree(sbi, et, true);
+                       node_cnt += __free_extent_tree(sbi, et);
                        write_unlock(&et->lock);
                }
-
+               f2fs_bug_on(sbi, atomic_read(&et->node_cnt));
                list_del_init(&et->list);
                radix_tree_delete(&sbi->extent_tree_root, et->ino);
                kmem_cache_free(extent_tree_slab, et);
@@ -585,6 +569,7 @@ unsigned int f2fs_shrink_extent_tree(struct f2fs_sb_info *sbi, int nr_shrink)
 
                if (node_cnt + tree_cnt >= nr_shrink)
                        goto unlock_out;
+               cond_resched();
        }
        up_write(&sbi->extent_tree_lock);
 
@@ -596,42 +581,29 @@ free_node:
        remained = nr_shrink - (node_cnt + tree_cnt);
 
        spin_lock(&sbi->extent_lock);
-       list_for_each_entry_safe(en, tmp, &sbi->extent_list, list) {
-               if (!remained--)
+       for (; remained > 0; remained--) {
+               if (list_empty(&sbi->extent_list))
                        break;
-               list_del_init(&en->list);
-               do_free = true;
-       }
-       spin_unlock(&sbi->extent_lock);
-
-       if (do_free == false)
-               goto unlock_out;
-
-       /*
-        * reset ino for searching victims from beginning of global extent tree.
-        */
-       ino = F2FS_ROOT_INO(sbi);
-
-       while ((found = radix_tree_gang_lookup(&sbi->extent_tree_root,
-                               (void **)treevec, ino, EXT_TREE_VEC_SIZE))) {
-               unsigned i;
-
-               ino = treevec[found - 1]->ino + 1;
-               for (i = 0; i < found; i++) {
-                       struct extent_tree *et = treevec[i];
+               en = list_first_entry(&sbi->extent_list,
+                                       struct extent_node, list);
+               et = en->et;
+               if (!write_trylock(&et->lock)) {
+                       /* refresh this extent node's position in extent list */
+                       list_move_tail(&en->list, &sbi->extent_list);
+                       continue;
+               }
 
-                       if (!atomic_read(&et->node_cnt))
-                               continue;
+               list_del_init(&en->list);
+               spin_unlock(&sbi->extent_lock);
 
-                       if (write_trylock(&et->lock)) {
-                               node_cnt += __free_extent_tree(sbi, et, false);
-                               write_unlock(&et->lock);
-                       }
+               __detach_extent_node(sbi, et, en);
 
-                       if (node_cnt + tree_cnt >= nr_shrink)
-                               goto unlock_out;
-               }
+               write_unlock(&et->lock);
+               node_cnt++;
+               spin_lock(&sbi->extent_lock);
        }
+       spin_unlock(&sbi->extent_lock);
+
 unlock_out:
        up_write(&sbi->extent_tree_lock);
 out:
@@ -650,7 +622,7 @@ unsigned int f2fs_destroy_extent_node(struct inode *inode)
                return 0;
 
        write_lock(&et->lock);
-       node_cnt = __free_extent_tree(sbi, et, true);
+       node_cnt = __free_extent_tree(sbi, et);
        write_unlock(&et->lock);
 
        return node_cnt;
@@ -701,19 +673,21 @@ bool f2fs_lookup_extent_cache(struct inode *inode, pgoff_t pgofs,
 
 void f2fs_update_extent_cache(struct dnode_of_data *dn)
 {
-       struct f2fs_inode_info *fi = F2FS_I(dn->inode);
        pgoff_t fofs;
+       block_t blkaddr;
 
        if (!f2fs_may_extent_tree(dn->inode))
                return;
 
-       f2fs_bug_on(F2FS_I_SB(dn->inode), dn->data_blkaddr == NEW_ADDR);
-
+       if (dn->data_blkaddr == NEW_ADDR)
+               blkaddr = NULL_ADDR;
+       else
+               blkaddr = dn->data_blkaddr;
 
-       fofs = start_bidx_of_node(ofs_of_node(dn->node_page), fi) +
-                                                       dn->ofs_in_node;
+       fofs = start_bidx_of_node(ofs_of_node(dn->node_page), dn->inode) +
+                                                               dn->ofs_in_node;
 
-       if (f2fs_update_extent_tree_range(dn->inode, fofs, dn->data_blkaddr, 1))
+       if (f2fs_update_extent_tree_range(dn->inode, fofs, blkaddr, 1))
                sync_inode_page(dn);
 }
 
index ff79054..bbe2cd1 100644 (file)
 #include <linux/vmalloc.h>
 #include <linux/bio.h>
 #include <linux/blkdev.h>
+#include <linux/fscrypto.h>
+#include <crypto/hash.h>
 
 #ifdef CONFIG_F2FS_CHECK_FS
 #define f2fs_bug_on(sbi, condition)    BUG_ON(condition)
-#define f2fs_down_write(x, y)  down_write_nest_lock(x, y)
 #else
 #define f2fs_bug_on(sbi, condition)                                    \
        do {                                                            \
@@ -34,7 +35,6 @@
                        set_sbi_flag(sbi, SBI_NEED_FSCK);               \
                }                                                       \
        } while (0)
-#define f2fs_down_write(x, y)  down_write(x)
 #endif
 
 /*
@@ -84,27 +84,6 @@ struct f2fs_mount_info {
 #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)
-{
-       unsigned char *p = (unsigned char *)buf;
-       __u32 crc = F2FS_SUPER_MAGIC;
-       int i;
-
-       while (len--) {
-               crc ^= *p++;
-               for (i = 0; i < 8; i++)
-                       crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_LE : 0);
-       }
-       return crc;
-}
-
-static inline bool f2fs_crc_valid(__u32 blk_crc, void *buf, size_t buf_size)
-{
-       return f2fs_crc32(buf, buf_size) == blk_crc;
-}
-
 /*
  * For checkpoint manager
  */
@@ -183,37 +162,37 @@ struct fsync_inode_entry {
        block_t last_inode;     /* block address locating the last inode */
 };
 
-#define nats_in_cursum(sum)            (le16_to_cpu(sum->n_nats))
-#define sits_in_cursum(sum)            (le16_to_cpu(sum->n_sits))
+#define nats_in_cursum(jnl)            (le16_to_cpu(jnl->n_nats))
+#define sits_in_cursum(jnl)            (le16_to_cpu(jnl->n_sits))
 
-#define nat_in_journal(sum, i)         (sum->nat_j.entries[i].ne)
-#define nid_in_journal(sum, i)         (sum->nat_j.entries[i].nid)
-#define sit_in_journal(sum, i)         (sum->sit_j.entries[i].se)
-#define segno_in_journal(sum, i)       (sum->sit_j.entries[i].segno)
+#define nat_in_journal(jnl, i)         (jnl->nat_j.entries[i].ne)
+#define nid_in_journal(jnl, i)         (jnl->nat_j.entries[i].nid)
+#define sit_in_journal(jnl, i)         (jnl->sit_j.entries[i].se)
+#define segno_in_journal(jnl, i)       (jnl->sit_j.entries[i].segno)
 
-#define MAX_NAT_JENTRIES(sum)  (NAT_JOURNAL_ENTRIES - nats_in_cursum(sum))
-#define MAX_SIT_JENTRIES(sum)  (SIT_JOURNAL_ENTRIES - sits_in_cursum(sum))
+#define MAX_NAT_JENTRIES(jnl)  (NAT_JOURNAL_ENTRIES - nats_in_cursum(jnl))
+#define MAX_SIT_JENTRIES(jnl)  (SIT_JOURNAL_ENTRIES - sits_in_cursum(jnl))
 
-static inline int update_nats_in_cursum(struct f2fs_summary_block *rs, int i)
+static inline int update_nats_in_cursum(struct f2fs_journal *journal, int i)
 {
-       int before = nats_in_cursum(rs);
-       rs->n_nats = cpu_to_le16(before + i);
+       int before = nats_in_cursum(journal);
+       journal->n_nats = cpu_to_le16(before + i);
        return before;
 }
 
-static inline int update_sits_in_cursum(struct f2fs_summary_block *rs, int i)
+static inline int update_sits_in_cursum(struct f2fs_journal *journal, int i)
 {
-       int before = sits_in_cursum(rs);
-       rs->n_sits = cpu_to_le16(before + i);
+       int before = sits_in_cursum(journal);
+       journal->n_sits = cpu_to_le16(before + i);
        return before;
 }
 
-static inline bool __has_cursum_space(struct f2fs_summary_block *sum, int size,
-                                                               int type)
+static inline bool __has_cursum_space(struct f2fs_journal *journal,
+                                                       int size, int type)
 {
        if (type == NAT_JOURNAL)
-               return size <= MAX_NAT_JENTRIES(sum);
-       return size <= MAX_SIT_JENTRIES(sum);
+               return size <= MAX_NAT_JENTRIES(journal);
+       return size <= MAX_SIT_JENTRIES(journal);
 }
 
 /*
@@ -233,12 +212,9 @@ static inline bool __has_cursum_space(struct f2fs_summary_block *sum, int size,
 #define F2FS_IOC_WRITE_CHECKPOINT      _IO(F2FS_IOCTL_MAGIC, 7)
 #define F2FS_IOC_DEFRAGMENT            _IO(F2FS_IOCTL_MAGIC, 8)
 
-#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)
+#define F2FS_IOC_SET_ENCRYPTION_POLICY FS_IOC_SET_ENCRYPTION_POLICY
+#define F2FS_IOC_GET_ENCRYPTION_POLICY FS_IOC_GET_ENCRYPTION_POLICY
+#define F2FS_IOC_GET_ENCRYPTION_PWSALT FS_IOC_GET_ENCRYPTION_PWSALT
 
 /*
  * should be same as XFS_IOC_GOINGDOWN.
@@ -268,25 +244,6 @@ struct f2fs_defragment {
  * 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;
@@ -354,6 +311,7 @@ struct extent_node {
        struct rb_node rb_node;         /* rb node located in rb-tree */
        struct list_head list;          /* node in global extent list of sbi */
        struct extent_info ei;          /* extent info */
+       struct extent_tree *et;         /* extent tree pointer */
 };
 
 struct extent_tree {
@@ -382,6 +340,7 @@ struct f2fs_map_blocks {
        block_t m_lblk;
        unsigned int m_len;
        unsigned int m_flags;
+       pgoff_t *m_next_pgofs;          /* point next possible non-hole pgofs */
 };
 
 /* for flag in get_data_block */
@@ -389,6 +348,8 @@ struct f2fs_map_blocks {
 #define F2FS_GET_BLOCK_DIO             1
 #define F2FS_GET_BLOCK_FIEMAP          2
 #define F2FS_GET_BLOCK_BMAP            3
+#define F2FS_GET_BLOCK_PRE_DIO         4
+#define F2FS_GET_BLOCK_PRE_AIO         5
 
 /*
  * i_advise uses FADVISE_XXX_BIT. We can add additional hints later.
@@ -410,15 +371,6 @@ struct f2fs_map_blocks {
 #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
 
 struct f2fs_inode_info {
@@ -442,13 +394,7 @@ struct f2fs_inode_info {
        struct list_head dirty_list;    /* linked in global dirty list */
        struct list_head inmem_pages;   /* inmemory pages managed by f2fs */
        struct mutex inmem_lock;        /* lock for inmemory pages */
-
        struct extent_tree *extent_tree;        /* cached extent_tree entry */
-
-#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,
@@ -515,6 +461,7 @@ struct f2fs_nm_info {
        nid_t next_scan_nid;            /* the next nid to be scanned */
        unsigned int ram_thresh;        /* control the memory footprint */
        unsigned int ra_nid_pages;      /* # of nid pages to be readaheaded */
+       unsigned int dirty_nats_ratio;  /* control dirty nats ratio threshold */
 
        /* NAT cache management */
        struct radix_tree_root nat_root;/* root of the nat entry cache */
@@ -549,6 +496,8 @@ struct dnode_of_data {
        unsigned int ofs_in_node;       /* data offset in the node page */
        bool inode_page_locked;         /* inode page is locked or not */
        bool node_changed;              /* is node block changed */
+       char cur_level;                 /* level of hole node page */
+       char max_level;                 /* level of current page located */
        block_t data_blkaddr;           /* block address of the node block */
 };
 
@@ -679,6 +628,7 @@ enum page_type {
        META_FLUSH,
        INMEM,          /* the below types are used by tracepoints only. */
        INMEM_DROP,
+       INMEM_REVOKE,
        IPU,
        OPU,
 };
@@ -687,7 +637,8 @@ 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 */
+       block_t new_blkaddr;    /* new block address to be written */
+       block_t old_blkaddr;    /* old block address before Cow */
        struct page *page;      /* page to be written */
        struct page *encrypted_page;    /* encrypted page */
 };
@@ -844,8 +795,22 @@ struct f2fs_sb_info {
        struct list_head s_list;
        struct mutex umount_mutex;
        unsigned int shrinker_run_no;
+
+       /* For write statistics */
+       u64 sectors_written_start;
+       u64 kbytes_written;
+
+       /* Reference to checksum algorithm driver via cryptoapi */
+       struct crypto_shash *s_chksum_driver;
 };
 
+/* For write statistics. Suppose sector size is 512 bytes,
+ * and the return value is in kbytes. s is of struct f2fs_sb_info.
+ */
+#define BD_PART_WRITTEN(s)                                              \
+(((u64)part_stat_read(s->sb->s_bdev->bd_part, sectors[1]) -             \
+               s->sectors_written_start) >> 1)
+
 static inline void f2fs_update_time(struct f2fs_sb_info *sbi, int type)
 {
        sbi->last_time[type] = jiffies;
@@ -874,6 +839,29 @@ static inline bool is_idle(struct f2fs_sb_info *sbi)
 /*
  * Inline functions
  */
+static inline u32 f2fs_crc32(struct f2fs_sb_info *sbi, const void *address,
+                          unsigned int length)
+{
+       SHASH_DESC_ON_STACK(shash, sbi->s_chksum_driver);
+       u32 *ctx = (u32 *)shash_desc_ctx(shash);
+       int err;
+
+       shash->tfm = sbi->s_chksum_driver;
+       shash->flags = 0;
+       *ctx = F2FS_SUPER_MAGIC;
+
+       err = crypto_shash_update(shash, address, length);
+       BUG_ON(err);
+
+       return *ctx;
+}
+
+static inline bool f2fs_crc_valid(struct f2fs_sb_info *sbi, __u32 blk_crc,
+                                 void *buf, size_t buf_size)
+{
+       return f2fs_crc32(sbi, buf, buf_size) == blk_crc;
+}
+
 static inline struct f2fs_inode_info *F2FS_I(struct inode *inode)
 {
        return container_of(inode, struct f2fs_inode_info, vfs_inode);
@@ -1006,7 +994,7 @@ static inline void f2fs_unlock_op(struct f2fs_sb_info *sbi)
 
 static inline void f2fs_lock_all(struct f2fs_sb_info *sbi)
 {
-       f2fs_down_write(&sbi->cp_rwsem, &sbi->cp_mutex);
+       down_write(&sbi->cp_rwsem);
 }
 
 static inline void f2fs_unlock_all(struct f2fs_sb_info *sbi)
@@ -1525,9 +1513,9 @@ static inline int f2fs_has_inline_xattr(struct inode *inode)
        return is_inode_flag_set(F2FS_I(inode), FI_INLINE_XATTR);
 }
 
-static inline unsigned int addrs_per_inode(struct f2fs_inode_info *fi)
+static inline unsigned int addrs_per_inode(struct inode *inode)
 {
-       if (f2fs_has_inline_xattr(&fi->vfs_inode))
+       if (f2fs_has_inline_xattr(inode))
                return DEF_ADDRS_PER_INODE - F2FS_INLINE_XATTR_ADDRS;
        return DEF_ADDRS_PER_INODE;
 }
@@ -1681,10 +1669,10 @@ static inline void *f2fs_kvzalloc(size_t size, gfp_t flags)
         (F2FS_I(i)->i_acl_mode) : ((i)->i_mode))
 
 /* get offset of first page in next direct node */
-#define PGOFS_OF_NEXT_DNODE(pgofs, fi)                         \
-       ((pgofs < ADDRS_PER_INODE(fi)) ? ADDRS_PER_INODE(fi) :  \
-       (pgofs - ADDRS_PER_INODE(fi) + ADDRS_PER_BLOCK) /       \
-       ADDRS_PER_BLOCK * ADDRS_PER_BLOCK + ADDRS_PER_INODE(fi))
+#define PGOFS_OF_NEXT_DNODE(pgofs, inode)                              \
+       ((pgofs < ADDRS_PER_INODE(inode)) ? ADDRS_PER_INODE(inode) :    \
+       (pgofs - ADDRS_PER_INODE(inode) + ADDRS_PER_BLOCK) /    \
+       ADDRS_PER_BLOCK * ADDRS_PER_BLOCK + ADDRS_PER_INODE(inode))
 
 /*
  * file.c
@@ -1723,10 +1711,10 @@ 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 f2fs_filename *,
+struct f2fs_dir_entry *find_target_dentry(struct fscrypt_name *,
                        f2fs_hash_t, int *, struct f2fs_dentry_ptr *);
 bool f2fs_fill_dentries(struct dir_context *, struct f2fs_dentry_ptr *,
-                       unsigned int, struct f2fs_str *);
+                       unsigned int, struct fscrypt_str *);
 void do_make_empty_dir(struct inode *, struct inode *,
                        struct f2fs_dentry_ptr *);
 struct page *init_inode_metadata(struct inode *, struct inode *,
@@ -1763,6 +1751,7 @@ 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 *, ...);
+int sanity_check_ckpt(struct f2fs_sb_info *sbi);
 
 /*
  * hash.c
@@ -1780,6 +1769,7 @@ int need_dentry_mark(struct f2fs_sb_info *, nid_t);
 bool is_checkpointed_node(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 *);
+pgoff_t get_next_page_offset(struct dnode_of_data *, pgoff_t);
 int get_dnode_of_data(struct dnode_of_data *, pgoff_t, int);
 int truncate_inode_blocks(struct inode *, pgoff_t);
 int truncate_xattr_node(struct inode *, struct page *);
@@ -1811,7 +1801,8 @@ void destroy_node_manager_caches(void);
  * segment.c
  */
 void register_inmem_page(struct inode *, struct page *);
-int commit_inmem_pages(struct inode *, bool);
+void drop_inmem_pages(struct inode *);
+int commit_inmem_pages(struct inode *);
 void f2fs_balance_fs(struct f2fs_sb_info *, bool);
 void f2fs_balance_fs_bg(struct f2fs_sb_info *);
 int f2fs_issue_flush(struct f2fs_sb_info *);
@@ -1832,16 +1823,17 @@ void write_meta_page(struct f2fs_sb_info *, struct page *);
 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 f2fs_summary *,
+                                       block_t, block_t, bool, bool);
 void f2fs_replace_block(struct f2fs_sb_info *, struct dnode_of_data *,
-                               block_t, block_t, unsigned char, bool);
+                               block_t, block_t, unsigned char, bool, 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);
+void f2fs_wait_on_page_writeback(struct page *, enum page_type, bool);
 void f2fs_wait_on_encrypted_page_writeback(struct f2fs_sb_info *, block_t);
 void write_data_summaries(struct f2fs_sb_info *, block_t);
 void write_node_summaries(struct f2fs_sb_info *, block_t);
-int lookup_journal_in_cursum(struct f2fs_summary_block *,
-                                       int, unsigned int, int);
+int lookup_journal_in_cursum(struct f2fs_journal *, int, unsigned int, int);
 void flush_sit_entries(struct f2fs_sb_info *, struct cp_control *);
 int build_segment_manager(struct f2fs_sb_info *);
 void destroy_segment_manager(struct f2fs_sb_info *);
@@ -1881,11 +1873,16 @@ void destroy_checkpoint_caches(void);
  * data.c
  */
 void f2fs_submit_merged_bio(struct f2fs_sb_info *, enum page_type, int);
+void f2fs_submit_merged_bio_cond(struct f2fs_sb_info *, struct inode *,
+                               struct page *, nid_t, enum page_type, int);
+void f2fs_flush_merged_bios(struct f2fs_sb_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 *);
+void f2fs_update_data_blkaddr(struct dnode_of_data *, block_t);
 int reserve_new_block(struct dnode_of_data *);
 int f2fs_get_block(struct dnode_of_data *, pgoff_t);
+ssize_t f2fs_preallocate_blocks(struct kiocb *, struct iov_iter *);
 int f2fs_reserve_block(struct dnode_of_data *, pgoff_t);
 struct page *get_read_data_page(struct inode *, pgoff_t, int, bool);
 struct page *find_data_page(struct inode *, pgoff_t);
@@ -1902,7 +1899,7 @@ int f2fs_release_page(struct page *, gfp_t);
  */
 int start_gc_thread(struct f2fs_sb_info *);
 void stop_gc_thread(struct f2fs_sb_info *);
-block_t start_bidx_of_node(unsigned int, struct f2fs_inode_info *);
+block_t start_bidx_of_node(unsigned int, struct inode *);
 int f2fs_gc(struct f2fs_sb_info *, bool);
 void build_gc_manager(struct f2fs_sb_info *);
 
@@ -2093,7 +2090,7 @@ 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 f2fs_filename *, struct page **);
+                               struct fscrypt_name *, 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 *,
@@ -2102,7 +2099,7 @@ 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 *,
-                                               struct f2fs_str *);
+                                               struct fscrypt_str *);
 int f2fs_inline_data_fiemap(struct inode *,
                struct fiemap_extent_info *, __u64, __u64);
 
@@ -2132,13 +2129,9 @@ void destroy_extent_cache(void);
 /*
  * crypto support
  */
-static inline int f2fs_encrypted_inode(struct inode *inode)
+static inline bool 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)
@@ -2150,20 +2143,12 @@ static inline void f2fs_set_encrypted_inode(struct inode *inode)
 
 static inline bool f2fs_bio_encrypted(struct bio *bio)
 {
-#ifdef CONFIG_F2FS_FS_ENCRYPTION
-       return unlikely(bio->bi_private != NULL);
-#else
-       return false;
-#endif
+       return bio->bi_private != NULL;
 }
 
 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)
@@ -2177,86 +2162,28 @@ static inline bool f2fs_may_encrypt(struct inode *inode)
 #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) { }
+#ifndef CONFIG_F2FS_FS_ENCRYPTION
+#define fscrypt_set_d_op(i)
+#define fscrypt_get_ctx                        fscrypt_notsupp_get_ctx
+#define fscrypt_release_ctx            fscrypt_notsupp_release_ctx
+#define fscrypt_encrypt_page           fscrypt_notsupp_encrypt_page
+#define fscrypt_decrypt_page           fscrypt_notsupp_decrypt_page
+#define fscrypt_decrypt_bio_pages      fscrypt_notsupp_decrypt_bio_pages
+#define fscrypt_pullback_bio_page      fscrypt_notsupp_pullback_bio_page
+#define fscrypt_restore_control_page   fscrypt_notsupp_restore_control_page
+#define fscrypt_zeroout_range          fscrypt_notsupp_zeroout_range
+#define fscrypt_process_policy         fscrypt_notsupp_process_policy
+#define fscrypt_get_policy             fscrypt_notsupp_get_policy
+#define fscrypt_has_permitted_context  fscrypt_notsupp_has_permitted_context
+#define fscrypt_inherit_context                fscrypt_notsupp_inherit_context
+#define fscrypt_get_encryption_info    fscrypt_notsupp_get_encryption_info
+#define fscrypt_put_encryption_info    fscrypt_notsupp_put_encryption_info
+#define fscrypt_setup_filename         fscrypt_notsupp_setup_filename
+#define fscrypt_free_filename          fscrypt_notsupp_free_filename
+#define fscrypt_fname_encrypted_size   fscrypt_notsupp_fname_encrypted_size
+#define fscrypt_fname_alloc_buffer     fscrypt_notsupp_fname_alloc_buffer
+#define fscrypt_fname_free_buffer      fscrypt_notsupp_fname_free_buffer
+#define fscrypt_fname_disk_to_usr      fscrypt_notsupp_fname_disk_to_usr
+#define fscrypt_fname_usr_to_disk      fscrypt_notsupp_fname_usr_to_disk
 #endif
 #endif
diff --git a/fs/f2fs/f2fs_crypto.h b/fs/f2fs/f2fs_crypto.h
deleted file mode 100644 (file)
index ea3d1d7..0000000
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * 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_skcipher *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 */
index ea272be..b41c357 100644 (file)
@@ -86,7 +86,7 @@ static int f2fs_vm_page_mkwrite(struct vm_area_struct *vma,
        trace_f2fs_vm_page_mkwrite(page, DATA);
 mapped:
        /* fill the page */
-       f2fs_wait_on_page_writeback(page, DATA);
+       f2fs_wait_on_page_writeback(page, DATA, false);
 
        /* wait for GCed encrypted page writeback */
        if (f2fs_encrypted_inode(inode) && S_ISREG(inode->i_mode))
@@ -301,7 +301,7 @@ static pgoff_t __get_first_dirty_index(struct address_space *mapping,
        pagevec_init(&pvec, 0);
        nr_pages = pagevec_lookup_tag(&pvec, mapping, &pgofs,
                                        PAGECACHE_TAG_DIRTY, 1);
-       pgofs = nr_pages ? pvec.pages[0]->index : LONG_MAX;
+       pgofs = nr_pages ? pvec.pages[0]->index : ULONG_MAX;
        pagevec_release(&pvec);
        return pgofs;
 }
@@ -358,15 +358,14 @@ static loff_t f2fs_seek_block(struct file *file, loff_t offset, int whence)
                } else if (err == -ENOENT) {
                        /* direct node does not exists */
                        if (whence == SEEK_DATA) {
-                               pgofs = PGOFS_OF_NEXT_DNODE(pgofs,
-                                                       F2FS_I(inode));
+                               pgofs = get_next_page_offset(&dn, pgofs);
                                continue;
                        } else {
                                goto found;
                        }
                }
 
-               end_offset = ADDRS_PER_PAGE(dn.node_page, F2FS_I(inode));
+               end_offset = ADDRS_PER_PAGE(dn.node_page, inode);
 
                /* find data/hole in dnode block */
                for (; dn.ofs_in_node < end_offset;
@@ -422,9 +421,11 @@ static int f2fs_file_mmap(struct file *file, struct vm_area_struct *vma)
        int err;
 
        if (f2fs_encrypted_inode(inode)) {
-               err = f2fs_get_encryption_info(inode);
+               err = fscrypt_get_encryption_info(inode);
                if (err)
                        return 0;
+               if (!f2fs_encrypted_inode(inode))
+                       return -ENOKEY;
        }
 
        /* we don't need to use inline_data strictly */
@@ -440,12 +441,18 @@ static int f2fs_file_mmap(struct file *file, struct vm_area_struct *vma)
 static int f2fs_file_open(struct inode *inode, struct file *filp)
 {
        int ret = generic_file_open(inode, filp);
+       struct inode *dir = filp->f_path.dentry->d_parent->d_inode;
 
        if (!ret && f2fs_encrypted_inode(inode)) {
-               ret = f2fs_get_encryption_info(inode);
+               ret = fscrypt_get_encryption_info(inode);
                if (ret)
-                       ret = -EACCES;
+                       return -EACCES;
+               if (!fscrypt_has_encryption_key(inode))
+                       return -ENOKEY;
        }
+       if (f2fs_encrypted_inode(dir) &&
+                       !fscrypt_has_permitted_context(dir, inode))
+               return -EPERM;
        return ret;
 }
 
@@ -480,7 +487,7 @@ int truncate_data_blocks_range(struct dnode_of_data *dn, int count)
                 * we will invalidate all blkaddr in the whole range.
                 */
                fofs = start_bidx_of_node(ofs_of_node(dn->node_page),
-                                               F2FS_I(dn->inode)) + ofs;
+                                                       dn->inode) + ofs;
                f2fs_update_extent_cache_range(dn, fofs, 0, len);
                dec_valid_block_count(sbi, dn->inode, nr_free);
                sync_inode_page(dn);
@@ -521,9 +528,10 @@ static int truncate_partial_data_page(struct inode *inode, u64 from,
        if (IS_ERR(page))
                return 0;
 truncate_out:
-       f2fs_wait_on_page_writeback(page, DATA);
+       f2fs_wait_on_page_writeback(page, DATA, true);
        zero_user(page, offset, PAGE_CACHE_SIZE - offset);
-       if (!cache_only || !f2fs_encrypted_inode(inode) || !S_ISREG(inode->i_mode))
+       if (!cache_only || !f2fs_encrypted_inode(inode) ||
+                                       !S_ISREG(inode->i_mode))
                set_page_dirty(page);
        f2fs_put_page(page, 1);
        return 0;
@@ -568,7 +576,7 @@ int truncate_blocks(struct inode *inode, u64 from, bool lock)
                goto out;
        }
 
-       count = ADDRS_PER_PAGE(dn.node_page, F2FS_I(inode));
+       count = ADDRS_PER_PAGE(dn.node_page, inode);
 
        count -= dn.ofs_in_node;
        f2fs_bug_on(sbi, count < 0);
@@ -671,7 +679,7 @@ int f2fs_setattr(struct dentry *dentry, struct iattr *attr)
 
        if (attr->ia_valid & ATTR_SIZE) {
                if (f2fs_encrypted_inode(inode) &&
-                               f2fs_get_encryption_info(inode))
+                               fscrypt_get_encryption_info(inode))
                        return -EACCES;
 
                if (attr->ia_size <= i_size_read(inode)) {
@@ -743,7 +751,7 @@ static int fill_zero(struct inode *inode, pgoff_t index,
        if (IS_ERR(page))
                return PTR_ERR(page);
 
-       f2fs_wait_on_page_writeback(page, DATA);
+       f2fs_wait_on_page_writeback(page, DATA, true);
        zero_user(page, start, len);
        set_page_dirty(page);
        f2fs_put_page(page, 1);
@@ -768,7 +776,7 @@ int truncate_hole(struct inode *inode, pgoff_t pg_start, pgoff_t pg_end)
                        return err;
                }
 
-               end_offset = ADDRS_PER_PAGE(dn.node_page, F2FS_I(inode));
+               end_offset = ADDRS_PER_PAGE(dn.node_page, inode);
                count = min(end_offset - dn.ofs_in_node, pg_end - pg_start);
 
                f2fs_bug_on(F2FS_I_SB(inode), count == 0 || count > end_offset);
@@ -854,10 +862,8 @@ static int __exchange_data_block(struct inode *inode, pgoff_t src,
        } else {
                new_addr = dn.data_blkaddr;
                if (!is_checkpointed_data(sbi, new_addr)) {
-                       dn.data_blkaddr = NULL_ADDR;
                        /* do not invalidate this block address */
-                       set_data_blkaddr(&dn);
-                       f2fs_update_extent_cache(&dn);
+                       f2fs_update_data_blkaddr(&dn, NULL_ADDR);
                        do_replace = true;
                }
                f2fs_put_dnode(&dn);
@@ -884,7 +890,7 @@ static int __exchange_data_block(struct inode *inode, pgoff_t src,
 
                get_node_info(sbi, dn.nid, &ni);
                f2fs_replace_block(sbi, &dn, dn.data_blkaddr, new_addr,
-                               ni.version, true);
+                               ni.version, true, false);
                f2fs_put_dnode(&dn);
        } else {
                struct page *psrc, *pdst;
@@ -892,7 +898,7 @@ static int __exchange_data_block(struct inode *inode, pgoff_t src,
                psrc = get_lock_data_page(inode, src, true);
                if (IS_ERR(psrc))
                        return PTR_ERR(psrc);
-               pdst = get_new_data_page(inode, NULL, dst, false);
+               pdst = get_new_data_page(inode, NULL, dst, true);
                if (IS_ERR(pdst)) {
                        f2fs_put_page(psrc, 1);
                        return PTR_ERR(pdst);
@@ -908,9 +914,7 @@ static int __exchange_data_block(struct inode *inode, pgoff_t src,
 
 err_out:
        if (!get_dnode_of_data(&dn, src, LOOKUP_NODE)) {
-               dn.data_blkaddr = new_addr;
-               set_data_blkaddr(&dn);
-               f2fs_update_extent_cache(&dn);
+               f2fs_update_data_blkaddr(&dn, new_addr);
                f2fs_put_dnode(&dn);
        }
        return ret;
@@ -1050,12 +1054,7 @@ static int f2fs_zero_range(struct inode *inode, loff_t offset, loff_t len,
 
                        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_update_data_blkaddr(&dn, NEW_ADDR);
                        }
                        f2fs_put_dnode(&dn);
                        f2fs_unlock_op(sbi);
@@ -1253,7 +1252,7 @@ static int f2fs_release_file(struct inode *inode, struct file *filp)
 {
        /* some remained atomic pages should discarded */
        if (f2fs_is_atomic_file(inode))
-               commit_inmem_pages(inode, true);
+               drop_inmem_pages(inode);
        if (f2fs_is_volatile_file(inode)) {
                set_inode_flag(F2FS_I(inode), FI_DROP_CACHE);
                filemap_fdatawrite(inode->i_mapping);
@@ -1377,7 +1376,7 @@ static int f2fs_ioc_commit_atomic_write(struct file *filp)
 
        if (f2fs_is_atomic_file(inode)) {
                clear_inode_flag(F2FS_I(inode), FI_ATOMIC_FILE);
-               ret = commit_inmem_pages(inode, false);
+               ret = commit_inmem_pages(inode);
                if (ret) {
                        set_inode_flag(F2FS_I(inode), FI_ATOMIC_FILE);
                        goto err_out;
@@ -1440,7 +1439,7 @@ static int f2fs_ioc_abort_volatile_write(struct file *filp)
 
        if (f2fs_is_atomic_file(inode)) {
                clear_inode_flag(F2FS_I(inode), FI_ATOMIC_FILE);
-               commit_inmem_pages(inode, true);
+               drop_inmem_pages(inode);
        }
        if (f2fs_is_volatile_file(inode)) {
                clear_inode_flag(F2FS_I(inode), FI_VOLATILE_FILE);
@@ -1535,39 +1534,30 @@ static bool uuid_is_nonzero(__u8 u[16])
 
 static int f2fs_ioc_set_encryption_policy(struct file *filp, unsigned long arg)
 {
-#ifdef CONFIG_F2FS_FS_ENCRYPTION
-       struct f2fs_encryption_policy policy;
+       struct fscrypt_policy policy;
        struct inode *inode = file_inode(filp);
 
-       if (copy_from_user(&policy, (struct f2fs_encryption_policy __user *)arg,
-                               sizeof(policy)))
+       if (copy_from_user(&policy, (struct fscrypt_policy __user *)arg,
+                                                       sizeof(policy)))
                return -EFAULT;
 
        f2fs_update_time(F2FS_I_SB(inode), REQ_TIME);
-       return f2fs_process_policy(&policy, inode);
-#else
-       return -EOPNOTSUPP;
-#endif
+       return fscrypt_process_policy(inode, &policy);
 }
 
 static int f2fs_ioc_get_encryption_policy(struct file *filp, unsigned long arg)
 {
-#ifdef CONFIG_F2FS_FS_ENCRYPTION
-       struct f2fs_encryption_policy policy;
+       struct fscrypt_policy policy;
        struct inode *inode = file_inode(filp);
        int err;
 
-       err = f2fs_get_policy(inode, &policy);
+       err = fscrypt_get_policy(inode, &policy);
        if (err)
                return err;
 
-       if (copy_to_user((struct f2fs_encryption_policy __user *)arg, &policy,
-                                                       sizeof(policy)))
+       if (copy_to_user((struct fscrypt_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)
@@ -1648,7 +1638,7 @@ static int f2fs_defragment_range(struct f2fs_sb_info *sbi,
                                        struct f2fs_defragment *range)
 {
        struct inode *inode = file_inode(filp);
-       struct f2fs_map_blocks map;
+       struct f2fs_map_blocks map = { .m_next_pgofs = NULL };
        struct extent_info ei;
        pgoff_t pg_start, pg_end;
        unsigned int blk_per_seg = sbi->blocks_per_seg;
@@ -1874,14 +1864,32 @@ long f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 
 static ssize_t f2fs_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
 {
-       struct inode *inode = file_inode(iocb->ki_filp);
+       struct file *file = iocb->ki_filp;
+       struct inode *inode = file_inode(file);
+       ssize_t ret;
 
        if (f2fs_encrypted_inode(inode) &&
-                               !f2fs_has_encryption_key(inode) &&
-                               f2fs_get_encryption_info(inode))
+                               !fscrypt_has_encryption_key(inode) &&
+                               fscrypt_get_encryption_info(inode))
                return -EACCES;
 
-       return generic_file_write_iter(iocb, from);
+       inode_lock(inode);
+       ret = generic_write_checks(iocb, from);
+       if (ret > 0) {
+               ret = f2fs_preallocate_blocks(iocb, from);
+               if (!ret)
+                       ret = __generic_file_write_iter(iocb, from);
+       }
+       inode_unlock(inode);
+
+       if (ret > 0) {
+               ssize_t err;
+
+               err = generic_write_sync(file, iocb->ki_pos - ret, ret);
+               if (err < 0)
+                       ret = err;
+       }
+       return ret;
 }
 
 #ifdef CONFIG_COMPAT
index f610c2a..b0051a9 100644 (file)
@@ -245,6 +245,18 @@ static inline unsigned int get_gc_cost(struct f2fs_sb_info *sbi,
                return get_cb_cost(sbi, segno);
 }
 
+static unsigned int count_bits(const unsigned long *addr,
+                               unsigned int offset, unsigned int len)
+{
+       unsigned int end = offset + len, sum = 0;
+
+       while (offset < end) {
+               if (test_bit(offset++, addr))
+                       ++sum;
+       }
+       return sum;
+}
+
 /*
  * This function is called from two paths.
  * One is garbage collection and the other is SSR segment selection.
@@ -258,9 +270,9 @@ static int get_victim_by_default(struct f2fs_sb_info *sbi,
 {
        struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
        struct victim_sel_policy p;
-       unsigned int secno, max_cost;
+       unsigned int secno, max_cost, last_victim;
        unsigned int last_segment = MAIN_SEGS(sbi);
-       int nsearched = 0;
+       unsigned int nsearched = 0;
 
        mutex_lock(&dirty_i->seglist_lock);
 
@@ -273,6 +285,7 @@ static int get_victim_by_default(struct f2fs_sb_info *sbi,
        if (p.max_search == 0)
                goto out;
 
+       last_victim = sbi->last_victim[p.gc_mode];
        if (p.alloc_mode == LFS && gc_type == FG_GC) {
                p.min_segno = check_bg_victims(sbi);
                if (p.min_segno != NULL_SEGNO)
@@ -295,27 +308,35 @@ static int get_victim_by_default(struct f2fs_sb_info *sbi,
                }
 
                p.offset = segno + p.ofs_unit;
-               if (p.ofs_unit > 1)
+               if (p.ofs_unit > 1) {
                        p.offset -= segno % p.ofs_unit;
+                       nsearched += count_bits(p.dirty_segmap,
+                                               p.offset - p.ofs_unit,
+                                               p.ofs_unit);
+               } else {
+                       nsearched++;
+               }
+
 
                secno = GET_SECNO(sbi, segno);
 
                if (sec_usage_check(sbi, secno))
-                       continue;
+                       goto next;
                if (gc_type == BG_GC && test_bit(secno, dirty_i->victim_secmap))
-                       continue;
+                       goto next;
 
                cost = get_gc_cost(sbi, segno, &p);
 
                if (p.min_cost > cost) {
                        p.min_segno = segno;
                        p.min_cost = cost;
-               } else if (unlikely(cost == max_cost)) {
-                       continue;
                }
-
-               if (nsearched++ >= p.max_search) {
-                       sbi->last_victim[p.gc_mode] = segno;
+next:
+               if (nsearched >= p.max_search) {
+                       if (!sbi->last_victim[p.gc_mode] && segno <= last_victim)
+                               sbi->last_victim[p.gc_mode] = last_victim + 1;
+                       else
+                               sbi->last_victim[p.gc_mode] = segno + 1;
                        break;
                }
        }
@@ -399,7 +420,7 @@ static int check_valid_map(struct f2fs_sb_info *sbi,
  * On validity, copy that node with cold status, otherwise (invalid node)
  * ignore that.
  */
-static int gc_node_segment(struct f2fs_sb_info *sbi,
+static void gc_node_segment(struct f2fs_sb_info *sbi,
                struct f2fs_summary *sum, unsigned int segno, int gc_type)
 {
        bool initial = true;
@@ -419,7 +440,7 @@ next_step:
 
                /* stop BG_GC if there is not enough free sections. */
                if (gc_type == BG_GC && has_not_enough_free_secs(sbi, 0))
-                       return 0;
+                       return;
 
                if (check_valid_map(sbi, segno, off) == 0)
                        continue;
@@ -446,7 +467,7 @@ next_step:
 
                /* set page dirty and write it */
                if (gc_type == FG_GC) {
-                       f2fs_wait_on_page_writeback(node_page, NODE);
+                       f2fs_wait_on_page_writeback(node_page, NODE, true);
                        set_page_dirty(node_page);
                } else {
                        if (!PageWriteback(node_page))
@@ -460,20 +481,6 @@ next_step:
                initial = false;
                goto next_step;
        }
-
-       if (gc_type == FG_GC) {
-               struct writeback_control wbc = {
-                       .sync_mode = WB_SYNC_ALL,
-                       .nr_to_write = LONG_MAX,
-                       .for_reclaim = 0,
-               };
-               sync_node_pages(sbi, 0, &wbc);
-
-               /* return 1 only if FG_GC succefully reclaimed one */
-               if (get_valid_blocks(sbi, segno, 1) == 0)
-                       return 1;
-       }
-       return 0;
 }
 
 /*
@@ -483,7 +490,7 @@ next_step:
  * as indirect or double indirect node blocks, are given, it must be a caller's
  * bug.
  */
-block_t start_bidx_of_node(unsigned int node_ofs, struct f2fs_inode_info *fi)
+block_t start_bidx_of_node(unsigned int node_ofs, struct inode *inode)
 {
        unsigned int indirect_blks = 2 * NIDS_PER_BLOCK + 4;
        unsigned int bidx;
@@ -500,7 +507,7 @@ block_t start_bidx_of_node(unsigned int node_ofs, struct f2fs_inode_info *fi)
                int dec = (node_ofs - indirect_blks - 3) / (NIDS_PER_BLOCK + 1);
                bidx = node_ofs - 5 - dec;
        }
-       return bidx * ADDRS_PER_BLOCK + ADDRS_PER_INODE(fi);
+       return bidx * ADDRS_PER_BLOCK + ADDRS_PER_INODE(inode);
 }
 
 static bool is_alive(struct f2fs_sb_info *sbi, struct f2fs_summary *sum,
@@ -546,6 +553,7 @@ static void move_encrypted_block(struct inode *inode, block_t bidx)
        struct f2fs_summary sum;
        struct node_info ni;
        struct page *page;
+       block_t newaddr;
        int err;
 
        /* do not read out */
@@ -567,21 +575,24 @@ static void move_encrypted_block(struct inode *inode, block_t bidx)
         * don't cache encrypted data into meta inode until previous dirty
         * data were writebacked to avoid racing between GC and flush.
         */
-       f2fs_wait_on_page_writeback(page, DATA);
+       f2fs_wait_on_page_writeback(page, DATA, true);
 
        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.new_blkaddr = fio.old_blkaddr = dn.data_blkaddr;
 
-       fio.encrypted_page = pagecache_get_page(META_MAPPING(fio.sbi),
-                                       fio.blk_addr,
-                                       FGP_LOCK|FGP_CREAT,
-                                       GFP_NOFS);
-       if (!fio.encrypted_page)
-               goto put_out;
+       allocate_data_block(fio.sbi, NULL, fio.old_blkaddr, &newaddr,
+                                                       &sum, CURSEG_COLD_DATA);
+
+       fio.encrypted_page = pagecache_get_page(META_MAPPING(fio.sbi), newaddr,
+                                       FGP_LOCK | FGP_CREAT, GFP_NOFS);
+       if (!fio.encrypted_page) {
+               err = -ENOMEM;
+               goto recover_block;
+       }
 
        err = f2fs_submit_page_bio(&fio);
        if (err)
@@ -590,33 +601,39 @@ static void move_encrypted_block(struct inode *inode, block_t bidx)
        /* write page */
        lock_page(fio.encrypted_page);
 
-       if (unlikely(!PageUptodate(fio.encrypted_page)))
+       if (unlikely(!PageUptodate(fio.encrypted_page))) {
+               err = -EIO;
                goto put_page_out;
-       if (unlikely(fio.encrypted_page->mapping != META_MAPPING(fio.sbi)))
+       }
+       if (unlikely(fio.encrypted_page->mapping != META_MAPPING(fio.sbi))) {
+               err = -EIO;
                goto put_page_out;
+       }
 
        set_page_dirty(fio.encrypted_page);
-       f2fs_wait_on_page_writeback(fio.encrypted_page, DATA);
+       f2fs_wait_on_page_writeback(fio.encrypted_page, DATA, true);
        if (clear_page_dirty_for_io(fio.encrypted_page))
                dec_page_count(fio.sbi, F2FS_DIRTY_META);
 
        set_page_writeback(fio.encrypted_page);
 
        /* 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);
+       f2fs_wait_on_page_writeback(dn.node_page, NODE, true);
+
        fio.rw = WRITE_SYNC;
+       fio.new_blkaddr = newaddr;
        f2fs_submit_page_mbio(&fio);
 
-       dn.data_blkaddr = fio.blk_addr;
-       set_data_blkaddr(&dn);
-       f2fs_update_extent_cache(&dn);
+       f2fs_update_data_blkaddr(&dn, newaddr);
        set_inode_flag(F2FS_I(inode), FI_APPEND_WRITE);
        if (page->index == 0)
                set_inode_flag(F2FS_I(inode), FI_FIRST_BLOCK_WRITTEN);
 put_page_out:
        f2fs_put_page(fio.encrypted_page, 1);
+recover_block:
+       if (err)
+               __f2fs_replace_block(fio.sbi, &sum, newaddr, fio.old_blkaddr,
+                                                               true, true);
 put_out:
        f2fs_put_dnode(&dn);
 out:
@@ -645,7 +662,7 @@ static void move_data_page(struct inode *inode, block_t bidx, int gc_type)
                        .encrypted_page = NULL,
                };
                set_page_dirty(page);
-               f2fs_wait_on_page_writeback(page, DATA);
+               f2fs_wait_on_page_writeback(page, DATA, true);
                if (clear_page_dirty_for_io(page))
                        inode_dec_dirty_pages(inode);
                set_cold_data(page);
@@ -663,7 +680,7 @@ out:
  * If the parent node is not valid or the data block address is different,
  * the victim data block is ignored.
  */
-static int gc_data_segment(struct f2fs_sb_info *sbi, struct f2fs_summary *sum,
+static void gc_data_segment(struct f2fs_sb_info *sbi, struct f2fs_summary *sum,
                struct gc_inode_list *gc_list, unsigned int segno, int gc_type)
 {
        struct super_block *sb = sbi->sb;
@@ -686,7 +703,7 @@ next_step:
 
                /* stop BG_GC if there is not enough free sections. */
                if (gc_type == BG_GC && has_not_enough_free_secs(sbi, 0))
-                       return 0;
+                       return;
 
                if (check_valid_map(sbi, segno, off) == 0)
                        continue;
@@ -719,7 +736,7 @@ next_step:
                                continue;
                        }
 
-                       start_bidx = start_bidx_of_node(nofs, F2FS_I(inode));
+                       start_bidx = start_bidx_of_node(nofs, inode);
                        data_page = get_read_data_page(inode,
                                        start_bidx + ofs_in_node, READA, true);
                        if (IS_ERR(data_page)) {
@@ -735,7 +752,7 @@ next_step:
                /* phase 3 */
                inode = find_gc_inode(gc_list, dni.ino);
                if (inode) {
-                       start_bidx = start_bidx_of_node(nofs, F2FS_I(inode))
+                       start_bidx = start_bidx_of_node(nofs, inode)
                                                                + ofs_in_node;
                        if (f2fs_encrypted_inode(inode) && S_ISREG(inode->i_mode))
                                move_encrypted_block(inode, start_bidx);
@@ -747,15 +764,6 @@ next_step:
 
        if (++phase < 4)
                goto next_step;
-
-       if (gc_type == FG_GC) {
-               f2fs_submit_merged_bio(sbi, DATA, WRITE);
-
-               /* return 1 only if FG_GC succefully reclaimed one */
-               if (get_valid_blocks(sbi, segno, 1) == 0)
-                       return 1;
-       }
-       return 0;
 }
 
 static int __get_victim(struct f2fs_sb_info *sbi, unsigned int *victim,
@@ -771,53 +779,92 @@ static int __get_victim(struct f2fs_sb_info *sbi, unsigned int *victim,
        return ret;
 }
 
-static int do_garbage_collect(struct f2fs_sb_info *sbi, unsigned int segno,
+static int do_garbage_collect(struct f2fs_sb_info *sbi,
+                               unsigned int start_segno,
                                struct gc_inode_list *gc_list, int gc_type)
 {
        struct page *sum_page;
        struct f2fs_summary_block *sum;
        struct blk_plug plug;
-       int nfree = 0;
+       unsigned int segno = start_segno;
+       unsigned int end_segno = start_segno + sbi->segs_per_sec;
+       int seg_freed = 0;
+       unsigned char type = IS_DATASEG(get_seg_entry(sbi, segno)->type) ?
+                                               SUM_TYPE_DATA : SUM_TYPE_NODE;
 
-       /* read segment summary of victim */
-       sum_page = get_sum_page(sbi, segno);
+       /* readahead multi ssa blocks those have contiguous address */
+       if (sbi->segs_per_sec > 1)
+               ra_meta_pages(sbi, GET_SUM_BLOCK(sbi, segno),
+                                       sbi->segs_per_sec, META_SSA, true);
+
+       /* reference all summary page */
+       while (segno < end_segno) {
+               sum_page = get_sum_page(sbi, segno++);
+               unlock_page(sum_page);
+       }
 
        blk_start_plug(&plug);
 
-       sum = page_address(sum_page);
+       for (segno = start_segno; segno < end_segno; segno++) {
+               /* find segment summary of victim */
+               sum_page = find_get_page(META_MAPPING(sbi),
+                                       GET_SUM_BLOCK(sbi, segno));
+               f2fs_bug_on(sbi, !PageUptodate(sum_page));
+               f2fs_put_page(sum_page, 0);
 
-       /*
-        * 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:
-               nfree = gc_node_segment(sbi, sum->entries, segno, gc_type);
-               break;
-       case SUM_TYPE_DATA:
-               nfree = gc_data_segment(sbi, sum->entries, gc_list,
-                                                       segno, gc_type);
-               break;
+               sum = page_address(sum_page);
+               f2fs_bug_on(sbi, type != GET_SUM_TYPE((&sum->footer)));
+
+               /*
+                * 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)
+                */
+
+               if (type == SUM_TYPE_NODE)
+                       gc_node_segment(sbi, sum->entries, segno, gc_type);
+               else
+                       gc_data_segment(sbi, sum->entries, gc_list, segno,
+                                                               gc_type);
+
+               stat_inc_seg_count(sbi, type, gc_type);
+
+               f2fs_put_page(sum_page, 0);
+       }
+
+       if (gc_type == FG_GC) {
+               if (type == SUM_TYPE_NODE) {
+                       struct writeback_control wbc = {
+                               .sync_mode = WB_SYNC_ALL,
+                               .nr_to_write = LONG_MAX,
+                               .for_reclaim = 0,
+                       };
+                       sync_node_pages(sbi, 0, &wbc);
+               } else {
+                       f2fs_submit_merged_bio(sbi, DATA, WRITE);
+               }
        }
+
        blk_finish_plug(&plug);
 
-       stat_inc_seg_count(sbi, GET_SUM_TYPE((&sum->footer)), gc_type);
+       if (gc_type == FG_GC) {
+               while (start_segno < end_segno)
+                       if (get_valid_blocks(sbi, start_segno++, 1) == 0)
+                               seg_freed++;
+       }
+
        stat_inc_call_count(sbi->stat_info);
 
-       f2fs_put_page(sum_page, 0);
-       return nfree;
+       return seg_freed;
 }
 
 int f2fs_gc(struct f2fs_sb_info *sbi, bool sync)
 {
-       unsigned int segno, i;
+       unsigned int segno;
        int gc_type = sync ? FG_GC : BG_GC;
-       int sec_freed = 0;
+       int sec_freed = 0, seg_freed;
        int ret = -EINVAL;
        struct cp_control cpc;
        struct gc_inode_list gc_list = {
@@ -838,30 +885,24 @@ gc_more:
 
        if (gc_type == BG_GC && has_not_enough_free_secs(sbi, sec_freed)) {
                gc_type = FG_GC;
+               /*
+                * If there is no victim and no prefree segment but still not
+                * enough free sections, we should flush dent/node blocks and do
+                * garbage collections.
+                */
                if (__get_victim(sbi, &segno, gc_type) || prefree_segments(sbi))
                        write_checkpoint(sbi, &cpc);
+               else if (has_not_enough_free_secs(sbi, 0))
+                       write_checkpoint(sbi, &cpc);
        }
 
        if (segno == NULL_SEGNO && !__get_victim(sbi, &segno, gc_type))
                goto stop;
        ret = 0;
 
-       /* readahead multi ssa blocks those have contiguous address */
-       if (sbi->segs_per_sec > 1)
-               ra_meta_pages(sbi, GET_SUM_BLOCK(sbi, segno), sbi->segs_per_sec,
-                                                       META_SSA, true);
-
-       for (i = 0; i < sbi->segs_per_sec; i++) {
-               /*
-                * for FG_GC case, halt gcing left segments once failed one
-                * of segments in selected section to avoid long latency.
-                */
-               if (!do_garbage_collect(sbi, segno + i, &gc_list, gc_type) &&
-                               gc_type == FG_GC)
-                       break;
-       }
+       seg_freed = do_garbage_collect(sbi, segno, &gc_list, gc_type);
 
-       if (i == sbi->segs_per_sec && gc_type == FG_GC)
+       if (gc_type == FG_GC && seg_freed == sbi->segs_per_sec)
                sec_freed++;
 
        if (gc_type == FG_GC)
index c3f0b7d..358214e 100644 (file)
@@ -71,7 +71,7 @@ bool truncate_inline_inode(struct page *ipage, u64 from)
 
        addr = inline_data_addr(ipage);
 
-       f2fs_wait_on_page_writeback(ipage, NODE);
+       f2fs_wait_on_page_writeback(ipage, NODE, true);
        memset(addr + from, 0, MAX_INLINE_DATA - from);
 
        return true;
@@ -105,7 +105,6 @@ int f2fs_read_inline_data(struct inode *inode, struct page *page)
 
 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,
@@ -115,8 +114,6 @@ int f2fs_convert_inline_page(struct dnode_of_data *dn, struct page *page)
        };
        int dirty, err;
 
-       f2fs_bug_on(F2FS_I_SB(dn->inode), page->index);
-
        if (!f2fs_exist_data(dn->inode))
                goto clear_out;
 
@@ -124,21 +121,9 @@ int f2fs_convert_inline_page(struct dnode_of_data *dn, struct page *page)
        if (err)
                return err;
 
-       f2fs_wait_on_page_writeback(page, DATA);
-
-       if (PageUptodate(page))
-               goto no_update;
-
-       zero_user_segment(page, MAX_INLINE_DATA, PAGE_CACHE_SIZE);
+       f2fs_bug_on(F2FS_P_SB(page), PageWriteback(page));
 
-       /* Copy the whole inline data block */
-       src_addr = inline_data_addr(dn->inode_page);
-       dst_addr = kmap_atomic(page);
-       memcpy(dst_addr, src_addr, MAX_INLINE_DATA);
-       flush_dcache_page(page);
-       kunmap_atomic(dst_addr);
-       SetPageUptodate(page);
-no_update:
+       read_inline_data(page, dn->inode_page);
        set_page_dirty(page);
 
        /* clear dirty state */
@@ -146,11 +131,9 @@ no_update:
 
        /* write data page to try to make data consistent */
        set_page_writeback(page);
-       fio.blk_addr = dn->data_blkaddr;
+       fio.old_blkaddr = dn->data_blkaddr;
        write_data_page(dn, &fio);
-       set_data_blkaddr(dn);
-       f2fs_update_extent_cache(dn);
-       f2fs_wait_on_page_writeback(page, DATA);
+       f2fs_wait_on_page_writeback(page, DATA, true);
        if (dirty)
                inode_dec_dirty_pages(dn->inode);
 
@@ -159,6 +142,7 @@ no_update:
 
        /* clear inline data and flag after data writeback */
        truncate_inline_inode(dn->inode_page, 0);
+       clear_inline_node(dn->inode_page);
 clear_out:
        stat_dec_inline_inode(dn->inode);
        f2fs_clear_inline_inode(dn->inode);
@@ -223,7 +207,7 @@ int f2fs_write_inline_data(struct inode *inode, struct page *page)
 
        f2fs_bug_on(F2FS_I_SB(inode), page->index);
 
-       f2fs_wait_on_page_writeback(dn.inode_page, NODE);
+       f2fs_wait_on_page_writeback(dn.inode_page, NODE, true);
        src_addr = kmap_atomic(page);
        dst_addr = inline_data_addr(dn.inode_page);
        memcpy(dst_addr, src_addr, MAX_INLINE_DATA);
@@ -233,6 +217,7 @@ int f2fs_write_inline_data(struct inode *inode, struct page *page)
        set_inode_flag(F2FS_I(inode), FI_DATA_EXIST);
 
        sync_inode_page(&dn);
+       clear_inline_node(dn.inode_page);
        f2fs_put_dnode(&dn);
        return 0;
 }
@@ -261,7 +246,7 @@ process_inline:
                ipage = get_node_page(sbi, inode->i_ino);
                f2fs_bug_on(sbi, IS_ERR(ipage));
 
-               f2fs_wait_on_page_writeback(ipage, NODE);
+               f2fs_wait_on_page_writeback(ipage, NODE, true);
 
                src_addr = inline_data_addr(npage);
                dst_addr = inline_data_addr(ipage);
@@ -292,7 +277,7 @@ process_inline:
 }
 
 struct f2fs_dir_entry *find_in_inline_dir(struct inode *dir,
-                       struct f2fs_filename *fname, struct page **res_page)
+                       struct fscrypt_name *fname, struct page **res_page)
 {
        struct f2fs_sb_info *sbi = F2FS_SB(dir->i_sb);
        struct f2fs_inline_dentry *inline_dentry;
@@ -389,7 +374,7 @@ static int f2fs_convert_inline_dir(struct inode *dir, struct page *ipage,
        if (err)
                goto out;
 
-       f2fs_wait_on_page_writeback(page, DATA);
+       f2fs_wait_on_page_writeback(page, DATA, true);
        zero_user_segment(page, MAX_INLINE_DATA, PAGE_CACHE_SIZE);
 
        dentry_blk = kmap_atomic(page);
@@ -469,7 +454,7 @@ int f2fs_add_inline_entry(struct inode *dir, const struct qstr *name,
                }
        }
 
-       f2fs_wait_on_page_writeback(ipage, NODE);
+       f2fs_wait_on_page_writeback(ipage, NODE, true);
 
        name_hash = f2fs_dentry_hash(name);
        make_dentry_ptr(NULL, &d, (void *)dentry_blk, 2);
@@ -507,7 +492,7 @@ void f2fs_delete_inline_entry(struct f2fs_dir_entry *dentry, struct page *page,
        int i;
 
        lock_page(page);
-       f2fs_wait_on_page_writeback(page, NODE);
+       f2fs_wait_on_page_writeback(page, NODE, true);
 
        inline_dentry = inline_data_addr(page);
        bit_pos = dentry - inline_dentry->dentry;
@@ -550,7 +535,7 @@ bool f2fs_empty_inline_dir(struct inode *dir)
 }
 
 int f2fs_read_inline_dir(struct file *file, struct dir_context *ctx,
-                               struct f2fs_str *fstr)
+                               struct fscrypt_str *fstr)
 {
        struct inode *inode = file_inode(file);
        struct f2fs_inline_dentry *inline_dentry = NULL;
index 2adeff2..cb269c4 100644 (file)
@@ -83,7 +83,7 @@ static void __recover_inline_status(struct inode *inode, struct page *ipage)
 
        while (start < end) {
                if (*start++) {
-                       f2fs_wait_on_page_writeback(ipage, NODE);
+                       f2fs_wait_on_page_writeback(ipage, NODE, true);
 
                        set_inode_flag(F2FS_I(inode), FI_DATA_EXIST);
                        set_raw_inline(F2FS_I(inode), F2FS_INODE(ipage));
@@ -227,7 +227,7 @@ int update_inode(struct inode *inode, struct page *node_page)
 {
        struct f2fs_inode *ri;
 
-       f2fs_wait_on_page_writeback(node_page, NODE);
+       f2fs_wait_on_page_writeback(node_page, NODE, true);
 
        ri = F2FS_INODE(node_page);
 
@@ -263,6 +263,10 @@ int update_inode(struct inode *inode, struct page *node_page)
        set_cold_node(inode, node_page);
        clear_inode_flag(F2FS_I(inode), FI_DIRTY_INODE);
 
+       /* deleted inode */
+       if (inode->i_nlink == 0)
+               clear_inline_node(node_page);
+
        return set_page_dirty(node_page);
 }
 
@@ -320,7 +324,7 @@ void f2fs_evict_inode(struct inode *inode)
 
        /* some remained atomic pages should discarded */
        if (f2fs_is_atomic_file(inode))
-               commit_inmem_pages(inode, true);
+               drop_inmem_pages(inode);
 
        trace_f2fs_evict_inode(inode);
        truncate_inode_pages_final(&inode->i_data);
@@ -385,10 +389,7 @@ no_delete:
                }
        }
 out_clear:
-#ifdef CONFIG_F2FS_FS_ENCRYPTION
-       if (fi->i_crypt_info)
-               f2fs_free_encryption_info(inode, fi->i_crypt_info);
-#endif
+       fscrypt_put_encryption_info(inode, NULL);
        clear_inode(inode);
 }
 
index 6f944e5..7876f10 100644 (file)
@@ -169,7 +169,7 @@ static int f2fs_link(struct dentry *old_dentry, struct inode *dir,
        int err;
 
        if (f2fs_encrypted_inode(dir) &&
-               !f2fs_is_child_context_consistent_with_parent(dir, inode))
+                       !fscrypt_has_permitted_context(dir, inode))
                return -EPERM;
 
        f2fs_balance_fs(sbi, true);
@@ -260,6 +260,22 @@ static struct dentry *f2fs_lookup(struct inode *dir, struct dentry *dentry,
        struct page *page;
        nid_t ino;
        int err = 0;
+       unsigned int root_ino = F2FS_ROOT_INO(F2FS_I_SB(dir));
+
+       if (f2fs_encrypted_inode(dir)) {
+               int res = fscrypt_get_encryption_info(dir);
+
+               /*
+                * DCACHE_ENCRYPTED_WITH_KEY is set if the dentry is
+                * created while the directory was encrypted and we
+                * don't have access to the key.
+                */
+               if (fscrypt_has_encryption_key(dir))
+                       fscrypt_set_encrypted_dentry(dentry);
+               fscrypt_set_d_op(dentry);
+               if (res && res != -ENOKEY)
+                       return ERR_PTR(res);
+       }
 
        if (dentry->d_name.len > F2FS_NAME_LEN)
                return ERR_PTR(-ENAMETOOLONG);
@@ -276,15 +292,29 @@ static struct dentry *f2fs_lookup(struct inode *dir, struct dentry *dentry,
        if (IS_ERR(inode))
                return ERR_CAST(inode);
 
+       if ((dir->i_ino == root_ino) && f2fs_has_inline_dots(dir)) {
+               err = __recover_dot_dentries(dir, root_ino);
+               if (err)
+                       goto err_out;
+       }
+
        if (f2fs_has_inline_dots(inode)) {
                err = __recover_dot_dentries(inode, dir->i_ino);
                if (err)
                        goto err_out;
        }
+       if (!IS_ERR(inode) && f2fs_encrypted_inode(dir) &&
+                       (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)) &&
+                       !fscrypt_has_permitted_context(dir, inode)) {
+               bool nokey = f2fs_encrypted_inode(inode) &&
+                       !fscrypt_has_encryption_key(inode);
+               err = nokey ? -ENOKEY : -EPERM;
+               goto err_out;
+       }
        return d_splice_alias(inode, dentry);
 
 err_out:
-       iget_failed(inode);
+       iput(inode);
        return ERR_PTR(err);
 }
 
@@ -345,13 +375,23 @@ static int f2fs_symlink(struct inode *dir, struct dentry *dentry,
        struct f2fs_sb_info *sbi = F2FS_I_SB(dir);
        struct inode *inode;
        size_t len = strlen(symname);
-       size_t p_len;
-       char *p_str;
-       struct f2fs_str disk_link = FSTR_INIT(NULL, 0);
-       struct f2fs_encrypted_symlink_data *sd = NULL;
+       struct fscrypt_str disk_link = FSTR_INIT((char *)symname, len + 1);
+       struct fscrypt_symlink_data *sd = NULL;
        int err;
 
-       if (len > dir->i_sb->s_blocksize)
+       if (f2fs_encrypted_inode(dir)) {
+               err = fscrypt_get_encryption_info(dir);
+               if (err)
+                       return err;
+
+               if (!fscrypt_has_encryption_key(dir))
+                       return -EPERM;
+
+               disk_link.len = (fscrypt_fname_encrypted_size(dir, len) +
+                               sizeof(struct fscrypt_symlink_data));
+       }
+
+       if (disk_link.len > dir->i_sb->s_blocksize)
                return -ENAMETOOLONG;
 
        inode = f2fs_new_inode(dir, S_IFLNK | S_IRWXUGO);
@@ -374,42 +414,36 @@ static int f2fs_symlink(struct inode *dir, struct dentry *dentry,
        f2fs_unlock_op(sbi);
        alloc_nid_done(sbi, inode->i_ino);
 
-       if (f2fs_encrypted_inode(dir)) {
+       if (f2fs_encrypted_inode(inode)) {
                struct qstr istr = QSTR_INIT(symname, len);
+               struct fscrypt_str ostr;
 
-               err = f2fs_get_encryption_info(inode);
-               if (err)
+               sd = kzalloc(disk_link.len, GFP_NOFS);
+               if (!sd) {
+                       err = -ENOMEM;
                        goto err_out;
+               }
 
-               err = f2fs_fname_crypto_alloc_buffer(inode, len, &disk_link);
+               err = fscrypt_get_encryption_info(inode);
                if (err)
                        goto err_out;
 
-               err = f2fs_fname_usr_to_disk(inode, &istr, &disk_link);
-               if (err < 0)
-                       goto err_out;
-
-               p_len = encrypted_symlink_data_len(disk_link.len) + 1;
-
-               if (p_len > dir->i_sb->s_blocksize) {
-                       err = -ENAMETOOLONG;
+               if (!fscrypt_has_encryption_key(inode)) {
+                       err = -EPERM;
                        goto err_out;
                }
 
-               sd = kzalloc(p_len, GFP_NOFS);
-               if (!sd) {
-                       err = -ENOMEM;
+               ostr.name = sd->encrypted_path;
+               ostr.len = disk_link.len;
+               err = fscrypt_fname_usr_to_disk(inode, &istr, &ostr);
+               if (err < 0)
                        goto err_out;
-               }
-               memcpy(sd->encrypted_path, disk_link.name, disk_link.len);
-               sd->len = cpu_to_le16(disk_link.len);
-               p_str = (char *)sd;
-       } else {
-               p_len = len + 1;
-               p_str = (char *)symname;
+
+               sd->len = cpu_to_le16(ostr.len);
+               disk_link.name = (char *)sd;
        }
 
-       err = page_symlink(inode, p_str, p_len);
+       err = page_symlink(inode, disk_link.name, disk_link.len);
 
 err_out:
        d_instantiate(dentry, inode);
@@ -425,7 +459,8 @@ err_out:
         * performance regression.
         */
        if (!err) {
-               filemap_write_and_wait_range(inode->i_mapping, 0, p_len - 1);
+               filemap_write_and_wait_range(inode->i_mapping, 0,
+                                                       disk_link.len - 1);
 
                if (IS_DIRSYNC(dir))
                        f2fs_sync_fs(sbi->sb, 1);
@@ -434,7 +469,6 @@ err_out:
        }
 
        kfree(sd);
-       f2fs_fname_crypto_free_buffer(&disk_link);
        return err;
 out:
        handle_failed_inode(inode);
@@ -582,7 +616,7 @@ out:
 static int f2fs_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode)
 {
        if (f2fs_encrypted_inode(dir)) {
-               int err = f2fs_get_encryption_info(dir);
+               int err = fscrypt_get_encryption_info(dir);
                if (err)
                        return err;
        }
@@ -608,11 +642,11 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
        struct f2fs_dir_entry *old_dir_entry = NULL;
        struct f2fs_dir_entry *old_entry;
        struct f2fs_dir_entry *new_entry;
+       bool is_old_inline = f2fs_has_inline_dentry(old_dir);
        int err = -ENOENT;
 
        if ((old_dir != new_dir) && f2fs_encrypted_inode(new_dir) &&
-               !f2fs_is_child_context_consistent_with_parent(new_dir,
-                                                       old_inode)) {
+                       !fscrypt_has_permitted_context(new_dir, old_inode)) {
                err = -EPERM;
                goto out;
        }
@@ -654,8 +688,9 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
                if (err)
                        goto put_out_dir;
 
-               if (update_dent_inode(old_inode, new_inode,
-                                               &new_dentry->d_name)) {
+               err = update_dent_inode(old_inode, new_inode,
+                                               &new_dentry->d_name);
+               if (err) {
                        release_orphan_inode(sbi);
                        goto put_out_dir;
                }
@@ -693,6 +728,26 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
                        inc_nlink(new_dir);
                        update_inode_page(new_dir);
                }
+
+               /*
+                * old entry and new entry can locate in the same inline
+                * dentry in inode, when attaching new entry in inline dentry,
+                * it could force inline dentry conversion, after that,
+                * old_entry and old_page will point to wrong address, in
+                * order to avoid this, let's do the check and update here.
+                */
+               if (is_old_inline && !f2fs_has_inline_dentry(old_dir)) {
+                       f2fs_put_page(old_page, 0);
+                       old_page = NULL;
+
+                       old_entry = f2fs_find_entry(old_dir,
+                                               &old_dentry->d_name, &old_page);
+                       if (!old_entry) {
+                               err = -EIO;
+                               f2fs_unlock_op(sbi);
+                               goto out_whiteout;
+                       }
+               }
        }
 
        down_write(&F2FS_I(old_inode)->i_sem);
@@ -771,11 +826,9 @@ static int f2fs_cross_rename(struct inode *old_dir, struct dentry *old_dentry,
        int err = -ENOENT;
 
        if ((f2fs_encrypted_inode(old_dir) || f2fs_encrypted_inode(new_dir)) &&
-               (old_dir != new_dir) &&
-               (!f2fs_is_child_context_consistent_with_parent(new_dir,
-                                                               old_inode) ||
-               !f2fs_is_child_context_consistent_with_parent(old_dir,
-                                                               new_inode)))
+                       (old_dir != new_dir) &&
+                       (!fscrypt_has_permitted_context(new_dir, old_inode) ||
+                        !fscrypt_has_permitted_context(old_dir, new_inode)))
                return -EPERM;
 
        old_entry = f2fs_find_entry(old_dir, &old_dentry->d_name, &old_page);
@@ -937,16 +990,15 @@ static int f2fs_rename2(struct inode *old_dir, struct dentry *old_dentry,
        return f2fs_rename(old_dir, old_dentry, new_dir, new_dentry, flags);
 }
 
-#ifdef CONFIG_F2FS_FS_ENCRYPTION
 static const char *f2fs_encrypted_get_link(struct dentry *dentry,
                                           struct inode *inode,
                                           struct delayed_call *done)
 {
        struct page *cpage = NULL;
        char *caddr, *paddr = NULL;
-       struct f2fs_str cstr = FSTR_INIT(NULL, 0);
-       struct f2fs_str pstr = FSTR_INIT(NULL, 0);
-       struct f2fs_encrypted_symlink_data *sd;
+       struct fscrypt_str cstr = FSTR_INIT(NULL, 0);
+       struct fscrypt_str pstr = FSTR_INIT(NULL, 0);
+       struct fscrypt_symlink_data *sd;
        loff_t size = min_t(loff_t, i_size_read(inode), PAGE_SIZE - 1);
        u32 max_size = inode->i_sb->s_blocksize;
        int res;
@@ -954,7 +1006,7 @@ static const char *f2fs_encrypted_get_link(struct dentry *dentry,
        if (!dentry)
                return ERR_PTR(-ECHILD);
 
-       res = f2fs_get_encryption_info(inode);
+       res = fscrypt_get_encryption_info(inode);
        if (res)
                return ERR_PTR(res);
 
@@ -965,7 +1017,8 @@ static const char *f2fs_encrypted_get_link(struct dentry *dentry,
        caddr[size] = 0;
 
        /* Symlink is encrypted */
-       sd = (struct f2fs_encrypted_symlink_data *)caddr;
+       sd = (struct fscrypt_symlink_data *)caddr;
+       cstr.name = sd->encrypted_path;
        cstr.len = le16_to_cpu(sd->len);
 
        /* this is broken symlink case */
@@ -973,12 +1026,6 @@ static const char *f2fs_encrypted_get_link(struct dentry *dentry,
                res = -ENOENT;
                goto errout;
        }
-       cstr.name = kmalloc(cstr.len, GFP_NOFS);
-       if (!cstr.name) {
-               res = -ENOMEM;
-               goto errout;
-       }
-       memcpy(cstr.name, sd->encrypted_path, cstr.len);
 
        /* this is broken symlink case */
        if (unlikely(cstr.name[0] == 0)) {
@@ -986,22 +1033,19 @@ static const char *f2fs_encrypted_get_link(struct dentry *dentry,
                goto errout;
        }
 
-       if ((cstr.len + sizeof(struct f2fs_encrypted_symlink_data) - 1) >
-                                                               max_size) {
+       if ((cstr.len + sizeof(struct fscrypt_symlink_data) - 1) > max_size) {
                /* Symlink data on the disk is corrupted */
                res = -EIO;
                goto errout;
        }
-       res = f2fs_fname_crypto_alloc_buffer(inode, cstr.len, &pstr);
+       res = fscrypt_fname_alloc_buffer(inode, cstr.len, &pstr);
        if (res)
                goto errout;
 
-       res = f2fs_fname_disk_to_usr(inode, NULL, &cstr, &pstr);
+       res = fscrypt_fname_disk_to_usr(inode, 0, 0, &cstr, &pstr);
        if (res < 0)
                goto errout;
 
-       kfree(cstr.name);
-
        paddr = pstr.name;
 
        /* Null-terminate the name */
@@ -1011,8 +1055,7 @@ static const char *f2fs_encrypted_get_link(struct dentry *dentry,
        set_delayed_call(done, kfree_link, paddr);
        return paddr;
 errout:
-       kfree(cstr.name);
-       f2fs_fname_crypto_free_buffer(&pstr);
+       fscrypt_fname_free_buffer(&pstr);
        page_cache_release(cpage);
        return ERR_PTR(res);
 }
@@ -1029,7 +1072,6 @@ const struct inode_operations f2fs_encrypted_symlink_inode_operations = {
        .removexattr    = generic_removexattr,
 #endif
 };
-#endif
 
 const struct inode_operations f2fs_dir_inode_operations = {
        .create         = f2fs_create,
index 342597a..118321b 100644 (file)
@@ -257,15 +257,20 @@ static struct nat_entry *grab_nat_entry(struct f2fs_nm_info *nm_i, nid_t nid)
        return new;
 }
 
-static void cache_nat_entry(struct f2fs_nm_info *nm_i, nid_t nid,
+static void cache_nat_entry(struct f2fs_sb_info *sbi, nid_t nid,
                                                struct f2fs_nat_entry *ne)
 {
+       struct f2fs_nm_info *nm_i = NM_I(sbi);
        struct nat_entry *e;
 
        e = __lookup_nat_cache(nm_i, nid);
        if (!e) {
                e = grab_nat_entry(nm_i, nid);
                node_info_from_raw_nat(&e->ni, ne);
+       } else {
+               f2fs_bug_on(sbi, nat_get_ino(e) != ne->ino ||
+                               nat_get_blkaddr(e) != ne->block_addr ||
+                               nat_get_version(e) != ne->version);
        }
 }
 
@@ -354,7 +359,7 @@ void get_node_info(struct f2fs_sb_info *sbi, nid_t nid, struct node_info *ni)
 {
        struct f2fs_nm_info *nm_i = NM_I(sbi);
        struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_HOT_DATA);
-       struct f2fs_summary_block *sum = curseg->sum_blk;
+       struct f2fs_journal *journal = curseg->journal;
        nid_t start_nid = START_NID(nid);
        struct f2fs_nat_block *nat_blk;
        struct page *page = NULL;
@@ -371,23 +376,20 @@ void get_node_info(struct f2fs_sb_info *sbi, nid_t nid, struct node_info *ni)
                ni->ino = nat_get_ino(e);
                ni->blk_addr = nat_get_blkaddr(e);
                ni->version = nat_get_version(e);
-       }
-       up_read(&nm_i->nat_tree_lock);
-       if (e)
+               up_read(&nm_i->nat_tree_lock);
                return;
+       }
 
        memset(&ne, 0, sizeof(struct f2fs_nat_entry));
 
-       down_write(&nm_i->nat_tree_lock);
-
        /* Check current segment summary */
-       mutex_lock(&curseg->curseg_mutex);
-       i = lookup_journal_in_cursum(sum, NAT_JOURNAL, nid, 0);
+       down_read(&curseg->journal_rwsem);
+       i = lookup_journal_in_cursum(journal, NAT_JOURNAL, nid, 0);
        if (i >= 0) {
-               ne = nat_in_journal(sum, i);
+               ne = nat_in_journal(journal, i);
                node_info_from_raw_nat(ni, &ne);
        }
-       mutex_unlock(&curseg->curseg_mutex);
+       up_read(&curseg->journal_rwsem);
        if (i >= 0)
                goto cache;
 
@@ -398,19 +400,52 @@ void get_node_info(struct f2fs_sb_info *sbi, nid_t nid, struct node_info *ni)
        node_info_from_raw_nat(ni, &ne);
        f2fs_put_page(page, 1);
 cache:
+       up_read(&nm_i->nat_tree_lock);
        /* cache nat entry */
-       cache_nat_entry(NM_I(sbi), nid, &ne);
+       down_write(&nm_i->nat_tree_lock);
+       cache_nat_entry(sbi, nid, &ne);
        up_write(&nm_i->nat_tree_lock);
 }
 
+pgoff_t get_next_page_offset(struct dnode_of_data *dn, pgoff_t pgofs)
+{
+       const long direct_index = ADDRS_PER_INODE(dn->inode);
+       const long direct_blks = ADDRS_PER_BLOCK;
+       const long indirect_blks = ADDRS_PER_BLOCK * NIDS_PER_BLOCK;
+       unsigned int skipped_unit = ADDRS_PER_BLOCK;
+       int cur_level = dn->cur_level;
+       int max_level = dn->max_level;
+       pgoff_t base = 0;
+
+       if (!dn->max_level)
+               return pgofs + 1;
+
+       while (max_level-- > cur_level)
+               skipped_unit *= NIDS_PER_BLOCK;
+
+       switch (dn->max_level) {
+       case 3:
+               base += 2 * indirect_blks;
+       case 2:
+               base += 2 * direct_blks;
+       case 1:
+               base += direct_index;
+               break;
+       default:
+               f2fs_bug_on(F2FS_I_SB(dn->inode), 1);
+       }
+
+       return ((pgofs - base) / skipped_unit + 1) * skipped_unit + base;
+}
+
 /*
  * The maximum depth is four.
  * Offset[0] will have raw inode offset.
  */
-static int get_node_path(struct f2fs_inode_info *fi, long block,
+static int get_node_path(struct inode *inode, long block,
                                int offset[4], unsigned int noffset[4])
 {
-       const long direct_index = ADDRS_PER_INODE(fi);
+       const long direct_index = ADDRS_PER_INODE(inode);
        const long direct_blks = ADDRS_PER_BLOCK;
        const long dptrs_per_blk = NIDS_PER_BLOCK;
        const long indirect_blks = ADDRS_PER_BLOCK * NIDS_PER_BLOCK;
@@ -495,10 +530,10 @@ int get_dnode_of_data(struct dnode_of_data *dn, pgoff_t index, int mode)
        int offset[4];
        unsigned int noffset[4];
        nid_t nids[4];
-       int level, i;
+       int level, i = 0;
        int err = 0;
 
-       level = get_node_path(F2FS_I(dn->inode), index, offset, noffset);
+       level = get_node_path(dn->inode, index, offset, noffset);
 
        nids[0] = dn->inode->i_ino;
        npage[0] = dn->inode_page;
@@ -585,6 +620,10 @@ release_pages:
 release_out:
        dn->inode_page = NULL;
        dn->node_page = NULL;
+       if (err == -ENOENT) {
+               dn->cur_level = i;
+               dn->max_level = level;
+       }
        return err;
 }
 
@@ -792,7 +831,7 @@ int truncate_inode_blocks(struct inode *inode, pgoff_t from)
 
        trace_f2fs_truncate_inode_blocks_enter(inode, from);
 
-       level = get_node_path(F2FS_I(inode), from, offset, noffset);
+       level = get_node_path(inode, from, offset, noffset);
 restart:
        page = get_node_page(sbi, inode->i_ino);
        if (IS_ERR(page)) {
@@ -861,7 +900,7 @@ skip_partial:
                                f2fs_put_page(page, 1);
                                goto restart;
                        }
-                       f2fs_wait_on_page_writeback(page, NODE);
+                       f2fs_wait_on_page_writeback(page, NODE, true);
                        ri->i_nid[offset[0] - NODE_DIR1_BLOCK] = 0;
                        set_page_dirty(page);
                        unlock_page(page);
@@ -976,7 +1015,7 @@ struct page *new_node_page(struct dnode_of_data *dn,
        new_ni.ino = dn->inode->i_ino;
        set_node_addr(sbi, &new_ni, NEW_ADDR, false);
 
-       f2fs_wait_on_page_writeback(page, NODE);
+       f2fs_wait_on_page_writeback(page, NODE, true);
        fill_node_footer(page, dn->nid, dn->inode->i_ino, ofs, true);
        set_cold_node(dn->inode, page);
        SetPageUptodate(page);
@@ -1029,7 +1068,7 @@ static int read_node_page(struct page *page, int rw)
        if (PageUptodate(page))
                return LOCKED_PAGE;
 
-       fio.blk_addr = ni.blk_addr;
+       fio.new_blkaddr = fio.old_blkaddr = ni.blk_addr;
        return f2fs_submit_page_bio(&fio);
 }
 
@@ -1045,12 +1084,11 @@ void ra_node_page(struct f2fs_sb_info *sbi, nid_t nid)
                return;
        f2fs_bug_on(sbi, check_nid_range(sbi, nid));
 
-       apage = find_get_page(NODE_MAPPING(sbi), nid);
-       if (apage && PageUptodate(apage)) {
-               f2fs_put_page(apage, 0);
+       rcu_read_lock();
+       apage = radix_tree_lookup(&NODE_MAPPING(sbi)->page_tree, nid);
+       rcu_read_unlock();
+       if (apage)
                return;
-       }
-       f2fs_put_page(apage, 0);
 
        apage = grab_cache_page(NODE_MAPPING(sbi), nid);
        if (!apage)
@@ -1063,7 +1101,7 @@ void ra_node_page(struct f2fs_sb_info *sbi, nid_t nid)
 /*
  * readahead MAX_RA_NODE number of node pages.
  */
-void ra_node_pages(struct page *parent, int start)
+static void ra_node_pages(struct page *parent, int start)
 {
        struct f2fs_sb_info *sbi = F2FS_P_SB(parent);
        struct blk_plug plug;
@@ -1083,7 +1121,7 @@ void ra_node_pages(struct page *parent, int start)
        blk_finish_plug(&plug);
 }
 
-struct page *__get_node_page(struct f2fs_sb_info *sbi, pgoff_t nid,
+static struct page *__get_node_page(struct f2fs_sb_info *sbi, pgoff_t nid,
                                        struct page *parent, int start)
 {
        struct page *page;
@@ -1154,19 +1192,57 @@ void sync_inode_page(struct dnode_of_data *dn)
        dn->node_changed = ret ? true: false;
 }
 
+static void flush_inline_data(struct f2fs_sb_info *sbi, nid_t ino)
+{
+       struct inode *inode;
+       struct page *page;
+
+       /* should flush inline_data before evict_inode */
+       inode = ilookup(sbi->sb, ino);
+       if (!inode)
+               return;
+
+       page = pagecache_get_page(inode->i_mapping, 0, FGP_NOWAIT, 0);
+       if (!page)
+               goto iput_out;
+
+       if (!trylock_page(page))
+               goto release_out;
+
+       if (!PageUptodate(page))
+               goto page_out;
+
+       if (!PageDirty(page))
+               goto page_out;
+
+       if (!clear_page_dirty_for_io(page))
+               goto page_out;
+
+       if (!f2fs_write_inline_data(inode, page))
+               inode_dec_dirty_pages(inode);
+       else
+               set_page_dirty(page);
+page_out:
+       unlock_page(page);
+release_out:
+       f2fs_put_page(page, 0);
+iput_out:
+       iput(inode);
+}
+
 int sync_node_pages(struct f2fs_sb_info *sbi, nid_t ino,
                                        struct writeback_control *wbc)
 {
        pgoff_t index, end;
        struct pagevec pvec;
        int step = ino ? 2 : 0;
-       int nwritten = 0, wrote = 0;
+       int nwritten = 0;
 
        pagevec_init(&pvec, 0);
 
 next_step:
        index = 0;
-       end = LONG_MAX;
+       end = ULONG_MAX;
 
        while (index <= end) {
                int i, nr_pages;
@@ -1203,6 +1279,7 @@ next_step:
                         * If an fsync mode,
                         * we should not skip writing node pages.
                         */
+lock_node:
                        if (ino && ino_of_node(page) == ino)
                                lock_page(page);
                        else if (!trylock_page(page))
@@ -1221,6 +1298,17 @@ continue_unlock:
                                goto continue_unlock;
                        }
 
+                       /* flush inline_data */
+                       if (!ino && is_inline_node(page)) {
+                               clear_inline_node(page);
+                               unlock_page(page);
+                               flush_inline_data(sbi, ino_of_node(page));
+                               goto lock_node;
+                       }
+
+                       f2fs_wait_on_page_writeback(page, NODE, true);
+
+                       BUG_ON(PageWriteback(page));
                        if (!clear_page_dirty_for_io(page))
                                goto continue_unlock;
 
@@ -1238,8 +1326,6 @@ continue_unlock:
 
                        if (NODE_MAPPING(sbi)->a_ops->writepage(page, wbc))
                                unlock_page(page);
-                       else
-                               wrote++;
 
                        if (--wbc->nr_to_write == 0)
                                break;
@@ -1257,15 +1343,12 @@ continue_unlock:
                step++;
                goto next_step;
        }
-
-       if (wrote)
-               f2fs_submit_merged_bio(sbi, NODE, WRITE);
        return nwritten;
 }
 
 int wait_on_node_pages_writeback(struct f2fs_sb_info *sbi, nid_t ino)
 {
-       pgoff_t index = 0, end = LONG_MAX;
+       pgoff_t index = 0, end = ULONG_MAX;
        struct pagevec pvec;
        int ret2 = 0, ret = 0;
 
@@ -1287,7 +1370,7 @@ int wait_on_node_pages_writeback(struct f2fs_sb_info *sbi, nid_t ino)
                                continue;
 
                        if (ino && ino_of_node(page) == ino) {
-                               f2fs_wait_on_page_writeback(page, NODE);
+                               f2fs_wait_on_page_writeback(page, NODE, true);
                                if (TestClearPageError(page))
                                        ret = -EIO;
                        }
@@ -1326,8 +1409,6 @@ static int f2fs_write_node_page(struct page *page,
        if (unlikely(f2fs_cp_error(sbi)))
                goto redirty_out;
 
-       f2fs_wait_on_page_writeback(page, NODE);
-
        /* get old block addr of this node page */
        nid = nid_of_node(page);
        f2fs_bug_on(sbi, page->index != nid);
@@ -1351,14 +1432,18 @@ static int f2fs_write_node_page(struct page *page,
        }
 
        set_page_writeback(page);
-       fio.blk_addr = ni.blk_addr;
+       fio.old_blkaddr = ni.blk_addr;
        write_node_page(nid, &fio);
-       set_node_addr(sbi, &ni, fio.blk_addr, is_fsync_dnode(page));
+       set_node_addr(sbi, &ni, fio.new_blkaddr, is_fsync_dnode(page));
        dec_page_count(sbi, F2FS_DIRTY_NODES);
        up_read(&sbi->node_write);
+
+       if (wbc->for_reclaim)
+               f2fs_submit_merged_bio_cond(sbi, NULL, page, 0, NODE, WRITE);
+
        unlock_page(page);
 
-       if (wbc->for_reclaim || unlikely(f2fs_cp_error(sbi)))
+       if (unlikely(f2fs_cp_error(sbi)))
                f2fs_submit_merged_bio(sbi, NODE, WRITE);
 
        return 0;
@@ -1374,8 +1459,6 @@ static int f2fs_write_node_pages(struct address_space *mapping,
        struct f2fs_sb_info *sbi = F2FS_M_SB(mapping);
        long diff;
 
-       trace_f2fs_writepages(mapping->host, wbc, NODE);
-
        /* balancing f2fs's metadata in background */
        f2fs_balance_fs_bg(sbi);
 
@@ -1383,6 +1466,8 @@ static int f2fs_write_node_pages(struct address_space *mapping,
        if (get_pages(sbi, F2FS_DIRTY_NODES) < nr_pages_to_skip(sbi, NODE))
                goto skip_write;
 
+       trace_f2fs_writepages(mapping->host, wbc, NODE);
+
        diff = nr_pages_to_write(sbi, NODE, wbc);
        wbc->sync_mode = WB_SYNC_NONE;
        sync_node_pages(sbi, 0, wbc);
@@ -1391,6 +1476,7 @@ static int f2fs_write_node_pages(struct address_space *mapping,
 
 skip_write:
        wbc->pages_skipped += get_pages(sbi, F2FS_DIRTY_NODES);
+       trace_f2fs_writepages(mapping->host, wbc, NODE);
        return 0;
 }
 
@@ -1526,7 +1612,7 @@ static void build_free_nids(struct f2fs_sb_info *sbi)
 {
        struct f2fs_nm_info *nm_i = NM_I(sbi);
        struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_HOT_DATA);
-       struct f2fs_summary_block *sum = curseg->sum_blk;
+       struct f2fs_journal *journal = curseg->journal;
        int i = 0;
        nid_t nid = nm_i->next_scan_nid;
 
@@ -1558,16 +1644,18 @@ static void build_free_nids(struct f2fs_sb_info *sbi)
        nm_i->next_scan_nid = nid;
 
        /* find free nids from current sum_pages */
-       mutex_lock(&curseg->curseg_mutex);
-       for (i = 0; i < nats_in_cursum(sum); i++) {
-               block_t addr = le32_to_cpu(nat_in_journal(sum, i).block_addr);
-               nid = le32_to_cpu(nid_in_journal(sum, i));
+       down_read(&curseg->journal_rwsem);
+       for (i = 0; i < nats_in_cursum(journal); i++) {
+               block_t addr;
+
+               addr = le32_to_cpu(nat_in_journal(journal, i).block_addr);
+               nid = le32_to_cpu(nid_in_journal(journal, i));
                if (addr == NULL_ADDR)
                        add_free_nid(sbi, nid, true);
                else
                        remove_free_nid(nm_i, nid);
        }
-       mutex_unlock(&curseg->curseg_mutex);
+       up_read(&curseg->journal_rwsem);
        up_read(&nm_i->nat_tree_lock);
 
        ra_meta_pages(sbi, NAT_BLOCK_OFFSET(nm_i->next_scan_nid),
@@ -1703,7 +1791,7 @@ void recover_inline_xattr(struct inode *inode, struct page *page)
        src_addr = inline_xattr_addr(page);
        inline_size = inline_xattr_size(inode);
 
-       f2fs_wait_on_page_writeback(ipage, NODE);
+       f2fs_wait_on_page_writeback(ipage, NODE, true);
        memcpy(dst_addr, src_addr, inline_size);
 update_inode:
        update_inode(inode, ipage);
@@ -1831,16 +1919,16 @@ static void remove_nats_in_journal(struct f2fs_sb_info *sbi)
 {
        struct f2fs_nm_info *nm_i = NM_I(sbi);
        struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_HOT_DATA);
-       struct f2fs_summary_block *sum = curseg->sum_blk;
+       struct f2fs_journal *journal = curseg->journal;
        int i;
 
-       mutex_lock(&curseg->curseg_mutex);
-       for (i = 0; i < nats_in_cursum(sum); i++) {
+       down_write(&curseg->journal_rwsem);
+       for (i = 0; i < nats_in_cursum(journal); i++) {
                struct nat_entry *ne;
                struct f2fs_nat_entry raw_ne;
-               nid_t nid = le32_to_cpu(nid_in_journal(sum, i));
+               nid_t nid = le32_to_cpu(nid_in_journal(journal, i));
 
-               raw_ne = nat_in_journal(sum, i);
+               raw_ne = nat_in_journal(journal, i);
 
                ne = __lookup_nat_cache(nm_i, nid);
                if (!ne) {
@@ -1849,8 +1937,8 @@ static void remove_nats_in_journal(struct f2fs_sb_info *sbi)
                }
                __set_nat_cache_dirty(nm_i, ne);
        }
-       update_nats_in_cursum(sum, -i);
-       mutex_unlock(&curseg->curseg_mutex);
+       update_nats_in_cursum(journal, -i);
+       up_write(&curseg->journal_rwsem);
 }
 
 static void __adjust_nat_entry_set(struct nat_entry_set *nes,
@@ -1875,7 +1963,7 @@ static void __flush_nat_entry_set(struct f2fs_sb_info *sbi,
                                        struct nat_entry_set *set)
 {
        struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_HOT_DATA);
-       struct f2fs_summary_block *sum = curseg->sum_blk;
+       struct f2fs_journal *journal = curseg->journal;
        nid_t start_nid = set->set * NAT_ENTRY_PER_BLOCK;
        bool to_journal = true;
        struct f2fs_nat_block *nat_blk;
@@ -1887,11 +1975,11 @@ static void __flush_nat_entry_set(struct f2fs_sb_info *sbi,
         * #1, flush nat entries to journal in current hot data summary block.
         * #2, flush nat entries to nat page.
         */
-       if (!__has_cursum_space(sum, set->entry_cnt, NAT_JOURNAL))
+       if (!__has_cursum_space(journal, set->entry_cnt, NAT_JOURNAL))
                to_journal = false;
 
        if (to_journal) {
-               mutex_lock(&curseg->curseg_mutex);
+               down_write(&curseg->journal_rwsem);
        } else {
                page = get_next_nat_page(sbi, start_nid);
                nat_blk = page_address(page);
@@ -1908,11 +1996,11 @@ static void __flush_nat_entry_set(struct f2fs_sb_info *sbi,
                        continue;
 
                if (to_journal) {
-                       offset = lookup_journal_in_cursum(sum,
+                       offset = lookup_journal_in_cursum(journal,
                                                        NAT_JOURNAL, nid, 1);
                        f2fs_bug_on(sbi, offset < 0);
-                       raw_ne = &nat_in_journal(sum, offset);
-                       nid_in_journal(sum, offset) = cpu_to_le32(nid);
+                       raw_ne = &nat_in_journal(journal, offset);
+                       nid_in_journal(journal, offset) = cpu_to_le32(nid);
                } else {
                        raw_ne = &nat_blk->entries[nid - start_nid];
                }
@@ -1924,7 +2012,7 @@ static void __flush_nat_entry_set(struct f2fs_sb_info *sbi,
        }
 
        if (to_journal)
-               mutex_unlock(&curseg->curseg_mutex);
+               up_write(&curseg->journal_rwsem);
        else
                f2fs_put_page(page, 1);
 
@@ -1941,7 +2029,7 @@ void flush_nat_entries(struct f2fs_sb_info *sbi)
 {
        struct f2fs_nm_info *nm_i = NM_I(sbi);
        struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_HOT_DATA);
-       struct f2fs_summary_block *sum = curseg->sum_blk;
+       struct f2fs_journal *journal = curseg->journal;
        struct nat_entry_set *setvec[SETVEC_SIZE];
        struct nat_entry_set *set, *tmp;
        unsigned int found;
@@ -1958,7 +2046,7 @@ void flush_nat_entries(struct f2fs_sb_info *sbi)
         * entries, remove all entries from journal and merge them
         * into nat entry set.
         */
-       if (!__has_cursum_space(sum, nm_i->dirty_nat_cnt, NAT_JOURNAL))
+       if (!__has_cursum_space(journal, nm_i->dirty_nat_cnt, NAT_JOURNAL))
                remove_nats_in_journal(sbi);
 
        while ((found = __gang_lookup_nat_set(nm_i,
@@ -1967,7 +2055,7 @@ void flush_nat_entries(struct f2fs_sb_info *sbi)
                set_idx = setvec[found - 1]->set + 1;
                for (idx = 0; idx < found; idx++)
                        __adjust_nat_entry_set(setvec[idx], &sets,
-                                                       MAX_NAT_JENTRIES(sum));
+                                               MAX_NAT_JENTRIES(journal));
        }
 
        /* flush dirty nats in nat entry set */
@@ -2000,6 +2088,7 @@ static int init_node_manager(struct f2fs_sb_info *sbi)
        nm_i->nat_cnt = 0;
        nm_i->ram_thresh = DEF_RAM_THRESHOLD;
        nm_i->ra_nid_pages = DEF_RA_NID_PAGES;
+       nm_i->dirty_nats_ratio = DEF_DIRTY_NAT_RATIO_THRESHOLD;
 
        INIT_RADIX_TREE(&nm_i->free_nid_root, GFP_ATOMIC);
        INIT_LIST_HEAD(&nm_i->free_nid_list);
index d4d1f63..1f4f9d4 100644 (file)
@@ -25,6 +25,9 @@
 /* control the memory footprint threshold (10MB per 1GB ram) */
 #define DEF_RAM_THRESHOLD      10
 
+/* control dirty nats ratio threshold (default: 10% over max nid count) */
+#define DEF_DIRTY_NAT_RATIO_THRESHOLD          10
+
 /* vector size for gang look-up from nat cache that consists of radix tree */
 #define NATVEC_SIZE    64
 #define SETVEC_SIZE    32
@@ -117,6 +120,12 @@ static inline void raw_nat_from_node_info(struct f2fs_nat_entry *raw_ne,
        raw_ne->version = ni->version;
 }
 
+static inline bool excess_dirty_nats(struct f2fs_sb_info *sbi)
+{
+       return NM_I(sbi)->dirty_nat_cnt >= NM_I(sbi)->max_nid *
+                                       NM_I(sbi)->dirty_nats_ratio / 100;
+}
+
 enum mem_type {
        FREE_NIDS,      /* indicates the free nid list */
        NAT_ENTRIES,    /* indicates the cached nat entry */
@@ -321,7 +330,7 @@ static inline int set_nid(struct page *p, int off, nid_t nid, bool i)
 {
        struct f2fs_node *rn = F2FS_NODE(p);
 
-       f2fs_wait_on_page_writeback(p, NODE);
+       f2fs_wait_on_page_writeback(p, NODE, true);
 
        if (i)
                rn->i.i_nid[off - NODE_DIR1_BLOCK] = cpu_to_le32(nid);
@@ -370,6 +379,21 @@ static inline int is_node(struct page *page, int type)
 #define is_fsync_dnode(page)   is_node(page, FSYNC_BIT_SHIFT)
 #define is_dent_dnode(page)    is_node(page, DENT_BIT_SHIFT)
 
+static inline int is_inline_node(struct page *page)
+{
+       return PageChecked(page);
+}
+
+static inline void set_inline_node(struct page *page)
+{
+       SetPageChecked(page);
+}
+
+static inline void clear_inline_node(struct page *page)
+{
+       ClearPageChecked(page);
+}
+
 static inline void set_cold_node(struct inode *inode, struct page *page)
 {
        struct f2fs_node *rn = F2FS_NODE(page);
index 589b20b..0b30cd2 100644 (file)
@@ -350,8 +350,7 @@ got_it:
                inode = dn->inode;
        }
 
-       bidx = start_bidx_of_node(offset, F2FS_I(inode)) +
-                       le16_to_cpu(sum.ofs_in_node);
+       bidx = start_bidx_of_node(offset, inode) + le16_to_cpu(sum.ofs_in_node);
 
        /*
         * if inode page is locked, unlock temporarily, but its reference
@@ -386,10 +385,9 @@ truncate_out:
 static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode,
                                        struct page *page, block_t blkaddr)
 {
-       struct f2fs_inode_info *fi = F2FS_I(inode);
-       unsigned int start, end;
        struct dnode_of_data dn;
        struct node_info ni;
+       unsigned int start, end;
        int err = 0, recovered = 0;
 
        /* step 1: recover xattr */
@@ -409,8 +407,8 @@ static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode,
                goto out;
 
        /* step 3: recover data indices */
-       start = start_bidx_of_node(ofs_of_node(page), fi);
-       end = start + ADDRS_PER_PAGE(page, fi);
+       start = start_bidx_of_node(ofs_of_node(page), inode);
+       end = start + ADDRS_PER_PAGE(page, inode);
 
        set_new_dnode(&dn, inode, NULL, NULL, 0);
 
@@ -418,7 +416,7 @@ static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode,
        if (err)
                goto out;
 
-       f2fs_wait_on_page_writeback(dn.node_page, NODE);
+       f2fs_wait_on_page_writeback(dn.node_page, NODE, true);
 
        get_node_info(sbi, dn.nid, &ni);
        f2fs_bug_on(sbi, ni.ino != ino_of_node(page));
@@ -467,7 +465,7 @@ static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode,
 
                        /* write dummy data page */
                        f2fs_replace_block(sbi, &dn, src, dest,
-                                                       ni.version, false);
+                                               ni.version, false, false);
                        recovered++;
                }
        }
index 5904a41..6f16b39 100644 (file)
@@ -191,70 +191,145 @@ void register_inmem_page(struct inode *inode, struct page *page)
        trace_f2fs_register_inmem_page(page, INMEM);
 }
 
-int commit_inmem_pages(struct inode *inode, bool abort)
+static int __revoke_inmem_pages(struct inode *inode,
+                               struct list_head *head, bool drop, bool recover)
+{
+       struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
+       struct inmem_pages *cur, *tmp;
+       int err = 0;
+
+       list_for_each_entry_safe(cur, tmp, head, list) {
+               struct page *page = cur->page;
+
+               if (drop)
+                       trace_f2fs_commit_inmem_page(page, INMEM_DROP);
+
+               lock_page(page);
+
+               if (recover) {
+                       struct dnode_of_data dn;
+                       struct node_info ni;
+
+                       trace_f2fs_commit_inmem_page(page, INMEM_REVOKE);
+
+                       set_new_dnode(&dn, inode, NULL, NULL, 0);
+                       if (get_dnode_of_data(&dn, page->index, LOOKUP_NODE)) {
+                               err = -EAGAIN;
+                               goto next;
+                       }
+                       get_node_info(sbi, dn.nid, &ni);
+                       f2fs_replace_block(sbi, &dn, dn.data_blkaddr,
+                                       cur->old_addr, ni.version, true, true);
+                       f2fs_put_dnode(&dn);
+               }
+next:
+               ClearPageUptodate(page);
+               set_page_private(page, 0);
+               ClearPageUptodate(page);
+               f2fs_put_page(page, 1);
+
+               list_del(&cur->list);
+               kmem_cache_free(inmem_entry_slab, cur);
+               dec_page_count(F2FS_I_SB(inode), F2FS_INMEM_PAGES);
+       }
+       return err;
+}
+
+void drop_inmem_pages(struct inode *inode)
+{
+       struct f2fs_inode_info *fi = F2FS_I(inode);
+
+       mutex_lock(&fi->inmem_lock);
+       __revoke_inmem_pages(inode, &fi->inmem_pages, true, false);
+       mutex_unlock(&fi->inmem_lock);
+}
+
+static int __commit_inmem_pages(struct inode *inode,
+                                       struct list_head *revoke_list)
 {
        struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
        struct f2fs_inode_info *fi = F2FS_I(inode);
        struct inmem_pages *cur, *tmp;
-       bool submit_bio = false;
        struct f2fs_io_info fio = {
                .sbi = sbi,
                .type = DATA,
                .rw = WRITE_SYNC | REQ_PRIO,
                .encrypted_page = NULL,
        };
+       bool submit_bio = false;
        int err = 0;
 
-       /*
-        * The abort is true only when f2fs_evict_inode is called.
-        * Basically, the f2fs_evict_inode doesn't produce any data writes, so
-        * that we don't need to call f2fs_balance_fs.
-        * Otherwise, f2fs_gc in f2fs_balance_fs can wait forever until this
-        * inode becomes free by iget_locked in f2fs_iget.
-        */
-       if (!abort) {
-               f2fs_balance_fs(sbi, true);
-               f2fs_lock_op(sbi);
-       }
-
-       mutex_lock(&fi->inmem_lock);
        list_for_each_entry_safe(cur, tmp, &fi->inmem_pages, list) {
-               lock_page(cur->page);
-               if (!abort) {
-                       if (cur->page->mapping == inode->i_mapping) {
-                               set_page_dirty(cur->page);
-                               f2fs_wait_on_page_writeback(cur->page, DATA);
-                               if (clear_page_dirty_for_io(cur->page))
-                                       inode_dec_dirty_pages(inode);
-                               trace_f2fs_commit_inmem_page(cur->page, INMEM);
-                               fio.page = cur->page;
-                               err = do_write_data_page(&fio);
-                               if (err) {
-                                       unlock_page(cur->page);
-                                       break;
-                               }
-                               clear_cold_data(cur->page);
-                               submit_bio = true;
+               struct page *page = cur->page;
+
+               lock_page(page);
+               if (page->mapping == inode->i_mapping) {
+                       trace_f2fs_commit_inmem_page(page, INMEM);
+
+                       set_page_dirty(page);
+                       f2fs_wait_on_page_writeback(page, DATA, true);
+                       if (clear_page_dirty_for_io(page))
+                               inode_dec_dirty_pages(inode);
+
+                       fio.page = page;
+                       err = do_write_data_page(&fio);
+                       if (err) {
+                               unlock_page(page);
+                               break;
                        }
-               } else {
-                       ClearPageUptodate(cur->page);
-                       trace_f2fs_commit_inmem_page(cur->page, INMEM_DROP);
+
+                       /* record old blkaddr for revoking */
+                       cur->old_addr = fio.old_blkaddr;
+
+                       clear_cold_data(page);
+                       submit_bio = true;
                }
-               set_page_private(cur->page, 0);
-               ClearPagePrivate(cur->page);
-               f2fs_put_page(cur->page, 1);
+               unlock_page(page);
+               list_move_tail(&cur->list, revoke_list);
+       }
 
-               list_del(&cur->list);
-               kmem_cache_free(inmem_entry_slab, cur);
-               dec_page_count(F2FS_I_SB(inode), F2FS_INMEM_PAGES);
+       if (submit_bio)
+               f2fs_submit_merged_bio_cond(sbi, inode, NULL, 0, DATA, WRITE);
+
+       if (!err)
+               __revoke_inmem_pages(inode, revoke_list, false, false);
+
+       return err;
+}
+
+int commit_inmem_pages(struct inode *inode)
+{
+       struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
+       struct f2fs_inode_info *fi = F2FS_I(inode);
+       struct list_head revoke_list;
+       int err;
+
+       INIT_LIST_HEAD(&revoke_list);
+       f2fs_balance_fs(sbi, true);
+       f2fs_lock_op(sbi);
+
+       mutex_lock(&fi->inmem_lock);
+       err = __commit_inmem_pages(inode, &revoke_list);
+       if (err) {
+               int ret;
+               /*
+                * try to revoke all committed pages, but still we could fail
+                * due to no memory or other reason, if that happened, EAGAIN
+                * will be returned, which means in such case, transaction is
+                * already not integrity, caller should use journal to do the
+                * recovery or rewrite & commit last transaction. For other
+                * error number, revoking was done by filesystem itself.
+                */
+               ret = __revoke_inmem_pages(inode, &revoke_list, false, true);
+               if (ret)
+                       err = ret;
+
+               /* drop all uncommitted pages */
+               __revoke_inmem_pages(inode, &fi->inmem_pages, true, false);
        }
        mutex_unlock(&fi->inmem_lock);
 
-       if (!abort) {
-               f2fs_unlock_op(sbi);
-               if (submit_bio)
-                       f2fs_submit_merged_bio(sbi, DATA, WRITE);
-       }
+       f2fs_unlock_op(sbi);
        return err;
 }
 
@@ -291,11 +366,17 @@ void f2fs_balance_fs_bg(struct f2fs_sb_info *sbi)
 
        /* checkpoint is the only way to shrink partial cached entries */
        if (!available_free_memory(sbi, NAT_ENTRIES) ||
-                       excess_prefree_segs(sbi) ||
                        !available_free_memory(sbi, INO_ENTRIES) ||
+                       excess_prefree_segs(sbi) ||
+                       excess_dirty_nats(sbi) ||
                        (is_idle(sbi) && f2fs_time_over(sbi, CP_TIME))) {
-               if (test_opt(sbi, DATA_FLUSH))
+               if (test_opt(sbi, DATA_FLUSH)) {
+                       struct blk_plug plug;
+
+                       blk_start_plug(&plug);
                        sync_dirty_inodes(sbi, FILE_INODE);
+                       blk_finish_plug(&plug);
+               }
                f2fs_sync_fs(sbi->sb, true);
                stat_inc_bg_cp_count(sbi->stat_info);
        }
@@ -502,7 +583,7 @@ static int f2fs_issue_discard(struct f2fs_sb_info *sbi,
 
 bool discard_next_dnode(struct f2fs_sb_info *sbi, block_t blkaddr)
 {
-       int err = -ENOTSUPP;
+       int err = -EOPNOTSUPP;
 
        if (test_opt(sbi, DISCARD)) {
                struct seg_entry *se = get_seg_entry(sbi,
@@ -841,6 +922,31 @@ static void write_sum_page(struct f2fs_sb_info *sbi,
        update_meta_page(sbi, (void *)sum_blk, blk_addr);
 }
 
+static void write_current_sum_page(struct f2fs_sb_info *sbi,
+                                               int type, block_t blk_addr)
+{
+       struct curseg_info *curseg = CURSEG_I(sbi, type);
+       struct page *page = grab_meta_page(sbi, blk_addr);
+       struct f2fs_summary_block *src = curseg->sum_blk;
+       struct f2fs_summary_block *dst;
+
+       dst = (struct f2fs_summary_block *)page_address(page);
+
+       mutex_lock(&curseg->curseg_mutex);
+
+       down_read(&curseg->journal_rwsem);
+       memcpy(&dst->journal, curseg->journal, SUM_JOURNAL_SIZE);
+       up_read(&curseg->journal_rwsem);
+
+       memcpy(dst->entries, src->entries, SUM_ENTRY_SIZE);
+       memcpy(&dst->footer, &src->footer, SUM_FOOTER_SIZE);
+
+       mutex_unlock(&curseg->curseg_mutex);
+
+       set_page_dirty(page);
+       f2fs_put_page(page, 1);
+}
+
 static int is_next_segment_free(struct f2fs_sb_info *sbi, int type)
 {
        struct curseg_info *curseg = CURSEG_I(sbi, type);
@@ -873,9 +979,8 @@ static void get_new_segment(struct f2fs_sb_info *sbi,
 
        if (!new_sec && ((*newseg + 1) % sbi->segs_per_sec)) {
                segno = find_next_zero_bit(free_i->free_segmap,
-                                       MAIN_SEGS(sbi), *newseg + 1);
-               if (segno - *newseg < sbi->segs_per_sec -
-                                       (*newseg % sbi->segs_per_sec))
+                               (hint + 1) * sbi->segs_per_sec, *newseg + 1);
+               if (segno < (hint + 1) * sbi->segs_per_sec)
                        goto got_it;
        }
 find_other_zone:
@@ -1280,8 +1385,8 @@ static void do_write_page(struct f2fs_summary *sum, struct f2fs_io_info *fio)
 {
        int type = __get_segment_type(fio->page, fio->type);
 
-       allocate_data_block(fio->sbi, fio->page, fio->blk_addr,
-                                       &fio->blk_addr, sum, type);
+       allocate_data_block(fio->sbi, fio->page, fio->old_blkaddr,
+                                       &fio->new_blkaddr, sum, type);
 
        /* writeout dirty page into bdev */
        f2fs_submit_page_mbio(fio);
@@ -1293,7 +1398,8 @@ void write_meta_page(struct f2fs_sb_info *sbi, struct page *page)
                .sbi = sbi,
                .type = META,
                .rw = WRITE_SYNC | REQ_META | REQ_PRIO,
-               .blk_addr = page->index,
+               .old_blkaddr = page->index,
+               .new_blkaddr = page->index,
                .page = page,
                .encrypted_page = NULL,
        };
@@ -1323,19 +1429,19 @@ void write_data_page(struct dnode_of_data *dn, struct f2fs_io_info *fio)
        get_node_info(sbi, dn->nid, &ni);
        set_summary(&sum, dn->nid, dn->ofs_in_node, ni.version);
        do_write_page(&sum, fio);
-       dn->data_blkaddr = fio->blk_addr;
+       f2fs_update_data_blkaddr(dn, fio->new_blkaddr);
 }
 
 void rewrite_data_page(struct f2fs_io_info *fio)
 {
+       fio->new_blkaddr = fio->old_blkaddr;
        stat_inc_inplace_blocks(fio->sbi);
        f2fs_submit_page_mbio(fio);
 }
 
-static void __f2fs_replace_block(struct f2fs_sb_info *sbi,
-                               struct f2fs_summary *sum,
+void __f2fs_replace_block(struct f2fs_sb_info *sbi, struct f2fs_summary *sum,
                                block_t old_blkaddr, block_t new_blkaddr,
-                               bool recover_curseg)
+                               bool recover_curseg, bool recover_newaddr)
 {
        struct sit_info *sit_i = SIT_I(sbi);
        struct curseg_info *curseg;
@@ -1378,7 +1484,7 @@ static void __f2fs_replace_block(struct f2fs_sb_info *sbi,
        curseg->next_blkoff = GET_BLKOFF_FROM_SEG0(sbi, new_blkaddr);
        __add_sum_entry(sbi, type, sum);
 
-       if (!recover_curseg)
+       if (!recover_curseg || recover_newaddr)
                update_sit_entry(sbi, new_blkaddr, 1);
        if (GET_SEGNO(sbi, old_blkaddr) != NULL_SEGNO)
                update_sit_entry(sbi, old_blkaddr, -1);
@@ -1402,66 +1508,30 @@ static void __f2fs_replace_block(struct f2fs_sb_info *sbi,
 
 void f2fs_replace_block(struct f2fs_sb_info *sbi, struct dnode_of_data *dn,
                                block_t old_addr, block_t new_addr,
-                               unsigned char version, bool recover_curseg)
+                               unsigned char version, bool recover_curseg,
+                               bool recover_newaddr)
 {
        struct f2fs_summary sum;
 
        set_summary(&sum, dn->nid, dn->ofs_in_node, version);
 
-       __f2fs_replace_block(sbi, &sum, old_addr, new_addr, recover_curseg);
+       __f2fs_replace_block(sbi, &sum, old_addr, new_addr,
+                                       recover_curseg, recover_newaddr);
 
-       dn->data_blkaddr = new_addr;
-       set_data_blkaddr(dn);
-       f2fs_update_extent_cache(dn);
-}
-
-static inline bool is_merged_page(struct f2fs_sb_info *sbi,
-                                       struct page *page, enum page_type type)
-{
-       enum page_type btype = PAGE_TYPE_OF_BIO(type);
-       struct f2fs_bio_info *io = &sbi->write_io[btype];
-       struct bio_vec *bvec;
-       struct page *target;
-       int i;
-
-       down_read(&io->io_rwsem);
-       if (!io->bio) {
-               up_read(&io->io_rwsem);
-               return false;
-       }
-
-       bio_for_each_segment_all(bvec, io->bio, i) {
-
-               if (bvec->bv_page->mapping) {
-                       target = bvec->bv_page;
-               } else {
-                       struct f2fs_crypto_ctx *ctx;
-
-                       /* encrypted page */
-                       ctx = (struct f2fs_crypto_ctx *)page_private(
-                                                               bvec->bv_page);
-                       target = ctx->w.control_page;
-               }
-
-               if (page == target) {
-                       up_read(&io->io_rwsem);
-                       return true;
-               }
-       }
-
-       up_read(&io->io_rwsem);
-       return false;
+       f2fs_update_data_blkaddr(dn, new_addr);
 }
 
 void f2fs_wait_on_page_writeback(struct page *page,
-                               enum page_type type)
+                               enum page_type type, bool ordered)
 {
        if (PageWriteback(page)) {
                struct f2fs_sb_info *sbi = F2FS_P_SB(page);
 
-               if (is_merged_page(sbi, page, type))
-                       f2fs_submit_merged_bio(sbi, type, WRITE);
-               wait_on_page_writeback(page);
+               f2fs_submit_merged_bio_cond(sbi, NULL, page, 0, type, WRITE);
+               if (ordered)
+                       wait_on_page_writeback(page);
+               else
+                       wait_for_stable_page(page);
        }
 }
 
@@ -1477,7 +1547,7 @@ void f2fs_wait_on_encrypted_page_writeback(struct f2fs_sb_info *sbi,
 
        cpage = find_lock_page(META_MAPPING(sbi), blkaddr);
        if (cpage) {
-               f2fs_wait_on_page_writeback(cpage, DATA);
+               f2fs_wait_on_page_writeback(cpage, DATA, true);
                f2fs_put_page(cpage, 1);
        }
 }
@@ -1498,12 +1568,11 @@ static int read_compacted_summaries(struct f2fs_sb_info *sbi)
 
        /* Step 1: restore nat cache */
        seg_i = CURSEG_I(sbi, CURSEG_HOT_DATA);
-       memcpy(&seg_i->sum_blk->n_nats, kaddr, SUM_JOURNAL_SIZE);
+       memcpy(seg_i->journal, kaddr, SUM_JOURNAL_SIZE);
 
        /* Step 2: restore sit cache */
        seg_i = CURSEG_I(sbi, CURSEG_COLD_DATA);
-       memcpy(&seg_i->sum_blk->n_sits, kaddr + SUM_JOURNAL_SIZE,
-                                               SUM_JOURNAL_SIZE);
+       memcpy(seg_i->journal, kaddr + SUM_JOURNAL_SIZE, SUM_JOURNAL_SIZE);
        offset = 2 * SUM_JOURNAL_SIZE;
 
        /* Step 3: restore summary entries */
@@ -1599,7 +1668,14 @@ static int read_normal_summaries(struct f2fs_sb_info *sbi, int type)
        /* set uncompleted segment to curseg */
        curseg = CURSEG_I(sbi, type);
        mutex_lock(&curseg->curseg_mutex);
-       memcpy(curseg->sum_blk, sum, PAGE_CACHE_SIZE);
+
+       /* update journal info */
+       down_write(&curseg->journal_rwsem);
+       memcpy(curseg->journal, &sum->journal, SUM_JOURNAL_SIZE);
+       up_write(&curseg->journal_rwsem);
+
+       memcpy(curseg->sum_blk->entries, sum->entries, SUM_ENTRY_SIZE);
+       memcpy(&curseg->sum_blk->footer, &sum->footer, SUM_FOOTER_SIZE);
        curseg->next_segno = segno;
        reset_curseg(sbi, type, 0);
        curseg->alloc_type = ckpt->alloc_type[type];
@@ -1654,13 +1730,12 @@ static void write_compacted_summaries(struct f2fs_sb_info *sbi, block_t blkaddr)
 
        /* Step 1: write nat cache */
        seg_i = CURSEG_I(sbi, CURSEG_HOT_DATA);
-       memcpy(kaddr, &seg_i->sum_blk->n_nats, SUM_JOURNAL_SIZE);
+       memcpy(kaddr, seg_i->journal, SUM_JOURNAL_SIZE);
        written_size += SUM_JOURNAL_SIZE;
 
        /* Step 2: write sit cache */
        seg_i = CURSEG_I(sbi, CURSEG_COLD_DATA);
-       memcpy(kaddr + written_size, &seg_i->sum_blk->n_sits,
-                                               SUM_JOURNAL_SIZE);
+       memcpy(kaddr + written_size, seg_i->journal, SUM_JOURNAL_SIZE);
        written_size += SUM_JOURNAL_SIZE;
 
        /* Step 3: write summary entries */
@@ -1706,12 +1781,8 @@ static void write_normal_summaries(struct f2fs_sb_info *sbi,
        else
                end = type + NR_CURSEG_NODE_TYPE;
 
-       for (i = type; i < end; i++) {
-               struct curseg_info *sum = CURSEG_I(sbi, i);
-               mutex_lock(&sum->curseg_mutex);
-               write_sum_page(sbi, sum->sum_blk, blkaddr + (i - type));
-               mutex_unlock(&sum->curseg_mutex);
-       }
+       for (i = type; i < end; i++)
+               write_current_sum_page(sbi, i, blkaddr + (i - type));
 }
 
 void write_data_summaries(struct f2fs_sb_info *sbi, block_t start_blk)
@@ -1727,24 +1798,24 @@ void write_node_summaries(struct f2fs_sb_info *sbi, block_t start_blk)
        write_normal_summaries(sbi, start_blk, CURSEG_HOT_NODE);
 }
 
-int lookup_journal_in_cursum(struct f2fs_summary_block *sum, int type,
+int lookup_journal_in_cursum(struct f2fs_journal *journal, int type,
                                        unsigned int val, int alloc)
 {
        int i;
 
        if (type == NAT_JOURNAL) {
-               for (i = 0; i < nats_in_cursum(sum); i++) {
-                       if (le32_to_cpu(nid_in_journal(sum, i)) == val)
+               for (i = 0; i < nats_in_cursum(journal); i++) {
+                       if (le32_to_cpu(nid_in_journal(journal, i)) == val)
                                return i;
                }
-               if (alloc && __has_cursum_space(sum, 1, NAT_JOURNAL))
-                       return update_nats_in_cursum(sum, 1);
+               if (alloc && __has_cursum_space(journal, 1, NAT_JOURNAL))
+                       return update_nats_in_cursum(journal, 1);
        } else if (type == SIT_JOURNAL) {
-               for (i = 0; i < sits_in_cursum(sum); i++)
-                       if (le32_to_cpu(segno_in_journal(sum, i)) == val)
+               for (i = 0; i < sits_in_cursum(journal); i++)
+                       if (le32_to_cpu(segno_in_journal(journal, i)) == val)
                                return i;
-               if (alloc && __has_cursum_space(sum, 1, SIT_JOURNAL))
-                       return update_sits_in_cursum(sum, 1);
+               if (alloc && __has_cursum_space(journal, 1, SIT_JOURNAL))
+                       return update_sits_in_cursum(journal, 1);
        }
        return -1;
 }
@@ -1848,20 +1919,22 @@ static void add_sits_in_set(struct f2fs_sb_info *sbi)
 static void remove_sits_in_journal(struct f2fs_sb_info *sbi)
 {
        struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_COLD_DATA);
-       struct f2fs_summary_block *sum = curseg->sum_blk;
+       struct f2fs_journal *journal = curseg->journal;
        int i;
 
-       for (i = sits_in_cursum(sum) - 1; i >= 0; i--) {
+       down_write(&curseg->journal_rwsem);
+       for (i = 0; i < sits_in_cursum(journal); i++) {
                unsigned int segno;
                bool dirtied;
 
-               segno = le32_to_cpu(segno_in_journal(sum, i));
+               segno = le32_to_cpu(segno_in_journal(journal, i));
                dirtied = __mark_sit_entry_dirty(sbi, segno);
 
                if (!dirtied)
                        add_sit_entry(segno, &SM_I(sbi)->sit_entry_set);
        }
-       update_sits_in_cursum(sum, -sits_in_cursum(sum));
+       update_sits_in_cursum(journal, -i);
+       up_write(&curseg->journal_rwsem);
 }
 
 /*
@@ -1873,13 +1946,12 @@ void flush_sit_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc)
        struct sit_info *sit_i = SIT_I(sbi);
        unsigned long *bitmap = sit_i->dirty_sentries_bitmap;
        struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_COLD_DATA);
-       struct f2fs_summary_block *sum = curseg->sum_blk;
+       struct f2fs_journal *journal = curseg->journal;
        struct sit_entry_set *ses, *tmp;
        struct list_head *head = &SM_I(sbi)->sit_entry_set;
        bool to_journal = true;
        struct seg_entry *se;
 
-       mutex_lock(&curseg->curseg_mutex);
        mutex_lock(&sit_i->sentry_lock);
 
        if (!sit_i->dirty_sentries)
@@ -1896,7 +1968,7 @@ void flush_sit_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc)
         * entries, remove all entries from journal and add and account
         * them in sit entry set.
         */
-       if (!__has_cursum_space(sum, sit_i->dirty_sentries, SIT_JOURNAL))
+       if (!__has_cursum_space(journal, sit_i->dirty_sentries, SIT_JOURNAL))
                remove_sits_in_journal(sbi);
 
        /*
@@ -1913,10 +1985,12 @@ void flush_sit_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc)
                unsigned int segno = start_segno;
 
                if (to_journal &&
-                       !__has_cursum_space(sum, ses->entry_cnt, SIT_JOURNAL))
+                       !__has_cursum_space(journal, ses->entry_cnt, SIT_JOURNAL))
                        to_journal = false;
 
-               if (!to_journal) {
+               if (to_journal) {
+                       down_write(&curseg->journal_rwsem);
+               } else {
                        page = get_next_sit_page(sbi, start_segno);
                        raw_sit = page_address(page);
                }
@@ -1934,13 +2008,13 @@ void flush_sit_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc)
                        }
 
                        if (to_journal) {
-                               offset = lookup_journal_in_cursum(sum,
+                               offset = lookup_journal_in_cursum(journal,
                                                        SIT_JOURNAL, segno, 1);
                                f2fs_bug_on(sbi, offset < 0);
-                               segno_in_journal(sum, offset) =
+                               segno_in_journal(journal, offset) =
                                                        cpu_to_le32(segno);
                                seg_info_to_raw_sit(se,
-                                               &sit_in_journal(sum, offset));
+                                       &sit_in_journal(journal, offset));
                        } else {
                                sit_offset = SIT_ENTRY_OFFSET(sit_i, segno);
                                seg_info_to_raw_sit(se,
@@ -1952,7 +2026,9 @@ void flush_sit_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc)
                        ses->entry_cnt--;
                }
 
-               if (!to_journal)
+               if (to_journal)
+                       up_write(&curseg->journal_rwsem);
+               else
                        f2fs_put_page(page, 1);
 
                f2fs_bug_on(sbi, ses->entry_cnt);
@@ -1967,7 +2043,6 @@ out:
                        add_discard_addrs(sbi, cpc);
        }
        mutex_unlock(&sit_i->sentry_lock);
-       mutex_unlock(&curseg->curseg_mutex);
 
        set_prefree_as_free_segments(sbi);
 }
@@ -2099,6 +2174,11 @@ static int build_curseg(struct f2fs_sb_info *sbi)
                array[i].sum_blk = kzalloc(PAGE_CACHE_SIZE, GFP_KERNEL);
                if (!array[i].sum_blk)
                        return -ENOMEM;
+               init_rwsem(&array[i].journal_rwsem);
+               array[i].journal = kzalloc(sizeof(struct f2fs_journal),
+                                                       GFP_KERNEL);
+               if (!array[i].journal)
+                       return -ENOMEM;
                array[i].segno = NULL_SEGNO;
                array[i].next_blkoff = 0;
        }
@@ -2109,11 +2189,11 @@ static void build_sit_entries(struct f2fs_sb_info *sbi)
 {
        struct sit_info *sit_i = SIT_I(sbi);
        struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_COLD_DATA);
-       struct f2fs_summary_block *sum = curseg->sum_blk;
+       struct f2fs_journal *journal = curseg->journal;
        int sit_blk_cnt = SIT_BLK_CNT(sbi);
        unsigned int i, start, end;
        unsigned int readed, start_blk = 0;
-       int nrpages = MAX_BIO_BLOCKS(sbi);
+       int nrpages = MAX_BIO_BLOCKS(sbi) * 8;
 
        do {
                readed = ra_meta_pages(sbi, start_blk, nrpages, META_SIT, true);
@@ -2127,16 +2207,16 @@ static void build_sit_entries(struct f2fs_sb_info *sbi)
                        struct f2fs_sit_entry sit;
                        struct page *page;
 
-                       mutex_lock(&curseg->curseg_mutex);
-                       for (i = 0; i < sits_in_cursum(sum); i++) {
-                               if (le32_to_cpu(segno_in_journal(sum, i))
+                       down_read(&curseg->journal_rwsem);
+                       for (i = 0; i < sits_in_cursum(journal); i++) {
+                               if (le32_to_cpu(segno_in_journal(journal, i))
                                                                == start) {
-                                       sit = sit_in_journal(sum, i);
-                                       mutex_unlock(&curseg->curseg_mutex);
+                                       sit = sit_in_journal(journal, i);
+                                       up_read(&curseg->journal_rwsem);
                                        goto got_it;
                                }
                        }
-                       mutex_unlock(&curseg->curseg_mutex);
+                       up_read(&curseg->journal_rwsem);
 
                        page = get_current_sit_page(sbi, start);
                        sit_blk = (struct f2fs_sit_block *)page_address(page);
@@ -2371,8 +2451,10 @@ static void destroy_curseg(struct f2fs_sb_info *sbi)
        if (!array)
                return;
        SM_I(sbi)->curseg_array = NULL;
-       for (i = 0; i < NR_CURSEG_TYPE; i++)
+       for (i = 0; i < NR_CURSEG_TYPE; i++) {
                kfree(array[i].sum_blk);
+               kfree(array[i].journal);
+       }
        kfree(array);
 }
 
index ee44d34..975c33d 100644 (file)
@@ -183,7 +183,7 @@ struct segment_allocation {
  * this value is set in page as a private data which indicate that
  * the page is atomically written, and it is in inmem_pages list.
  */
-#define ATOMIC_WRITTEN_PAGE            0x0000ffff
+#define ATOMIC_WRITTEN_PAGE            ((unsigned long)-1)
 
 #define IS_ATOMIC_WRITTEN_PAGE(page)                   \
                (page_private(page) == (unsigned long)ATOMIC_WRITTEN_PAGE)
@@ -191,6 +191,7 @@ struct segment_allocation {
 struct inmem_pages {
        struct list_head list;
        struct page *page;
+       block_t old_addr;               /* for revoking when fail to commit */
 };
 
 struct sit_info {
@@ -257,6 +258,8 @@ struct victim_selection {
 struct curseg_info {
        struct mutex curseg_mutex;              /* lock for consistency */
        struct f2fs_summary_block *sum_blk;     /* cached summary block */
+       struct rw_semaphore journal_rwsem;      /* protect journal area */
+       struct f2fs_journal *journal;           /* cached journal info */
        unsigned char alloc_type;               /* current allocation type */
        unsigned int segno;                     /* current segment number */
        unsigned short next_blkoff;             /* next block offset to write */
index 6134832..15bb81f 100644 (file)
@@ -126,6 +126,19 @@ static unsigned char *__struct_ptr(struct f2fs_sb_info *sbi, int struct_type)
        return NULL;
 }
 
+static ssize_t lifetime_write_kbytes_show(struct f2fs_attr *a,
+               struct f2fs_sb_info *sbi, char *buf)
+{
+       struct super_block *sb = sbi->sb;
+
+       if (!sb->s_bdev->bd_part)
+               return snprintf(buf, PAGE_SIZE, "0\n");
+
+       return snprintf(buf, PAGE_SIZE, "%llu\n",
+               (unsigned long long)(sbi->kbytes_written +
+                       BD_PART_WRITTEN(sbi)));
+}
+
 static ssize_t f2fs_sbi_show(struct f2fs_attr *a,
                        struct f2fs_sb_info *sbi, char *buf)
 {
@@ -204,6 +217,9 @@ static struct f2fs_attr f2fs_attr_##_name = {                       \
                f2fs_sbi_show, f2fs_sbi_store,                  \
                offsetof(struct struct_name, elname))
 
+#define F2FS_GENERAL_RO_ATTR(name) \
+static struct f2fs_attr f2fs_attr_##name = __ATTR(name, 0444, name##_show, NULL)
+
 F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_min_sleep_time, min_sleep_time);
 F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_max_sleep_time, max_sleep_time);
 F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_no_gc_sleep_time, no_gc_sleep_time);
@@ -216,10 +232,12 @@ F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, min_ipu_util, min_ipu_util);
 F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, min_fsync_blocks, min_fsync_blocks);
 F2FS_RW_ATTR(NM_INFO, f2fs_nm_info, ram_thresh, ram_thresh);
 F2FS_RW_ATTR(NM_INFO, f2fs_nm_info, ra_nid_pages, ra_nid_pages);
+F2FS_RW_ATTR(NM_INFO, f2fs_nm_info, dirty_nats_ratio, dirty_nats_ratio);
 F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, max_victim_search, max_victim_search);
 F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, dir_level, dir_level);
 F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, cp_interval, interval_time[CP_TIME]);
 F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, idle_interval, interval_time[REQ_TIME]);
+F2FS_GENERAL_RO_ATTR(lifetime_write_kbytes);
 
 #define ATTR_LIST(name) (&f2fs_attr_##name.attr)
 static struct attribute *f2fs_attrs[] = {
@@ -237,8 +255,10 @@ static struct attribute *f2fs_attrs[] = {
        ATTR_LIST(dir_level),
        ATTR_LIST(ram_thresh),
        ATTR_LIST(ra_nid_pages),
+       ATTR_LIST(dirty_nats_ratio),
        ATTR_LIST(cp_interval),
        ATTR_LIST(idle_interval),
+       ATTR_LIST(lifetime_write_kbytes),
        NULL,
 };
 
@@ -450,10 +470,6 @@ static struct inode *f2fs_alloc_inode(struct super_block *sb)
 
        /* Will be used by directory only */
        fi->i_dir_level = F2FS_SB(sb)->dir_level;
-
-#ifdef CONFIG_F2FS_FS_ENCRYPTION
-       fi->i_crypt_info = NULL;
-#endif
        return &fi->vfs_inode;
 }
 
@@ -474,7 +490,7 @@ static int f2fs_drop_inode(struct inode *inode)
 
                        /* some remained atomic pages should discarded */
                        if (f2fs_is_atomic_file(inode))
-                               commit_inmem_pages(inode, true);
+                               drop_inmem_pages(inode);
 
                        /* should remain fi->extent_tree for writepage */
                        f2fs_destroy_extent_node(inode);
@@ -487,11 +503,7 @@ static int f2fs_drop_inode(struct inode *inode)
 
                        sb_end_intwrite(inode->i_sb);
 
-#ifdef CONFIG_F2FS_FS_ENCRYPTION
-                       if (F2FS_I(inode)->i_crypt_info)
-                               f2fs_free_encryption_info(inode,
-                                       F2FS_I(inode)->i_crypt_info);
-#endif
+                       fscrypt_put_encryption_info(inode, NULL);
                        spin_lock(&inode->i_lock);
                        atomic_dec(&inode->i_count);
                }
@@ -562,6 +574,10 @@ static void f2fs_put_super(struct super_block *sb)
        f2fs_leave_shrinker(sbi);
        mutex_unlock(&sbi->umount_mutex);
 
+       /* our cp_error case, we can wait for any writeback page */
+       if (get_pages(sbi, F2FS_WRITEBACK))
+               f2fs_flush_merged_bios(sbi);
+
        iput(sbi->node_inode);
        iput(sbi->meta_inode);
 
@@ -574,6 +590,8 @@ static void f2fs_put_super(struct super_block *sb)
        wait_for_completion(&sbi->s_kobj_unregister);
 
        sb->s_fs_info = NULL;
+       if (sbi->s_chksum_driver)
+               crypto_free_shash(sbi->s_chksum_driver);
        kfree(sbi->raw_super);
        kfree(sbi);
 }
@@ -766,8 +784,6 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data)
        bool need_stop_gc = false;
        bool no_extent_cache = !test_opt(sbi, EXTENT_CACHE);
 
-       sync_filesystem(sb);
-
        /*
         * Save the old mount options in case we
         * need to restore them.
@@ -775,6 +791,13 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data)
        org_mount_opt = sbi->mount_opt;
        active_logs = sbi->active_logs;
 
+       if (*flags & MS_RDONLY) {
+               set_opt(sbi, FASTBOOT);
+               set_sbi_flag(sbi, SBI_IS_DIRTY);
+       }
+
+       sync_filesystem(sb);
+
        sbi->mount_opt.opt = 0;
        default_options(sbi);
 
@@ -862,6 +885,41 @@ static struct super_operations f2fs_sops = {
        .remount_fs     = f2fs_remount,
 };
 
+#ifdef CONFIG_F2FS_FS_ENCRYPTION
+static int f2fs_get_context(struct inode *inode, void *ctx, size_t len)
+{
+       return f2fs_getxattr(inode, F2FS_XATTR_INDEX_ENCRYPTION,
+                               F2FS_XATTR_NAME_ENCRYPTION_CONTEXT,
+                               ctx, len, NULL);
+}
+
+static int f2fs_set_context(struct inode *inode, const void *ctx, size_t len,
+                                                       void *fs_data)
+{
+       return f2fs_setxattr(inode, F2FS_XATTR_INDEX_ENCRYPTION,
+                               F2FS_XATTR_NAME_ENCRYPTION_CONTEXT,
+                               ctx, len, fs_data, XATTR_CREATE);
+}
+
+static unsigned f2fs_max_namelen(struct inode *inode)
+{
+       return S_ISLNK(inode->i_mode) ?
+                       inode->i_sb->s_blocksize : F2FS_NAME_LEN;
+}
+
+static struct fscrypt_operations f2fs_cryptops = {
+       .get_context    = f2fs_get_context,
+       .set_context    = f2fs_set_context,
+       .is_encrypted   = f2fs_encrypted_inode,
+       .empty_dir      = f2fs_empty_dir,
+       .max_namelen    = f2fs_max_namelen,
+};
+#else
+static struct fscrypt_operations f2fs_cryptops = {
+       .is_encrypted   = f2fs_encrypted_inode,
+};
+#endif
+
 static struct inode *f2fs_nfs_get_inode(struct super_block *sb,
                u64 ino, u32 generation)
 {
@@ -1074,7 +1132,7 @@ static int sanity_check_raw_super(struct super_block *sb,
        return 0;
 }
 
-static int sanity_check_ckpt(struct f2fs_sb_info *sbi)
+int sanity_check_ckpt(struct f2fs_sb_info *sbi)
 {
        unsigned int total, fsmeta;
        struct f2fs_super_block *raw_super = F2FS_RAW_SUPER(sbi);
@@ -1134,14 +1192,15 @@ static void init_sb_info(struct f2fs_sb_info *sbi)
 
 /*
  * Read f2fs raw super block.
- * Because we have two copies of super block, so read the first one at first,
- * if the first one is invalid, move to read the second one.
+ * Because we have two copies of super block, so read both of them
+ * to get the first valid one. If any one of them is broken, we pass
+ * them recovery flag back to the caller.
  */
 static int read_raw_super_block(struct super_block *sb,
                        struct f2fs_super_block **raw_super,
                        int *valid_super_block, int *recovery)
 {
-       int block = 0;
+       int block;
        struct buffer_head *bh;
        struct f2fs_super_block *super, *buf;
        int err = 0;
@@ -1149,50 +1208,48 @@ static int read_raw_super_block(struct super_block *sb,
        super = kzalloc(sizeof(struct f2fs_super_block), GFP_KERNEL);
        if (!super)
                return -ENOMEM;
-retry:
-       bh = sb_bread(sb, block);
-       if (!bh) {
-               *recovery = 1;
-               f2fs_msg(sb, KERN_ERR, "Unable to read %dth superblock",
+
+       for (block = 0; block < 2; block++) {
+               bh = sb_bread(sb, block);
+               if (!bh) {
+                       f2fs_msg(sb, KERN_ERR, "Unable to read %dth superblock",
                                block + 1);
-               err = -EIO;
-               goto next;
-       }
+                       err = -EIO;
+                       continue;
+               }
 
-       buf = (struct f2fs_super_block *)(bh->b_data + F2FS_SUPER_OFFSET);
+               buf = (struct f2fs_super_block *)
+                               (bh->b_data + F2FS_SUPER_OFFSET);
 
-       /* sanity checking of raw super */
-       if (sanity_check_raw_super(sb, buf)) {
-               brelse(bh);
-               *recovery = 1;
-               f2fs_msg(sb, KERN_ERR,
-                       "Can't find valid F2FS filesystem in %dth superblock",
-                                                               block + 1);
-               err = -EINVAL;
-               goto next;
-       }
+               /* sanity checking of raw super */
+               if (sanity_check_raw_super(sb, buf)) {
+                       f2fs_msg(sb, KERN_ERR,
+                               "Can't find valid F2FS filesystem in %dth superblock",
+                               block + 1);
+                       err = -EINVAL;
+                       brelse(bh);
+                       continue;
+               }
 
-       if (!*raw_super) {
-               memcpy(super, buf, sizeof(*super));
-               *valid_super_block = block;
-               *raw_super = super;
+               if (!*raw_super) {
+                       memcpy(super, buf, sizeof(*super));
+                       *valid_super_block = block;
+                       *raw_super = super;
+               }
+               brelse(bh);
        }
-       brelse(bh);
 
-next:
-       /* check the validity of the second superblock */
-       if (block == 0) {
-               block++;
-               goto retry;
-       }
+       /* Fail to read any one of the superblocks*/
+       if (err < 0)
+               *recovery = 1;
 
        /* No valid superblock */
-       if (!*raw_super) {
+       if (!*raw_super)
                kfree(super);
-               return err;
-       }
+       else
+               err = 0;
 
-       return 0;
+       return err;
 }
 
 static int __f2fs_commit_super(struct f2fs_sb_info *sbi, int block)
@@ -1242,6 +1299,7 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
        bool retry = true, need_fsck = false;
        char *options = NULL;
        int recovery, i, valid_super_block;
+       struct curseg_info *seg_i;
 
 try_onemore:
        err = -EINVAL;
@@ -1254,6 +1312,15 @@ try_onemore:
        if (!sbi)
                return -ENOMEM;
 
+       /* Load the checksum driver */
+       sbi->s_chksum_driver = crypto_alloc_shash("crc32", 0, 0);
+       if (IS_ERR(sbi->s_chksum_driver)) {
+               f2fs_msg(sb, KERN_ERR, "Cannot load crc32 driver.");
+               err = PTR_ERR(sbi->s_chksum_driver);
+               sbi->s_chksum_driver = NULL;
+               goto free_sbi;
+       }
+
        /* set a block size */
        if (unlikely(!sb_set_blocksize(sb, F2FS_BLKSIZE))) {
                f2fs_msg(sb, KERN_ERR, "unable to set blocksize");
@@ -1285,6 +1352,7 @@ try_onemore:
        get_random_bytes(&sbi->s_next_generation, sizeof(u32));
 
        sb->s_op = &f2fs_sops;
+       sb->s_cop = &f2fs_cryptops;
        sb->s_xattr = f2fs_xattr_handlers;
        sb->s_export_op = &f2fs_export_ops;
        sb->s_magic = F2FS_SUPER_MAGIC;
@@ -1333,13 +1401,6 @@ try_onemore:
                goto free_meta_inode;
        }
 
-       /* sanity checking of checkpoint */
-       err = -EINVAL;
-       if (sanity_check_ckpt(sbi)) {
-               f2fs_msg(sb, KERN_ERR, "Invalid F2FS checkpoint");
-               goto free_cp;
-       }
-
        sbi->total_valid_node_count =
                                le32_to_cpu(sbi->ckpt->valid_node_count);
        sbi->total_valid_inode_count =
@@ -1372,6 +1433,17 @@ try_onemore:
                goto free_nm;
        }
 
+       /* For write statistics */
+       if (sb->s_bdev->bd_part)
+               sbi->sectors_written_start =
+                       (u64)part_stat_read(sb->s_bdev->bd_part, sectors[1]);
+
+       /* Read accumulated write IO statistics if exists */
+       seg_i = CURSEG_I(sbi, CURSEG_HOT_NODE);
+       if (__exist_node_summaries(sbi))
+               sbi->kbytes_written =
+                       le64_to_cpu(seg_i->sum_blk->journal.info.kbytes_written);
+
        build_gc_manager(sbi);
 
        /* get an inode for node space */
@@ -1466,8 +1538,10 @@ try_onemore:
 
        /* recover broken superblock */
        if (recovery && !f2fs_readonly(sb) && !bdev_read_only(sb->s_bdev)) {
-               f2fs_msg(sb, KERN_INFO, "Recover invalid superblock");
-               f2fs_commit_super(sbi, true);
+               err = f2fs_commit_super(sbi, true);
+               f2fs_msg(sb, KERN_INFO,
+                       "Try to recover %dth superblock, ret: %ld",
+                       sbi->valid_super_block ? 1 : 2, err);
        }
 
        f2fs_update_time(sbi, CP_TIME);
@@ -1496,7 +1570,6 @@ free_nm:
        destroy_node_manager(sbi);
 free_sm:
        destroy_segment_manager(sbi);
-free_cp:
        kfree(sbi->ckpt);
 free_meta_inode:
        make_bad_inode(sbi->meta_inode);
@@ -1506,6 +1579,8 @@ free_options:
 free_sb_buf:
        kfree(raw_super);
 free_sbi:
+       if (sbi->s_chksum_driver)
+               crypto_free_shash(sbi->s_chksum_driver);
        kfree(sbi);
 
        /* give only one another chance */
@@ -1585,13 +1660,9 @@ static int __init init_f2fs_fs(void)
                err = -ENOMEM;
                goto free_extent_cache;
        }
-       err = f2fs_init_crypto();
-       if (err)
-               goto free_kset;
-
        err = register_shrinker(&f2fs_shrinker_info);
        if (err)
-               goto free_crypto;
+               goto free_kset;
 
        err = register_filesystem(&f2fs_fs_type);
        if (err)
@@ -1606,8 +1677,6 @@ free_filesystem:
        unregister_filesystem(&f2fs_fs_type);
 free_shrinker:
        unregister_shrinker(&f2fs_shrinker_info);
-free_crypto:
-       f2fs_exit_crypto();
 free_kset:
        kset_unregister(f2fs_kset);
 free_extent_cache:
@@ -1630,7 +1699,6 @@ static void __exit exit_f2fs_fs(void)
        f2fs_destroy_root_stats();
        unregister_shrinker(&f2fs_shrinker_info);
        unregister_filesystem(&f2fs_fs_type);
-       f2fs_exit_crypto();
        destroy_extent_cache();
        destroy_checkpoint_caches();
        destroy_segment_manager_caches();
index 145fb65..562ce08 100644 (file)
@@ -29,7 +29,8 @@ static inline void __print_last_io(void)
                        last_io.major, last_io.minor,
                        last_io.pid, "----------------",
                        last_io.type,
-                       last_io.fio.rw, last_io.fio.blk_addr,
+                       last_io.fio.rw,
+                       last_io.fio.new_blkaddr,
                        last_io.len);
        memset(&last_io, 0, sizeof(last_io));
 }
@@ -101,7 +102,8 @@ void f2fs_trace_ios(struct f2fs_io_info *fio, int flush)
                        last_io.pid == pid &&
                        last_io.type == __file_type(inode, pid) &&
                        last_io.fio.rw == fio->rw &&
-                       last_io.fio.blk_addr + last_io.len == fio->blk_addr) {
+                       last_io.fio.new_blkaddr + last_io.len ==
+                                                       fio->new_blkaddr) {
                last_io.len++;
                return;
        }
index 10f1e78..06a72dc 100644 (file)
@@ -300,7 +300,7 @@ static inline int write_all_xattrs(struct inode *inode, __u32 hsize,
 
                if (ipage) {
                        inline_addr = inline_xattr_addr(ipage);
-                       f2fs_wait_on_page_writeback(ipage, NODE);
+                       f2fs_wait_on_page_writeback(ipage, NODE, true);
                } else {
                        page = get_node_page(sbi, inode->i_ino);
                        if (IS_ERR(page)) {
@@ -308,7 +308,7 @@ static inline int write_all_xattrs(struct inode *inode, __u32 hsize,
                                return PTR_ERR(page);
                        }
                        inline_addr = inline_xattr_addr(page);
-                       f2fs_wait_on_page_writeback(page, NODE);
+                       f2fs_wait_on_page_writeback(page, NODE, true);
                }
                memcpy(inline_addr, txattr_addr, inline_size);
                f2fs_put_page(page, 1);
@@ -329,7 +329,7 @@ static inline int write_all_xattrs(struct inode *inode, __u32 hsize,
                        return PTR_ERR(xpage);
                }
                f2fs_bug_on(sbi, new_nid);
-               f2fs_wait_on_page_writeback(xpage, NODE);
+               f2fs_wait_on_page_writeback(xpage, NODE, true);
        } else {
                struct dnode_of_data dn;
                set_new_dnode(&dn, inode, NULL, NULL, new_nid);
index 79dccc8..f990de2 100644 (file)
@@ -126,7 +126,8 @@ extern ssize_t f2fs_listxattr(struct dentry *, char *, size_t);
 
 #define f2fs_xattr_handlers    NULL
 static inline int f2fs_setxattr(struct inode *inode, int index,
-               const char *name, const void *value, size_t size, int flags)
+               const char *name, const void *value, size_t size,
+               struct page *page, int flags)
 {
        return -EOPNOTSUPP;
 }
index 1c51d2d..7cb043d 100644 (file)
@@ -228,6 +228,8 @@ struct dentry_operations {
 #define DCACHE_FALLTHRU                        0x01000000 /* Fall through to lower layer */
 #define DCACHE_OP_SELECT_INODE         0x02000000 /* Unioned entry: dcache op selects inode */
 
+#define DCACHE_ENCRYPTED_WITH_KEY      0x04000000 /* dir is encrypted with a valid key */
+
 extern seqlock_t rename_lock;
 
 /*
index e59c3be..9eb215a 100644 (file)
@@ -21,7 +21,7 @@
 #define F2FS_BLKSIZE                   4096    /* support only 4KB block */
 #define F2FS_BLKSIZE_BITS              12      /* bits for F2FS_BLKSIZE */
 #define F2FS_MAX_EXTENSION             64      /* # of extension entries */
-#define F2FS_BLK_ALIGN(x)      (((x) + F2FS_BLKSIZE - 1) / F2FS_BLKSIZE)
+#define F2FS_BLK_ALIGN(x)      (((x) + F2FS_BLKSIZE - 1) >> F2FS_BLKSIZE_BITS)
 
 #define NULL_ADDR              ((block_t)0)    /* used as block_t addresses */
 #define NEW_ADDR               ((block_t)-1)   /* used as block_t addresses */
@@ -170,12 +170,12 @@ struct f2fs_extent {
 #define F2FS_INLINE_XATTR_ADDRS        50      /* 200 bytes for inline xattrs */
 #define DEF_ADDRS_PER_INODE    923     /* Address Pointers in an Inode */
 #define DEF_NIDS_PER_INODE     5       /* Node IDs in an Inode */
-#define ADDRS_PER_INODE(fi)    addrs_per_inode(fi)
+#define ADDRS_PER_INODE(inode) addrs_per_inode(inode)
 #define ADDRS_PER_BLOCK                1018    /* Address Pointers in a Direct Block */
 #define NIDS_PER_BLOCK         1018    /* Node IDs in an Indirect Block */
 
-#define ADDRS_PER_PAGE(page, fi)       \
-       (IS_INODE(page) ? ADDRS_PER_INODE(fi) : ADDRS_PER_BLOCK)
+#define ADDRS_PER_PAGE(page, inode)    \
+       (IS_INODE(page) ? ADDRS_PER_INODE(inode) : ADDRS_PER_BLOCK)
 
 #define        NODE_DIR1_BLOCK         (DEF_ADDRS_PER_INODE + 1)
 #define        NODE_DIR2_BLOCK         (DEF_ADDRS_PER_INODE + 2)
@@ -345,7 +345,7 @@ struct f2fs_summary {
 
 struct summary_footer {
        unsigned char entry_type;       /* SUM_TYPE_XXX */
-       __u32 check_sum;                /* summary checksum */
+       __le32 check_sum;               /* summary checksum */
 } __packed;
 
 #define SUM_JOURNAL_SIZE       (F2FS_BLKSIZE - SUM_FOOTER_SIZE -\
@@ -358,6 +358,12 @@ struct summary_footer {
                                sizeof(struct sit_journal_entry))
 #define SIT_JOURNAL_RESERVED   ((SUM_JOURNAL_SIZE - 2) %\
                                sizeof(struct sit_journal_entry))
+
+/* Reserved area should make size of f2fs_extra_info equals to
+ * that of nat_journal and sit_journal.
+ */
+#define EXTRA_INFO_RESERVED    (SUM_JOURNAL_SIZE - 2 - 8)
+
 /*
  * frequently updated NAT/SIT entries can be stored in the spare area in
  * summary blocks
@@ -387,18 +393,28 @@ struct sit_journal {
        __u8 reserved[SIT_JOURNAL_RESERVED];
 } __packed;
 
-/* 4KB-sized summary block structure */
-struct f2fs_summary_block {
-       struct f2fs_summary entries[ENTRIES_IN_SUM];
+struct f2fs_extra_info {
+       __le64 kbytes_written;
+       __u8 reserved[EXTRA_INFO_RESERVED];
+} __packed;
+
+struct f2fs_journal {
        union {
                __le16 n_nats;
                __le16 n_sits;
        };
-       /* spare area is used by NAT or SIT journals */
+       /* spare area is used by NAT or SIT journals or extra info */
        union {
                struct nat_journal nat_j;
                struct sit_journal sit_j;
+               struct f2fs_extra_info info;
        };
+} __packed;
+
+/* 4KB-sized summary block structure */
+struct f2fs_summary_block {
+       struct f2fs_summary entries[ENTRIES_IN_SUM];
+       struct f2fs_journal journal;
        struct summary_footer footer;
 } __packed;
 
index bb703ef..cc08198 100644 (file)
@@ -53,6 +53,8 @@ struct swap_info_struct;
 struct seq_file;
 struct workqueue_struct;
 struct iov_iter;
+struct fscrypt_info;
+struct fscrypt_operations;
 
 extern void __init inode_init(void);
 extern void __init inode_init_early(void);
@@ -679,6 +681,10 @@ struct inode {
        struct hlist_head       i_fsnotify_marks;
 #endif
 
+#if IS_ENABLED(CONFIG_FS_ENCRYPTION)
+       struct fscrypt_info     *i_crypt_info;
+#endif
+
        void                    *i_private; /* fs or device private pointer */
 };
 
@@ -1324,6 +1330,8 @@ struct super_block {
 #endif
        const struct xattr_handler **s_xattr;
 
+       const struct fscrypt_operations *s_cop;
+
        struct hlist_bl_head    s_anon;         /* anonymous dentries for (nfs) exporting */
        struct list_head        s_mounts;       /* list of mounts; _not_ for fs use */
        struct block_device     *s_bdev;
diff --git a/include/linux/fscrypto.h b/include/linux/fscrypto.h
new file mode 100644 (file)
index 0000000..cd91f75
--- /dev/null
@@ -0,0 +1,434 @@
+/*
+ * General per-file encryption definition
+ *
+ * Copyright (C) 2015, Google, Inc.
+ *
+ * Written by Michael Halcrow, 2015.
+ * Modified by Jaegeuk Kim, 2015.
+ */
+
+#ifndef _LINUX_FSCRYPTO_H
+#define _LINUX_FSCRYPTO_H
+
+#include <linux/key.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/bio.h>
+#include <linux/dcache.h>
+#include <crypto/skcipher.h>
+#include <uapi/linux/fs.h>
+
+#define FS_KEY_DERIVATION_NONCE_SIZE           16
+#define FS_ENCRYPTION_CONTEXT_FORMAT_V1                1
+
+#define FS_POLICY_FLAGS_PAD_4          0x00
+#define FS_POLICY_FLAGS_PAD_8          0x01
+#define FS_POLICY_FLAGS_PAD_16         0x02
+#define FS_POLICY_FLAGS_PAD_32         0x03
+#define FS_POLICY_FLAGS_PAD_MASK       0x03
+#define FS_POLICY_FLAGS_VALID          0x03
+
+/* Encryption algorithms */
+#define FS_ENCRYPTION_MODE_INVALID             0
+#define FS_ENCRYPTION_MODE_AES_256_XTS         1
+#define FS_ENCRYPTION_MODE_AES_256_GCM         2
+#define FS_ENCRYPTION_MODE_AES_256_CBC         3
+#define FS_ENCRYPTION_MODE_AES_256_CTS         4
+
+/**
+ * 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 fscrypt_context {
+       u8 format;
+       u8 contents_encryption_mode;
+       u8 filenames_encryption_mode;
+       u8 flags;
+       u8 master_key_descriptor[FS_KEY_DESCRIPTOR_SIZE];
+       u8 nonce[FS_KEY_DERIVATION_NONCE_SIZE];
+} __packed;
+
+/* Encryption parameters */
+#define FS_XTS_TWEAK_SIZE              16
+#define FS_AES_128_ECB_KEY_SIZE                16
+#define FS_AES_256_GCM_KEY_SIZE                32
+#define FS_AES_256_CBC_KEY_SIZE                32
+#define FS_AES_256_CTS_KEY_SIZE                32
+#define FS_AES_256_XTS_KEY_SIZE                64
+#define FS_MAX_KEY_SIZE                        64
+
+#define FS_KEY_DESC_PREFIX             "fscrypt:"
+#define FS_KEY_DESC_PREFIX_SIZE                8
+
+/* This is passed in from userspace into the kernel keyring */
+struct fscrypt_key {
+       u32 mode;
+       u8 raw[FS_MAX_KEY_SIZE];
+       u32 size;
+} __packed;
+
+struct fscrypt_info {
+       u8 ci_data_mode;
+       u8 ci_filename_mode;
+       u8 ci_flags;
+       struct crypto_skcipher *ci_ctfm;
+       struct key *ci_keyring_key;
+       u8 ci_master_key[FS_KEY_DESCRIPTOR_SIZE];
+};
+
+#define FS_CTX_REQUIRES_FREE_ENCRYPT_FL                0x00000001
+#define FS_WRITE_PATH_FL                       0x00000002
+
+struct fscrypt_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 */
+       };
+       u8 flags;                               /* Flags */
+       u8 mode;                                /* Encryption mode for tfm */
+};
+
+struct fscrypt_completion_result {
+       struct completion completion;
+       int res;
+};
+
+#define DECLARE_FS_COMPLETION_RESULT(ecr) \
+       struct fscrypt_completion_result ecr = { \
+               COMPLETION_INITIALIZER((ecr).completion), 0 }
+
+static inline int fscrypt_key_size(int mode)
+{
+       switch (mode) {
+       case FS_ENCRYPTION_MODE_AES_256_XTS:
+               return FS_AES_256_XTS_KEY_SIZE;
+       case FS_ENCRYPTION_MODE_AES_256_GCM:
+               return FS_AES_256_GCM_KEY_SIZE;
+       case FS_ENCRYPTION_MODE_AES_256_CBC:
+               return FS_AES_256_CBC_KEY_SIZE;
+       case FS_ENCRYPTION_MODE_AES_256_CTS:
+               return FS_AES_256_CTS_KEY_SIZE;
+       default:
+               BUG();
+       }
+       return 0;
+}
+
+#define FS_FNAME_NUM_SCATTER_ENTRIES   4
+#define FS_CRYPTO_BLOCK_SIZE           16
+#define FS_FNAME_CRYPTO_DIGEST_SIZE    32
+
+/**
+ * For encrypted symlinks, the ciphertext length is stored at the beginning
+ * of the string in little-endian format.
+ */
+struct fscrypt_symlink_data {
+       __le16 len;
+       char encrypted_path[1];
+} __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 fscrypt_symlink_data_len(u32 l)
+{
+       if (l < FS_CRYPTO_BLOCK_SIZE)
+               l = FS_CRYPTO_BLOCK_SIZE;
+       return (l + sizeof(struct fscrypt_symlink_data) - 1);
+}
+
+struct fscrypt_str {
+       unsigned char *name;
+       u32 len;
+};
+
+struct fscrypt_name {
+       const struct qstr *usr_fname;
+       struct fscrypt_str disk_name;
+       u32 hash;
+       u32 minor_hash;
+       struct fscrypt_str crypto_buf;
+};
+
+#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)
+
+/*
+ * crypto opertions for filesystems
+ */
+struct fscrypt_operations {
+       int (*get_context)(struct inode *, void *, size_t);
+       int (*prepare_context)(struct inode *);
+       int (*set_context)(struct inode *, const void *, size_t, void *);
+       int (*dummy_context)(struct inode *);
+       bool (*is_encrypted)(struct inode *);
+       bool (*empty_dir)(struct inode *);
+       unsigned (*max_namelen)(struct inode *);
+};
+
+static inline bool fscrypt_dummy_context_enabled(struct inode *inode)
+{
+       if (inode->i_sb->s_cop->dummy_context &&
+                               inode->i_sb->s_cop->dummy_context(inode))
+               return true;
+       return false;
+}
+
+static inline bool fscrypt_valid_contents_enc_mode(u32 mode)
+{
+       return (mode == FS_ENCRYPTION_MODE_AES_256_XTS);
+}
+
+static inline bool fscrypt_valid_filenames_enc_mode(u32 mode)
+{
+       return (mode == FS_ENCRYPTION_MODE_AES_256_CTS);
+}
+
+static inline u32 fscrypt_validate_encryption_key_size(u32 mode, u32 size)
+{
+       if (size == fscrypt_key_size(mode))
+               return size;
+       return 0;
+}
+
+static inline bool fscrypt_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;
+}
+
+static inline struct page *fscrypt_control_page(struct page *page)
+{
+#if IS_ENABLED(CONFIG_FS_ENCRYPTION)
+       return ((struct fscrypt_ctx *)page_private(page))->w.control_page;
+#else
+       WARN_ON_ONCE(1);
+       return ERR_PTR(-EINVAL);
+#endif
+}
+
+static inline int fscrypt_has_encryption_key(struct inode *inode)
+{
+#if IS_ENABLED(CONFIG_FS_ENCRYPTION)
+       return (inode->i_crypt_info != NULL);
+#else
+       return 0;
+#endif
+}
+
+static inline void fscrypt_set_encrypted_dentry(struct dentry *dentry)
+{
+#if IS_ENABLED(CONFIG_FS_ENCRYPTION)
+       spin_lock(&dentry->d_lock);
+       dentry->d_flags |= DCACHE_ENCRYPTED_WITH_KEY;
+       spin_unlock(&dentry->d_lock);
+#endif
+}
+
+#if IS_ENABLED(CONFIG_FS_ENCRYPTION)
+extern const struct dentry_operations fscrypt_d_ops;
+#endif
+
+static inline void fscrypt_set_d_op(struct dentry *dentry)
+{
+#if IS_ENABLED(CONFIG_FS_ENCRYPTION)
+       d_set_d_op(dentry, &fscrypt_d_ops);
+#endif
+}
+
+#if IS_ENABLED(CONFIG_FS_ENCRYPTION)
+/* crypto.c */
+extern struct kmem_cache *fscrypt_info_cachep;
+int fscrypt_initialize(void);
+
+extern struct fscrypt_ctx *fscrypt_get_ctx(struct inode *);
+extern void fscrypt_release_ctx(struct fscrypt_ctx *);
+extern struct page *fscrypt_encrypt_page(struct inode *, struct page *);
+extern int fscrypt_decrypt_page(struct page *);
+extern void fscrypt_decrypt_bio_pages(struct fscrypt_ctx *, struct bio *);
+extern void fscrypt_pullback_bio_page(struct page **, bool);
+extern void fscrypt_restore_control_page(struct page *);
+extern int fscrypt_zeroout_range(struct inode *, pgoff_t, sector_t,
+                                               unsigned int);
+/* policy.c */
+extern int fscrypt_process_policy(struct inode *,
+                                       const struct fscrypt_policy *);
+extern int fscrypt_get_policy(struct inode *, struct fscrypt_policy *);
+extern int fscrypt_has_permitted_context(struct inode *, struct inode *);
+extern int fscrypt_inherit_context(struct inode *, struct inode *,
+                                       void *, bool);
+/* keyinfo.c */
+extern int get_crypt_info(struct inode *);
+extern int fscrypt_get_encryption_info(struct inode *);
+extern void fscrypt_put_encryption_info(struct inode *, struct fscrypt_info *);
+
+/* fname.c */
+extern int fscrypt_setup_filename(struct inode *, const struct qstr *,
+                               int lookup, struct fscrypt_name *);
+extern void fscrypt_free_filename(struct fscrypt_name *);
+extern u32 fscrypt_fname_encrypted_size(struct inode *, u32);
+extern int fscrypt_fname_alloc_buffer(struct inode *, u32,
+                               struct fscrypt_str *);
+extern void fscrypt_fname_free_buffer(struct fscrypt_str *);
+extern int fscrypt_fname_disk_to_usr(struct inode *, u32, u32,
+                       const struct fscrypt_str *, struct fscrypt_str *);
+extern int fscrypt_fname_usr_to_disk(struct inode *, const struct qstr *,
+                       struct fscrypt_str *);
+#endif
+
+/* crypto.c */
+static inline struct fscrypt_ctx *fscrypt_notsupp_get_ctx(struct inode *i)
+{
+       return ERR_PTR(-EOPNOTSUPP);
+}
+
+static inline void fscrypt_notsupp_release_ctx(struct fscrypt_ctx *c)
+{
+       return;
+}
+
+static inline struct page *fscrypt_notsupp_encrypt_page(struct inode *i,
+                                               struct page *p)
+{
+       return ERR_PTR(-EOPNOTSUPP);
+}
+
+static inline int fscrypt_notsupp_decrypt_page(struct page *p)
+{
+       return -EOPNOTSUPP;
+}
+
+static inline void fscrypt_notsupp_decrypt_bio_pages(struct fscrypt_ctx *c,
+                                               struct bio *b)
+{
+       return;
+}
+
+static inline void fscrypt_notsupp_pullback_bio_page(struct page **p, bool b)
+{
+       return;
+}
+
+static inline void fscrypt_notsupp_restore_control_page(struct page *p)
+{
+       return;
+}
+
+static inline int fscrypt_notsupp_zeroout_range(struct inode *i, pgoff_t p,
+                                       sector_t s, unsigned int f)
+{
+       return -EOPNOTSUPP;
+}
+
+/* policy.c */
+static inline int fscrypt_notsupp_process_policy(struct inode *i,
+                               const struct fscrypt_policy *p)
+{
+       return -EOPNOTSUPP;
+}
+
+static inline int fscrypt_notsupp_get_policy(struct inode *i,
+                               struct fscrypt_policy *p)
+{
+       return -EOPNOTSUPP;
+}
+
+static inline int fscrypt_notsupp_has_permitted_context(struct inode *p,
+                               struct inode *i)
+{
+       return 0;
+}
+
+static inline int fscrypt_notsupp_inherit_context(struct inode *p,
+                               struct inode *i, void *v, bool b)
+{
+       return -EOPNOTSUPP;
+}
+
+/* keyinfo.c */
+static inline int fscrypt_notsupp_get_encryption_info(struct inode *i)
+{
+       return -EOPNOTSUPP;
+}
+
+static inline void fscrypt_notsupp_put_encryption_info(struct inode *i,
+                                       struct fscrypt_info *f)
+{
+       return;
+}
+
+ /* fname.c */
+static inline int fscrypt_notsupp_setup_filename(struct inode *dir,
+                       const struct qstr *iname,
+                       int lookup, struct fscrypt_name *fname)
+{
+       if (dir->i_sb->s_cop->is_encrypted(dir))
+               return -EOPNOTSUPP;
+
+       memset(fname, 0, sizeof(struct fscrypt_name));
+       fname->usr_fname = iname;
+       fname->disk_name.name = (unsigned char *)iname->name;
+       fname->disk_name.len = iname->len;
+       return 0;
+}
+
+static inline void fscrypt_notsupp_free_filename(struct fscrypt_name *fname)
+{
+       return;
+}
+
+static inline u32 fscrypt_notsupp_fname_encrypted_size(struct inode *i, u32 s)
+{
+       /* never happens */
+       WARN_ON(1);
+       return 0;
+}
+
+static inline int fscrypt_notsupp_fname_alloc_buffer(struct inode *inode,
+                               u32 ilen, struct fscrypt_str *crypto_str)
+{
+       return -EOPNOTSUPP;
+}
+
+static inline void fscrypt_notsupp_fname_free_buffer(struct fscrypt_str *c)
+{
+       return;
+}
+
+static inline int fscrypt_notsupp_fname_disk_to_usr(struct inode *inode,
+                       u32 hash, u32 minor_hash,
+                       const struct fscrypt_str *iname,
+                       struct fscrypt_str *oname)
+{
+       return -EOPNOTSUPP;
+}
+
+static inline int fscrypt_notsupp_fname_usr_to_disk(struct inode *inode,
+                       const struct qstr *iname,
+                       struct fscrypt_str *oname)
+{
+       return -EOPNOTSUPP;
+}
+#endif /* _LINUX_FSCRYPTO_H */
index a1b4888..0f56584 100644 (file)
@@ -52,6 +52,7 @@ TRACE_DEFINE_ENUM(CP_DISCARD);
                { META_FLUSH,   "META_FLUSH" },                         \
                { INMEM,        "INMEM" },                              \
                { INMEM_DROP,   "INMEM_DROP" },                         \
+               { INMEM_REVOKE, "INMEM_REVOKE" },                       \
                { IPU,          "IN-PLACE" },                           \
                { OPU,          "OUT-OF-PLACE" })
 
@@ -727,7 +728,8 @@ DECLARE_EVENT_CLASS(f2fs__submit_page_bio,
                __field(dev_t, dev)
                __field(ino_t, ino)
                __field(pgoff_t, index)
-               __field(block_t, blkaddr)
+               __field(block_t, old_blkaddr)
+               __field(block_t, new_blkaddr)
                __field(int, rw)
                __field(int, type)
        ),
@@ -736,16 +738,18 @@ DECLARE_EVENT_CLASS(f2fs__submit_page_bio,
                __entry->dev            = page->mapping->host->i_sb->s_dev;
                __entry->ino            = page->mapping->host->i_ino;
                __entry->index          = page->index;
-               __entry->blkaddr        = fio->blk_addr;
+               __entry->old_blkaddr    = fio->old_blkaddr;
+               __entry->new_blkaddr    = fio->new_blkaddr;
                __entry->rw             = fio->rw;
                __entry->type           = fio->type;
        ),
 
        TP_printk("dev = (%d,%d), ino = %lu, page_index = 0x%lx, "
-               "blkaddr = 0x%llx, rw = %s%s, type = %s",
+               "oldaddr = 0x%llx, newaddr = 0x%llx rw = %s%s, type = %s",
                show_dev_ino(__entry),
                (unsigned long)__entry->index,
-               (unsigned long long)__entry->blkaddr,
+               (unsigned long long)__entry->old_blkaddr,
+               (unsigned long long)__entry->new_blkaddr,
                show_bio_type(__entry->rw),
                show_block_type(__entry->type))
 );
index d246339..a079d50 100644 (file)
@@ -247,6 +247,24 @@ struct fsxattr {
 #define FS_IOC_FSSETXATTR              _IOW ('X', 32, struct fsxattr)
 
 /*
+ * File system encryption support
+ */
+/* Policy provided via an ioctl on the topmost directory */
+#define FS_KEY_DESCRIPTOR_SIZE 8
+
+struct fscrypt_policy {
+       __u8 version;
+       __u8 contents_encryption_mode;
+       __u8 filenames_encryption_mode;
+       __u8 flags;
+       __u8 master_key_descriptor[FS_KEY_DESCRIPTOR_SIZE];
+} __packed;
+
+#define FS_IOC_SET_ENCRYPTION_POLICY   _IOR('f', 19, struct fscrypt_policy)
+#define FS_IOC_GET_ENCRYPTION_PWSALT   _IOW('f', 20, __u8[16])
+#define FS_IOC_GET_ENCRYPTION_POLICY   _IOW('f', 21, struct fscrypt_policy)
+
+/*
  * Inode flags (FS_IOC_GETFLAGS / FS_IOC_SETFLAGS)
  *
  * Note: for historical reasons, these flags were originally used and