Whamcloud - gitweb
LU-16091 enc: S_ENCRYPTED flag on OST objects for enc files 98/48198/12
authorSebastien Buisson <sbuisson@ddn.com>
Thu, 11 Aug 2022 15:08:11 +0000 (17:08 +0200)
committerOleg Drokin <green@whamcloud.com>
Fri, 13 Jan 2023 07:19:40 +0000 (07:19 +0000)
Add a dumb encryption context on OST objects being created, when the
LUSTRE_ENCRYPT_FL flag gets set in the LMA, for ldiskfs backend
targets. This leads ldiskfs to internally set the LDISKFS_ENCRYPT_FL
flag on the on-disk inode. Also, it makes e2fsprogs happy to see an
enc ctx for an inode that has the LDISKFS_ENCRYPT_FL flag.

Add a dumb encryption context on OST objects being opened, if there is
not already one, for ldiskfs backend targets. This is done by adding
the LUSTRE_ENCRYPT_FL flag if necessary, at the same time as atime
gets updated. It is some sort of live self-check that fixes OST
objects created with an older Lustre version.

Enhance lfsck to detect and fix OST objects belonging to encrypted
files that are missing the encryption flag. This is implemented in the
MDT-OST consistency routine, as part of the layout checking.

Also add sanity-sec test_62 and sanity-lfsck test_42 to exercise this.

Note this patch does not add any dumb encryption context on OST
objects when the backend is ZFS.

Test-Parameters: testlist=sanity-sec mdscount=2 mdtcount=4 osscount=1 ostcount=8 clientcount=2 fstype=zfs
Test-Parameters: testlist=sanity-sec mdscount=2 mdtcount=4 osscount=1 ostcount=8 clientcount=2 fstype=zfs
Test-Parameters: testlist=sanity-sec mdscount=2 mdtcount=4 osscount=1 ostcount=8 clientcount=2 fstype=zfs
Test-Parameters: testlist=sanity-sec mdscount=2 mdtcount=4 osscount=1 ostcount=8 clientcount=2 fstype=zfs
Signed-off-by: Sebastien Buisson <sbuisson@ddn.com>
Change-Id: I6bee3c82ee4d1a52275facf9e2b0d60061e0beef
Reviewed-on: https://review.whamcloud.com/c/fs/lustre-release/+/48198
Tested-by: jenkins <devops@whamcloud.com>
Tested-by: Maloo <maloo@whamcloud.com>
Reviewed-by: Andreas Dilger <adilger@whamcloud.com>
Reviewed-by: Lai Siyao <lai.siyao@whamcloud.com>
Reviewed-by: Oleg Drokin <green@whamcloud.com>
17 files changed:
ldiskfs/kernel_patches/patches/linux-5.4/ext4-enc-flag.patch
ldiskfs/kernel_patches/patches/linux-5.8/ext4-enc-flag.patch
ldiskfs/kernel_patches/patches/rhel7.9/ext4-enc-flag.patch
ldiskfs/kernel_patches/patches/rhel8.4/ext4-enc-flag.patch
ldiskfs/kernel_patches/patches/rhel8.5/ext4-enc-flag.patch
ldiskfs/kernel_patches/patches/rhel8/ext4-enc-flag.patch
lustre/include/obd_support.h
lustre/lfsck/lfsck_layout.c
lustre/llite/file.c
lustre/llite/llite_lib.c
lustre/ofd/ofd_io.c
lustre/osc/osc_request.c
lustre/osd-ldiskfs/osd_handler.c
lustre/osd-zfs/osd_object.c
lustre/osp/osp_object.c
lustre/tests/sanity-lfsck.sh
lustre/tests/sanity-sec.sh

index 7cf59c9..11f0db6 100644 (file)
@@ -47,13 +47,15 @@ diff -wur a/fs/ext4/xattr.c b/fs/ext4/xattr.c
  
  static int
  ext4_xattr_list_entries(struct dentry *dentry, struct ext4_xattr_entry *entry,
-@@ -2413,12 +2415,17 @@
+@@ -2413,12 +2415,19 @@
                        ext4_handle_sync(handle);
        }
  
 +      if (!error && name_index == EXT4_XATTR_INDEX_ENCRYPTION &&
-+          strcmp(name, "c") == 0)
++          strcmp(name, "c") == 0) {
 +              EXT4_I(inode)->i_flags |= EXT4_ENCRYPT_FL;
++              mark_inode_dirty(inode);
++      }
 +
  cleanup:
        brelse(is.iloc.bh);
