Signed-off-by: Mark Harmstone <[email protected]>
---
 fs/btrfs/transaction.c | 79 +++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 78 insertions(+), 1 deletion(-)

diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
index d1eeef9ec5da..a6c8d49b6962 100644
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -19,6 +19,7 @@
 #include "volumes.h"
 #include "dev-replace.h"
 #include "qgroup.h"
+#include "encryption.h"
 
 #define BTRFS_ROOT_TRANS_TAG 0
 
@@ -520,7 +521,7 @@ start_transaction(struct btrfs_root *root, unsigned int 
num_items,
         * and then we deadlock with somebody doing a freeze.
         *
         * If we are ATTACH, it means we just want to catch the current
-        * transaction and commit it, so we needn't do sb_start_intwrite(). 
+        * transaction and commit it, so we needn't do sb_start_intwrite().
         */
        if (type & __TRANS_FREEZABLE)
                sb_start_intwrite(fs_info->sb);
@@ -1918,12 +1919,74 @@ btrfs_wait_pending_ordered(struct btrfs_transaction 
*cur_trans)
                   atomic_read(&cur_trans->pending_ordered) == 0);
 }
 
+static int flush_key(struct btrfs_trans_handle *trans,
+                    struct btrfs_enc_key *k)
+{
+       struct btrfs_fs_info *fs_info = trans->fs_info;
+       struct btrfs_path *path;
+       struct btrfs_key key;
+       struct extent_buffer *leaf;
+       struct btrfs_encryption_key_item *item;
+       int ret;
+
+       path = btrfs_alloc_path();
+       if (!path)
+               return -ENOMEM;
+
+       path->leave_spinning = 1;
+
+       if (!fs_info->key_root) {
+               struct btrfs_root *root;
+
+               root = btrfs_create_tree(trans, fs_info,
+                                        BTRFS_KEY_TREE_OBJECTID);
+
+               if (IS_ERR(root)) {
+                       btrfs_free_path(path);
+                       return PTR_ERR(root);
+               }
+
+               fs_info->key_root = root;
+
+               btrfs_set_fs_incompat(fs_info, ENCRYPTION);
+       }
+
+       key.objectid = k->key_number;
+       key.type = BTRFS_ENCRYPTION_KEY;
+       key.offset = 0;
+
+       ret = btrfs_insert_empty_item(trans, fs_info->key_root, path, &key,
+                                     sizeof(struct btrfs_encryption_key_item));
+
+       if (ret) {
+               btrfs_free_path(path);
+               return ret;
+       }
+
+       leaf = path->nodes[0];
+
+       btrfs_mark_buffer_dirty(leaf);
+
+       item = btrfs_item_ptr(leaf, path->slots[0],
+                             struct btrfs_encryption_key_item);
+
+       write_eb_member(leaf, item, struct btrfs_encryption_key_item,
+                       key_id, k->key_id);
+
+       btrfs_free_path(path);
+
+       k->added = false;
+
+       return ret;
+}
+
 int btrfs_commit_transaction(struct btrfs_trans_handle *trans)
 {
        struct btrfs_fs_info *fs_info = trans->fs_info;
        struct btrfs_transaction *cur_trans = trans->transaction;
        struct btrfs_transaction *prev_trans = NULL;
        int ret;
+       struct btrfs_enc_key *key;
 
        /* Stop the commit early if ->aborted is set */
        if (unlikely(READ_ONCE(cur_trans->aborted))) {
@@ -2071,6 +2134,20 @@ int btrfs_commit_transaction(struct btrfs_trans_handle 
*trans)
                ret = cur_trans->aborted;
                goto scrub_continue;
        }
+
+       down_read(&fs_info->key_sem);
+
+       list_for_each_entry(key, &fs_info->key_list, key_list) {
+               if (key->added && key->used) {
+                       ret = flush_key(trans, key);
+
+                       if (ret)
+                               goto scrub_continue;
+               }
+       }
+
+       up_read(&fs_info->key_sem);
+
        /*
         * the reloc mutex makes sure that we stop
         * the balancing code from coming in and moving
-- 
2.19.2

Reply via email to