/* 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,
#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.
* 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"
} __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;
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,
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) {
{
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);
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 */
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,
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;
}
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;
}
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;
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);
* 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);
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);
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);
}
.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 {
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);
}
__u64 mcuc_minrec;
__u32 mcuc_id;
bool mcuc_flush;
+ struct mdd_device *mcuc_mdd;
};
/**
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;
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,
/* 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.
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);
.mcuc_id = id,
.mcuc_minrec = endrec,
.mcuc_flush = false,
+ .mcuc_mdd = mdd,
};
struct llog_ctxt *ctxt;
__u64 start_rec;
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
}
/* 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);
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;
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;
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);
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;
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++;
}
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)
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;
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;
}
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);
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",
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)
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);
* 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));
__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
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
* 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;
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
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));
}
}
/* 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;
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 ||
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:
* 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;
}
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;
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) {
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;
(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",
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"
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"
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 |
}
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) ]] ||
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
{"=== 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"},
char dev_path[PATH_MAX];
char cmd[64];
size_t cmd_len = sizeof(cmd);
+ char *dashp, *clidp = NULL;
int fd;
int rc;
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);
out_close:
close(fd);
+out:
+ free(clidp);
return rc;
}
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;
#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) {
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;
}
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
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)
#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; }
#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; }
(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",