/* Allow records up to endrec to be destroyed; requires registered id. */
int llapi_changelog_clear(const char *mdtname, const char *idstr,
long long endrec);
+extern int llapi_changelog_set_xflags(void *priv,
+ enum changelog_send_extra_flag extra_flags);
/* HSM copytool interface.
* priv is private state, managed internally by these functions
LLOG_F_EXT_JOBID = 0x8,
LLOG_F_IS_FIXSIZE = 0x10,
LLOG_F_EXT_EXTRA_FLAGS = 0x20,
+ LLOG_F_EXT_X_UIDGID = 0x40,
/* 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_EXTRA_FLAGS,
+ LLOG_F_EXT_MASK = LLOG_F_EXT_JOBID | LLOG_F_EXT_EXTRA_FLAGS |
+ LLOG_F_EXT_X_UIDGID,
};
/* On-disk header structure of each log object, stored in little endian order */
}
enum changelog_rec_extra_flags {
- CLFE_INVALID = 0, /* No additional flags currently implemented */
- CLFE_SUPPORTED = CLFE_INVALID
+ CLFE_INVALID = 0,
+ CLFE_UIDGID = 0x0001,
+ CLFE_SUPPORTED = CLFE_UIDGID
};
enum changelog_send_flag {
CHANGELOG_FLAG_EXTRA_FLAGS = 0x08,
};
+enum changelog_send_extra_flag {
+ /* Pack uid/gid into the changelog record */
+ CHANGELOG_EXTRA_FLAG_UIDGID = 0x01,
+};
+
#define CR_MAXSIZE cfs_size_round(2 * NAME_MAX + 2 + \
changelog_rec_offset(CLF_SUPPORTED, \
CLFE_SUPPORTED))
__u64 cr_extra_flags; /* Additional CLFE_* flags */
};
+/* Changelog extra extension to include UID/GID. */
+struct changelog_ext_uidgid {
+ __u64 cr_uid;
+ __u64 cr_gid;
+};
+
static inline struct changelog_ext_extra_flags *changelog_rec_extra_flags(
const struct changelog_rec *rec);
if (crf & CLF_EXTRA_FLAGS) {
size += sizeof(struct changelog_ext_extra_flags);
+ if (cref & CLFE_UIDGID)
+ size += sizeof(struct changelog_ext_uidgid);
}
return size;
CLFE_INVALID));
}
+/* The uid/gid is the first extra extension */
+static inline
+struct changelog_ext_uidgid *changelog_rec_uidgid(
+ const struct changelog_rec *rec)
+{
+ enum changelog_rec_flags crf = rec->cr_flags &
+ (CLF_VERSION | CLF_RENAME | CLF_JOBID | CLF_EXTRA_FLAGS);
+
+ return (struct changelog_ext_uidgid *)((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)
{
enum changelog_rec_flags crf_wanted,
enum changelog_rec_extra_flags cref_want)
{
+ char *uidgid_mov = NULL;
char *ef_mov;
char *jid_mov;
char *rnm_mov;
+ enum changelog_rec_extra_flags cref = CLFE_INVALID;
crf_wanted &= CLF_SUPPORTED;
cref_want &= CLFE_SUPPORTED;
changelog_rec_name(rec), rec->cr_namelen);
/* Locations of extensions in the remapped record */
+ if (rec->cr_flags & CLF_EXTRA_FLAGS) {
+ uidgid_mov = (char *)rec +
+ changelog_rec_offset(crf_wanted & CLF_SUPPORTED,
+ CLFE_INVALID);
+ cref = changelog_rec_extra_flags(rec)->cr_extra_flags;
+ }
+
ef_mov = (char *)rec +
changelog_rec_offset(crf_wanted & ~CLF_EXTRA_FLAGS,
CLFE_INVALID);
/* Move the extension fields to the desired positions */
if ((crf_wanted & CLF_EXTRA_FLAGS) &&
(rec->cr_flags & CLF_EXTRA_FLAGS)) {
+ if ((cref_want & CLFE_UIDGID) && (cref & CLFE_UIDGID))
+ memmove(uidgid_mov, changelog_rec_uidgid(rec),
+ sizeof(struct changelog_ext_uidgid));
+
memmove(ef_mov, changelog_rec_extra_flags(rec),
sizeof(struct changelog_ext_extra_flags));
}
sizeof(struct changelog_ext_rename));
/* Clear newly added fields */
+ if (uidgid_mov && (cref_want & CLFE_UIDGID) &&
+ !(cref & CLFE_UIDGID))
+ memset(uidgid_mov, 0, sizeof(struct changelog_ext_uidgid));
+
if ((crf_wanted & CLF_EXTRA_FLAGS) &&
!(rec->cr_flags & CLF_EXTRA_FLAGS))
memset(ef_mov, 0, sizeof(struct changelog_ext_extra_flags));
rc = llog_init_handle(NULL, llh,
LLOG_F_IS_CAT |
LLOG_F_EXT_JOBID |
- LLOG_F_EXT_EXTRA_FLAGS,
+ LLOG_F_EXT_EXTRA_FLAGS |
+ LLOG_F_EXT_X_UIDGID,
NULL);
if (rc) {
CERROR("%s: fail to init llog handle: rc = %d\n",
{
const struct lu_ucred *uc = lu_ucred(env);
enum changelog_rec_flags crf = CLF_EXTRA_FLAGS;
- enum changelog_rec_extra_flags crfe = CLFE_INVALID;
+ enum changelog_rec_extra_flags crfe = CLFE_UIDGID;
if (sname != NULL)
crf |= CLF_RENAME;
const struct lu_fid *spfid,
const struct lu_name *sname)
{
- struct changelog_ext_rename *rnm = changelog_rec_rename(rec);
- size_t extsize = sname->ln_namelen + 1;
+ struct changelog_ext_rename *rnm = changelog_rec_rename(rec);
+ size_t extsize = sname->ln_namelen + 1;
LASSERT(sfid != NULL);
LASSERT(spfid != NULL);
void mdd_changelog_rec_ext_jobid(struct changelog_rec *rec, const char *jobid)
{
- struct changelog_ext_jobid *jid = changelog_rec_jobid(rec);
+ struct changelog_ext_jobid *jid = changelog_rec_jobid(rec);
if (jobid == NULL || jobid[0] == '\0')
return;
ef->cr_extra_flags = eflags;
}
+void mdd_changelog_rec_extra_uidgid(struct changelog_rec *rec,
+ __u64 uid, __u64 gid)
+{
+ struct changelog_ext_uidgid *uidgid = changelog_rec_uidgid(rec);
+
+ uidgid->cr_uid = uid;
+ uidgid->cr_gid = gid;
+}
+
/** 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.
else
crf |= CLF_VERSION;
+ xflags |= CLFE_UIDGID;
+
rec->cr.cr_flags = crf;
if (crf & CLF_EXTRA_FLAGS) {
mdd_changelog_rec_ext_extra_flags(&rec->cr, xflags);
+ if (xflags & CLFE_UIDGID)
+ mdd_changelog_rec_extra_uidgid(&rec->cr,
+ uc->uc_uid, uc->uc_gid);
}
rec->cr.cr_type = (__u32)type;
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);
+void mdd_changelog_rec_extra_uidgid(struct changelog_rec *rec,
+ __u64 uid, __u64 gid);
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,
if (uc != NULL && uc->uc_jobid[0] != '\0')
flags |= CLF_JOBID;
+ xflags |= CLFE_UIDGID;
+
reclen = llog_data_len(LLOG_CHANGELOG_HDR_SZ +
changelog_rec_offset(flags & CLF_SUPPORTED,
xflags & CLFE_SUPPORTED));
if (flags & CLF_JOBID)
mdd_changelog_rec_ext_jobid(&rec->cr, uc->uc_jobid);
- if (flags & CLF_EXTRA_FLAGS)
+ if (flags & CLF_EXTRA_FLAGS) {
mdd_changelog_rec_ext_extra_flags(&rec->cr, xflags);
+ if (xflags & CLFE_UIDGID)
+ mdd_changelog_rec_extra_uidgid(&rec->cr,
+ uc->uc_uid, uc->uc_gid);
+ }
rc = mdd_changelog_store(env, mdd, rec, handle);
/* Trim unsupported extensions for compat w/ older clients */
flags = CLF_SUPPORTED;
xflags = CLFE_SUPPORTED;
+ if (!(loghandle->lgh_hdr->llh_flags & LLOG_F_EXT_X_UIDGID))
+ xflags &= ~CLFE_UIDGID;
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))
/* Trim unsupported extensions for compat w/ older clients */
flags = CLF_SUPPORTED;
xflags = CLFE_SUPPORTED;
+ if (!(loghandle->lgh_hdr->llh_flags & LLOG_F_EXT_X_UIDGID))
+ xflags &= ~CLFE_UIDGID;
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))
return rc;
}
+ rc = llapi_changelog_set_xflags(changelog_priv,
+ CHANGELOG_EXTRA_FLAG_UIDGID);
+ if (rc < 0) {
+ fprintf(stderr, "Can't set xflags for changelog: %s\n",
+ strerror(errno = -rc));
+ return rc;
+ }
+
while ((rc = llapi_changelog_recv(changelog_priv, &rec)) == 0) {
time_t secs;
struct tm ts;
changelog_rec_extra_flags(rec);
printf(" ef=0x%llx", ef->cr_extra_flags);
+
+ if (ef->cr_extra_flags & CLFE_UIDGID) {
+ struct changelog_ext_uidgid *uidgid =
+ changelog_rec_uidgid(rec);
+
+ printf(" u=%llu:%llu",
+ uidgid->cr_uid, uidgid->cr_gid);
+ }
}
if (rec->cr_namelen)
int clp_fd;
/* Changelog delivery mode */
enum changelog_send_flag clp_send_flags;
+ /* Changelog extra flags */
+ enum changelog_send_extra_flag clp_send_extra_flags;
/* Available bytes in buffer */
size_t clp_buf_len;
/* Current position in buffer */
if (cp->clp_send_flags & CHANGELOG_FLAG_EXTRA_FLAGS) {
rec_fmt |= CLF_EXTRA_FLAGS;
+ if (cp->clp_send_extra_flags & CHANGELOG_EXTRA_FLAG_UIDGID)
+ rec_extra_fmt |= CLFE_UIDGID;
}
if (cp->clp_buf + cp->clp_buf_len <= cp->clp_buf_pos) {
close(fd);
return rc;
}
+
+/**
+ * Set extra flags for reading changelogs
+ *
+ * @param priv Opaque private control structure
+ * @param extra_flags Read extra flags (e.g. CHANGELOG_EXTRA_FLAG_UIDGID)
+ *
+ * Just call this function right after llapi_changelog_start().
+ */
+int llapi_changelog_set_xflags(void *priv,
+ enum changelog_send_extra_flag extra_flags)
+{
+ struct changelog_private *cp = priv;
+ static bool warned_uidgid;
+
+ if (!cp || cp->clp_magic != CHANGELOG_PRIV_MAGIC)
+ return -EINVAL;
+
+ cp->clp_send_extra_flags = extra_flags;
+
+ /* CHANGELOG_EXTRA_FLAG_UIDGID will eventually become mandatory.
+ * If it wasn't specified, display a warning here.
+ * Code elsewhere will remove the corresponding extension.
+ */
+ if (!(extra_flags & CHANGELOG_EXTRA_FLAG_UIDGID) && !warned_uidgid) {
+ llapi_err_noerrno(LLAPI_MSG_WARN,
+ "warning: %s() called without CHANGELOG_EXTRA_FLAG_UIDGID",
+ __func__);
+ warned_uidgid = true;
+ }
+
+ return 0;
+}
goto out;
}
+ rc = llapi_changelog_set_xflags(changelog_priv,
+ CHANGELOG_EXTRA_FLAG_UIDGID);
+ if (rc < 0) {
+ fprintf(stderr, "Error setting xflag in changelog for fs %s.\n",
+ status->ls_source_fs);
+ goto out;
+ }
+
while (!quit && lr_parse_line(changelog_priv, info) == 0) {
rc = 0;
if (info->type == CL_RENAME && !info->is_extended) {