Whamcloud - gitweb
LU-7986 hsm: update actions llog in place
[fs/lustre-release.git] / lustre / mdt / mdt_coordinator.c
index a9ee560..c74cf10 100644 (file)
  * GPL HEADER END
  */
 /*
- * Copyright (c) 2012, 2013, Intel Corporation.
- * Use is subject to license terms.
  * Copyright (c) 2011, 2012 Commissariat a l'energie atomique et aux energies
  *                          alternatives
+ *
+ * Copyright (c) 2013, 2014, Intel Corporation.
+ * Use is subject to license terms.
  */
 /*
  * lustre/mdt/mdt_coordinator.c
 
 #define DEBUG_SUBSYSTEM S_MDS
 
+#include <linux/kthread.h>
 #include <obd_support.h>
 #include <lustre_net.h>
 #include <lustre_export.h>
 #include <obd.h>
 #include <lprocfs_status.h>
 #include <lustre_log.h>
+#include <lustre_kernelcomm.h>
 #include "mdt_internal.h"
 
 static struct lprocfs_vars lprocfs_mdt_hsm_vars[];
@@ -139,10 +142,6 @@ struct hsm_scan_data {
                int                      hal_used_sz;
                struct hsm_action_list  *hal;
        } *request;
-       /* records to be canceled */
-       int                              max_cookie;    /** vector size */
-       int                              cookie_cnt;    /** used count */
-       __u64                           *cookies;
 };
 
 /**
@@ -161,7 +160,7 @@ static int mdt_coordinator_cb(const struct lu_env *env,
                              struct llog_rec_hdr *hdr,
                              void *data)
 {
-       const struct llog_agent_req_rec *larr;
+       struct llog_agent_req_rec       *larr;
        struct hsm_scan_data            *hsd;
        struct hsm_action_item          *hai;
        struct mdt_device               *mdt;
@@ -184,8 +183,8 @@ static int mdt_coordinator_cb(const struct lu_env *env,
                    cdt->cdt_max_requests)
                        break;
 
-               /* first search if the request if known in the list we have
-                * build and if there is room in the request vector */
+               /* first search whether the request is found in the list we
+                * have built and if there is room in the request vector */
                empty_slot = -1;
                found = -1;
                for (i = 0; i < hsd->max_requests &&
@@ -227,9 +226,8 @@ static int mdt_coordinator_cb(const struct lu_env *env,
                                RETURN(-ENOMEM);
                        }
                        hal->hal_version = HAL_VERSION;
-                       strncpy(hal->hal_fsname, hsd->fs_name,
-                               MTI_NAME_MAXLEN);
-                       hal->hal_fsname[MTI_NAME_MAXLEN] = '\0';
+                       strlcpy(hal->hal_fsname, hsd->fs_name,
+                               MTI_NAME_MAXLEN + 1);
                        hal->hal_compound_id = larr->arr_compound_id;
                        hal->hal_archive_id = larr->arr_archive_id;
                        hal->hal_flags = larr->arr_flags;
@@ -290,7 +288,9 @@ static int mdt_coordinator_cb(const struct lu_env *env,
                break;
        }
        case ARS_STARTED: {
+               struct hsm_progress_kernel pgs;
                struct cdt_agent_req *car;
+               cfs_time_t now = cfs_time_current_sec();
                cfs_time_t last;
 
                /* we search for a running request
@@ -307,65 +307,52 @@ static int mdt_coordinator_cb(const struct lu_env *env,
 
                /* test if request too long, if yes cancel it
                 * the same way the copy tool acknowledge a cancel request */
-               if ((last + cdt->cdt_active_req_timeout)
-                    < cfs_time_current_sec()) {
-                       struct hsm_progress_kernel pgs;
-
-                       dump_llog_agent_req_rec("mdt_coordinator_cb(): "
-                                               "request timeouted, start "
-                                               "cleaning", larr);
-                       /* a too old cancel request just needs to be removed
-                        * this can happen, if copy tool does not support cancel
-                        * for other requests, we have to remove the running
-                        * request and notify the copytool
-                        */
-                       pgs.hpk_fid = larr->arr_hai.hai_fid;
-                       pgs.hpk_cookie = larr->arr_hai.hai_cookie;
-                       pgs.hpk_extent = larr->arr_hai.hai_extent;
-                       pgs.hpk_flags = HP_FLAG_COMPLETED;
-                       pgs.hpk_errval = ENOSYS;
-                       pgs.hpk_data_version = 0;
-                       /* update request state, but do not record in llog, to
-                        * avoid deadlock on cdt_llog_lock
-                        */
-                       rc = mdt_hsm_update_request_state(hsd->mti, &pgs, 0);
-                       if (rc)
-                               CERROR("%s: Cannot cleanup timeouted request: "
-                                      DFID" for cookie "LPX64" action=%s\n",
-                                      mdt_obd_name(mdt),
-                                      PFID(&pgs.hpk_fid), pgs.hpk_cookie,
-                                      hsm_copytool_action2name(
-                                                    larr->arr_hai.hai_action));
-
-                       /* add the cookie to the list of record to be
-                        * canceled by caller */
-                       if (hsd->max_cookie == (hsd->cookie_cnt - 1)) {
-                               __u64 *ptr, *old_ptr;
-                               int old_sz, new_sz, new_cnt;
+               if (now <= last + cdt->cdt_active_req_timeout)
+                       RETURN(0);
 
-                               /* need to increase vector size */
-                               old_sz = sizeof(__u64) * hsd->max_cookie;
-                               old_ptr = hsd->cookies;
+               dump_llog_agent_req_rec("request timed out, start cleaning",
+                                       larr);
+               /* a too old cancel request just needs to be removed
+                * this can happen, if copy tool does not support
+                * cancel for other requests, we have to remove the
+                * running request and notify the copytool */
+               pgs.hpk_fid = larr->arr_hai.hai_fid;
+               pgs.hpk_cookie = larr->arr_hai.hai_cookie;
+               pgs.hpk_extent = larr->arr_hai.hai_extent;
+               pgs.hpk_flags = HP_FLAG_COMPLETED;
+               pgs.hpk_errval = ENOSYS;
+               pgs.hpk_data_version = 0;
+
+               /* update request state, but do not record in llog, to
+                * avoid deadlock on cdt_llog_lock */
+               rc = mdt_hsm_update_request_state(hsd->mti, &pgs, 0);
+               if (rc)
+                       CERROR("%s: cannot cleanup timed out request: "
+                              DFID" for cookie "LPX64" action=%s\n",
+                              mdt_obd_name(mdt),
+                              PFID(&pgs.hpk_fid), pgs.hpk_cookie,
+                              hsm_copytool_action2name(
+                                      larr->arr_hai.hai_action));
+
+               if (rc == -ENOENT) {
+                       /* The request no longer exists, forget
+                        * about it, and do not send a cancel request
+                        * to the client, for which an error will be
+                        * sent back, leading to an endless cycle of
+                        * cancellation. */
+                       RETURN(LLOG_DEL_RECORD);
+               }
 
-                               new_cnt = 2 * hsd->max_cookie;
-                               new_sz = sizeof(__u64) * new_cnt;
+               /* XXX A cancel request cannot be cancelled. */
+               if (larr->arr_hai.hai_action == HSMA_CANCEL)
+                       RETURN(0);
 
-                               OBD_ALLOC(ptr, new_sz);
-                               if (!ptr) {
-                                       CERROR("%s: Cannot allocate memory "
-                                              "(%d o) for cookie vector\n",
-                                              mdt_obd_name(mdt), new_sz);
-                                       RETURN(-ENOMEM);
-                               }
-                               memcpy(ptr, hsd->cookies, old_sz);
-                               hsd->cookies = ptr;
-                               hsd->max_cookie = new_cnt;
-                               OBD_FREE(old_ptr, old_sz);
-                       }
-                       hsd->cookies[hsd->cookie_cnt] =
-                                                      larr->arr_hai.hai_cookie;
-                       hsd->cookie_cnt++;
-               }
+               larr->arr_status = ARS_CANCELED;
+               larr->arr_req_change = now;
+               rc = llog_write(hsd->mti->mti_env, llh, hdr, hdr->lrh_index);
+               if (rc < 0)
+                       CERROR("%s: cannot update agent log: rc = %d\n",
+                              mdt_obd_name(mdt), rc);
                break;
        }
        case ARS_FAILED:
@@ -440,7 +427,7 @@ static int mdt_coordinator(void *data)
        struct mdt_thread_info  *mti = data;
        struct mdt_device       *mdt = mti->mti_mdt;
        struct coordinator      *cdt = &mdt->mdt_coordinator;
-       struct hsm_scan_data     hsd = { 0 };
+       struct hsm_scan_data     hsd = { NULL };
        int                      rc = 0;
        ENTRY;
 
@@ -450,10 +437,6 @@ static int mdt_coordinator(void *data)
        CDEBUG(D_HSM, "%s: coordinator thread starting, pid=%d\n",
               mdt_obd_name(mdt), current_pid());
 
-       /* timeouted cookie vector initialization */
-       hsd.max_cookie = 0;
-       hsd.cookie_cnt = 0;
-       hsd.cookies = NULL;
        /* we use a copy of cdt_max_requests in the cb, so if cdt_max_requests
         * increases due to a change from /proc we do not overflow the
         * hsd.request[] vector
@@ -514,16 +497,6 @@ static int mdt_coordinator(void *data)
                        }
                }
 
-               /* create canceled cookie vector for an arbitrary size
-                * if needed, vector will grow during llog scan
-                */
-               hsd.max_cookie = 10;
-               hsd.cookie_cnt = 0;
-               OBD_ALLOC(hsd.cookies, hsd.max_cookie * sizeof(__u64));
-               if (!hsd.cookies) {
-                       rc = -ENOMEM;
-                       goto clean_cb_alloc;
-               }
                hsd.request_cnt = 0;
 
                rc = cdt_llog_process(mti->mti_env, mdt,
@@ -531,23 +504,7 @@ static int mdt_coordinator(void *data)
                if (rc < 0)
                        goto clean_cb_alloc;
 
-               CDEBUG(D_HSM, "Found %d requests to send and %d"
-                             " requests to cancel\n",
-                      hsd.request_cnt, hsd.cookie_cnt);
-               /* first we cancel llog records of the timeouted requests */
-               if (hsd.cookie_cnt > 0) {
-                       rc = mdt_agent_record_update(mti->mti_env, mdt,
-                                                    hsd.cookies,
-                                                    hsd.cookie_cnt,
-                                                    ARS_CANCELED);
-                       if (rc)
-                               CERROR("%s: mdt_agent_record_update() failed, "
-                                      "rc=%d, cannot update status to %s "
-                                      "for %d cookies\n",
-                                      mdt_obd_name(mdt), rc,
-                                      agent_req_status2name(ARS_CANCELED),
-                                      hsd.cookie_cnt);
-               }
+               CDEBUG(D_HSM, "found %d requests to send\n", hsd.request_cnt);
 
                if (list_empty(&cdt->cdt_agents)) {
                        CDEBUG(D_HSM, "no agent available, "
@@ -629,14 +586,6 @@ static int mdt_coordinator(void *data)
                        kuc_free(hal, hsd.request[i].hal_used_sz);
                }
 clean_cb_alloc:
-               /* free cookie vector allocated for/by callback */
-               if (hsd.cookies) {
-                       OBD_FREE(hsd.cookies, hsd.max_cookie * sizeof(__u64));
-                       hsd.max_cookie = 0;
-                       hsd.cookie_cnt = 0;
-                       hsd.cookies = NULL;
-               }
-
                /* free hal allocated by callback */
                for (i = 0; i < hsd.max_requests; i++) {
                        if (hsd.request[i].hal) {
@@ -657,9 +606,6 @@ out:
        if (hsd.request)
                OBD_FREE(hsd.request, hsd.request_sz);
 
-       if (hsd.cookies)
-               OBD_FREE(hsd.cookies, hsd.max_cookie * sizeof(__u64));
-
        if (cdt->cdt_state == CDT_STOPPING) {
                /* request comes from /proc path, so we need to clean cdt
                 * struct */
@@ -869,9 +815,9 @@ int mdt_hsm_cdt_init(struct mdt_device *mdt)
        init_rwsem(&cdt->cdt_request_lock);
        mutex_init(&cdt->cdt_restore_lock);
 
-       CFS_INIT_LIST_HEAD(&cdt->cdt_requests);
-       CFS_INIT_LIST_HEAD(&cdt->cdt_agents);
-       CFS_INIT_LIST_HEAD(&cdt->cdt_restore_hdl);
+       INIT_LIST_HEAD(&cdt->cdt_requests);
+       INIT_LIST_HEAD(&cdt->cdt_agents);
+       INIT_LIST_HEAD(&cdt->cdt_restore_hdl);
 
        rc = lu_env_init(&cdt->cdt_env, LCT_MD_THREAD);
        if (rc < 0)
@@ -1261,7 +1207,7 @@ static int hsm_cdt_request_completed(struct mdt_thread_info *mti,
                         * ENOSYS only if does not support cancel
                         */
                        /* this can also happen when cdt calls it to
-                        * for a timeouted request */
+                        * for a timed out request */
                        *status = ARS_FAILED;
                        /* to have a cancel event in changelog */
                        pgs->hpk_errval = ECANCELED;
@@ -1391,7 +1337,7 @@ unlock:
                struct cdt_restore_handle       *crh;
 
                /* restore in data FID done, we swap the layouts
-                * only if restore is successfull */
+                * only if restore is successful */
                if (pgs->hpk_errval == 0) {
                        rc = hsm_swap_layouts(mti, &car->car_hai->hai_fid,
                                              &car->car_hai->hai_dfid, &mh);
@@ -1462,8 +1408,7 @@ 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));
        }
 
@@ -1594,10 +1539,9 @@ static int mdt_cancel_all_cb(const struct lu_env *env,
            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);
-               if (rc == 0)
-                       RETURN(LLOG_DEL_RECORD);
+               rc = llog_write(env, llh, hdr, hdr->lrh_index);
        }
+
        RETURN(rc);
 }
 
@@ -1702,7 +1646,7 @@ out:
 }
 
 /**
- * check if a request is comptaible with file status
+ * check if a request is compatible with file status
  * \param hai [IN] request description
  * \param hal_an [IN] request archive number (not used)
  * \param rq_flags [IN] request flags
@@ -1785,22 +1729,17 @@ static __u64 hsm_policy_str2bit(const char *name)
  * \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, const bool hexa, char *buffer,
-                             int count)
+static void hsm_policy_bit2str(struct seq_file *m, const __u64 mask,
+                               const bool hexa)
 {
-       int      i, j, sz;
-       char    *ptr;
+       int      i, j;
        __u64    bit;
        ENTRY;
 
-       ptr = buffer;
-       if (hexa) {
-               sz = snprintf(buffer, count, "("LPX64") ", mask);
-               ptr += sz;
-               count -= sz;
-       }
+       if (hexa)
+               seq_printf(m, "("LPX64") ", mask);
+
        for (i = 0; i < CDT_POLICY_SHIFT_COUNT; i++) {
                bit = (1ULL << i);
 
@@ -1809,48 +1748,37 @@ static int hsm_policy_bit2str(const __u64 mask, const bool hexa, char *buffer,
                                break;
                }
                if (bit & mask)
-                       sz = snprintf(ptr, count, "[%s] ",
-                                     hsm_policy_names[j].name);
+                       seq_printf(m, "[%s] ", hsm_policy_names[j].name);
                else
-                       sz = snprintf(ptr, count, "%s ",
-                                     hsm_policy_names[j].name);
-
-               ptr += sz;
-               count -= sz;
+                       seq_printf(m, "%s ", hsm_policy_names[j].name);
        }
        /* remove last ' ' */
-       *ptr = '\0';
-       ptr--;
-       RETURN(ptr - buffer);
+       m->count--;
+       seq_putc(m, '\0');
 }
 
 /* methods to read/write HSM policy flags */
-static int lprocfs_rd_hsm_policy(char *page, char **start, off_t off,
-                                int count, int *eof, void *data)
+static int mdt_hsm_policy_seq_show(struct seq_file *m, void *data)
 {
-       struct mdt_device       *mdt = data;
+       struct mdt_device       *mdt = m->private;
        struct coordinator      *cdt = &mdt->mdt_coordinator;
-       int                      sz;
        ENTRY;
 
-       sz = hsm_policy_bit2str(cdt->cdt_policy, false, page, count);
-       page[sz] = '\n';
-       sz++;
-       page[sz] = '\0';
-       *eof = 1;
-       RETURN(sz);
+       hsm_policy_bit2str(m, cdt->cdt_policy, false);
+       RETURN(0);
 }
 
-static int lprocfs_wr_hsm_policy(struct file *file, const char *buffer,
-                                unsigned long count, void *data)
+static ssize_t
+mdt_hsm_policy_seq_write(struct file *file, const char __user *buffer,
+                        size_t count, loff_t *off)
 {
-       struct mdt_device       *mdt = data;
+       struct seq_file         *m = file->private_data;
+       struct mdt_device       *mdt = m->private;
        struct coordinator      *cdt = &mdt->mdt_coordinator;
        char                    *start, *token, sign;
        char                    *buf;
        __u64                    policy;
        __u64                    add_mask, remove_mask, set_mask;
-       int                      sz;
        int                      rc;
        ENTRY;
 
@@ -1883,18 +1811,10 @@ static int lprocfs_wr_hsm_policy(struct file *file, const char *buffer,
 
                policy = hsm_policy_str2bit(token);
                if (policy == 0) {
-                       char *msg;
-
-                       sz = PAGE_SIZE;
-                       OBD_ALLOC(msg, sz);
-                       if (!msg)
-                               GOTO(out, rc = -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);
+                             "supported policies are:\n", mdt_obd_name(mdt),
+                             token);
+                       hsm_policy_bit2str(m, 0, false);
                        GOTO(out, rc = -EINVAL);
                }
                switch (sign) {
@@ -1933,25 +1853,25 @@ out:
        OBD_FREE(buf, count + 1);
        RETURN(rc);
 }
+LPROC_SEQ_FOPS(mdt_hsm_policy);
 
 #define GENERATE_PROC_METHOD(VAR)                                      \
-static int lprocfs_rd_hsm_##VAR(char *page, char **start, off_t off,   \
-                               int count, int *eof, void *data)        \
+static int mdt_hsm_##VAR##_seq_show(struct seq_file *m, void *data)    \
 {                                                                      \
-       struct mdt_device       *mdt = data;                            \
+       struct mdt_device       *mdt = m->private;                      \
        struct coordinator      *cdt = &mdt->mdt_coordinator;           \
-       int                      sz;                                    \
        ENTRY;                                                          \
                                                                        \
-       sz = snprintf(page, count, LPU64"\n", (__u64)cdt->VAR);         \
-       *eof = 1;                                                       \
-       RETURN(sz);                                                     \
+       seq_printf(m, LPU64"\n", (__u64)cdt->VAR);                      \
+       RETURN(0);                                                      \
 }                                                                      \
-static int lprocfs_wr_hsm_##VAR(struct file *file, const char *buffer, \
-                               unsigned long count, void *data)        \
+static ssize_t                                                         \
+mdt_hsm_##VAR##_seq_write(struct file *file, const char __user *buffer,        \
+                         size_t count, loff_t *off)                    \
                                                                        \
 {                                                                      \
-       struct mdt_device       *mdt = data;                            \
+       struct seq_file         *m = file->private_data;                \
+       struct mdt_device       *mdt = m->private;                      \
        struct coordinator      *cdt = &mdt->mdt_coordinator;           \
        int                      val;                                   \
        int                      rc;                                    \
@@ -1965,7 +1885,7 @@ static int lprocfs_wr_hsm_##VAR(struct file *file, const char *buffer,    \
                RETURN(count);                                          \
        }                                                               \
        RETURN(-EINVAL);                                                \
