Whamcloud - gitweb
LU-12275 sec: enable client side encryption 43/36143/22
authorSebastien Buisson <sbuisson@ddn.com>
Mon, 8 Jul 2019 14:51:39 +0000 (14:51 +0000)
committerOleg Drokin <green@whamcloud.com>
Sat, 6 Jun 2020 14:02:20 +0000 (14:02 +0000)
Enable client side encryption. By default it is activated,
letting user specifies actual encryption policy to use on
a per-directory basis. It is possible to deactivate client
side encryption by using the 'noencrypt' mount option.

Also add the test dummy encryption mode option to ease
testing.

Signed-off-by: Sebastien Buisson <sbuisson@ddn.com>
Change-Id: I0e8d4db7ab8a77aba0600788cca9403f7c50f8a6
Reviewed-on: https://review.whamcloud.com/36143
Reviewed-by: John L. Hammond <jhammond@whamcloud.com>
Reviewed-by: Andreas Dilger <adilger@whamcloud.com>
Tested-by: jenkins <devops@whamcloud.com>
Tested-by: Maloo <maloo@whamcloud.com>
Reviewed-by: Oleg Drokin <green@whamcloud.com>
24 files changed:
MAINTAINERS
lustre/autoconf/lustre-core.m4
lustre/doc/mount.lustre.8
lustre/include/Makefile.am
lustre/include/lustre_crypto.h [new file with mode: 0644]
lustre/include/obd_support.h
lustre/include/uapi/linux/lustre/lustre_idl.h
lustre/include/uapi/linux/lustre/lustre_user.h
lustre/llite/Makefile.in
lustre/llite/crypto.c [new file with mode: 0644]
lustre/llite/llite_internal.h
lustre/llite/llite_lib.c
lustre/llite/super25.c
lustre/mdd/mdd_dir.c
lustre/mdd/mdd_internal.h
lustre/mdd/mdd_object.c
lustre/osd-ldiskfs/osd_handler.c
lustre/osd-zfs/osd_internal.h
lustre/osd-zfs/osd_object.c
lustre/osd-zfs/osd_xattr.c
lustre/ptlrpc/wiretest.c
lustre/utils/mount_lustre.c
lustre/utils/wirecheck.c
lustre/utils/wiretest.c

