LLOG_F_IS_PLAIN = 0x4,
LLOG_F_EXT_JOBID = 0x8,
LLOG_F_IS_FIXSIZE = 0x10,
+ LLOG_F_EXT_EXTRA_FLAGS = 0x20,
/* Note: Flags covered by LLOG_F_EXT_MASK will be inherited from
* catlog to plain log, so do not add LLOG_F_IS_FIXSIZE here,
* because the catlog record is usually fixed size, but its plain
* log record can be variable */
- LLOG_F_EXT_MASK = LLOG_F_EXT_JOBID,
+ LLOG_F_EXT_MASK = LLOG_F_EXT_JOBID | LLOG_F_EXT_EXTRA_FLAGS,
};
/* On-disk header structure of each log object, stored in little endian order */
CLF_VERSION = 0x1000,
CLF_RENAME = 0x2000,
CLF_JOBID = 0x4000,
- CLF_SUPPORTED = CLF_VERSION | CLF_RENAME | CLF_JOBID
+ CLF_EXTRA_FLAGS = 0x8000,
+ CLF_SUPPORTED = CLF_VERSION | CLF_RENAME | CLF_JOBID | CLF_EXTRA_FLAGS
};
*flags |= (error << CLF_HSM_ERR_L);
}
+enum changelog_rec_extra_flags {
+ CLFE_INVALID = 0, /* No additional flags currently implemented */
+ CLFE_SUPPORTED = CLFE_INVALID
+};
+
enum changelog_send_flag {
/* Not yet implemented */
- CHANGELOG_FLAG_FOLLOW = 0x01,
+ CHANGELOG_FLAG_FOLLOW = 0x01,
/* Blocking IO makes sense in case of slow user parsing of the records,
* but it also prevents us from cleaning up if the records are not
* consumed. */
- CHANGELOG_FLAG_BLOCK = 0x02,
+ CHANGELOG_FLAG_BLOCK = 0x02,
/* Pack jobid into the changelog records if available. */
- CHANGELOG_FLAG_JOBID = 0x04,
+ CHANGELOG_FLAG_JOBID = 0x04,
+ /* Pack additional flag bits into the changelog record */
+ CHANGELOG_FLAG_EXTRA_FLAGS = 0x08,
};
#define CR_MAXSIZE cfs_size_round(2 * NAME_MAX + 2 + \
- changelog_rec_offset(CLF_SUPPORTED))
+ changelog_rec_offset(CLF_SUPPORTED, \
+ CLFE_SUPPORTED))
/* 31 usable bytes string + null terminator. */
#define LUSTRE_JOBID_SIZE 32
/* This is the minimal changelog record. It can contain extensions
* such as rename fields or process jobid. Its exact content is described
- * by the cr_flags.
+ * by the cr_flags and cr_extra_flags.
*
- * Extensions are packed in the same order as their corresponding flags.
+ * Extensions are packed in the same order as their corresponding flags,
+ * then in the same order as their corresponding extra flags.
*/
struct changelog_rec {
__u16 cr_namelen;
char cr_jobid[LUSTRE_JOBID_SIZE]; /**< zero-terminated string. */
};
+/* Changelog extension to include additional flags. */
+struct changelog_ext_extra_flags {
+ __u64 cr_extra_flags; /* Additional CLFE_* flags */
+};
+
+static inline struct changelog_ext_extra_flags *changelog_rec_extra_flags(
+ const struct changelog_rec *rec);
-static inline size_t changelog_rec_offset(enum changelog_rec_flags crf)
+static inline size_t changelog_rec_offset(enum changelog_rec_flags crf,
+ enum changelog_rec_extra_flags cref)
{
size_t size = sizeof(struct changelog_rec);
if (crf & CLF_JOBID)
size += sizeof(struct changelog_ext_jobid);
+ if (crf & CLF_EXTRA_FLAGS) {
+ size += sizeof(struct changelog_ext_extra_flags);
+ }
+
return size;
}
static inline size_t changelog_rec_size(const struct changelog_rec *rec)
{
- return changelog_rec_offset(rec->cr_flags);
+ enum changelog_rec_extra_flags cref = CLFE_INVALID;
+
+ if (rec->cr_flags & CLF_EXTRA_FLAGS)
+ cref = changelog_rec_extra_flags(rec)->cr_extra_flags;
+
+ return changelog_rec_offset(rec->cr_flags, cref);
}
static inline size_t changelog_rec_varsize(const struct changelog_rec *rec)
enum changelog_rec_flags crf = rec->cr_flags & CLF_VERSION;
return (struct changelog_ext_rename *)((char *)rec +
- changelog_rec_offset(crf));
+ changelog_rec_offset(crf,
+ CLFE_INVALID));
}
/* The jobid follows the rename extension, if present */
(CLF_VERSION | CLF_RENAME);
return (struct changelog_ext_jobid *)((char *)rec +
- changelog_rec_offset(crf));
+ changelog_rec_offset(crf,
+ CLFE_INVALID));
}
-/* The name follows the rename and jobid extensions, if present */
+/* The additional flags follow the rename and jobid extensions, if present */
+static inline
+struct changelog_ext_extra_flags *changelog_rec_extra_flags(
+ const struct changelog_rec *rec)
+{
+ enum changelog_rec_flags crf = rec->cr_flags &
+ (CLF_VERSION | CLF_RENAME | CLF_JOBID);
+
+ return (struct changelog_ext_extra_flags *)((char *)rec +
+ changelog_rec_offset(crf,
+ CLFE_INVALID));
+}
+
+/* The name follows the rename, jobid and extra flags extns, if present */
static inline char *changelog_rec_name(const struct changelog_rec *rec)
{
- return (char *)rec + changelog_rec_offset(rec->cr_flags &
- CLF_SUPPORTED);
+ enum changelog_rec_extra_flags cref = CLFE_INVALID;
+
+ if (rec->cr_flags & CLF_EXTRA_FLAGS)
+ cref = changelog_rec_extra_flags(rec)->cr_extra_flags;
+
+ return (char *)rec + changelog_rec_offset(rec->cr_flags & CLF_SUPPORTED,
+ cref & CLFE_SUPPORTED);
}
static inline size_t changelog_rec_snamelen(const struct changelog_rec *rec)
* The following assumptions are being made:
* - CLF_RENAME will not be removed
* - CLF_JOBID will not be added without CLF_RENAME being added too
+ * - CLF_EXTRA_FLAGS will not be added without CLF_JOBID being added too
*
* @param[in,out] rec The record to remap.
* @param[in] crf_wanted Flags describing the desired extensions.
+ * @param[in] cref_want Flags describing the desired extra extensions.
*/
static inline void changelog_remap_rec(struct changelog_rec *rec,
- enum changelog_rec_flags crf_wanted)
+ enum changelog_rec_flags crf_wanted,
+ enum changelog_rec_extra_flags cref_want)
{
+ char *ef_mov;
char *jid_mov;
char *rnm_mov;
crf_wanted &= CLF_SUPPORTED;
-
- if ((rec->cr_flags & CLF_SUPPORTED) == crf_wanted)
- return;
+ cref_want &= CLFE_SUPPORTED;
+
+ if ((rec->cr_flags & CLF_SUPPORTED) == crf_wanted) {
+ if (!(rec->cr_flags & CLF_EXTRA_FLAGS) ||
+ (rec->cr_flags & CLF_EXTRA_FLAGS &&
+ (changelog_rec_extra_flags(rec)->cr_extra_flags &
+ CLFE_SUPPORTED) ==
+ cref_want))
+ return;
+ }
/* First move the variable-length name field */
- memmove((char *)rec + changelog_rec_offset(crf_wanted),
+ memmove((char *)rec + changelog_rec_offset(crf_wanted, cref_want),
changelog_rec_name(rec), rec->cr_namelen);
- /* Locations of jobid and rename extensions in the remapped record */
+ /* Locations of extensions in the remapped record */
+ ef_mov = (char *)rec +
+ changelog_rec_offset(crf_wanted & ~CLF_EXTRA_FLAGS,
+ CLFE_INVALID);
jid_mov = (char *)rec +
- changelog_rec_offset(crf_wanted & ~CLF_JOBID);
+ changelog_rec_offset(crf_wanted &
+ ~(CLF_EXTRA_FLAGS | CLF_JOBID),
+ CLFE_INVALID);
rnm_mov = (char *)rec +
- changelog_rec_offset(crf_wanted & ~(CLF_JOBID | CLF_RENAME));
+ changelog_rec_offset(crf_wanted &
+ ~(CLF_EXTRA_FLAGS |
+ CLF_JOBID |
+ CLF_RENAME),
+ CLFE_INVALID);
/* Move the extension fields to the desired positions */
+ if ((crf_wanted & CLF_EXTRA_FLAGS) &&
+ (rec->cr_flags & CLF_EXTRA_FLAGS)) {
+ memmove(ef_mov, changelog_rec_extra_flags(rec),
+ sizeof(struct changelog_ext_extra_flags));
+ }
+
if ((crf_wanted & CLF_JOBID) && (rec->cr_flags & CLF_JOBID))
memmove(jid_mov, changelog_rec_jobid(rec),
sizeof(struct changelog_ext_jobid));
sizeof(struct changelog_ext_rename));
/* Clear newly added fields */
+ if ((crf_wanted & CLF_EXTRA_FLAGS) &&
+ !(rec->cr_flags & CLF_EXTRA_FLAGS))
+ memset(ef_mov, 0, sizeof(struct changelog_ext_extra_flags));
+
if ((crf_wanted & CLF_JOBID) && !(rec->cr_flags & CLF_JOBID))
memset(jid_mov, 0, sizeof(struct changelog_ext_jobid));
/* Update the record's flags accordingly */
rec->cr_flags = (rec->cr_flags & CLF_FLAGMASK) | crf_wanted;
+ if (rec->cr_flags & CLF_EXTRA_FLAGS)
+ changelog_rec_extra_flags(rec)->cr_extra_flags =
+ changelog_rec_extra_flags(rec)->cr_extra_flags |
+ cref_want;
}
enum changelog_message_type {
GOTO(err_out, rc);
}
- rc = llog_init_handle(NULL, llh, LLOG_F_IS_CAT|LLOG_F_EXT_JOBID, NULL);
+ rc = llog_init_handle(NULL, llh,
+ LLOG_F_IS_CAT |
+ LLOG_F_EXT_JOBID |
+ LLOG_F_EXT_EXTRA_FLAGS,
+ NULL);
if (rc) {
CERROR("%s: fail to init llog handle: rc = %d\n",
obd->obd_name, rc);
const struct lu_name *sname)
{
const struct lu_ucred *uc = lu_ucred(env);
- enum changelog_rec_flags crf = 0;
+ enum changelog_rec_flags crf = CLF_EXTRA_FLAGS;
+ enum changelog_rec_extra_flags crfe = CLFE_INVALID;
if (sname != NULL)
crf |= CLF_RENAME;
if (uc != NULL && uc->uc_jobid[0] != '\0')
crf |= CLF_JOBID;
- return llog_data_len(LLOG_CHANGELOG_HDR_SZ + changelog_rec_offset(crf) +
+ return llog_data_len(LLOG_CHANGELOG_HDR_SZ +
+ changelog_rec_offset(crf, crfe) +
(tname != NULL ? tname->ln_namelen : 0) +
(sname != NULL ? 1 + sname->ln_namelen : 0));
}
strlcpy(jid->cr_jobid, jobid, sizeof(jid->cr_jobid));
}
+void mdd_changelog_rec_ext_extra_flags(struct changelog_rec *rec, __u64 eflags)
+{
+ struct changelog_ext_extra_flags *ef = changelog_rec_extra_flags(rec);
+
+ ef->cr_extra_flags = eflags;
+}
+
/** Store a namespace change changelog record
* If this fails, we must fail the whole transaction; we don't
* want the change to commit without the log entry.
struct llog_changelog_rec *rec;
struct lu_buf *buf;
int reclen;
+ __u64 xflags = CLFE_INVALID;
int rc;
ENTRY;
rec = buf->lb_buf;
crf &= CLF_FLAGMASK;
+ crf |= CLF_EXTRA_FLAGS;
if (uc != NULL && uc->uc_jobid[0] != '\0')
crf |= CLF_JOBID;
crf |= CLF_VERSION;
rec->cr.cr_flags = crf;
+
+ if (crf & CLF_EXTRA_FLAGS) {
+ mdd_changelog_rec_ext_extra_flags(&rec->cr, xflags);
+ }
+
rec->cr.cr_type = (__u32)type;
rec->cr.cr_pfid = *tpfid;
rec->cr.cr_namelen = tname->ln_namelen;
const struct lu_name *sname,
struct thandle *handle);
void mdd_changelog_rec_ext_jobid(struct changelog_rec *rec, const char *jobid);
+void mdd_changelog_rec_ext_extra_flags(struct changelog_rec *rec, __u64 eflags);
int mdd_changelog_store(const struct lu_env *env, struct mdd_device *mdd,
struct llog_changelog_rec *rec, struct thandle *th);
int mdd_changelog_data_store(const struct lu_env *env, struct mdd_device *mdd,
struct llog_changelog_rec *rec;
struct lu_buf *buf;
int reclen;
+ int xflags = CLFE_INVALID;
int rc;
- flags = (flags & CLF_FLAGMASK) | CLF_VERSION;
+ flags = (flags & CLF_FLAGMASK) | CLF_VERSION | CLF_EXTRA_FLAGS;
if (uc != NULL && uc->uc_jobid[0] != '\0')
flags |= CLF_JOBID;
reclen = llog_data_len(LLOG_CHANGELOG_HDR_SZ +
- changelog_rec_offset(flags & CLF_SUPPORTED));
+ changelog_rec_offset(flags & CLF_SUPPORTED,
+ xflags & CLFE_SUPPORTED));
buf = lu_buf_check_and_alloc(&mdd_env_info(env)->mti_big_buf, reclen);
if (buf->lb_buf == NULL)
RETURN(-ENOMEM);
if (flags & CLF_JOBID)
mdd_changelog_rec_ext_jobid(&rec->cr, uc->uc_jobid);
+ if (flags & CLF_EXTRA_FLAGS)
+ mdd_changelog_rec_ext_extra_flags(&rec->cr, xflags);
+
rc = mdd_changelog_store(env, mdd, rec, handle);
RETURN(rc);
* big enough to handle the remapped records. It is also assumed that records
* of a block have the same format (i.e.: the same features enabled).
*
- * \param[in,out] hdr Header of the block of records to remap.
- * \param[in,out] last_hdr Last header, don't read past this point.
- * \param[in] flags Flags describing the fields to keep.
+ * \param[in,out] hdr Header of the block of records to remap.
+ * \param[in,out] last_hdr Last header, don't read past this point.
+ * \param[in] flags Flags describing the fields to keep.
+ * \param[in] extra_flags Flags describing the extra fields to keep.
*/
static void changelog_block_trim_ext(struct llog_rec_hdr *hdr,
struct llog_rec_hdr *last_hdr,
- enum changelog_rec_flags flags)
+ enum changelog_rec_flags flags,
+ enum changelog_rec_extra_flags extra_flags)
{
if (hdr->lrh_type != CHANGELOG_REC)
return;
do {
struct changelog_rec *rec = (struct changelog_rec *)(hdr + 1);
+ enum changelog_rec_extra_flags xflag = CLFE_INVALID;
- changelog_remap_rec(rec, rec->cr_flags & flags);
+ if (flags & CLF_EXTRA_FLAGS &&
+ rec->cr_flags & CLF_EXTRA_FLAGS) {
+ xflag = changelog_rec_extra_flags(rec)->cr_extra_flags &
+ extra_flags;
+ }
+
+ changelog_remap_rec(rec, rec->cr_flags & flags, xflag);
hdr = llog_rec_hdr_next(hdr);
} while ((char *)hdr <= (char *)last_hdr);
}
int last_idx = *cur_idx;
__u64 last_offset = *cur_offset;
bool force_mini_rec = false;
+ enum changelog_rec_flags flags;
+ enum changelog_rec_extra_flags xflags;
ENTRY;
}
/* Trim unsupported extensions for compat w/ older clients */
+ flags = CLF_SUPPORTED;
+ xflags = CLFE_SUPPORTED;
+ if (!(loghandle->lgh_hdr->llh_flags & LLOG_F_EXT_EXTRA_FLAGS))
+ flags &= ~CLF_EXTRA_FLAGS;
if (!(loghandle->lgh_hdr->llh_flags & LLOG_F_EXT_JOBID))
- changelog_block_trim_ext(rec, last_rec,
- CLF_VERSION | CLF_RENAME);
+ flags &= ~CLF_JOBID;
+ if (flags != CLF_SUPPORTED || xflags != CLFE_SUPPORTED)
+ changelog_block_trim_ext(rec, last_rec, flags, xflags);
GOTO(out, rc = 0);
struct dt_device *dt;
loff_t cur_offset;
__u32 chunk_size;
+ enum changelog_rec_flags flags;
+ enum changelog_rec_extra_flags xflags;
int rc;
ENTRY;
}
/* Trim unsupported extensions for compat w/ older clients */
+ flags = CLF_SUPPORTED;
+ xflags = CLFE_SUPPORTED;
+ if (!(loghandle->lgh_hdr->llh_flags & LLOG_F_EXT_EXTRA_FLAGS))
+ flags &= ~CLF_EXTRA_FLAGS;
if (!(loghandle->lgh_hdr->llh_flags & LLOG_F_EXT_JOBID))
- changelog_block_trim_ext(rec, last_rec,
- CLF_VERSION | CLF_RENAME);
+ flags &= ~CLF_JOBID;
+ if (flags != CLF_SUPPORTED || xflags != CLFE_SUPPORTED)
+ changelog_block_trim_ext(rec, last_rec, flags, xflags);
GOTO(out, rc = 0);
}
#include <stdlib.h>
#include <stdio.h>
+#include <inttypes.h>
#include <getopt.h>
#include <string.h>
#include <mntent.h>
rc = llapi_changelog_start(&changelog_priv,
CHANGELOG_FLAG_BLOCK |
CHANGELOG_FLAG_JOBID |
+ CHANGELOG_FLAG_EXTRA_FLAGS |
(follow ? CHANGELOG_FLAG_FOLLOW : 0),
mdd, startrec);
if (rc < 0) {
printf(" j=%s", jid->cr_jobid);
}
+ if (rec->cr_flags & CLF_EXTRA_FLAGS) {
+ struct changelog_ext_extra_flags *ef =
+ changelog_rec_extra_flags(rec);
+
+ printf(" ef=0x%llx", ef->cr_extra_flags);
+ }
+
if (rec->cr_namelen)
printf(" p="DFID" %.*s", PFID(&rec->cr_pfid),
rec->cr_namelen, changelog_rec_name(rec));
const char *device, long long startrec)
{
struct changelog_private *cp;
+ static bool warned_extra_flags;
static bool warned_jobid;
static bool warned_follow;
char cdev_path[PATH_MAX];
*priv = cp;
+ /* CHANGELOG_FLAG_EXTRA_FLAGS will eventually become mandatory.
+ * If it wasn't specified, display a warning here.
+ * Code elsewhere will remove the corresponding extension.
+ */
+ if (!(flags & CHANGELOG_FLAG_EXTRA_FLAGS) && !warned_extra_flags) {
+ llapi_err_noerrno(LLAPI_MSG_WARN,
+ "warning: %s() called without CHANGELOG_FLAG_EXTRA_FLAGS",
+ __func__);
+ warned_extra_flags = true;
+ }
+
/* CHANGELOG_FLAG_JOBID will eventually become mandatory. Display a
* warning if it's missing. */
if (!(flags & CHANGELOG_FLAG_JOBID) && !warned_jobid) {
{
struct changelog_private *cp = priv;
enum changelog_rec_flags rec_fmt = DEFAULT_RECORD_FMT;
+ enum changelog_rec_extra_flags rec_extra_fmt = CLFE_INVALID;
struct changelog_rec *tmp;
int rc = 0;
if (cp->clp_send_flags & CHANGELOG_FLAG_JOBID)
rec_fmt |= CLF_JOBID;
+ if (cp->clp_send_flags & CHANGELOG_FLAG_EXTRA_FLAGS) {
+ rec_fmt |= CLF_EXTRA_FLAGS;
+ }
+
if (cp->clp_buf + cp->clp_buf_len <= cp->clp_buf_pos) {
ssize_t refresh;
changelog_rec_size(tmp) + tmp->cr_namelen);
cp->clp_buf_pos += changelog_rec_size(tmp) + tmp->cr_namelen;
- changelog_remap_rec(*rech, rec_fmt);
+ changelog_remap_rec(*rech, rec_fmt, rec_extra_fmt);
return 0;
/* Open changelogs for consumption*/
rc = llapi_changelog_start(&changelog_priv,
- CHANGELOG_FLAG_BLOCK | CHANGELOG_FLAG_JOBID,
+ CHANGELOG_FLAG_BLOCK |
+ CHANGELOG_FLAG_JOBID |
+ CHANGELOG_FLAG_EXTRA_FLAGS,
status->ls_mdt_device, status->ls_last_recno);
if (rc < 0) {
fprintf(stderr, "Error opening changelog file for fs %s.\n",