index 966120a..4d2ac0a 100644 (file)
@@ -47,13 +47,15 @@ diff -wur a/fs/ext4/xattr.c b/fs/ext4/xattr.c
  
  static int
  ext4_xattr_list_entries(struct dentry *dentry, struct ext4_xattr_entry *entry,
-@@ -2425,12 +2425,17 @@
+@@ -2425,12 +2425,19 @@
                        ext4_handle_sync(handle);
        }
  
 +      if (!error && name_index == EXT4_XATTR_INDEX_ENCRYPTION &&
-+          strcmp(name, "c") == 0)
++          strcmp(name, "c") == 0) {
 +              EXT4_I(inode)->i_flags |= EXT4_ENCRYPT_FL;
++              mark_inode_dirty(inode);
++      }
 +
  cleanup:
        brelse(is.iloc.bh);
index d24ef32..02e10cd 100644 (file)
@@ -22,13 +22,15 @@ diff -wur a/fs/ext4/xattr.c b/fs/ext4/xattr.c
  
  static int
  ext4_xattr_list_entries(struct dentry *dentry, struct ext4_xattr_entry *entry,
-@@ -1197,14 +1197,19 @@
+@@ -1197,14 +1197,21 @@
                        ext4_handle_sync(handle);
        }
  
 +      if (!error && name_index == EXT4_XATTR_INDEX_ENCRYPTION &&
-+          strcmp(name, "c") == 0)
++          strcmp(name, "c") == 0) {
 +              EXT4_I(inode)->i_flags |= EXT4_ENCRYPT_FL;
++              mark_inode_dirty(inode);
++      }
 +
  cleanup:
        brelse(is.iloc.bh);
index a6abcab..63eb82d 100644 (file)
@@ -47,13 +47,15 @@ diff -wur a/fs/ext4/xattr.c b/fs/ext4/xattr.c
  
  static int
  ext4_xattr_list_entries(struct dentry *dentry, struct ext4_xattr_entry *entry,
-@@ -2413,13 +2415,18 @@
+@@ -2413,13 +2415,20 @@
                        ext4_handle_sync(handle);
        }
  
 +      if (!error && name_index == EXT4_XATTR_INDEX_ENCRYPTION &&
-+          strcmp(name, "c") == 0)
++          strcmp(name, "c") == 0) {
 +              EXT4_I(inode)->i_flags |= EXT4_ENCRYPT_FL;
++              mark_inode_dirty(inode);
++      }
 +
  cleanup:
        brelse(is.iloc.bh);
index 2d9d130..e0f547d 100644 (file)
@@ -47,13 +47,15 @@ diff -wur a/fs/ext4/xattr.c b/fs/ext4/xattr.c
  
  static int
  ext4_xattr_list_entries(struct dentry *dentry, struct ext4_xattr_entry *entry,
-@@ -2413,12 +2413,17 @@ retry_inode:
+@@ -2413,12 +2413,19 @@ retry_inode:
                        ext4_handle_sync(handle);
        }
  
 +      if (!error && name_index == EXT4_XATTR_INDEX_ENCRYPTION &&
-+          strcmp(name, "c") == 0)
++          strcmp(name, "c") == 0) {
 +              EXT4_I(inode)->i_flags |= EXT4_ENCRYPT_FL;
++              mark_inode_dirty(inode);
++      }
 +
  cleanup:
        brelse(is.iloc.bh);
index e7f8693..275e5c7 100644 (file)
@@ -47,13 +47,15 @@ diff -wur a/fs/ext4/xattr.c b/fs/ext4/xattr.c
  
  static int
  ext4_xattr_list_entries(struct dentry *dentry, struct ext4_xattr_entry *entry,
-@@ -2413,13 +2415,18 @@
+@@ -2413,13 +2415,20 @@
                        ext4_handle_sync(handle);
        }
  
 +      if (!error && name_index == EXT4_XATTR_INDEX_ENCRYPTION &&
-+          strcmp(name, "c") == 0)
++          strcmp(name, "c") == 0) {
 +              EXT4_I(inode)->i_flags |= EXT4_ENCRYPT_FL;
++              mark_inode_dirty(inode);
++      }
 +
  cleanup:
        brelse(is.iloc.bh);
