Whamcloud - gitweb
LU-14677 sec: no encryption key migrate/extend/resync/split 24/44024/24
authorSebastien Buisson <sbuisson@ddn.com>
Thu, 17 Jun 2021 13:31:44 +0000 (15:31 +0200)
committerOleg Drokin <green@whamcloud.com>
Thu, 23 Dec 2021 07:17:58 +0000 (07:17 +0000)
Allow some layout operations on encrypted files, even when the
encryption key is not available:
- lfs migrate
- lfs mirror extend
- lfs mirror resync
- lfs mirror verify
- lfs mirror split
We allow these access patterns to applications that know what they are
doing, by using the specific flag O_FILE_ENC and O_DIRECT.

Also add sanity-sec test_59a,b,c to exercise these access patterns.

Signed-off-by: Sebastien Buisson <sbuisson@ddn.com>
Change-Id: Ieaeee0e5bf7643f18d775fe6daa5e31c2f349f8c
Reviewed-on: https://review.whamcloud.com/44024
Reviewed-by: Andreas Dilger <adilger@whamcloud.com>
Tested-by: jenkins <devops@whamcloud.com>
Tested-by: Maloo <maloo@whamcloud.com>
Reviewed-by: Patrick Farrell <pfarrell@whamcloud.com>
Reviewed-by: Oleg Drokin <green@whamcloud.com>
16 files changed:
lustre/doc/lfs-migrate.1
lustre/doc/lfs-mirror-split.1
lustre/include/lustre/lustreapi.h
lustre/include/obd.h
lustre/include/uapi/linux/lustre/lustre_user.h
lustre/llite/crypto.c
lustre/llite/dir.c
lustre/llite/file.c
lustre/llite/llite_internal.h
lustre/llite/llite_lib.c
lustre/llite/namei.c
lustre/osc/osc_request.c
lustre/tests/sanity-sec.sh
lustre/utils/lfs.c
lustre/utils/liblustreapi_layout.c
lustre/utils/lustreapi_internal.h

index 3991c9f..1ee23fd 100644 (file)
@@ -72,6 +72,11 @@ write operations synchronous.  Using the
 .B --non-direct
 option uses buffered read/write operations, which may improve migration
 speed at the cost of more CPU and memory overhead.
+.br
+This option cannot be used on encrypted files when the encryption key is not
+available. It will result in
+.B
+-ENOKEY.
 .TP
 .BR -v , --verbose
 Print each filename as it is migrated.
index fb74f18..9dd5daa 100644 (file)
@@ -40,10 +40,20 @@ The pool storing a component contained within a mirror.
 .TP
 .BR \-\-destroy\fR|\fB\-d\fR
 This option indicates the split mirror will be destroyed.
+.br
+This option is mandatory on encrypted files when the encryption key is not
+available. Otherwise operation results in
+.B
+-ENOKEY.
 .TP
 .BR \-f\fR\ <\fInew_file\fR>
 This option indicates the layout of the split mirror will be stored into
 <\fInew_file\fR>.
+.br
+This option cannot be used on encrypted files when the encryption key is not
+available. It will result in
+.B
+-ENOKEY.
 .SH EXAMPLES
 .TP
 .B lfs mirror split --mirror-id 1 /mnt/lustre/file1
