Whamcloud - gitweb
LU-14677 sec: migrate/extend/split on encrypted file
authorSebastien Buisson <sbuisson@ddn.com>
Fri, 28 May 2021 16:11:53 +0000 (18:11 +0200)
committerAndreas Dilger <adilger@whamcloud.com>
Fri, 10 Sep 2021 21:28:33 +0000 (21:28 +0000)
lfs migrate/extend/split makes use of volatile files to swap layouts.
When operation is carried out on an encrypted file, the volatile file
must be assigned the same encryption context as the original file, so
that data moved/copied to different OSTs is identical to the original
file's.
Also update sanity-sec test_52 to exercise these commands.

Lustre-change: https://review.whamcloud.com/43878
Lustre-commit: 09c558d16f0a80f436522edde89367c088fe2055

Change-Id: I3878b5e9e6d3738dfee0ce0f89a3646e6a7b976f
Signed-off-by: Sebastien Buisson <sbuisson@ddn.com>
Reviewed-on: https://review.whamcloud.com/43879
Tested-by: jenkins <devops@whamcloud.com>
Tested-by: Maloo <maloo@whamcloud.com>
Reviewed-by: Andreas Dilger <adilger@whamcloud.com>
lustre/include/lustre/lustreapi.h
lustre/include/lustre_crypto.h
lustre/llite/llite_lib.c
lustre/llite/namei.c
lustre/tests/sanity-sec.sh
lustre/utils/lfs.c
lustre/utils/liblustreapi.c

index dcf7967..c79e48b 100644 (file)
@@ -143,6 +143,7 @@ __u32 llapi_pattern_to_lov(uint64_t pattern);
 
 int llapi_file_open_param(const char *name, int flags, mode_t mode,
                          const struct llapi_stripe_param *param);
+int llapi_file_is_encrypted(int fd);
 int llapi_file_create_foreign(const char *name, mode_t mode, __u32 type,
                              __u32 flags, char *foreign_lov);
 int llapi_file_create(const char *name, unsigned long long stripe_size,
index f71ddf8..9f76f87 100644 (file)
@@ -36,6 +36,9 @@ void llcrypt_free_ctx(void *encctx, __u32 size);
 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);
+/* sizeof(struct fscrypt_context_v2) = 40 */
+#define LLCRYPT_ENC_CTX_SIZE 40
+
 
 /* Encoding/decoding routines inspired from yEnc principles.
  * We just take care of a few critical characters:
index 2a83264..e588851 100644 (file)
@@ -2054,8 +2054,7 @@ int ll_setattr_raw(struct dentry *dentry, struct iattr *attr,
                         * it is necessary due to possible time
                         * de-synchronization between MDT inode and OST objects
                         */