index 137e272..6ca8902 100644 (file)
@@ -133,9 +133,14 @@ Lustre client side encryption
 M:     Sebastien Buisson <sbuisson@whamcloud.com>
 S:     Maintained
 F:     Documentation/client_side_encryption/*.txt
+F:     lustre/llite/crypto*.[ch]
 F:     libcfs/libcfs/crypto/*.[ch]
 F:     libcfs/include/libcfs/crypto/*.h
 F:     libcfs/include/uapi/linux/llcrypt.h
+F:     lustre/include/lustre_crypto.h
+K:     fscrypt
+K:     llcrypt
+K:     HAVE_LUSTRE_CRYPTO
 
 Lustre Client VFS Interface
 R:     Oleg Drokin <green@whamcloud.com>
index ac986de..4f9ce29 100644 (file)
@@ -2655,6 +2655,8 @@ No selinux package found, unable to build selinux enabled tools
 ])
 AC_SUBST(SELINUX)
 
+AC_CHECK_LIB([keyutils], [add_key])
+
 # Super safe df
 AC_MSG_CHECKING([whether to report minimum OST free space])
 AC_ARG_ENABLE([mindf],
index f2fb607..cc1a25a 100644 (file)
@@ -221,6 +221,16 @@ Warning! 'network' option is incompatible with LNet Dynamic Peer Discovery.
 If you want to restrict client NID, please make sure LNet Dynamic Peer Discovery
 is disabled.
 .RE
+.TP
+.BI test_dummy_encryption
+Enable test dummy encryption mode.
+.RE
+.TP
+.BI noencrypt
+Disable Lustre client-side encryption. By default, Lustre client-side encryption
+is enabled, letting users define encryption policies on a per-directory basis.
+fscrypt userspace tool can be used for that purpose, see
+https://github.com/google/fscrypt
 .SH SERVER OPTIONS
 In addition to the standard mount options and backing disk type
 (e.g. ldiskfs) options listed in
index 0dcd3c2..16a6cab 100644 (file)
@@ -47,6 +47,7 @@ EXTRA_DIST = \
        lustre_acl.h \
        lustre_barrier.h \
        lustre_compat.h \
+       lustre_crypto.h \
        lustre_debug.h \
        lustre_disk.h \
        lustre_dlm_flags.h \
diff --git a/lustre/include/lustre_crypto.h b/lustre/include/lustre_crypto.h
new file mode 100644 (file)
index 0000000..63f7696
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * 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_LL_ENCRYPTION
+#include <libcfs/crypto/llcrypt.h>
+#else /* !CONFIG_LL_ENCRYPTION */
+#ifdef HAVE_LUSTRE_CRYPTO
+#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 /* !HAVE_LUSTRE_CRYPTO */
+#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 /* HAVE_LUSTRE_CRYPTO */
+#endif /* !CONFIG_LL_ENCRYPTION */
+
+#endif /* _LUSTRE_CRYPTO_H_ */
index d4b3585..e8a99d5 100644 (file)
@@ -965,12 +965,14 @@ do {                                                                          \
 
 static inline int lma_to_lustre_flags(__u32 lma_flags)
 {
-       return (lma_flags & LMAI_ORPHAN) ? LUSTRE_ORPHAN_FL : 0;
+       return (((lma_flags & LMAI_ORPHAN) ? LUSTRE_ORPHAN_FL : 0) |
+               ((lma_flags & LMAI_ENCRYPT) ? LUSTRE_ENCRYPT_FL : 0));
 }
 
 static inline int lustre_to_lma_flags(__u32 la_flags)
 {
-       return (la_flags & LUSTRE_ORPHAN_FL) ? LMAI_ORPHAN : 0;
+       return (((la_flags & LUSTRE_ORPHAN_FL) ? LMAI_ORPHAN : 0) |
+               ((la_flags & LUSTRE_ENCRYPT_FL) ? LMAI_ENCRYPT : 0));
 }
 
 /* Convert wire LUSTRE_*_FL to corresponding client local VFS S_* values
@@ -986,6 +988,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));
 }
 
@@ -995,6 +1000,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));
 }
 
index 088dab5..6450380 100644 (file)
@@ -1199,6 +1199,8 @@ struct lov_mds_md_v1 {            /* LOV EA mds/wire data (little-endian) */
 #define XATTR_NAME_LFSCK_BITMAP "trusted.lfsck_bitmap"
 #define XATTR_NAME_DUMMY       "trusted.dummy"
 
+#define LL_XATTR_NAME_ENCRYPTION_CONTEXT XATTR_SECURITY_PREFIX"c"
+
 #define XATTR_NAME_LFSCK_NAMESPACE "trusted.lfsck_ns"
 #define XATTR_NAME_MAX_LEN     32 /* increase this, if there is longer name. */
 
@@ -1775,8 +1777,9 @@ enum {
         * stored in LMA. see LMAI_XXXX */
        LUSTRE_ORPHAN_FL        = 0x00002000,
        LUSTRE_SET_SYNC_FL      = 0x00040000, /* Synchronous setattr on OSTs */
+       LUSTRE_ENCRYPT_FL       = 0x00800000, /* encrypted file */
 
-       LUSTRE_LMA_FL_MASKS     = LUSTRE_ORPHAN_FL,
+       LUSTRE_LMA_FL_MASKS     = LUSTRE_ENCRYPT_FL | LUSTRE_ORPHAN_FL,
 };
 
 #ifndef FS_XFLAG_SYNC
index 6e52437..291c70e 100644 (file)
@@ -424,8 +424,9 @@ enum lma_incompat {
                                                 is on the remote MDT */
        LMAI_STRIPED            = 0x00000008, /* striped directory inode */
        LMAI_ORPHAN             = 0x00000010, /* inode is orphan */
+       LMAI_ENCRYPT            = 0x00000020, /* inode is encrypted */
        LMA_INCOMPAT_SUPP       = (LMAI_AGENT | LMAI_REMOTE_PARENT | \
-                                  LMAI_STRIPED | LMAI_ORPHAN)
+                                  LMAI_STRIPED | LMAI_ORPHAN | LMAI_ENCRYPT)
 };
 
 
