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.
Signed-off-by: Sebastien Buisson <sbuisson@ddn.com>
Change-Id: I3878b5e9e6d3738dfee0ce0f89a3646e6a7b976f
Reviewed-on: https://review.whamcloud.com/43878
Reviewed-by: Andreas Dilger <adilger@whamcloud.com>
Reviewed-by: Bobi Jam <bobijam@hotmail.com>
Tested-by: jenkins <devops@whamcloud.com>
Tested-by: Maloo <maloo@whamcloud.com>
Reviewed-by: Oleg Drokin <green@whamcloud.com>
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,
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:
* 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
* 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 =
#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>
*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)
$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"
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;
int mdt_index;
int fd, fdv;
bool purge = true; /* delete mirror by setting fdv=fd */
+ bool is_encrypted;
int rc;
if (victim_file && (strcmp(fname, victim_file) == 0)) {
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;
+
again:
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,
* try the old way to delete mirror using
* volatile file.
*/
- 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);
}
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)