-                       if (S_ISREG(inode->i_mode) && IS_ENCRYPTED(inode) &&
-                           attr->ia_valid & ATTR_SIZE) {
+                       if (S_ISREG(inode->i_mode) && IS_ENCRYPTED(inode)) {
                                xvalid |= OP_XVALID_FLAGS;
                                flags = LUSTRE_ENCRYPT_FL;
                                /* Call to ll_io_zero_page is not necessary if
@@ -2064,7 +2063,8 @@ int ll_setattr_raw(struct dentry *dentry, struct iattr *attr,
                                 * In case of Direct IO, all we need is to set
                                 * new size.
                                 */
-                               if (attr->ia_size & ~PAGE_MASK &&
+                               if (attr->ia_valid & ATTR_SIZE &&
+                                   attr->ia_size & ~PAGE_MASK &&
                                    !(attr->ia_valid & ATTR_FILE &&
                                      attr->ia_file->f_flags & O_DIRECT)) {
                                        pgoff_t offset =
index 57e5210..460e02d 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/fs.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
+#include <linux/file.h>
 #include <linux/quotaops.h>
 #include <linux/highmem.h>
 #include <linux/pagemap.h>
@@ -863,9 +864,90 @@ static struct dentry *ll_lookup_it(struct inode *parent, struct dentry *dentry,
                        *secctxlen = 0;
        }
        if (it->it_op & IT_CREAT && encrypt) {
-               rc = llcrypt_inherit_context(parent, NULL, op_data, false);
-               if (rc)
-                       GOTO(out, retval = ERR_PTR(rc));
+               /* 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))) {
+                       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);
+                       if (rc)
+                               GOTO(inherit, rc = -EINVAL);
+
+                       ref_file = fget(fd);
+                       if (!ref_file)
+                               GOTO(inherit, rc = -EINVAL);
+
+                       ref_inode = file_inode(ref_file);
+                       if (!ref_inode) {
+                               fput(ref_file);
+                               GOTO(inherit, rc = -EINVAL);
+                       }
+
+                       lsi = s2lsi(ref_inode->i_sb);
+
+getctx:
+                       OBD_ALLOC(ctx, ctx_size);
+                       if (!ctx)
+                               GOTO(out, retval = ERR_PTR(-ENOMEM));
+
+#ifdef CONFIG_LL_ENCRYPTION
+                       rc = lsi->lsi_cop->get_context(ref_inode,
+                                                      ctx, ctx_size);
+#else
+                       rc = -ENODATA;
+#endif
+                       if (rc == -ERANGE) {
+                               OBD_FREE(ctx, ctx_size);
+                               ctx_size *= 2;
+                               goto getctx;
+                       }
+                       fput(ref_file);
+                       if (rc < 0) {
+                               OBD_FREE(ctx, ctx_size);
+                               GOTO(inherit, rc);
+                       }
+
+                       op_data->op_file_encctx_size = rc;
+                       if (rc == ctx_size) {
+                               op_data->op_file_encctx = ctx;
+                       } else {
+                               OBD_ALLOC(op_data->op_file_encctx,
+                                         op_data->op_file_encctx_size);
+                               if (!op_data->op_file_encctx) {
+                                       OBD_FREE(ctx, ctx_size);
+                                       GOTO(out, retval = ERR_PTR(-ENOMEM));
+                               }
+                               memcpy(op_data->op_file_encctx, ctx,
+                                      op_data->op_file_encctx_size);
+                               OBD_FREE(ctx, ctx_size);
+                       }
+
+               } else {
+inherit:
+                       rc = llcrypt_inherit_context(parent, NULL, op_data,
+                                                    false);
+                       if (rc)
+                               GOTO(out, retval = ERR_PTR(rc));
+               }
                if (encctx != NULL)
                        *encctx = op_data->op_file_encctx;
                if (encctxlen != NULL)
index 192db38..5795a2f 100755 (executable)
@@ -3786,6 +3786,68 @@ test_52() {
        $LFS mirror verify -v $testfile &&
                error "mirrors should be different"
 
+       rm -f $testfile $mirror1 $mirror2
+
+       $LFS setstripe -c1 -i0 $testfile
+       dd if=$tmpfile of=$testfile bs=9000 count=1 conv=fsync ||
+               error "write to $testfile failed"
+       $LFS getstripe $testfile
+       cancel_lru_locks
+
+       $LFS migrate -i1 $testfile ||
+               error "migrate $testfile failed"
+       $LFS getstripe $testfile
+       stripe=$($LFS getstripe -i $testfile)
+       [ $stripe -eq 1 ] || error "migrate file $testfile failed"
+
+       cancel_lru_locks
+       cmp -bl $tmpfile $testfile ||
+               error "migrated file is corrupted"
+
+       $LFS mirror extend -N -i0 $testfile ||
+               error "mirror extend $testfile failed"
+       $LFS getstripe $testfile
+       mirror_count=$($LFS getstripe -N $testfile)
+       [ $mirror_count -eq 2 ] ||
+               error "mirror extend file $testfile failed (1)"
+       stripe=$($LFS getstripe --mirror-id=1 -i $testfile)
+       [ $stripe -eq 1 ] || error "mirror extend file $testfile failed (2)"
+       stripe=$($LFS getstripe --mirror-id=2 -i $testfile)
+       [ $stripe -eq 0 ] || error "mirror extend file $testfile failed (3)"
+
+       cancel_lru_locks
+       $LFS mirror verify -v $testfile ||
+               error "mirror verify failed"
+       $LFS mirror read -N 1 -o $mirror1 $testfile ||
+               error "read from mirror 1 failed"
+       cmp -bl $tmpfile $mirror1 ||
+               error "corruption of mirror 1"
+       $LFS mirror read -N 2 -o $mirror2 $testfile ||
+               error "read from mirror 2 failed"
+       cmp -bl $tmpfile $mirror2 ||
+               error "corruption of mirror 2"
+
+       $LFS mirror split --mirror-id 1 -f ${testfile}.mirror $testfile &&
+               error "mirror split -f should fail"
+
+       $LFS mirror split --mirror-id 1 $testfile &&
+               error "mirror split without -d should fail"
+
+       $LFS mirror split --mirror-id 1 -d $testfile ||
+               error "mirror split failed"
+       $LFS getstripe $testfile
+       mirror_count=$($LFS getstripe -N $testfile)
+       [ $mirror_count -eq 1 ] ||
+               error "mirror split file $testfile failed (1)"
+       stripe=$($LFS getstripe --mirror-id=1 -i $testfile)
+       [ -z "$stripe" ] || error "mirror extend file $testfile failed (2)"
+       stripe=$($LFS getstripe --mirror-id=2 -i $testfile)
+       [ $stripe -eq 0 ] || error "mirror extend file $testfile failed (3)"
+
+       cancel_lru_locks
+       cmp -bl $tmpfile $testfile ||
+               error "extended/split file is corrupted"
+
        rm -f $tmpfile $mirror1 $mirror2
 }
 run_test 52 "Mirrored encrypted file"
index 8bbebd5..78e776f 100644 (file)
@@ -844,8 +844,9 @@ migrate_open_files(const char *name, __u64 migration_flags,
 
                random_value = random();
                rc = snprintf(volatile_file, sizeof(volatile_file),
-                             "%s/%s:%.4X:%.4X", parent, LUSTRE_VOLATILE_HDR,
-                             mdt_index, random_value);
+                             "%s/%s:%.4X:%.4X:fd=%.2d", parent,
+                             LUSTRE_VOLATILE_HDR, mdt_index,
+                             random_value, fd);
                if (rc >= sizeof(volatile_file)) {
                        rc = -ENAMETOOLONG;
                        break;
@@ -2132,6 +2133,7 @@ static int mirror_split(const char *fname, __u32 id, const char *pool,
        __u32 mirror_id;
        int mdt_index;
        int fd, fdv;
+       bool is_encrypted;
        int rc;
 
        /* check fname contains mirror with mirror_id/comp_id */
@@ -2236,9 +2238,21 @@ static int mirror_split(const char *fname, __u32 id, const char *pool,
                goto close_fd;
        }
 
+       rc = llapi_file_is_encrypted(fd);
+       if (rc < 0) {
+               fprintf(stderr, "%s: cannot get flags of '%s': %d\n",
+                       progname, fname, rc);
+               goto close_fd;
+       }
+       is_encrypted = rc;
+
        if (!victim_file) {
                /* use a temp file to store the splitted layout */
                if (mflags & MF_DESTROY) {
+                       char file_path[PATH_MAX];
+                       unsigned int rnumber;
+                       int open_flags;
+
                        if (last_non_stale_mirror(mirror_id, layout)) {
                                rc = -EUCLEAN;
                                fprintf(stderr,
@@ -2247,15 +2261,46 @@ static int mirror_split(const char *fname, __u32 id, const char *pool,
                                goto close_fd;
                        }
 
-                       fdv = llapi_create_volatile_idx(parent, mdt_index,
-                                                       O_LOV_DELAY_CREATE);
+                       do {
+                               rnumber = random();
+                               rc = snprintf(file_path, sizeof(file_path),
+                                             "%s/" LUSTRE_VOLATILE_HDR ":%.4X:%.4X:fd=%.2d",
+                                             parent, mdt_index, rnumber, fd);
+                               if (rc < 0 || rc >= sizeof(file_path)) {
+                                       fdv = -ENAMETOOLONG;
+                                       break;
+                               }
+
+                               open_flags = O_RDWR |
+                                       (O_LOV_DELAY_CREATE & ~O_ACCMODE) |
+                                       O_CREAT | O_EXCL | O_NOFOLLOW;
+                               fdv = open(file_path, open_flags,
+                                          S_IRUSR | S_IWUSR);
+                               if (fdv < 0)
+                                       rc = -errno;
+                       } while (fdv < 0 && rc == -EEXIST);
                } else {
+                       if (is_encrypted) {
+                               rc = -1;
+                               fprintf(stderr,
+                                       "error %s: not permitted on encrypted file '%s': %d\n",
+                                       progname, fname, rc);
+                               goto close_fd;
+                       }
+
                        snprintf(victim, sizeof(victim), "%s.mirror~%u",
                                 fname, mirror_id);
                        fdv = open(victim, flags, S_IRUSR | S_IWUSR);
                }
        } else {
                /* user specified victim file */
+               if (is_encrypted) {
+                       rc = -1;
+                       fprintf(stderr,
+                               "error %s: not permitted on encrypted file '%s': %d\n",
+                               progname, fname, rc);
+                       goto close_fd;
+               }
                fdv = open(victim_file, flags, S_IRUSR | S_IWUSR);
        }
 
index ddcf22b..62d81e4 100644 (file)
@@ -746,6 +746,18 @@ retry_open:
        return fd;
 }
 
+int llapi_file_is_encrypted(int fd)
+{
+       unsigned long flags;
+       int rc;
+
+       rc = ioctl(fd, FS_IOC_GETFLAGS, &flags);
+       if (rc == -1)
+               return -errno;
+
+       return !!(flags & LUSTRE_ENCRYPT_FL);
+}
+
 int llapi_file_open_pool(const char *name, int flags, int mode,
                         unsigned long long stripe_size, int stripe_offset,
                         int stripe_count, int stripe_pattern, char *pool_name)