index ec5ab34..3a5293f 100644 (file)
@@ -7,7 +7,7 @@ lustre-objs += glimpse.o
 lustre-objs += lcommon_cl.o
 lustre-objs += lcommon_misc.o
 lustre-objs += vvp_dev.o vvp_page.o vvp_io.o vvp_object.o
-lustre-objs += range_lock.o pcc.o
+lustre-objs += range_lock.o pcc.o crypto.o
 
 EXTRA_DIST := $(lustre-objs:.o=.c) xattr.c rw26.c super25.c
 EXTRA_DIST += llite_internal.h vvp_internal.h range_lock.h pcc.h
diff --git a/lustre/llite/crypto.c b/lustre/llite/crypto.c
new file mode 100644 (file)
index 0000000..5ccbedf
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ * 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"
+
+#ifdef HAVE_LUSTRE_CRYPTO
+
+static int ll_get_context(struct inode *inode, void *ctx, size_t len)
+{
+       struct dentry *dentry;
+       int rc;
+
+       if (hlist_empty(&inode->i_dentry))
+               return -ENODATA;
+
+       hlist_for_each_entry(dentry, &inode->i_dentry, d_alias) {
+               break;
+       }
+
+       rc = ll_vfs_getxattr(dentry, inode, LL_XATTR_NAME_ENCRYPTION_CONTEXT,
+                            ctx, len);
+
+       return rc;
+}
+
+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 = ll_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,
+};
+#else /* !HAVE_LUSTRE_CRYPTO */
+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
+
index 76db0b0..cb0ebf2 100644 (file)
@@ -45,6 +45,7 @@
 #include <linux/compat.h>
 #include <linux/aio.h>
 #include <lustre_compat.h>
+#include <lustre_crypto.h>
 
 #include "vvp_internal.h"
 #include "range_lock.h"
@@ -585,6 +586,8 @@ enum stats_track_type {
                                         2.10, abandoned */
 #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",     \
@@ -613,6 +616,8 @@ enum stats_track_type {
        "pio",          \
        "tiny_write",   \
        "file_heat",    \
+       "test_dummy_encryption", \
+       "noencrypt",    \
 }
 
 /* This is embedded into llite super-blocks to keep track of connect
@@ -1639,4 +1644,9 @@ static inline struct pcc_super *ll_info2pccs(struct ll_inode_info *lli)
        return ll_i2pccs(ll_info2i(lli));
 }
 
+#ifdef HAVE_LUSTRE_CRYPTO
+/* crypto.c */
+extern const struct llcrypt_operations lustre_cryptops;
+#endif
+
 #endif /* LLITE_INTERNAL_H */
index 254a641..78ff536 100644 (file)
@@ -166,6 +166,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;
@@ -559,6 +560,9 @@ 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
+#ifdef HAVE_LUSTRE_CRYPTO
+       llcrypt_set_ops(sb, &lustre_cryptops);
+#endif
 
        /* make root inode
         * XXX: move this to after cbd setup? */
@@ -944,6 +948,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 HAVE_LUSTRE_CRYPTO
+                       *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 HAVE_LUSTRE_CRYPTO
+                       *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);
@@ -1635,6 +1658,8 @@ void ll_clear_inode(struct inode *inode)
         */
        cl_inode_fini(inode);
 
+       llcrypt_put_encryption_info(inode);
+
        EXIT;
 }
 
