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 <libcfs/libcfs.h>
40 #include <libcfs/libcfs_hash.h>
41 #include <obd_support.h>
42 #include <lustre_export.h>
44 #include <lprocfs_status.h>
45 #include <lustre_log.h>
46 #include "mdt_internal.h"
48 struct cdt_agent_record_loc {
49 struct hlist_node carl_hnode;
50 atomic_t carl_refcount;
56 static inline void cdt_agent_record_loc_get(struct cdt_agent_record_loc *carl)
58 LASSERT(atomic_read(&carl->carl_refcount) > 0);
59 atomic_inc(&carl->carl_refcount);
62 static inline void cdt_agent_record_loc_put(struct cdt_agent_record_loc *carl)
64 LASSERT(atomic_read(&carl->carl_refcount) > 0);
65 if (atomic_dec_and_test(&carl->carl_refcount))
70 cdt_agent_record_hash(struct cfs_hash *hs, const void *key, unsigned int mask)
72 return cfs_hash_djb2_hash(key, sizeof(u64), mask);
75 static void *cdt_agent_record_object(struct hlist_node *hnode)
77 return hlist_entry(hnode, struct cdt_agent_record_loc, carl_hnode);
80 static void *cdt_agent_record_key(struct hlist_node *hnode)
82 struct cdt_agent_record_loc *carl = cdt_agent_record_object(hnode);
84 return &carl->carl_cookie;
87 static int cdt_agent_record_keycmp(const void *key, struct hlist_node *hnode)
89 const u64 *cookie2 = cdt_agent_record_key(hnode);
91 return *(const u64 *)key == *cookie2;
94 static void cdt_agent_record_get(struct cfs_hash *hs, struct hlist_node *hnode)
96 struct cdt_agent_record_loc *carl = cdt_agent_record_object(hnode);
98 cdt_agent_record_loc_get(carl);
101 static void cdt_agent_record_put(struct cfs_hash *hs, struct hlist_node *hnode)
103 struct cdt_agent_record_loc *carl = cdt_agent_record_object(hnode);
105 cdt_agent_record_loc_put(carl);
108 struct cfs_hash_ops cdt_agent_record_hash_ops = {
109 .hs_hash = cdt_agent_record_hash,
110 .hs_key = cdt_agent_record_key,
111 .hs_keycmp = cdt_agent_record_keycmp,
112 .hs_object = cdt_agent_record_object,
113 .hs_get = cdt_agent_record_get,
114 .hs_put_locked = cdt_agent_record_put,
117 void cdt_agent_record_hash_add(struct coordinator *cdt, u64 cookie, u32 cat_idx,
120 struct cdt_agent_record_loc *carl0;
121 struct cdt_agent_record_loc *carl1;
123 OBD_ALLOC_PTR(carl1);
127 INIT_HLIST_NODE(&carl1->carl_hnode);
128 atomic_set(&carl1->carl_refcount, 1);
129 carl1->carl_cookie = cookie;
130 carl1->carl_cat_idx = cat_idx;
131 carl1->carl_rec_idx = rec_idx;
133 carl0 = cfs_hash_findadd_unique(cdt->cdt_agent_record_hash,
137 LASSERT(carl0->carl_cookie == carl1->carl_cookie);
138 LASSERT(carl0->carl_cat_idx == carl1->carl_cat_idx);
139 LASSERT(carl0->carl_rec_idx == carl1->carl_rec_idx);
142 cdt_agent_record_loc_put(carl0);
144 cdt_agent_record_loc_put(carl1);
147 void cdt_agent_record_hash_lookup(struct coordinator *cdt, u64 cookie,
148 u32 *cat_idx, u32 *rec_idx)
150 struct cdt_agent_record_loc *carl;
152 carl = cfs_hash_lookup(cdt->cdt_agent_record_hash, &cookie);
154 LASSERT(carl->carl_cookie == cookie);
155 *cat_idx = carl->carl_cat_idx;
156 *rec_idx = carl->carl_rec_idx;
157 cdt_agent_record_loc_put(carl);
164 void cdt_agent_record_hash_del(struct coordinator *cdt, u64 cookie)
166 cfs_hash_del_key(cdt->cdt_agent_record_hash, &cookie);
169 void dump_llog_agent_req_rec(const char *prefix,
170 const struct llog_agent_req_rec *larr)
175 sz = larr->arr_hai.hai_len - sizeof(larr->arr_hai);
176 CDEBUG(D_HSM, "%slrh=[type=%X len=%d idx=%d] fid="DFID
178 " compound/cookie=%#llx/%#llx"
179 " status=%s action=%s archive#=%d flags=%#llx"
180 " create=%llu change=%llu"
181 " extent=%#llx-%#llx gid=%#llx datalen=%d"
184 larr->arr_hdr.lrh_type,
185 larr->arr_hdr.lrh_len, larr->arr_hdr.lrh_index,
186 PFID(&larr->arr_hai.hai_fid),
187 PFID(&larr->arr_hai.hai_dfid),
188 larr->arr_compound_id, larr->arr_hai.hai_cookie,
189 agent_req_status2name(larr->arr_status),
190 hsm_copytool_action2name(larr->arr_hai.hai_action),
191 larr->arr_archive_id,
193 larr->arr_req_create, larr->arr_req_change,
194 larr->arr_hai.hai_extent.offset,
195 larr->arr_hai.hai_extent.length,
196 larr->arr_hai.hai_gid, sz,
197 hai_dump_data_field(&larr->arr_hai, buf, sizeof(buf)));
201 * process the actions llog
202 * \param env [IN] environment
203 * \param mdt [IN] MDT device
204 * \param cb [IN] llog callback funtion
205 * \param data [IN] llog callback data
206 * \param rw [IN] cdt_llog_lock mode (READ or WRITE)
207 * \param start_cat_idx first catalog index to examine
208 * \param start_rec_idx first record index to examine
210 * \retval -ve failure
212 int cdt_llog_process(const struct lu_env *env, struct mdt_device *mdt,
213 llog_cb_t cb, void *data, u32 start_cat_idx,
214 u32 start_rec_idx, int rw)
216 struct obd_device *obd = mdt2obd_dev(mdt);
217 struct llog_ctxt *lctxt = NULL;
218 struct coordinator *cdt = &mdt->mdt_coordinator;
222 lctxt = llog_get_context(obd, LLOG_AGENT_ORIG_CTXT);
223 if (lctxt == NULL || lctxt->loc_handle == NULL)
227 down_read(&cdt->cdt_llog_lock);
229 down_write(&cdt->cdt_llog_lock);
231 rc = llog_cat_process(env, lctxt->loc_handle, cb, data, start_cat_idx,
234 CERROR("%s: failed to process HSM_ACTIONS llog (rc=%d)\n",
235 mdt_obd_name(mdt), rc);
239 llog_ctxt_put(lctxt);
242 up_read(&cdt->cdt_llog_lock);
244 up_write(&cdt->cdt_llog_lock);
250 * add an entry in agent llog
251 * \param env [IN] environment
252 * \param mdt [IN] PDT device
253 * \param compound_id [IN] global id associated with the record
254 * \param archive_id [IN] backend archive number
255 * \param hai [IN] record to register
257 * \retval -ve failure
259 int mdt_agent_record_add(const struct lu_env *env,
260 struct mdt_device *mdt,
261 __u64 compound_id, __u32 archive_id,
262 __u64 flags, struct hsm_action_item *hai)
264 struct obd_device *obd = mdt2obd_dev(mdt);
265 struct coordinator *cdt = &mdt->mdt_coordinator;
266 struct llog_ctxt *lctxt = NULL;
267 struct llog_agent_req_rec *larr;
272 sz = llog_data_len(sizeof(*larr) + hai->hai_len - sizeof(*hai));
276 larr->arr_hdr.lrh_len = sz;
277 larr->arr_hdr.lrh_type = HSM_AGENT_REC;
278 larr->arr_status = ARS_WAITING;
279 larr->arr_compound_id = compound_id;
280 larr->arr_archive_id = archive_id;
281 larr->arr_flags = flags;
282 larr->arr_req_create = ktime_get_real_seconds();
283 larr->arr_req_change = larr->arr_req_create;
284 memcpy(&larr->arr_hai, hai, hai->hai_len);
286 lctxt = llog_get_context(obd, LLOG_AGENT_ORIG_CTXT);
287 if (lctxt == NULL || lctxt->loc_handle == NULL)
288 GOTO(free, rc = -ENOENT);
290 down_write(&cdt->cdt_llog_lock);
292 /* in case of cancel request, the cookie is already set to the
293 * value of the request cookie to be cancelled
294 * so we do not change it */
295 if (hai->hai_action == HSMA_CANCEL) {
296 larr->arr_hai.hai_cookie = hai->hai_cookie;
298 cdt->cdt_last_cookie++;
299 larr->arr_hai.hai_cookie = cdt->cdt_last_cookie;
302 rc = llog_cat_add(env, lctxt->loc_handle, &larr->arr_hdr, NULL);
306 up_write(&cdt->cdt_llog_lock);
307 llog_ctxt_put(lctxt);
316 * data passed to llog_cat_process() callback
319 struct data_update_cb {
320 struct mdt_device *mdt;
321 struct hsm_record_update *updates;
322 unsigned int updates_count;
323 unsigned int updates_done;
324 time64_t change_time;
328 * llog_cat_process() callback, used to update a record
329 * \param env [IN] environment
330 * \param llh [IN] llog handle
331 * \param hdr [IN] llog record
332 * \param data [IN] cb data = data_update_cb
334 * \retval -ve failure
336 static int mdt_agent_record_update_cb(const struct lu_env *env,
337 struct llog_handle *llh,
338 struct llog_rec_hdr *hdr,
341 struct llog_agent_req_rec *larr;
342 struct data_update_cb *ducb;
346 larr = (struct llog_agent_req_rec *)hdr;
349 /* check if all done */
350 if (ducb->updates_count == ducb->updates_done)
351 RETURN(LLOG_PROC_BREAK);
353 /* if record is in final state, never change */
354 if (agent_req_in_final_state(larr->arr_status))
358 for (i = 0 ; i < ducb->updates_count ; i++) {
359 struct hsm_record_update *update = &ducb->updates[i];
361 CDEBUG(D_HSM, "%s: search %#llx, found %#llx\n",
362 mdt_obd_name(ducb->mdt), update->cookie,
363 larr->arr_hai.hai_cookie);
364 if (larr->arr_hai.hai_cookie == update->cookie) {
366 /* If record is a cancel request, it cannot be
367 * canceled. This is to manage the following
368 * case: when a request is canceled, we have 2
369 * records with the the same cookie: the one
370 * to cancel and the cancel request the 1st
371 * has to be set to ARS_CANCELED and the 2nd
374 if (larr->arr_hai.hai_action == HSMA_CANCEL &&
375 update->status == ARS_CANCELED)
378 larr->arr_status = update->status;
379 larr->arr_req_change = ducb->change_time;
380 rc = llog_write(env, llh, hdr, hdr->lrh_index);
381 ducb->updates_done++;
387 CERROR("%s: mdt_agent_llog_update_rec() failed, rc = %d\n",
388 mdt_obd_name(ducb->mdt), rc);
394 * update an entry in agent llog
396 * \param env [IN] environment
397 * \param mdt [IN] MDT device
398 * \param updates [IN] array of entries to update
399 * \param updates_count [IN] number of entries in updates
401 * \retval 0 on success
402 * \retval negative on failure
404 int mdt_agent_record_update(const struct lu_env *env, struct mdt_device *mdt,
405 struct hsm_record_update *updates,
406 unsigned int updates_count)
408 struct data_update_cb ducb;
409 u32 start_cat_idx = -1;
410 u32 start_rec_idx = -1;
417 /* Find the first location (start_cat_idx, start_rec_idx)
418 * among the records corresponding to cookies. */
419 for (i = 0; i < updates_count; i++) {
420 /* If we cannot find a cached location for a cookie
421 * (perhaps because the MDT was restart then we must
422 * start from the beginning. In this case
423 * mdt_agent_record_hash_get() sets both of cat_idx and
425 cdt_agent_record_hash_lookup(&mdt->mdt_coordinator,
428 if (cat_idx < start_cat_idx) {
429 start_cat_idx = cat_idx;
430 start_rec_idx = rec_idx;
431 } else if (cat_idx == start_cat_idx &&
432 rec_idx < start_rec_idx) {
433 start_rec_idx = rec_idx;
437 /* Fixup starting record index for llog_cat_process(). */
438 if (start_rec_idx != 0)
442 ducb.updates = updates;
443 ducb.updates_count = updates_count;
444 ducb.updates_done = 0;
445 ducb.change_time = ktime_get_real_seconds();
447 rc = cdt_llog_process(env, mdt, mdt_agent_record_update_cb, &ducb,
448 start_cat_idx, start_rec_idx, WRITE);
450 CERROR("%s: cdt_llog_process() failed, rc=%d, cannot update "
451 "status for %u cookies, done %u\n",
452 mdt_obd_name(mdt), rc,
453 updates_count, ducb.updates_done);
458 * Agent actions /proc seq_file methods
459 * As llog processing uses a callback for each entry, we cannot do a sequential
460 * read. To limit calls to llog_cat_process (it spawns a thread), we fill
461 * multiple record in seq_file buffer in one show call.
462 * op->start() sets the iterator up and returns the first element of sequence
463 * op->stop() shuts it down.
464 * op->show() iterate llog and print element into the buffer.
465 * In case of error ->start() and ->next() return ERR_PTR(error)
466 * In the end of sequence they return %NULL
467 * op->show() returns 0 in case of success and negative number in case of error.
471 * seq_file iterator for agent_action entry
473 #define AGENT_ACTIONS_IT_MAGIC 0x19660426
474 struct agent_action_iterator {
475 int aai_magic; /**< magic number */
476 bool aai_eof; /**< all done */
477 struct lu_env aai_env; /**< lustre env for llog */
478 struct mdt_device *aai_mdt; /**< metadata device */
479 struct llog_ctxt *aai_ctxt; /**< llog context */
480 int aai_cat_index; /**< cata idx already shown */
481 int aai_index; /**< idx in cata shown */
485 * seq_file method called to start access to /proc file
486 * get llog context + llog handle
488 static void *mdt_hsm_actions_proc_start(struct seq_file *s, loff_t *pos)
490 struct agent_action_iterator *aai = s->private;
493 LASSERTF(aai->aai_magic == AGENT_ACTIONS_IT_MAGIC, "%08X\n",
496 aai->aai_ctxt = llog_get_context(mdt2obd_dev(aai->aai_mdt),
497 LLOG_AGENT_ORIG_CTXT);
498 if (aai->aai_ctxt == NULL || aai->aai_ctxt->loc_handle == NULL) {
499 CERROR("llog_get_context() failed\n");
500 RETURN(ERR_PTR(-ENOENT));
503 CDEBUG(D_HSM, "llog successfully initialized, start from %lld\n",
505 /* first call = rewind */
507 aai->aai_cat_index = 0;
509 aai->aai_eof = false;
519 static void *mdt_hsm_actions_proc_next(struct seq_file *s, void *v,
526 * llog_cat_process() callback, used to fill a seq_file buffer
528 static int hsm_actions_show_cb(const struct lu_env *env,
529 struct llog_handle *llh,
530 struct llog_rec_hdr *hdr,
533 struct llog_agent_req_rec *larr = (struct llog_agent_req_rec *)hdr;
534 struct seq_file *s = data;
535 struct agent_action_iterator *aai;
541 LASSERTF(aai->aai_magic == AGENT_ACTIONS_IT_MAGIC, "%08X\n",
544 /* if rec already printed => skip */
545 if (unlikely(llh->lgh_hdr->llh_cat_idx < aai->aai_cat_index))
548 if (unlikely(llh->lgh_hdr->llh_cat_idx == aai->aai_cat_index &&
549 hdr->lrh_index <= aai->aai_index))
552 sz = larr->arr_hai.hai_len - sizeof(larr->arr_hai);
553 seq_printf(s, "lrh=[type=%X len=%d idx=%d/%d] fid="DFID
554 " dfid="DFID" compound/cookie=%#llx/%#llx"
555 " action=%s archive#=%d flags=%#llx"
556 " extent=%#llx-%#llx"
557 " gid=%#llx datalen=%d status=%s data=[%s]\n",
558 hdr->lrh_type, hdr->lrh_len,
559 llh->lgh_hdr->llh_cat_idx, hdr->lrh_index,
560 PFID(&larr->arr_hai.hai_fid),
561 PFID(&larr->arr_hai.hai_dfid),
562 larr->arr_compound_id, larr->arr_hai.hai_cookie,
563 hsm_copytool_action2name(larr->arr_hai.hai_action),
564 larr->arr_archive_id,
566 larr->arr_hai.hai_extent.offset,
567 larr->arr_hai.hai_extent.length,
568 larr->arr_hai.hai_gid, sz,
569 agent_req_status2name(larr->arr_status),
570 hai_dump_data_field(&larr->arr_hai, buf, sizeof(buf)));
572 aai->aai_cat_index = llh->lgh_hdr->llh_cat_idx;
573 aai->aai_index = hdr->lrh_index;
579 * mdt_hsm_actions_proc_show() is called at for each seq record
580 * process the llog, with a cb which fill the file_seq buffer
581 * to be faster, one show will fill multiple records
583 static int mdt_hsm_actions_proc_show(struct seq_file *s, void *v)
585 struct agent_action_iterator *aai = s->private;
586 struct coordinator *cdt = &aai->aai_mdt->mdt_coordinator;
590 LASSERTF(aai->aai_magic == AGENT_ACTIONS_IT_MAGIC, "%08X\n",
593 CDEBUG(D_HSM, "show from cat %d index %d eof=%d\n",
594 aai->aai_cat_index, aai->aai_index, aai->aai_eof);
598 down_read(&cdt->cdt_llog_lock);
599 rc = llog_cat_process(&aai->aai_env, aai->aai_ctxt->loc_handle,
600 hsm_actions_show_cb, s,
601 aai->aai_cat_index, aai->aai_index);
602 up_read(&cdt->cdt_llog_lock);
603 if (rc == 0) /* all llog parsed */
605 if (rc == LLOG_PROC_BREAK) /* buffer full */
611 * seq_file method called to stop access to /proc file
612 * clean + put llog context
614 static void mdt_hsm_actions_proc_stop(struct seq_file *s, void *v)
616 struct agent_action_iterator *aai = s->private;
619 LASSERTF(aai->aai_magic == AGENT_ACTIONS_IT_MAGIC, "%08X\n",
623 llog_ctxt_put(aai->aai_ctxt);
629 static const struct seq_operations mdt_hsm_actions_proc_ops = {
630 .start = mdt_hsm_actions_proc_start,
631 .next = mdt_hsm_actions_proc_next,
632 .show = mdt_hsm_actions_proc_show,
633 .stop = mdt_hsm_actions_proc_stop,
636 static int lprocfs_open_hsm_actions(struct inode *inode, struct file *file)
638 struct agent_action_iterator *aai;
641 struct mdt_device *mdt;
644 rc = seq_open(file, &mdt_hsm_actions_proc_ops);
650 GOTO(err, rc = -ENOMEM);
652 aai->aai_magic = AGENT_ACTIONS_IT_MAGIC;
653 rc = lu_env_init(&aai->aai_env, LCT_LOCAL);
657 /* mdt is saved in proc_dir_entry->data by
658 * mdt_coordinator_procfs_init() calling lprocfs_register()
660 mdt = (struct mdt_device *)PDE_DATA(inode);
662 s = file->private_data;
668 lprocfs_seq_release(inode, file);
669 if (aai && aai->aai_env.le_ses)
670 OBD_FREE_PTR(aai->aai_env.le_ses);
678 * lprocfs_release_hsm_actions() is called at end of /proc access.
679 * It frees allocated resources and calls cleanup lprocfs methods.
681 static int lprocfs_release_hsm_actions(struct inode *inode, struct file *file)
683 struct seq_file *seq = file->private_data;
684 struct agent_action_iterator *aai = seq->private;
687 lu_env_fini(&aai->aai_env);
691 return lprocfs_seq_release(inode, file);
694 /* Methods to access HSM action list LLOG through /proc */
695 const struct file_operations mdt_hsm_actions_fops = {
696 .owner = THIS_MODULE,
697 .open = lprocfs_open_hsm_actions,
700 .release = lprocfs_release_hsm_actions,