.br
.B lfs check \fR<\fBmgts\fR|\fBmdts\fR|\fBosts\fR|\fBall\fR> [\fIpath\fR]
.br
-.B lfs data_version \fR[\fB-nrw\fR] \fB<\fIfilename\fR>
+.B lfs data_version \fR[\fB-nrws\fR] \fB<\fIfilename\fR>
.br
.B lfs df \fR[\fB-ihlv\fR] [\fB--pool\fR|\fB-p \fR<\fIfsname\fR>[.<\fIpool\fR>]] [\fIpath\fR]
.br
all the servers (MGTs, MDTs and OSTs). If \fBpath\fR is provided, display
the status of the lustre file system mounted at specified \fBpath\fR only.
.TP
-.B data_version [-nrw] <filename>
-Display the current version of file data. If -n is specified, the data version
-is read without taking a lock. As a consequence, the data version could be
-outdated if there are dirty caches on filesystem clients, but this option will
-not force data flushes and has less of an impact on the filesystem. If -r is
-specified, the data version is read after dirty pages on clients are flushed. If
--w is specified, the data version is read after all caching pages on clients are
-flushed.
+.B data_version [-nrws] <filename>
+Display the current version of file data and optionally set the data version
+stored in the HSM xattr. If -n is specified, the data version is read without
+taking a lock. As a consequence, the data version could be outdated if there are
+dirty caches on filesystem clients, but this option will not force data flushes
+and has less of an impact on the filesystem. If -r is specified, the data
+version is read after dirty pages on clients are flushed. If -w is specified,
+the data version is read after all caching pages on clients are flushed. If -s
+is specified, the data version that was read, is also written to the HSM xattr.
Even with -r or -w, race conditions are possible and the data version should be
checked before and after an operation to be confident the data did not change
int llapi_get_data_version(int fd, __u64 *data_version, __u64 flags);
int llapi_file_flush(int fd);
extern int llapi_get_ost_layout_version(int fd, __u32 *layout_version);
+int llapi_hsm_data_version_set(int fd, __u64 data_version);
int llapi_hsm_state_get_fd(int fd, struct hsm_user_state *hus);
int llapi_hsm_state_get(const char *path, struct hsm_user_state *hus);
int llapi_hsm_state_set_fd(int fd, __u64 setmask, __u64 clearmask,
extern struct req_format RQF_MDS_HSM_CT_REGISTER;
extern struct req_format RQF_MDS_HSM_CT_UNREGISTER;
extern struct req_format RQF_MDS_HSM_REQUEST;
+extern struct req_format RQF_MDS_HSM_DATA_VERSION;
/* OST req_format */
extern struct req_format RQF_OST_CONNECT;
extern struct req_format RQF_OST_DISCONNECT;
#define OBD_FAIL_MDS_HSM_RESTORE_RACE 0x18b
#define OBD_FAIL_MDS_CHANGELOG_ENOSPC 0x18c
#define OBD_FAIL_MDS_BATCH_NET 0x18d
+#define OBD_FAIL_MDS_HSM_DATA_VERSION_NET 0x18e
/* OI scrub */
#define OBD_FAIL_OSD_SCRUB_DELAY 0x190
MDS_SWAP_LAYOUTS = 61,
MDS_RMFID = 62,
MDS_BATCH = 63,
+ MDS_HSM_DATA_VERSION = 64,
MDS_LAST_OPC
};
struct lu_pcc_detach_fid)
#define LL_IOC_PCC_STATE _IOR('f', 252, struct lu_pcc_state)
#define LL_IOC_PROJECT _IOW('f', 253, struct lu_project)
+#define LL_IOC_HSM_DATA_VERSION _IOW('f', 254, struct ioc_data_version)
#ifndef FS_IOC_FSGETXATTR
/*
RETURN(rc);
}
+static int ll_hsm_data_version_sync(struct inode *inode, __u64 data_version)
+{
+ struct obd_export *exp = ll_i2mdexp(inode);
+ struct md_op_data *op_data;
+ int rc;
+ ENTRY;
+
+ if (!data_version)
+ RETURN(-EINVAL);
+
+ op_data = ll_prep_md_op_data(NULL, inode, NULL, NULL, 0, 0,
+ LUSTRE_OPC_ANY, NULL);
+ if (IS_ERR(op_data))
+ RETURN(PTR_ERR(op_data));
+
+ op_data->op_data_version = data_version;
+
+ rc = obd_iocontrol(LL_IOC_HSM_DATA_VERSION, exp, sizeof(*op_data),
+ op_data, NULL);
+
+ ll_finish_md_op_data(op_data);
+
+ RETURN(rc);
+}
+
static int ll_hsm_import(struct inode *inode, struct file *file,
struct hsm_user_import *hui)
{
OBD_FREE_PTR(hca);
RETURN(rc);
}
+ case LL_IOC_HSM_DATA_VERSION: {
+ __u64 data_version;
+
+ if (get_user(data_version, (u64 __user *)arg))
+ RETURN(-EFAULT);
+
+ rc = ll_hsm_data_version_sync(inode, data_version);
+
+ RETURN(rc);
+ }
case LL_IOC_SET_LEASE_OLD: {
struct ll_ioc_lease ioc = { .lil_mode = arg };
}
case LL_IOC_HSM_STATE_GET:
case LL_IOC_HSM_STATE_SET:
+ case LL_IOC_HSM_DATA_VERSION:
case LL_IOC_HSM_ACTION: {
struct md_op_data *op_data = karg;
return rc;
}
+static int mdc_ioc_hsm_data_version(struct obd_export *exp,
+ struct md_op_data *op_data)
+{
+ struct ptlrpc_request *req;
+ struct mdt_body *b;
+ int rc;
+ ENTRY;
+
+ req = ptlrpc_request_alloc(class_exp2cliimp(exp),
+ &RQF_MDS_HSM_DATA_VERSION);
+ if (req == NULL)
+ RETURN(-ENOMEM);
+
+ rc = ptlrpc_request_pack(req, LUSTRE_MDS_VERSION, MDS_HSM_DATA_VERSION);
+ if (rc) {
+ ptlrpc_request_free(req);
+ RETURN(rc);
+ }
+
+ mdc_pack_body(&req->rq_pill, &op_data->op_fid1, 0, 0,
+ op_data->op_suppgids[0], 0);
+
+ b = req_capsule_client_get(&req->rq_pill, &RMF_MDT_BODY);
+ LASSERT(b);
+
+ b->mbo_version = op_data->op_data_version;
+
+ ptlrpc_request_set_replen(req);
+
+ ptlrpc_get_mod_rpc_slot(req);
+ rc = ptlrpc_queue_wait(req);
+ ptlrpc_put_mod_rpc_slot(req);
+
+ GOTO(out, rc);
+out:
+ ptlrpc_req_put(req);
+ return rc;
+}
static int mdc_ioc_hsm_ct_start(struct obd_export *exp,
struct lustre_kernelcomm *lk);
static int mdc_quotactl(struct obd_device *unused, struct obd_export *exp,
case LL_IOC_HSM_REQUEST:
rc = mdc_ioc_hsm_request(exp, karg);
GOTO(out, rc);
+ case LL_IOC_HSM_DATA_VERSION:
+ rc = mdc_ioc_hsm_data_version(exp, karg);
+ GOTO(out, rc);
case OBD_IOC_CLIENT_RECOVER:
rc = ptlrpc_recover_import(imp, data->ioc_inlbuf1, 0);
if (rc < 0)
TGT_MDT_HDL(HAS_KEY | HAS_BODY | HAS_REPLY | IS_MUTABLE,
MDS_SWAP_LAYOUTS,
mdt_swap_layouts),
+TGT_MDT_HDL(HAS_BODY | HAS_REPLY | IS_MUTABLE, MDS_HSM_DATA_VERSION,
+ mdt_hsm_data_version),
TGT_MDT_HDL(IS_MUTABLE, MDS_RMFID, mdt_rmfid),
TGT_MDT_HDL(IS_MUTABLE, MDS_BATCH, mdt_batch),
};
}
/**
+ * Set the data version in the HSM xattr of a file.
+ *
+ * This is MDS_HSM_DATA_VERSION RPC handler.
+ */
+int mdt_hsm_data_version(struct tgt_session_info *tsi)
+{
+ struct mdt_thread_info *info = tsi2mdt_info(tsi);
+ struct mdt_object *obj = info->mti_object;
+ struct md_attr *ma = &info->mti_attr;
+ struct mdt_lock_handle *lh;
+ int rc;
+ ENTRY;
+
+ if (info->mti_body == NULL || obj == NULL)
+ GOTO(out, rc = -EPROTO);
+
+ /* Only valid if client is remote */
+ rc = mdt_init_ucred(info, (struct mdt_body *)info->mti_body);
+ if (rc < 0)
+ GOTO(out, rc = err_serious(rc));
+
+ lh = &info->mti_lh[MDT_LH_CHILD];
+ rc = mdt_object_lock(info, obj, lh, MDS_INODELOCK_LOOKUP |
+ MDS_INODELOCK_XATTR, LCK_PW);
+ if (rc < 0)
+ GOTO(out_ucred, rc);
+
+ /* Read current HSM info */
+ ma->ma_valid = 0;
+ ma->ma_need = MA_HSM;
+ rc = mdt_attr_get_complex(info, obj, ma);
+ if (rc)
+ GOTO(out_unlock, rc);
+
+ if (unlikely(!info->mti_body->mbo_version)) {
+ CDEBUG(D_HSM, "Can't set HSM xattr data version to zero "
+ DFID"\n", PFID(&info->mti_body->mbo_fid1));
+ GOTO(out_unlock, rc = -EINVAL);
+ } else {
+ CDEBUG(D_HSM, "Setting HSM xattr data version to %llu "DFID"\n",
+ info->mti_body->mbo_version,
+ PFID(&info->mti_body->mbo_fid1));
+ }
+
+ ma->ma_hsm.mh_arch_ver = info->mti_body->mbo_version;
+
+ /* Save the data version */
+ rc = mdt_hsm_attr_set(info, obj, &ma->ma_hsm);
+ if (rc)
+ GOTO(out_unlock, rc);
+
+ EXIT;
+
+out_unlock:
+ mdt_object_unlock(info, obj, lh, 1);
+out_ucred:
+ mdt_exit_ucred(info);
+out:
+ mdt_thread_info_fini(info);
+ return rc;
+}
+
+/**
* Retrieve undergoing HSM requests for the fid provided in RPC body.
* Current requests are read from coordinator states.
*
int mdt_hsm_ct_register(struct tgt_session_info *tsi);
int mdt_hsm_ct_unregister(struct tgt_session_info *tsi);
int mdt_hsm_request(struct tgt_session_info *tsi);
+int mdt_hsm_data_version(struct tgt_session_info *tsi);
/* mdt/mdt_hsm_cdt_actions.c */
extern const struct file_operations mdt_hsm_actions_fops;
&RMF_GENERIC_DATA,
};
+static const struct req_msg_field *mdt_hsm_data_version[] = {
+ &RMF_PTLRPC_BODY,
+ &RMF_MDT_BODY
+};
+
static const struct req_msg_field *obd_lfsck_request[] = {
&RMF_PTLRPC_BODY,
&RMF_LFSCK_REQUEST,
&RQF_MDS_HSM_STATE_SET,
&RQF_MDS_HSM_ACTION,
&RQF_MDS_HSM_REQUEST,
+ &RQF_MDS_HSM_DATA_VERSION,
&RQF_MDS_SWAP_LAYOUTS,
&RQF_MDS_RMFID,
#ifdef HAVE_SERVER_SUPPORT
DEFINE_REQ_FMT0("MDS_HSM_REQUEST", mdt_hsm_request, empty);
EXPORT_SYMBOL(RQF_MDS_HSM_REQUEST);
+struct req_format RQF_MDS_HSM_DATA_VERSION =
+ DEFINE_REQ_FMT0("MDS_HSM_DATA_VERSION", mdt_hsm_data_version, empty);
+EXPORT_SYMBOL(RQF_MDS_HSM_DATA_VERSION);
+
struct req_format RQF_MDS_SWAP_LAYOUTS =
DEFINE_REQ_FMT0("MDS_SWAP_LAYOUTS",
mdt_swap_layouts, empty);
{ MDS_SWAP_LAYOUTS, "mds_swap_layouts" },
{ MDS_RMFID, "mds_rmfid" },
{ MDS_BATCH, "mds_batch" },
+ { MDS_HSM_DATA_VERSION, "mds_hsm_data_version" },
{ LDLM_ENQUEUE, "ldlm_enqueue" },
{ LDLM_CONVERT, "ldlm_convert" },
{ LDLM_CANCEL, "ldlm_cancel" },
(long long)MDS_RMFID);
LASSERTF(MDS_BATCH == 63, "found %lld\n",
(long long)MDS_BATCH);
- LASSERTF(MDS_LAST_OPC == 64, "found %lld\n",
+ LASSERTF(MDS_HSM_DATA_VERSION == 64, "found %lld\n",
+ (long long)MDS_HSM_DATA_VERSION);
+ LASSERTF(MDS_LAST_OPC == 65, "found %lld\n",
(long long)MDS_LAST_OPC);
LASSERTF(REINT_SETATTR == 1, "found %lld\n",
(long long)REINT_SETATTR);
case MDS_HSM_PROGRESS:
case MDS_HSM_STATE_SET:
case MDS_HSM_REQUEST:
+ case MDS_HSM_DATA_VERSION:
case OST_FALLOCATE:
*process = target_queue_recovery_request(req, obd);
RETURN(0);
}
run_test 409b "getattr released file with CDT stopped after remount"
+test_410()
+{
+ [ "$MDS1_VERSION" -lt $(version_code 2.15.3.2) ] &&
+ skip "need MDS version at least 2.15.3.2"
+
+ [ "$CLIENT_VERSION" -lt $(version_code 2.15.3.2) ] &&
+ skip "need client version at least 2.15.3.2"
+
+ mkdir_on_mdt0 $DIR/$tdir
+
+ local f=$DIR/$tdir/$tfile
+ local fid=$(create_small_file $f)
+
+ copytool setup
+
+ $LFS hsm_set --exists --archived $f ||
+ error "could not change hsm flags"
+ $LFS hsm_release $f 2>&1 > /dev/null && error "HSM release should fail"
+
+ $LFS data_version -ws $f 2>&1 > /dev/null
+ $LFS hsm_release $f || error "could not release file"
+}
+run_test 410 "lfs data_version -s allows release of force-archived file"
+
test_500()
{
[ "$MDS1_VERSION" -lt $(version_code 2.6.92) ] &&
"usage: path2fid [--parents] <path> ..."},
{"rmfid", lfs_rmfid, 0, "Remove file(s) by FID(s)\n"
"usage: rmfid <fsname|rootpath> <fid> ..."},
- {"data_version", lfs_data_version, 0, "Display file data version for "
- "a given path.\n" "usage: data_version [-n|-r|-w] <path>"},
+ {"data_version", lfs_data_version, 0, "Display file data version or "
+ "set the data version in the HSM xattr for a given path.\n"
+ "usage: data_version [-n|-r|-w|-s] <path>"},
{"hsm_state", lfs_hsm_state, 0, "Display the HSM information (states, "
"undergoing actions) for given files.\n usage: hsm_state <file> ..."},
{"hsm_set", lfs_hsm_set, 0, "Set HSM user flag on specified files.\n"
int data_version_flags = LL_DV_RD_FLUSH; /* Read by default */
__u64 data_version;
char *path;
+ bool hsm_sync = false;
int fd;
int rc;
int c;
return CMD_HELP;
}
- while ((c = getopt(argc, argv, "hnrw")) != -1) {
+ while ((c = getopt(argc, argv, "hnrws")) != -1) {
switch (c) {
case 'n':
data_version_flags = 0;
case 'w':
data_version_flags |= LL_DV_WR_FLUSH;
break;
+ case 's':
+ hsm_sync = true;
+ break;
default:
fprintf(stderr,
"%s data_version: unrecognized option '%s'\n",
}
rc = llapi_get_data_version(fd, &data_version, data_version_flags);
- if (rc < 0)
+ if (rc < 0) {
fprintf(stderr,
"%s data_version: cannot get version for '%s': %s\n",
progname, path, strerror(-rc));
- else
+ } else {
printf("%ju" "\n", (uintmax_t)data_version);
+ if (hsm_sync) {
+ rc = llapi_hsm_data_version_set(fd, data_version);
+ if (rc < 0)
+ fprintf(stderr,
+ "%s data_version: cannot set version %llu for"
+ " '%s': %s\n", progname,
+ (unsigned long long)data_version, path,
+ strerror(-rc));
+ }
+ }
+
close(fd);
return rc;
}
return rc;
}
+/**
+ * Set the data version in the HSM xattr on the MDT inode of a file to a
+ * specific value.
+ *
+ * \retval 0 on success.
+ * \retval -errno on error.
+ */
+int llapi_hsm_data_version_set(int fd, __u64 data_version)
+{
+ int rc;
+
+ rc = ioctl(fd, LL_IOC_HSM_DATA_VERSION, &data_version);
+ if (rc)
+ rc = -errno;
+
+ return rc;
+}
+
/*
* Create a file without any name and open it for read/write
*
CHECK_VALUE(MDS_SWAP_LAYOUTS);
CHECK_VALUE(MDS_RMFID);
CHECK_VALUE(MDS_BATCH);
+ CHECK_VALUE(MDS_HSM_DATA_VERSION);
CHECK_VALUE(MDS_LAST_OPC);
CHECK_VALUE(REINT_SETATTR);
(long long)MDS_RMFID);
LASSERTF(MDS_BATCH == 63, "found %lld\n",
(long long)MDS_BATCH);
- LASSERTF(MDS_LAST_OPC == 64, "found %lld\n",
+ LASSERTF(MDS_HSM_DATA_VERSION == 64, "found %lld\n",
+ (long long)MDS_BATCH);
+ LASSERTF(MDS_LAST_OPC == 65, "found %lld\n",
(long long)MDS_LAST_OPC);
LASSERTF(REINT_SETATTR == 1, "found %lld\n",
(long long)REINT_SETATTR);