@@ -2042,6 +2067,8 @@ void ll_inode_size_unlock(struct inode *inode)
 
 void ll_update_inode_flags(struct inode *inode, int ext_flags)
 {
+       /* 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)
                ll_file_set_flag(ll_i2info(inode), LLIF_PROJECT_INHERIT);
@@ -2793,6 +2820,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);
 }
 
index befd246..30397af 100644 (file)
@@ -61,6 +61,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);
        OBD_SLAB_FREE_PTR(ptr, ll_inode_cachep);
 }
 
index 0006f16..8f45fb9 100644 (file)
@@ -356,8 +356,7 @@ int mdd_is_subdir(const struct lu_env *env, struct md_object *mo,
  *           -ve        other error
  *
  */
-static int mdd_dir_is_empty(const struct lu_env *env,
-                            struct mdd_object *dir)
+int mdd_dir_is_empty(const struct lu_env *env, struct mdd_object *dir)
 {
        struct dt_it     *it;
        struct dt_object *obj;
index a5bc753..5a502f9 100644 (file)
@@ -312,6 +312,7 @@ int mdd_orphan_declare_insert(const struct lu_env *env, struct mdd_object *obj,
                              umode_t mode, struct thandle *thandle);
 int mdd_orphan_declare_delete(const struct lu_env *env, struct mdd_object *obj,
                              struct thandle *thandle);
+int mdd_dir_is_empty(const struct lu_env *env, struct mdd_object *dir);
 
 /* mdd_lproc.c */
 int mdd_procfs_init(struct mdd_device *mdd, const char *name);
index df5bea0..d30599a 100644 (file)
@@ -735,8 +735,17 @@ static int mdd_fix_attr(const struct lu_env *env, struct mdd_object *obj,
                    !md_capable(uc, CFS_CAP_LINUX_IMMUTABLE))
                        RETURN(-EPERM);
 
-               if (!S_ISDIR(oattr->la_mode))
+               if (!S_ISDIR(oattr->la_mode)) {
                        la->la_flags &= ~(LUSTRE_DIRSYNC_FL | LUSTRE_TOPDIR_FL);
+               } else if (la->la_flags & LUSTRE_ENCRYPT_FL) {
+                       /* when trying to add encryption flag on dir,
+                        * make sure it is empty
+                        */
+                       rc = mdd_dir_is_empty(env, obj);
+                       if (rc)
+                               RETURN(rc);
+                       rc = 0;
+               }
        }
 
        if (oattr->la_flags & (LUSTRE_IMMUTABLE_FL | LUSTRE_APPEND_FL) &&
index 027ded0..88f3576 100644 (file)
@@ -2704,6 +2704,10 @@ static int osd_attr_get(const struct lu_env *env, struct dt_object *dt,
                attr->la_valid |= LA_FLAGS;
                attr->la_flags |= LUSTRE_ORPHAN_FL;
        }
+       if (obj->oo_lma_flags & LUSTRE_ENCRYPT_FL) {
+               attr->la_valid |= LA_FLAGS;
+               attr->la_flags |= LUSTRE_ENCRYPT_FL;
+       }
        spin_unlock(&obj->oo_guard);
 
        if (S_ISDIR(obj->oo_inode->i_mode) &&
index 737ec68..9887b58 100644 (file)
@@ -715,6 +715,8 @@ int __osd_xattr_get_large(const struct lu_env *env, struct osd_device *osd,
                          const char *name, int *sizep);
 int osd_xattr_get_internal(const struct lu_env *env, struct osd_object *obj,
                           struct lu_buf *buf, const char *name, int *sizep);
+int osd_xattr_get_lma(const struct lu_env *env, struct osd_object *obj,
+                     struct lu_buf *buf);
 int osd_xattr_get(const struct lu_env *env, struct dt_object *dt,
                  struct lu_buf *buf, const char *name);
 int osd_declare_xattr_set(const struct lu_env *env, struct dt_object *dt,
index cce661c..8293a01 100644 (file)
@@ -186,9 +186,11 @@ osd_object_sa_bulk_update(struct osd_object *obj, sa_bulk_attr_t *attrs,
 static int __osd_object_attr_get(const struct lu_env *env, struct osd_device *o,
                                 struct osd_object *obj, struct lu_attr *la)
 {
-       struct osa_attr *osa = &osd_oti_get(env)->oti_osa;
-       sa_bulk_attr_t  *bulk = osd_oti_get(env)->oti_attr_bulk;
-       int              cnt = 0;
+       struct osa_attr *osa = &osd_oti_get(env)->oti_osa;
+       sa_bulk_attr_t *bulk = osd_oti_get(env)->oti_attr_bulk;
+       struct lustre_mdt_attrs *lma;
+       struct lu_buf buf;
+       int cnt = 0;
        int              rc;
        ENTRY;
 
@@ -244,27 +246,22 @@ static int __osd_object_attr_get(const struct lu_env *env, struct osd_device *o,
        la->la_flags = attrs_zfs2fs(osa->flags);
        la->la_size = osa->size;
 
-       /* Try to get extra flag from LMA. Right now, only LMAI_ORPHAN
-        * flags is stored in LMA, and it is only for orphan directory */
-       if (S_ISDIR(la->la_mode) && dt_object_exists(&obj->oo_dt)) {
-               struct osd_thread_info *info = osd_oti_get(env);
-               struct lustre_mdt_attrs *lma;
-               struct lu_buf buf;
-
-               lma = (struct lustre_mdt_attrs *)info->oti_buf;
-               buf.lb_buf = lma;
-               buf.lb_len = sizeof(info->oti_buf);
-               rc = osd_xattr_get(env, &obj->oo_dt, &buf, XATTR_NAME_LMA);
-               if (rc > 0) {
-                       rc = 0;
-                       lma->lma_incompat = le32_to_cpu(lma->lma_incompat);
-                       obj->oo_lma_flags =
-                               lma_to_lustre_flags(lma->lma_incompat);
-
-               } else if (rc == -ENODATA) {
-                       rc = 0;
-               }
+       /* Try to get extra flags from LMA */
+       lma = (struct lustre_mdt_attrs *)osd_oti_get(env)->oti_buf;
+       buf.lb_buf = lma;
+       buf.lb_len = sizeof(osd_oti_get(env)->oti_buf);
+       down_read(&obj->oo_guard);
+       rc = osd_xattr_get_lma(env, obj, &buf);
+       if (!rc) {
+               lma->lma_incompat = le32_to_cpu(lma->lma_incompat);
+               obj->oo_lma_flags =
+                       lma_to_lustre_flags(lma->lma_incompat);
+       } else if (rc == -ENODATA ||
+                  !(S_ISDIR(la->la_mode) &&
+                    dt_object_exists(&obj->oo_dt))) {
+               rc = 0;
        }
+       up_read(&obj->oo_guard);
 
        if (S_ISCHR(la->la_mode) || S_ISBLK(la->la_mode)) {
                rc = -sa_lookup(obj->oo_sa_hdl, SA_ZPL_RDEV(o), &osa->rdev, 8);
@@ -1013,6 +1010,10 @@ static int osd_attr_get(const struct lu_env *env, struct dt_object *dt,
                attr->la_valid |= LA_FLAGS;
                attr->la_flags |= LUSTRE_ORPHAN_FL;
        }
+       if (obj->oo_lma_flags & LUSTRE_ENCRYPT_FL) {
+               attr->la_valid |= LA_FLAGS;
+               attr->la_flags |= LUSTRE_ENCRYPT_FL;
+       }
        read_unlock(&obj->oo_attr_lock);
        if (attr->la_valid & LA_FLAGS && attr->la_flags & LUSTRE_ORPHAN_FL)
                CDEBUG(D_INFO, "%s: set orphan flag on "DFID" (%llx/%x)\n",
@@ -1339,6 +1340,9 @@ static int osd_attr_set(const struct lu_env *env, struct dt_object *dt,
                                CWARN("%s: failed to set LMA flags: rc = %d\n",
                                       osd->od_svname, rc);
                                GOTO(out, rc);
+                       } else {
+                               obj->oo_lma_flags =
+                                       la->la_flags & LUSTRE_LMA_FL_MASKS;
                        }
                }
        }
index 91ed638..e50f23f 100644 (file)
@@ -223,6 +223,46 @@ int osd_xattr_get_internal(const struct lu_env *env, struct osd_object *obj,
                                     buf, name, sizep);
 }
 
+/**
+ * Copy LMA extended attribute into provided buffer
+ *
+ * Note that no locking is done here.
+ *
+ * \param[in] env      execution environment
+ * \param[in] obj      object for which to retrieve xattr
+ * \param[out] buf     buffer to store xattr value in
+ *
+ * \retval 0           on success
+ * \retval negative    negated errno on failure
+ */
+int osd_xattr_get_lma(const struct lu_env *env, struct osd_object *obj,
+                     struct lu_buf *buf)
+{
+       int size = 0;
+       int rc = -ENOENT;
+
+       if (!buf)
+               return 0;
+
+       if (unlikely(obj->oo_destroyed))
+               goto out_lma;
+
+       /* check SA_ZPL_DXATTR first then fallback to directory xattr */
+       rc = __osd_sa_xattr_get(env, obj, buf, XATTR_NAME_LMA, &size);
+       if (!rc && unlikely(size < sizeof(struct lustre_mdt_attrs)))
+               rc = -EINVAL;
+       if (rc != -ENOENT)
+               goto out_lma;
+
+       rc = __osd_xattr_get_large(env, osd_obj2dev(obj), obj->oo_xattr,
+                                    buf, XATTR_NAME_LMA, &size);
+       if (!rc && unlikely(size < sizeof(struct lustre_mdt_attrs)))
+               rc = -EINVAL;
+
+out_lma:
+       return rc;
+}
+
 static int osd_get_pfid_from_lma(const struct lu_env *env,
                                 struct osd_object *obj,
                                 struct lu_buf *buf, int *sizep)
index 019d45e..50cef04 100644 (file)
@@ -451,6 +451,8 @@ void lustre_assert_wire_constants(void)
                (unsigned)LMAI_STRIPED);
        LASSERTF(LMAI_ORPHAN == 0x00000010UL, "found 0x%.8xUL\n",
                (unsigned)LMAI_ORPHAN);
+       LASSERTF(LMAI_ENCRYPT == 0x00000020UL, "found 0x%.8xUL\n",
+                (unsigned)LMAI_ENCRYPT);
 
        /* Checks for struct lustre_ost_attrs */
        LASSERTF((int)sizeof(struct lustre_ost_attrs) == 64, "found %lld\n",
@@ -2575,6 +2577,8 @@ void lustre_assert_wire_constants(void)
                (unsigned)LUSTRE_INLINE_DATA_FL);
        LASSERTF(LUSTRE_SET_SYNC_FL == 0x00040000UL, "found 0x%.8xUL\n",
                (unsigned)LUSTRE_SET_SYNC_FL);
+       LASSERTF(LUSTRE_ENCRYPT_FL == 0x00800000UL, "found 0x%.8xUL\n",
+                (unsigned)LUSTRE_ENCRYPT_FL);
        LASSERTF(MDS_INODELOCK_LOOKUP == 0x00000001UL, "found 0x%.8xUL\n",
                (unsigned)MDS_INODELOCK_LOOKUP);
        LASSERTF(MDS_INODELOCK_UPDATE == 0x00000002UL, "found 0x%.8xUL\n",
index 566a8d5..820dc7f 100644 (file)
@@ -52,6 +52,9 @@
 #include <linux/lustre/lustre_ver.h>
 #include <ctype.h>
 #include <limits.h>
+#if defined(HAVE_LUSTRE_CRYPTO) && defined(HAVE_LIBKEYUTILS)
+#include <keyutils.h>
+#endif
 #include <linux/lnet/nidstr.h>
 #include <libcfs/util/string.h>
 
@@ -116,6 +119,12 @@ void usage(FILE *out)
                "\t\t(no)lazystatfs: disable or enable* statfs to work if OST is unavailable\n"
                "\t\t32bitapi: return only 32-bit inode numbers to userspace\n"
                "\t\t(no)verbose: disable or enable* messages at filesystem (un,re)mount\n"
+#ifdef HAVE_LUSTRE_CRYPTO
+#ifdef HAVE_LIBKEYUTILS
+               "\t\ttest_dummy_encryption: enable test dummy encryption mode\n"
+#endif
+               "\t\tnoencrypt: disable client side encryption\n"
+#endif
                );
        exit((out != stdout) ? EINVAL : 0);
 }
@@ -345,6 +354,52 @@ int parse_options(struct mount_opts *mop, char *orig_options,
                        strncpy(mop->mo_skpath, val + 1,
                                sizeof(mop->mo_skpath) - 1);
 #endif
+#ifdef HAVE_LUSTRE_CRYPTO
+               } else if (strncmp(arg, "test_dummy_encryption", 21) == 0) {
+#ifdef HAVE_LIBKEYUTILS
+                       /* Using dummy encryption mode requires inserting a
+                        * special dummy key into the session keyring.
+                        * Key type is "logon", key description is
+                        * "fscrypt:4242424242424242", and key payload has to be
+                        * in the form <mode><raw><size>, where:
+                        * <mode> is "\x00\x00\x00\x00"
+                        * <raw> is "$(printf ""\\\\x%02x"" {0..63})"
+                        * <size> is "\x40\x00\x00\x00" for little endian,
+                        * "\x00\x00\x00\x40" for big endian.
+                        */
+                       char payload[72];
+                       int *p = (int *)payload;
+                       char *q = (char *)(p + 1);
+                       int i = 0;
+                       key_serial_t key;
+
+                       *p = 0;
+                       while (i < 0x40)
+                               *(q++) = i++;
+                       p = (int *)q;
+                       *p = 0x40;
+
+                       key = add_key("logon", "fscrypt:4242424242424242",
+                                     (const void *)payload, sizeof(payload),
+                                     KEY_SPEC_SESSION_KEYRING);
+
+                       if (key == -1) {
+                               fprintf(stderr,
+                                       "%s: test dummy encryption option ignored: could not insert dummy encryption key into session keyring\n",
+                                       progname);
+                       } else {
+                               /* pass this on as an option */
+                               rc = append_option(options, options_len, opt,
+                                                  NULL);
+                               if (rc != 0)
+                                       goto out_options;
+                       }
+#else /* HAVE_LIBKEYUTILS */
+                       fprintf(stderr,
+                               "%s: test dummy encryption option ignored: Lustre not built with libkeyutils support\n",
+                               progname);
+#endif
+#endif
                } else if (parse_one_option(opt, flagp) == 0) {
                        /* pass this on as an option */
                        rc = append_option(options, options_len, opt, NULL);
index c4d5e33..5f200da 100644 (file)
@@ -221,6 +221,7 @@ check_lustre_mdt_attrs(void)
        CHECK_VALUE_X(LMAI_REMOTE_PARENT);
        CHECK_VALUE_X(LMAI_STRIPED);
        CHECK_VALUE_X(LMAI_ORPHAN);
+       CHECK_VALUE_X(LMAI_ENCRYPT);
 }
 
 static void
@@ -1178,6 +1179,7 @@ check_mdt_body(void)
        CHECK_VALUE_X(LUSTRE_TOPDIR_FL);
        CHECK_VALUE_X(LUSTRE_INLINE_DATA_FL);
        CHECK_VALUE_X(LUSTRE_SET_SYNC_FL);
+       CHECK_VALUE_X(LUSTRE_ENCRYPT_FL);
 
        CHECK_VALUE_X(MDS_INODELOCK_LOOKUP);
        CHECK_VALUE_X(MDS_INODELOCK_UPDATE);
index 3c9d0a4..6ff30e6 100644 (file)
@@ -477,6 +477,8 @@ void lustre_assert_wire_constants(void)
                (unsigned)LMAI_STRIPED);
        LASSERTF(LMAI_ORPHAN == 0x00000010UL, "found 0x%.8xUL\n",
                (unsigned)LMAI_ORPHAN);
+       LASSERTF(LMAI_ENCRYPT == 0x00000020UL, "found 0x%.8xUL\n",
+                (unsigned)LMAI_ENCRYPT);
 
        /* Checks for struct lustre_ost_attrs */
        LASSERTF((int)sizeof(struct lustre_ost_attrs) == 64, "found %lld\n",
@@ -2601,6 +2603,8 @@ void lustre_assert_wire_constants(void)
                (unsigned)LUSTRE_INLINE_DATA_FL);
        LASSERTF(LUSTRE_SET_SYNC_FL == 0x00040000UL, "found 0x%.8xUL\n",
                (unsigned)LUSTRE_SET_SYNC_FL);
+       LASSERTF(LUSTRE_ENCRYPT_FL == 0x00800000UL, "found 0x%.8xUL\n",
+                (unsigned)LUSTRE_ENCRYPT_FL);
        LASSERTF(MDS_INODELOCK_LOOKUP == 0x00000001UL, "found 0x%.8xUL\n",
                (unsigned)MDS_INODELOCK_LOOKUP);
        LASSERTF(MDS_INODELOCK_UPDATE == 0x00000002UL, "found 0x%.8xUL\n",