Whamcloud - gitweb
LU-3341 mdt: HSM coordinator client interface 32/6532/16
authorjcl <jacques-charles.lafoucriere@cea.fr>
Mon, 3 Jun 2013 14:13:09 +0000 (16:13 +0200)
committerOleg Drokin <oleg.drokin@intel.com>
Thu, 25 Jul 2013 03:13:02 +0000 (03:13 +0000)
This patch implements the HSM coordinator methods
used by client to add/remove/list HSM actions on
FID.

Signed-off-by: JC Lafoucriere <jacques-charles.lafoucriere@cea.fr>
Change-Id: I0f2d7bfc3d98d98cb13040fad0f7f585c6f3dadf
Reviewed-on: http://review.whamcloud.com/6532
Tested-by: Hudson
Reviewed-by: John L. Hammond <john.hammond@intel.com>
Reviewed-by: Jinshan Xiong <jinshan.xiong@intel.com>
Tested-by: Maloo <whamcloud.maloo@gmail.com>
Reviewed-by: Andreas Dilger <andreas.dilger@intel.com>
lustre/include/lustre/lustre_user.h
lustre/mdc/mdc_request.c
lustre/mdt/Makefile.in
lustre/mdt/mdt_handler.c
lustre/mdt/mdt_hsm.c
lustre/mdt/mdt_hsm_cdt_client.c [new file with mode: 0644]
lustre/mdt/mdt_internal.h
lustre/tests/sanity-hsm.sh

index 211d4cb..28fb629 100644 (file)
@@ -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 */
index f318474..ebdd54b 100644 (file)
@@ -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)
index 5ce9f8f..59a8fb0 100644 (file)
@@ -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@
index 1d9f96c..6bafc90 100644 (file)
@@ -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);
index b4d10e6..57fa2df 100644 (file)
@@ -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 (file)
index 0000000..af2ddf4
--- /dev/null
@@ -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 <jacques-charles.lafoucriere@cea.fr>
+ * Author: Aurelien Degremont <aurelien.degremont@cea.fr>
+ */
+
+#define DEBUG_SUBSYSTEM S_MDS
+
+#include <obd_support.h>
+#include <lustre_net.h>
+#include <lustre_export.h>
+#include <obd.h>
+#include <obd_lov.h>
+#include <lprocfs_status.h>
+#include <lustre_log.h>
+#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);
+}
+
index 90f002e..044c26b 100644 (file)
@@ -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*/
index e7f4909..0cf3355 100644 (file)
@@ -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"