/** to create directory */
const struct dt_index_features *sp_feat;
+
+ /* name of xattr used to store jobid in inode, or empty if disabled */
+ char sp_cr_job_xattr[XATTR_JOB_MAX_LEN];
};
enum md_layout_opc {
#define XATTR_NAME_LFSCK_NAMESPACE "trusted.lfsck_ns"
#define XATTR_NAME_MAX_LEN 32 /* increase this, if there is longer name. */
+#define XATTR_NAME_JOB_DEFAULT "user.job"
+/* longest allowed jobid xattr name is "user." + 7 chars + null terminator */
+#define XATTR_JOB_MAX_LEN 13
+
struct lov_mds_md_v3 { /* LOV EA mds/wire data (little-endian) */
__u32 lmm_magic; /* magic number = LOV_MAGIC_V3 */
__u32 lmm_pattern; /* LOV_PATTERN_RAID0, LOV_PATTERN_RAID1 */
struct lu_buf *def_acl_buf,
struct lu_buf *hsm_buf,
struct dt_allocation_hint *hint,
- struct thandle *handle, bool initsecctx)
+ struct thandle *handle, bool initial_create)
{
+ const struct lu_fid *son_fid = mdd_object_fid(son);
+ const struct lu_ucred *uc = lu_ucred(env);
+ const char *jobid = uc->uc_jobid;
const struct lu_buf *buf;
+ size_t jobid_len;
int rc;
mdd_write_lock(env, son, DT_TGT_CHILD);
GOTO(err_initlized, rc = -EFAULT);
}
- if (initsecctx && spec->sp_cr_file_secctx_name != NULL) {
+ if (initial_create && spec->sp_cr_file_secctx_name != NULL) {
buf = mdd_buf_get_const(env, spec->sp_cr_file_secctx,
spec->sp_cr_file_secctx_size);
rc = mdo_xattr_set(env, son, buf, spec->sp_cr_file_secctx_name,
GOTO(err_initlized, rc);
}
+ if (initial_create &&
+ spec->sp_cr_job_xattr[0] != '\0' &&
+ jobid[0] != '\0' &&
+ (S_ISREG(attr->la_mode) || S_ISDIR(attr->la_mode))) {
+ jobid_len = strnlen(jobid, LUSTRE_JOBID_SIZE);
+ buf = mdd_buf_get_const(env, jobid, jobid_len);
+
+ rc = mdo_xattr_set(env, son, buf, spec->sp_cr_job_xattr,
+ LU_XATTR_CREATE, handle);
+
+ /* this xattr is nonessential, so ignore errors. */
+ if (rc != 0) {
+ CDEBUG(D_INODE,
+ DFID" failed to set xattr '%s': rc = %d\n",
+ PFID(son_fid), spec->sp_cr_job_xattr, rc);
+ rc = 0;
+ }
+ }
+
err_initlized:
if (unlikely(rc != 0)) {
int rc2;
/* Set this lu_device to obd for error handling purposes. */
obd->obd_lu_dev = &m->mdt_lu_dev;
+ strncpy(m->mdt_job_xattr, XATTR_NAME_JOB_DEFAULT, XATTR_JOB_MAX_LEN);
+
/* init the stack */
rc = mdt_stack_init((struct lu_env *)env, m, cfg);
if (rc) {
/* count of old clients that doesn't support DMV implicite inherit */
atomic_t mdt_dmv_old_client_count;
+
+ /* name of xattr used to store jobid in mdt inode */
+ char mdt_job_xattr[XATTR_JOB_MAX_LEN];
};
#define MDT_SERVICE_WATCHDOG_FACTOR (2)
return 0;
}
+ssize_t job_xattr_show(struct kobject *kobj, struct attribute *attr, char *buf)
+{
+ struct obd_device *obd = container_of(kobj, struct obd_device,
+ obd_kset.kobj);
+ struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
+
+ if (mdt->mdt_job_xattr[0] == '\0')
+ return scnprintf(buf, PAGE_SIZE, "NONE\n");
+
+ return scnprintf(buf, PAGE_SIZE, "%s\n", mdt->mdt_job_xattr);
+}
+
+/**
+ * Read in a name for the jobid xattr and validate it.
+ * The only valid names are "trusted.job" or "user.*" where the name portion
+ * is <= 7 bytes in the user namespace. Only alphanumeric characters are
+ * allowed, aside from the namespace separator '.'.
+ *
+ * "none" is a valid value to turn this feature off.
+ *
+ * @return -EINVAL if the name is invalid, else count
+ */
+ssize_t job_xattr_store(struct kobject *kobj, struct attribute *attr,
+ const char *buffer, size_t count)
+{
+ struct obd_device *obd = container_of(kobj, struct obd_device,
+ obd_kset.kobj);
+ struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
+ char name[XATTR_JOB_MAX_LEN] = { 0 };
+ char *p;
+
+
+ /* writing "none" turns this off by leaving the name empty */
+ if (!strncmp(buffer, "none", 4) ||
+ !strncmp(buffer, "NONE", 4)) {
+ memset(mdt->mdt_job_xattr, 0, sizeof(mdt->mdt_job_xattr));
+ return count;
+ }
+
+ /* account for stripping \n before rejecting name for being too long */
+ if (count > XATTR_JOB_MAX_LEN - 1 &&
+ buffer[XATTR_JOB_MAX_LEN - 1] != '\n')
+ return -EINVAL;
+
+ strncpy(name, buffer, XATTR_JOB_MAX_LEN - 1);
+
+ /* reject if not in namespace.name format */
+ p = strchr(name, '.');
+ if (p == NULL)
+ return -EINVAL;
+
+ p++;
+ for (; *p != '\0'; p++) {
+ /*
+ * if there are any non-alphanumeric characters, the name is
+ * invalid unless it's a newline, in which case overwrite it
+ * with '\0' and that's the end of the name.
+ */
+ if (!isalnum(*p)) {
+ if (*p != '\n')
+ return -EINVAL;
+ *p = '\0';
+ }
+ }
+
+ /* trusted.job is only valid name in trusted namespace */
+ if (!strncmp(name, "trusted.job", 12)) {
+ strncpy(mdt->mdt_job_xattr, name, XATTR_JOB_MAX_LEN);
+ return count;
+ }
+
+ /* only other valid namespace is user */
+ if (strncmp(name, XATTR_USER_PREFIX, sizeof(XATTR_USER_PREFIX) - 1))
+ return -EINVAL;
+
+ /* ensure that a name was specified */
+ if (name[sizeof(XATTR_USER_PREFIX) - 1] == '\0')
+ return -EINVAL;
+
+ strncpy(mdt->mdt_job_xattr, name, XATTR_JOB_MAX_LEN);
+
+ return count;
+}
+
LPROC_SEQ_FOPS_RO(mdt_checksum_type);
LPROC_SEQ_FOPS_RO_TYPE(mdt, hash);
LPROC_SEQ_FOPS_WR_ONLY(mdt, mds_evict_client);
LPROC_SEQ_FOPS_RW_TYPE(mdt, checksum_dump);
LUSTRE_RW_ATTR(job_cleanup_interval);
+LUSTRE_RW_ATTR(job_xattr);
LPROC_SEQ_FOPS_RW_TYPE(mdt, nid_stats_clear);
LUSTRE_RW_ATTR(hsm_control);
&lustre_attr_migrate_hsm_allowed.attr,
&lustre_attr_hsm_control.attr,
&lustre_attr_job_cleanup_interval.attr,
+ &lustre_attr_job_xattr.attr,
&lustre_attr_readonly.attr,
&lustre_attr_dir_split_count.attr,
&lustre_attr_dir_split_delta.attr,
info->mti_spec.sp_cr_lookup = 0;
info->mti_spec.sp_feat = &dt_directory_features;
+ /* set jobid xattr name from sysfs parameter */
+ strncpy(info->mti_spec.sp_cr_job_xattr, mdt->mdt_job_xattr,
+ XATTR_JOB_MAX_LEN);
+
result = mdo_create(info->mti_env, mdt_object_child(parent),
&rr->rr_name, mdt_object_child(child),
&info->mti_spec, &info->mti_attr);
info->mti_spec.sp_cr_lookup = 1;
info->mti_spec.sp_feat = &dt_directory_features;
+ /* set jobid xattr name from sysfs parameter */
+ strncpy(info->mti_spec.sp_cr_job_xattr, mdt->mdt_job_xattr,
+ XATTR_JOB_MAX_LEN);
+
rc = mdo_create(info->mti_env, mdt_object_child(parent), &rr->rr_name,
mdt_object_child(child), &info->mti_spec, ma);
if (rc == 0)
which setfacl || skip_env "could not find setfacl"
remote_mds_nodsh && skip "remote MDS with nodsh"
+ local mdts=$(comma_list $(mdts_nodes))
+ local saved=$(do_facet mds1 $LCTL get_param -n mdt.$FSNAME-MDT0000.job_xattr)
+
+ do_nodes $mdts $LCTL set_param mdt.*.job_xattr=NONE
+ stack_trap "do_nodes $mdts $LCTL set_param mdt.*.job_xattr=$saved" EXIT
+
ACLBIN=${ACLBIN:-"bin"}
ACLDMN=${ACLDMN:-"daemon"}
ACLGRP=${ACLGRP:-"users"}
}
run_test 205g "stress test for job_stats procfile"
+test_205h() {
+ which getfattr > /dev/null 2>&1 || skip_env "no getfattr command"
+
+ local dir=$DIR/$tdir
+ local f=$dir/$tfile
+ local f2=$dir/$tfile-2
+ local f3=$dir/$tfile-3
+ local subdir=$DIR/dir
+ local val
+
+ local mdts=$(comma_list $(mdts_nodes))
+ local mds_saved=$(do_facet mds1 $LCTL get_param -n mdt.$FSNAME-MDT0000.job_xattr)
+ local client_saved=$($LCTL get_param -n jobid_var)
+
+ stack_trap "do_nodes $mdts $LCTL set_param mdt.*.job_xattr=$mds_saved" EXIT
+ stack_trap "$LCTL set_param jobid_var=$client_saved" EXIT
+
+ do_nodes $mdts $LCTL set_param mdt.*.job_xattr=user.job ||
+ error "failed to set job_xattr parameter to user.job"
+ $LCTL set_param jobid_var=procname.uid ||
+ error "failed to set jobid_var parameter"
+
+ test_mkdir $dir
+
+ touch $f
+ val=$(getfattr -n user.job $f | grep user.job)
+ [[ $val = user.job=\"touch.0\" ]] ||
+ error "expected user.job=\"touch.0\", got '$val'"
+
+ mkdir $subdir
+ val=$(getfattr -n user.job $subdir | grep user.job)
+ [[ $val = user.job=\"mkdir.0\" ]] ||
+ error "expected user.job=\"mkdir.0\", got '$val'"
+
+ do_nodes $mdts $LCTL set_param mdt.*.job_xattr=NONE ||
+ error "failed to set job_xattr parameter to NONE"
+
+ touch $f2
+ val=$(getfattr -d $f2)
+ [[ -z $val ]] ||
+ error "expected no user xattr, got '$val'"
+
+ do_nodes $mdts $LCTL set_param mdt.*.job_xattr=trusted.job ||
+ error "failed to set job_xattr parameter to trusted.job"
+
+ touch $f3
+ val=$(getfattr -n trusted.job $f3 | grep trusted.job)
+ [[ $val = trusted.job=\"touch.0\" ]] ||
+ error "expected trusted.job=\"touch.0\", got '$val'"
+}
+run_test 205h "check jobid xattr is stored correctly"
+
+test_205i() {
+ local mdts=$(comma_list $(mdts_nodes))
+ local mds_saved=$(do_facet mds1 $LCTL get_param -n mdt.$FSNAME-MDT0000.job_xattr)
+
+ stack_trap "do_nodes $mdts $LCTL set_param mdt.*.job_xattr=$mds_saved" EXIT
+
+ do_nodes $mdts $LCTL set_param mdt.*.job_xattr=user.1234567 ||
+ error "failed to set mdt.*.job_xattr to user.1234567"
+
+ do_nodes $mdts $LCTL set_param mdt.*.job_xattr=user.12345678 &&
+ error "failed to reject too long job_xattr name"
+
+ do_nodes $mdts $LCTL set_param mdt.*.job_xattr=userjob &&
+ error "failed to reject job_xattr name in bad format"
+
+ do_nodes $mdts $LCTL set_param mdt.*.job_xattr=user.job/ &&
+ error "failed to reject job_xattr name with invalid character"
+
+ do_nodes $mdts "printf 'mdt.*.job_xattr=user.job\x80' |
+ xargs $LCTL set_param" &&
+ error "failed to reject job_xattr name with non-ascii character"
+
+ return 0
+}
+run_test 205i "check job_xattr parameter accepts and rejects values correctly"
+
# LU-1480, LU-1773 and LU-1657
test_206() {
mkdir -p $DIR/$tdir