Whamcloud - gitweb
LU-3866 hsm: permission checks on HSM operations
[fs/lustre-release.git] / lustre / mdt / mdt_coordinator.c
index a48bc36..9d5d4cd 100644 (file)
@@ -53,7 +53,7 @@ static struct lprocfs_vars lprocfs_mdt_hsm_vars[];
  * \param mti [IN] context
  * \param fid [IN] object fid
  * \param hsm [OUT] HSM meta data
- * \retval obj
+ * \retval obj or error (-ENOENT if not found)
  */
 struct mdt_object *mdt_hsm_get_md_hsm(struct mdt_thread_info *mti,
                                      const struct lu_fid *fid,
@@ -105,7 +105,7 @@ void mdt_hsm_dump_hal(int level, const char *prefix,
               prefix, hal->hal_version, hal->hal_count,
               hal->hal_compound_id, hal->hal_archive_id, hal->hal_flags);
 
-       hai = hai_zero(hal);
+       hai = hai_first(hal);
        for (i = 0; i < hal->hal_count; i++) {
                sz = hai->hai_len - sizeof(*hai);
                CDEBUG(level, "%s %d: fid="DFID" dfid="DFID
@@ -201,7 +201,7 @@ static int mdt_coordinator_cb(const struct lu_env *env,
                                continue;
                        }
                }
-               if ((found == -1) && (empty_slot == -1))
+               if (found == -1 && empty_slot == -1)
                        /* unknown request and no more room for new request,
                         * continue scan for to find other entries for
                         * already found request
@@ -239,7 +239,7 @@ static int mdt_coordinator_cb(const struct lu_env *env,
                        hsd->request[empty_slot].hal = hal;
                        hsd->request_cnt++;
                        found = empty_slot;
-                       hai = hai_zero(hal);
+                       hai = hai_first(hal);
                } else {
                        /* request is known */
                        /* we check if record archive num is the same as the
@@ -276,7 +276,7 @@ static int mdt_coordinator_cb(const struct lu_env *env,
                                hsd->request[found].hal = hal_buffer;
                                hsd->request[found].hal_sz = sz;
                        }
-                       hai = hai_zero(hsd->request[found].hal);
+                       hai = hai_first(hsd->request[found].hal);
                        for (i = 0; i < hsd->request[found].hal->hal_count;
                             i++)
                                hai = hai_next(hai);
@@ -385,7 +385,7 @@ static int mdt_coordinator_cb(const struct lu_env *env,
  * \retval 0 success
  * \retval -ve failure
  */
-static int hsm_cdt_procfs_init(struct mdt_device *mdt)
+int hsm_cdt_procfs_init(struct mdt_device *mdt)
 {
        struct coordinator      *cdt = &mdt->mdt_coordinator;
        int                      rc = 0;
@@ -407,6 +407,29 @@ static int hsm_cdt_procfs_init(struct mdt_device *mdt)
 }
 
 /**
+ * remove /proc entries for coordinator
+ * \param mdt [IN]
+ */
+void  hsm_cdt_procfs_fini(struct mdt_device *mdt)
+{
+       struct coordinator      *cdt = &mdt->mdt_coordinator;
+
+       LASSERT(cdt->cdt_state == CDT_STOPPED);
+       if (cdt->cdt_proc_dir != NULL)
+               lprocfs_remove(&cdt->cdt_proc_dir);
+}
+
+/**
+ * get vector of hsm cdt /proc vars
+ * \param none
+ * \retval var vector
+ */
+struct lprocfs_vars *hsm_cdt_get_proc_vars(void)
+{
+       return lprocfs_mdt_hsm_vars;
+}
+
+/**
  * coordinator thread
  * \param data [IN] obd device
  * \retval 0 success
@@ -422,15 +445,11 @@ static int mdt_coordinator(void *data)
        ENTRY;
 
        cdt->cdt_thread.t_flags = SVC_RUNNING;
-       cfs_waitq_signal(&cdt->cdt_thread.t_ctl_waitq);
+       wake_up(&cdt->cdt_thread.t_ctl_waitq);
 
        CDEBUG(D_HSM, "%s: coordinator thread starting, pid=%d\n",
-              mdt_obd_name(mdt), cfs_curproc_pid());
+              mdt_obd_name(mdt), current_pid());
 
-       /*
-        * create /proc entries for coordinator
-        */
-       hsm_cdt_procfs_init(mdt);
        /* timeouted cookie vector initialization */
        hsd.max_cookie = 0;
        hsd.cookie_cnt = 0;
@@ -461,8 +480,8 @@ static int mdt_coordinator(void *data)
 
                CDEBUG(D_HSM, "coordinator resumes\n");
 
-               if ((cdt->cdt_thread.t_flags & SVC_STOPPING) ||
-                   (cdt->cdt_state == CDT_STOPPING)) {
+               if (cdt->cdt_thread.t_flags & SVC_STOPPING ||
+                   cdt->cdt_state == CDT_STOPPING) {
                        cdt->cdt_thread.t_flags &= ~SVC_STOPPING;
                        rc = 0;
                        break;
@@ -589,7 +608,7 @@ static int mdt_coordinator(void *data)
                                kuc_free(hal, hsd.request[i].hal_used_sz);
                                continue;
                        }
-                       hai = hai_zero(hal);
+                       hai = hai_first(hal);
                        for (j = 0; j < hsd.request[i].hal->hal_count; j++) {
                                cookies[j] = hai->hai_cookie;
                                hai = hai_next(hai);
@@ -652,16 +671,16 @@ out:
                 * and cdt cleaning will be done by event sender
                 */
                cdt->cdt_thread.t_flags = SVC_STOPPED;
-               cfs_waitq_signal(&cdt->cdt_thread.t_ctl_waitq);
+               wake_up(&cdt->cdt_thread.t_ctl_waitq);
        }
 
        if (rc != 0)
                CERROR("%s: coordinator thread exiting, process=%d, rc=%d\n",
-                      mdt_obd_name(mdt), cfs_curproc_pid(), rc);
+                      mdt_obd_name(mdt), current_pid(), rc);
        else
                CDEBUG(D_HSM, "%s: coordinator thread exiting, process=%d,"
                              " no error\n",
-                      mdt_obd_name(mdt), cfs_curproc_pid());
+                      mdt_obd_name(mdt), current_pid());
 
        return rc;
 }
