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