index 2cf1669..2ce4bf1 100644 (file)
@@ -148,6 +148,13 @@ struct llapi_stripe_param {
 
 #define lsp_tgts       lsp_osts
 
+enum {
+       LLAPI_MIGRATION_NONBLOCK        = 0x0001,
+       LLAPI_MIGRATION_MIRROR          = 0x0002,
+       LLAPI_MIGRATION_NONDIRECT       = 0x0004,
+       LLAPI_MIGRATION_VERBOSE         = 0x0008,
+};
+
 __u32 llapi_pattern_to_lov(uint64_t pattern);
 
 int llapi_file_open_param(const char *name, int flags, mode_t mode,
index a2c2a40..9ebd53f 100644 (file)
@@ -866,7 +866,6 @@ enum md_op_code {
        LUSTRE_OPC_ANY,
        LUSTRE_OPC_LOOKUP,
        LUSTRE_OPC_OPEN,
-       LUSTRE_OPC_MIGR,
 };
 
 /**
index bb5d3e6..49f0b4c 100644 (file)
@@ -683,6 +683,10 @@ struct fsxattr {
 #define O_LOV_DELAY_CREATE_MASK        (O_NOCTTY | FASYNC)
 #define O_LOV_DELAY_CREATE             (O_LOV_DELAY_CREATE_1_8 | \
                                         O_LOV_DELAY_CREATE_MASK)
+/* O_FILE_ENC principle is similar to O_LOV_DELAY_CREATE above,
+ * for access to encrypted files without the encryption key.
+ */
+#define O_FILE_ENC             (O_NOCTTY | O_NDELAY)
 
 #define LL_FILE_IGNORE_LOCK     0x00000001
 #define LL_FILE_GROUP_LOCKED    0x00000002
index 7a073c9..cc80aea 100644 (file)
@@ -131,6 +131,34 @@ static int ll_set_context(struct inode *inode, const void *ctx, size_t len,
        return ll_set_encflags(inode, (void *)ctx, len, false);
 }
 
+/**
+ * ll_file_open_encrypt() - overlay to llcrypt_file_open
+ * @inode: the inode being opened
+ * @filp: the struct file being set up
+ *
+ * This overlay function is necessary to handle encrypted file open without
+ * the key. We allow this access pattern to applications that know what they
+ * are doing, by using the specific flag O_FILE_ENC.
+ * This flag is only compatible with O_DIRECT IOs, to make sure ciphertext
+ * data is wiped from page cache once IOs are finished.
+ */
+int ll_file_open_encrypt(struct inode *inode, struct file *filp)
+{
+       int rc;
+
+       rc = llcrypt_file_open(inode, filp);
+       if (likely(rc != -ENOKEY))
+               return rc;
+
+       if (rc == -ENOKEY &&
+           (filp->f_flags & O_FILE_ENC) == O_FILE_ENC &&
+           filp->f_flags & O_DIRECT)
+               /* allow file open with O_FILE_ENC flag when we have O_DIRECT */
+               rc = 0;
+
+       return rc;
+}
+
 void llcrypt_free_ctx(void *encctx, __u32 size)
 {
        if (encctx)
@@ -218,6 +246,17 @@ int ll_setup_filename(struct inode *dir, const struct qstr *iname,
                fid->f_ver = 0;
        }
        rc = llcrypt_setup_filename(dir, &dname, lookup, fname);
+       if (rc == -ENOENT && lookup &&
+           !llcrypt_has_encryption_key(dir) &&
+           unlikely(filename_is_volatile(iname->name, iname->len, NULL))) {
+               /* For purpose of migration or mirroring without enc key, we
+                * allow lookup of volatile file without enc context.
+                */
+               memset(fname, 0, sizeof(struct llcrypt_name));
+               fname->disk_name.name = (unsigned char *)iname->name;
+               fname->disk_name.len = iname->len;
+               rc = 0;
+       }
        if (rc)
                return rc;
 
@@ -418,6 +457,11 @@ int ll_set_encflags(struct inode *inode, void *encctx, __u32 encctxlen,
        return 0;
 }
 
+int ll_file_open_encrypt(struct inode *inode, struct file *filp)
+{
+       return llcrypt_file_open(inode, filp);
+}
+
 void llcrypt_free_ctx(void *encctx, __u32 size)
 {
 }
index ad94e5a..6294d23 100644 (file)
@@ -1847,7 +1847,11 @@ out_rmdir:
                        st.st_uid       = body->mbo_uid;
                        st.st_gid       = body->mbo_gid;
                        st.st_rdev      = body->mbo_rdev;
-                       st.st_size      = body->mbo_size;
+                       if (llcrypt_require_key(inode) == -ENOKEY)
+                               st.st_size = round_up(st.st_size,
+                                                  LUSTRE_ENCRYPTION_UNIT_SIZE);
+                       else
+                               st.st_size = body->mbo_size;
                        st.st_blksize   = PAGE_SIZE;
                        st.st_blocks    = body->mbo_blocks;
                        st.st_atime     = body->mbo_atime;
@@ -1870,7 +1874,11 @@ out_rmdir:
                        stx.stx_mode = body->mbo_mode;
                        stx.stx_ino = cl_fid_build_ino(&body->mbo_fid1,
                                                       api32);
-                       stx.stx_size = body->mbo_size;
+                       if (llcrypt_require_key(inode) == -ENOKEY)
+                               stx.stx_size = round_up(stx.stx_size,
+                                                  LUSTRE_ENCRYPTION_UNIT_SIZE);
+                       else
+                               stx.stx_size = body->mbo_size;
                        stx.stx_blocks = body->mbo_blocks;
                        stx.stx_atime.tv_sec = body->mbo_atime;
                        stx.stx_ctime.tv_sec = body->mbo_ctime;
index 21fb0b4..b5e11ca 100644 (file)
@@ -105,7 +105,16 @@ static void ll_prepare_close(struct inode *inode, struct md_op_data *op_data,
        op_data->op_attr.ia_atime = inode->i_atime;
        op_data->op_attr.ia_mtime = inode->i_mtime;
        op_data->op_attr.ia_ctime = inode->i_ctime;
-       op_data->op_attr.ia_size = i_size_read(inode);
+       /* In case of encrypted file without the key, visible size was rounded
+        * up to next LUSTRE_ENCRYPTION_UNIT_SIZE, and clear text size was
+        * stored into lli_lazysize in ll_merge_attr(), so set proper file size
+        * now that we are closing.
+        */
+       if (llcrypt_require_key(inode) == -ENOKEY &&
+           ll_i2info(inode)->lli_attr_valid & OBD_MD_FLLAZYSIZE)
+               op_data->op_attr.ia_size = ll_i2info(inode)->lli_lazysize;
+       else
+               op_data->op_attr.ia_size = i_size_read(inode);
        op_data->op_attr.ia_valid |= (ATTR_MODE | ATTR_ATIME | ATTR_ATIME_SET |
                                      ATTR_MTIME | ATTR_MTIME_SET |
                                      ATTR_CTIME);
@@ -816,9 +825,12 @@ int ll_file_open(struct inode *inode, struct file *file)
        file->private_data = NULL; /* prevent ll_local_open assertion */
 
        if (S_ISREG(inode->i_mode)) {
-               rc = llcrypt_file_open(inode, file);
-               if (rc)
+               rc = ll_file_open_encrypt(inode, file);
+               if (rc) {
+                       if (it && it->it_disposition)
+                               ll_release_openhandle(file_dentry(file), it);
                        GOTO(out_nofiledata, rc);
+               }
        }
 
        fd = ll_file_data_get();
@@ -1467,6 +1479,16 @@ int ll_merge_attr(const struct lu_env *env, struct inode *inode)
        CDEBUG(D_VFSTRACE, DFID" updating i_size %llu\n",
               PFID(&lli->lli_fid), attr->cat_size);
 
+       if (llcrypt_require_key(inode) == -ENOKEY) {
+               /* Without the key, round up encrypted file size to next
+                * LUSTRE_ENCRYPTION_UNIT_SIZE. Clear text size is put in
+                * lli_lazysize for proper file size setting at close time.
+                */
+               lli->lli_attr_valid |= OBD_MD_FLLAZYSIZE;
+               lli->lli_lazysize = attr->cat_size;
+               attr->cat_size = round_up(attr->cat_size,
+                                         LUSTRE_ENCRYPTION_UNIT_SIZE);
+       }
        i_size_write(inode, attr->cat_size);
        inode->i_blocks = attr->cat_blocks;
 
@@ -4420,6 +4442,12 @@ loff_t ll_lseek(struct file *file, loff_t offset, int whence)
 
        cl_env_put(env, &refcheck);
 
+       /* Without the key, SEEK_HOLE return value has to be
+        * rounded up to next LUSTRE_ENCRYPTION_UNIT_SIZE.
+        */
+       if (llcrypt_require_key(inode) == -ENOKEY && whence == SEEK_HOLE)
+               retval = round_up(retval, LUSTRE_ENCRYPTION_UNIT_SIZE);
+
        RETURN(retval);
 }
 
@@ -4802,6 +4830,7 @@ int ll_migrate(struct inode *parent, struct file *file, struct lmv_user_md *lum,
        __u64 data_version = 0;
        size_t namelen = strlen(name);
        int lumlen = lmv_user_md_size(lum->lum_stripe_count, lum->lum_magic);
+       bool oldformat = false;
        int rc;
        ENTRY;
 
@@ -4852,26 +4881,22 @@ int ll_migrate(struct inode *parent, struct file *file, struct lmv_user_md *lum,
        if (is_root_inode(child_inode))
                GOTO(out_iput, rc = -EINVAL);
 
-       if (IS_ENCRYPTED(child_inode)) {
-               rc = llcrypt_get_encryption_info(child_inode);
-               if (rc)
-                       GOTO(out_iput, rc);
-               if (!llcrypt_has_encryption_key(child_inode)) {
-                       CDEBUG(D_SEC, "no enc key for "DFID"\n",
-                              PFID(ll_inode2fid(child_inode)));
-                       GOTO(out_iput, rc = -ENOKEY);
-               }
-               if (unlikely(!llcrypt_policy_has_filename_enc(child_inode))) {
-                       CDEBUG(D_SEC,
-                              "cannot migrate old format encrypted "DFID", please move to new enc dir first\n",
-                              PFID(ll_inode2fid(child_inode)));
-                       GOTO(out_iput, rc = -EUCLEAN);
-               }
+       if (IS_ENCRYPTED(parent)) {
+               if (unlikely(!llcrypt_policy_has_filename_enc(parent)))
+                       oldformat = true;
+       } else if (IS_ENCRYPTED(child_inode) &&
+                  unlikely(!llcrypt_policy_has_filename_enc(child_inode))) {
+               oldformat = true;
+       }
+       if (unlikely(oldformat)) {
+               CDEBUG(D_SEC,
+                      "cannot migrate old format encrypted "DFID", please move to new enc dir first\n",
+                      PFID(ll_inode2fid(child_inode)));
+               GOTO(out_iput, rc = -EUCLEAN);
        }
 
        op_data = ll_prep_md_op_data(NULL, parent, NULL, name, namelen,
-                                    child_inode->i_mode, LUSTRE_OPC_MIGR,
-                                    NULL);
+                                    child_inode->i_mode, LUSTRE_OPC_ANY, NULL);
        if (IS_ERR(op_data))
                GOTO(out_iput, rc = PTR_ERR(op_data));
 
index 1a8ff18..97ec1d2 100644 (file)
@@ -1190,6 +1190,8 @@ void ll_kill_super(struct super_block *sb);
 struct inode *ll_inode_from_resource_lock(struct ldlm_lock *lock);
 void ll_dir_clear_lsm_md(struct inode *inode);
 void ll_clear_inode(struct inode *inode);
+int volatile_ref_file(const char *volatile_name, int volatile_len,
+                     struct file **ref_file);
 int ll_setattr_raw(struct dentry *dentry, struct iattr *attr,
                   enum op_xvalid xvalid, bool hsm_import);
 int ll_setattr(struct dentry *de, struct iattr *attr);
@@ -1718,6 +1720,7 @@ int ll_fname_disk_to_usr(struct inode *inode,
                         struct llcrypt_str *iname, struct llcrypt_str *oname,
                         struct lu_fid *fid);
 int ll_revalidate_d_crypto(struct dentry *dentry, unsigned int flags);
+int ll_file_open_encrypt(struct inode *inode, struct file *filp);
 #ifdef HAVE_LUSTRE_CRYPTO
 extern const struct llcrypt_operations lustre_cryptops;
 #endif
index a60739e..d5c3c94 100644 (file)
@@ -40,6 +40,7 @@
 #include <linux/random.h>
 #include <linux/statfs.h>
 #include <linux/time.h>
+#include <linux/file.h>
 #include <linux/types.h>
 #include <libcfs/linux/linux-uuid.h>
 #include <linux/version.h>
@@ -2025,6 +2026,44 @@ putenv:
        RETURN(rc);
 }
 
+/**
+ * Get reference file from volatile file name.
+ * Volatile file name may look like:
+ * <parent>/LUSTRE_VOLATILE_HDR:<mdt_index>:<random>:fd=<fd>
+ * where fd is opened descriptor of reference file.
+ *
+ * \param[in] volatile_name    volatile file name
+ * \param[in] volatile_len     volatile file name length
+ * \param[out] ref_file                pointer to struct file of reference file
+ *
+ * \retval 0           on success
+ * \retval negative    errno on failure
+ */
+int volatile_ref_file(const char *volatile_name, int volatile_len,
+                     struct file **ref_file)
+{
+       char *p, *q, *fd_str;
+       int fd, rc;
+
+       p = strnstr(volatile_name, ":fd=", volatile_len);
+       if (!p || strlen(p + 4) == 0)
+               return -EINVAL;
+
+       q = strchrnul(p + 4, ':');
+       fd_str = kstrndup(p + 4, q - p - 4, GFP_NOFS);
+       if (!fd_str)
+               return -ENOMEM;
+       rc = kstrtouint(fd_str, 10, &fd);
+       kfree(fd_str);
+       if (rc)
+               return -EINVAL;
+
+       *ref_file = fget(fd);
+       if (!(*ref_file))
+               return -EINVAL;
+       return 0;
+}
+
 /* If this inode has objects allocated to it (lsm != NULL), then the OST
  * object(s) determine the file size and mtime.  Otherwise, the MDS will
  * keep these values until such a time that objects are allocated for it.
@@ -2188,6 +2227,55 @@ int ll_setattr_raw(struct dentry *dentry, struct iattr *attr,
                                        if (rc)
                                                GOTO(out, rc);
                                }
+                               /* If encrypted volatile file without the key,
+                                * we need to fetch size from reference file,
+                                * and set it on OST objects. This happens when
+                                * migrating or extending an encrypted file
+                                * without the key.
+                                */
+                               if (filename_is_volatile(dentry->d_name.name,
+                                                        dentry->d_name.len,
+                                                        NULL) &&
+                                   llcrypt_require_key(inode) == -ENOKEY) {
+                                       struct file *ref_file;
+                                       struct inode *ref_inode;
+                                       struct ll_inode_info *ref_lli;
+                                       struct cl_object *ref_obj;
+                                       struct cl_attr ref_attr = { 0 };
+                                       struct lu_env *env;
+                                       __u16 refcheck;
+
+                                       rc = volatile_ref_file(
+                                               dentry->d_name.name,
+                                               dentry->d_name.len,
+                                               &ref_file);
+                                       if (rc)
+                                               GOTO(out, rc);
+
+                                       ref_inode = file_inode(ref_file);
+                                       if (!ref_inode) {
+                                               fput(ref_file);
+                                               GOTO(out, rc = -EINVAL);
+                                       }
+
+                                       env = cl_env_get(&refcheck);
+                                       if (IS_ERR(env))
+                                               GOTO(out, rc = PTR_ERR(env));
+
+                                       ref_lli = ll_i2info(ref_inode);
+                                       ref_obj = ref_lli->lli_clob;
+                                       cl_object_attr_lock(ref_obj);
+                                       rc = cl_object_attr_get(env, ref_obj,
+                                                               &ref_attr);
+                                       cl_object_attr_unlock(ref_obj);
+                                       cl_env_put(env, &refcheck);
+                                       fput(ref_file);
+                                       if (rc)
+                                               GOTO(out, rc);
+
+                                       attr->ia_valid |= ATTR_SIZE;
+                                       attr->ia_size = ref_attr.cat_size;
+                               }
                        }
                        rc = cl_setattr_ost(lli->lli_clob, attr, xvalid, flags);
                }
@@ -2246,7 +2334,7 @@ out:
                                        LPROC_LL_TRUNC : LPROC_LL_SETATTR,
                                   ktime_us_delta(ktime_get(), kstart));
 
-       return rc;
+       RETURN(rc);
 }
 
 int ll_setattr(struct dentry *de, struct iattr *attr)