@@ -725,8 +744,12 @@ static int hsm_restore_cb(const struct lu_env *env,
 
        larr = (struct llog_agent_req_rec *)hdr;
        hai = &larr->arr_hai;
-       if ((hai->hai_action != HSMA_RESTORE) ||
-            agent_req_in_final_state(larr->arr_status))
+       if (hai->hai_cookie > cdt->cdt_last_cookie)
+               /* update the cookie to avoid collision */
+               cdt->cdt_last_cookie = hai->hai_cookie + 1;
+
+       if (hai->hai_action != HSMA_RESTORE ||
+           agent_req_in_final_state(larr->arr_status))
                RETURN(0);
 
        /* restore request not in a final state */
@@ -741,7 +764,7 @@ static int hsm_restore_cb(const struct lu_env *env,
        crh->extent.end = hai->hai_extent.offset + hai->hai_extent.length;
        */
        crh->crh_extent.start = 0;
-       crh->crh_extent.end = OBD_OBJECT_EOF;
+       crh->crh_extent.end = hai->hai_extent.length;
        /* get the layout lock */
        mdt_lock_reg_init(&crh->crh_lh, LCK_EX);
        child = mdt_object_find_lock(mti, &crh->crh_fid, &crh->crh_lh,
@@ -796,7 +819,7 @@ static int hsm_init_ucred(struct lu_ucred *uc)
        uc->uc_fsgid = 0;
        uc->uc_suppgids[0] = -1;
        uc->uc_suppgids[1] = -1;
-       uc->uc_cap = 0;
+       uc->uc_cap = CFS_CAP_FS_MASK;
        uc->uc_umask = 0777;
        uc->uc_ginfo = NULL;
        uc->uc_identity = NULL;
@@ -820,7 +843,7 @@ int mdt_hsm_cdt_wakeup(struct mdt_device *mdt)
 
        /* wake up coordinator */
        cdt->cdt_thread.t_flags = SVC_EVENT;
-       cfs_waitq_signal(&cdt->cdt_thread.t_ctl_waitq);
+       wake_up(&cdt->cdt_thread.t_ctl_waitq);
 
        RETURN(0);
 }
@@ -840,7 +863,7 @@ int mdt_hsm_cdt_init(struct mdt_device *mdt)
 
        cdt->cdt_state = CDT_STOPPED;
 
-       cfs_waitq_init(&cdt->cdt_thread.t_ctl_waitq);
+       init_waitqueue_head(&cdt->cdt_thread.t_ctl_waitq);
        mutex_init(&cdt->cdt_llog_lock);
        init_rwsem(&cdt->cdt_agent_lock);
        init_rwsem(&cdt->cdt_request_lock);
@@ -872,6 +895,15 @@ int mdt_hsm_cdt_init(struct mdt_device *mdt)
 
        hsm_init_ucred(mdt_ucred(cdt_mti));
 
+       /* default values for /proc tunnables
+        * can be override by MGS conf */
+       cdt->cdt_default_archive_id = 1;
+       cdt->cdt_delay = 60;
+       cdt->cdt_loop_period = 10;
+       cdt->cdt_max_request = 3;
+       cdt->cdt_policy = CDT_DEFAULT_POLICY;
+       cdt->cdt_timeout = 3600;
+
        RETURN(0);
 }
 
@@ -904,7 +936,7 @@ int mdt_hsm_cdt_start(struct mdt_device *mdt)
        int                      rc;
        void                    *ptr;
        struct mdt_thread_info  *cdt_mti;
-       cfs_task_t              *task;
+       struct task_struct      *task;
        ENTRY;
 
        /* functions defined but not yet used
@@ -918,18 +950,20 @@ int mdt_hsm_cdt_start(struct mdt_device *mdt)
                RETURN(-EALREADY);
        }
 
+       CLASSERT(1 << (CDT_POLICY_SHIFT_COUNT - 1) == CDT_POLICY_LAST);
        cdt->cdt_policy = CDT_DEFAULT_POLICY;
+
        cdt->cdt_state = CDT_INIT;
 
-       cfs_atomic_set(&cdt->cdt_compound_id, cfs_time_current_sec());
+       atomic_set(&cdt->cdt_compound_id, cfs_time_current_sec());
        /* just need to be larger than previous one */
        /* cdt_last_cookie is protected by cdt_llog_lock */
        cdt->cdt_last_cookie = cfs_time_current_sec();
-       cdt->cdt_loop_period = 10;
-       cdt->cdt_delay = 60;
-       cdt->cdt_timeout = 3600;
-       cdt->cdt_max_request = 3;
+
        atomic_set(&cdt->cdt_request_count, 0);
+       cdt->cdt_user_request_mask = (1UL << HSMA_RESTORE);
+       cdt->cdt_group_request_mask = (1UL << HSMA_RESTORE);
+       cdt->cdt_other_request_mask = (1UL << HSMA_RESTORE);
 
        /* to avoid deadlock when start is made through /proc
         * /proc entries are created by the coordinator thread */
@@ -955,7 +989,7 @@ int mdt_hsm_cdt_start(struct mdt_device *mdt)
                rc = 0;
        }
 
