Viewing: mdt_hsm_cdt_actions.c
// SPDX-License-Identifier: GPL-2.0
/*
* (C) Copyright 2012 Commissariat a l'energie atomique et aux energies
* alternatives
*
* Copyright (c) 2013, 2017, Intel Corporation.
*/
/*
* Lustre HSM
*
* 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_export.h>
#include <obd.h>
#include <lprocfs_status.h>
#include <lustre_log.h>
#include "mdt_internal.h"
void dump_llog_agent_req_rec(const char *prefix,
const struct llog_agent_req_rec *larr)
{
char buf[12];
int sz;
sz = larr->arr_hai.hai_len - sizeof(larr->arr_hai);
CDEBUG(D_HSM, "%slrh=[type=%X len=%d idx=%d] fid="DFID
" dfid="DFID
" cookie=%#llx"
" status=%s action=%s archive#=%d flags=%#llx"
" create=%llu change=%llu"
" extent=%#llx-%#llx gid=%#llx datalen=%d"
" data=[%s]\n",
prefix,
larr->arr_hdr.lrh_type,
larr->arr_hdr.lrh_len, larr->arr_hdr.lrh_index,
PFID(&larr->arr_hai.hai_fid),
PFID(&larr->arr_hai.hai_dfid),
larr->arr_hai.hai_cookie,
agent_req_status2name(larr->arr_status),
hsm_copytool_action2name(larr->arr_hai.hai_action),
larr->arr_archive_id,
larr->arr_flags,
larr->arr_req_create, larr->arr_req_change,
larr->arr_hai.hai_extent.offset,
larr->arr_hai.hai_extent.length,
larr->arr_hai.hai_gid, sz,
hai_dump_data_field(&larr->arr_hai, buf, sizeof(buf)));
}
/*
* process the actions llog
* \param env [IN] environment
* \param mdt [IN] MDT device
* \param cb [IN] llog callback funtion
* \param data [IN] llog callback data
* \param start_cat_idx first catalog index to examine
* \param start_rec_idx first record index to examine
* \retval 0 success
* \retval -ve failure
*/
int cdt_llog_process(const struct lu_env *env, struct mdt_device *mdt,
llog_cb_t cb, void *data, u32 start_cat_idx,
u32 start_rec_idx)
{
struct obd_device *obd = mdt2obd_dev(mdt);
struct llog_ctxt *lctxt = NULL;
int rc;
ENTRY;
lctxt = llog_get_context(obd, LLOG_AGENT_ORIG_CTXT);
if (lctxt == NULL || lctxt->loc_handle == NULL)
RETURN(-ENOENT);
rc = llog_cat_process(env, lctxt->loc_handle, cb, data, start_cat_idx,
start_rec_idx);
if (rc < 0)
CERROR("%s: failed to process HSM_ACTIONS llog (rc=%d)\n",
mdt_obd_name(mdt), rc);
else
rc = 0;
llog_ctxt_put(lctxt);
RETURN(rc);
}
/*
* hsm_last_cookie_cb() - find last used cookie.
* @env: Lustre environment
* @llh: llog handle
* @hdr: llog record
* @data: cb data = coordinator [in, out]
*
* llog_cat_process() callback, used to find last used cookie.
* The processing ends at the first non-cancel record.
*
* Return:
* * %0 success
* * %negative failure
*/
static int hsm_last_cookie_cb(const struct lu_env *env, struct llog_handle *llh,
struct llog_rec_hdr *hdr, void *data)
{
struct llog_agent_req_rec *larr = (struct llog_agent_req_rec *)hdr;
struct hsm_action_item *hai = &larr->arr_hai;
struct coordinator *cdt = data;
/* do not stop on cancel, it takes cookie from other request */
if (hai->hai_action == HSMA_CANCEL)
RETURN(0);
if (hai->hai_cookie > atomic64_read(&cdt->cdt_last_cookie))
atomic64_set(&cdt->cdt_last_cookie, hai->hai_cookie);
RETURN(LLOG_PROC_BREAK);
}
/*
* cdt_update_last_cookie() - Update the last cookie used by a request.
* @env: Lustre environment
* @lctxt: llog context handle
* @coordinator: pointer to struct coordinator (coordinator state)
*/
static int cdt_update_last_cookie(const struct lu_env *env,
struct llog_ctxt *lctxt,
struct coordinator *cdt)
{
int rc;
rc = llog_cat_reverse_process(env, lctxt->loc_handle,
hsm_last_cookie_cb, cdt);
if (rc < 0) {
CERROR("%s: failed to process HSM_ACTIONS llog: rc = %d\n",
lctxt->loc_obd->obd_name, rc);
RETURN(rc);
}
/* no pending request found -> start a new session */
if (!atomic64_read(&cdt->cdt_last_cookie))
atomic64_set(&cdt->cdt_last_cookie, ktime_get_real_seconds());
RETURN(0);
}
/**
* mdt_agent_record_add() - add an entry in agent llog
* @env: Lustre environment
* @mdt: MDT device
* @archive_id: backend archive number
* @flags: Request flags
* @hai: record to register
*
* Return:
* * %0 success
* * %negative failure
*/
int mdt_agent_record_add(const struct lu_env *env, struct mdt_device *mdt,
__u32 archive_id, __u64 flags,
struct hsm_action_item *hai)
{
struct obd_device *obd = mdt2obd_dev(mdt);
struct coordinator *cdt = &mdt->mdt_coordinator;
struct llog_ctxt *lctxt = NULL;
struct llog_agent_req_rec *larr;
int rc;
int sz;
ENTRY;
sz = llog_data_len(sizeof(*larr) + hai->hai_len - sizeof(*hai));
OBD_ALLOC(larr, sz);
if (!larr)
RETURN(-ENOMEM);
larr->arr_hdr.lrh_len = sz;
larr->arr_hdr.lrh_type = HSM_AGENT_REC;
larr->arr_status = ARS_WAITING;
larr->arr_archive_id = archive_id;
larr->arr_flags = flags;
larr->arr_req_create = ktime_get_real_seconds();
larr->arr_req_change = larr->arr_req_create;
memcpy(&larr->arr_hai, hai, hai->hai_len);
lctxt = llog_get_context(obd, LLOG_AGENT_ORIG_CTXT);
if (lctxt == NULL || lctxt->loc_handle == NULL)
GOTO(free, rc = -ENOENT);
/* If cdt_last_cookie is not set, try to initialize it.
* This is used by RAoLU with non-started coordinator.
*/
if (unlikely(!atomic64_read(&cdt->cdt_last_cookie))) {
rc = cdt_update_last_cookie(env, lctxt, cdt);
if (rc < 0)
GOTO(putctxt, rc);
}
/* in case of cancel request, the cookie is already set to the
* value of the request cookie to be cancelled
* so we do not change it */
if (hai->hai_action == HSMA_CANCEL)
larr->arr_hai.hai_cookie = hai->hai_cookie;
else
larr->arr_hai.hai_cookie =
atomic64_inc_return(&cdt->cdt_last_cookie);
rc = llog_cat_add(env, lctxt->loc_handle, &larr->arr_hdr, NULL);
if (rc > 0)
rc = 0;
putctxt:
llog_ctxt_put(lctxt);
CDEBUG(D_TRACE,
"%s: HSM added record idx %d "DFID" action %s: rc = %d\n",
mdt_obd_name(mdt), larr->arr_hdr.lrh_index, PFID(&hai->hai_fid),
hsm_copytool_action2name(hai->hai_action), rc);
EXIT;
free:
OBD_FREE(larr, sz);
return rc;
}
/*
* Agent actions /proc seq_file methods
* As llog processing uses a callback for each entry, we cannot do a sequential
* read. To limit calls to llog_cat_process (it spawns a thread), we fill
* multiple record in seq_file buffer in one show call.
* op->start() sets the iterator up and returns the first element of sequence
* op->stop() shuts it down.
* op->show() iterate llog and print element into the buffer.
* In case of error ->start() and ->next() return ERR_PTR(error)
* In the end of sequence they return %NULL
* op->show() returns 0 in case of success and negative number in case of error.
*
*/
/* seq_file iterator for agent_action entry */
#define AGENT_ACTIONS_IT_MAGIC 0x19660426
struct agent_action_iterator {
int aai_magic; /**< magic number */
bool aai_eof; /**< all done */
struct lu_env aai_env; /**< lustre env for llog */
struct mdt_device *aai_mdt; /**< metadata device */
struct llog_ctxt *aai_ctxt; /**< llog context */
int aai_cat_index; /**< cata idx already shown */
int aai_index; /**< idx in cata shown */
};
/*
* seq_file method called to start access to /proc file
* get llog context + llog handle
*/
static void *mdt_hsm_actions_debugfs_start(struct seq_file *s, loff_t *pos)
{
struct agent_action_iterator *aai = s->private;
ENTRY;
LASSERTF(aai->aai_magic == AGENT_ACTIONS_IT_MAGIC, "%08X\n",
aai->aai_magic);
aai->aai_ctxt = llog_get_context(mdt2obd_dev(aai->aai_mdt),
LLOG_AGENT_ORIG_CTXT);
if (aai->aai_ctxt == NULL || aai->aai_ctxt->loc_handle == NULL) {
CERROR("llog_get_context() failed\n");
RETURN(ERR_PTR(-ENOENT));
}
CDEBUG(D_HSM, "llog successfully initialized, start from %lld\n",
*pos);
/* first call = rewind */
if (*pos == 0) {
aai->aai_cat_index = 0;
aai->aai_index = 0;
aai->aai_eof = false;
}
if (aai->aai_eof)
RETURN(NULL);
RETURN(aai);
}
static void *mdt_hsm_actions_debugfs_next(struct seq_file *s, void *v,
loff_t *pos)
{
struct agent_action_iterator *aai = s->private;
(*pos)++;
if (aai->aai_eof)
RETURN(NULL);
RETURN(aai);
}
/*
* llog_cat_process() callback, used to fill a seq_file buffer
*/
static int hsm_actions_show_cb(const struct lu_env *env,
struct llog_handle *llh,
struct llog_rec_hdr *hdr,
void *data)
{
struct llog_agent_req_rec *larr = (struct llog_agent_req_rec *)hdr;
struct seq_file *s = data;
struct agent_action_iterator *aai = s->private;
int sz;
char buf[12];
ENTRY;
LASSERTF(aai->aai_magic == AGENT_ACTIONS_IT_MAGIC, "%08X\n",
aai->aai_magic);
/* if rec already printed => skip */
if (unlikely(llh->lgh_hdr->llh_cat_idx < aai->aai_cat_index))
RETURN(0);
if (unlikely(llh->lgh_hdr->llh_cat_idx == aai->aai_cat_index &&
hdr->lrh_index <= aai->aai_index))
RETURN(0);
sz = larr->arr_hai.hai_len - sizeof(larr->arr_hai);
seq_printf(s, "lrh=[type=%X len=%d idx=%d/%d] fid="DFID
" dfid="DFID" compound/cookie=%#llx/%#llx"
" action=%s archive#=%d flags=%#llx"
" extent=%#llx-%#llx"
" gid=%#llx datalen=%d status=%s data=[%s]\n",
hdr->lrh_type, hdr->lrh_len,
llh->lgh_hdr->llh_cat_idx, hdr->lrh_index,
PFID(&larr->arr_hai.hai_fid),
PFID(&larr->arr_hai.hai_dfid),
0ULL /* compound_id */, larr->arr_hai.hai_cookie,
hsm_copytool_action2name(larr->arr_hai.hai_action),
larr->arr_archive_id,
larr->arr_flags,
larr->arr_hai.hai_extent.offset,
larr->arr_hai.hai_extent.length,
larr->arr_hai.hai_gid, sz,
agent_req_status2name(larr->arr_status),
hai_dump_data_field(&larr->arr_hai, buf, sizeof(buf)));
aai->aai_cat_index = llh->lgh_hdr->llh_cat_idx;
aai->aai_index = hdr->lrh_index;
RETURN(0);
}
/*
* mdt_hsm_actions_debugfs_show() is called at for each seq record
* process the llog, with a cb which fill the file_seq buffer
* to be faster, one show will fill multiple records
*/
static int mdt_hsm_actions_debugfs_show(struct seq_file *s, void *v)
{
struct agent_action_iterator *aai = s->private;
int rc;
ENTRY;
LASSERTF(aai->aai_magic == AGENT_ACTIONS_IT_MAGIC, "%08X\n",
aai->aai_magic);
CDEBUG(D_HSM, "show from cat %d index %d eof=%d\n",
aai->aai_cat_index, aai->aai_index, aai->aai_eof);
if (aai->aai_eof)
RETURN(0);
rc = llog_cat_process(&aai->aai_env, aai->aai_ctxt->loc_handle,
hsm_actions_show_cb, s,
aai->aai_cat_index, aai->aai_index);
if (rc == 0) /* all llog parsed */
aai->aai_eof = true;
if (rc == LLOG_PROC_BREAK) /* buffer full */
rc = 0;
RETURN(rc);
}
/*
* seq_file method called to stop access to /proc file
* clean + put llog context
*/
static void mdt_hsm_actions_debugfs_stop(struct seq_file *s, void *v)
{
struct agent_action_iterator *aai = s->private;
ENTRY;
LASSERTF(aai->aai_magic == AGENT_ACTIONS_IT_MAGIC, "%08X\n",
aai->aai_magic);
if (aai->aai_ctxt)
llog_ctxt_put(aai->aai_ctxt);
EXIT;
}
static const struct seq_operations mdt_hsm_actions_debugfs_ops = {
.start = mdt_hsm_actions_debugfs_start,
.next = mdt_hsm_actions_debugfs_next,
.show = mdt_hsm_actions_debugfs_show,
.stop = mdt_hsm_actions_debugfs_stop,
};
static int ldebugfs_open_hsm_actions(struct inode *inode, struct file *file)
{
struct agent_action_iterator *aai;
struct seq_file *s;
int rc;
struct mdt_device *mdt;
ENTRY;
rc = seq_open(file, &mdt_hsm_actions_debugfs_ops);
if (rc)
RETURN(rc);
OBD_ALLOC_PTR(aai);
if (aai == NULL)
GOTO(err, rc = -ENOMEM);
aai->aai_magic = AGENT_ACTIONS_IT_MAGIC;
rc = lu_env_init(&aai->aai_env, LCT_LOCAL);
if (rc)
GOTO(err, rc);
/* mdt is saved in seq_file->data by
* mdt_coordinator_tunables_init() calling
* debugfs_register()
*/
mdt = inode->i_private;
aai->aai_mdt = mdt;
s = file->private_data;
s->private = aai;
GOTO(out, rc = 0);
err:
seq_release(inode, file);
if (aai && aai->aai_env.le_ses)
OBD_FREE_PTR(aai->aai_env.le_ses);
OBD_FREE_PTR(aai);
out:
return rc;
}
/*
* ldebugfs_release_hsm_actions() is called at end of /proc access.
* It frees allocated resources and calls cleanup lprocfs methods.
*/
static int ldebugfs_release_hsm_actions(struct inode *inode, struct file *file)
{
struct seq_file *seq = file->private_data;
struct agent_action_iterator *aai = seq->private;
if (aai) {
lu_env_fini(&aai->aai_env);
OBD_FREE_PTR(aai);
}
return seq_release(inode, file);
}
/* Methods to access HSM action list LLOG through /proc */
const struct file_operations mdt_hsm_actions_fops = {
.owner = THIS_MODULE,
.open = ldebugfs_open_hsm_actions,
.read = seq_read,
.llseek = seq_lseek,
.release = ldebugfs_release_hsm_actions,
};