-}
+}                                                                      \
 
 GENERATE_PROC_METHOD(cdt_loop_period)
 GENERATE_PROC_METHOD(cdt_grace_delay)
@@ -1982,25 +1902,39 @@ GENERATE_PROC_METHOD(cdt_default_archive_id)
 #define CDT_DISABLE_CMD  "disabled"
 #define CDT_PURGE_CMD    "purge"
 #define CDT_HELP_CMD     "help"
+#define CDT_MAX_CMD_LEN  10
 
-int lprocfs_wr_hsm_cdt_control(struct file *file, const char *buffer,
-                              unsigned long count, void *data)
+ssize_t
+mdt_hsm_cdt_control_seq_write(struct file *file, const char __user *buffer,
+                             size_t count, loff_t *off)
 {
-       struct obd_device       *obd = data;
+       struct seq_file         *m = file->private_data;
+       struct obd_device       *obd = m->private;
        struct mdt_device       *mdt = mdt_dev(obd->obd_lu_dev);
        struct coordinator      *cdt = &(mdt->mdt_coordinator);
        int                      rc, usage = 0;
+       char                     kernbuf[CDT_MAX_CMD_LEN];
        ENTRY;
 
+       if (count == 0 || count >= sizeof(kernbuf))
+               RETURN(-EINVAL);
+
+       if (copy_from_user(kernbuf, buffer, count))
+               RETURN(-EFAULT);
+       kernbuf[count] = 0;
+
+       if (kernbuf[count - 1] == '\n')
+               kernbuf[count - 1] = 0;
+
        rc = 0;
-       if (strncmp(buffer, CDT_ENABLE_CMD, strlen(CDT_ENABLE_CMD)) == 0) {
+       if (strcmp(kernbuf, CDT_ENABLE_CMD) == 0) {
                if (cdt->cdt_state == CDT_DISABLE) {
                        cdt->cdt_state = CDT_RUNNING;
                        mdt_hsm_cdt_wakeup(mdt);
                } else {
                        rc = mdt_hsm_cdt_start(mdt);
                }
-       } else if (strncmp(buffer, CDT_STOP_CMD, strlen(CDT_STOP_CMD)) == 0) {
+       } else if (strcmp(kernbuf, CDT_STOP_CMD) == 0) {
                if ((cdt->cdt_state == CDT_STOPPING) ||
                    (cdt->cdt_state == CDT_STOPPED)) {
                        CERROR("%s: Coordinator already stopped\n",
@@ -2009,8 +1943,7 @@ int lprocfs_wr_hsm_cdt_control(struct file *file, const char *buffer,
                } else {
                        cdt->cdt_state = CDT_STOPPING;
                }
-       } else if (strncmp(buffer, CDT_DISABLE_CMD,
-                          strlen(CDT_DISABLE_CMD)) == 0) {
+       } else if (strcmp(kernbuf, CDT_DISABLE_CMD) == 0) {
                if ((cdt->cdt_state == CDT_STOPPING) ||
                    (cdt->cdt_state == CDT_STOPPED)) {
                        CERROR("%s: Coordinator is stopped\n",
@@ -2019,9 +1952,9 @@ int lprocfs_wr_hsm_cdt_control(struct file *file, const char *buffer,
                } else {
                        cdt->cdt_state = CDT_DISABLE;
                }
-       } else if (strncmp(buffer, CDT_PURGE_CMD, strlen(CDT_PURGE_CMD)) == 0) {
+       } else if (strcmp(kernbuf, CDT_PURGE_CMD) == 0) {
                rc = hsm_cancel_all_actions(mdt);
-       } else if (strncmp(buffer, CDT_HELP_CMD, strlen(CDT_HELP_CMD)) == 0) {
+       } else if (strcmp(kernbuf, CDT_HELP_CMD) == 0) {
                usage = 1;
        } else {
                usage = 1;
@@ -2040,83 +1973,74 @@ int lprocfs_wr_hsm_cdt_control(struct file *file, const char *buffer,
        RETURN(count);
 }
 
-int lprocfs_rd_hsm_cdt_control(char *page, char **start, off_t off,
-                              int count, int *eof, void *data)
+int mdt_hsm_cdt_control_seq_show(struct seq_file *m, void *data)
 {
-       struct obd_device       *obd = data;
+       struct obd_device       *obd = m->private;
        struct coordinator      *cdt;
-       int                      sz;
        ENTRY;
 
        cdt = &(mdt_dev(obd->obd_lu_dev)->mdt_coordinator);
-       *eof = 1;
 
        if (cdt->cdt_state == CDT_INIT)
-               sz = snprintf(page, count, "init\n");
+               seq_printf(m, "init\n");
        else if (cdt->cdt_state == CDT_RUNNING)
-               sz = snprintf(page, count, "enabled\n");
+               seq_printf(m, "enabled\n");
        else if (cdt->cdt_state == CDT_STOPPING)
-               sz = snprintf(page, count, "stopping\n");
+               seq_printf(m, "stopping\n");
        else if (cdt->cdt_state == CDT_STOPPED)
-               sz = snprintf(page, count, "stopped\n");
+               seq_printf(m, "stopped\n");
        else if (cdt->cdt_state == CDT_DISABLE)
-               sz = snprintf(page, count, "disabled\n");
+               seq_printf(m, "disabled\n");
        else
-               sz = snprintf(page, count, "unknown\n");
+               seq_printf(m, "unknown\n");
 
-       RETURN(sz);
+       RETURN(0);
 }
 
 static int
-lprocfs_rd_hsm_request_mask(char *page, char **start, off_t off,
-                           int count, int *eof, __u64 mask)
+mdt_hsm_request_mask_show(struct seq_file *m, __u64 mask)
 {
-       int i, rc = 0;
+       bool first = true;
+       int i;
        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));
+               if (mask & (1UL << i)) {
+                       seq_printf(m, "%s%s", first ? "" : " ",
+                                  hsm_copytool_action2name(i));
+                       first = false;
+               }
        }
+       seq_putc(m, '\n');
 
-       rc += snprintf(page + rc, count - rc, "\n");
-
-       RETURN(rc);
+       RETURN(0);
 }
 
 static int
-lprocfs_rd_hsm_user_request_mask(char *page, char **start, off_t off,
-                                int count, int *eof, void *data)
+mdt_hsm_user_request_mask_seq_show(struct seq_file *m, void *data)
 {
-       struct mdt_device *mdt = data;
+       struct mdt_device *mdt = m->private;
        struct coordinator *cdt = &mdt->mdt_coordinator;
 
-       return lprocfs_rd_hsm_request_mask(page, start, off, count, eof,
-                                          cdt->cdt_user_request_mask);
+       return mdt_hsm_request_mask_show(m, 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)
+mdt_hsm_group_request_mask_seq_show(struct seq_file *m, void *data)
 {
-       struct mdt_device *mdt = data;
+       struct mdt_device *mdt = m->private;
        struct coordinator *cdt = &mdt->mdt_coordinator;
 
-       return lprocfs_rd_hsm_request_mask(page, start, off, count, eof,
-                                          cdt->cdt_group_request_mask);
+       return mdt_hsm_request_mask_show(m, 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)
+mdt_hsm_other_request_mask_seq_show(struct seq_file *m, void *data)
 {
-       struct mdt_device *mdt = data;
+       struct mdt_device *mdt = m->private;
        struct coordinator *cdt = &mdt->mdt_coordinator;
 
-       return lprocfs_rd_hsm_request_mask(page, start, off, count, eof,
-                                          cdt->cdt_other_request_mask);
+       return mdt_hsm_request_mask_show(m, cdt->cdt_other_request_mask);
 }
 
 static inline enum hsm_copytool_action
@@ -2136,9 +2060,9 @@ hsm_copytool_name2action(const char *name)
                return -1;
 }
 
-static int
-lprocfs_wr_hsm_request_mask(struct file *file, const char __user *user_buf,
-                           unsigned long user_count, __u64 *mask)
+static ssize_t
+mdt_write_hsm_request_mask(struct file *file, const char __user *user_buf,
+                           size_t user_count, __u64 *mask)
 {
        char *buf, *pos, *name;
        size_t buf_size;
@@ -2182,69 +2106,76 @@ out:
        RETURN(rc);
 }
 
-static int
-lprocfs_wr_hsm_user_request_mask(struct file *file, const char __user *buf,
-                                unsigned long count, void *data)
+static ssize_t
+mdt_hsm_user_request_mask_seq_write(struct file *file, const char __user *buf,
+                                       size_t count, loff_t *off)
 {
-       struct mdt_device *mdt = data;
+       struct seq_file         *m = file->private_data;
+       struct mdt_device       *mdt = m->private;
        struct coordinator *cdt = &mdt->mdt_coordinator;
 
-       return lprocfs_wr_hsm_request_mask(file, buf, count,
+       return mdt_write_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)
+static ssize_t
+mdt_hsm_group_request_mask_seq_write(struct file *file, const char __user *buf,
+                                       size_t count, loff_t *off)
 {
-       struct mdt_device *mdt = data;
-       struct coordinator *cdt = &mdt->mdt_coordinator;
+       struct seq_file         *m = file->private_data;
+       struct mdt_device       *mdt = m->private;
+       struct coordinator      *cdt = &mdt->mdt_coordinator;
 
-       return lprocfs_wr_hsm_request_mask(file, buf, count,
+       return mdt_write_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)
+static ssize_t
+mdt_hsm_other_request_mask_seq_write(struct file *file, const char __user *buf,
+                                       size_t count, loff_t *off)
 {
-       struct mdt_device *mdt = data;
-       struct coordinator *cdt = &mdt->mdt_coordinator;
+       struct seq_file         *m = file->private_data;
+       struct mdt_device       *mdt = m->private;
+       struct coordinator      *cdt = &mdt->mdt_coordinator;
 
-       return lprocfs_wr_hsm_request_mask(file, buf, count,
+       return mdt_write_hsm_request_mask(file, buf, count,
                                           &cdt->cdt_other_request_mask);
 }
 
+LPROC_SEQ_FOPS(mdt_hsm_cdt_loop_period);
+LPROC_SEQ_FOPS(mdt_hsm_cdt_grace_delay);
+LPROC_SEQ_FOPS(mdt_hsm_cdt_active_req_timeout);
+LPROC_SEQ_FOPS(mdt_hsm_cdt_max_requests);
+LPROC_SEQ_FOPS(mdt_hsm_cdt_default_archive_id);
+LPROC_SEQ_FOPS(mdt_hsm_user_request_mask);
+LPROC_SEQ_FOPS(mdt_hsm_group_request_mask);
+LPROC_SEQ_FOPS(mdt_hsm_other_request_mask);
+
 static struct lprocfs_vars lprocfs_mdt_hsm_vars[] = {
-       { "agents",                     NULL, NULL, NULL, &mdt_hsm_agent_fops,
-                                       0 },
-       { "actions",                    NULL, NULL, NULL, &mdt_hsm_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_grace_delay,
-                                       lprocfs_wr_hsm_cdt_grace_delay,
-                                       NULL, NULL, 0 },
-       { "loop_period",                lprocfs_rd_hsm_cdt_loop_period,
-                                       lprocfs_wr_hsm_cdt_loop_period,
-                                       NULL, NULL, 0 },
-       { "max_requests",               lprocfs_rd_hsm_cdt_max_requests,
-                                       lprocfs_wr_hsm_cdt_max_requests,
-                                       NULL, NULL, 0 },
-       { "policy",                     lprocfs_rd_hsm_policy,
-                                       lprocfs_wr_hsm_policy,
-                                       NULL, NULL, 0 },
-       { "active_request_timeout",     lprocfs_rd_hsm_cdt_active_req_timeout,
-                                       lprocfs_wr_hsm_cdt_active_req_timeout,
-                                       NULL, NULL, 0 },
-       { "active_requests",            NULL, NULL, NULL,
-                                       &mdt_hsm_active_requests_fops, 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, },
+       { .name =       "agents",
+         .fops =       &mdt_hsm_agent_fops                     },
+       { .name =       "actions",
+         .fops =       &mdt_hsm_actions_fops,
+         .proc_mode =  0444                                    },
+       { .name =       "default_archive_id",
+         .fops =       &mdt_hsm_cdt_default_archive_id_fops    },
+       { .name =       "grace_delay",
+         .fops =       &mdt_hsm_cdt_grace_delay_fops           },
+       { .name =       "loop_period",
+         .fops =       &mdt_hsm_cdt_loop_period_fops           },
+       { .name =       "max_requests",
+         .fops =       &mdt_hsm_cdt_max_requests_fops          },
+       { .name =       "policy",
+         .fops =       &mdt_hsm_policy_fops                    },
+       { .name =       "active_request_timeout",
+         .fops =       &mdt_hsm_cdt_active_req_timeout_fops    },
+       { .name =       "active_requests",
+         .fops =       &mdt_hsm_active_requests_fops           },
+       { .name =       "user_request_mask",
+         .fops =       &mdt_hsm_user_request_mask_fops,        },
+       { .name =       "group_request_mask",
+         .fops =       &mdt_hsm_group_request_mask_fops,       },
+       { .name =       "other_request_mask",
+         .fops =       &mdt_hsm_other_request_mask_fops,       },
        { 0 }
 };