Whamcloud - gitweb
LU-13055 mdd: per-user changelog names and mask 80/43380/9
authorMikhail Pershin <mpershin@whamcloud.com>
Tue, 22 Jun 2021 18:16:26 +0000 (21:16 +0300)
committerOleg Drokin <green@whamcloud.com>
Thu, 8 Jul 2021 02:05:16 +0000 (02:05 +0000)
Allow specifying a name for newly-registered changelog users,
rather than the default "clNNN" that is otherwise used. This
allows services to register a "well-known" changelog user,
rather than having to store the changelog username in HA storage
outside of the filesystem.

Each changelog user still has a unique ID appended to it, to allow
the changelog_clear and changelog_deregister commands to be run
using only the ID if necessary/desired. User name can be used to
deregister. User name is also unique per server.

If no name is given, then default "cl" format is used.

With this new functionality, it is possible to specify the name like:
 # lctl --device testfs-MDT0000 changelog_register --user watcher
   testfs-MDT0000: Registered changelog userid 'cl13-watcher'

Per-user mask is also added to allow specific operation logging on
per-user basis. Mask can be set only during registration. Resulting
mask from per-server mask and all user masks is used for current
changelog operations.

Signed-off-by: Mikhail Pershin <mpershin@whamcloud.com>
Change-Id: I56028f54cc97bbc9af03fd6559c19ef854f759d8
Reviewed-on: https://review.whamcloud.com/43380
Tested-by: jenkins <devops@whamcloud.com>
Reviewed-by: Andreas Dilger <adilger@whamcloud.com>
Reviewed-by: John L. Hammond <jhammond@whamcloud.com>
Tested-by: Maloo <maloo@whamcloud.com>
Reviewed-by: Sebastien Buisson <sbuisson@ddn.com>
Reviewed-by: Oleg Drokin <green@whamcloud.com>
19 files changed:
lustre/include/uapi/linux/lustre/lustre_idl.h
lustre/include/uapi/linux/lustre/lustre_user.h
lustre/mdd/mdd_device.c
lustre/mdd/mdd_internal.h
lustre/mdd/mdd_lproc.c
lustre/mdd/mdd_object.c
lustre/mdd/mdd_trans.c
lustre/obdclass/llog_swab.c
lustre/obdclass/llog_test.c
lustre/ptlrpc/wiretest.c
lustre/tests/sanity.sh
lustre/tests/test-framework.sh
lustre/utils/lctl.c
lustre/utils/liblustreapi_chlg.c
lustre/utils/llog_reader.c
lustre/utils/obd.c
lustre/utils/wirecheck.c
lustre/utils/wirehdr.c
lustre/utils/wiretest.c

index 19d2fe3..0f2462b 100644 (file)
@@ -2733,6 +2733,7 @@ enum llog_op_type {
        /* LLOG_JOIN_REC        = LLOG_OP_MAGIC | 0x50000, obsolete  1.8.0 */
        CHANGELOG_REC           = LLOG_OP_MAGIC | 0x60000,
        CHANGELOG_USER_REC      = LLOG_OP_MAGIC | 0x70000,
+       CHANGELOG_USER_REC2     = LLOG_OP_MAGIC | 0x70002,
        HSM_AGENT_REC           = LLOG_OP_MAGIC | 0x80000,
        UPDATE_REC              = LLOG_OP_MAGIC | 0xa0000,
        LLOG_HDR_MAGIC          = LLOG_OP_MAGIC | 0x45539,
@@ -2833,9 +2834,9 @@ struct llog_size_change_rec {
 #define CHANGELOG_MAGIC 0xca103000
 
 /** \a changelog_rec_type's that can't be masked */
-#define CHANGELOG_MINMASK (1 << CL_MARK)
+#define CHANGELOG_MINMASK BIT(CL_MARK)
 /** bits covering all \a changelog_rec_type's */
-#define CHANGELOG_ALLMASK 0XFFFFFFFF
+#define CHANGELOG_ALLMASK (BIT(CL_LAST) - 1)
 /** default \a changelog_rec_type mask. Allow all of them, except
  * CL_ATIME since it can really be time consuming, and not necessary
  * under normal use.
@@ -2843,8 +2844,7 @@ struct llog_size_change_rec {
  * be costly and only necessary for audit purpose.
  */
 #define CHANGELOG_DEFMASK (CHANGELOG_ALLMASK & \
-                          ~(1 << CL_ATIME | 1 << CL_OPEN | 1 << CL_GETXATTR | \
-                            1 << CL_DN_OPEN))
+       ~(BIT(CL_ATIME) | BIT(CL_OPEN) | BIT(CL_GETXATTR) | BIT(CL_DN_OPEN)))
 
 /* changelog llog name, needed by client replicators */
 #define CHANGELOG_CATALOG "changelog_catalog"
@@ -2862,6 +2862,8 @@ struct llog_changelog_rec {
 } __attribute__((packed));
 
 #define CHANGELOG_USER_PREFIX "cl"