-       cfs_wait_event(cdt->cdt_thread.t_ctl_waitq,
+       wait_event(cdt->cdt_thread.t_ctl_waitq,
                       (cdt->cdt_thread.t_flags & SVC_RUNNING));
 
        cdt->cdt_state = CDT_RUNNING;
@@ -982,16 +1016,12 @@ int mdt_hsm_cdt_stop(struct mdt_device *mdt)
                RETURN(-EALREADY);
        }
 
-       /* remove proc entries */
-       if (cdt->cdt_proc_dir != NULL)
-               lprocfs_remove(&cdt->cdt_proc_dir);
-
        if (cdt->cdt_state != CDT_STOPPING) {
                /* stop coordinator thread before cleaning */
                cdt->cdt_thread.t_flags = SVC_STOPPING;
-               cfs_waitq_signal(&cdt->cdt_thread.t_ctl_waitq);
-               cfs_wait_event(cdt->cdt_thread.t_ctl_waitq,
-                              cdt->cdt_thread.t_flags & SVC_STOPPED);
+               wake_up(&cdt->cdt_thread.t_ctl_waitq);
+               wait_event(cdt->cdt_thread.t_ctl_waitq,
+                          cdt->cdt_thread.t_flags & SVC_STOPPED);
        }
        cdt->cdt_state = CDT_STOPPED;
 
