/** 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.
- * Remove also CL_OPEN from default list as it can be costly and only necessary
- * for audit purpose.
+ * Remove also CL_OPEN and CL_GETXATTR from default list as it can be costly and
+ * only necessary for audit purpose.
*/
-#define CHANGELOG_DEFMASK (CHANGELOG_ALLMASK & ~(1 << CL_ATIME | 1 << CL_OPEN))
+#define CHANGELOG_DEFMASK (CHANGELOG_ALLMASK & \
+ ~(1 << CL_ATIME | 1 << CL_OPEN | 1 << CL_GETXATTR))
/* changelog llog name, needed by client replicators */
#define CHANGELOG_CATALOG "changelog_catalog"
LLOG_F_EXT_X_UIDGID = 0x40,
LLOG_F_EXT_X_NID = 0x80,
LLOG_F_EXT_X_OMODE = 0x100,
+ LLOG_F_EXT_X_XATTR = 0x200,
/* 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,
* log record can be variable */
LLOG_F_EXT_MASK = LLOG_F_EXT_JOBID | LLOG_F_EXT_EXTRA_FLAGS |
LLOG_F_EXT_X_UIDGID | LLOG_F_EXT_X_NID |
- LLOG_F_EXT_X_OMODE,
+ LLOG_F_EXT_X_OMODE | LLOG_F_EXT_X_XATTR,
};
/* On-disk header structure of each log object, stored in little endian order */
CL_LAYOUT = 12, /* file layout/striping modified */
CL_TRUNC = 13,
CL_SETATTR = 14,
- CL_XATTR = 15,
+ CL_SETXATTR = 15,
+ CL_XATTR = CL_SETXATTR, /* Deprecated name */
CL_HSM = 16, /* HSM specific events, see flags */
CL_MTIME = 17, /* Precedence: setattr > mtime > ctime > atime */
CL_CTIME = 18,
CL_MIGRATE = 20,
CL_FLRW = 21, /* FLR: file was firstly written */
CL_RESYNC = 22, /* FLR: file was resync-ed */
+ CL_GETXATTR = 23,
CL_LAST
};
"MARK", "CREAT", "MKDIR", "HLINK", "SLINK", "MKNOD", "UNLNK",
"RMDIR", "RENME", "RNMTO", "OPEN", "CLOSE", "LYOUT", "TRUNC",
"SATTR", "XATTR", "HSM", "MTIME", "CTIME", "ATIME", "MIGRT",
- "FLRW", "RESYNC",
+ "FLRW", "RESYNC","GXATR",
};
if (type >= 0 && type < CL_LAST)
CLFE_UIDGID = 0x0001,
CLFE_NID = 0x0002,
CLFE_OPEN = 0x0004,
- CLFE_SUPPORTED = CLFE_UIDGID | CLFE_NID | CLFE_OPEN
+ CLFE_XATTR = 0x0008,
+ CLFE_SUPPORTED = CLFE_UIDGID | CLFE_NID | CLFE_OPEN | CLFE_XATTR
};
enum changelog_send_flag {
CHANGELOG_EXTRA_FLAG_NID = 0x02,
/* Pack open mode into the changelog record */
CHANGELOG_EXTRA_FLAG_OMODE = 0x04,
+ /* Pack xattr name into the changelog record */
+ CHANGELOG_EXTRA_FLAG_XATTR = 0x08,
};
#define CR_MAXSIZE cfs_size_round(2 * NAME_MAX + 2 + \
__u32 cr_openflags;
};
+/* Changelog extra extension to include xattr */
+struct changelog_ext_xattr {
+ char cr_xattr[XATTR_NAME_MAX + 1]; /**< zero-terminated string. */
+};
+
static inline struct changelog_ext_extra_flags *changelog_rec_extra_flags(
const struct changelog_rec *rec);
size += sizeof(struct changelog_ext_nid);
if (cref & CLFE_OPEN)
size += sizeof(struct changelog_ext_openmode);
+ if (cref & CLFE_XATTR)
+ size += sizeof(struct changelog_ext_xattr);
}
return size;
changelog_rec_offset(crf, cref));
}
+/* The xattr name is the fourth extra extension */
+static inline
+struct changelog_ext_xattr *changelog_rec_xattr(
+ const struct changelog_rec *rec)
+{
+ enum changelog_rec_flags crf = rec->cr_flags &
+ (CLF_VERSION | CLF_RENAME | CLF_JOBID | CLF_EXTRA_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 &
+ (CLFE_UIDGID | CLFE_NID | CLFE_OPEN);
+
+ return (struct changelog_ext_xattr *)((char *)rec +
+ changelog_rec_offset(crf, cref));
+}
+
/* 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 *xattr_mov = NULL;
char *omd_mov = NULL;
char *nid_mov = NULL;
char *uidgid_mov = NULL;
/* Locations of extensions in the remapped record */
if (rec->cr_flags & CLF_EXTRA_FLAGS) {
+ xattr_mov = (char *)rec +
+ changelog_rec_offset(crf_wanted & CLF_SUPPORTED,
+ cref_want & ~CLFE_XATTR);
omd_mov = (char *)rec +
changelog_rec_offset(crf_wanted & CLF_SUPPORTED,
- cref_want & ~CLFE_OPEN);
+ cref_want & ~(CLFE_OPEN |
+ CLFE_XATTR));
nid_mov = (char *)rec +
changelog_rec_offset(crf_wanted & CLF_SUPPORTED,
cref_want & ~(CLFE_NID |
- CLFE_OPEN));
+ CLFE_OPEN |
+ CLFE_XATTR));
uidgid_mov = (char *)rec +
changelog_rec_offset(crf_wanted & CLF_SUPPORTED,
cref_want & ~(CLFE_UIDGID |
CLFE_NID |
- CLFE_OPEN));
+ CLFE_OPEN |
+ CLFE_XATTR));
cref = changelog_rec_extra_flags(rec)->cr_extra_flags;
}
/* Move the extension fields to the desired positions */
if ((crf_wanted & CLF_EXTRA_FLAGS) &&
(rec->cr_flags & CLF_EXTRA_FLAGS)) {
+ if ((cref_want & CLFE_XATTR) && (cref & CLFE_XATTR))
+ memmove(xattr_mov, changelog_rec_xattr(rec),
+ sizeof(struct changelog_ext_xattr));
+
if ((cref_want & CLFE_OPEN) && (cref & CLFE_OPEN))
memmove(omd_mov, changelog_rec_openmode(rec),
sizeof(struct changelog_ext_openmode));
sizeof(struct changelog_ext_rename));
/* Clear newly added fields */
+ if (xattr_mov && (cref_want & CLFE_XATTR) &&
+ !(cref & CLFE_XATTR))
+ memset(xattr_mov, 0, sizeof(struct changelog_ext_xattr));
+
if (omd_mov && (cref_want & CLFE_OPEN) &&
!(cref & CLFE_OPEN))
memset(omd_mov, 0, sizeof(struct changelog_ext_openmode));
LLOG_F_EXT_EXTRA_FLAGS |
LLOG_F_EXT_X_UIDGID |
LLOG_F_EXT_X_NID |
- LLOG_F_EXT_X_OMODE,
+ LLOG_F_EXT_X_OMODE |
+ LLOG_F_EXT_X_XATTR,
NULL);
if (rc) {
CERROR("%s: fail to init llog handle: rc = %d\n",
omd->cr_openflags = (__u32)flags;
}
+void mdd_changelog_rec_extra_xattr(struct changelog_rec *rec,
+ const char *xattr_name)
+{
+ struct changelog_ext_xattr *xattr = changelog_rec_xattr(rec);
+
+ strlcpy(xattr->cr_xattr, xattr_name, sizeof(xattr->cr_xattr));
+}
+
/** 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.
void mdd_changelog_rec_extra_nid(struct changelog_rec *rec,
lnet_nid_t nid);
void mdd_changelog_rec_extra_omode(struct changelog_rec *rec, int flags);
+void mdd_changelog_rec_extra_xattr(struct changelog_rec *rec,
+ const char *xattr_name);
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 md_object *obj, struct lu_buf *buf,
const char *name);
+static int mdd_changelog_data_store_by_fid(const struct lu_env *env,
+ struct mdd_device *mdd,
+ enum changelog_rec_type type,
+ int flags, const struct lu_fid *fid,
+ const char *xattr_name,
+ struct thandle *handle);
+
+static inline bool has_prefix(const char *str, const char *prefix);
+
int mdd_la_get(const struct lu_env *env, struct mdd_object *obj,
struct lu_attr *la)
{
struct md_object *obj, struct lu_buf *buf,
const char *name)
{
- struct mdd_object *mdd_obj = md2mdd_obj(obj);
- int rc;
+ struct mdd_object *mdd_obj = md2mdd_obj(obj);
+ struct md_device *md_dev = lu2md_dev(mdd2lu_dev(mdo2mdd(obj)));
+ int rc;
- ENTRY;
+ ENTRY;
- if (mdd_object_exists(mdd_obj) == 0) {
- CERROR("%s: object "DFID" not found: rc = -2\n",
- mdd_obj_dev_name(mdd_obj),PFID(mdd_object_fid(mdd_obj)));
- return -ENOENT;
- }
+ if (mdd_object_exists(mdd_obj) == 0) {
+ CERROR("%s: object "DFID" not found: rc = -2\n",
+ mdd_obj_dev_name(mdd_obj),
+ PFID(mdd_object_fid(mdd_obj)));
+ return -ENOENT;
+ }
/* If the object has been destroyed, then do not get LMVEA, because
* it needs to load stripes from the iteration of the master object,
strcmp(name, XATTR_NAME_LINK) == 0))
RETURN(-ENOENT);
- mdd_read_lock(env, mdd_obj, MOR_TGT_CHILD);
+ mdd_read_lock(env, mdd_obj, MOR_TGT_CHILD);
rc = mdo_xattr_get(env, mdd_obj, buf, name);
- mdd_read_unlock(env, mdd_obj);
+ mdd_read_unlock(env, mdd_obj);
+
+ /* record only getting user xattrs and acls */
+ if (rc >= 0 &&
+ (has_prefix(name, XATTR_USER_PREFIX) ||
+ has_prefix(name, XATTR_NAME_POSIX_ACL_ACCESS) ||
+ has_prefix(name, XATTR_NAME_POSIX_ACL_DEFAULT))) {
+ struct thandle *handle;
+ struct mdd_device *mdd = lu2mdd_dev(&md_dev->md_lu_dev);
+ int rc2;
+
+ /* Not recording */
+ if (!(mdd->mdd_cl.mc_flags & CLM_ON))
+ RETURN(rc);
+ if (!(mdd->mdd_cl.mc_mask & (1 << CL_GETXATTR)))
+ RETURN(rc);
- RETURN(rc);
+ LASSERT(mdo2fid(mdd_obj) != NULL);
+
+ handle = mdd_trans_create(env, mdd);
+ if (IS_ERR(handle))
+ RETURN(PTR_ERR(handle));
+
+ rc2 = mdd_declare_changelog_store(env, mdd, NULL, NULL, handle);
+ if (rc2)
+ GOTO(stop, rc2);
+
+ rc2 = mdd_trans_start(env, mdd, handle);
+ if (rc2)
+ GOTO(stop, rc2);
+
+ rc2 = mdd_changelog_data_store_by_fid(env, mdd, CL_GETXATTR, 0,
+ mdo2fid(mdd_obj), name,
+ handle);
+
+stop:
+ rc2 = mdd_trans_stop(env, mdd, rc2, handle);
+ if (rc2)
+ rc = rc2;
+ }
+
+ RETURN(rc);
}
/*
}
static int mdd_changelog_data_store_by_fid(const struct lu_env *env,
- struct mdd_device *mdd,
- enum changelog_rec_type type, int flags,
- const struct lu_fid *fid,
- struct thandle *handle)
+ struct mdd_device *mdd,
+ enum changelog_rec_type type,
+ int flags, const struct lu_fid *fid,
+ const char *xattr_name,
+ struct thandle *handle)
{
const struct lu_ucred *uc = lu_ucred(env);
struct llog_changelog_rec *rec;
}
if (type == CL_OPEN)
xflags |= CLFE_OPEN;
+ if (type == CL_SETXATTR || type == CL_GETXATTR)
+ xflags |= CLFE_XATTR;
reclen = llog_data_len(LLOG_CHANGELOG_HDR_SZ +
changelog_rec_offset(flags & CLF_SUPPORTED,
mdd_changelog_rec_extra_nid(&rec->cr, uc->uc_nid);
if (xflags & CLFE_OPEN)
mdd_changelog_rec_extra_omode(&rec->cr, flags);
+ if (xflags & CLFE_XATTR) {
+ if (xattr_name == NULL)
+ RETURN(-EINVAL);
+ mdd_changelog_rec_extra_xattr(&rec->cr, xattr_name);
+ }
}
rc = mdd_changelog_store(env, mdd, rec, handle);
}
rc = mdd_changelog_data_store_by_fid(env, mdd, type, flags,
- mdo2fid(mdd_obj), handle);
+ mdo2fid(mdd_obj), NULL, handle);
+ if (rc == 0)
+ mdd_obj->mod_cltime = ktime_get();
+
+ RETURN(rc);
+}
+
+static int mdd_changelog_data_store_xattr(const struct lu_env *env,
+ struct mdd_device *mdd,
+ enum changelog_rec_type type,
+ int flags, struct mdd_object *mdd_obj,
+ const char *xattr_name,
+ struct thandle *handle)
+{
+ int rc;
+
+ LASSERT(mdd_obj != NULL);
+ LASSERT(handle != NULL);
+
+ /* Not recording */
+ if (!(mdd->mdd_cl.mc_flags & CLM_ON))
+ RETURN(0);
+ if ((mdd->mdd_cl.mc_mask & (1 << type)) == 0)
+ RETURN(0);
+
+ if (mdd_is_volatile_obj(mdd_obj))
+ RETURN(0);
+
+ if ((type >= CL_MTIME) && (type <= CL_ATIME) &&
+ ktime_before(mdd->mdd_cl.mc_starttime, mdd_obj->mod_cltime)) {
+ /* Don't need multiple updates in this log */
+ /* Don't check under lock - no big deal if we get an extra
+ * entry
+ */
+ RETURN(0);
+ }
+
+ rc = mdd_changelog_data_store_by_fid(env, mdd, type, flags,
+ mdo2fid(mdd_obj), xattr_name,
+ handle);
if (rc == 0)
mdd_obj->mod_cltime = ktime_get();
GOTO(stop, rc);
rc = mdd_changelog_data_store_by_fid(env, mdd, type, flags,
- fid, handle);
+ fid, NULL, handle);
stop:
rc = mdd_trans_stop(env, mdd, rc, handle);
if (has_prefix(xattr_name, XATTR_USER_PREFIX) ||
has_prefix(xattr_name, XATTR_NAME_POSIX_ACL_ACCESS) ||
- has_prefix(xattr_name, XATTR_NAME_POSIX_ACL_DEFAULT))
- return CL_XATTR;
+ has_prefix(xattr_name, XATTR_NAME_POSIX_ACL_DEFAULT) ||
+ has_prefix(xattr_name, XATTR_TRUSTED_PREFIX) ||
+ has_prefix(xattr_name, XATTR_SECURITY_PREFIX))
+ return CL_SETXATTR;
return -1;
}
if (cl_type < 0)
GOTO(stop, rc = 0);
- rc = mdd_changelog_data_store(env, mdd, cl_type, cl_flags, mdd_obj,
- handle);
+ rc = mdd_changelog_data_store_xattr(env, mdd, cl_type, cl_flags,
+ mdd_obj, name, handle);
EXIT;
stop:
if (mdd_xattr_changelog_type(env, mdd, name) < 0)
GOTO(stop, rc = 0);
- rc = mdd_changelog_data_store(env, mdd, CL_XATTR, 0, mdd_obj, handle);
+ rc = mdd_changelog_data_store_xattr(env, mdd, CL_SETXATTR, 0, mdd_obj,
+ name, handle);
EXIT;
stop:
enum changelog_rec_flags flags = CLF_SUPPORTED;
enum changelog_rec_extra_flags extra_flags = CLFE_SUPPORTED;
+ if (!(loghandle->lgh_hdr->llh_flags & LLOG_F_EXT_X_XATTR))
+ extra_flags &= ~CLFE_XATTR;
if (!(loghandle->lgh_hdr->llh_flags & LLOG_F_EXT_X_OMODE))
extra_flags &= ~CLFE_OPEN;
if (!(loghandle->lgh_hdr->llh_flags & LLOG_F_EXT_X_NID))
rc = llapi_changelog_set_xflags(changelog_priv,
CHANGELOG_EXTRA_FLAG_UIDGID |
CHANGELOG_EXTRA_FLAG_NID |
- CHANGELOG_EXTRA_FLAG_OMODE);
+ CHANGELOG_EXTRA_FLAG_OMODE |
+ CHANGELOG_EXTRA_FLAG_XATTR);
if (rc < 0) {
fprintf(stderr, "Can't set xflags for changelog: %s\n",
strerror(errno = -rc));
printf(" m=%s", mode);
}
+
+ if (ef->cr_extra_flags & CLFE_XATTR) {
+ struct changelog_ext_xattr *xattr =
+ changelog_rec_xattr(rec);
+
+ if (xattr->cr_xattr[0] != '\0')
+ printf(" x=%s", xattr->cr_xattr);
+ }
}
if (rec->cr_namelen)
rec_extra_fmt |= CLFE_NID;
if (cp->clp_send_extra_flags & CHANGELOG_EXTRA_FLAG_OMODE)
rec_extra_fmt |= CLFE_OPEN;
+ if (cp->clp_send_extra_flags & CHANGELOG_EXTRA_FLAG_XATTR)
+ rec_extra_fmt |= CLFE_XATTR;
}
if (cp->clp_buf + cp->clp_buf_len <= cp->clp_buf_pos) {
rc = llapi_changelog_set_xflags(changelog_priv,
CHANGELOG_EXTRA_FLAG_UIDGID |
CHANGELOG_EXTRA_FLAG_NID |
- CHANGELOG_EXTRA_FLAG_OMODE);
+ CHANGELOG_EXTRA_FLAG_OMODE |
+ CHANGELOG_EXTRA_FLAG_XATTR);
if (rc < 0) {
fprintf(stderr, "Error setting xflag in changelog for fs %s.\n",
status->ls_source_fs);
case CL_SETATTR:
rc = lr_setattr(info);
break;
- case CL_XATTR:
+ case CL_SETXATTR:
rc = lr_setxattr(info);
break;
case CL_CLOSE:
case CL_EXT:
case CL_OPEN:
+ case CL_GETXATTR:
case CL_LAYOUT:
case CL_MARK:
/* Nothing needs to be done for these entries */