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>
])
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],
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
lustre_acl.h \
lustre_barrier.h \
lustre_compat.h \
+ lustre_crypto.h \
lustre_debug.h \
lustre_disk.h \
lustre_dlm_flags.h \
--- /dev/null
+/*
+ * 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_ */
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
((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));
}
((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));
}
#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. */
* 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
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)
};
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
--- /dev/null
+/*
+ * 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
+
#include <linux/compat.h>
#include <linux/aio.h>
#include <lustre_compat.h>
+#include <lustre_crypto.h>
#include "vvp_internal.h"
#include "range_lock.h"
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", \
"pio", \
"tiny_write", \
"file_heat", \
+ "test_dummy_encryption", \
+ "noencrypt", \
}
/* This is embedded into llite super-blocks to keep track of connect
return ll_i2pccs(ll_info2i(lli));
}
+#ifdef HAVE_LUSTRE_CRYPTO
+/* crypto.c */
+extern const struct llcrypt_operations lustre_cryptops;
+#endif
+
#endif /* LLITE_INTERNAL_H */
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;
#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? */
*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);
*/
cl_inode_fini(inode);
+ llcrypt_put_encryption_info(inode);
+
EXIT;
}
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);
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);
}
{
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);
}
* -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;
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);
!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) &&
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) &&
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,
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;
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);
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",
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;
}
}
}
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)
(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",
(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",
#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>
"\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);
}
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);
CHECK_VALUE_X(LMAI_REMOTE_PARENT);
CHECK_VALUE_X(LMAI_STRIPED);
CHECK_VALUE_X(LMAI_ORPHAN);
+ CHECK_VALUE_X(LMAI_ENCRYPT);
}
static 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);
(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",
(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",