@@ -1051,7 +1081,7 @@ int mdt_hsm_add_hal(struct mdt_thread_info *mti,
        ENTRY;
 
        /* register request in memory list */
-       hai = hai_zero(hal);
+       hai = hai_first(hal);
        for (i = 0; i < hal->hal_count; i++, hai = hai_next(hai)) {
                struct cdt_agent_req *car;
 
@@ -1229,9 +1259,8 @@ static int hsm_cdt_request_completed(struct mdt_thread_info *mti,
                        *status = ARS_SUCCEED;
                        break;
                default:
-                       *status = (((cdt->cdt_policy &
-                                  CDT_NORETRY_ACTION) ||
-                                  !(pgs->hpk_flags & HP_FLAG_RETRY)) ?
+                       *status = (cdt->cdt_policy & CDT_NORETRY_ACTION ||
+                                  !(pgs->hpk_flags & HP_FLAG_RETRY) ?
                                   ARS_FAILED : ARS_WAITING);
                        break;
                }
@@ -1329,8 +1358,8 @@ static int hsm_cdt_request_completed(struct mdt_thread_info *mti,
         * a crasy CT no need to manage DIRTY
         */
        if (rc == 0)
-               hsm_set_cl_flags(&cl_flags, ((mh.mh_flags & HS_DIRTY) ?
-                                            CLF_HSM_DIRTY : 0));
+               hsm_set_cl_flags(&cl_flags,
+                                mh.mh_flags & HS_DIRTY ? CLF_HSM_DIRTY : 0);
 
        /* unlock is done later, after layout lock management */
        if (is_mh_changed)
@@ -1340,9 +1369,9 @@ unlock:
        /* we give back layout lock only if restore was successful or
         * if restore was canceled or if policy is to not retry
         * in other cases we just unlock the object */
-       if ((car->car_hai->hai_action == HSMA_RESTORE) &&
-           ((pgs->hpk_errval == 0) || (pgs->hpk_errval == ECANCELED) ||
-            (cdt->cdt_policy & CDT_NORETRY_ACTION))) {
+       if (car->car_hai->hai_action == HSMA_RESTORE &&
+           (pgs->hpk_errval == 0 || pgs->hpk_errval == ECANCELED ||
+            cdt->cdt_policy & CDT_NORETRY_ACTION)) {
                struct cdt_restore_handle       *crh;
 
                /* restore in data FID done, we swap the layouts
@@ -1369,8 +1398,9 @@ unlock:
                /* just give back layout lock, we keep
                 * the reference which is given back
                 * later with the lock for HSM flags */
-               if (!IS_ERR(obj))
+               if (!IS_ERR(obj) && crh != NULL)
                        mdt_object_unlock(mti, obj, &crh->crh_lh, 1);
+
                if (crh != NULL)
                        OBD_SLAB_FREE_PTR(crh, mdt_hsm_cdt_kmem);
        }
@@ -1378,7 +1408,7 @@ unlock:
        GOTO(out, rc);
 
 out:
-       if ((obj != NULL) && !IS_ERR(obj)) {
+       if (obj != NULL && !IS_ERR(obj)) {
                mo_changelog(env, CL_HSM, cl_flags,
                             mdt_object_child(obj));
                mdt_object_put(mti->mti_env, obj);
@@ -1416,6 +1446,8 @@ int mdt_hsm_update_request_state(struct mdt_thread_info *mti,
                       " on fid="DFID"\n",
                       mdt_obd_name(mdt),
                       pgs->hpk_cookie, PFID(&pgs->hpk_fid));
+               if (car == NULL)
+                       RETURN(-ENOENT);
                RETURN(PTR_ERR(car));
        }
 
@@ -1430,12 +1462,12 @@ int mdt_hsm_update_request_state(struct mdt_thread_info *mti,
        /* progress is done on FID or data FID depending of the action and
         * of the copy progress */
        /* for restore progress is used to send back the data FID to cdt */
-       if ((car->car_hai->hai_action == HSMA_RESTORE) &&
-           (lu_fid_eq(&car->car_hai->hai_fid, &car->car_hai->hai_dfid)))
+       if (car->car_hai->hai_action == HSMA_RESTORE &&
+           lu_fid_eq(&car->car_hai->hai_fid, &car->car_hai->hai_dfid))
                car->car_hai->hai_dfid = pgs->hpk_fid;
 
-       if (((car->car_hai->hai_action == HSMA_RESTORE) ||
-            (car->car_hai->hai_action == HSMA_ARCHIVE)) &&
+       if ((car->car_hai->hai_action == HSMA_RESTORE ||
+            car->car_hai->hai_action == HSMA_ARCHIVE) &&
            (!lu_fid_eq(&pgs->hpk_fid, &car->car_hai->hai_dfid) &&
             !lu_fid_eq(&pgs->hpk_fid, &car->car_hai->hai_fid))) {
                CERROR("%s: Progress on "DFID" for cookie "LPX64
@@ -1542,8 +1574,8 @@ static int mdt_cancel_all_cb(const struct lu_env *env,
 
        larr = (struct llog_agent_req_rec *)hdr;
        hcad = data;
-       if ((larr->arr_status == ARS_WAITING) ||
-           (larr->arr_status == ARS_STARTED)) {
+       if (larr->arr_status == ARS_WAITING ||
+           larr->arr_status == ARS_STARTED) {
                larr->arr_status = ARS_CANCELED;
                larr->arr_req_change = cfs_time_current_sec();
                rc = mdt_agent_llog_update_rec(env, hcad->mdt, llh, larr);
@@ -1593,7 +1625,7 @@ static int hsm_cancel_all_actions(struct mdt_device *mdt)
                hal_len = sizeof(*hal) + cfs_size_round(MTI_NAME_MAXLEN + 1) +
                          cfs_size_round(car->car_hai->hai_len);
 
-               if ((hal_len > hal_sz) && (hal_sz > 0)) {
+               if (hal_len > hal_sz && hal_sz > 0) {
                        /* not enough room, free old buffer */
                        OBD_FREE(hal, hal_sz);
                        hal = NULL;
@@ -1619,7 +1651,7 @@ static int hsm_cancel_all_actions(struct mdt_device *mdt)
                hal->hal_flags = car->car_flags;
                hal->hal_count = 0;
 
-               hai = hai_zero(hal);
+               hai = hai_first(hal);
                memcpy(hai, car->car_hai, car->car_hai->hai_len);
                hai->hai_action = HSMA_CANCEL;
                hal->hal_count = 1;
@@ -1673,12 +1705,12 @@ bool mdt_hsm_is_action_compat(const struct hsm_action_item *hai,
        switch (hai->hai_action) {
        case HSMA_ARCHIVE:
                if (!(hsm_flags & HS_NOARCHIVE) &&
-                   ((hsm_flags & HS_DIRTY) || !(hsm_flags & HS_ARCHIVED)))
+                   (hsm_flags & HS_DIRTY || !(hsm_flags & HS_ARCHIVED)))
                        is_compat = true;
                break;
        case HSMA_RESTORE:
                if (!(hsm_flags & HS_DIRTY) && (hsm_flags & HS_RELEASED) &&
-                   (hsm_flags & HS_ARCHIVED) && !(hsm_flags & HS_LOST))
+                   hsm_flags & HS_ARCHIVED && !(hsm_flags & HS_LOST))
                        is_compat = true;
                break;
        case HSMA_REMOVE:
@@ -1709,8 +1741,8 @@ static const struct {
        char            *name;
        char            *nickname;
 } hsm_policy_names[] = {
-       { CDT_NONBLOCKING_RESTORE,      "non_blocking_restore", "nbr"},
-       { CDT_NORETRY_ACTION,           "no_retry_action",      "nra"},
+       { CDT_NONBLOCKING_RESTORE,      "NonBlockingRestore",   "NBR"},
+       { CDT_NORETRY_ACTION,           "NoRetryAction",        "NRA"},
        { 0 },
 };
 
@@ -1725,7 +1757,8 @@ static __u64 hsm_policy_str2bit(const char *name)
        int      i;
 
        for (i = 0; hsm_policy_names[i].bit != 0; i++)
-               if (strcmp(hsm_policy_names[i].nickname, name) == 0)
+               if (strcmp(hsm_policy_names[i].nickname, name) == 0 ||
+                   strcmp(hsm_policy_names[i].name, name) == 0)
                        return hsm_policy_names[i].bit;
        return 0;
 }
@@ -1733,11 +1766,13 @@ static __u64 hsm_policy_str2bit(const char *name)
 /**
  * convert a policy bit field to a string
  * \param mask [IN] policy bit field
+ * \param hexa [IN] print mask before bit names
  * \param buffer [OUT] string
  * \param count [IN] size of buffer
  * \retval size filled in buffer
  */
-static int hsm_policy_bit2str(const __u64 mask, char *buffer, int count)
+static int hsm_policy_bit2str(const __u64 mask, const bool hexa, char *buffer,
+                             int count)
 {
        int      i, j, sz;
        char    *ptr;
@@ -1745,25 +1780,31 @@ static int hsm_policy_bit2str(const __u64 mask, char *buffer, int count)
        ENTRY;
 
        ptr = buffer;
-       sz = snprintf(buffer, count, "("LPX64") ", mask);
-       ptr += sz;
-       count -= sz;
-       for (i = 0; i < (sizeof(mask) * 8); i++) {
+       if (hexa) {
+               sz = snprintf(buffer, count, "("LPX64") ", mask);
+               ptr += sz;
+               count -= sz;
+       }
+       for (i = 0; i < CDT_POLICY_SHIFT_COUNT; i++) {
                bit = (1ULL << i);
-               if (!(bit  & mask))
-                       continue;
 
                for (j = 0; hsm_policy_names[j].bit != 0; j++) {
-                       if (hsm_policy_names[j].bit == bit) {
-                               sz = snprintf(ptr, count, "%s(%s) ",
-                                             hsm_policy_names[j].name,
-                                             hsm_policy_names[j].nickname);
-                               ptr += sz;
-                               count -= sz;
+                       if (hsm_policy_names[j].bit == bit)
                                break;
-                       }
                }
+               if (bit & mask)
+                       sz = snprintf(ptr, count, "[%s] ",
+                                     hsm_policy_names[j].name);
+               else
+                       sz = snprintf(ptr, count, "%s ",
+                                     hsm_policy_names[j].name);
+
+               ptr += sz;
+               count -= sz;
        }
+       /* remove last ' ' */
+       *ptr = '\0';
+       ptr--;
        RETURN(ptr - buffer);
 }
 
@@ -1776,7 +1817,7 @@ static int lprocfs_rd_hsm_policy(char *page, char **start, off_t off,
        int                      sz;
        ENTRY;
 
-       sz = hsm_policy_bit2str(cdt->cdt_policy, page, count);
+       sz = hsm_policy_bit2str(cdt->cdt_policy, false, page, count);
        page[sz] = '\n';
        sz++;
        page[sz] = '\0';
@@ -1789,24 +1830,16 @@ static int lprocfs_wr_hsm_policy(struct file *file, const char *buffer,
 {
        struct mdt_device       *mdt = data;
        struct coordinator      *cdt = &mdt->mdt_coordinator;
-       int                      sz;
-       char                    *start, *end;
-       __u64                    policy;
-       int                      set;
+       char                    *start, *token, sign;
        char                    *buf;
+       __u64                    policy;
+       __u64                    add_mask, remove_mask, set_mask;
+       int                      sz;
+       int                      rc;
        ENTRY;
 
-       if (strncmp(buffer, "help", 4) == 0) {
-               sz = PAGE_SIZE;
-               OBD_ALLOC(buf, sz);
-               if (!buf)
-                       RETURN(-ENOMEM);
-
-               hsm_policy_bit2str(CDT_POLICY_MASK, buf, sz);
-               CWARN("Supported policies are: %s\n", buf);
-               OBD_FREE(buf, sz);
-               RETURN(count);
-       }
+       if (count + 1 > PAGE_SIZE)
+               RETURN(-EINVAL);
 
        OBD_ALLOC(buf, count + 1);
        if (buf == NULL)
@@ -1814,48 +1847,74 @@ static int lprocfs_wr_hsm_policy(struct file *file, const char *buffer,
 
        if (copy_from_user(buf, buffer, count))
                RETURN(-EFAULT);
-
        buf[count] = '\0';
+
        start = buf;
+       CDEBUG(D_HSM, "%s: receive new policy: '%s'\n", mdt_obd_name(mdt),
+              start);
 
-       policy = 0;
+       add_mask = remove_mask = set_mask = 0;
        do {
-               end = strchr(start, ' ');
-               if (end != NULL)
-                       *end = '\0';
-               switch (*start) {
+               token = strsep(&start, "\n ");
+               sign = *token;
+
+               if (sign == '\0')
+                       continue;
+
+               if (sign == '-' || sign == '+')
+                       token++;
+
+               policy = hsm_policy_str2bit(token);
+               if (policy == 0) {
+                       char *msg;
+
+                       sz = PAGE_SIZE;
+                       OBD_ALLOC(msg, sz);
+                       if (!msg)
+                               RETURN(-ENOMEM);
+
+                       hsm_policy_bit2str(0, false, msg, sz);
+                       CWARN("%s: '%s' is unknown, "
+                             "supported policies are: %s\n", mdt_obd_name(mdt),
+                             token, msg);
+                       OBD_FREE(msg, sz);
+                       GOTO(out, rc = -EINVAL);
+               }
+               switch (sign) {
                case '-':
-                       start++;
-                       set = 0;
+                       remove_mask |= policy;
                        break;
                case '+':
-                       start++;
-                       set = 1;
+                       add_mask |= policy;
                        break;
                default:
-                       set = 2;
+                       set_mask |= policy;
                        break;
                }
-               policy = hsm_policy_str2bit(start);
-               if (!policy)
-                       break;
 
-               switch (set) {
-               case 0:
-                       cdt->cdt_policy &= ~policy;
-                       break;
-               case 1:
-                       cdt->cdt_policy |= policy;
-                       break;
-               case 2:
-                       cdt->cdt_policy = policy;
-                       break;
-               }
+       } while (start != NULL);
 
-               start = end + 1;
-       } while (end != NULL);
+       CDEBUG(D_HSM, "%s: new policy: rm="LPX64" add="LPX64" set="LPX64"\n",
+              mdt_obd_name(mdt), remove_mask, add_mask, set_mask);
+
+       /* if no sign in all string, it is a clear and set
+        * if some sign found, all unsigned are converted
+        * to add
+        * P1 P2 = set to P1 and P2
+        * P1 -P2 = add P1 clear P2 same as +P1 -P2
+        */
+       if (remove_mask == 0 && add_mask == 0) {
+               cdt->cdt_policy = set_mask;
+       } else {
+               cdt->cdt_policy |= set_mask | add_mask;
+               cdt->cdt_policy &= ~remove_mask;
+       }
+
+       GOTO(out, rc = count);
+
+out:
        OBD_FREE(buf, count + 1);
-       RETURN(count);
+       RETURN(rc);
 }
 
 #define GENERATE_PROC_METHOD(VAR)                                      \
@@ -1895,6 +1954,7 @@ GENERATE_PROC_METHOD(cdt_loop_period)
 GENERATE_PROC_METHOD(cdt_delay)
 GENERATE_PROC_METHOD(cdt_timeout)
 GENERATE_PROC_METHOD(cdt_max_request)
+GENERATE_PROC_METHOD(cdt_default_archive_id)
 
 /*
  * procfs write method for MDT/hsm_control
@@ -1976,10 +2036,161 @@ int lprocfs_rd_hsm_cdt_control(char *page, char **start, off_t off,
        RETURN(sz);
 }
 
+static int
+lprocfs_rd_hsm_request_mask(char *page, char **start, off_t off,
+                           int count, int *eof, __u64 mask)
+{
+       int i, rc = 0;
+       ENTRY;
+
+       for (i = 0; i < 8 * sizeof(mask); i++) {
+               if (mask & (1UL << i))
+                       rc += snprintf(page + rc, count - rc, "%s%s",
+                                      rc == 0 ? "" : " ",
+                                      hsm_copytool_action2name(i));
+       }
+
+       rc += snprintf(page + rc, count - rc, "\n");
+
+       RETURN(rc);
+}
+
+static int
+lprocfs_rd_hsm_user_request_mask(char *page, char **start, off_t off,
+                                int count, int *eof, void *data)
+{
+       struct mdt_device *mdt = data;
+       struct coordinator *cdt = &mdt->mdt_coordinator;
+
+       return lprocfs_rd_hsm_request_mask(page, start, off, count, eof,
+                                          cdt->cdt_user_request_mask);
+}
+
+static int
+lprocfs_rd_hsm_group_request_mask(char *page, char **start, off_t off,
+                                 int count, int *eof, void *data)
+{
+       struct mdt_device *mdt = data;
+       struct coordinator *cdt = &mdt->mdt_coordinator;
+
+       return lprocfs_rd_hsm_request_mask(page, start, off, count, eof,
+                                          cdt->cdt_group_request_mask);
+}
+
+static int
+lprocfs_rd_hsm_other_request_mask(char *page, char **start, off_t off,
+                                 int count, int *eof, void *data)
+{
+       struct mdt_device *mdt = data;
+       struct coordinator *cdt = &mdt->mdt_coordinator;
+
+       return lprocfs_rd_hsm_request_mask(page, start, off, count, eof,
+                                          cdt->cdt_other_request_mask);
+}
+
+static inline enum hsm_copytool_action
+hsm_copytool_name2action(const char *name)
+{
+       if (strcasecmp(name, "NOOP") == 0)
+               return HSMA_NONE;
+       else if (strcasecmp(name, "ARCHIVE") == 0)
+               return HSMA_ARCHIVE;
+       else if (strcasecmp(name, "RESTORE") == 0)
+               return HSMA_RESTORE;
+       else if (strcasecmp(name, "REMOVE") == 0)
+               return HSMA_REMOVE;
+       else if (strcasecmp(name, "CANCEL") == 0)
+               return HSMA_CANCEL;
+       else
+               return -1;
+}
+
+static int
+lprocfs_wr_hsm_request_mask(struct file *file, const char __user *user_buf,
+                           unsigned long user_count, __u64 *mask)
+{
+       char *buf, *pos, *name;
+       size_t buf_size;
+       __u64 new_mask = 0;
+       int rc;
+       ENTRY;
+
+       if (!(user_count < 4096))
+               RETURN(-ENOMEM);
+
+       buf_size = user_count + 1;
+
+       OBD_ALLOC(buf, buf_size);
+       if (buf == NULL)
+               RETURN(-ENOMEM);
+
+       if (copy_from_user(buf, user_buf, buf_size - 1))
+               GOTO(out, rc = -EFAULT);
+
+       buf[buf_size - 1] = '\0';
+
+       pos = buf;
+       while ((name = strsep(&pos, " \t\v\n")) != NULL) {
+               int action;
+
+               if (*name == '\0')
+                       continue;
+
+               action = hsm_copytool_name2action(name);
+               if (action < 0)
+                       GOTO(out, rc = -EINVAL);
+
+               new_mask |= (1UL << action);
+       }
+
+       *mask = new_mask;
+       rc = user_count;
+out:
+       OBD_FREE(buf, buf_size);
+
+       RETURN(rc);
+}
+
+static int
+lprocfs_wr_hsm_user_request_mask(struct file *file, const char __user *buf,
+                                unsigned long count, void *data)
+{
+       struct mdt_device *mdt = data;
+       struct coordinator *cdt = &mdt->mdt_coordinator;
+
+       return lprocfs_wr_hsm_request_mask(file, buf, count,
+                                          &cdt->cdt_user_request_mask);
+}
+
+static int
+lprocfs_wr_hsm_group_request_mask(struct file *file, const char __user *buf,
+                                 unsigned long count, void *data)
+{
+       struct mdt_device *mdt = data;
+       struct coordinator *cdt = &mdt->mdt_coordinator;
+
+       return lprocfs_wr_hsm_request_mask(file, buf, count,
+                                          &cdt->cdt_group_request_mask);
+}
+
+static int
+lprocfs_wr_hsm_other_request_mask(struct file *file, const char __user *buf,
+                                 unsigned long count, void *data)
+{
+       struct mdt_device *mdt = data;
+       struct coordinator *cdt = &mdt->mdt_coordinator;
+
+       return lprocfs_wr_hsm_request_mask(file, buf, count,
+                                          &cdt->cdt_other_request_mask);
+}
+
 static struct lprocfs_vars lprocfs_mdt_hsm_vars[] = {
        { "agents",             NULL, NULL, NULL, &mdt_hsm_agent_fops, 0 },
        { "agent_actions",      NULL, NULL, NULL,
                                &mdt_agent_actions_fops, 0444 },
+       { "default_archive_id", lprocfs_rd_hsm_cdt_default_archive_id,
+                               lprocfs_wr_hsm_cdt_default_archive_id,
+                               NULL, NULL, 0 },
        { "grace_delay",        lprocfs_rd_hsm_cdt_delay,
                                lprocfs_wr_hsm_cdt_delay,
                                NULL, NULL, 0 },
@@ -1995,5 +2206,11 @@ static struct lprocfs_vars lprocfs_mdt_hsm_vars[] = {
                                lprocfs_wr_hsm_cdt_timeout,
                                NULL, NULL, 0 },
        { "requests",           NULL, NULL, NULL, &mdt_hsm_request_fops, 0 },
-       { 0 }
+       { "user_request_mask", lprocfs_rd_hsm_user_request_mask,
+         lprocfs_wr_hsm_user_request_mask, },
+       { "group_request_mask", lprocfs_rd_hsm_group_request_mask,
+         lprocfs_wr_hsm_group_request_mask, },
+       { "other_request_mask", lprocfs_rd_hsm_other_request_mask,
+         lprocfs_wr_hsm_other_request_mask, },
+       { NULL }
 };