index 3ef800b..8291909 100644 (file)
@@ -671,6 +671,7 @@ extern char obd_jobid_var[];
 #define OBD_FAIL_LFSCK_BAD_PFL_RANGE   0x162f
 #define OBD_FAIL_LFSCK_NO_AGENTOBJ     0x1630
 #define OBD_FAIL_LFSCK_NO_AGENTENT     0x1631
+#define OBD_FAIL_LFSCK_NO_ENCFLAG      0x1632
 
 #define OBD_FAIL_LFSCK_NOTIFY_NET      0x16f0
 #define OBD_FAIL_LFSCK_QUERY_NET       0x16f1
index 70d5452..4c039b2 100644 (file)
@@ -4344,6 +4344,65 @@ out:
        return rc;
 }
 
+/*
+ * If the MDT-object has the LUSTRE_ENCRYPT_FL flag, it needs to be set
+ * on the OST-object as well.
+ */
+static int lfsck_layout_repair_encflag(const struct lu_env *env,
+                                      struct lfsck_component *com,
+                                      struct dt_object *parent,
+                                      struct lfsck_layout_req *llr)
+{
+       struct lfsck_thread_info *info = lfsck_env_info(env);
+       struct lu_attr *tla = &info->lti_la2;
+       struct dt_object *child = llr->llr_child;
+       struct dt_device *dev = lfsck_obj2dev(child);
+       struct thandle *handle;
+       int rc;
+
+       ENTRY;
+
+       tla->la_valid = LA_FLAGS;
+       tla->la_flags = LUSTRE_ENCRYPT_FL;
+       handle = lfsck_trans_create(env, dev, com->lc_lfsck);
+       if (IS_ERR(handle))
+               GOTO(log, rc = PTR_ERR(handle));
+
+       rc = dt_declare_attr_set(env, child, tla, handle);
+       if (rc != 0)
+               GOTO(stop, rc);
+
+       rc = dt_trans_start_local(env, dev, handle);
+       if (rc != 0)
+               GOTO(stop, rc);
+
+       /* Use the dt_object lock to serialize with destroy and attr_set. */
+       dt_read_lock(env, parent, 0);
+       if (unlikely(lfsck_is_dead_obj(parent)))
+               GOTO(unlock, rc = 1);
+
+       rc = dt_attr_set(env, child, tla, handle);
+       GOTO(unlock, rc);
+
+unlock:
+       dt_read_unlock(env, parent);
+
+stop:
+       rc = lfsck_layout_trans_stop(env, dev, handle, rc);
+
+log:
+       if (rc != 0)
+               CDEBUG(D_LFSCK,
+                      "%s: layout LFSCK assistant repair of inconsistent file enc flag for: parent "
+                      DFID", child "
+                      DFID", OST-index %u, stripe-index %u: rc = %d\n",
+                      lfsck_lfsck2name(com->lc_lfsck),
+                      PFID(lfsck_dto2fid(parent)), PFID(lfsck_dto2fid(child)),
+                      llr->llr_ost_idx, llr->llr_lov_idx, rc);
+
+       return rc;
+}
+
 static int lfsck_layout_assistant_handler_p1(const struct lu_env *env,
                                             struct lfsck_component *com,
                                             struct lfsck_assistant_req *lar)
