From adce970c84628879840c66e263fdb1f8506a20f2 Mon Sep 17 00:00:00 2001 From: jcl Date: Mon, 3 Jun 2013 16:13:09 +0200 Subject: [PATCH] LU-3341 mdt: HSM coordinator client interface This patch implements the HSM coordinator methods used by client to add/remove/list HSM actions on FID. Signed-off-by: JC Lafoucriere Change-Id: I0f2d7bfc3d98d98cb13040fad0f7f585c6f3dadf Reviewed-on: http://review.whamcloud.com/6532 Tested-by: Hudson Reviewed-by: John L. Hammond Reviewed-by: Jinshan Xiong Tested-by: Maloo Reviewed-by: Andreas Dilger --- lustre/include/lustre/lustre_user.h | 19 +- lustre/mdc/mdc_request.c | 4 +- lustre/mdt/Makefile.in | 1 + lustre/mdt/mdt_handler.c | 14 + lustre/mdt/mdt_hsm.c | 21 +- lustre/mdt/mdt_hsm_cdt_client.c | 553 ++++++++++++++++++++++++++++++++++++ lustre/mdt/mdt_internal.h | 66 ++++- lustre/tests/sanity-hsm.sh | 116 +++++--- 8 files changed, 707 insertions(+), 87 deletions(-) create mode 100644 lustre/mdt/mdt_hsm_cdt_client.c diff --git a/lustre/include/lustre/lustre_user.h b/lustre/include/lustre/lustre_user.h index 211d4cb..28fb629 100644 --- a/lustre/include/lustre/lustre_user.h +++ b/lustre/include/lustre/lustre_user.h @@ -1127,16 +1127,15 @@ static inline struct hsm_action_item * hai_next(struct hsm_action_item *hai) /* Return size of an hsm_action_list */ static inline int hal_size(struct hsm_action_list *hal) { - int i, sz; - struct hsm_action_item *hai; - - sz = sizeof(*hal) + cfs_size_round(strlen(hal->hal_fsname)); - hai = hai_zero(hal); - for (i = 0 ; i < hal->hal_count ; i++) { - sz += cfs_size_round(hai->hai_len); - hai = hai_next(hai); - } - return(sz); + int i, sz; + struct hsm_action_item *hai; + + sz = sizeof(*hal) + cfs_size_round(strlen(hal->hal_fsname)); + hai = hai_zero(hal); + for (i = 0 ; i < hal->hal_count ; i++, hai = hai_next(hai)) + sz += cfs_size_round(hai->hai_len); + + return sz; } /* Copytool progress reporting */ diff --git a/lustre/mdc/mdc_request.c b/lustre/mdc/mdc_request.c index f318474..ebdd54b 100644 --- a/lustre/mdc/mdc_request.c +++ b/lustre/mdc/mdc_request.c @@ -2015,10 +2015,8 @@ static void lustre_swab_hal(struct hsm_action_list *h) __swab32s(&h->hal_archive_id); __swab64s(&h->hal_flags); hai = hai_zero(h); - for (i = 0; i < h->hal_count; i++) { + for (i = 0; i < h->hal_count; i++, hai = hai_next(hai)) lustre_swab_hai(hai); - hai = hai_next(hai); - } } static void lustre_swab_kuch(struct kuc_hdr *l) diff --git a/lustre/mdt/Makefile.in b/lustre/mdt/Makefile.in index 5ce9f8f..59a8fb0 100644 --- a/lustre/mdt/Makefile.in +++ b/lustre/mdt/Makefile.in @@ -4,5 +4,6 @@ mdt-objs += mdt_open.o mdt_idmap.o mdt_identity.o mdt_capa.o mdt_lproc.o mdt_fs. mdt-objs += mdt_lvb.o mdt_hsm.o mdt_mds.o out_handler.o mdt-objs += mdt_hsm_cdt_actions.o mdt-objs += mdt_hsm_cdt_requests.o +mdt-objs += mdt_hsm_cdt_client.o @INCLUDE_RULES@ diff --git a/lustre/mdt/mdt_handler.c b/lustre/mdt/mdt_handler.c index 1d9f96c..6bafc90 100644 --- a/lustre/mdt/mdt_handler.c +++ b/lustre/mdt/mdt_handler.c @@ -4609,6 +4609,11 @@ static void mdt_fini(const struct lu_env *env, struct mdt_device *m) mdt_stack_pre_fini(env, m, md2lu_dev(m->mdt_child)); + if (m->mdt_opts.mo_coordinator) + mdt_hsm_cdt_stop(m); + + mdt_hsm_cdt_fini(m); + mdt_llog_ctxt_unclone(env, m, LLOG_AGENT_ORIG_CTXT); mdt_llog_ctxt_unclone(env, m, LLOG_CHANGELOG_ORIG_CTXT); obd_exports_barrier(obd); @@ -4727,6 +4732,10 @@ static int mdt_init0(const struct lu_env *env, struct mdt_device *m, m->mdt_opts.mo_cos = MDT_COS_DEFAULT; + /* default is coordinator off, it is started through conf_param + * or /proc */ + m->mdt_opts.mo_coordinator = 0; + lmi = server_get_mount(dev); if (lmi == NULL) { CERROR("Cannot get mount info for %s!\n", dev); @@ -4823,6 +4832,11 @@ static int mdt_init0(const struct lu_env *env, struct mdt_device *m, cfs_timer_init(&m->mdt_ck_timer, mdt_ck_timer_callback, m); + rc = mdt_hsm_cdt_init(m); + if (rc != 0) + CERROR("%s: Cannot init coordinator, rc %d\n", + mdt_obd_name(m), rc); + rc = mdt_ck_thread_start(m); if (rc) GOTO(err_free_ns, rc); diff --git a/lustre/mdt/mdt_hsm.c b/lustre/mdt/mdt_hsm.c index b4d10e6..57fa2df 100644 --- a/lustre/mdt/mdt_hsm.c +++ b/lustre/mdt/mdt_hsm.c @@ -79,20 +79,6 @@ static int mdt_hsm_agent_unregister(struct mdt_thread_info *info, return 0; } -static int mdt_hsm_coordinator_get_actions(struct mdt_thread_info *mti, - struct hsm_action_list *hal) -{ - return 0; -} - -static int mdt_hsm_coordinator_actions(struct mdt_thread_info *info, - struct hsm_action_list *hal, - __u64 *compound_id, - int mti_attr_is_valid) -{ - return -ENODATA; -} - /** * Update on-disk HSM attributes. */ @@ -402,7 +388,7 @@ int mdt_hsm_action(struct mdt_thread_info *info) hai->hai_fid = info->mti_body->fid1; hai->hai_len = sizeof(*hai); - rc = mdt_hsm_coordinator_get_actions(info, hal); + rc = mdt_hsm_get_actions(info, hal); if (rc) GOTO(out_free, rc); @@ -536,7 +522,7 @@ int mdt_hsm_request(struct mdt_thread_info *info) hal->hal_count = hr->hr_itemcount; hai = hai_zero(hal); - for (i = 0; i < hr->hr_itemcount; i++) { + for (i = 0; i < hr->hr_itemcount; i++, hai = hai_next(hai)) { hai->hai_action = action; hai->hai_cookie = 0; hai->hai_gid = 0; @@ -544,10 +530,9 @@ int mdt_hsm_request(struct mdt_thread_info *info) hai->hai_extent = hui[i].hui_extent; memcpy(hai->hai_data, data, hr->hr_data_len); hai->hai_len = sizeof(*hai) + hr->hr_data_len; - hai = hai_next(hai); } - rc = mdt_hsm_coordinator_actions(info, hal, &compound_id, 0); + rc = mdt_hsm_add_actions(info, hal, &compound_id); /* ENODATA error code is needed only for implicit requests */ if (rc == -ENODATA) rc = 0; diff --git a/lustre/mdt/mdt_hsm_cdt_client.c b/lustre/mdt/mdt_hsm_cdt_client.c new file mode 100644 index 0000000..af2ddf4 --- /dev/null +++ b/lustre/mdt/mdt_hsm_cdt_client.c @@ -0,0 +1,553 @@ +/* + * GPL HEADER START + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 only, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License version 2 for more details. A copy is + * included in the COPYING file that accompanied this code. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * GPL HEADER END + */ +/* + * (C) Copyright 2012 Commissariat a l'energie atomique et aux energies + * alternatives + * + */ +/* + * lustre/mdt/mdt_hsm_cdt_client.c + * + * Lustre HSM Coordinator + * + * Author: Jacques-Charles Lafoucriere + * Author: Aurelien Degremont + */ + +#define DEBUG_SUBSYSTEM S_MDS + +#include +#include +#include +#include +#include +#include +#include +#include "mdt_internal.h" + +/** + * data passed to llog_cat_process() callback + * to find compatible requests + */ +struct hsm_compat_data_cb { + struct coordinator *cdt; + struct hsm_action_list *hal; +}; + +/** + * llog_cat_process() callback, used to find record + * compatibles with a new hsm_action_list + * \param env [IN] environment + * \param llh [IN] llog handle + * \param hdr [IN] llog record + * \param data [IN] cb data = hsm_compat_data_cb + * \retval 0 success + * \retval -ve failure + */ +static int hsm_find_compatible_cb(const struct lu_env *env, + struct llog_handle *llh, + struct llog_rec_hdr *hdr, void *data) +{ + struct llog_agent_req_rec *larr; + struct hsm_compat_data_cb *hcdcb; + struct hsm_action_item *hai; + int i; + ENTRY; + + larr = (struct llog_agent_req_rec *)hdr; + hcdcb = data; + /* a compatible request must be WAITING or STARTED + * and not a cancel */ + if (((larr->arr_status != ARS_WAITING) && + (larr->arr_status != ARS_STARTED)) || + (larr->arr_hai.hai_action == HSMA_CANCEL)) + RETURN(0); + + hai = hai_zero(hcdcb->hal); + for (i = 0; i < hcdcb->hal->hal_count; i++, hai = hai_next(hai)) { + /* if request is a CANCEL: + * if cookie set in the request, there is no need to find a + * compatible one, the cookie in the request is directly used. + * if cookie is not set, we use the FID to find the request + * to cancel (the "compatible" one) + * if the caller sets the cookie, we assume he also sets the + * arr_archive_id + */ + if ((hai->hai_action == HSMA_CANCEL) && (hai->hai_cookie != 0)) + continue; + + if (!lu_fid_eq(&hai->hai_fid, &larr->arr_hai.hai_fid)) + continue; + + /* HSMA_NONE is used to find running request for some FID */ + if (hai->hai_action == HSMA_NONE) { + hcdcb->hal->hal_archive_id = larr->arr_archive_id; + hcdcb->hal->hal_flags = larr->arr_flags; + *hai = larr->arr_hai; + continue; + } + /* in V1 we do not manage partial transfer + * so extent is always whole file + */ + hai->hai_cookie = larr->arr_hai.hai_cookie; + /* we read the archive number from the request we cancel */ + if ((hai->hai_action == HSMA_CANCEL) && + (hcdcb->hal->hal_archive_id == 0)) + hcdcb->hal->hal_archive_id = larr->arr_archive_id; + } + RETURN(0); +} + +/** + * find compatible requests already recorded + * \param env [IN] environment + * \param mdt [IN] MDT device + * \param hal [IN/OUT] new request + * cookie set to compatible found or to 0 if not found + * for cancel request, see callback hsm_find_compatible_cb() + * \retval 0 success + * \retval -ve failure + */ +static int hsm_find_compatible(const struct lu_env *env, struct mdt_device *mdt, + struct hsm_action_list *hal) +{ + struct hsm_action_item *hai; + struct hsm_compat_data_cb hcdcb; + int rc, i, ok_cnt; + ENTRY; + + ok_cnt = 0; + hai = hai_zero(hal); + for (i = 0; i < hal->hal_count; i++, hai = hai_next(hai)) { + /* in a cancel request hai_cookie may be set by caller to + * show the request to be canceled + * if not we need to search by FID + */ + if ((hai->hai_action == HSMA_CANCEL) && (hai->hai_cookie != 0)) + ok_cnt++; + else + hai->hai_cookie = 0; + } + + /* if all requests are cancel with cookie, no need to find compatible */ + if (ok_cnt == hal->hal_count) + RETURN(0); + + hcdcb.cdt = &mdt->mdt_coordinator; + hcdcb.hal = hal; + + rc = cdt_llog_process(env, mdt, hsm_find_compatible_cb, &hcdcb); + + RETURN(rc); +} + +/** + * check if an action is really needed + * \param hai [IN] request description + * \param hal_an [IN] request archive number (not used) + * \param rq_flags [IN] request flags + * \param hsm [IN] file HSM metadata + * \retval boolean + */ +static bool hsm_action_is_needed(struct hsm_action_item *hai, int hal_an, + __u64 rq_flags, struct md_hsm *hsm) +{ + bool is_needed = false; + int hsm_flags; + ENTRY; + + if (rq_flags & HSM_FORCE_ACTION) + RETURN(true); + + hsm_flags = hsm->mh_flags; + switch (hai->hai_action) { + case HSMA_ARCHIVE: + if ((hsm_flags & HS_DIRTY) || !(hsm_flags & HS_ARCHIVED)) + is_needed = true; + break; + case HSMA_RESTORE: + /* if file is dirty we must return an error, this function + * cannot, so we ask for an action and + * mdt_hsm_is_action_compat() will return an error + */ + if (hsm_flags & (HS_RELEASED | HS_DIRTY)) + is_needed = true; + break; + case HSMA_REMOVE: + if (hsm_flags & (HS_ARCHIVED | HS_EXISTS)) + is_needed = true; + break; + case HSMA_CANCEL: + is_needed = true; + break; + } + CDEBUG(D_HSM, "fid="DFID" action=%s rq_flags="LPX64 + " extent="LPX64"-"LPX64" hsm_flags=%X %s\n", + PFID(&hai->hai_fid), + hsm_copytool_action2name(hai->hai_action), rq_flags, + hai->hai_extent.offset, hai->hai_extent.length, + hsm->mh_flags, + (is_needed ? "action needed" : "no action needed")); + + RETURN(is_needed); +} + +/** + * test sanity of an hal + * FID must be valid + * action must be known + * \param hal [IN] + * \retval boolean + */ +static bool hal_is_sane(struct hsm_action_list *hal) +{ + int i; + struct hsm_action_item *hai; + ENTRY; + + if (hal->hal_count == 0) + RETURN(false); + + hai = hai_zero(hal); + for (i = 0; i < hal->hal_count; i++, hai = hai_next(hai)) { + if (!fid_is_sane(&hai->hai_fid)) + RETURN(false); + switch (hai->hai_action) { + case HSMA_NONE: + case HSMA_ARCHIVE: + case HSMA_RESTORE: + case HSMA_REMOVE: + case HSMA_CANCEL: + break; + default: + RETURN(false); + } + } + RETURN(true); +} + +/* + * Coordinator external API + */ + +/** + * register a list of requests + * \param mti [IN] + * \param hal [IN] list of requests + * \param compound_id [OUT] id of the compound request + * \retval 0 success + * \retval -ve failure + * in case of restore, caller must hold layout lock + */ +int mdt_hsm_add_actions(struct mdt_thread_info *mti, + struct hsm_action_list *hal, __u64 *compound_id) +{ + struct mdt_device *mdt = mti->mti_mdt; + struct coordinator *cdt = &mdt->mdt_coordinator; + struct hsm_action_item *hai; + struct mdt_object *obj = NULL; + int rc = 0, i; + struct md_hsm mh; + bool is_restore = false; + ENTRY; + + /* no coordinator started, so we cannot serve requests */ + if (cdt->cdt_state == CDT_STOPPED) + RETURN(-EAGAIN); + + if (!hal_is_sane(hal)) + RETURN(-EINVAL); + + *compound_id = cfs_atomic_inc_return(&cdt->cdt_compound_id); + + /* search for compatible request, if found hai_cookie is set + * to the request cookie + * it is also used to set the cookie for cancel request by FID + */ + rc = hsm_find_compatible(mti->mti_env, mdt, hal); + if (rc) + GOTO(out, rc); + + hai = hai_zero(hal); + for (i = 0; i < hal->hal_count; i++, hai = hai_next(hai)) { + int archive_id; + __u64 flags; + + /* default archive number is the one explicitly specified */ + archive_id = hal->hal_archive_id; + flags = hal->hal_flags; + + /* by default, data FID is same as Lustre FID */ + /* the volatile data FID will be created by copy tool and + * send from the agent through the progress call */ + hai->hai_dfid = hai->hai_fid; + + /* done here to manage first and redundant requests cases */ + if (hai->hai_action == HSMA_RESTORE) + is_restore = true; + + /* test result of hsm_find_compatible() + * if request redundant or cancel of nothing + * do not record + */ + /* redundant case */ + if ((hai->hai_action != HSMA_CANCEL) && (hai->hai_cookie != 0)) + continue; + /* cancel nothing case */ + if ((hai->hai_action == HSMA_CANCEL) && (hai->hai_cookie == 0)) + continue; + + /* new request or cancel request + * we search for HSM status flags to check for compatibility + * if restore, we take the layout lock + */ + + /* if action is cancel, also no need to check */ + if (hai->hai_action == HSMA_CANCEL) + goto record; + + /* get HSM attributes */ + obj = mdt_hsm_get_md_hsm(mti, &hai->hai_fid, &mh, NULL); + if (IS_ERR(obj)) { + /* in case of archive remove, Lustre file + * is not mandatory */ + if (hai->hai_action == HSMA_REMOVE) + goto record; + GOTO(out, rc = PTR_ERR(obj)); + } + + /* Check if an action is needed, compare request + * and HSM flags status */ + if (!hsm_action_is_needed(hai, archive_id, flags, &mh)) + continue; + + /* Check if file request is compatible with HSM flags status + * and stop at first incompatible + */ + if (!mdt_hsm_is_action_compat(hai, archive_id, flags, &mh)) + GOTO(out, rc = -EPERM); + + /* for cancel archive number is taken from canceled request + * for other request, we take from lma if not specified, + * this works also for archive because the default value is 0 + * /!\ there is a side effect: in case of restore on multiple + * files which are in different backend, the initial compound + * request will be split in multiple requests because we cannot + * warranty an agent can serve any combinaison of archive + * backend + */ + if ((hai->hai_action != HSMA_CANCEL) && + (archive_id == 0)) + archive_id = mh.mh_arch_id; + + /* if restore, take an exclusive lock on layout */ + if (hai->hai_action == HSMA_RESTORE) { + struct cdt_restore_handle *crh; + struct mdt_object *child; + + OBD_ALLOC_PTR(crh); + if (crh == NULL) + GOTO(out, rc = -ENOMEM); + + crh->crh_fid = hai->hai_fid; + /* in V1 only whole file is supported + crh->extent.start = hai->hai_extent.offset; + crh->extent.end = hai->hai_extent.offset + + hai->hai_extent.length; + */ + crh->crh_extent.start = 0; + crh->crh_extent.end = OBD_OBJECT_EOF; + + mdt_lock_reg_init(&crh->crh_lh, LCK_EX); + child = mdt_object_find_lock(mti, &crh->crh_fid, + &crh->crh_lh, + MDS_INODELOCK_LAYOUT); + if (IS_ERR(child)) { + rc = PTR_ERR(child); + CERROR("%s: cannot take layout lock for " + DFID": rc = %d\n", mdt_obd_name(mdt), + PFID(&crh->crh_fid), rc); + OBD_FREE_PTR(crh); + GOTO(out, rc); + } + /* we choose to not keep a keep a reference + * on the object during the restore time which can be + * very long */ + mdt_object_put(mti->mti_env, child); + + down(&cdt->cdt_restore_lock); + cfs_list_add_tail(&crh->crh_list, + &cdt->cdt_restore_hdl); + up(&cdt->cdt_restore_lock); + } +record: + /* record request */ + rc = mdt_agent_record_add(mti->mti_env, mdt, *compound_id, + archive_id, flags, hai); + if (rc) + GOTO(out, rc); + } + if (is_restore && + (cdt->cdt_policy & CDT_NONBLOCKING_RESTORE)) + rc = -ENODATA; + else + rc = 0; + EXIT; +out: + /* if work has been added, wake up coordinator */ + if ((rc == 0) || (rc == -ENODATA)) + mdt_hsm_cdt_wakeup(mdt); + + return rc; +} + +/** + * get running action on a FID list or from cookie + * \param mti [IN] + * \param hal [IN/OUT] requests + * \retval 0 success + * \retval -ve failure + */ +int mdt_hsm_get_running(struct mdt_thread_info *mti, + struct hsm_action_list *hal) +{ + struct mdt_device *mdt = mti->mti_mdt; + struct coordinator *cdt = &mdt->mdt_coordinator; + struct hsm_action_item *hai; + int i; + ENTRY; + + hai = hai_zero(hal); + for (i = 0; i < hal->hal_count; i++, hai = hai_next(hai)) { + struct cdt_agent_req *car; + + if (!fid_is_sane(&hai->hai_fid)) + RETURN(-EINVAL); + + car = mdt_cdt_find_request(cdt, 0, &hai->hai_fid); + if (IS_ERR(car)) { + hai->hai_cookie = 0; + hai->hai_action = HSMA_NONE; + } else { + *hai = *car->car_hai; + mdt_cdt_put_request(car); + } + } + RETURN(0); +} + +/** + * check if a restore is running on a FID + * this is redundant with mdt_hsm_coordinator_get_running() + * but as it can be called frequently when getting attr + * we make an optimized/simpler version only for a FID + * \param mti [IN] + * \param fid [IN] file FID + * \retval boolean + */ +bool mdt_hsm_restore_is_running(struct mdt_thread_info *mti, + const struct lu_fid *fid) +{ + struct mdt_device *mdt = mti->mti_mdt; + struct coordinator *cdt = &mdt->mdt_coordinator; + cfs_list_t *pos, *tmp; + struct cdt_restore_handle *crh; + bool rc = false; + ENTRY; + + if (!fid_is_sane(fid)) + RETURN(rc); + + down(&cdt->cdt_restore_lock); + cfs_list_for_each_safe(pos, tmp, &cdt->cdt_restore_hdl) { + crh = cfs_list_entry(pos, struct cdt_restore_handle, crh_list); + if (lu_fid_eq(&crh->crh_fid, fid)) { + rc = true; + break; + } + } + up(&cdt->cdt_restore_lock); + RETURN(rc); +} + +/** + * get registered action on a FID list + * \param mti [IN] + * \param hal [IN/OUT] requests + * \retval 0 success + * \retval -ve failure + */ +int mdt_hsm_get_actions(struct mdt_thread_info *mti, + struct hsm_action_list *hal) +{ + struct mdt_device *mdt = mti->mti_mdt; + struct coordinator *cdt = &mdt->mdt_coordinator; + struct hsm_action_item *hai; + int i, rc; + ENTRY; + + hai = hai_zero(hal); + for (i = 0; i < hal->hal_count; i++, hai = hai_next(hai)) { + hai->hai_action = HSMA_NONE; + if (!fid_is_sane(&hai->hai_fid)) + RETURN(-EINVAL); + } + + /* 1st we search in recorded requests */ + rc = hsm_find_compatible(mti->mti_env, mdt, hal); + /* if llog file is not created, no action is recorded */ + if (rc == -ENOENT) + RETURN(0); + + if (rc) + RETURN(rc); + + /* 2nd we search if the request are running + * cookie is cleared to tell to caller, the request is + * waiting + * we could in place use the record status, but in the future + * we may want do give back dynamic informations on the + * running request + */ + hai = hai_zero(hal); + for (i = 0; i < hal->hal_count; i++, hai = hai_next(hai)) { + struct cdt_agent_req *car; + + car = mdt_cdt_find_request(cdt, hai->hai_cookie, NULL); + if (IS_ERR(car)) { + hai->hai_cookie = 0; + } else { + __u64 data_moved; + + mdt_cdt_get_work_done(car, &data_moved); + /* this is just to give the volume of data moved + * it means data_moved data have been moved from the + * original request but we do not know which one + */ + hai->hai_extent.length = data_moved; + mdt_cdt_put_request(car); + } + } + + RETURN(0); +} + diff --git a/lustre/mdt/mdt_internal.h b/lustre/mdt/mdt_internal.h index 90f002e..044c26b 100644 --- a/lustre/mdt/mdt_internal.h +++ b/lustre/mdt/mdt_internal.h @@ -930,16 +930,6 @@ int mdt_hsm_progress(struct mdt_thread_info *info); int mdt_hsm_ct_register(struct mdt_thread_info *info); int mdt_hsm_ct_unregister(struct mdt_thread_info *info); int mdt_hsm_request(struct mdt_thread_info *info); -/* HSM restore cannot be active yet, until the coordinator - * patch is landed, so this function always returns false for now, but - * allows the other parts of the code to start checking for this. - */ -static inline bool mdt_hsm_restore_is_running(struct mdt_thread_info *mti, - const struct lu_fid *fid) -{ - return false; -} - /* mdt/mdt_hsm_cdt_actions.c */ extern const struct file_operations mdt_agent_actions_fops; void dump_llog_agent_req_rec(char *prefix, struct llog_agent_req_rec *larr); @@ -955,6 +945,16 @@ int mdt_agent_llog_update_rec(const struct lu_env *env, struct mdt_device *mdt, struct llog_handle *llh, struct llog_agent_req_rec *larr); +/* mdt/mdt_hsm_cdt_client.c */ +int mdt_hsm_add_actions(struct mdt_thread_info *info, + struct hsm_action_list *hal, __u64 *compound_id); +int mdt_hsm_get_actions(struct mdt_thread_info *mti, + struct hsm_action_list *hal); +int mdt_hsm_get_running(struct mdt_thread_info *mti, + struct hsm_action_list *hal); +bool mdt_hsm_restore_is_running(struct mdt_thread_info *mti, + const struct lu_fid *fid); + /* mdt/mdt_hsm_cdt_requests.c */ extern const struct file_operations mdt_hsm_request_fops; void dump_requests(char *prefix, struct coordinator *cdt); @@ -981,6 +981,52 @@ static inline int mdt_hsm_agent_update_statistics(struct coordinator *cdt, { return 0; } +static inline struct mdt_object *mdt_hsm_get_md_hsm(struct mdt_thread_info *mti, + struct lu_fid *fid, + struct md_hsm *hsm, + struct mdt_lock_handle *lh) +{ + return ERR_PTR(-EINVAL); +} +static inline bool mdt_hsm_is_action_compat(struct hsm_action_item *hai, + int hal_an, __u64 rq_flags, + struct md_hsm *hsm) +{ + return false; +} +static inline int mdt_hsm_cdt_init(struct mdt_device *mdt) +{ + struct coordinator *cdt = &mdt->mdt_coordinator; + + /* minimal init before final patch landing */ + sema_init(&cdt->cdt_llog_lock, 1); + init_rwsem(&cdt->cdt_agent_lock); + init_rwsem(&cdt->cdt_request_lock); + + CFS_INIT_LIST_HEAD(&cdt->cdt_requests); + CFS_INIT_LIST_HEAD(&cdt->cdt_agents); + CFS_INIT_LIST_HEAD(&cdt->cdt_restore_hdl); + + cdt->cdt_state = CDT_STOPPED; + return 0; +} +static inline int mdt_hsm_cdt_start(struct mdt_device *mdt) +{ + return 0; +} +static inline int mdt_hsm_cdt_stop(struct mdt_device *mdt) +{ + return 0; +} +static inline int mdt_hsm_cdt_fini(struct mdt_device *mdt) +{ + return 0; +} +static inline int mdt_hsm_cdt_wakeup(struct mdt_device *mdt) +{ + return 0; +} +/* end of fake functions */ extern struct lu_context_key mdt_thread_key; /* debug issues helper starts here*/ diff --git a/lustre/tests/sanity-hsm.sh b/lustre/tests/sanity-hsm.sh index e7f4909..0cf3355 100644 --- a/lustre/tests/sanity-hsm.sh +++ b/lustre/tests/sanity-hsm.sh @@ -58,32 +58,41 @@ test_1() { $RUNAS touch $TESTFILE # User flags - $RUNAS $LFS hsm_state $TESTFILE | grep -q "(0x00000000)" || - error "wrong initial hsm state" + local state=$($RUNAS $LFS hsm_state $TESTFILE | cut -f 2 -d" ") + [[ $state == "(0x00000000)" ]] || + error "wrong initial hsm state $state" + $RUNAS $LFS hsm_set --norelease $TESTFILE || - error "user could not change hsm flags" - $RUNAS $LFS hsm_state $TESTFILE | grep -q "(0x00000010)" || - error "wrong hsm state, should be: --norelease" + error "user could not change hsm flags" + state=$($RUNAS $LFS hsm_state $TESTFILE | cut -f 2 -d" ") + [[ $state == "(0x00000010)" ]] || + error "wrong hsm state $state, should be: --norelease" + $RUNAS $LFS hsm_clear --norelease $TESTFILE || - error "user could not clear hsm flags" - $RUNAS $LFS hsm_state $TESTFILE | grep -q "(0x00000000)" || - error "wrong hsm state, should be empty" + error "user could not clear hsm flags" + state=$($RUNAS $LFS hsm_state $TESTFILE | cut -f 2 -d" ") + [[ $state == "(0x00000000)" ]] || + error "wrong hsm state $state, should be empty" # User could not change those flags... $RUNAS $LFS hsm_set --exists $TESTFILE && - error "user should not set this flag" - $RUNAS $LFS hsm_state $TESTFILE | grep -q "(0x00000000)" || - error "wrong hsm state, should be empty" + error "user should not set this flag" + state=$($RUNAS $LFS hsm_state $TESTFILE | cut -f 2 -d" ") + [[ $state == "(0x00000000)" ]] || + error "wrong hsm state $state, should be empty" # ...but root can $LFS hsm_set --exists $TESTFILE || - error "root could not change hsm flags" - $LFS hsm_state $TESTFILE | grep -q "(0x00000001)" || - error "wrong hsm state, should be: --exists" + error "root could not change hsm flags" + state=$($RUNAS $LFS hsm_state $TESTFILE | cut -f 2 -d" ") + [[ $state == "(0x00000001)" ]] || + error "wrong hsm state $state, should be: --exists" + $LFS hsm_clear --exists $TESTFILE || - error "root could not clear hsm state" - $LFS hsm_state $TESTFILE | grep -q "(0x00000000)" || - error "wrong hsm state, should be empty" + error "root could not clear hsm state" + state=$($RUNAS $LFS hsm_state $TESTFILE | cut -f 2 -d" ") + [[ $state == "(0x00000000)" ]] || + error "wrong hsm state $state, should be empty" } run_test 1 "lfs hsm flags root/non-root access" @@ -93,31 +102,38 @@ test_2() { touch $TESTFILE # New files are not dirty - $LFS hsm_state $TESTFILE | grep -q " (0x00000000)" || - error "wrong hsm state: !0x0" + local state=$($LFS hsm_state $TESTFILE | cut -f 2 -d" ") + [[ $state == "(0x00000000)" ]] || + error "wrong hsm state $state, should be empty" # For test, we simulate an archived file. $LFS hsm_set --exists $TESTFILE || error "user could not change hsm flags" - $LFS hsm_state $TESTFILE | grep -q " (0x00000001)" || - error "wrong hsm state: !0x1" + state=$($LFS hsm_state $TESTFILE | cut -f 2 -d" ") + [[ $state == "(0x00000001)" ]] || + error "wrong hsm state $state, should be: --exists" # chmod do not put the file dirty chmod 600 $TESTFILE || error "could not chmod test file" - $LFS hsm_state $TESTFILE | grep -q " (0x00000001)" || - error "wrong hsm state: !0x1" + state=$($LFS hsm_state $TESTFILE | cut -f 2 -d" ") + [[ $state == "(0x00000001)" ]] || + error "wrong hsm state $state, should be: --exists" # chown do not put the file dirty chown $RUNAS_ID $TESTFILE || error "could not chown test file" - $LFS hsm_state $TESTFILE | grep -q " (0x00000001)" || - error "wrong hsm state: !0x1" + state=$($LFS hsm_state $TESTFILE | cut -f 2 -d" ") + [[ $state == "(0x00000001)" ]] || + error "wrong hsm state $state, should be: --exists" # truncate put the file dirty - ./truncate $TESTFILE 1 || error "could not truncate test file" - $LFS hsm_state $TESTFILE | grep -q " (0x00000003)" || - error "wrong hsm state: !0x3" + $TRUNCATE $TESTFILE 1 || error "could not truncate test file" + state=$($LFS hsm_state $TESTFILE | cut -f 2 -d" ") + [[ $state == "(0x00000003)" ]] || + error "wrong hsm state $state, should be 0x00000003" + $LFS hsm_clear --dirty $TESTFILE || error "could not clear hsm flags" - $LFS hsm_state $TESTFILE | grep -q " (0x00000001)" || - error "wrong hsm state: !0x1" + state=$($LFS hsm_state $TESTFILE | cut -f 2 -d" ") + [[ $state == "(0x00000001)" ]] || + error "wrong hsm state $state, should be: --exists" } run_test 2 "Check file dirtyness when doing setattr" @@ -127,24 +143,28 @@ test_3() { # New files are not dirty cp -p /etc/passwd $TESTFILE - $LFS hsm_state $TESTFILE | grep -q " (0x00000000)" || - error "wrong hsm state: !0x0" + local state=$($LFS hsm_state $TESTFILE | cut -f 2 -d" ") + [[ $state == "(0x00000000)" ]] || + error "wrong hsm state $state, should be empty" # For test, we simulate an archived file. $LFS hsm_set --exists $TESTFILE || error "user could not change hsm flags" - $LFS hsm_state $TESTFILE | grep -q " (0x00000001)" || - error "wrong hsm state: !0x1" + state=$($LFS hsm_state $TESTFILE | cut -f 2 -d" ") + [[ $state == "(0x00000001)" ]] || + error "wrong hsm state $state, should be: --exists" # Reading a file, does not set dirty cat $TESTFILE > /dev/null || error "could not read file" - $LFS hsm_state $TESTFILE | grep -q " (0x00000001)" || - error "wrong hsm state: !0x1" + state=$($LFS hsm_state $TESTFILE | cut -f 2 -d" ") + [[ $state == "(0x00000001)" ]] || + error "wrong hsm state $state, should be: --exists" # Open for write without modifying data, does not set dirty openfile -f O_WRONLY $TESTFILE || error "could not open test file" - $LFS hsm_state $TESTFILE | grep -q " (0x00000001)" || - error "wrong hsm state: !0x1" + state=$($LFS hsm_state $TESTFILE | cut -f 2 -d" ") + [[ $state == "(0x00000001)" ]] || + error "wrong hsm state $state, should be: --exists" # Append to a file sets it dirty cp -p /etc/passwd $TESTFILE.append || error "could not create file" @@ -153,8 +173,9 @@ test_3() { dd if=/etc/passwd of=$TESTFILE.append bs=1 count=3 \ conv=notrunc oflag=append status=noxfer || error "could not append to test file" - $LFS hsm_state $TESTFILE.append | grep -q " (0x00000003)" || - error "wrong hsm state: !0x3" + state=$($LFS hsm_state $TESTFILE.append | cut -f 2 -d" ") + [[ $state == "(0x00000003)" ]] || + error "wrong hsm state $state, should be 0x00000003" # Modify a file sets it dirty cp -p /etc/passwd $TESTFILE.modify || error "could not create file" @@ -163,24 +184,27 @@ test_3() { dd if=/dev/zero of=$TESTFILE.modify bs=1 count=3 \ conv=notrunc status=noxfer || error "could not modify test file" - $LFS hsm_state $TESTFILE.modify | grep -q " (0x00000003)" || - error "wrong hsm state: !0x3" + state=$($LFS hsm_state $TESTFILE.modify | cut -f 2 -d" ") + [[ $state == "(0x00000003)" ]] || + error "wrong hsm state $state, should be 0x00000003" # Open O_TRUNC sets dirty cp -p /etc/passwd $TESTFILE.trunc || error "could not create file" $LFS hsm_set --exists $TESTFILE.trunc || error "user could not change hsm flags" cp /etc/group $TESTFILE.trunc || error "could not override a file" - $LFS hsm_state $TESTFILE.trunc | grep -q " (0x00000003)" || - error "wrong hsm state: !0x3" + state=$($LFS hsm_state $TESTFILE.trunc | cut -f 2 -d" ") + [[ $state == "(0x00000003)" ]] || + error "wrong hsm state $state, should be 0x00000003" # Mmapped a file sets dirty cp -p /etc/passwd $TESTFILE.mmap || error "could not create file" $LFS hsm_set --exists $TESTFILE.mmap || error "user could not change hsm flags" multiop $TESTFILE.mmap OSMWUc || error "could not mmap a file" - $LFS hsm_state $TESTFILE.mmap | grep -q " (0x00000003)" || - error "wrong hsm state: !0x3" + state=$($LFS hsm_state $TESTFILE.mmap | cut -f 2 -d" ") + [[ $state == "(0x00000003)" ]] || + error "wrong hsm state $state, should be 0x00000003" } run_test 3 "Check file dirtyness when opening for write" -- 1.8.3.1