@@ -3348,6 +3348,7 @@ struct btrfs_new_inode_args {
*/
struct posix_acl *default_acl;
struct posix_acl *acl;
+ bool encrypt;
};
int btrfs_new_inode_prepare(struct btrfs_new_inode_args *args,
unsigned int *trans_num_items);
@@ -3709,6 +3709,9 @@ static int btrfs_file_open(struct inode *inode, struct file *filp)
int ret;
filp->f_mode |= FMODE_NOWAIT | FMODE_BUF_RASYNC;
+ ret = fscrypt_file_open(inode, filp);
+ if (ret)
+ return ret;
ret = fsverity_file_open(inode, filp);
if (ret)
@@ -5453,6 +5453,7 @@ void btrfs_evict_inode(struct inode *inode)
trace_btrfs_inode_evict(inode);
if (!root) {
+ fscrypt_put_encryption_info(inode);
fsverity_cleanup_inode(inode);
clear_inode(inode);
return;
@@ -5554,6 +5555,7 @@ void btrfs_evict_inode(struct inode *inode)
* to retry these periodically in the future.
*/
btrfs_remove_delayed_node(BTRFS_I(inode));
+ fscrypt_put_encryption_info(inode);
fsverity_cleanup_inode(inode);
clear_inode(inode);
}
@@ -6292,6 +6294,10 @@ int btrfs_new_inode_prepare(struct btrfs_new_inode_args *args,
return ret;
}
+ ret = fscrypt_prepare_new_inode(dir, inode, &args->encrypt);
+ if (ret)
+ return ret;
+
/* 1 to add inode item */
*trans_num_items = 1;
/* 1 to add compression property */
@@ -6770,9 +6776,13 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir,
if (inode->i_nlink >= BTRFS_LINK_MAX)
return -EMLINK;
+ err = fscrypt_prepare_link(old_dentry, dir, dentry);
+ if (err)
+ return err;
+
err = fscrypt_setup_filename(dir, &dentry->d_name, 0, &fname);
if (err)
- goto fail;
+ return err;
err = btrfs_set_inode_index(BTRFS_I(dir), &index);
if (err)
@@ -9002,6 +9012,7 @@ void btrfs_test_destroy_inode(struct inode *inode)
void btrfs_free_inode(struct inode *inode)
{
+ fscrypt_free_inode(inode);
kmem_cache_free(btrfs_inode_cachep, BTRFS_I(inode));
}
@@ -9061,8 +9072,7 @@ int btrfs_drop_inode(struct inode *inode)
/* the snap/subvol tree is on deleting */
if (btrfs_root_refs(&root->root_item) == 0)
return 1;
- else
- return generic_drop_inode(inode);
+ return generic_drop_inode(inode) || fscrypt_drop_inode(inode);
}
static void init_once(void *foo)
@@ -9676,6 +9686,11 @@ static int btrfs_rename2(struct user_namespace *mnt_userns, struct inode *old_di
if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE | RENAME_WHITEOUT))
return -EINVAL;
+ ret = fscrypt_prepare_rename(old_dir, old_dentry, new_dir, new_dentry,
+ flags);
+ if (ret)
+ return ret;
+
if (flags & RENAME_EXCHANGE)
ret = btrfs_rename_exchange(old_dir, old_dentry, new_dir,
new_dentry);
@@ -9895,15 +9910,22 @@ static int btrfs_symlink(struct user_namespace *mnt_userns, struct inode *dir,
};
unsigned int trans_num_items;
int err;
- int name_len;
int datasize;
unsigned long ptr;
struct btrfs_file_extent_item *ei;
struct extent_buffer *leaf;
+ struct fscrypt_str disk_link;
+ u32 name_len = strlen(symname);
- name_len = strlen(symname);
- if (name_len > BTRFS_MAX_INLINE_DATA_SIZE(fs_info))
- return -ENAMETOOLONG;
+ /*
+ * fscrypt sets disk_link.len to be len + 1, including a NULL terminator, but we
+ * don't store that NULL.
+ */
+ err = fscrypt_prepare_symlink(dir, symname, name_len,
+ BTRFS_MAX_INLINE_DATA_SIZE(fs_info) + 1,
+ &disk_link);
+ if (err)
+ return err;
inode = new_inode(dir->i_sb);
if (!inode)
@@ -9912,8 +9934,8 @@ static int btrfs_symlink(struct user_namespace *mnt_userns, struct inode *dir,
inode->i_op = &btrfs_symlink_inode_operations;
inode_nohighmem(inode);
inode->i_mapping->a_ops = &btrfs_aops;
- btrfs_i_size_write(BTRFS_I(inode), name_len);
- inode_set_bytes(inode, name_len);
+ btrfs_i_size_write(BTRFS_I(inode), disk_link.len - 1);
+ inode_set_bytes(inode, disk_link.len - 1);
new_inode_args.inode = inode;
err = btrfs_new_inode_prepare(&new_inode_args, &trans_num_items);
@@ -9943,7 +9965,7 @@ static int btrfs_symlink(struct user_namespace *mnt_userns, struct inode *dir,
key.objectid = btrfs_ino(BTRFS_I(inode));
key.offset = 0;
key.type = BTRFS_EXTENT_DATA_KEY;
- datasize = btrfs_file_extent_calc_inline_size(name_len);
+ datasize = btrfs_file_extent_calc_inline_size(disk_link.len - 1);
err = btrfs_insert_empty_item(trans, root, path, &key,
datasize);
if (err) {
@@ -9962,10 +9984,22 @@ static int btrfs_symlink(struct user_namespace *mnt_userns, struct inode *dir,
btrfs_set_file_extent_encryption(leaf, ei, 0);
btrfs_set_file_extent_compression(leaf, ei, 0);
btrfs_set_file_extent_other_encoding(leaf, ei, 0);
+ /* ram size is the unencrypted size */
btrfs_set_file_extent_ram_bytes(leaf, ei, name_len);
ptr = btrfs_file_extent_inline_start(ei);
- write_extent_buffer(leaf, symname, ptr, name_len);
+ if (IS_ENCRYPTED(inode)) {
+ err = fscrypt_encrypt_symlink(inode, symname, name_len,
+ &disk_link);
+ if (err) {
+ btrfs_abort_transaction(trans, err);
+ btrfs_free_path(path);
+ discard_new_inode(inode);
+ inode = NULL;
+ goto out;
+ }
+ }
+ write_extent_buffer(leaf, disk_link.name, ptr, disk_link.len - 1);
btrfs_mark_buffer_dirty(leaf);
btrfs_free_path(path);
@@ -9982,6 +10016,29 @@ static int btrfs_symlink(struct user_namespace *mnt_userns, struct inode *dir,
return err;
}
+static const char *btrfs_get_link(struct dentry *dentry, struct inode *inode,
+ struct delayed_call *done)
+{
+ struct page *cpage;
+ const char *paddr;
+ struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
+
+ if (!IS_ENCRYPTED(inode))
+ return page_get_link(dentry, inode, done);
+
+ if (!dentry)
+ return ERR_PTR(-ECHILD);
+
+ cpage = read_mapping_page(inode->i_mapping, 0, NULL);
+ if (IS_ERR(cpage))
+ return ERR_CAST(cpage);
+
+ paddr = fscrypt_get_symlink(inode, page_address(cpage),
+ BTRFS_MAX_INLINE_DATA_SIZE(fs_info), done);
+ put_page(cpage);
+ return paddr;
+}
+
static struct btrfs_trans_handle *insert_prealloc_file_extent(
struct btrfs_trans_handle *trans_in,
struct btrfs_inode *inode,
@@ -11568,7 +11625,7 @@ static const struct inode_operations btrfs_special_inode_operations = {
.update_time = btrfs_update_time,
};
static const struct inode_operations btrfs_symlink_inode_operations = {
- .get_link = page_get_link,
+ .get_link = btrfs_get_link,
.getattr = btrfs_getattr,
.setattr = btrfs_setattr,
.permission = btrfs_permission,
@@ -11578,4 +11635,7 @@ static const struct inode_operations btrfs_symlink_inode_operations = {
const struct dentry_operations btrfs_dentry_operations = {
.d_delete = btrfs_dentry_delete,
+#ifdef CONFIG_FS_ENCRYPTION
+ .d_revalidate = fscrypt_d_revalidate,
+#endif
};