@@ -4387,6 +4446,29 @@ static int lfsck_layout_assistant_handler_p1(const struct lu_env *env,
        if (rc != 0)
                GOTO(out, rc);
 
+       if (!(bk->lb_param & LPF_DRYRUN) &&
+           pla->la_valid & LA_FLAGS && pla->la_flags & LUSTRE_ENCRYPT_FL) {
+               /* MDT-inode is encrypted */
+               struct lu_buf lb = { .lb_buf = NULL, .lb_len = 0 };
+
+               /* if OST-inode is missing encryption.c xattr, fix it */
+               if (dt_xattr_get(env, child, &lb,
+                                LL_XATTR_NAME_ENCRYPTION_CONTEXT) >= 0)
+                       goto check_fid;
+
+               if (parent == NULL)
+                       parent = lfsck_assistant_object_load(env, lfsck, lso);
+               if (!IS_ERR_OR_NULL(parent))
+                       rc = lfsck_layout_repair_encflag(env, com, parent, llr);
+               down_write(&com->lc_sem);
+               if (rc < 0)
+                       lfsck_layout_record_failure(env, lfsck, lo);
+               else if (rc > 0)
+                       lo->ll_objs_repaired[LLIT_OTHERS - 1]++;
+               up_write(&com->lc_sem);
+       }
+
+check_fid:
        lfsck_buf_init(&buf, ff, sizeof(*ff));
        rc = dt_xattr_get(env, child, &buf, XATTR_NAME_FID);
        if (unlikely(rc > 0 && rc < sizeof(struct lu_fid))) {
index 98c3cc7..4993c04 100644 (file)
@@ -5435,6 +5435,11 @@ fill_attr:
        stat->attributes_mask |= STATX_ATTR_ENCRYPTED;
 #endif
        stat->attributes |= ll_inode_to_ext_flags(inode->i_flags);
+       /* if Lustre specific LUSTRE_ENCRYPT_FL flag is set, also set
+        * ext4 equivalent to please statx
+        */
+       if (stat->attributes & LUSTRE_ENCRYPT_FL)
+               stat->attributes |= STATX_ATTR_ENCRYPTED;
        stat->result_mask &= request_mask;
 #endif
 
index e67ab23..13b6dcb 100644 (file)
@@ -2990,6 +2990,11 @@ int ll_iocontrol(struct inode *inode, struct file *file,
                 body = req_capsule_server_get(&req->rq_pill, &RMF_MDT_BODY);
 
                flags = body->mbo_flags;
+               /* if Lustre specific LUSTRE_ENCRYPT_FL flag is set, also set
+                * ext4 equivalent to please lsattr and other e2fsprogs tools
+                */
+               if (flags & LUSTRE_ENCRYPT_FL)
+                       flags |= STATX_ATTR_ENCRYPTED;
 
                ptlrpc_req_finished(req);
 
index dd84015..ac6d56c 100644 (file)
@@ -470,38 +470,62 @@ out:
 }
 
 /*
+ * Handle multiple attrs at once:
+ *
  * Lazy ATIME update to refresh atime every ofd_atime_diff
  * seconds so that external scanning tool can see it actual
  * within that period and be able to identify accessed files
+ *
+ * Update enc flag on OST object
+ * OSD layer will find out if this is really necessary.
  */
-static void ofd_handle_atime(const struct lu_env *env, struct ofd_device *ofd,
-                            struct ofd_object *fo, time64_t atime)
+static void ofd_handle_attrs(const struct lu_env *env, struct ofd_device *ofd,
+                            struct ofd_object *fo, struct obdo *oa)
 {
+       bool need_atime = (oa->o_valid & OBD_MD_FLATIME);
+       bool need_encfl = (oa->o_valid & OBD_MD_FLFLAGS &&
+                          oa->o_flags & LUSTRE_ENCRYPT_FL);
        struct lu_attr *la;
        struct dt_object *o;
        struct thandle *th;
        int rc;
 
-       if (ofd->ofd_atime_diff == 0)
+       if (need_atime && ofd->ofd_atime_diff == 0)
+               need_atime = false;
+
+       if (need_encfl && OBD_FAIL_CHECK(OBD_FAIL_LFSCK_NO_ENCFLAG))
+               need_encfl = false;
+
+       if (!need_atime && !need_encfl)
                return;
 
        la = &ofd_info(env)->fti_attr2;
        o = ofd_object_child(fo);
 
-       if (unlikely(fo->ofo_atime_ondisk == 0)) {
-               rc = dt_attr_get(env, o, la);
-               if (unlikely(rc))
-                       return;
-               LASSERT(la->la_valid & LA_ATIME);
-               if (la->la_atime == 0)
-                       la->la_atime = la->la_mtime;
-               fo->ofo_atime_ondisk = la->la_atime;
+       if (need_atime) {
+               if (unlikely(fo->ofo_atime_ondisk == 0)) {
+                       rc = dt_attr_get(env, o, la);
+                       if (unlikely(rc)) {
+                               need_atime = false;
+                               GOTO(trans, rc);
+                       }
+                       LASSERT(la->la_valid & LA_ATIME);
+                       if (la->la_atime == 0)
+                               la->la_atime = la->la_mtime;
+                       fo->ofo_atime_ondisk = la->la_atime;
+               }
+               if (oa->o_atime - fo->ofo_atime_ondisk < ofd->ofd_atime_diff) {
+                       need_atime = false;
+                       GOTO(trans, rc = 0);
+               }
+
+               /* atime hasn't been updated too long, update it */
+               fo->ofo_atime_ondisk = oa->o_atime;
        }
-       if (atime - fo->ofo_atime_ondisk < ofd->ofd_atime_diff)
-               return;
 
-       /* atime hasn't been updated too long, update it */
-       fo->ofo_atime_ondisk = atime;
+trans:
+       if (!need_atime && !need_encfl)
+               return;
 
        th = ofd_trans_create(env, ofd);
        if (IS_ERR(th)) {
@@ -510,7 +534,16 @@ static void ofd_handle_atime(const struct lu_env *env, struct ofd_device *ofd,
                return;
        }
 
-       la->la_valid = LA_ATIME;
+       la->la_valid = 0;
+       if (need_atime) {
+               la->la_valid |= LA_ATIME;
+               la->la_atime = fo->ofo_atime_ondisk;
+       }
+       if (need_encfl) {
+               la->la_valid |= LA_FLAGS;
+               la->la_flags = LUSTRE_ENCRYPT_FL;
+       }
+
        rc = dt_declare_attr_set(env, o, la, th);
        if (rc)
                GOTO(out_tx, rc);
@@ -523,11 +556,8 @@ static void ofd_handle_atime(const struct lu_env *env, struct ofd_device *ofd,
        }
 
        ofd_read_lock(env, fo);
-       if (ofd_object_exists(fo)) {
-               la->la_atime = fo->ofo_atime_ondisk;
+       if (ofd_object_exists(fo))
                rc = dt_attr_set(env, o, la, th);
-       }
-
        ofd_read_unlock(env, fo);
 
 out_tx:
@@ -577,8 +607,7 @@ static int ofd_preprw_read(const struct lu_env *env, struct obd_export *exp,
 
        ofd_info(env)->fti_obj = fo;
 
-       if (oa->o_valid & OBD_MD_FLATIME)
-               ofd_handle_atime(env, ofd, fo, oa->o_atime);
+       ofd_handle_attrs(env, ofd, fo, oa);
 
        if (!ofd_object_exists(fo))
                GOTO(obj_put, rc = -ENOENT);
@@ -990,13 +1019,14 @@ ofd_write_attr_set(const struct lu_env *env, struct ofd_device *ofd,
                   struct ofd_object *ofd_obj, struct lu_attr *la,
                   struct obdo *oa)
 {
-       struct ofd_thread_info  *info = ofd_info(env);
-       struct filter_fid       *ff = &info->fti_mds_fid;
-       __u64                    valid = la->la_valid;
-       struct thandle          *th;
-       struct dt_object        *dt_obj;
-       int                      fl = 0;
-       int                      rc;
+       struct ofd_thread_info *info = ofd_info(env);
+       struct filter_fid *ff = &info->fti_mds_fid;
+       __u64 valid = la->la_valid;
+       __u32 flags = la->la_flags;
+       struct thandle *th;
+       struct dt_object *dt_obj;
+       int fl = 0;
+       int rc;
 
        ENTRY;
 
@@ -1006,6 +1036,11 @@ ofd_write_attr_set(const struct lu_env *env, struct ofd_device *ofd,
        LASSERT(dt_obj != NULL);
 
        la->la_valid &= LA_UID | LA_GID | LA_PROJID;
+       if (oa->o_valid & OBD_MD_FLFLAGS && oa->o_flags & LUSTRE_ENCRYPT_FL &&
+           !OBD_FAIL_CHECK(OBD_FAIL_LFSCK_NO_ENCFLAG)) {
+               la->la_valid |= LA_FLAGS;
+               la->la_flags = LUSTRE_ENCRYPT_FL;
+       }
 
        rc = ofd_attr_handle_id(env, ofd_obj, la, 0 /* !is_setattr */);
        if (rc != 0)
@@ -1090,6 +1125,7 @@ out_tx:
        dt_trans_stop(env, ofd->ofd_osd, th);
 out:
        la->la_valid = valid;
+       la->la_flags = flags;
        return rc;
 }
 
index 580e4d4..194e8cd 100644 (file)
@@ -1780,6 +1780,16 @@ no_bulk:
        else /* short io */
                ioobj_max_brw_set(ioobj, 0);
 
+       if (inode && IS_ENCRYPTED(inode) &&
+           llcrypt_has_encryption_key(inode) &&
+           !OBD_FAIL_CHECK(OBD_FAIL_LFSCK_NO_ENCFLAG)) {
+               if ((body->oa.o_valid & OBD_MD_FLFLAGS) == 0) {
+                       body->oa.o_valid |= OBD_MD_FLFLAGS;
+                       body->oa.o_flags = 0;
+               }
+               body->oa.o_flags |= LUSTRE_ENCRYPT_FL;
+       }
+
        if (short_io_size != 0) {
                if ((body->oa.o_valid & OBD_MD_FLFLAGS) == 0) {
                        body->oa.o_valid |= OBD_MD_FLFLAGS;
index 759b83f..18c747d 100644 (file)
@@ -123,6 +123,9 @@ static int osd_remote_fid(const struct lu_env *env, struct osd_device *osd,
                          const struct lu_fid *fid);
 static int osd_process_scheduled_agent_removals(const struct lu_env *env,
                                                struct osd_device *osd);
+static int osd_xattr_set(const struct lu_env *env, struct dt_object *dt,
+                        const struct lu_buf *buf, const char *name, int fl,
+                        struct thandle *handle);
 
 int osd_trans_declare_op2rb[] = {
        [OSD_OT_ATTR_SET]       = OSD_OT_ATTR_SET,
@@ -3156,7 +3159,9 @@ static int osd_attr_set(const struct lu_env *env,
                        const struct lu_attr *attr,
                        struct thandle *handle)
 {
+       struct osd_thread_info *info = osd_oti_get(env);
        struct osd_object *obj = osd_dt_obj(dt);
+       struct osd_device *osd = osd_obj2dev(obj);
        struct inode *inode;
        int rc;
 
@@ -3215,9 +3220,34 @@ static int osd_attr_set(const struct lu_env *env,
        if (!(attr->la_valid & LA_FLAGS))
                GOTO(out, rc);
 
+       /* If setting LUSTRE_ENCRYPT_FL on an OST object, also set a dummy
+        * enc ctx xattr, with 2 benefits:
+        * - setting the LL_XATTR_NAME_ENCRYPTION_CONTEXT xattr internally sets
+        *   the LDISKFS_ENCRYPT_FL flag on the on-disk inode;
+        * - it makes e2fsprogs happy to see an enc ctx for an inode that has
+        *   the LDISKFS_ENCRYPT_FL flag
+        * We do not need the actual encryption context on OST objects, it is
+        * only stored on MDT inodes, at file creation time.
+        */
+       if (!(LDISKFS_I(obj->oo_inode)->i_flags & LDISKFS_ENCRYPT_FL) &&
+           attr->la_flags & LUSTRE_ENCRYPT_FL && osd->od_is_ost &&
+           !OBD_FAIL_CHECK(OBD_FAIL_LFSCK_NO_ENCFLAG)) {
+               struct lu_buf buf;
+
+               /* use a dummy enc ctx, fine with e2fsprogs */
+               buf.lb_buf = "\xFF";
+               buf.lb_len = 1;
+               rc = osd_xattr_set(env, dt, &buf,
+                                  LL_XATTR_NAME_ENCRYPTION_CONTEXT,
+                                  0, handle);
+               if (rc)
+                       CWARN("%s: set "DFID" enc ctx failed: rc = %d\n",
+                             osd_name(osd), PFID(lu_object_fid(&dt->do_lu)),
+                             rc);
+       }
+
        /* Let's check if there are extra flags need to be set into LMA */
        if (attr->la_flags & LUSTRE_LMA_FL_MASKS) {
-               struct osd_thread_info *info = osd_oti_get(env);
                struct lustre_mdt_attrs *lma = &info->oti_ost_attrs.loa_lma;
 
                LASSERT(!obj->oo_pfid_in_lma);
@@ -3227,6 +3257,13 @@ static int osd_attr_set(const struct lu_env *env,
                if (rc)
                        GOTO(out, rc);
 
+               if ((lma->lma_incompat & lustre_to_lma_flags(attr->la_flags)) ==
+                   lustre_to_lma_flags(attr->la_flags))
+                       /* if lma incompat already has the flags,
+                        * save a useless call to xattr_set
+                        */
+                       GOTO(out, rc = 0);
+
                lma->lma_incompat |=
                        lustre_to_lma_flags(attr->la_flags);
                lustre_lma_swab(lma);
@@ -3235,20 +3272,17 @@ static int osd_attr_set(const struct lu_env *env,
 
                rc = __osd_xattr_set(info, inode, XATTR_NAME_LMA,
                                     lma, sizeof(*lma), XATTR_REPLACE);
-               if (rc != 0) {
-                       struct osd_device *osd = osd_obj2dev(obj);
-
+               if (rc != 0)
                        CWARN("%s: set "DFID" lma flags %u failed: rc = %d\n",
                              osd_name(osd), PFID(lu_object_fid(&dt->do_lu)),
                              lma->lma_incompat, rc);
-               } else {
+               else
                        obj->oo_lma_flags =
                                attr->la_flags & LUSTRE_LMA_FL_MASKS;
-               }
                osd_trans_exec_check(env, handle, OSD_OT_XATTR_SET);
        }
-out:
 
+out:
        return rc;
 }
 
index 9411183..9332883 100644 (file)
@@ -1343,6 +1343,15 @@ static int osd_attr_set(const struct lu_env *env, struct dt_object *dt,
                        } else if (!rc) {
                                lma->lma_incompat =
                                        le32_to_cpu(lma->lma_incompat);
+
+                               if ((lma->lma_incompat &
+                                    lustre_to_lma_flags(la->la_flags)) ==
+                                   lustre_to_lma_flags(la->la_flags))
+                                       /* save a useless xattr set if lma
+                                        * incompat already has the flags
+                                        */
+                                       GOTO(lock, rc = 0);
+
                                lma->lma_incompat |=
                                        lustre_to_lma_flags(la->la_flags);
                                lma->lma_incompat =
@@ -1365,6 +1374,7 @@ static int osd_attr_set(const struct lu_env *env, struct dt_object *dt,
                }
        }
 
+lock:
        write_lock(&obj->oo_attr_lock);
        cnt = 0;
 
index 52a12c4..a2f245b 100644 (file)
@@ -756,8 +756,12 @@ static int osp_attr_set(const struct lu_env *env, struct dt_object *dt,
        int                      rc = 0;
        ENTRY;
 
-       /* we're interested in uid/gid/projid/layout version changes only */
-       if (!(attr->la_valid & LA_REMOTE_ATTR_SET))
+       /* we're interested in uid/gid/projid/layout version changes,
+        * and also specific setting of enc flag
+        */
+       if (!(attr->la_valid & LA_REMOTE_ATTR_SET) &&
+           !(attr->la_valid == LA_FLAGS &&
+             attr->la_flags == LUSTRE_ENCRYPT_FL))
                RETURN(0);
 
        if (!is_only_remote_trans(th)) {
index 0d24f46..1f305f1 100644 (file)
@@ -6037,6 +6037,140 @@ test_41()
 }
 run_test 41 "SEL support in LFSCK"
 
+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
+}
+
+insert_enc_key() {
+       cancel_lru_locks
+       sync ; echo 3 > /proc/sys/vm/drop_caches
+       setup_dummy_key
+}
+
+remove_enc_key() {
+       local dummy_key
+
+       $LCTL set_param -n ldlm.namespaces.*.lru_size=clear
+       sync ; echo 3 > /proc/sys/vm/drop_caches
+       dummy_key=$(keyctl show | awk '$7 ~ "^fscrypt:" {print $1}')
+       if [ -n "$dummy_key" ]; then
+               keyctl revoke $dummy_key
+               keyctl reap
+       fi
+}
+
+remount_client_normally() {
+       # remount client without dummy encryption key
+       if is_mounted $MOUNT; then
+               umount_client $MOUNT || error "umount $MOUNT failed"
+       fi
+       mount_client $MOUNT ${MOUNT_OPTS} ||
+               error "remount failed"
+
+       if is_mounted $MOUNT2; then
+               umount_client $MOUNT2 || error "umount $MOUNT2 failed"
+       fi
+       if [ "$MOUNT_2" ]; then
+               mount_client $MOUNT2 ${MOUNT_OPTS} ||
+                       error "remount failed"
+       fi
+
+       remove_enc_key
+}
+
+remount_client_dummykey() {
+       insert_enc_key
+
+       # remount client with dummy encryption key
+       if is_mounted $MOUNT; then
+               umount_client $MOUNT || error "umount $MOUNT failed"
+       fi
+       mount_client $MOUNT ${MOUNT_OPTS},test_dummy_encryption ||
+               error "remount failed"
+}
+
+setup_for_enc_tests() {
+       rm -rf $DIR/[df][0-9]* || error "Fail to cleanup env"
+
+       # remount client with test_dummy_encryption option
+       if is_mounted $MOUNT; then
+               umount_client $MOUNT || error "umount $MOUNT failed"
+       fi
+       mount_client $MOUNT ${MOUNT_OPTS},test_dummy_encryption ||
+               error "mount with '-o test_dummy_encryption' failed"
+
+       # this directory will be encrypted, because of dummy mode
+       $LFS setdirstripe -c 1 -i 0 $DIR/$tdir
+       $LFS setstripe -c 1 -i 0 $DIR/$tdir
+}
+
+cleanup_for_enc_tests() {
+       rm -rf $DIR/$tdir $*
+
+       remount_client_normally
+}
+
+test_42() {
+       [[ $(facet_fstype ost1) == zfs ]] && skip "skip ZFS backend"
+
+       (( $MDS1_VERSION > $(version_code 2.15.51) )) ||
+               skip "Need MDS version at least 2.15.51"
+
+       echo "#####"
+       echo "If the MDT-object has the encryption flag but the OST-object"
+       echo "does not, add it to the OST-object."
+       echo "#####"
+
+       check_mount_and_prep
+
+       $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"
+
+       stack_trap cleanup_for_enc_tests EXIT
+       setup_for_enc_tests
+
+       $LFS setstripe -c 1 -i 0 $DIR/$tdir
+       touch $DIR/$tdir/${tfile}_1 || error "touch ${tfile}_1 failed"
+       dd if=/dev/zero of=$DIR/$tdir/${tfile}_2 bs=1 count=1 conv=fsync ||
+               error "dd ${tfile}_2 failed"
+
+       #define OBD_FAIL_LFSCK_NO_ENCFLAG       0x1632
+       do_nodes $(comma_list $(all_nodes)) "$LCTL set_param fail_loc=0x1632"
+       touch $DIR/$tdir/${tfile}_3 || error "touch ${tfile}_3 failed"
+       dd if=/dev/zero of=$DIR/$tdir/${tfile}_4 bs=1 count=1 conv=fsync ||
+               error "dd ${tfile}_4 failed"
+       do_nodes $(comma_list $(all_nodes)) "$LCTL set_param fail_loc=0x0"
+       cancel_lru_locks osc
+
+       echo "Trigger layout LFSCK to find out inconsistent OST-object enc flag"
+
+       $START_LAYOUT -r || error "Fail to start LFSCK for layout!"
+
+       wait_update_facet $SINGLEMDS "$LCTL get_param -n \
+               mdd.${MDT_DEV}.lfsck_layout |
+               awk '/^status/ { print \\\$2 }'" "completed" 32 || {
+               $SHOW_LAYOUT
+               error "unexpected lfsck status"
+       }
+
+       local repaired=$($SHOW_LAYOUT |
+                        awk '/^repaired_others/ { print $2 }')
+       [ $repaired -eq 2 ] ||
+               error "Fail to repair inconsistent enc flag: $repaired"
+}
+run_test 42 "LFSCK can repair inconsistent MDT-object/OST-object encryption flags"
+
 # restore MDS/OST size
 MDSSIZE=${SAVED_MDSSIZE}
 OSTSIZE=${SAVED_OSTSIZE}
index 360e3ca..c1f26ec 100755 (executable)
@@ -5115,6 +5115,46 @@ test_61() {
 }
 run_test 61 "Nodemap enforces read-only mount"
 
+test_62() {
+       local testdir=$DIR/$tdir/mytestdir
+       local testfile=$DIR/$tdir/$tfile
+
+       [[ $(facet_fstype ost1) == zfs ]] && skip "skip ZFS backend"
+
+       (( $MDS1_VERSION > $(version_code 2.15.51) )) ||
+               skip "Need MDS version at least 2.15.51"
+
+       $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"
+
+       stack_trap cleanup_for_enc_tests EXIT
+       setup_for_enc_tests
+
+       lfs setstripe -c -1 $DIR/$tdir
+       touch $DIR/$tdir/${tfile}_1 || error "touch ${tfile}_1 failed"
+       dd if=/dev/zero of=$DIR/$tdir/${tfile}_2 bs=1 count=1 conv=fsync ||
+               error "dd ${tfile}_2 failed"
+
+       # unmount the Lustre filesystem
+       stopall || error "stopping for e2fsck run"
+
+       # run e2fsck on the MDT and OST devices
+       local mds_host=$(facet_active_host $SINGLEMDS)
+       local ost_host=$(facet_active_host ost1)
+       local mds_dev=$(mdsdevname ${SINGLEMDS//mds/})
+       local ost_dev=$(ostdevname 1)
+
+       run_e2fsck $mds_host $mds_dev "-n"
+       run_e2fsck $ost_host $ost_dev "-n"
+
+       # mount the Lustre filesystem
+       setupall || error "remounting the filesystem failed"
+}
+run_test 62 "e2fsck with encrypted files"
+
 log "cleanup: ======================================================"
 
 sec_unsetup() {