Whamcloud - gitweb
LU-17888 osd-ldiskfs: osd_scrub_refresh_mapping deadlock
[fs/lustre-release.git] / lustre / mdt / mdt_hsm_cdt_actions.c
1 /*
2  * GPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
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.
9  *
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.
15  *
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
19  *
20  * GPL HEADER END
21  */
22 /*
23  * (C) Copyright 2012 Commissariat a l'energie atomique et aux energies
24  *     alternatives
25  *
26  * Copyright (c) 2013, 2017, Intel Corporation.
27  */
28 /*
29  * lustre/mdt/mdt_hsm_cdt_actions.c
30  *
31  * Lustre HSM
32  *
33  * Author: Jacques-Charles Lafoucriere <jacques-charles.lafoucriere@cea.fr>
34  * Author: Aurelien Degremont <aurelien.degremont@cea.fr>
35  */
36
37 #define DEBUG_SUBSYSTEM S_MDS
38
39 #include <libcfs/libcfs.h>
40 #include <libcfs/libcfs_hash.h>
41 #include <obd_support.h>
42 #include <lustre_export.h>
43 #include <obd.h>
44 #include <lprocfs_status.h>
45 #include <lustre_log.h>
46 #include "mdt_internal.h"
47
48 struct cdt_agent_record_loc {
49         struct hlist_node carl_hnode;
50         struct kref carl_refcount;
51         u64 carl_cookie;
52         u32 carl_cat_idx;
53         u32 carl_rec_idx;
54 };
55
56 static inline void cdt_agent_record_loc_get(struct cdt_agent_record_loc *carl)
57 {
58         kref_get(&carl->carl_refcount);
59 }
60
61 static void cdt_agent_record_loc_put_free(struct kref *kref)
62 {
63         struct cdt_agent_record_loc *carl;
64
65         carl = container_of(kref, struct cdt_agent_record_loc, carl_refcount);
66         OBD_FREE_PTR(carl);
67
68 }
69
70 static inline void cdt_agent_record_loc_put(struct cdt_agent_record_loc *carl)
71 {
72         kref_put(&carl->carl_refcount, cdt_agent_record_loc_put_free);
73 }
74
75 static unsigned int
76 cdt_agent_record_hash(struct cfs_hash *hs, const void *key,
77                       const unsigned int bits)
78 {
79         return cfs_hash_djb2_hash(key, sizeof(u64), bits);
80 }
81
82 static void *cdt_agent_record_object(struct hlist_node *hnode)
83 {
84         return hlist_entry(hnode, struct cdt_agent_record_loc, carl_hnode);
85 }
86
87 static void *cdt_agent_record_key(struct hlist_node *hnode)
88 {
89         struct cdt_agent_record_loc *carl = cdt_agent_record_object(hnode);
90
91         return &carl->carl_cookie;
92 }
93
94 static int cdt_agent_record_keycmp(const void *key, struct hlist_node *hnode)
95 {
96         const u64 *cookie2 = cdt_agent_record_key(hnode);
97
98         return *(const u64 *)key == *cookie2;
99 }
100
101 static void cdt_agent_record_get(struct cfs_hash *hs, struct hlist_node *hnode)
102 {
103         struct cdt_agent_record_loc *carl = cdt_agent_record_object(hnode);
104
105         cdt_agent_record_loc_get(carl);
106 }
107
108 static void cdt_agent_record_put(struct cfs_hash *hs, struct hlist_node *hnode)
109 {
110         struct cdt_agent_record_loc *carl = cdt_agent_record_object(hnode);
111
112         cdt_agent_record_loc_put(carl);
113 }
114
115 struct cfs_hash_ops cdt_agent_record_hash_ops = {
116         .hs_hash        = cdt_agent_record_hash,
117         .hs_key         = cdt_agent_record_key,
118         .hs_keycmp      = cdt_agent_record_keycmp,
119         .hs_object      = cdt_agent_record_object,
120         .hs_get         = cdt_agent_record_get,
121         .hs_put_locked  = cdt_agent_record_put,
122 };
123
124 void cdt_agent_record_hash_add(struct coordinator *cdt, u64 cookie, u32 cat_idx,
125                                u32 rec_idx)
126 {
127         struct cdt_agent_record_loc *carl0;
128         struct cdt_agent_record_loc *carl1;
129
130         OBD_ALLOC_PTR(carl1);
131         if (carl1 == NULL)
132                 return;
133
134         INIT_HLIST_NODE(&carl1->carl_hnode);
135         kref_init(&carl1->carl_refcount);
136         carl1->carl_cookie = cookie;
137         carl1->carl_cat_idx = cat_idx;
138         carl1->carl_rec_idx = rec_idx;
139
140         carl0 = cfs_hash_findadd_unique(cdt->cdt_agent_record_hash,
141                                         &carl1->carl_cookie,
142                                         &carl1->carl_hnode);
143
144         LASSERT(carl0->carl_cookie == carl1->carl_cookie);
145         LASSERT(carl0->carl_cat_idx == carl1->carl_cat_idx);
146         LASSERT(carl0->carl_rec_idx == carl1->carl_rec_idx);
147
148         if (carl0 != carl1)
149                 cdt_agent_record_loc_put(carl0);
150
151         cdt_agent_record_loc_put(carl1);
152 }
153
154 void cdt_agent_record_hash_lookup(struct coordinator *cdt, u64 cookie,
155                                   u32 *cat_idx, u32 *rec_idx)
156 {
157         struct cdt_agent_record_loc *carl;
158
159         carl = cfs_hash_lookup(cdt->cdt_agent_record_hash, &cookie);
160         if (carl != NULL) {
161                 LASSERT(carl->carl_cookie == cookie);
162                 *cat_idx = carl->carl_cat_idx;
163                 *rec_idx = carl->carl_rec_idx;
164                 cdt_agent_record_loc_put(carl);
165         } else {
166                 *cat_idx = 0;
167                 *rec_idx = 0;
168         }
169 }
170
171 void cdt_agent_record_hash_del(struct coordinator *cdt, u64 cookie)
172 {
173         cfs_hash_del_key(cdt->cdt_agent_record_hash, &cookie);
174 }
175
176 void dump_llog_agent_req_rec(const char *prefix,
177                              const struct llog_agent_req_rec *larr)
178 {
179         char    buf[12];
180         int     sz;
181
182         sz = larr->arr_hai.hai_len - sizeof(larr->arr_hai);
183         CDEBUG(D_HSM, "%slrh=[type=%X len=%d idx=%d] fid="DFID
184                " dfid="DFID
185                " cookie=%#llx"
186                " status=%s action=%s archive#=%d flags=%#llx"
187                " create=%llu change=%llu"
188                " extent=%#llx-%#llx gid=%#llx datalen=%d"
189                " data=[%s]\n",
190                prefix,
191                larr->arr_hdr.lrh_type,
192                larr->arr_hdr.lrh_len, larr->arr_hdr.lrh_index,
193                PFID(&larr->arr_hai.hai_fid),
194                PFID(&larr->arr_hai.hai_dfid),
195                larr->arr_hai.hai_cookie,
196                agent_req_status2name(larr->arr_status),
197                hsm_copytool_action2name(larr->arr_hai.hai_action),
198                larr->arr_archive_id,
199                larr->arr_flags,
200                larr->arr_req_create, larr->arr_req_change,
201                larr->arr_hai.hai_extent.offset,
202                larr->arr_hai.hai_extent.length,
203                larr->arr_hai.hai_gid, sz,
204                hai_dump_data_field(&larr->arr_hai, buf, sizeof(buf)));
205 }
206
207 /*
208  * process the actions llog
209  * \param env [IN] environment
210  * \param mdt [IN] MDT device
211  * \param cb [IN] llog callback funtion
212  * \param data [IN] llog callback  data
213  * \param rw [IN] cdt_llog_lock mode (READ or WRITE)
214  * \param start_cat_idx first catalog index to examine
215  * \param start_rec_idx first record index to examine
216  * \retval 0 success
217  * \retval -ve failure
218  */
219 int cdt_llog_process(const struct lu_env *env, struct mdt_device *mdt,
220                      llog_cb_t cb, void *data, u32 start_cat_idx,
221                      u32 start_rec_idx, int rw)
222 {
223         struct obd_device       *obd = mdt2obd_dev(mdt);
224         struct llog_ctxt        *lctxt = NULL;
225         struct coordinator      *cdt = &mdt->mdt_coordinator;
226         int                      rc;
227         ENTRY;
228
229         lctxt = llog_get_context(obd, LLOG_AGENT_ORIG_CTXT);
230         if (lctxt == NULL || lctxt->loc_handle == NULL)
231                 RETURN(-ENOENT);
232
233         if (rw == READ)
234                 down_read(&cdt->cdt_llog_lock);
235         else
236                 down_write(&cdt->cdt_llog_lock);
237
238         rc = llog_cat_process(env, lctxt->loc_handle, cb, data, start_cat_idx,
239                               start_rec_idx);
240         if (rc < 0)
241                 CERROR("%s: failed to process HSM_ACTIONS llog (rc=%d)\n",
242                         mdt_obd_name(mdt), rc);
243         else
244                 rc = 0;
245
246         llog_ctxt_put(lctxt);
247
248         if (rw == READ)
249                 up_read(&cdt->cdt_llog_lock);
250         else
251                 up_write(&cdt->cdt_llog_lock);
252
253         RETURN(rc);
254 }
255
256 /**
257  * add an entry in agent llog
258  * \param env [IN] environment
259  * \param mdt [IN] PDT device
260  * \param archive_id [IN] backend archive number
261  * \param hai [IN] record to register
262  * \retval 0 success
263  * \retval -ve failure
264  */
265 int mdt_agent_record_add(const struct lu_env *env, struct mdt_device *mdt,
266                          __u32 archive_id, __u64 flags,
267                          struct hsm_action_item *hai)
268 {
269         struct obd_device               *obd = mdt2obd_dev(mdt);
270         struct coordinator              *cdt = &mdt->mdt_coordinator;
271         struct llog_ctxt                *lctxt = NULL;
272         struct llog_agent_req_rec       *larr;
273         int                              rc;
274         int                              sz;
275         ENTRY;
276
277         sz = llog_data_len(sizeof(*larr) + hai->hai_len - sizeof(*hai));
278         OBD_ALLOC(larr, sz);
279         if (!larr)
280                 RETURN(-ENOMEM);
281         larr->arr_hdr.lrh_len = sz;
282         larr->arr_hdr.lrh_type = HSM_AGENT_REC;
283         larr->arr_status = ARS_WAITING;
284         larr->arr_archive_id = archive_id;
285         larr->arr_flags = flags;
286         larr->arr_req_create = ktime_get_real_seconds();
287         larr->arr_req_change = larr->arr_req_create;
288         memcpy(&larr->arr_hai, hai, hai->hai_len);
289
290         lctxt = llog_get_context(obd, LLOG_AGENT_ORIG_CTXT);
291         if (lctxt == NULL || lctxt->loc_handle == NULL)
292                 GOTO(free, rc = -ENOENT);
293
294         down_write(&cdt->cdt_llog_lock);
295
296         /* in case of cancel request, the cookie is already set to the
297          * value of the request cookie to be cancelled
298          * so we do not change it */
299         if (hai->hai_action == HSMA_CANCEL)
300                 larr->arr_hai.hai_cookie = hai->hai_cookie;
301         else
302                 larr->arr_hai.hai_cookie = cdt->cdt_last_cookie++;
303
304         rc = llog_cat_add(env, lctxt->loc_handle, &larr->arr_hdr, NULL);
305         if (rc > 0)
306                 rc = 0;
307
308         up_write(&cdt->cdt_llog_lock);
309         llog_ctxt_put(lctxt);
310
311         EXIT;
312 free:
313         OBD_FREE(larr, sz);
314         return rc;
315 }
316
317 /**
318  * data passed to llog_cat_process() callback
319  * to find requests
320  */
321 struct data_update_cb {
322         struct mdt_thread_info *mti;
323         struct hsm_record_update *updates;
324         unsigned int updates_count;
325         unsigned int updates_done;
326         time64_t change_time;
327 };
328
329 /**
330  *  llog_cat_process() callback, used to update a record
331  * \param env [IN] environment
332  * \param llh [IN] llog handle
333  * \param hdr [IN] llog record
334  * \param data [IN] cb data = data_update_cb
335  * \retval 0 success
336  * \retval -ve failure
337  */
338 static int mdt_agent_record_update_cb(const struct lu_env *env,
339                                       struct llog_handle *llh,
340                                       struct llog_rec_hdr *hdr,
341                                       void *data)
342 {
343         struct llog_agent_req_rec *larr = (struct llog_agent_req_rec *)hdr;
344         struct hsm_action_item *hai = &larr->arr_hai;
345         struct data_update_cb *ducb = data;
346         struct mdt_thread_info *mti = ducb->mti;
347         struct mdt_device *mdt = ducb->mti->mti_mdt;
348         struct coordinator *cdt = &mdt->mdt_coordinator;
349         int rc, i;
350         ENTRY;
351
352         /* check if all done */
353         if (ducb->updates_count == ducb->updates_done)
354                 RETURN(LLOG_PROC_BREAK);
355
356         /* if record is in final state, never change */
357         if (agent_req_in_final_state(larr->arr_status))
358                 RETURN(0);
359
360         rc = 0;
361         for (i = 0 ; i < ducb->updates_count ; i++) {
362                 struct hsm_record_update *update = &ducb->updates[i];
363
364                 CDEBUG(D_HSM, "%s: search %#llx, found %#llx\n",
365                        mdt_obd_name(mdt), update->cookie,
366                        hai->hai_cookie);
367                 if (hai->hai_cookie == update->cookie) {
368
369                         /* If record is a cancel request, it cannot be
370                          * canceled. This is to manage the following
371                          * case: when a request is canceled, we have 2
372                          * records with the the same cookie: the one
373                          * to cancel and the cancel request the 1st
374                          * has to be set to ARS_CANCELED and the 2nd
375                          * to ARS_SUCCEED
376                          */
377                         if (hai->hai_action == HSMA_CANCEL &&
378                             update->status == ARS_CANCELED)
379                                 RETURN(0);
380
381                         larr->arr_status = update->status;
382                         larr->arr_req_change = ducb->change_time;
383                         rc = llog_write(env, llh, hdr, hdr->lrh_index);
384                         if (rc < 0)
385                                 break;
386
387                         ducb->updates_done++;
388
389                         /* Unlock the EX layout lock */
390                         if (hai->hai_action == HSMA_RESTORE &&
391                             update->status == ARS_CANCELED)
392                                 cdt_restore_handle_del(mti, cdt, &hai->hai_fid);
393
394                         break;
395                 }
396         }
397
398         if (rc < 0)
399                 CERROR("%s: mdt_agent_llog_update_rec() failed, rc = %d\n",
400                        mdt_obd_name(mdt), rc);
401
402         RETURN(rc);
403 }
404
405 /**
406  * update an entry in agent llog
407  *
408  * \param env [IN] environment
409  * \param mdt [IN] MDT device
410  * \param updates [IN] array of entries to update
411  * \param updates_count [IN] number of entries in updates
412  *
413  * \retval 0 on success
414  * \retval negative on failure
415  */
416 int mdt_agent_record_update(struct mdt_thread_info *mti,
417                             struct hsm_record_update *updates,
418                             unsigned int updates_count)
419 {
420         const struct lu_env *env = mti->mti_env;
421         struct mdt_device *mdt = mti->mti_mdt;
422         struct data_update_cb    ducb;
423         u32 start_cat_idx = -1;
424         u32 start_rec_idx = -1;
425         u32 cat_idx;
426         u32 rec_idx;
427         int i;
428         int rc;
429         ENTRY;
430
431         /* Find the first location (start_cat_idx, start_rec_idx)
432          * among the records corresponding to cookies. */
433         for (i = 0; i < updates_count; i++) {
434                 /* If we cannot find a cached location for a cookie
435                  * (perhaps because the MDT was restart then we must
436                  * start from the beginning. In this case
437                  * mdt_agent_record_hash_get() sets both of cat_idx and
438                  * rec_idx to 0. */
439                 cdt_agent_record_hash_lookup(&mdt->mdt_coordinator,
440                                              updates[i].cookie,
441                                              &cat_idx, &rec_idx);
442                 if (cat_idx < start_cat_idx) {
443                         start_cat_idx = cat_idx;
444                         start_rec_idx = rec_idx;
445                 } else if (cat_idx == start_cat_idx &&
446                            rec_idx < start_rec_idx) {
447                         start_rec_idx = rec_idx;
448                 }
449         }
450
451         /* Fixup starting record index for llog_cat_process(). */
452         if (start_rec_idx != 0)
453                 start_rec_idx -= 1;
454
455         ducb.mti = mti;
456         ducb.updates = updates;
457         ducb.updates_count = updates_count;
458         ducb.updates_done = 0;
459         ducb.change_time = ktime_get_real_seconds();
460
461         rc = cdt_llog_process(env, mdt, mdt_agent_record_update_cb, &ducb,
462                               start_cat_idx, start_rec_idx, WRITE);
463         if (rc < 0)
464                 CERROR("%s: cdt_llog_process() failed, rc=%d, cannot update "
465                        "status for %u cookies, done %u\n",
466                        mdt_obd_name(mdt), rc,
467                        updates_count, ducb.updates_done);
468         RETURN(rc);
469 }
470
471 /*
472  * Agent actions /proc seq_file methods
473  * As llog processing uses a callback for each entry, we cannot do a sequential
474  * read. To limit calls to llog_cat_process (it spawns a thread), we fill
475  * multiple record in seq_file buffer in one show call.
476  * op->start() sets the iterator up and returns the first element of sequence
477  * op->stop() shuts it down.
478  * op->show() iterate llog and print element into the buffer.
479  * In case of error ->start() and ->next() return ERR_PTR(error)
480  * In the end of sequence they return %NULL
481  * op->show() returns 0 in case of success and negative number in case of error.
482  *
483  */
484 /**
485  * seq_file iterator for agent_action entry
486  */
487 #define AGENT_ACTIONS_IT_MAGIC 0x19660426
488 struct agent_action_iterator {
489         int                      aai_magic;      /**< magic number */
490         bool                     aai_eof;        /**< all done */
491         struct lu_env            aai_env;        /**< lustre env for llog */
492         struct mdt_device       *aai_mdt;        /**< metadata device */
493         struct llog_ctxt        *aai_ctxt;       /**< llog context */
494         int                      aai_cat_index;  /**< cata idx already shown */
495         int                      aai_index;      /**< idx in cata shown */
496 };
497
498 /**
499  * seq_file method called to start access to /proc file
500  * get llog context + llog handle
501  */
502 static void *mdt_hsm_actions_debugfs_start(struct seq_file *s, loff_t *pos)
503 {
504         struct agent_action_iterator *aai = s->private;
505
506         ENTRY;
507
508         LASSERTF(aai->aai_magic == AGENT_ACTIONS_IT_MAGIC, "%08X\n",
509                  aai->aai_magic);
510
511         aai->aai_ctxt = llog_get_context(mdt2obd_dev(aai->aai_mdt),
512                                          LLOG_AGENT_ORIG_CTXT);
513         if (aai->aai_ctxt == NULL || aai->aai_ctxt->loc_handle == NULL) {
514                 CERROR("llog_get_context() failed\n");
515                 RETURN(ERR_PTR(-ENOENT));
516         }
517
518         CDEBUG(D_HSM, "llog successfully initialized, start from %lld\n",
519                *pos);
520         /* first call = rewind */
521         if (*pos == 0) {
522                 aai->aai_cat_index = 0;
523                 aai->aai_index = 0;
524                 aai->aai_eof = false;
525         }
526
527         if (aai->aai_eof)
528                 RETURN(NULL);
529
530         RETURN(aai);
531 }
532
533 static void *mdt_hsm_actions_debugfs_next(struct seq_file *s, void *v,
534                                          loff_t *pos)
535 {
536         struct agent_action_iterator *aai = s->private;
537
538         (*pos)++;
539         if (aai->aai_eof)
540                 RETURN(NULL);
541         RETURN(aai);
542 }
543
544 /**
545  *  llog_cat_process() callback, used to fill a seq_file buffer
546  */
547 static int hsm_actions_show_cb(const struct lu_env *env,
548                                  struct llog_handle *llh,
549                                  struct llog_rec_hdr *hdr,
550                                  void *data)
551 {
552         struct llog_agent_req_rec *larr = (struct llog_agent_req_rec *)hdr;
553         struct seq_file *s = data;
554         struct agent_action_iterator *aai = s->private;
555         int sz;
556         char buf[12];
557
558         ENTRY;
559
560         LASSERTF(aai->aai_magic == AGENT_ACTIONS_IT_MAGIC, "%08X\n",
561                  aai->aai_magic);
562
563         /* if rec already printed => skip */
564         if (unlikely(llh->lgh_hdr->llh_cat_idx < aai->aai_cat_index))
565                 RETURN(0);
566
567         if (unlikely(llh->lgh_hdr->llh_cat_idx == aai->aai_cat_index &&
568                      hdr->lrh_index <= aai->aai_index))
569                 RETURN(0);
570
571         sz = larr->arr_hai.hai_len - sizeof(larr->arr_hai);
572         seq_printf(s, "lrh=[type=%X len=%d idx=%d/%d] fid="DFID
573                    " dfid="DFID" compound/cookie=%#llx/%#llx"
574                    " action=%s archive#=%d flags=%#llx"
575                    " extent=%#llx-%#llx"
576                    " gid=%#llx datalen=%d status=%s data=[%s]\n",
577                    hdr->lrh_type, hdr->lrh_len,
578                    llh->lgh_hdr->llh_cat_idx, hdr->lrh_index,
579                    PFID(&larr->arr_hai.hai_fid),
580                    PFID(&larr->arr_hai.hai_dfid),
581                    0ULL /* compound_id */, larr->arr_hai.hai_cookie,
582                    hsm_copytool_action2name(larr->arr_hai.hai_action),
583                    larr->arr_archive_id,
584                    larr->arr_flags,
585                    larr->arr_hai.hai_extent.offset,
586                    larr->arr_hai.hai_extent.length,
587                    larr->arr_hai.hai_gid, sz,
588                    agent_req_status2name(larr->arr_status),
589                    hai_dump_data_field(&larr->arr_hai, buf, sizeof(buf)));
590
591         aai->aai_cat_index = llh->lgh_hdr->llh_cat_idx;
592         aai->aai_index = hdr->lrh_index;
593
594         RETURN(0);
595 }
596
597 /**
598  * mdt_hsm_actions_debugfs_show() is called at for each seq record
599  * process the llog, with a cb which fill the file_seq buffer
600  * to be faster, one show will fill multiple records
601  */
602 static int mdt_hsm_actions_debugfs_show(struct seq_file *s, void *v)
603 {
604         struct agent_action_iterator *aai = s->private;
605         struct coordinator *cdt = &aai->aai_mdt->mdt_coordinator;
606         int rc;
607
608         ENTRY;
609
610         LASSERTF(aai->aai_magic == AGENT_ACTIONS_IT_MAGIC, "%08X\n",
611                  aai->aai_magic);
612
613         CDEBUG(D_HSM, "show from cat %d index %d eof=%d\n",
614                aai->aai_cat_index, aai->aai_index, aai->aai_eof);
615         if (aai->aai_eof)
616                 RETURN(0);
617
618         down_read(&cdt->cdt_llog_lock);
619         rc = llog_cat_process(&aai->aai_env, aai->aai_ctxt->loc_handle,
620                               hsm_actions_show_cb, s,
621                               aai->aai_cat_index, aai->aai_index);
622         up_read(&cdt->cdt_llog_lock);
623         if (rc == 0) /* all llog parsed */
624                 aai->aai_eof = true;
625         if (rc == LLOG_PROC_BREAK) /* buffer full */
626                 rc = 0;
627
628         RETURN(rc);
629 }
630
631 /**
632  * seq_file method called to stop access to /proc file
633  * clean + put llog context
634  */
635 static void mdt_hsm_actions_debugfs_stop(struct seq_file *s, void *v)
636 {
637         struct agent_action_iterator *aai = s->private;
638
639         ENTRY;
640
641         LASSERTF(aai->aai_magic == AGENT_ACTIONS_IT_MAGIC, "%08X\n",
642                  aai->aai_magic);
643
644         if (aai->aai_ctxt)
645                 llog_ctxt_put(aai->aai_ctxt);
646
647         EXIT;
648 }
649
650 static const struct seq_operations mdt_hsm_actions_debugfs_ops = {
651         .start  = mdt_hsm_actions_debugfs_start,
652         .next   = mdt_hsm_actions_debugfs_next,
653         .show   = mdt_hsm_actions_debugfs_show,
654         .stop   = mdt_hsm_actions_debugfs_stop,
655 };
656
657 static int ldebugfs_open_hsm_actions(struct inode *inode, struct file *file)
658 {
659         struct agent_action_iterator    *aai;
660         struct seq_file                 *s;
661         int                              rc;
662         struct mdt_device               *mdt;
663         ENTRY;
664
665         rc = seq_open(file, &mdt_hsm_actions_debugfs_ops);
666         if (rc)
667                 RETURN(rc);
668
669         OBD_ALLOC_PTR(aai);
670         if (aai == NULL)
671                 GOTO(err, rc = -ENOMEM);
672
673         aai->aai_magic = AGENT_ACTIONS_IT_MAGIC;
674         rc = lu_env_init(&aai->aai_env, LCT_LOCAL);
675         if (rc)
676                 GOTO(err, rc);
677
678         /* mdt is saved in seq_file->data by
679          * mdt_coordinator_tunables_init() calling
680          * debugfs_register()
681          */
682         mdt = inode->i_private;
683         aai->aai_mdt = mdt;
684         s = file->private_data;
685         s->private = aai;
686
687         GOTO(out, rc = 0);
688
689 err:
690         seq_release(inode, file);
691         if (aai && aai->aai_env.le_ses)
692                 OBD_FREE_PTR(aai->aai_env.le_ses);
693         if (aai)
694                 OBD_FREE_PTR(aai);
695 out:
696         return rc;
697 }
698
699 /**
700  * ldebugfs_release_hsm_actions() is called at end of /proc access.
701  * It frees allocated resources and calls cleanup lprocfs methods.
702  */
703 static int ldebugfs_release_hsm_actions(struct inode *inode, struct file *file)
704 {
705         struct seq_file                 *seq = file->private_data;
706         struct agent_action_iterator    *aai = seq->private;
707
708         if (aai) {
709                 lu_env_fini(&aai->aai_env);
710                 OBD_FREE_PTR(aai);
711         }
712
713         return seq_release(inode, file);
714 }
715
716 /* Methods to access HSM action list LLOG through /proc */
717 const struct file_operations mdt_hsm_actions_fops = {
718         .owner          = THIS_MODULE,
719         .open           = ldebugfs_open_hsm_actions,
720         .read           = seq_read,
721         .llseek         = seq_lseek,
722         .release        = ldebugfs_release_hsm_actions,
723 };