+#define CHANGELOG_USER_NAMELEN 16 /* base name including NUL terminator */
+#define CHANGELOG_USER_NAMELEN_FULL 30 /* basename plus 'cl$ID-' prefix */
 
 struct llog_changelog_user_rec {
        struct llog_rec_hdr   cur_hdr;
@@ -2873,6 +2875,21 @@ struct llog_changelog_user_rec {
        struct llog_rec_tail  cur_tail;
 } __attribute__((packed));
 
+/* this is twice the size of CHANGELOG_USER_REC */
+struct llog_changelog_user_rec2 {
+       struct llog_rec_hdr     cur_hdr;
+       __u32                   cur_id;
+       /* only for use in relative time comparisons to detect idle users */
+       __u32                   cur_time;
+       __u64                   cur_endrec;
+       __u32                   cur_mask;
+       __u32                   cur_padding1;
+       char                    cur_name[CHANGELOG_USER_NAMELEN];
+       __u64                   cur_padding2;
+       __u64                   cur_padding3;
+       struct llog_rec_tail    cur_tail;
+} __attribute__((packed));
+
 enum agent_req_status {
        ARS_WAITING,
        ARS_STARTED,
index 5bd1693..b56e079 100644 (file)
@@ -1567,7 +1567,7 @@ enum changelog_rec_type {
        CL_RESYNC   = 22, /* FLR: file was resync-ed */
        CL_GETXATTR = 23,
        CL_DN_OPEN  = 24, /* denied open */
-       CL_LAST
+       CL_LAST,
 };
 
 static inline const char *changelog_type2str(int type) {
index 59a852d..1ce1c2e 100644 (file)
@@ -119,11 +119,15 @@ static int mdd_init0(const struct lu_env *env, struct mdd_device *mdd,
 {
        int rc = -EINVAL;
        const char *dev;
+
        ENTRY;
 
        /* LU-8040 Set defaults here, before values configs */
        mdd->mdd_cl.mc_flags = 0; /* off by default */
-       mdd->mdd_cl.mc_mask = CHANGELOG_DEFMASK;
+       /* per-server mask is set via parameters if needed */
+       mdd->mdd_cl.mc_proc_mask = CHANGELOG_MINMASK;
+       /* current mask is calculated from mask above and users masks */
+       mdd->mdd_cl.mc_current_mask = CHANGELOG_MINMASK;
        mdd->mdd_cl.mc_deniednext = 60; /* 60 secs by default */
 
        dev = lustre_cfg_string(lcfg, 0);
@@ -195,39 +199,75 @@ static int changelog_init_cb(const struct lu_env *env, struct llog_handle *llh,
               DFID"\n", hdr->lrh_index, rec->cr_hdr.lrh_index,
               rec->cr.cr_index, rec->cr.cr_type, rec->cr.cr_namelen,
               changelog_rec_name(&rec->cr), PFID(&llh->lgh_id.lgl_oi.oi_fid));
-
+       spin_lock(&mdd->mdd_cl.mc_lock);
        mdd->mdd_cl.mc_index = rec->cr.cr_index;
+       spin_unlock(&mdd->mdd_cl.mc_lock);
        return LLOG_PROC_BREAK;
 }
 
+char *mdd_chlg_username(struct llog_changelog_user_rec2 *rec, char *buf,
+                       size_t len)
+{
+       if (rec->cur_hdr.lrh_type == CHANGELOG_USER_REC2 &&
+           rec->cur_name[0])
+               snprintf(buf, len, "%s%u-%s",  CHANGELOG_USER_PREFIX,
+                        rec->cur_id, rec->cur_name);
+       else
+               snprintf(buf, len, "%s%u", CHANGELOG_USER_PREFIX, rec->cur_id);
+       return buf;
+}
+
+__u32 mdd_chlg_usermask(struct llog_changelog_user_rec2 *rec)
+{
+       return rec->cur_hdr.lrh_type == CHANGELOG_USER_REC2 ?
+              rec->cur_mask : 0;
+}
+
 static int changelog_user_init_cb(const struct lu_env *env,
                                  struct llog_handle *llh,
                                  struct llog_rec_hdr *hdr, void *data)
 {
-       struct mdd_device *mdd = (struct mdd_device *)data;
-       struct llog_changelog_user_rec *rec =
-               (struct llog_changelog_user_rec *)hdr;
+       struct mdd_device *mdd = data;
+       struct llog_changelog_user_rec2 *rec;
+       char user_name[CHANGELOG_USER_NAMELEN_FULL];
 
        LASSERT(llh->lgh_hdr->llh_flags & LLOG_F_IS_PLAIN);
-       LASSERT(rec->cur_hdr.lrh_type == CHANGELOG_USER_REC);
 
-       CDEBUG(D_INFO, "seeing user at index %d/%d id=%d endrec=%llu"
-              " in log "DFID"\n", hdr->lrh_index, rec->cur_hdr.lrh_index,
-              rec->cur_id, rec->cur_endrec, PFID(&llh->lgh_id.lgl_oi.oi_fid));
+       rec = container_of(hdr, typeof(*rec), cur_hdr);
+       if (rec->cur_hdr.lrh_type != CHANGELOG_USER_REC &&
+           rec->cur_hdr.lrh_type != CHANGELOG_USER_REC2) {
+               CWARN("%s: unknown user type %x at index %u in log "DFID"\n",
+                     mdd2obd_dev(mdd)->obd_name, hdr->lrh_index,
+                     rec->cur_hdr.lrh_type, PFID(&llh->lgh_id.lgl_oi.oi_fid));
+
+               return 0;
+       }
+
+       CDEBUG(D_INFO, "%s: user %s at index %u/%u endrec=%llu in log "DFID"\n",
+              mdd2obd_dev(mdd)->obd_name, mdd_chlg_username(rec, user_name,
+                                                            sizeof(user_name)),
+              hdr->lrh_index, rec->cur_hdr.lrh_index, rec->cur_endrec,
+              PFID(&llh->lgh_id.lgl_oi.oi_fid));
 
        spin_lock(&mdd->mdd_cl.mc_user_lock);
        mdd->mdd_cl.mc_lastuser = rec->cur_id;
        mdd->mdd_cl.mc_users++;
+       if (rec->cur_hdr.lrh_type == CHANGELOG_USER_REC2 && rec->cur_mask)
+               mdd->mdd_cl.mc_current_mask |= rec->cur_mask;
+       else if (mdd->mdd_cl.mc_proc_mask == CHANGELOG_MINMASK)
+               mdd->mdd_cl.mc_current_mask |= CHANGELOG_DEFMASK;
+       spin_unlock(&mdd->mdd_cl.mc_user_lock);
+       spin_lock(&mdd->mdd_cl.mc_lock);
        if (rec->cur_endrec > mdd->mdd_cl.mc_index)
                mdd->mdd_cl.mc_index = rec->cur_endrec;
-       spin_unlock(&mdd->mdd_cl.mc_user_lock);
+       spin_unlock(&mdd->mdd_cl.mc_lock);
 
        return LLOG_PROC_BREAK;
 }
 
 struct changelog_orphan_data {
-       __u64 index;
-       struct mdd_device *mdd;
+       __u64                   clod_index;
+       struct mdd_device       *clod_mdd;
 };
 
 /* find oldest changelog record index */
@@ -235,13 +275,13 @@ static int changelog_detect_orphan_cb(const struct lu_env *env,
                                      struct llog_handle *llh,
                                      struct llog_rec_hdr *hdr, void *data)
 {
-       struct mdd_device *mdd = ((struct changelog_orphan_data *)data)->mdd;
-       struct llog_changelog_rec *rec = container_of(hdr,
-                                                     struct llog_changelog_rec,
-                                                     cr_hdr);
+       struct changelog_orphan_data *clod = data;
+       struct mdd_device *mdd = clod->clod_mdd;
+       struct llog_changelog_rec *rec;
 
        LASSERT(llh->lgh_hdr->llh_flags & LLOG_F_IS_PLAIN);
 
+       rec = container_of(hdr, typeof(*rec), cr_hdr);
        if (rec->cr_hdr.lrh_type != CHANGELOG_REC) {
                CWARN("%s: invalid record at index %d in log "DFID"\n",
                      mdd2obd_dev(mdd)->obd_name, hdr->lrh_index,
@@ -252,13 +292,15 @@ static int changelog_detect_orphan_cb(const struct lu_env *env,
                return 0;
        }
 
-       CDEBUG(D_INFO, "%s: seeing record at index %d/%d/%llu t=%x %.*s in log "
-              DFID"\n", mdd2obd_dev(mdd)->obd_name, hdr->lrh_index,
+       CDEBUG(D_INFO,
+              "%s: record at index %d/%d/%llu t=%x %.*s in log "DFID"\n",
+              mdd2obd_dev(mdd)->obd_name, hdr->lrh_index,
               rec->cr_hdr.lrh_index, rec->cr.cr_index, rec->cr.cr_type,
               rec->cr.cr_namelen, changelog_rec_name(&rec->cr),
               PFID(&llh->lgh_id.lgl_oi.oi_fid));
 
-       ((struct changelog_orphan_data *)data)->index = rec->cr.cr_index;
+       clod->clod_index = rec->cr.cr_index;
+
        return LLOG_PROC_BREAK;
 }
 
@@ -267,30 +309,32 @@ static int changelog_user_detect_orphan_cb(const struct lu_env *env,
                                           struct llog_handle *llh,
                                           struct llog_rec_hdr *hdr, void *data)
 {
-       struct changelog_orphan_data *user_orphan = data;
-       struct mdd_device *mdd = user_orphan->mdd;
-       struct llog_changelog_user_rec *rec = container_of(hdr,
-                                               struct llog_changelog_user_rec,
-                                               cur_hdr);
+       struct changelog_orphan_data *clod = data;
+       struct mdd_device *mdd = clod->clod_mdd;
+       struct llog_changelog_user_rec2 *rec;
+       char user_name[CHANGELOG_USER_NAMELEN_FULL];
 
        LASSERT(llh->lgh_hdr->llh_flags & LLOG_F_IS_PLAIN);
 
-       if (rec->cur_hdr.lrh_type != CHANGELOG_USER_REC) {
-               CWARN("%s: invalid user at index %d in log "DFID"\n",
+       rec = container_of(hdr, typeof(*rec), cur_hdr);
+       if (rec->cur_hdr.lrh_type != CHANGELOG_USER_REC &&
+           rec->cur_hdr.lrh_type != CHANGELOG_USER_REC2) {
+               CWARN("%s: unknown user type %u at index %u in log "DFID"\n",
                      mdd2obd_dev(mdd)->obd_name, hdr->lrh_index,
-                     PFID(&llh->lgh_id.lgl_oi.oi_fid));
+                     rec->cur_hdr.lrh_type, PFID(&llh->lgh_id.lgl_oi.oi_fid));
                /* try to find some next valid record and thus allow to recover
                 * from a corrupted LLOG, instead to assert and force a crash
                 */
                return 0;
        }
 
-       CDEBUG(D_INFO, "%s: seeing user at index %d/%d id=%d endrec=%llu in "
-              "log "DFID"\n", mdd2obd_dev(mdd)->obd_name, hdr->lrh_index,
-              rec->cur_hdr.lrh_index, rec->cur_id, rec->cur_endrec,
-              PFID(&llh->lgh_id.lgl_oi.oi_fid));
+       CDEBUG(D_INFO, "%s: user %s at index %u/%u endrec=%llu in log "DFID"\n",
+              mdd2obd_dev(mdd)->obd_name, mdd_chlg_username(rec, user_name,
+                                                            sizeof(user_name)),
+              hdr->lrh_index, rec->cur_hdr.lrh_index,
+              rec->cur_endrec, PFID(&llh->lgh_id.lgl_oi.oi_fid));
 
-       user_orphan->index = min_t(__u64, user_orphan->index, rec->cur_endrec);
+       clod->clod_index = min_t(__u64, clod->clod_index, rec->cur_endrec);
 
        return 0;
 }
@@ -446,14 +490,14 @@ mdd_changelog_off(const struct lu_env *env, struct mdd_device *mdd)
 static int mdd_changelog_llog_init(const struct lu_env *env,
                                   struct mdd_device *mdd)
 {
-       struct obd_device       *obd = mdd2obd_dev(mdd);
-       struct llog_ctxt        *ctxt = NULL, *uctxt = NULL;
-       struct changelog_orphan_data changelog_orphan = {
-               .mdd = mdd,
-               .index = -1,
+       struct obd_device *obd = mdd2obd_dev(mdd);
+       struct llog_ctxt *ctxt = NULL, *uctxt = NULL;
+       struct changelog_orphan_data clod = {
+               .clod_mdd = mdd,
+               .clod_index = -1,
        }, user_orphan = {
-               .mdd = mdd,
-               .index = -1,
+               .clod_mdd = mdd,
+               .clod_index = -1,
        };
        int rc;
 
@@ -526,6 +570,9 @@ static int mdd_changelog_llog_init(const struct lu_env *env,
                GOTO(out_uclose, rc);
        }
 
+       /* Finally apply per-server mask */
+       mdd->mdd_cl.mc_current_mask |= mdd->mdd_cl.mc_proc_mask;
+
        /* If we have registered users, assume we want changelogs on */
        if (mdd->mdd_cl.mc_lastuser > 0) {
                rc = mdd_changelog_on(env, mdd);
@@ -544,7 +591,7 @@ static int mdd_changelog_llog_init(const struct lu_env *env,
         * XXX we may need to run end of purge as a separate thread
         */
        rc = llog_cat_process(env, ctxt->loc_handle, changelog_detect_orphan_cb,
-                             &changelog_orphan, 0, 0);
+                             &clod, 0, 0);
        if (rc < 0) {
                CERROR("%s: changelog detect orphan failed: rc = %d\n",
                       obd->obd_name, rc);
@@ -558,15 +605,15 @@ static int mdd_changelog_llog_init(const struct lu_env *env,
                       obd->obd_name, rc);
                GOTO(out_uclose, rc);
        }
-       if (unlikely(changelog_orphan.index < user_orphan.index)) {
+       if (unlikely(clod.clod_index < user_orphan.clod_index)) {
                struct changelog_cancel_cookie cl_cookie = {
-                       .endrec = user_orphan.index,
+                       .endrec = user_orphan.clod_index,
                        .mdd = mdd,
                };
 
                CWARN("%s : orphan changelog records found, starting from "
                      "index %llu to index %llu, being cleared now\n",
-                     obd->obd_name, changelog_orphan.index, user_orphan.index);
+                     obd->obd_name, clod.clod_index, user_orphan.clod_index);
 
                /* XXX we may need to run end of purge as a separate thread */
                rc = llog_changelog_cancel(env, ctxt, &cl_cookie);
@@ -743,7 +790,7 @@ int mdd_changelog_write_header(const struct lu_env *env,
 
        ENTRY;
 
-       if (mdd->mdd_cl.mc_mask & BIT(CL_MARK)) {
+       if (mdd->mdd_cl.mc_current_mask & BIT(CL_MARK)) {
                mdd->mdd_cl.mc_starttime = ktime_get();
                RETURN(0);
        }
@@ -1540,66 +1587,247 @@ static const struct obd_ops mdd_obd_device_ops = {
        .o_set_info_async = mdd_obd_set_info_async,
 };
 
+struct mdd_changelog_name_check_data {
+       const char *mcnc_name;
+       __u32       mcnc_id;
+};
+
+/**
+ * changelog_recalc_mask callback
+ *
+ * Is is called per each registered user and calculates combined mask of
+ * all registered users.
+ */
+static int mdd_changelog_name_check_cb(const struct lu_env *env,
+                                      struct llog_handle *llh,
+                                      struct llog_rec_hdr *hdr, void *data)
+{
+       struct llog_changelog_user_rec2 *rec;
+       struct mdd_changelog_name_check_data *mcnc = data;
+
+       rec = container_of(hdr, typeof(*rec), cur_hdr);
+       if (rec->cur_hdr.lrh_type == CHANGELOG_USER_REC2 &&
+           !strncmp(rec->cur_name, mcnc->mcnc_name, sizeof(rec->cur_name))) {
+               mcnc->mcnc_id = rec->cur_id;
+               return -EEXIST;
+       }
+       return 0;
+}
+
+static int mdd_changelog_name_check(const struct lu_env *env,
+                                   struct llog_ctxt *ctxt,
+                                   struct mdd_device *mdd, const char *name)
+{
+       struct mdd_changelog_name_check_data mcnc = { .mcnc_name = name, };
+       int chr = 0;
+       int rc;
+
+       ENTRY;
+
+       /* first symbol is a letter */
+       if (!isalpha(name[0])) {
+               rc = -EINVAL;
+               CERROR("%s: first char '%c' in '%s' is not letter: rc = %d\n",
+                      mdd2obd_dev(mdd)->obd_name, name[0], name, rc);
+               RETURN(rc);
+       }
+
+       /* name is valid: contains letters, numbers and '-', '_' only */
+       while (name[++chr]) {
+               if (!(isalnum(name[chr]) || name[chr] == '_' ||
+                     name[chr] == '-')) {
+                       rc = -EINVAL;
+                       CERROR("%s: wrong char '%c' in name '%s': rc = %d\n",
+                              mdd2obd_dev(mdd)->obd_name, name[chr], name, rc);
+                       RETURN(rc);
+               }
+       }
+
+       if (chr > CHANGELOG_USER_NAMELEN) {
+               rc = -ENAMETOOLONG;
+               CERROR("%s: name '%s' is over %d symbols limit: rc = %d\n",
+                      mdd2obd_dev(mdd)->obd_name, name,
+                      CHANGELOG_USER_NAMELEN, rc);
+               RETURN(rc);
+       }
+
+       rc = llog_cat_process(env, ctxt->loc_handle,
+                             mdd_changelog_name_check_cb, &mcnc, 0, 0);
+       if (rc == -EEXIST)
+               CWARN("%s: changelog name %s exists already: rc = %d\n",
+                     mdd2obd_dev(mdd)->obd_name, name, rc);
+       else if (rc < 0)
+               CWARN("%s: failed user changelog processing: rc = %d\n",
+                     mdd2obd_dev(mdd)->obd_name, rc);
+       RETURN(rc);
+}
+
 static int mdd_changelog_user_register(const struct lu_env *env,
-                                      struct mdd_device *mdd, int *id)
+                                      struct mdd_device *mdd, int *id,
+                                      const char *name, const char *mask)
 {
-        struct llog_ctxt *ctxt;
-        struct llog_changelog_user_rec *rec;
-        int rc;
-        ENTRY;
+       struct llog_ctxt *ctxt;
+       struct llog_changelog_user_rec2 *rec;
+       char user_name[CHANGELOG_USER_NAMELEN_FULL];
+       int rc;
 
-        ctxt = llog_get_context(mdd2obd_dev(mdd),
+       ENTRY;
+
+       ctxt = llog_get_context(mdd2obd_dev(mdd),
                                LLOG_CHANGELOG_USER_ORIG_CTXT);
-        if (ctxt == NULL)
-                RETURN(-ENXIO);
+       if (ctxt == NULL)
+               RETURN(-ENXIO);
 
-        OBD_ALLOC_PTR(rec);
-        if (rec == NULL) {
-                llog_ctxt_put(ctxt);
-                RETURN(-ENOMEM);
-        }
+       OBD_ALLOC_PTR(rec);
+       if (rec == NULL) {
+               llog_ctxt_put(ctxt);
+               RETURN(-ENOMEM);
+       }
 
        CFS_RACE(CFS_FAIL_CHLOG_USER_REG_UNREG_RACE);
 
-        rec->cur_hdr.lrh_len = sizeof(*rec);
-        rec->cur_hdr.lrh_type = CHANGELOG_USER_REC;
+       rec->cur_hdr.lrh_len = sizeof(*rec);
+       /* keep old record type for users without mask/name for
+        * compatibility needs
+        */
+       if (mask || (name && name[0]))
+               rec->cur_hdr.lrh_type = CHANGELOG_USER_REC2;
+       else
+               rec->cur_hdr.lrh_type = CHANGELOG_USER_REC;
        spin_lock(&mdd->mdd_cl.mc_user_lock);
        if (mdd->mdd_cl.mc_lastuser == (unsigned int)(-1)) {
                spin_unlock(&mdd->mdd_cl.mc_user_lock);
-               CERROR("Maximum number of changelog users exceeded!\n");
-               GOTO(out, rc = -EOVERFLOW);
+               rc = -EOVERFLOW;
+               CERROR("%s: registering %s user: max ID is exceeded: rc = %d\n",
+                      mdd2obd_dev(mdd)->obd_name,
+                      (name && name[0]) ? name : "new", rc);
+               GOTO(out, rc);
        }
        *id = rec->cur_id = ++mdd->mdd_cl.mc_lastuser;
        mdd->mdd_cl.mc_users++;
-       rec->cur_endrec = mdd->mdd_cl.mc_index;
+       spin_unlock(&mdd->mdd_cl.mc_user_lock);
 
        rec->cur_time = (__u32)ktime_get_real_seconds();
        if (OBD_FAIL_CHECK(OBD_FAIL_TIME_IN_CHLOG_USER))
                rec->cur_time = 0;
 
-       spin_unlock(&mdd->mdd_cl.mc_user_lock);
+       spin_lock(&mdd->mdd_cl.mc_lock);
+       rec->cur_endrec = mdd->mdd_cl.mc_index;
+       spin_unlock(&mdd->mdd_cl.mc_lock);
+
+       if (mask) {
+               /* if user will use relative mask apply it on default one */
+               rec->cur_mask = CHANGELOG_DEFMASK;
+               rc = cfs_str2mask(mask, changelog_type2str, &rec->cur_mask,
+                                 CHANGELOG_MINMASK, CHANGELOG_ALLMASK);
+               if (rc)
+                       GOTO(out_users, rc);
+       }
+
+       if (name && name[0]) {
+               rc = mdd_changelog_name_check(env, ctxt, mdd, name);
+               if (rc)
+                       GOTO(out_users, rc);
+               strlcpy(rec->cur_name, name, sizeof(rec->cur_name));
+       }
+       mdd_chlg_username(rec, user_name, sizeof(user_name));
 
        rc = llog_cat_add(env, ctxt->loc_handle, &rec->cur_hdr, NULL);
        if (rc) {
-               CWARN("%s: Failed to register changelog user %d: rc=%d\n",
-                     mdd2obd_dev(mdd)->obd_name, *id, rc);
-               spin_lock(&mdd->mdd_cl.mc_user_lock);
-               mdd->mdd_cl.mc_users--;
-               spin_unlock(&mdd->mdd_cl.mc_user_lock);
-               GOTO(out, rc);
+               CWARN("%s: failed to register changelog user %s: rc = %d\n",
+                     mdd2obd_dev(mdd)->obd_name, user_name, rc);
+               GOTO(out_users, rc);
        }
 
-        CDEBUG(D_IOCTL, "Registered changelog user %d\n", *id);
+       /* apply user mask finally */
+       spin_lock(&mdd->mdd_cl.mc_user_lock);
+       mdd->mdd_cl.mc_current_mask |= rec->cur_mask;
+       spin_unlock(&mdd->mdd_cl.mc_user_lock);
+
+       CDEBUG(D_IOCTL, "%s: registered changelog user '%s', mask %#x\n",
+              mdd2obd_dev(mdd)->obd_name, user_name, rec->cur_mask);
 
        /* Assume we want it on since somebody registered */
        rc = mdd_changelog_on(env, mdd);
        if (rc)
+               /* record is added, so don't decrement users on error */
                GOTO(out, rc);
+out_users:
+       if (rc) {
+               spin_lock(&mdd->mdd_cl.mc_user_lock);
+               mdd->mdd_cl.mc_users--;
+               spin_unlock(&mdd->mdd_cl.mc_user_lock);
+       }
+out:
+       OBD_FREE_PTR(rec);
+       llog_ctxt_put(ctxt);
+       RETURN(rc);
+}
+
+struct mdd_changelog_recalc_mask_data {
+       struct mdd_device *mcrm_mdd;
+       __u32              mcrm_mask;
+};
 
+/**
+ * changelog_recalc_mask callback
+ *
+ * Is is called per each registered user and calculates combined mask of
+ * all registered users.
+ */
+static int mdd_changelog_recalc_mask_cb(const struct lu_env *env,
+                                      struct llog_handle *llh,
+                                      struct llog_rec_hdr *hdr, void *data)
+{
+       struct llog_changelog_user_rec2 *rec;
+       struct mdd_changelog_recalc_mask_data *mcrm = data;
+
+       rec = container_of(hdr, typeof(*rec), cur_hdr);
+       if (rec->cur_hdr.lrh_type == CHANGELOG_USER_REC2 && rec->cur_mask)
+               mcrm->mcrm_mask |= rec->cur_mask;
+       else if (mcrm->mcrm_mdd->mdd_cl.mc_proc_mask == CHANGELOG_MINMASK)
+               mcrm->mcrm_mask |= CHANGELOG_DEFMASK;
+
+       return 0;
+}
+
+int mdd_changelog_recalc_mask(const struct lu_env *env, struct mdd_device *mdd)
+{
+       struct llog_ctxt *ctxt;
+       struct mdd_changelog_recalc_mask_data mcrm = {
+               .mcrm_mdd = mdd,
+               .mcrm_mask = mdd->mdd_cl.mc_proc_mask,
+       };
+       int rc;
+
+       ENTRY;
+
+       ctxt = llog_get_context(mdd2obd_dev(mdd),
+                               LLOG_CHANGELOG_USER_ORIG_CTXT);
+       if (!ctxt)
+               RETURN(-ENXIO);
+
+       if (!(ctxt->loc_handle->lgh_hdr->llh_flags & LLOG_F_IS_CAT))
+               GOTO(out, rc = -ENXIO);
+
+       rc = llog_cat_process(env, ctxt->loc_handle,
+                             mdd_changelog_recalc_mask_cb, &mcrm, 0, 0);
+       if (rc < 0)
+               CWARN("%s: failed user changelog processing: rc = %d\n",
+                     mdd2obd_dev(mdd)->obd_name, rc);
+
+       spin_lock(&mdd->mdd_cl.mc_user_lock);
+       CDEBUG(D_INFO, "%s: recalc changelog mask: %#x -> %#x\n",
+              mdd2obd_dev(mdd)->obd_name, mdd->mdd_cl.mc_current_mask,
+              mcrm.mcrm_mask);
+       mdd->mdd_cl.mc_current_mask = mcrm.mcrm_mask;
+       spin_unlock(&mdd->mdd_cl.mc_user_lock);
+
+       EXIT;
 out:
-        OBD_FREE_PTR(rec);
-        llog_ctxt_put(ctxt);
-        RETURN(rc);
+       llog_ctxt_put(ctxt);
+
+       return rc;
 }
 
 struct mdd_changelog_user_purge {
@@ -1623,24 +1851,23 @@ static int mdd_changelog_user_purge_cb(const struct lu_env *env,
                                       struct llog_handle *llh,
                                       struct llog_rec_hdr *hdr, void *data)
 {
-       struct llog_changelog_user_rec  *rec;
-       struct mdd_changelog_user_purge *mcup = data;
-       struct llog_cookie               cookie;
-       int                              rc;
+       struct llog_changelog_user_rec2 *rec;
+       struct mdd_changelog_user_purge *mcup = data;
+       struct llog_cookie cookie;
+       int rc;
 
        ENTRY;
 
        if ((llh->lgh_hdr->llh_flags & LLOG_F_IS_PLAIN) == 0)
                RETURN(-ENXIO);
 
-       rec = container_of(hdr, struct llog_changelog_user_rec, cur_hdr);
+       rec = container_of(hdr, typeof(*rec), cur_hdr);
 
        mcup->mcup_usercount++;
 
        if (rec->cur_id != mcup->mcup_id) {
                /* truncate to the lowest endrec that is not this user */
-               mcup->mcup_minrec = min(mcup->mcup_minrec,
-                                       rec->cur_endrec);
+               mcup->mcup_minrec = min(mcup->mcup_minrec, rec->cur_endrec);
                RETURN(0);
        }
 
@@ -1732,6 +1959,7 @@ struct mdd_changelog_user_clear {
        __u64 mcuc_minrec;
        __u32 mcuc_id;
        bool mcuc_flush;
+       struct mdd_device *mcuc_mdd;
 };
 
 /**
@@ -1748,8 +1976,10 @@ static int mdd_changelog_clear_cb(const struct lu_env *env,
                                  struct llog_rec_hdr *hdr,
                                  void *data)
 {
-       struct llog_changelog_user_rec *rec;
+       struct llog_changelog_user_rec2 *rec;
        struct mdd_changelog_user_clear *mcuc = data;
+       char user_name[CHANGELOG_USER_NAMELEN_FULL];
+       struct mdd_device *mdd = mcuc->mcuc_mdd;
        int rc;
 
        ENTRY;
@@ -1757,8 +1987,7 @@ static int mdd_changelog_clear_cb(const struct lu_env *env,
        if ((llh->lgh_hdr->llh_flags & LLOG_F_IS_PLAIN) == 0)
                RETURN(-ENXIO);
 
-       rec = container_of(hdr, struct llog_changelog_user_rec, cur_hdr);
-
+       rec = container_of(hdr, typeof(*rec), cur_hdr);
        /* Does the changelog id match the requested id? */
        if (rec->cur_id != mcuc->mcuc_id) {
                mcuc->mcuc_minrec = min(mcuc->mcuc_minrec,
@@ -1768,9 +1997,14 @@ static int mdd_changelog_clear_cb(const struct lu_env *env,
 
        /* cur_endrec is the oldest purgeable record, make sure we're newer */
        if (rec->cur_endrec > mcuc->mcuc_endrec) {
-               CDEBUG(D_IOCTL, "Request %llu out of range: %llu\n",
-                      mcuc->mcuc_endrec, rec->cur_endrec);
-               RETURN(-EINVAL);
+               rc = -EINVAL;
+               CDEBUG(D_IOCTL,
+                      "%s: request %llu > endrec %llu for user %s: rc = %d\n",
+                      mdd2obd_dev(mdd)->obd_name,
+                      mcuc->mcuc_endrec, rec->cur_endrec,
+                      mdd_chlg_username(rec, user_name, sizeof(user_name)),
+                      rc);
+               RETURN(rc);
        }
 
        /* Flag that we've met all the range and user checks.
@@ -1784,8 +2018,10 @@ static int mdd_changelog_clear_cb(const struct lu_env *env,
 
        mcuc->mcuc_flush = true;
 
-       CDEBUG(D_IOCTL, "Rewriting changelog user %u endrec to %llu\n",
-              mcuc->mcuc_id, rec->cur_endrec);
+       CDEBUG(D_IOCTL, "%s: rewriting changelog user %s endrec = %llu\n",
+              mdd2obd_dev(mdd)->obd_name,
+              mdd_chlg_username(rec, user_name, sizeof(user_name)),
+              rec->cur_endrec);
 
        /* Update the endrec */
        rc = llog_write(env, llh, hdr, hdr->lrh_index);
@@ -1804,6 +2040,7 @@ static int mdd_changelog_clear(const struct lu_env *env,
                .mcuc_id = id,
                .mcuc_minrec = endrec,
                .mcuc_flush = false,
+               .mcuc_mdd = mdd,
        };
        struct llog_ctxt *ctxt;
        __u64 start_rec;
@@ -1873,6 +2110,51 @@ out:
        return rc;
 }
 
+static int mdd_changelog_user_deregister(const struct lu_env *env,
+                                      struct mdd_device *mdd, int *id,
+                                      const char *name)
+{
+       struct llog_ctxt *ctxt;
+       struct mdd_changelog_name_check_data mcnc = {
+               .mcnc_name = name,
+               .mcnc_id = 0,
+       };
+       int rc;
+
+       ENTRY;
+
+       if (name) {
+               ctxt = llog_get_context(mdd2obd_dev(mdd),
+                                       LLOG_CHANGELOG_USER_ORIG_CTXT);
+               if (!ctxt)
+                       RETURN(-ENXIO);
+
+               rc = llog_cat_process(env, ctxt->loc_handle,
+                             mdd_changelog_name_check_cb, &mcnc, 0, 0);
+               llog_ctxt_put(ctxt);
+
+               if (rc != -EEXIST) {
+                       CDEBUG(D_IOCTL, "%s: no entry for username %s\n",
+                              mdd2obd_dev(mdd)->obd_name, name);
+                       RETURN(-ENOENT);
+               }
+               *id = mcnc.mcnc_id;
+       }
+
+       /* explicitly clear changelog first, to protect from crash in
+        * the middle of purge that would lead to unregistered consumer
+        * but pending changelog entries
+        */
+       rc = mdd_changelog_clear(env, mdd, *id, 0);
+       if (!rc)
+               rc = mdd_changelog_user_purge(env, mdd, *id);
+
+       /* recalc changelog current mask */
+       mdd_changelog_recalc_mask(env, mdd);
+
+       RETURN(rc);
+}
+
 /** mdd_iocontrol
  * May be called remotely from mdt_iocontrol_handle or locally from
  * mdt_iocontrol. Data may be freeform - remote handling doesn't enforce
@@ -1920,10 +2202,6 @@ static int mdd_iocontrol(const struct lu_env *env, struct md_device *m,
        }
 
        /* Below ioctls use obd_ioctl_data */
-       if (len != sizeof(*data)) {
-               CERROR("Bad ioctl size %d\n", len);
-               RETURN(-EINVAL);
-       }
        if (data->ioc_version != OBD_IOCTL_VERSION) {
                CERROR("Bad magic %x != %x\n", data->ioc_version,
                       OBD_IOCTL_VERSION);
@@ -1935,21 +2213,17 @@ static int mdd_iocontrol(const struct lu_env *env, struct md_device *m,
                if (unlikely(!barrier_entry(mdd->mdd_bottom)))
                        RETURN(-EINPROGRESS);
 
-               rc = mdd_changelog_user_register(env, mdd, &data->ioc_u32_1);
+               rc = mdd_changelog_user_register(env, mdd, &data->ioc_u32_1,
+                                                data->ioc_inlbuf1,
+                                                data->ioc_inlbuf2);
                barrier_exit(mdd->mdd_bottom);
                break;
        case OBD_IOC_CHANGELOG_DEREG:
                if (unlikely(!barrier_entry(mdd->mdd_bottom)))
                        RETURN(-EINPROGRESS);
 
-               /* explicitly clear changelog first, to protect from crash in
-                * the middle of purge that would lead to unregistered consumer
-                * but pending changelog entries
-                */
-               rc = mdd_changelog_clear(env, mdd, data->ioc_u32_1, 0);
-               if (!rc)
-                       rc = mdd_changelog_user_purge(env,
-                                                     mdd, data->ioc_u32_1);
+               rc = mdd_changelog_user_deregister(env, mdd, &data->ioc_u32_1,
+                                                  data->ioc_inlbuf1);
 
                barrier_exit(mdd->mdd_bottom);
                break;
index dc0af8f..ca63b9c 100644 (file)
@@ -95,7 +95,8 @@
 struct mdd_changelog {
        spinlock_t              mc_lock;        /* for index */
        int                     mc_flags;
-       int                     mc_mask;
+       __u32                   mc_proc_mask; /* per-server mask set via parameters */
+       __u32                   mc_current_mask; /* combined global+users */
        __u64                   mc_index;
        ktime_t                 mc_starttime;
        spinlock_t              mc_user_lock;
@@ -434,6 +435,10 @@ int mdd_generic_thread_start(struct mdd_generic_thread *thread,
 void mdd_generic_thread_stop(struct mdd_generic_thread *thread);
 int mdd_changelog_user_purge(const struct lu_env *env, struct mdd_device *mdd,
                             __u32 id);
+char *mdd_chlg_username(struct llog_changelog_user_rec2 *rec, char *buf,
+                       size_t len);
+__u32 mdd_chlg_usermask(struct llog_changelog_user_rec2 *rec);
+int mdd_changelog_recalc_mask(const struct lu_env *env, struct mdd_device *mdd);
 
 /* mdd_prepare.c */
 int mdd_compat_fixes(const struct lu_env *env, struct mdd_device *mdd);
@@ -840,7 +845,7 @@ static inline bool mdd_changelog_enabled(const struct lu_env *env,
        const struct lu_ucred *uc;
 
        if ((mdd->mdd_cl.mc_flags & CLM_ON) &&
-           (mdd->mdd_cl.mc_mask & BIT(type))) {
+           (mdd->mdd_cl.mc_current_mask & BIT(type))) {
                uc = lu_ucred_check(env);
 
                return uc != NULL ? uc->uc_enable_audit : true;
index 2865fbd..120ec92 100644 (file)
@@ -83,13 +83,28 @@ static ssize_t atime_diff_store(struct kobject *kobj,
 LUSTRE_RW_ATTR(atime_diff);
 
 /**** changelogs ****/
+static int mdd_changelog_current_mask_seq_show(struct seq_file *m, void *data)
+{
+       struct mdd_device *mdd = m->private;
+       int i = 0;
+
+       while (i < CL_LAST) {
+               if (mdd->mdd_cl.mc_current_mask & BIT(i))
+                       seq_printf(m, "%s ", changelog_type2str(i));
+               i++;
+       }
+       seq_putc(m, '\n');
+       return 0;
+}
+LDEBUGFS_SEQ_FOPS_RO(mdd_changelog_current_mask);
+
 static int mdd_changelog_mask_seq_show(struct seq_file *m, void *data)
 {
        struct mdd_device *mdd = m->private;
        int i = 0;
 
        while (i < CL_LAST) {
-               if (mdd->mdd_cl.mc_mask & BIT(i))
+               if (mdd->mdd_cl.mc_proc_mask & BIT(i))
                        seq_printf(m, "%s ", changelog_type2str(i));
                i++;
        }
@@ -105,6 +120,9 @@ mdd_changelog_mask_seq_write(struct file *file, const char __user *buffer,
        struct mdd_device *mdd = m->private;
        char *kernbuf;
        int rc;
+       int oldmask = mdd->mdd_cl.mc_proc_mask;
+       int newmask = oldmask;
+
        ENTRY;
 
        if (count >= PAGE_SIZE)
@@ -116,10 +134,48 @@ mdd_changelog_mask_seq_write(struct file *file, const char __user *buffer,
                GOTO(out, rc = -EFAULT);
        kernbuf[count] = 0;
 
-       rc = cfs_str2mask(kernbuf, changelog_type2str, &mdd->mdd_cl.mc_mask,
+       /* if the new mask is relative and proc mask is minimal then assume
+        * it is relative to DEFMASK, otherwise apply new mask on the current
+        * proc mask.
+        */
+       if (oldmask == CHANGELOG_MINMASK) {
+               char *str = kernbuf;
+
+               while (isspace(*str))
+                       str++;
+               if (*str == '+' || *str == '-')
+                       newmask = CHANGELOG_DEFMASK;
+       }
+
+       rc = cfs_str2mask(kernbuf, changelog_type2str, &newmask,
                          CHANGELOG_MINMASK, CHANGELOG_ALLMASK);
-       if (rc == 0)
+       if (rc)
+               GOTO(out, rc);
+
+       mdd->mdd_cl.mc_proc_mask = newmask;
+
+       /* if mask keeps all bits from oldmask then just extend the current
+        * mask, otherwise the current mask should be recalculated through
+        * all user masks.
+        */
+       if ((newmask & oldmask) == oldmask) {
+               spin_lock(&mdd->mdd_cl.mc_user_lock);
+               mdd->mdd_cl.mc_current_mask |= newmask;
+               spin_unlock(&mdd->mdd_cl.mc_user_lock);
+       } else {
+               struct lu_env env;
+
+               rc = lu_env_init(&env, LCT_LOCAL);
+               if (rc)
+                       GOTO(out, rc);
+
+               mdd_changelog_recalc_mask(&env, mdd);
+               lu_env_fini(&env);
+       }
+
+       if (!rc)
                rc = count;
+
 out:
        OBD_FREE(kernbuf, PAGE_SIZE);
        return rc;
@@ -130,16 +186,34 @@ static int lprocfs_changelog_users_cb(const struct lu_env *env,
                                      struct llog_handle *llh,
                                      struct llog_rec_hdr *hdr, void *data)
 {
-       struct llog_changelog_user_rec *rec;
+       struct llog_changelog_user_rec2 *rec;
        struct seq_file *m = data;
+       char user_name[CHANGELOG_USER_NAMELEN_FULL];
 
        LASSERT(llh->lgh_hdr->llh_flags & LLOG_F_IS_PLAIN);
 
-       rec = (struct llog_changelog_user_rec *)hdr;
+       rec = container_of(hdr, typeof(*rec), cur_hdr);
+
+       seq_printf(m, "%-24s %10llu (%u)",
+                  mdd_chlg_username(rec, user_name, sizeof(user_name)),
+                  rec->cur_endrec,
+                  (__u32)ktime_get_real_seconds() - rec->cur_time);
+       if (mdd_chlg_usermask(rec)) {
+               char *sep = "";
+               int i;
+
+               seq_puts(m, " mask=");
+               for (i = 0; i < CL_LAST; i++) {
+                       if (!(mdd_chlg_usermask(rec) & BIT(i)))
+                               continue;
+                       if (*sep)
+                               seq_puts(m, sep);
+                       seq_puts(m, changelog_type2str(i));
+                       sep = ",";
+               }
+       }
+       seq_puts(m, "\n");
 
-       seq_printf(m, CHANGELOG_USER_PREFIX"%-3d %llu (%u)\n",
-                  rec->cur_id, rec->cur_endrec, (__u32)get_seconds() -
-                                                rec->cur_time);
        return 0;
 }
 
@@ -167,8 +241,8 @@ static int mdd_changelog_users_seq_show(struct seq_file *m, void *data)
        cur = mdd->mdd_cl.mc_index;
        spin_unlock(&mdd->mdd_cl.mc_lock);
 
-       seq_printf(m, "current index: %llu\n", cur);
-       seq_printf(m, "%-5s %s %s\n", "ID", "index", "(idle seconds)");
+       seq_printf(m, "current_index: %llu\n", cur);
+       seq_printf(m, "%-24s %10s %s %s\n", "ID", "index", "(idle)", "mask");
 
        llog_cat_process(&env, ctxt->loc_handle, lprocfs_changelog_users_cb,
                         m, 0, 0);
@@ -646,6 +720,8 @@ LUSTRE_RW_ATTR(append_pool);
 static struct ldebugfs_vars ldebugfs_mdd_obd_vars[] = {
        { .name =       "changelog_mask",
          .fops =       &mdd_changelog_mask_fops        },
+       { .name =       "changelog_current_mask",
+         .fops =       &mdd_changelog_current_mask_fops },
        { .name =       "changelog_users",
          .fops =       &mdd_changelog_users_fops       },
        { .name =       "lfsck_namespace",
index 3689a90..c56392e 100644 (file)
@@ -1088,7 +1088,7 @@ static int mdd_attr_set_changelog(const struct lu_env *env,
        bits |= (valid & LA_MTIME) ? BIT(CL_MTIME) : 0;
        bits |= (valid & LA_CTIME) ? BIT(CL_CTIME) : 0;
        bits |= (valid & LA_ATIME) ? BIT(CL_ATIME) : 0;
-       bits = bits & mdd->mdd_cl.mc_mask;
+       bits = bits & mdd->mdd_cl.mc_current_mask;
        /* This is an implementation limit rather than a protocol limit */
        BUILD_BUG_ON(CL_LAST > sizeof(int) * 8);
        if (bits == 0)
@@ -3260,7 +3260,7 @@ static int mdd_open(const struct lu_env *env, struct md_object *obj,
 
        rc = mdd_open_sanity_check(env, mdd_obj, attr, open_flags,
                                   spec->no_create);
-       if ((rc == -EACCES) && (mdd->mdd_cl.mc_mask & BIT(CL_DN_OPEN)))
+       if ((rc == -EACCES) && (mdd->mdd_cl.mc_current_mask & BIT(CL_DN_OPEN)))
                type = CL_DN_OPEN;
        else if (rc != 0)
                GOTO(out, rc);
@@ -3498,10 +3498,11 @@ out:
         * this is not a big deal if we have a CL_CLOSE entry with no matching
         * CL_OPEN. Plus Changelogs mask may not change often.
         */
-       if (((!(mdd->mdd_cl.mc_mask & BIT(CL_OPEN)) &&
+       if (((!(mdd->mdd_cl.mc_current_mask & BIT(CL_OPEN)) &&
              (open_flags & (MDS_FMODE_WRITE | MDS_OPEN_APPEND |
                             MDS_OPEN_TRUNC))) ||
-            ((mdd->mdd_cl.mc_mask & BIT(CL_OPEN)) && last_close_by_uid)) &&
+            ((mdd->mdd_cl.mc_current_mask & BIT(CL_OPEN)) &&
+             last_close_by_uid)) &&
            !(ma->ma_valid & MA_FLAGS && ma->ma_attr_flags & MDS_RECOV_OPEN)) {
                if (handle == NULL) {
                        handle = mdd_trans_create(env, mdo2mdd(obj));
index c0e128c..0520052 100644 (file)
@@ -77,7 +77,7 @@ struct mdd_changelog_gc {
        __u32 mcgc_id;
        __u32 mcgc_maxtime;
        __u64 mcgc_maxindexes;
-       bool mcgc_found;
+       char mcgc_name[CHANGELOG_USER_NAMELEN_FULL];
 };
 
 /* return first registered ChangeLog user idle since too long
@@ -86,16 +86,16 @@ static int mdd_changelog_gc_cb(const struct lu_env *env,
                               struct llog_handle *llh,
                               struct llog_rec_hdr *hdr, void *data)
 {
-       struct llog_changelog_user_rec *rec;
-       struct mdd_changelog_gc *mcgc = (struct mdd_changelog_gc *)data;
+       struct llog_changelog_user_rec2 *rec;
+       struct mdd_changelog_gc *mcgc = data;
        struct mdd_device *mdd = mcgc->mcgc_mdd;
+
        ENTRY;
 
        if ((llh->lgh_hdr->llh_flags & LLOG_F_IS_PLAIN) == 0)
                RETURN(-ENXIO);
 
-       rec = container_of(hdr, struct llog_changelog_user_rec,
-                          cur_hdr);
+       rec = container_of(hdr, typeof(*rec), cur_hdr);
 
        /* find oldest idle user, based on last record update/cancel time (new
         * behavior), or for old user records, last record index vs current
@@ -103,9 +103,6 @@ static int mdd_changelog_gc_cb(const struct lu_env *env,
         * first as we assume they could be idle since longer
         */
        if (rec->cur_time != 0) {
-               /* FIXME !!!! cur_time is a timestamp but only 32 bit in
-                * in size. This is not 2038 safe !!!!
-                */
                u32 time_now = (u32)ktime_get_real_seconds();
                timeout_t time_out = rec->cur_time +
                                     mdd->mdd_changelog_max_idle_time;
@@ -119,7 +116,8 @@ static int mdd_changelog_gc_cb(const struct lu_env *env,
                    mcgc->mcgc_maxindexes == 0) {
                        mcgc->mcgc_maxtime = idle_time;
                        mcgc->mcgc_id = rec->cur_id;
-                       mcgc->mcgc_found = true;
+                       mdd_chlg_username(rec, mcgc->mcgc_name,
+                                         sizeof(mcgc->mcgc_name));
                }
        } else {
                /* old user record with no idle time stamp, so use empirical
@@ -134,7 +132,8 @@ static int mdd_changelog_gc_cb(const struct lu_env *env,
                    idle_indexes > mcgc->mcgc_maxindexes) {
                        mcgc->mcgc_maxindexes = idle_indexes;
                        mcgc->mcgc_id = rec->cur_id;
-                       mcgc->mcgc_found = true;
+                       mdd_chlg_username(rec, mcgc->mcgc_name,
+                                         sizeof(mcgc->mcgc_name));
                }
 
        }
@@ -144,16 +143,11 @@ static int mdd_changelog_gc_cb(const struct lu_env *env,
 /* recover space from long-term inactive ChangeLog users */
 static int mdd_chlg_garbage_collect(void *data)
 {
-       struct mdd_device *mdd = (struct mdd_device *)data;
-       struct lu_env             *env = NULL;
-       int                        rc;
+       struct mdd_device *mdd = data;
+       struct lu_env *env = NULL;
+       int rc;
        struct llog_ctxt *ctxt;
-       struct mdd_changelog_gc mcgc = {
-               .mcgc_mdd = mdd,
-               .mcgc_found = false,
-               .mcgc_maxtime = 0,
-               .mcgc_maxindexes = 0,
-       };
+
        ENTRY;
 
        mdd->mdd_cl.mc_gc_task = current;
@@ -170,6 +164,12 @@ static int mdd_chlg_garbage_collect(void *data)
                GOTO(out, rc);
 
        for (;;) {
+               struct mdd_changelog_gc mcgc = {
+                       .mcgc_mdd = mdd,
+                       .mcgc_maxtime = 0,
+                       .mcgc_maxindexes = 0,
+               };
+
                ctxt = llog_get_context(mdd2obd_dev(mdd),
                                        LLOG_CHANGELOG_USER_ORIG_CTXT);
                if (ctxt == NULL ||
@@ -178,30 +178,23 @@ static int mdd_chlg_garbage_collect(void *data)
 
                rc = llog_cat_process(env, ctxt->loc_handle,
                                      mdd_changelog_gc_cb, &mcgc, 0, 0);
-               if (rc != 0 || mcgc.mcgc_found == false)
+               if (rc != 0 || !mcgc.mcgc_name[0])
                        break;
                llog_ctxt_put(ctxt);
 
                if (mcgc.mcgc_maxindexes != 0)
-                       CWARN("%s: Force deregister of ChangeLog user cl%d "
-                             "idle with more than %llu unprocessed records\n",
-                             mdd2obd_dev(mdd)->obd_name, mcgc.mcgc_id,
+                       CWARN("%s: Force deregister of ChangeLog user %s idle with more than %llu unprocessed records\n",
+                             mdd2obd_dev(mdd)->obd_name, mcgc.mcgc_name,
                              mcgc.mcgc_maxindexes);
                else
-                       CWARN("%s: Force deregister of ChangeLog user cl%d "
-                             "idle since more than %us\n",
-                             mdd2obd_dev(mdd)->obd_name, mcgc.mcgc_id,
+                       CWARN("%s: Force deregister of ChangeLog user %s idle since more than %us\n",
+                             mdd2obd_dev(mdd)->obd_name, mcgc.mcgc_name,
                              mcgc.mcgc_maxtime);
 
                mdd_changelog_user_purge(env, mdd, mcgc.mcgc_id);
 
                if (kthread_should_stop())
                        GOTO(out_env, rc = 0);
-
-               /* try again to search for another candidate */
-               mcgc.mcgc_found = false;
-               mcgc.mcgc_maxtime = 0;
-               mcgc.mcgc_maxindexes = 0;
        }
 
 out_ctxt:
index 307ce65..67c0ce6 100644 (file)
@@ -202,21 +202,28 @@ void lustre_swab_llog_rec(struct llog_rec_hdr *rec)
                 * Because the tail follows a variable-length structure we need
                 * to compute its location at runtime
                 */
-               tail = (struct llog_rec_tail *)((char *)&cr->cr +
-                                               changelog_rec_size(&cr->cr) +
-                                               cr->cr.cr_namelen);
+               tail = (struct llog_rec_tail *)((char *)rec +
+                                               rec->lrh_len - sizeof(*tail));
                break;
        }
 
        case CHANGELOG_USER_REC:
+       case CHANGELOG_USER_REC2:
        {
-               struct llog_changelog_user_rec *cur =
-                       (struct llog_changelog_user_rec *)rec;
+               struct llog_changelog_user_rec2 *cur =
+                       (struct llog_changelog_user_rec2 *)rec;
 
                __swab32s(&cur->cur_id);
                __swab64s(&cur->cur_endrec);
                __swab32s(&cur->cur_time);
-               tail = &cur->cur_tail;
+               if (cur->cur_hdr.lrh_type == CHANGELOG_USER_REC2) {
+                       __swab32s(&cur->cur_mask);
+                       BUILD_BUG_ON(offsetof(typeof(*cur), cur_padding1) == 0);
+                       BUILD_BUG_ON(offsetof(typeof(*cur), cur_padding2) == 0);
+                       BUILD_BUG_ON(offsetof(typeof(*cur), cur_padding3) == 0);
+               }
+               tail = (struct llog_rec_tail *)((char *)rec +
+                                               rec->lrh_len - sizeof(*tail));
                break;
        }
 
index 957e2a0..ef0d146 100644 (file)
@@ -966,7 +966,7 @@ static union {
        struct llog_setattr64_rec_v2    lsr64_v2; /* MDS_SETATTR64_REC */
        struct llog_size_change_rec     lscr;  /* OST_SZ_REC */
        struct llog_changelog_rec       lcr;   /* CHANGELOG_REC */
-       struct llog_changelog_user_rec  lcur;  /* CHANGELOG_USER_REC */
+       struct llog_changelog_user_rec2 lcur;  /* CHANGELOG_USER_REC2 */
        struct llog_gen_rec             lgr;   /* LLOG_GEN_REC */
 } llog_records;
 
@@ -1141,10 +1141,10 @@ static int llog_test_7(const struct lu_env *env, struct obd_device *obd)
                GOTO(out, rc);
        }
 
-       CWARN("7f: test llog_changelog_user_rec\n");
+       CWARN("7f: test llog_changelog_user_rec2\n");
        llog_records.lcur.cur_hdr.lrh_len = sizeof(llog_records.lcur);
        llog_records.lcur.cur_tail.lrt_len = sizeof(llog_records.lcur);
-       llog_records.lcur.cur_hdr.lrh_type = CHANGELOG_USER_REC;
+       llog_records.lcur.cur_hdr.lrh_type = CHANGELOG_USER_REC2;
 
        rc = llog_test_7_sub(env, ctxt);
        if (rc) {
@@ -1406,7 +1406,7 @@ static int llog_test_9(const struct lu_env *env, struct obd_device *obd)
                GOTO(out, rc);
        }
 
-       CWARN("9d: test llog_changelog_user_rec\n");
+       CWARN("9d: test llog_changelog_user_rec2\n");
        llog_records.lcur.cur_hdr.lrh_len = sizeof(llog_records.lcur);
        llog_records.lcur.cur_tail.lrt_len = sizeof(llog_records.lcur);
        llog_records.lcur.cur_hdr.lrh_type = CHANGELOG_USER_REC;
index a843b29..ef54f00 100644 (file)
@@ -3894,18 +3894,19 @@ void lustre_assert_wire_constants(void)
                 (long long)(int)offsetof(struct llog_logid, lgl_ogen));
        LASSERTF((int)sizeof(((struct llog_logid *)0)->lgl_ogen) == 4, "found %lld\n",
                 (long long)(int)sizeof(((struct llog_logid *)0)->lgl_ogen));
-       BUILD_BUG_ON(OST_SZ_REC != 274730752);
-       BUILD_BUG_ON(MDS_UNLINK_REC != 274801668);
-       BUILD_BUG_ON(MDS_UNLINK64_REC != 275325956);
-       BUILD_BUG_ON(MDS_SETATTR64_REC != 275325953);
-       BUILD_BUG_ON(OBD_CFG_REC != 274857984);
-       BUILD_BUG_ON(LLOG_GEN_REC != 274989056);
-       BUILD_BUG_ON(CHANGELOG_REC != 275120128);
-       BUILD_BUG_ON(CHANGELOG_USER_REC != 275185664);
-       BUILD_BUG_ON(HSM_AGENT_REC != 275251200);
-       BUILD_BUG_ON(UPDATE_REC != 275382272);
-       BUILD_BUG_ON(LLOG_HDR_MAGIC != 275010873);
-       BUILD_BUG_ON(LLOG_LOGID_MAGIC != 275010875);
+       BUILD_BUG_ON(OST_SZ_REC != 0x10600f00);
+       BUILD_BUG_ON(MDS_UNLINK_REC != 0x10612404);
+       BUILD_BUG_ON(MDS_UNLINK64_REC != 0x10692404);
+       BUILD_BUG_ON(MDS_SETATTR64_REC != 0x10692401);
+       BUILD_BUG_ON(OBD_CFG_REC != 0x10620000);
+       BUILD_BUG_ON(LLOG_GEN_REC != 0x10640000);
+       BUILD_BUG_ON(CHANGELOG_REC != 0x10660000);
+       BUILD_BUG_ON(CHANGELOG_USER_REC != 0x10670000);
+       BUILD_BUG_ON(CHANGELOG_USER_REC2 != 0x10670002);
+       BUILD_BUG_ON(HSM_AGENT_REC != 0x10680000);
+       BUILD_BUG_ON(UPDATE_REC != 0x106a0000);
+       BUILD_BUG_ON(LLOG_HDR_MAGIC != 0x10645539);
+       BUILD_BUG_ON(LLOG_LOGID_MAGIC != 0x1064553b);
 
        /* Checks for struct llog_catid */
        LASSERTF((int)sizeof(struct llog_catid) == 32, "found %lld\n",
index 3649b61..7e71eba 100755 (executable)
@@ -15296,8 +15296,6 @@ test_160a() {
        ln -s $DIR/$tdir/pics/2008/portland.jpg $DIR/$tdir/pics/desktop.jpg
        rm $DIR/$tdir/pics/desktop.jpg
 
-       changelog_dump | tail -10
-
        echo "verifying changelog mask"
        changelog_chmask "-MKDIR"
        changelog_chmask "-CLOSE"
@@ -15311,7 +15309,6 @@ test_160a() {
        test_mkdir -p $DIR/$tdir/pics/2008/sofia                # mkdir 1
        echo "zzzzzz" > $DIR/$tdir/pics/zach/file               # open 3
 
-       changelog_dump | tail -10
        MKDIRS=$(changelog_dump | grep -c "MKDIR")
        CLOSES=$(changelog_dump | grep -c "CLOSE")
        [ $MKDIRS -eq 1 ] || error "MKDIR changelog mask count $MKDIRS != 1"
@@ -15374,10 +15371,10 @@ test_160a() {
                error "User '$cl_user' still in changelog_users"
 
        # lctl get_param -n mdd.*.changelog_users
-       # current index: 144
+       # current_index: 144
        # ID    index (idle seconds)
-       # cl3   144 (2)
-       if ! changelog_users $SINGLEMDS | grep "^cl"; then
+       # cl3   144   (2) mask=<list>
+       if [ -z "$(changelog_users $SINGLEMDS | grep -v current.index)" ]; then
                # this is the normal case where all users were deregistered
                # make sure no new records are added when no users are present
                local last_rec1=$(changelog_users $SINGLEMDS |
@@ -16196,6 +16193,72 @@ test_160n() {
 }
 run_test 160n "Changelog destroy race"
 
+test_160o() {
+       local mdt="$(facet_svc $SINGLEMDS)"
+
+       [[ $PARALLEL != "yes" ]] || skip "skip parallel run"
+       remote_mds_nodsh && skip "remote MDS with nodsh"
+       [ $MDS1_VERSION -ge $(version_code 2.14.52) ] ||
+               skip "Need MDS version at least 2.14.52"
+
+       changelog_register --user test_160o -m unlnk+close+open ||
+               error "changelog_register failed"
+       # drop server mask so it doesn't interfere
+       do_facet $SINGLEMDS $LCTL --device $mdt \
+                               changelog_register -u "Tt3_-#" &&
+               error "bad symbols in name should fail"
+
+       do_facet $SINGLEMDS $LCTL --device $mdt \
+                               changelog_register -u test_160o &&
+               error "the same name registration should fail"
+
+       do_facet $SINGLEMDS $LCTL --device $mdt \
+                       changelog_register -u test_160toolongname &&
+               error "too long name registration should fail"
+
+       changelog_chmask "MARK+HSM"
+       lctl get_param mdd.*.changelog*mask
+       local cl_user="${CL_USERS[$SINGLEMDS]%% *}"
+       changelog_users $SINGLEMDS | grep -q $cl_user ||
+               error "User $cl_user not found in changelog_users"
+       #verify username
+       echo $cl_user | grep -q test_160o ||
+               error "User $cl_user has no specific name 'test160o'"
+
+       # change something
+       changelog_clear 0 || error "changelog_clear failed"
+       # generate some changelog records to accumulate on MDT0
+       test_mkdir -p -i0 -c1 $DIR/$tdir || error "test_mkdir $tdir failed"
+       touch $DIR/$tdir/$tfile                 # open 1
+
+       OPENS=$(changelog_dump | grep -c "OPEN")
+       [[ $OPENS -eq 1 ]] || error "OPEN changelog mask count $OPENS != 1"
+
+       # must be no MKDIR it wasn't set as user mask
+       MKDIR=$(changelog_dump | grep -c "MKDIR")
+       [[ $MKDIR -eq 0 ]] || error "MKDIR changelog mask found $MKDIR > 0"
+
+       oldmask=$(do_facet $SINGLEMDS $LCTL get_param \
+                               mdd.$mdt.changelog_current_mask -n)
+       # register maskless user
+       changelog_register || error "changelog_register failed"
+       # effective mask should be not changed because it is not minimal
+       mask=$(do_facet $SINGLEMDS $LCTL get_param \
+                               mdd.$mdt.changelog_current_mask -n)
+       [[ $mask == $oldmask ]] || error "mask was changed: $mask vs $oldmask"
+       # set server mask to minimal value
+       changelog_chmask "MARK"
+       # check effective mask again, should be treated as DEFMASK now
+       mask=$(do_facet $SINGLEMDS $LCTL get_param \
+                               mdd.$mdt.changelog_current_mask -n)
+       [[ $mask == *"HLINK"* ]] || error "mask is not DEFMASK as expected"
+
+       do_facet $SINGLEMDS $LCTL --device $mdt \
+                               changelog_deregister -u test_160o ||
+               error "cannot deregister by name"
+}
+run_test 160o "changelog user name and mask"
+
 test_160p() {
        remote_mds_nodsh && skip "remote MDS with nodsh" && return
        [[ $MDS1_VERSION -ge $(version_code 2.14.51) ]] ||
index 6566c04..f75aaea 100755 (executable)
@@ -9444,8 +9444,8 @@ changelog_register() {
                        error "$mdt: changelog_mask=+hsm failed: $?"
 
                local cl_user
-               cl_user=$(do_facet $facet \
-                                 $LCTL --device $mdt changelog_register -n) ||
+               cl_user=$(do_facet $facet $LCTL --device $mdt \
+                       changelog_register -n $@) ||
                        error "$mdt: register changelog user failed: $?"
                stack_trap "__changelog_deregister $facet $cl_user" EXIT
 
index 7e7bb7c..8f4db50 100644 (file)
@@ -388,10 +388,15 @@ command_t cmdlist[] = {
        {"===  Changelogs ==", NULL, 0, "changelog user management"},
        {"changelog_register", jt_changelog_register, 0,
         "register a new persistent changelog user, returns id\n"
-        "usage: --device <mdtname> changelog_register [-n]"},
+        "usage: --device <mdtname> changelog_register [--help|-h]\n"
+        "                                             [--mask|-m <[+|-]mask1[<,|+|->mask2...]>]\n"
+        "                                             [--nameonly|-n]\n"
+        "                                             [--user|-u <username>]"},
        {"changelog_deregister", jt_changelog_deregister, 0,
         "deregister an existing changelog user\n"
-        "usage: --device <mdtname> changelog_deregister <id>"},
+        "usage: --device <mdtname> changelog_deregister [<id>|cl<id>...]\n"
+        "                                               [--help|-h]\n"
+        "                                               [--user|-u <username>]\n"},
 
        /* Persistent Client Cache (PCC) commands */
        {"=== Persistent Client Cache ===", NULL, 0, "PCC user management"},
index fc83fa4..ebb2450 100644 (file)
@@ -309,6 +309,7 @@ int llapi_changelog_clear(const char *mdtname, const char *idstr,
        char dev_path[PATH_MAX];
        char cmd[64];
        size_t cmd_len = sizeof(cmd);
+       char *dashp, *clidp = NULL;
        int fd;
        int rc;
 
@@ -320,17 +321,26 @@ int llapi_changelog_clear(const char *mdtname, const char *idstr,
 
        chlg_dev_path(dev_path, sizeof(dev_path), mdtname);
 
-       rc = snprintf(cmd, cmd_len, "clear:%s:%lld", idstr, endrec);
-       if (rc >= sizeof(cmd))
-               return -EINVAL;
+       dashp = strchr(idstr, '-');
+       if (dashp) {
+               clidp = strndup(idstr, dashp - idstr);
+               if (!clidp)
+                       return -ENOMEM;
+       }
 
+       rc = snprintf(cmd, cmd_len, "clear:%s:%lld", dashp ? clidp : idstr,
+                     endrec);
+       if (rc >= sizeof(cmd)) {
+               rc = -EINVAL;
+               goto out;
+       }
        cmd_len = rc + 1;
 
        fd = open(dev_path, O_WRONLY);
        if (fd < 0) {
                rc = -errno;
                llapi_error(LLAPI_MSG_ERROR, rc, "cannot open '%s'", dev_path);
-               return rc;
+               goto out;
        }
 
        rc = write(fd, cmd, cmd_len);
@@ -345,6 +355,8 @@ int llapi_changelog_clear(const char *mdtname, const char *idstr,
 
 out_close:
        close(fd);
+out:
+       free(clidp);
        return rc;
 }
 
index 24903c8..bb9bec6 100644 (file)
@@ -958,6 +958,7 @@ static void print_records(struct llog_rec_hdr **recs,
                                            recs[i]);
                        break;
                case CHANGELOG_USER_REC:
+               case CHANGELOG_USER_REC2:
                        printf("changelog_user record id:0x%x\n",
                               __le32_to_cpu(recs[i]->lrh_id));
                        break;
index 9238659..83f1707 100644 (file)
@@ -5536,86 +5536,167 @@ int jt_get_obj_version(int argc, char **argv)
 #ifdef HAVE_SERVER_SUPPORT
 int jt_changelog_register(int argc, char **argv)
 {
-       struct obd_ioctl_data    data = { 0 };
-       char                     rawbuf[MAX_IOC_BUFLEN] = "";
-       char                    *buf = rawbuf;
-       char                    *device = lcfg_get_devname();
-       bool                     print_name_only = false;
-       int                      c;
-       int                      rc;
+       struct option long_opts[] = {
+       { .val = 'h', .name = "help", .has_arg = no_argument },
+       { .val = 'm', .name = "mask", .has_arg = required_argument },
+       { .val = 'n', .name = "nameonly", .has_arg = no_argument },
+       { .val = 'u', .name = "user", .has_arg = required_argument },
+       { .name = NULL } };
+       struct obd_ioctl_data data = { 0 };
+       char rawbuf[MAX_IOC_BUFLEN] = "";
+       char *buf = rawbuf;
+       char *device = lcfg_get_devname();
+       char *username = NULL, *usermask = NULL;
+       bool print_name_only = false;
+       int c;
+       int rc;
 
-       if (argc > 2)
+       if (cur_device < 0 || !device)
                return CMD_HELP;
 
-       while ((c = getopt(argc, argv, "hn")) >= 0) {
+       while ((c = getopt_long(argc, argv, "hm:nu:", long_opts, NULL)) != -1) {
                switch (c) {
+               case 'm':
+                       usermask = strdup(optarg);
+                       if (!usermask) {
+                               fprintf(stderr,
+                                       "error: %s: %s: cannot copy '%s'\n",
+                                       jt_cmdname(argv[0]), strerror(errno),
+                                       optarg);
+                               return -errno;
+                       }
+                       break;
                case 'n':
                        print_name_only = true;
                        break;
+               case 'u':
+                       username = strdup(optarg);
+                       if (!username) {
+                               fprintf(stderr,
+                                       "error: %s: %s: cannot copy '%s'\n",
+                                       jt_cmdname(argv[0]), strerror(errno),
+                                       optarg);
+                               return -errno;
+                       }
+                       break;
                case 'h':
                default:
+                       free(username);
+                       free(usermask);
                        return CMD_HELP;
                }
        }
 
-       if (cur_device < 0 || !device)
-               return CMD_HELP;
-
        data.ioc_dev = cur_device;
+       if (username) {
+               data.ioc_inlbuf1 = username;
+               data.ioc_inllen1 = strlen(username) + 1;
+       }
+
+       if (usermask) {
+               data.ioc_inlbuf2 = usermask;
+               data.ioc_inllen2 = strlen(usermask) + 1;
+       }
 
        rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
        if (rc < 0) {
                fprintf(stderr, "error: %s: cannot pack ioctl: %s\n",
                        jt_cmdname(argv[0]), strerror(-rc));
-               return rc;
+               goto out;
        }
-
        rc = l_ioctl(OBD_DEV_ID, OBD_IOC_CHANGELOG_REG, buf);
        if (rc < 0) {
                rc = -errno;
                fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
-                       strerror(-rc));
-               return rc;
+                       rc == -EEXIST ? "User exists" : strerror(-rc));
+               goto out;
        }
 
        llapi_ioctl_unpack(&data, buf, sizeof(rawbuf));
 
        if (data.ioc_u32_1 == 0) {
                fprintf(stderr, "received invalid userid!\n");
-               return -EPROTO;
+               rc = -EPROTO;
+               goto out;
        }
 
        if (print_name_only)
-               printf("%s%u\n", CHANGELOG_USER_PREFIX, data.ioc_u32_1);
+               printf("%s%u%s%s\n", CHANGELOG_USER_PREFIX, data.ioc_u32_1,
+                      username ? "-" : "", username ? : "");
        else
-               printf("%s: Registered changelog userid '%s%u'\n",
-                      device, CHANGELOG_USER_PREFIX, data.ioc_u32_1);
-
-       return 0;
+               printf("%s: Registered changelog userid '%s%u%s%s'\n",
+                      device, CHANGELOG_USER_PREFIX, data.ioc_u32_1,
+                      username ? "-" : "", username ? : "");
+out:
+       free(usermask);
+       free(username);
+       return rc;
 }
 
 int jt_changelog_deregister(int argc, char **argv)
 {
-       struct obd_ioctl_data    data = { 0 };
-       char                     rawbuf[MAX_IOC_BUFLEN] = "";
-       char                    *buf = rawbuf;
-       char                    *device = lcfg_get_devname();
-       int                      id;
-       int                      rc;
+       struct option long_opts[] = {
+       { .val = 'h', .name = "help", .has_arg = no_argument },
+       { .val = 'u', .name = "user", .has_arg = required_argument },
+       { .name = NULL } };
+       struct obd_ioctl_data data = { 0 };
+       char rawbuf[MAX_IOC_BUFLEN] = "";
+       char *buf = rawbuf;
+       char *device = lcfg_get_devname();
+       char *username = NULL;
+       int id = 0;
+       int c, rc;
 
-       if (argc != 2 || cur_device < 0 || !device)
+       if (cur_device < 0 || !device)
                return CMD_HELP;
 
-       rc = sscanf(argv[1], CHANGELOG_USER_PREFIX"%d", &id);
-       if (rc != 1 || id <= 0) {
-               fprintf(stderr,
-                       "error: %s: expected id of the form %s<num> got '%s'\n",
-                       jt_cmdname(argv[0]), CHANGELOG_USER_PREFIX, argv[1]);
-               return CMD_HELP;
+       optind = 1;
+       while ((c = getopt_long(argc, argv, "hu:", long_opts, NULL)) != -1) {
+               switch (c) {
+               case 'u':
+                       username = strdup(optarg);
+                       if (!username) {
+                               fprintf(stderr,
+                                       "error: %s: %s: cannot copy '%s'\n",
+                                       jt_cmdname(argv[0]), strerror(errno),
+                                       optarg);
+                               return -errno;
+                       }
+                       break;
+               case 'h':
+               default:
+                       free(username);
+                       return CMD_HELP;
+               }
        }
 
+       if (1 == optind) {
+               /* first check if pure ID was passed */
+               id = atoi(argv[optind]);
+               /* nameless cl<ID> format or cl<ID>-... format, only ID matters */
+               if (id == 0)
+                       sscanf(argv[optind], CHANGELOG_USER_PREFIX"%d", &id);
+
+               /* no valid ID was parsed */
+               if (id <= 0) {
+                       rc = -EINVAL;
+                       fprintf(stderr,
+                               "error: %s: expect <ID> or cl<ID>[-name] got '%s'\n",
+                               strerror(-rc), argv[optind]);
+                       return CMD_HELP;
+               }
+               optind++;
+       }
+
+       if (optind < argc)
+               return CMD_HELP;
+
        data.ioc_dev = cur_device;
        data.ioc_u32_1 = id;
+       if (username) {
+               data.ioc_inlbuf1 = username;
+               data.ioc_inllen1 = strlen(username) + 1;
+       }
 
        rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
        if (rc < 0) {
@@ -5626,14 +5707,14 @@ int jt_changelog_deregister(int argc, char **argv)
 
        rc = l_ioctl(OBD_DEV_ID, OBD_IOC_CHANGELOG_DEREG, buf);
        if (rc < 0) {
+               rc = -errno;
                fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
-                       strerror(rc = errno));
+                       rc == -ENOENT ? "User not found" : strerror(-rc));
                return rc;
        }
 
        llapi_ioctl_unpack(&data, buf, sizeof(rawbuf));
-       printf("%s: Deregistered changelog user '%s%u'\n",
-              device, CHANGELOG_USER_PREFIX, data.ioc_u32_1);
+       printf("%s: Deregistered changelog user #%u\n", device, data.ioc_u32_1);
 
        return 0;
 }
index 1472488..6f77d1d 100644 (file)
@@ -1703,18 +1703,19 @@ check_llog_logid(void)
        CHECK_MEMBER(llog_logid, lgl_oi);
        CHECK_MEMBER(llog_logid, lgl_ogen);
 
-       CHECK_CVALUE(OST_SZ_REC);
-       CHECK_CVALUE(MDS_UNLINK_REC);
-       CHECK_CVALUE(MDS_UNLINK64_REC);
-       CHECK_CVALUE(MDS_SETATTR64_REC);
-       CHECK_CVALUE(OBD_CFG_REC);
-       CHECK_CVALUE(LLOG_GEN_REC);
-       CHECK_CVALUE(CHANGELOG_REC);
-       CHECK_CVALUE(CHANGELOG_USER_REC);
-       CHECK_CVALUE(HSM_AGENT_REC);
-       CHECK_CVALUE(UPDATE_REC);
-       CHECK_CVALUE(LLOG_HDR_MAGIC);
-       CHECK_CVALUE(LLOG_LOGID_MAGIC);
+       CHECK_CVALUE_X(OST_SZ_REC);
+       CHECK_CVALUE_X(MDS_UNLINK_REC);
+       CHECK_CVALUE_X(MDS_UNLINK64_REC);
+       CHECK_CVALUE_X(MDS_SETATTR64_REC);
+       CHECK_CVALUE_X(OBD_CFG_REC);
+       CHECK_CVALUE_X(LLOG_GEN_REC);
+       CHECK_CVALUE_X(CHANGELOG_REC);
+       CHECK_CVALUE_X(CHANGELOG_USER_REC);
+       CHECK_CVALUE_X(CHANGELOG_USER_REC2);
+       CHECK_CVALUE_X(HSM_AGENT_REC);
+       CHECK_CVALUE_X(UPDATE_REC);
+       CHECK_CVALUE_X(LLOG_HDR_MAGIC);
+       CHECK_CVALUE_X(LLOG_LOGID_MAGIC);
 }
 
 static void
@@ -2613,7 +2614,7 @@ static void check_update_op(void)
        CHECK_MEMBER(update_op, uop_fid);
        CHECK_MEMBER(update_op, uop_type);
        CHECK_MEMBER(update_op, uop_param_count);
-       CHECK_MEMBER(update_op, uop_params_off);
+       CHECK_MEMBER_OFFSET(update_op, uop_params_off);
 }
 
 static void check_update_ops(void)
index a6c27c2..a8e307f 100644 (file)
 #endif /* HAVE_SERVER_SUPPORT */
 #include <linux/lustre/lustre_cfg.h>
 
+#ifndef BUILD_BUG_ON
+#define BUILD_BUG_ON(cond) ((void)sizeof(char[1 - 2*!!(cond)]))
+#endif
+
 #define LASSERT(cond) if (!(cond)) { printf("failed " #cond "\n"); ret = 1; }
 #define LASSERTF(cond, fmt, ...) if (!(cond)) { printf("failed '" #cond "'" fmt, ## __VA_ARGS__); ret = 1; }
 
index ff6515d..c38b8b4 100644 (file)
 #endif /* CONFIG_FS_POSIX_ACL */
 #endif /* HAVE_SERVER_SUPPORT */
 #include <linux/lustre/lustre_cfg.h>
-#include <lustre/lustreapi.h>
+
+#ifndef BUILD_BUG_ON
+#define BUILD_BUG_ON(cond) ((void)sizeof(char[1 - 2*!!(cond)]))
+#endif
 
 #define LASSERT(cond) if (!(cond)) { printf("failed " #cond "\n"); ret = 1; }
 #define LASSERTF(cond, fmt, ...) if (!(cond)) { printf("failed '" #cond "'" fmt, ## __VA_ARGS__); ret = 1; }
@@ -3916,18 +3919,19 @@ void lustre_assert_wire_constants(void)
                 (long long)(int)offsetof(struct llog_logid, lgl_ogen));
        LASSERTF((int)sizeof(((struct llog_logid *)0)->lgl_ogen) == 4, "found %lld\n",
                 (long long)(int)sizeof(((struct llog_logid *)0)->lgl_ogen));
-       BUILD_BUG_ON(OST_SZ_REC != 274730752);
-       BUILD_BUG_ON(MDS_UNLINK_REC != 274801668);
-       BUILD_BUG_ON(MDS_UNLINK64_REC != 275325956);
-       BUILD_BUG_ON(MDS_SETATTR64_REC != 275325953);
-       BUILD_BUG_ON(OBD_CFG_REC != 274857984);
-       BUILD_BUG_ON(LLOG_GEN_REC != 274989056);
-       BUILD_BUG_ON(CHANGELOG_REC != 275120128);
-       BUILD_BUG_ON(CHANGELOG_USER_REC != 275185664);
-       BUILD_BUG_ON(HSM_AGENT_REC != 275251200);
-       BUILD_BUG_ON(UPDATE_REC != 275382272);
-       BUILD_BUG_ON(LLOG_HDR_MAGIC != 275010873);
-       BUILD_BUG_ON(LLOG_LOGID_MAGIC != 275010875);
+       BUILD_BUG_ON(OST_SZ_REC != 0x10600f00);
+       BUILD_BUG_ON(MDS_UNLINK_REC != 0x10612404);
+       BUILD_BUG_ON(MDS_UNLINK64_REC != 0x10692404);
+       BUILD_BUG_ON(MDS_SETATTR64_REC != 0x10692401);
+       BUILD_BUG_ON(OBD_CFG_REC != 0x10620000);
+       BUILD_BUG_ON(LLOG_GEN_REC != 0x10640000);
+       BUILD_BUG_ON(CHANGELOG_REC != 0x10660000);
+       BUILD_BUG_ON(CHANGELOG_USER_REC != 0x10670000);
+       BUILD_BUG_ON(CHANGELOG_USER_REC2 != 0x10670002);
+       BUILD_BUG_ON(HSM_AGENT_REC != 0x10680000);
+       BUILD_BUG_ON(UPDATE_REC != 0x106a0000);
+       BUILD_BUG_ON(LLOG_HDR_MAGIC != 0x10645539);
+       BUILD_BUG_ON(LLOG_LOGID_MAGIC != 0x1064553b);
 
        /* Checks for struct llog_catid */
        LASSERTF((int)sizeof(struct llog_catid) == 32, "found %lld\n",