Whamcloud - gitweb
LU-3866 hsm: permission checks on HSM operations
[fs/lustre-release.git] / lustre / mdt / mdt_coordinator.c
index 95437e2..9d5d4cd 100644 (file)
@@ -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), current_pid());
 
-       /*
-        * create /proc entries for coordinator
-        */
-       hsm_cdt_procfs_init(mdt);
        /* timeouted cookie vector initialization */
        hsd.max_cookie = 0;
        hsd.cookie_cnt = 0;
@@ -652,7 +671,7 @@ 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)
@@ -725,6 +744,10 @@ static int hsm_restore_cb(const struct lu_env *env,
 
        larr = (struct llog_agent_req_rec *)hdr;
        hai = &larr->arr_hai;
+       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);
@@ -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,
@@ -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);
 }
 
@@ -918,19 +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;
 
        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;
-       cdt->cdt_archive_id = 1;
+
        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 */
@@ -956,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;
@@ -983,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;
 
@@ -1712,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 },
 };
 
@@ -1728,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;
 }
@@ -1736,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;
@@ -1748,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);
 }
 
@@ -1779,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';
@@ -1792,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)
@@ -1817,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);
+
+       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);
 
-               start = end + 1;
-       } while (end != NULL);
+out:
        OBD_FREE(buf, count + 1);
-       RETURN(count);
+       RETURN(rc);
 }
 
 #define GENERATE_PROC_METHOD(VAR)                                      \
@@ -1898,7 +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_archive_id)
+GENERATE_PROC_METHOD(cdt_default_archive_id)
 
 /*
  * procfs write method for MDT/hsm_control
@@ -1980,12 +2036,160 @@ 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 },
-       { "archive_id",         lprocfs_rd_hsm_cdt_archive_id,
-                               lprocfs_wr_hsm_cdt_archive_id,
+       { "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,
@@ -2002,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 }
 };