4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 only,
8 * as published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License version 2 for more details. A copy is
14 * included in the COPYING file that accompanied this code.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 * (C) Copyright 2012 Commissariat a l'energie atomique et aux energies
26 * Copyright (c) 2013, 2016, Intel Corporation.
29 * lustre/mdt/mdt_hsm_cdt_actions.c
33 * Author: Jacques-Charles Lafoucriere <jacques-charles.lafoucriere@cea.fr>
34 * Author: Aurelien Degremont <aurelien.degremont@cea.fr>
37 #define DEBUG_SUBSYSTEM S_MDS
39 #include <obd_support.h>
40 #include <lustre_export.h>
42 #include <lprocfs_status.h>
43 #include <lustre_log.h>
44 #include "mdt_internal.h"
46 void dump_llog_agent_req_rec(const char *prefix,
47 const struct llog_agent_req_rec *larr)
52 sz = larr->arr_hai.hai_len - sizeof(larr->arr_hai);
53 CDEBUG(D_HSM, "%slrh=[type=%X len=%d idx=%d] fid="DFID
55 " compound/cookie=%#llx/%#llx"
56 " status=%s action=%s archive#=%d flags=%#llx"
57 " create=%llu change=%llu"
58 " extent=%#llx-%#llx gid=%#llx datalen=%d"
61 larr->arr_hdr.lrh_type,
62 larr->arr_hdr.lrh_len, larr->arr_hdr.lrh_index,
63 PFID(&larr->arr_hai.hai_fid),
64 PFID(&larr->arr_hai.hai_dfid),
65 larr->arr_compound_id, larr->arr_hai.hai_cookie,
66 agent_req_status2name(larr->arr_status),
67 hsm_copytool_action2name(larr->arr_hai.hai_action),
70 larr->arr_req_create, larr->arr_req_change,
71 larr->arr_hai.hai_extent.offset,
72 larr->arr_hai.hai_extent.length,
73 larr->arr_hai.hai_gid, sz,
74 hai_dump_data_field(&larr->arr_hai, buf, sizeof(buf)));
78 * process the actions llog
79 * \param env [IN] environment
80 * \param mdt [IN] MDT device
81 * \param cb [IN] llog callback funtion
82 * \param data [IN] llog callback data
83 * \param rw [IN] cdt_llog_lock mode (READ or WRITE)
87 int cdt_llog_process(const struct lu_env *env, struct mdt_device *mdt,
88 llog_cb_t cb, void *data, int rw)
90 struct obd_device *obd = mdt2obd_dev(mdt);
91 struct llog_ctxt *lctxt = NULL;
92 struct coordinator *cdt = &mdt->mdt_coordinator;
96 lctxt = llog_get_context(obd, LLOG_AGENT_ORIG_CTXT);
97 if (lctxt == NULL || lctxt->loc_handle == NULL)
101 down_read(&cdt->cdt_llog_lock);
103 down_write(&cdt->cdt_llog_lock);
105 rc = llog_cat_process(env, lctxt->loc_handle, cb, data, 0, 0);
107 CERROR("%s: failed to process HSM_ACTIONS llog (rc=%d)\n",
108 mdt_obd_name(mdt), rc);
112 llog_ctxt_put(lctxt);
115 up_read(&cdt->cdt_llog_lock);
117 up_write(&cdt->cdt_llog_lock);
123 * add an entry in agent llog
124 * \param env [IN] environment
125 * \param mdt [IN] PDT device
126 * \param compound_id [IN] global id associated with the record
127 * \param archive_id [IN] backend archive number
128 * \param hai [IN] record to register
130 * \retval -ve failure
132 int mdt_agent_record_add(const struct lu_env *env,
133 struct mdt_device *mdt,
134 __u64 compound_id, __u32 archive_id,
135 __u64 flags, struct hsm_action_item *hai)
137 struct obd_device *obd = mdt2obd_dev(mdt);
138 struct coordinator *cdt = &mdt->mdt_coordinator;
139 struct llog_ctxt *lctxt = NULL;
140 struct llog_agent_req_rec *larr;
145 sz = llog_data_len(sizeof(*larr) + hai->hai_len - sizeof(*hai));
149 larr->arr_hdr.lrh_len = sz;
150 larr->arr_hdr.lrh_type = HSM_AGENT_REC;
151 larr->arr_status = ARS_WAITING;
152 larr->arr_compound_id = compound_id;
153 larr->arr_archive_id = archive_id;
154 larr->arr_flags = flags;
155 larr->arr_req_create = cfs_time_current_sec();
156 larr->arr_req_change = larr->arr_req_create;
157 memcpy(&larr->arr_hai, hai, hai->hai_len);
159 lctxt = llog_get_context(obd, LLOG_AGENT_ORIG_CTXT);
160 if (lctxt == NULL || lctxt->loc_handle == NULL)
161 GOTO(free, rc = -ENOENT);
163 down_write(&cdt->cdt_llog_lock);
165 /* in case of cancel request, the cookie is already set to the
166 * value of the request cookie to be cancelled
167 * so we do not change it */
168 if (hai->hai_action == HSMA_CANCEL) {
169 larr->arr_hai.hai_cookie = hai->hai_cookie;
171 cdt->cdt_last_cookie++;
172 larr->arr_hai.hai_cookie = cdt->cdt_last_cookie;
175 rc = llog_cat_add(env, lctxt->loc_handle, &larr->arr_hdr, NULL);
179 up_write(&cdt->cdt_llog_lock);
180 llog_ctxt_put(lctxt);
189 * data passed to llog_cat_process() callback
192 struct data_update_cb {
193 struct mdt_device *mdt;
197 enum agent_req_status status;
198 cfs_time_t change_time;
202 * llog_cat_process() callback, used to update a record
203 * \param env [IN] environment
204 * \param llh [IN] llog handle
205 * \param hdr [IN] llog record
206 * \param data [IN] cb data = data_update_cb
208 * \retval -ve failure
210 static int mdt_agent_record_update_cb(const struct lu_env *env,
211 struct llog_handle *llh,
212 struct llog_rec_hdr *hdr,
215 struct llog_agent_req_rec *larr;
216 struct data_update_cb *ducb;
220 larr = (struct llog_agent_req_rec *)hdr;
223 /* check if all done */
224 if (ducb->cookies_count == ducb->cookies_done)
225 RETURN(LLOG_PROC_BREAK);
227 /* if record is in final state, never change */
228 /* if record is a cancel request, it cannot be canceled
229 * this is to manage the following case:
230 * when a request is canceled, we have 2 records with the
231 * the same cookie : the one to cancel and the cancel request
232 * the 1st has to be set to ARS_CANCELED and the 2nd to ARS_SUCCEED
234 if (agent_req_in_final_state(larr->arr_status) ||
235 (larr->arr_hai.hai_action == HSMA_CANCEL &&
236 ducb->status == ARS_CANCELED))
240 for (i = 0 ; i < ducb->cookies_count ; i++) {
241 CDEBUG(D_HSM, "%s: search %#llx, found %#llx\n",
242 mdt_obd_name(ducb->mdt), ducb->cookies[i],
243 larr->arr_hai.hai_cookie);
244 if (larr->arr_hai.hai_cookie == ducb->cookies[i]) {
246 larr->arr_status = ducb->status;
247 larr->arr_req_change = ducb->change_time;
248 rc = llog_write(env, llh, hdr, hdr->lrh_index);
249 ducb->cookies_done++;
255 CERROR("%s: mdt_agent_llog_update_rec() failed, rc = %d\n",
256 mdt_obd_name(ducb->mdt), rc);
262 * update an entry in agent llog
263 * \param env [IN] environment
264 * \param mdt [IN] MDT device
265 * \param cookie [IN] entries to update
266 * log cookie are returned by register
267 * \param status [IN] new status of the request
269 * \retval -ve failure
271 int mdt_agent_record_update(const struct lu_env *env, struct mdt_device *mdt,
272 __u64 *cookies, int cookies_count,
273 enum agent_req_status status)
275 struct data_update_cb ducb;
280 ducb.cookies = cookies;
281 ducb.cookies_count = cookies_count;
282 ducb.cookies_done = 0;
283 ducb.status = status;
284 ducb.change_time = cfs_time_current_sec();
286 rc = cdt_llog_process(env, mdt, mdt_agent_record_update_cb, &ducb,
289 CERROR("%s: cdt_llog_process() failed, rc=%d, cannot update "
290 "status to %s for %d cookies, done %d\n",
291 mdt_obd_name(mdt), rc,
292 agent_req_status2name(status),
293 cookies_count, ducb.cookies_done);
298 * Agent actions /proc seq_file methods
299 * As llog processing uses a callback for each entry, we cannot do a sequential
300 * read. To limit calls to llog_cat_process (it spawns a thread), we fill
301 * multiple record in seq_file buffer in one show call.
302 * op->start() sets the iterator up and returns the first element of sequence
303 * op->stop() shuts it down.
304 * op->show() iterate llog and print element into the buffer.
305 * In case of error ->start() and ->next() return ERR_PTR(error)
306 * In the end of sequence they return %NULL
307 * op->show() returns 0 in case of success and negative number in case of error.
311 * seq_file iterator for agent_action entry
313 #define AGENT_ACTIONS_IT_MAGIC 0x19660426
314 struct agent_action_iterator {
315 int aai_magic; /**< magic number */
316 bool aai_eof; /**< all done */
317 struct lu_env aai_env; /**< lustre env for llog */
318 struct mdt_device *aai_mdt; /**< metadata device */
319 struct llog_ctxt *aai_ctxt; /**< llog context */
320 int aai_cat_index; /**< cata idx already shown */
321 int aai_index; /**< idx in cata shown */
325 * seq_file method called to start access to /proc file
326 * get llog context + llog handle
328 static void *mdt_hsm_actions_proc_start(struct seq_file *s, loff_t *pos)
330 struct agent_action_iterator *aai = s->private;
333 LASSERTF(aai->aai_magic == AGENT_ACTIONS_IT_MAGIC, "%08X\n",
336 aai->aai_ctxt = llog_get_context(mdt2obd_dev(aai->aai_mdt),
337 LLOG_AGENT_ORIG_CTXT);
338 if (aai->aai_ctxt == NULL || aai->aai_ctxt->loc_handle == NULL) {
339 CERROR("llog_get_context() failed\n");
340 RETURN(ERR_PTR(-ENOENT));
343 CDEBUG(D_HSM, "llog successfully initialized, start from %lld\n",
345 /* first call = rewind */
347 aai->aai_cat_index = 0;
349 aai->aai_eof = false;
359 static void *mdt_hsm_actions_proc_next(struct seq_file *s, void *v,
366 * llog_cat_process() callback, used to fill a seq_file buffer
368 static int hsm_actions_show_cb(const struct lu_env *env,
369 struct llog_handle *llh,
370 struct llog_rec_hdr *hdr,
373 struct llog_agent_req_rec *larr = (struct llog_agent_req_rec *)hdr;
374 struct seq_file *s = data;
375 struct agent_action_iterator *aai;
381 LASSERTF(aai->aai_magic == AGENT_ACTIONS_IT_MAGIC, "%08X\n",
384 /* if rec already printed => skip */
385 if (unlikely(llh->lgh_hdr->llh_cat_idx < aai->aai_cat_index))
388 if (unlikely(llh->lgh_hdr->llh_cat_idx == aai->aai_cat_index &&
389 hdr->lrh_index <= aai->aai_index))
392 sz = larr->arr_hai.hai_len - sizeof(larr->arr_hai);
393 seq_printf(s, "lrh=[type=%X len=%d idx=%d/%d] fid="DFID
394 " dfid="DFID" compound/cookie=%#llx/%#llx"
395 " action=%s archive#=%d flags=%#llx"
396 " extent=%#llx-%#llx"
397 " gid=%#llx datalen=%d status=%s data=[%s]\n",
398 hdr->lrh_type, hdr->lrh_len,
399 llh->lgh_hdr->llh_cat_idx, hdr->lrh_index,
400 PFID(&larr->arr_hai.hai_fid),
401 PFID(&larr->arr_hai.hai_dfid),
402 larr->arr_compound_id, larr->arr_hai.hai_cookie,
403 hsm_copytool_action2name(larr->arr_hai.hai_action),
404 larr->arr_archive_id,
406 larr->arr_hai.hai_extent.offset,
407 larr->arr_hai.hai_extent.length,
408 larr->arr_hai.hai_gid, sz,
409 agent_req_status2name(larr->arr_status),
410 hai_dump_data_field(&larr->arr_hai, buf, sizeof(buf)));
412 aai->aai_cat_index = llh->lgh_hdr->llh_cat_idx;
413 aai->aai_index = hdr->lrh_index;
419 * mdt_hsm_actions_proc_show() is called at for each seq record
420 * process the llog, with a cb which fill the file_seq buffer
421 * to be faster, one show will fill multiple records
423 static int mdt_hsm_actions_proc_show(struct seq_file *s, void *v)
425 struct agent_action_iterator *aai = s->private;
426 struct coordinator *cdt = &aai->aai_mdt->mdt_coordinator;
430 LASSERTF(aai->aai_magic == AGENT_ACTIONS_IT_MAGIC, "%08X\n",
433 CDEBUG(D_HSM, "show from cat %d index %d eof=%d\n",
434 aai->aai_cat_index, aai->aai_index, aai->aai_eof);
438 down_read(&cdt->cdt_llog_lock);
439 rc = llog_cat_process(&aai->aai_env, aai->aai_ctxt->loc_handle,
440 hsm_actions_show_cb, s,
441 aai->aai_cat_index, aai->aai_index);
442 up_read(&cdt->cdt_llog_lock);
443 if (rc == 0) /* all llog parsed */
445 if (rc == LLOG_PROC_BREAK) /* buffer full */
451 * seq_file method called to stop access to /proc file
452 * clean + put llog context
454 static void mdt_hsm_actions_proc_stop(struct seq_file *s, void *v)
456 struct agent_action_iterator *aai = s->private;
459 LASSERTF(aai->aai_magic == AGENT_ACTIONS_IT_MAGIC, "%08X\n",
463 llog_ctxt_put(aai->aai_ctxt);
469 static const struct seq_operations mdt_hsm_actions_proc_ops = {
470 .start = mdt_hsm_actions_proc_start,
471 .next = mdt_hsm_actions_proc_next,
472 .show = mdt_hsm_actions_proc_show,
473 .stop = mdt_hsm_actions_proc_stop,
476 static int lprocfs_open_hsm_actions(struct inode *inode, struct file *file)
478 struct agent_action_iterator *aai;
481 struct mdt_device *mdt;
484 rc = seq_open(file, &mdt_hsm_actions_proc_ops);
490 GOTO(err, rc = -ENOMEM);
492 aai->aai_magic = AGENT_ACTIONS_IT_MAGIC;
493 rc = lu_env_init(&aai->aai_env, LCT_LOCAL);
497 /* mdt is saved in proc_dir_entry->data by
498 * mdt_coordinator_procfs_init() calling lprocfs_register()
500 mdt = (struct mdt_device *)PDE_DATA(inode);
502 s = file->private_data;
508 lprocfs_seq_release(inode, file);
509 if (aai && aai->aai_env.le_ses)
510 OBD_FREE_PTR(aai->aai_env.le_ses);
518 * lprocfs_release_hsm_actions() is called at end of /proc access.
519 * It frees allocated resources and calls cleanup lprocfs methods.
521 static int lprocfs_release_hsm_actions(struct inode *inode, struct file *file)
523 struct seq_file *seq = file->private_data;
524 struct agent_action_iterator *aai = seq->private;
527 lu_env_fini(&aai->aai_env);
531 return lprocfs_seq_release(inode, file);
534 /* Methods to access HSM action list LLOG through /proc */
535 const struct file_operations mdt_hsm_actions_fops = {
536 .owner = THIS_MODULE,
537 .open = lprocfs_open_hsm_actions,
540 .release = lprocfs_release_hsm_actions,