new file mode 100644
@@ -0,0 +1,106 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * GPL HEADER START
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 only,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License version 2 for more details (a copy is included
+ * in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 along with this program; If not, see
+ * http://www.gnu.org/licenses/gpl-2.0.html
+ *
+ * GPL HEADER END
+ */
+/*
+ * Copyright (c) 2019, 2020, Whamcloud.
+ */
+/*
+ * This file is part of Lustre, http://www.lustre.org/
+ */
+
+#ifndef _LUSTRE_CRYPTO_H_
+#define _LUSTRE_CRYPTO_H_
+
+struct ll_sb_info;
+bool ll_sbi_has_test_dummy_encryption(struct ll_sb_info *sbi);
+bool ll_sbi_has_encrypt(struct ll_sb_info *sbi);
+void ll_sbi_set_encrypt(struct ll_sb_info *sbi, bool set);
+
+#ifdef CONFIG_FS_ENCRYPTION
+#define __FS_HAS_ENCRYPTION 1
+#include <linux/fscrypt.h>
+
+#define llcrypt_operations fscrypt_operations
+#define llcrypt_symlink_data fscrypt_symlink_data
+#define llcrypt_dummy_context_enabled(inode) \
+ fscrypt_dummy_context_enabled(inode)
+#define llcrypt_has_encryption_key(inode) fscrypt_has_encryption_key(inode)
+#define llcrypt_encrypt_pagecache_blocks(page, len, offs, gfp_flags) \
+ fscrypt_encrypt_pagecache_blocks(page, len, offs, gfp_flags)
+#define llcrypt_decrypt_pagecache_blocks(page, len, offs) \
+ fscrypt_decrypt_pagecache_blocks(page, len, offs)
+#define llcrypt_inherit_context(parent, child, fs_data, preload) \
+ fscrypt_inherit_context(parent, child, fs_data, preload)
+#define llcrypt_get_encryption_info(inode) fscrypt_get_encryption_info(inode)
+#define llcrypt_put_encryption_info(inode) fscrypt_put_encryption_info(inode)
+#define llcrypt_free_inode(inode) fscrypt_free_inode(inode)
+#define llcrypt_finalize_bounce_page(pagep) fscrypt_finalize_bounce_page(pagep)
+#define llcrypt_file_open(inode, filp) fscrypt_file_open(inode, filp)
+#define llcrypt_ioctl_set_policy(filp, arg) fscrypt_ioctl_set_policy(filp, arg)
+#define llcrypt_ioctl_get_policy_ex(filp, arg) \
+ fscrypt_ioctl_get_policy_ex(filp, arg)
+#define llcrypt_ioctl_add_key(filp, arg) fscrypt_ioctl_add_key(filp, arg)
+#define llcrypt_ioctl_remove_key(filp, arg) fscrypt_ioctl_remove_key(filp, arg)
+#define llcrypt_ioctl_remove_key_all_users(filp, arg) \
+ fscrypt_ioctl_remove_key_all_users(filp, arg)
+#define llcrypt_ioctl_get_key_status(filp, arg) \
+ fscrypt_ioctl_get_key_status(filp, arg)
+#define llcrypt_drop_inode(inode) fscrypt_drop_inode(inode)
+#define llcrypt_prepare_rename(olddir, olddentry, newdir, newdentry, flags) \
+ fscrypt_prepare_rename(olddir, olddentry, newdir, newdentry, flags)
+#define llcrypt_prepare_link(old_dentry, dir, dentry) \
+ fscrypt_prepare_link(old_dentry, dir, dentry)
+#define llcrypt_prepare_setattr(dentry, attr) \
+ fscrypt_prepare_setattr(dentry, attr)
+#define llcrypt_set_ops(sb, cop) fscrypt_set_ops(sb, cop)
+#else /* !CONFIG_FS_ENCRYPTION */
+#undef IS_ENCRYPTED
+#define IS_ENCRYPTED(x) 0
+#define llcrypt_dummy_context_enabled(inode) NULL
+/* copied from include/linux/fscrypt.h */
+#define llcrypt_has_encryption_key(inode) false
+#define llcrypt_encrypt_pagecache_blocks(page, len, offs, gfp_flags) \
+ ERR_PTR(-EOPNOTSUPP)
+#define llcrypt_decrypt_pagecache_blocks(page, len, offs) -EOPNOTSUPP
+#define llcrypt_inherit_context(parent, child, fs_data, preload) -EOPNOTSUPP
+#define llcrypt_get_encryption_info(inode) -EOPNOTSUPP
+#define llcrypt_put_encryption_info(inode) do {} while (0)
+#define llcrypt_free_inode(inode) do {} while (0)
+#define llcrypt_finalize_bounce_page(pagep) do {} while (0)
+static inline int llcrypt_file_open(struct inode *inode, struct file *filp)
+{
+ return IS_ENCRYPTED(inode) ? -EOPNOTSUPP : 0;
+}
+#define llcrypt_ioctl_set_policy(filp, arg) -EOPNOTSUPP
+#define llcrypt_ioctl_get_policy_ex(filp, arg) -EOPNOTSUPP
+#define llcrypt_ioctl_add_key(filp, arg) -EOPNOTSUPP
+#define llcrypt_ioctl_remove_key(filp, arg) -EOPNOTSUPP
+#define llcrypt_ioctl_remove_key_all_users(filp, arg) -EOPNOTSUPP
+#define llcrypt_ioctl_get_key_status(filp, arg) -EOPNOTSUPP
+#define llcrypt_drop_inode(inode) 0
+#define llcrypt_prepare_rename(olddir, olddentry, newdir, newdentry, flags) 0
+#define llcrypt_prepare_link(old_dentry, dir, dentry) 0
+#define llcrypt_prepare_setattr(dentry, attr) 0
+#define llcrypt_set_ops(sb, cop) do {} while (0)
+#endif /* CONFIG_FS_ENCRYPTION */
+
+#endif /* _LUSTRE_CRYPTO_H_ */
@@ -559,6 +559,9 @@ static inline int ll_ext_to_inode_flags(int flags)
((flags & LUSTRE_NOATIME_FL) ? S_NOATIME : 0) |
((flags & LUSTRE_APPEND_FL) ? S_APPEND : 0) |
((flags & LUSTRE_DIRSYNC_FL) ? S_DIRSYNC : 0) |
+#if defined(S_ENCRYPTED)
+ ((flags & LUSTRE_ENCRYPT_FL) ? S_ENCRYPTED : 0) |
+#endif
((flags & LUSTRE_IMMUTABLE_FL) ? S_IMMUTABLE : 0));
}
@@ -568,6 +571,9 @@ static inline int ll_inode_to_ext_flags(int iflags)
((iflags & S_NOATIME) ? LUSTRE_NOATIME_FL : 0) |
((iflags & S_APPEND) ? LUSTRE_APPEND_FL : 0) |
((iflags & S_DIRSYNC) ? LUSTRE_DIRSYNC_FL : 0) |
+#if defined(S_ENCRYPTED)
+ ((iflags & S_ENCRYPTED) ? LUSTRE_ENCRYPT_FL : 0) |
+#endif
((iflags & S_IMMUTABLE) ? LUSTRE_IMMUTABLE_FL : 0));
}
@@ -10,3 +10,4 @@ lustre-y := dcache.o dir.o file.o llite_lib.o llite_nfs.o \
lproc_llite.o pcc.o
lustre-$(CONFIG_LUSTRE_FS_POSIX_ACL) += acl.o
+lustre-$(CONFIG_FS_ENCRYPTION) += crypto.o
new file mode 100644
@@ -0,0 +1,132 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * GPL HEADER START
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 only,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License version 2 for more details (a copy is included
+ * in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 along with this program; If not, see
+ * http://www.gnu.org/licenses/gpl-2.0.html
+ *
+ * GPL HEADER END
+ */
+/*
+ * Copyright (c) 2019, 2020, Whamcloud.
+ */
+/*
+ * This file is part of Lustre, http://www.lustre.org/
+ */
+
+#include "llite_internal.h"
+
+static int ll_get_context(struct inode *inode, void *ctx, size_t len)
+{
+ struct dentry *dentry;
+
+ if (hlist_empty(&inode->i_dentry))
+ return -ENODATA;
+
+ hlist_for_each_entry(dentry, &inode->i_dentry, d_u.d_alias)
+ break;
+
+ return __vfs_getxattr(dentry, inode, LL_XATTR_NAME_ENCRYPTION_CONTEXT,
+ ctx, len);
+}
+
+static int ll_set_context(struct inode *inode, const void *ctx, size_t len,
+ void *fs_data)
+{
+ unsigned int ext_flags;
+ struct dentry *dentry;
+ struct md_op_data *op_data;
+ struct ptlrpc_request *req = NULL;
+ int rc;
+
+ if (inode == NULL)
+ return 0;
+
+ ext_flags = ll_inode_to_ext_flags(inode->i_flags) | LUSTRE_ENCRYPT_FL;
+ dentry = (struct dentry *)fs_data;
+
+ /* Encrypting the root directory is not allowed */
+ if (inode->i_ino == inode->i_sb->s_root->d_inode->i_ino)
+ return -EPERM;
+
+ op_data = ll_prep_md_op_data(NULL, inode, NULL, NULL, 0, 0,
+ LUSTRE_OPC_ANY, NULL);
+ if (IS_ERR(op_data))
+ return PTR_ERR(op_data);
+
+ op_data->op_attr_flags = LUSTRE_ENCRYPT_FL;
+ op_data->op_xvalid |= OP_XVALID_FLAGS;
+ rc = md_setattr(ll_i2sbi(inode)->ll_md_exp, op_data, NULL, 0, &req);
+ ll_finish_md_op_data(op_data);
+ ptlrpc_req_finished(req);
+ if (rc)
+ return rc;
+
+ rc = __vfs_setxattr(dentry, inode, LL_XATTR_NAME_ENCRYPTION_CONTEXT,
+ ctx, len, XATTR_CREATE);
+ if (rc)
+ return rc;
+
+ ll_update_inode_flags(inode, ext_flags);
+ return 0;
+}
+
+inline bool ll_sbi_has_test_dummy_encryption(struct ll_sb_info *sbi)
+{
+ return unlikely(sbi->ll_flags & LL_SBI_TEST_DUMMY_ENCRYPTION);
+}
+
+static bool ll_dummy_context(struct inode *inode)
+{
+ struct ll_sb_info *sbi = ll_i2sbi(inode);
+
+ return sbi ? ll_sbi_has_test_dummy_encryption(sbi) : false;
+}
+
+inline bool ll_sbi_has_encrypt(struct ll_sb_info *sbi)
+{
+ return sbi->ll_flags & LL_SBI_ENCRYPT;
+}
+
+inline void ll_sbi_set_encrypt(struct ll_sb_info *sbi, bool set)
+{
+ if (set)
+ sbi->ll_flags |= LL_SBI_ENCRYPT;
+ else
+ sbi->ll_flags &=
+ ~(LL_SBI_ENCRYPT | LL_SBI_TEST_DUMMY_ENCRYPTION);
+}
+
+static bool ll_empty_dir(struct inode *inode)
+{
+ /* used by llcrypt_ioctl_set_policy(), because a policy can only be set
+ * on an empty dir.
+ */
+ /* Here we choose to return true, meaning we always call .set_context.
+ * Then we rely on server side, with mdd_fix_attr() that calls
+ * mdd_dir_is_empty() when setting encryption flag on directory.
+ */
+ return true;
+}
+
+const struct llcrypt_operations lustre_cryptops = {
+ .key_prefix = "lustre:",
+ .get_context = ll_get_context,
+ .set_context = ll_set_context,
+ .dummy_context = ll_dummy_context,
+ .empty_dir = ll_empty_dir,
+ .max_namelen = NAME_MAX,
+};
@@ -44,9 +44,11 @@
#include <lustre_mdc.h>
#include <lustre_intent.h>
#include <linux/compat.h>
+#include <lustre_crypto.h>
#include <linux/namei.h>
#include <linux/xattr.h>
#include <linux/posix_acl_xattr.h>
+
#include "vvp_internal.h"
#include "range_lock.h"
#include "pcc.h"
@@ -551,6 +553,8 @@ enum stats_track_type {
*/
#define LL_SBI_TINY_WRITE 0x2000000 /* tiny write support */
#define LL_SBI_FILE_HEAT 0x4000000 /* file heat support */
+#define LL_SBI_TEST_DUMMY_ENCRYPTION 0x8000000 /* test dummy encryption */
+#define LL_SBI_ENCRYPT 0x10000000 /* client side encryption */
#define LL_SBI_FLAGS { \
"nolck", \
"checksum", \
@@ -579,6 +583,8 @@ enum stats_track_type {
"pio", \
"tiny_write", \
"file_heat", \
+ "test_dummy_encryption", \
+ "noencrypt", \
}
/*
@@ -1578,4 +1584,24 @@ static inline struct pcc_super *ll_info2pccs(struct ll_inode_info *lli)
return ll_i2pccs(ll_info2i(lli));
}
+#ifdef CONFIG_FS_ENCRYPTION
+/* crypto.c */
+extern const struct llcrypt_operations lustre_cryptops;
+
+#else /* !CONFIG_FS_ENCRYPTION */
+inline bool ll_sbi_has_test_dummy_encryption(struct ll_sb_info *sbi)
+{
+ return false;
+}
+
+inline bool ll_sbi_has_encrypt(struct ll_sb_info *sbi)
+{
+ return false;
+}
+
+inline void ll_sbi_set_encrypt(struct ll_sb_info *sbi, bool set)
+{
+}
+#endif /* !CONFIG_FS_ENCRYPTION */
+
#endif /* LLITE_INTERNAL_H */
@@ -155,6 +155,7 @@ static struct ll_sb_info *ll_init_sbi(void)
sbi->ll_flags |= LL_SBI_AGL_ENABLED;
sbi->ll_flags |= LL_SBI_FAST_READ;
sbi->ll_flags |= LL_SBI_TINY_WRITE;
+ ll_sbi_set_encrypt(sbi, true);
/* root squash */
sbi->ll_squash.rsi_uid = 0;
@@ -551,6 +552,7 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt)
#if THREAD_SIZE >= 8192 /*b=17630*/
sb->s_export_op = &lustre_export_operations;
#endif
+ llcrypt_set_ops(sb, &lustre_cryptops);
/* make root inode
* XXX: move this to after cbd setup?
@@ -923,6 +925,25 @@ static int ll_options(char *options, struct ll_sb_info *sbi)
*flags |= tmp;
goto next;
}
+ tmp = ll_set_opt("test_dummy_encryption", s1,
+ LL_SBI_TEST_DUMMY_ENCRYPTION);
+ if (tmp) {
+#ifdef CONFIG_FS_ENCRYPTION
+ *flags |= tmp;
+#else
+ LCONSOLE_WARN("Test dummy encryption mount option ignored: encryption not supported\n");
+#endif
+ goto next;
+ }
+ tmp = ll_set_opt("noencrypt", s1, LL_SBI_ENCRYPT);
+ if (tmp) {
+#ifdef CONFIG_FS_ENCRYPTION
+ *flags &= ~tmp;
+#else
+ LCONSOLE_WARN("noencrypt mount option ignored: encryption not supported\n");
+#endif
+ goto next;
+ }
LCONSOLE_ERROR_MSG(0x152, "Unknown option '%s', won't mount.\n",
s1);
return -EINVAL;
@@ -1558,6 +1579,8 @@ void ll_clear_inode(struct inode *inode)
* cl_object still uses inode lsm.
*/
cl_inode_fini(inode);
+
+ llcrypt_put_encryption_info(inode);
}
static int ll_md_setattr(struct dentry *dentry, struct md_op_data *op_data)
@@ -1978,6 +2001,8 @@ void ll_update_inode_flags(struct inode *inode, int ext_flags)
{
struct ll_inode_info *lli = ll_i2info(inode);
+ /* do not clear encryption flag */
+ ext_flags |= ll_inode_to_ext_flags(inode->i_flags) & LUSTRE_ENCRYPT_FL;
inode->i_flags = ll_ext_to_inode_flags(ext_flags);
if (ext_flags & LUSTRE_PROJINHERIT_FL)
set_bit(LLIF_PROJECT_INHERIT, &lli->lli_flags);
@@ -2702,6 +2727,14 @@ int ll_show_options(struct seq_file *seq, struct dentry *dentry)
if (sbi->ll_flags & LL_SBI_ALWAYS_PING)
seq_puts(seq, ",always_ping");
+ if (ll_sbi_has_test_dummy_encryption(sbi))
+ seq_puts(seq, ",test_dummy_encryption");
+
+ if (ll_sbi_has_encrypt(sbi))
+ seq_puts(seq, ",encrypt");
+ else
+ seq_puts(seq, ",noencrypt");
+
return 0;
}
@@ -63,6 +63,7 @@ static void ll_inode_destroy_callback(struct rcu_head *head)
struct inode *inode = container_of(head, struct inode, i_rcu);
struct ll_inode_info *ptr = ll_i2info(inode);
+ llcrypt_free_inode(inode);
kmem_cache_free(ll_inode_cachep, ptr);
}
@@ -1108,6 +1108,8 @@ struct lov_mds_md_v1 { /* LOV EA mds/wire data (little-endian) */
#define XATTR_NAME_HSM "trusted.hsm"
#define XATTR_NAME_LFSCK_NAMESPACE "trusted.lfsck_namespace"
+#define LL_XATTR_NAME_ENCRYPTION_CONTEXT XATTR_SECURITY_PREFIX"c"
+
struct lov_mds_md_v3 { /* LOV EA mds/wire data (little-endian) */
__u32 lmm_magic; /* magic number = LOV_MAGIC_V3 */
__u32 lmm_pattern; /* LOV_PATTERN_RAID0, LOV_PATTERN_RAID1 */
@@ -1571,6 +1573,16 @@ enum {
LUSTRE_TOPDIR_FL = 0x00020000, /* Top of directory hierarchies*/
LUSTRE_INLINE_DATA_FL = 0x10000000, /* Inode has inline data. */
LUSTRE_PROJINHERIT_FL = 0x20000000, /* Create with parents projid */
+
+ /* These flags will not be identical to any EXT4_*_FL counterparts,
+ * and only reserved for lustre purpose. Note: these flags might
+ * be conflict with some of EXT4 flags, so
+ * 1. these conflict flags needs to be removed when the flag is
+ * wired by la_flags see osd_attr_get().
+ * 2. If these flags needs to be stored into inode, they will be
+ * stored in LMA. see LMAI_XXXX
+ */
+ LUSTRE_ENCRYPT_FL = 0x00800000, /* encrypted file */
};
/* 64 possible states */