@@ -2552,7 +2640,15 @@ int ll_update_inode(struct inode *inode, struct lustre_md *md)
 
        LASSERT(fid_seq(&lli->lli_fid) != 0);
 
-       lli->lli_attr_valid = body->mbo_valid;
+       /* In case of encrypted file without the key, please do not lose
+        * clear text size stored into lli_lazysize in ll_merge_attr(),
+        * we will need it in ll_prepare_close().
+        */
+       if (lli->lli_attr_valid & OBD_MD_FLLAZYSIZE && lli->lli_lazysize &&
+           llcrypt_require_key(inode) == -ENOKEY)
+               lli->lli_attr_valid = body->mbo_valid | OBD_MD_FLLAZYSIZE;
+       else
+               lli->lli_attr_valid = body->mbo_valid;
        if (body->mbo_valid & OBD_MD_FLSIZE) {
                i_size_write(inode, body->mbo_size);
 
@@ -3212,11 +3308,10 @@ struct md_op_data *ll_prep_md_op_data(struct md_op_data *op_data,
                        op_data->op_flags |= MF_OPNAME_KMALLOCED;
        }
 
-       /* In fact LUSTRE_OPC_LOOKUP, LUSTRE_OPC_OPEN, LUSTRE_OPC_MIGR
+       /* In fact LUSTRE_OPC_LOOKUP, LUSTRE_OPC_OPEN
         * are LUSTRE_OPC_ANY
         */
-       if (opc == LUSTRE_OPC_LOOKUP || opc == LUSTRE_OPC_OPEN ||
-           opc == LUSTRE_OPC_MIGR)
+       if (opc == LUSTRE_OPC_LOOKUP || opc == LUSTRE_OPC_OPEN)
                op_data->op_code = LUSTRE_OPC_ANY;
        else
                op_data->op_code = opc;
index 44d0666..6f372c7 100644 (file)
@@ -49,7 +49,7 @@
 static int ll_create_it(struct inode *dir, struct dentry *dentry,
                        struct lookup_intent *it,
                        void *secctx, __u32 secctxlen, bool encrypt,
-                       void *encctx, __u32 encctxlen);
+                       void *encctx, __u32 encctxlen, unsigned int open_flags);
 
 /* called from iget5_locked->find_inode() under inode_lock spinlock */
 static int ll_test_inode(struct inode *inode, void *opaque)
@@ -908,37 +908,20 @@ static struct dentry *ll_lookup_it(struct inode *parent, struct dentry *dentry,
                        *secctxlen = 0;
        }
        if (it->it_op & IT_CREAT && encrypt) {
-               /* Volatile file name may look like:
-                * <parent>/LUSTRE_VOLATILE_HDR:<mdt_index>:<random>:fd=<fd>
-                * where fd is opened descriptor of reference file.
-                */
                if (unlikely(filename_is_volatile(dentry->d_name.name,
                                                  dentry->d_name.len, NULL))) {
+                       /* get encryption context from reference file */
                        int ctx_size = LLCRYPT_ENC_CTX_SIZE;
                        struct lustre_sb_info *lsi;
                        struct file *ref_file;
                        struct inode *ref_inode;
-                       char *p, *q, *fd_str;
                        void *ctx;
-                       int fd;
-
-                       p = strnstr(dentry->d_name.name, ":fd=",
-                                   dentry->d_name.len);
-                       if (!p || strlen(p + 4) == 0)
-                               GOTO(out, retval = ERR_PTR(-EINVAL));
 
-                       q = strchrnul(p + 4, ':');
-                       fd_str = kstrndup(p + 4, q - p - 4, GFP_NOFS);
-                       if (!fd_str)
-                               GOTO(out, retval = ERR_PTR(-ENOMEM));
-                       rc = kstrtouint(fd_str, 10, &fd);
-                       kfree(fd_str);
+                       rc = volatile_ref_file(dentry->d_name.name,
+                                              dentry->d_name.len,
+                                              &ref_file);
                        if (rc)
-                               GOTO(inherit, rc = -EINVAL);
-
-                       ref_file = fget(fd);
-                       if (!ref_file)
-                               GOTO(inherit, rc = -EINVAL);
+                               GOTO(out, retval = ERR_PTR(rc));
 
                        ref_inode = file_inode(ref_file);
                        if (!ref_inode) {
@@ -984,7 +967,6 @@ getctx:
                                       op_data->op_file_encctx_size);
                                OBD_FREE(ctx, ctx_size);
                        }
-
                } else {
 inherit:
                        rc = llcrypt_inherit_context(parent, NULL, op_data,
@@ -1252,7 +1234,14 @@ static int ll_atomic_open(struct inode *dir, struct dentry *dentry,
                if (rc)
                        GOTO(out_release, rc);
                if (open_flags & O_CREAT) {
-                       if (!llcrypt_has_encryption_key(dir))
+                       /* For migration or mirroring without enc key, we still
+                        * need to be able to create a volatile file.
+                        */
+                       if (!llcrypt_has_encryption_key(dir) &&
+                           (!filename_is_volatile(dentry->d_name.name,
+                                                  dentry->d_name.len, NULL) ||
+                           (open_flags & O_FILE_ENC) != O_FILE_ENC ||
+                           !(open_flags & O_DIRECT)))
                                GOTO(out_release, rc = -ENOKEY);
                        encrypt = true;
                }
@@ -1283,7 +1272,8 @@ static int ll_atomic_open(struct inode *dir, struct dentry *dentry,
                if (it_disposition(it, DISP_OPEN_CREATE)) {
                        /* Dentry instantiated in ll_create_it. */
                        rc = ll_create_it(dir, dentry, it, secctx, secctxlen,
-                                         encrypt, encctx, encctxlen);
+                                         encrypt, encctx, encctxlen,
+                                         open_flags);
                        ll_security_release_secctx(secctx, secctxlen);
                        llcrypt_free_ctx(encctx, encctxlen);
                        if (rc) {
@@ -1409,7 +1399,7 @@ static struct inode *ll_create_node(struct inode *dir, struct lookup_intent *it)
 static int ll_create_it(struct inode *dir, struct dentry *dentry,
                        struct lookup_intent *it,
                        void *secctx, __u32 secctxlen, bool encrypt,
-                       void *encctx, __u32 encctxlen)
+                       void *encctx, __u32 encctxlen, unsigned int open_flags)
 {
        struct inode *inode;
        __u64 bits = 0;
@@ -1444,7 +1434,18 @@ static int ll_create_it(struct inode *dir, struct dentry *dentry,
        d_instantiate(dentry, inode);
 
        if (encrypt) {
-               rc = ll_set_encflags(inode, encctx, encctxlen, true);
+               bool preload = true;
+
+               /* For migration or mirroring without enc key, we
+                * create a volatile file without enc context.
+                */
+               if (!llcrypt_has_encryption_key(dir) &&
+                   filename_is_volatile(dentry->d_name.name,
+                                        dentry->d_name.len, NULL) &&
+                   (open_flags & O_FILE_ENC) == O_FILE_ENC &&
+                   open_flags & O_DIRECT)
+                       preload = false;
+               rc = ll_set_encflags(inode, encctx, encctxlen, preload);
                if (rc)
                        RETURN(rc);
        }
index fcac713..0d34360 100644 (file)
@@ -1441,7 +1441,8 @@ osc_brw_prep_request(int cmd, struct client_obd *cli, struct obdo *oa,
         if (req == NULL)
                 RETURN(-ENOMEM);
 
-       if (opc == OST_WRITE && inode && IS_ENCRYPTED(inode)) {
+       if (opc == OST_WRITE && inode && IS_ENCRYPTED(inode) &&
+           llcrypt_has_encryption_key(inode)) {
                for (i = 0; i < page_count; i++) {
                        struct brw_page *pg = pga[i];
                        struct page *data_page = NULL;
@@ -1452,9 +1453,7 @@ osc_brw_prep_request(int cmd, struct client_obd *cli, struct obdo *oa,
                        pgoff_t index_orig;
 
 retry_encrypt:
-                       if (nunits & ~LUSTRE_ENCRYPTION_MASK)
-                               nunits = (nunits & LUSTRE_ENCRYPTION_MASK) +
-                                       LUSTRE_ENCRYPTION_UNIT_SIZE;
+                       nunits = round_up(nunits, LUSTRE_ENCRYPTION_UNIT_SIZE);
                        /* The page can already be locked when we arrive here.
                         * This is possible when cl_page_assume/vvp_page_assume
                         * is stuck on wait_on_page_writeback with page lock
@@ -1511,14 +1510,38 @@ retry_encrypt:
                        pg->bp_off_diff = pg->off & ~PAGE_MASK;
                        pg->off = pg->off & PAGE_MASK;
                }
-       } else if (opc == OST_READ && inode && IS_ENCRYPTED(inode)) {
+       } else if (opc == OST_WRITE && inode && IS_ENCRYPTED(inode)) {
+               struct osc_async_page *oap = brw_page2oap(pga[0]);
+               struct cl_page *clpage = oap2cl_page(oap);
+               struct cl_object *clobj = clpage->cp_obj;
+               struct cl_attr attr = { 0 };
+               struct lu_env *env;
+               __u16 refcheck;
+
+               env = cl_env_get(&refcheck);
+               if (IS_ERR(env)) {
+                       rc = PTR_ERR(env);
+                       ptlrpc_request_free(req);
+                       RETURN(rc);
+               }
+
+               cl_object_attr_lock(clobj);
+               rc = cl_object_attr_get(env, clobj, &attr);
+               cl_object_attr_unlock(clobj);
+               cl_env_put(env, &refcheck);
+               if (rc != 0) {
+                       ptlrpc_request_free(req);
+                       RETURN(rc);
+               }
+               if (attr.cat_size)
+                       oa->o_size = attr.cat_size;
+       } else if (opc == OST_READ && inode && IS_ENCRYPTED(inode) &&
+                  llcrypt_has_encryption_key(inode)) {
                for (i = 0; i < page_count; i++) {
                        struct brw_page *pg = pga[i];
                        u32 nunits = (pg->off & ~PAGE_MASK) + pg->count;
 
-                       if (nunits & ~LUSTRE_ENCRYPTION_MASK)
-                               nunits = (nunits & LUSTRE_ENCRYPTION_MASK) +
-                                       LUSTRE_ENCRYPTION_UNIT_SIZE;
+                       nunits = round_up(nunits, LUSTRE_ENCRYPTION_UNIT_SIZE);
                        /* count/off are forced to cover the whole encryption
                         * unit size so that all encrypted data is stored on the
                         * OST, so adjust bp_{count,off}_diff for the size of
@@ -1544,7 +1567,8 @@ retry_encrypt:
 
        for (i = 0; i < page_count; i++) {
                short_io_size += pga[i]->count;
-               if (!inode || !IS_ENCRYPTED(inode)) {
+               if (!inode || !IS_ENCRYPTED(inode) ||
+                   !llcrypt_has_encryption_key(inode)) {
                        pga[i]->bp_count_diff = 0;
                        pga[i]->bp_off_diff = 0;
                }
index a7c3074..0f38097 100755 (executable)
@@ -2700,6 +2700,18 @@ test_35() {
 }
 run_test 35 "Check permissions when accessing changelogs"
 
+setup_dummy_key() {
+       local mode='\x00\x00\x00\x00'
+       local raw="$(printf ""\\\\x%02x"" {0..63})"
+       local size
+       local key
+
+       [[ $(lscpu) =~ Byte\ Order.*Little ]] && size='\x40\x00\x00\x00' ||
+               size='\x00\x00\x00\x40'
+       key="${mode}${raw}${size}"
+       echo -n -e "${key}" | keyctl padd logon fscrypt:4242424242424242 @s
+}
+
 setup_for_enc_tests() {
        # remount client with test_dummy_encryption option
        if is_mounted $MOUNT; then
@@ -2713,7 +2725,7 @@ setup_for_enc_tests() {
 }
 
 cleanup_for_enc_tests() {
-       rm -rf $DIR/$tdir
+       rm -rf $DIR/$tdir $*
 
        # remount client normally
        if is_mounted $MOUNT; then
@@ -2913,6 +2925,10 @@ test_40() {
        local tmpfile=$TMP/abc
        local tmpfile2=$TMP/abc2
        local seek
+       local filesz
+       #define LUSTRE_ENCRYPTION_UNIT_SIZE   (1 << 12)
+       local UNIT_SIZE=$((1 << 12))
+       local scrambledfile
 
        $LCTL get_param mdc.*.import | grep -q client_encryption ||
                skip "client encryption not supported"
@@ -3037,6 +3053,19 @@ test_40() {
        cmp -bl $tmpfile $testfile ||
                error "file $testfile is corrupted on server (5)"
 
+       filesz=$(stat --format=%s $testfile)
+       filesz=$(((filesz+UNIT_SIZE-1)/UNIT_SIZE * UNIT_SIZE))
+
+       sync ; echo 3 > /proc/sys/vm/drop_caches
+
+       # remove fscrypt key from keyring
+       keyctl revoke $(keyctl show | awk '$7 ~ "^fscrypt:" {print $1}')
+       keyctl reap
+
+       scrambledfile=$(find $DIR/$tdir/ -maxdepth 1 -mindepth 1 -type f)
+       [ $(stat --format=%s $scrambledfile) -eq $filesz ] ||
+               error "file size without key should be rounded up"
+
        rm -f $tmpfile
 }
 run_test 40 "exercise size of encrypted file"
@@ -3712,34 +3741,44 @@ test_49() {
        mkdir $dirname
 
        trace_cmd stat $dirname
-       trace_cmd touch $dirname/f1
+       trace_cmd echo a > $dirname/f1
+       sync ; sync ; echo 3 > /proc/sys/vm/drop_caches
        trace_cmd stat $dirname/f1
+       sync ; sync ; echo 3 > /proc/sys/vm/drop_caches
        trace_cmd cat $dirname/f1
        dd if=/dev/zero of=$dirname/f1 bs=1M count=10 conv=fsync
+       sync ; sync ; echo 3 > /proc/sys/vm/drop_caches
        MATCHING_STRING="get xattr 'security.c'" \
                trace_cmd $TRUNCATE $dirname/f1 10240
        trace_cmd $LFS setstripe -E -1 -S 4M $dirname/f2
+       sync ; sync ; echo 3 > /proc/sys/vm/drop_caches
        trace_cmd $LFS migrate -E -1 -S 256K $dirname/f2
 
        if [[ $MDSCOUNT -gt 1 ]]; then
                trace_cmd $LFS setdirstripe -i 1 $dirname/d2
+               sync ; sync ; echo 3 > /proc/sys/vm/drop_caches
                trace_cmd $LFS migrate -m 0 $dirname/d2
-               touch $dirname/d2/subf
+               echo b > $dirname/d2/subf
+               sync ; sync ; echo 3 > /proc/sys/vm/drop_caches
                # migrate a non-empty encrypted dir
                trace_cmd $LFS migrate -m 1 $dirname/d2
 
                $LFS setdirstripe -i 1 -c 1 $dirname/d3
                dirname=$dirname/d3/subdir
                mkdir $dirname
-
+               sync ; sync ; echo 3 > /proc/sys/vm/drop_caches
                trace_cmd stat $dirname
-               trace_cmd touch $dirname/f1
+               trace_cmd echo c > $dirname/f1
+               sync ; sync ; echo 3 > /proc/sys/vm/drop_caches
                trace_cmd stat $dirname/f1
+               sync ; sync ; echo 3 > /proc/sys/vm/drop_caches
                trace_cmd cat $dirname/f1
                dd if=/dev/zero of=$dirname/f1 bs=1M count=10 conv=fsync
+               sync ; sync ; echo 3 > /proc/sys/vm/drop_caches
                MATCHING_STRING="get xattr 'security.c'" \
                        trace_cmd $TRUNCATE $dirname/f1 10240
                trace_cmd $LFS setstripe -E -1 -S 4M $dirname/f2
+               sync ; sync ; echo 3 > /proc/sys/vm/drop_caches
                trace_cmd $LFS migrate -E -1 -S 256K $dirname/f2
        else
                skip_noexit "2nd part needs >= 2 MDTs"
@@ -3937,7 +3976,7 @@ test_52() {
 
        [[ $OSTCOUNT -lt 2 ]] && skip_env "needs >= 2 OSTs"
 
-       stack_trap cleanup_for_enc_tests EXIT
+       stack_trap "cleanup_for_enc_tests $tmpfile $mirror1 $mirror2" EXIT
        setup_for_enc_tests
 
        dd if=/dev/urandom of=$tmpfile bs=5000 count=1 conv=fsync
@@ -4036,8 +4075,6 @@ test_52() {
        cancel_lru_locks
        cmp -bl $tmpfile $testfile ||
                error "extended/split file is corrupted"
-
-       rm -f $tmpfile $mirror1 $mirror2
 }
 run_test 52 "Mirrored encrypted file"
 
@@ -4448,6 +4485,209 @@ test_58() {
 }
 run_test 58 "access to enc file's xattrs"
 
+insert_enc_key() {
+       sync ; echo 3 > /proc/sys/vm/drop_caches
+       setup_dummy_key
+}
+
+remove_env_key() {
+       cancel_lru_locks
+       sync ; echo 3 > /proc/sys/vm/drop_caches
+       keyctl revoke $(keyctl show | awk '$7 ~ "^fscrypt:" {print $1}')
+       keyctl reap
+}
+
+verify_mirror() {
+       local mirror1=$TMP/$tfile.mirror1
+       local mirror2=$TMP/$tfile.mirror2
+       local testfile=$1
+       local reffile=$2
+
+       $LFS mirror verify -vvv $testfile ||
+               error "verifying mirror failed (1)"
+       if [ $($LFS mirror verify -v $testfile 2>&1 |
+               grep -ci "only valid") -ne 0 ]; then
+               error "verifying mirror failed (2)"
+       fi
+
+       $LFS mirror read -N 1 -o $mirror1 $testfile ||
+               error "read from mirror 1 failed"
+       cmp -bl $reffile $mirror1 ||
+               error "corruption of mirror 1"
+       $LFS mirror read -N 2 -o $mirror2 $testfile ||
+               error "read from mirror 2 failed"
+       cmp -bl $reffile $mirror2 ||
+               error "corruption of mirror 2"
+}
+
+test_59a() {
+       local testfile=$DIR/$tdir/$tfile
+       local tmpfile=$TMP/$tfile
+       local mirror1=$TMP/$tfile.mirror1
+       local mirror2=$TMP/$tfile.mirror2
+       local scrambledfile
+
+       $LCTL get_param mdc.*.import | grep -q client_encryption ||
+               skip "client encryption not supported"
+
+       mount.lustre --help |& grep -q "test_dummy_encryption:" ||
+               skip "need dummy encryption support"
+
+       [[ $OSTCOUNT -lt 2 ]] && skip_env "needs >= 2 OSTs"
+
+       stack_trap "cleanup_for_enc_tests $tmpfile $mirror1 $mirror2" EXIT
+       setup_for_enc_tests
+
+       dd if=/dev/urandom of=$tmpfile bs=5000 count=1 conv=fsync
+
+       $LFS mirror create -N -i0 -N -i1 $testfile ||
+               error "could not create mirror"
+       dd if=$tmpfile of=$testfile bs=5000 count=1 conv=fsync ||
+               error "could not write to $testfile"
+       $LFS getstripe $testfile
+
+       # now, without the key
+       remove_env_key
+       scrambledfile=$(find $DIR/$tdir/ -maxdepth 1 -mindepth 1 -type f)
+       $LFS mirror resync $scrambledfile ||
+               error "could not resync mirror"
+
+       $LFS mirror verify -vvv $scrambledfile ||
+               error "mirror verify failed (1)"
+       if [ $($LFS mirror verify -v $scrambledfile 2>&1 |
+               grep -ci "only valid") -ne 0 ]; then
+               error "mirror verify failed (2)"
+       fi
+
+       $LFS mirror read -N 1 -o $mirror1 $scrambledfile &&
+               error "read from mirror should fail"
+
+       # now, with the key
+       insert_enc_key
+       verify_mirror $testfile $tmpfile
+}
+run_test 59a "mirror resync of encrypted files without key"
+
+test_59b() {
+       local testfile=$DIR/$tdir/$tfile
+       local tmpfile=$TMP/$tfile
+       local mirror1=$TMP/$tfile.mirror1
+       local mirror2=$TMP/$tfile.mirror2
+       local scrambledfile
+
+       $LCTL get_param mdc.*.import | grep -q client_encryption ||
+               skip "client encryption not supported"
+
+       mount.lustre --help |& grep -q "test_dummy_encryption:" ||
+               skip "need dummy encryption support"
+
+       [[ $OSTCOUNT -lt 2 ]] && skip_env "needs >= 2 OSTs"
+
+       stack_trap "cleanup_for_enc_tests $tmpfile $mirror1 $mirror2" EXIT
+       setup_for_enc_tests
+
+       tr '\0' '2' < /dev/zero |
+               dd of=$tmpfile bs=1 count=9000 conv=fsync
+
+       $LFS setstripe -c1 -i0 $testfile
+       dd if=$tmpfile of=$testfile bs=9000 count=1 conv=fsync ||
+               error "write to $testfile failed"
+       $LFS getstripe $testfile
+
+       # now, without the key
+       remove_env_key
+       scrambledfile=$(find $DIR/$tdir/ -maxdepth 1 -mindepth 1 -type f)
+       $LFS migrate -i1 $scrambledfile ||
+               error "migrate $scrambledfile failed"
+       $LFS getstripe $scrambledfile
+       stripe=$($LFS getstripe -i $scrambledfile)
+       [ $stripe -eq 1 ] || error "migrate file $scrambledfile failed"
+       cancel_lru_locks
+
+       # now, with the key
+       insert_enc_key
+       cmp -bl $tmpfile $testfile ||
+               error "migrated file is corrupted"
+
+       # now, without the key
+       remove_env_key
+       $LFS mirror extend -N -i0 $scrambledfile ||
+               error "mirror extend $scrambledfile failed (1)"
+       $LFS getstripe $scrambledfile
+       mirror_count=$($LFS getstripe -N $scrambledfile)
+       [ $mirror_count -eq 2 ] ||
+               error "mirror extend file $scrambledfile failed (2)"
+       stripe=$($LFS getstripe --mirror-id=1 -i $scrambledfile)
+       [ $stripe -eq 1 ] ||
+               error "mirror extend file $scrambledfile failed (3)"
+       stripe=$($LFS getstripe --mirror-id=2 -i $scrambledfile)
+       [ $stripe -eq 0 ] ||
+               error "mirror extend file $scrambledfile failed (4)"
+
+       $LFS mirror verify -vvv $scrambledfile ||
+               error "mirror verify failed (1)"
+       if [ $($LFS mirror verify -v $scrambledfile 2>&1 |
+               grep -ci "only valid") -ne 0 ]; then
+               error "mirror verify failed (2)"
+       fi
+
+       # now, with the key
+       insert_enc_key
+       verify_mirror $testfile $tmpfile
+
+       # now, without the key
+       remove_env_key
+       $LFS mirror split --mirror-id 1 -d $scrambledfile ||
+               error "mirror split file $scrambledfile failed (1)"
+       $LFS getstripe $scrambledfile
+       mirror_count=$($LFS getstripe -N $scrambledfile)
+       [ $mirror_count -eq 1 ] ||
+               error "mirror split file $scrambledfile failed (2)"
+       stripe=$($LFS getstripe --mirror-id=1 -i $scrambledfile)
+       [ -z "$stripe" ] || error "mirror split file $scrambledfile failed (3)"
+       stripe=$($LFS getstripe --mirror-id=2 -i $scrambledfile)
+       [ $stripe -eq 0 ] || error "mirror split file $scrambledfile failed (4)"
+
+       # now, with the key
+       insert_enc_key
+       cancel_lru_locks
+       cmp -bl $tmpfile $testfile ||
+               error "extended/split file is corrupted"
+}
+run_test 59b "migrate/extend/split of encrypted files without key"
+
+test_59c() {
+       local dirname=$DIR/$tdir/subdir
+       local scrambleddir
+
+       $LCTL get_param mdc.*.import | grep -q client_encryption ||
+               skip "client encryption not supported"
+
+       mount.lustre --help |& grep -q "test_dummy_encryption:" ||
+               skip "need dummy encryption support"
+
+       [[ $MDSCOUNT -ge 2 ]] || skip_env "needs >= 2 MDTs"
+
+       stack_trap "cleanup_for_enc_tests" EXIT
+       setup_for_enc_tests
+
+       $LFS setdirstripe -i 0 $dirname
+       echo b > $dirname/subf
+
+       # now, without the key
+       remove_env_key
+       scrambleddir=$(find $DIR/$tdir/ -maxdepth 1 -mindepth 1 -type d)
+
+       # migrate a non-empty encrypted dir
+       $LFS migrate -m 1 $scrambleddir ||
+               error "migrate $scrambleddir between MDTs failed (1)"
+
+       stripe=$($LFS getdirstripe -i $scrambleddir)
+       [ $stripe -eq 1 ] ||
+               error "migrate $scrambleddir between MDTs failed (2)"
+}
+run_test 59c "MDT migrate of encrypted files without key"
+
 log "cleanup: ======================================================"
 
 sec_unsetup() {
index 213dc09..fb630fa 100644 (file)
@@ -624,12 +624,10 @@ static uint32_t check_foreign_type_name(const char *foreign_type_name)
 
 static const char *error_loc = "syserror";
 
-enum {
-       MIGRATION_NONBLOCK      = 0x0001,
-       MIGRATION_MIRROR        = 0x0002,
-       MIGRATION_NONDIRECT     = 0x0004,
-       MIGRATION_VERBOSE       = 0x0008,
-};
+#define MIGRATION_NONBLOCK     LLAPI_MIGRATION_NONBLOCK
+#define MIGRATION_MIRROR       LLAPI_MIGRATION_MIRROR
+#define MIGRATION_NONDIRECT    LLAPI_MIGRATION_NONDIRECT
+#define MIGRATION_VERBOSE      LLAPI_MIGRATION_VERBOSE
 
 static int
 migrate_open_files(const char *name, __u64 migration_flags,
@@ -672,15 +670,24 @@ migrate_open_files(const char *name, __u64 migration_flags,
                *ptr = '\0';
        }
 
-       /* open file, direct io */
        /* even if the file is only read, WR mode is nedeed to allow
         * layout swap on fd
         */
-       rflags = O_RDWR | O_NOATIME;
+       /* Allow migrating even without the key on encrypted files */
+       rflags = O_RDWR | O_NOATIME | O_FILE_ENC;
        if (!(migration_flags & MIGRATION_NONDIRECT))
                rflags |= O_DIRECT;
+source_open:
        fd = open(name, rflags);
        if (fd < 0) {
+               /* If encrypted file without the key,
+                * retry mirror extend in O_DIRECT.
+                */
+               if (errno == ENOKEY && !(rflags & O_DIRECT) &&
+                   migration_flags & MIGRATION_MIRROR) {
+                       rflags |= O_DIRECT;
+                       goto source_open;
+               }
                rc = -errno;
                error_loc = "cannot open source file";
                return rc;
@@ -693,9 +700,13 @@ migrate_open_files(const char *name, __u64 migration_flags,
        }
 
        do {
-               int open_flags = O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW;
+               int open_flags = O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW |
+                       /* Allow migrating without the key on encrypted files */
+                       O_FILE_ENC;
                mode_t open_mode = S_IRUSR | S_IWUSR;
 
+               if (rflags & O_DIRECT)
+                       open_flags |= O_DIRECT;
                random_value = random();
                rc = snprintf(volatile_file, sizeof(volatile_file),
                              "%s/%s:%.4X:%.4X:fd=%.2d", parent,
@@ -1831,8 +1842,8 @@ static int mirror_extend_layout(char *name, struct llapi_layout *m_layout,
                }
        }
        llapi_layout_comp_flags_set(m_layout, flags);
-       rc = migrate_open_files(name, MIGRATION_NONDIRECT, NULL, m_layout, &fd,
-                               &fdv);
+       rc = migrate_open_files(name, MIGRATION_NONDIRECT | MIGRATION_MIRROR,
+                               NULL, m_layout, &fd, &fdv);
        if (rc < 0)
                goto out;
 
@@ -2153,7 +2164,15 @@ static int mirror_split(const char *fname, __u32 id, const char *pool,
                }
        }
 
-       fd = open(fname, O_RDWR);
+       if (!victim_file && mflags & MF_DESTROY)
+               /* Allow mirror split even without the key on encrypted files,
+                * and in this case of a 'split -d', open file with O_DIRECT
+                * (no IOs will be done).
+                */
+               fd = open(fname, O_RDWR | O_DIRECT | O_FILE_ENC);
+       else
+               fd = open(fname, O_RDWR);
+
        if (fd < 0) {
                fprintf(stderr,
                        "error %s: open file '%s' failed: %s\n",
@@ -2237,7 +2256,11 @@ again:
 
                                        open_flags = O_RDWR |
                                             (O_LOV_DELAY_CREATE & ~O_ACCMODE) |
-                                            O_CREAT | O_EXCL | O_NOFOLLOW;
+                                            O_CREAT | O_EXCL | O_NOFOLLOW |
+                                            /* O_DIRECT for mirror split -d */
+                                            O_DIRECT |
+                                            /* Allow split without the key */
+                                            O_FILE_ENC;
                                        fdv = open(file_path, open_flags,
                                                   S_IRUSR | S_IWUSR);
                                        if (fdv < 0)
@@ -10582,7 +10605,8 @@ int lfs_mirror_resync_file(const char *fname, struct ll_ioc_lease *ioc,
                goto error;
        }
 
-       fd = open(fname, O_DIRECT | O_RDWR);
+       /* Allow mirror resync even without the key on encrypted files */
+       fd = open(fname, O_DIRECT | O_RDWR | O_FILE_ENC);
        if (fd < 0) {
                fprintf(stderr, "%s: cannot open '%s': %s.\n",
                        progname, fname, strerror(errno));
@@ -11880,7 +11904,8 @@ int lfs_mirror_verify_file(const char *fname, __u16 *mirror_ids, int ids_nr,
                goto error;
        }
 
-       fd = open(fname, O_DIRECT | O_RDONLY);
+       /* Allow mirror verify even without the key on encrypted files */
+       fd = open(fname, O_DIRECT | O_RDONLY | O_FILE_ENC);
        if (fd < 0) {
                fprintf(stderr, "%s: cannot open '%s': %s.\n",
                        progname, fname, strerror(errno));
index f107d27..c90972b 100644 (file)
@@ -1069,15 +1069,27 @@ struct llapi_layout *llapi_layout_get_by_path(const char *path,
                                              enum llapi_layout_get_flags flags)
 {
        struct llapi_layout *layout = NULL;
+       bool failed = false;
+       int open_flags;
        int fd;
        int tmp;
 
        if (flags & LLAPI_LAYOUT_GET_EXPECTED)
                return llapi_layout_expected(path);
 
-       fd = open(path, O_RDONLY);
-       if (fd < 0)
-               return layout;
+       /* Always get layout in O_DIRECT */
+       /* Allow fetching layout even without the key on encrypted files */
+       open_flags = O_RDONLY | O_DIRECT | O_FILE_ENC;
+do_open:
+       fd = open(path, open_flags);
+       if (fd < 0) {
+               if (errno != EINVAL || failed)
+                       return layout;
+               /* EINVAL is because a directory cannot be opened in O_DIRECT */
+               open_flags = O_RDONLY | O_FILE_ENC;
+               failed = true;
+               goto do_open;
+       }
 
        layout = llapi_layout_get_by_fd(fd, flags);
        tmp = errno;
@@ -3110,7 +3122,11 @@ do_read:
                if (comp_array[i].lrc_synced && pos & (page_size - 1)) {
                        rc = llapi_mirror_truncate(fd,
                                        comp_array[i].lrc_mirror_id, pos);
-                       if (rc < 0)
+                       /* Ignore truncate error on encrypted file without the
+                        * key if tried on LUSTRE_ENCRYPTION_UNIT_SIZE boundary.
+                        */
+                       if (rc < 0 && (rc != -ENOKEY ||
+                                      pos & ~LUSTRE_ENCRYPTION_MASK))
                                comp_array[i].lrc_synced = false;
                }
        }
index 522b8c3..3d291dc 100644 (file)
 #define WANT_INDEX  0x8
 #define WANT_ERROR  0x10
 
+/* Define a fixed 4096-byte encryption unit size */
+#define LUSTRE_ENCRYPTION_BLOCKBITS   12
+#define LUSTRE_ENCRYPTION_UNIT_SIZE   ((size_t)1 << LUSTRE_ENCRYPTION_BLOCKBITS)
+#define LUSTRE_ENCRYPTION_MASK        (~(LUSTRE_ENCRYPTION_UNIT_SIZE - 1))
+
 /* mount point listings in /proc/mounts */
 #ifndef PROC_MOUNTS
 #define PROC_MOUNTS "/proc/mounts"