Whamcloud - gitweb
1767e112bdf11a1b931a6d837dd2ac1ff919ad6c
[fs/lustre-release.git] / lustre / mdt / mdt_hsm_cdt_agent.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  *
25  * Copyright (c) 2016, 2017, Intel Corporation.
26  *     alternatives
27  *
28  */
29 /*
30  * lustre/mdt/mdt_hsm_cdt_agent.c
31  *
32  * Lustre HSM Coordinator
33  *
34  * Author: Jacques-Charles Lafoucriere <jacques-charles.lafoucriere@cea.fr>
35  * Author: Aurelien Degremont <aurelien.degremont@cea.fr>
36  */
37
38 #define DEBUG_SUBSYSTEM S_MDS
39
40 #include <obd.h>
41 #include <obd_support.h>
42 #include <lustre_export.h>
43 #include <lprocfs_status.h>
44 #include <lustre_kernelcomm.h>
45 #include "mdt_internal.h"
46
47 /*
48  * Agent external API
49  */
50
51 /*
52  * find a hsm_agent by uuid
53  * lock cdt_agent_lock needs to be held by caller
54  * \param cdt [IN] coordinator
55  * \param uuid [IN] agent UUID
56  * \retval hsm_agent pointer or NULL if not found
57  */
58 static struct hsm_agent *mdt_hsm_agent_lookup(struct coordinator *cdt,
59                                               const struct obd_uuid *uuid)
60 {
61         struct hsm_agent        *ha;
62
63         list_for_each_entry(ha, &cdt->cdt_agents, ha_list) {
64                 if (obd_uuid_equals(&ha->ha_uuid, uuid))
65                         return ha;
66         }
67         return NULL;
68 }
69
70 /**
71  * register a copy tool
72  * \param mti [IN] MDT context
73  * \param uuid [IN] client UUID to be registered
74  * \param count [IN] number of archives agent serves
75  * \param archive_id [IN] vector of archive number served by the copytool
76  * \retval 0 success
77  * \retval -ve failure
78  */
79 int mdt_hsm_agent_register(struct mdt_thread_info *mti,
80                            const struct obd_uuid *uuid,
81                            int nr_archives, __u32 *archive_id)
82 {
83         struct coordinator      *cdt = &mti->mti_mdt->mdt_coordinator;
84         struct hsm_agent        *ha, *tmp;
85         int                      rc;
86         ENTRY;
87
88         /* no coordinator started, so we cannot serve requests */
89         if (cdt->cdt_state == CDT_STOPPED) {
90                 LCONSOLE_WARN("HSM coordinator thread is not running - "
91                               "denying agent registration.\n");
92                 RETURN(-ENXIO);
93         }
94
95         OBD_ALLOC_PTR(ha);
96         if (ha == NULL)
97                 GOTO(out, rc = -ENOMEM);
98
99         ha->ha_uuid = *uuid;
100         ha->ha_archive_cnt = nr_archives;
101         if (ha->ha_archive_cnt != 0) {
102                 int sz;
103
104                 sz = ha->ha_archive_cnt * sizeof(*ha->ha_archive_id);
105                 OBD_ALLOC(ha->ha_archive_id, sz);
106                 if (ha->ha_archive_id == NULL)
107                         GOTO(out_free, rc = -ENOMEM);
108                 memcpy(ha->ha_archive_id, archive_id, sz);
109         }
110         atomic_set(&ha->ha_requests, 0);
111         atomic_set(&ha->ha_success, 0);
112         atomic_set(&ha->ha_failure, 0);
113
114         down_write(&cdt->cdt_agent_lock);
115         tmp = mdt_hsm_agent_lookup(cdt, uuid);
116         if (tmp != NULL) {
117                 LCONSOLE_WARN("HSM agent %s already registered\n",
118                               obd_uuid2str(uuid));
119                 up_write(&cdt->cdt_agent_lock);
120                 GOTO(out_free, rc = -EEXIST);
121         }
122
123         list_add_tail(&ha->ha_list, &cdt->cdt_agents);
124
125         if (ha->ha_archive_cnt == 0)
126                 CDEBUG(D_HSM, "agent %s registered for all archives\n",
127                        obd_uuid2str(&ha->ha_uuid));
128         else
129                 CDEBUG(D_HSM, "agent %s registered for %d archives\n",
130                        obd_uuid2str(&ha->ha_uuid), ha->ha_archive_cnt);
131
132         up_write(&cdt->cdt_agent_lock);
133         GOTO(out, rc = 0);
134
135 out_free:
136
137         if (ha != NULL && ha->ha_archive_id != NULL)
138                 OBD_FREE_PTR_ARRAY(ha->ha_archive_id, ha->ha_archive_cnt);
139         if (ha != NULL)
140                 OBD_FREE_PTR(ha);
141 out:
142         /* wake the coordinator to potentially schedule requests */
143         if (rc == -EEXIST || rc == 0)
144                 mdt_hsm_cdt_event(cdt);
145
146         return rc;
147 }
148
149 /**
150  * register a copy tool
151  * \param mti [IN] MDT context
152  * \param uuid [IN] uuid to be registered
153  * \param archive_mask [IN] bitmask of archive number served by the copytool
154  * \retval 0 success
155  * \retval -ve failure
156  */
157 int mdt_hsm_agent_register_mask(struct mdt_thread_info *mti,
158                                 const struct obd_uuid *uuid, __u32 archive_mask)
159 {
160         int              rc, i, nr_archives = 0;
161         __u32           *archive_id = NULL;
162         ENTRY;
163
164         nr_archives = hweight32(archive_mask);
165
166         if (nr_archives != 0) {
167                 OBD_ALLOC_PTR_ARRAY(archive_id, nr_archives);
168                 if (!archive_id)
169                         RETURN(-ENOMEM);
170
171                 nr_archives = 0;
172                 for (i = 0; i < sizeof(archive_mask) * 8; i++) {
173                         if (BIT(i) & archive_mask) {
174                                 archive_id[nr_archives] = i + 1;
175                                 nr_archives++;
176                         }
177                 }
178         }
179
180         rc = mdt_hsm_agent_register(mti, uuid, nr_archives, archive_id);
181
182         if (archive_id != NULL)
183                 OBD_FREE_PTR_ARRAY(archive_id, nr_archives);
184
185         RETURN(rc);
186 }
187
188 /**
189  * unregister a copy tool
190  * \param mti [IN] MDT context
191  * \param uuid [IN] uuid to be unregistered
192  * \retval 0 success
193  * \retval -ve failure
194  */
195 int mdt_hsm_agent_unregister(struct mdt_thread_info *mti,
196                              const struct obd_uuid *uuid)
197 {
198         struct coordinator      *cdt = &mti->mti_mdt->mdt_coordinator;
199         struct hsm_agent        *ha;
200         int                      rc;
201         ENTRY;
202
203         /* no coordinator started, so we cannot serve requests */
204         if (cdt->cdt_state == CDT_STOPPED)
205                 RETURN(-ENXIO);
206
207         down_write(&cdt->cdt_agent_lock);
208
209         ha = mdt_hsm_agent_lookup(cdt, uuid);
210         if (ha != NULL)
211                 list_del_init(&ha->ha_list);
212
213         up_write(&cdt->cdt_agent_lock);
214
215         if (ha == NULL)
216                 GOTO(out, rc = -ENOENT);
217
218         if (ha->ha_archive_cnt != 0)
219                 OBD_FREE_PTR_ARRAY(ha->ha_archive_id, ha->ha_archive_cnt);
220         OBD_FREE_PTR(ha);
221
222         GOTO(out, rc = 0);
223 out:
224         CDEBUG(D_HSM, "agent %s unregistration: %d\n", obd_uuid2str(uuid), rc);
225
226         return rc;
227 }
228
229 /**
230  * update agent statistics
231  * \param mdt [IN] MDT device
232  * \param succ_rq [IN] number of success
233  * \param fail_rq [IN] number of failure
234  * \param new_rq [IN] number of new requests
235  * \param uuid [IN] agent uuid
236  * if all counters == 0, clear counters
237  * \retval 0 success
238  * \retval -ve failure
239  */
240 int mdt_hsm_agent_update_statistics(struct coordinator *cdt,
241                                     int succ_rq, int fail_rq, int new_rq,
242                                     const struct obd_uuid *uuid)
243 {
244         struct hsm_agent        *ha;
245         int                      rc;
246         ENTRY;
247
248         down_read(&cdt->cdt_agent_lock);
249         list_for_each_entry(ha, &cdt->cdt_agents, ha_list) {
250                 if (obd_uuid_equals(&ha->ha_uuid, uuid)) {
251                         if (succ_rq == 0 && fail_rq == 0 && new_rq == 0) {
252                                 atomic_set(&ha->ha_success, 0);
253                                 atomic_set(&ha->ha_failure, 0);
254                                 atomic_set(&ha->ha_requests, 0);
255                         } else {
256                                 atomic_add(succ_rq, &ha->ha_success);
257                                 atomic_add(fail_rq, &ha->ha_failure);
258                                 atomic_add(new_rq, &ha->ha_requests);
259                                 atomic_sub(succ_rq, &ha->ha_requests);
260                                 atomic_sub(fail_rq, &ha->ha_requests);
261                         }
262                         GOTO(out, rc = 0);
263                 }
264
265         }
266         rc = -ENOENT;
267 out:
268         up_read(&cdt->cdt_agent_lock);
269         RETURN(rc);
270 }
271
272 /**
273  * find the best agent
274  * \param cdt [IN] coordinator
275  * \param archive [IN] archive number
276  * \param uuid [OUT] agent who can serve archive
277  * \retval 0 success
278  * \retval -ve failure
279  */
280 int mdt_hsm_find_best_agent(struct coordinator *cdt, __u32 archive,
281                             struct obd_uuid *uuid)
282 {
283         int                      rc = -EAGAIN, i, load = -1;
284         struct hsm_agent        *ha;
285         ENTRY;
286
287         /* Choose an export to send a copytool req to */
288         down_read(&cdt->cdt_agent_lock);
289         list_for_each_entry(ha, &cdt->cdt_agents, ha_list) {
290                 for (i = 0; (i < ha->ha_archive_cnt) &&
291                               (ha->ha_archive_id[i] != archive); i++) {
292                         /* nothing to do, just skip unmatching records */
293                 }
294
295                 /* archive count == 0 means copy tool serves any backend */
296                 if (ha->ha_archive_cnt != 0 && i == ha->ha_archive_cnt)
297                         continue;
298
299                 if (load == -1 || load > atomic_read(&ha->ha_requests)) {
300                         load = atomic_read(&ha->ha_requests);
301                         *uuid = ha->ha_uuid;
302                         rc = 0;
303                 }
304                 if (atomic_read(&ha->ha_requests) == 0)
305                         break;
306         }
307         up_read(&cdt->cdt_agent_lock);
308
309         RETURN(rc);
310 }
311
312 int mdt_hsm_send_action_to_each_archive(struct mdt_thread_info *mti,
313                                     struct hsm_action_item *hai)
314 {
315         struct hsm_agent *ha;
316         __u32 archive_mask = 0;
317         struct coordinator *cdt = &mti->mti_mdt->mdt_coordinator;
318         int i;
319         /* return error by default in case all archive_ids have unregistered */
320         int rc = -EAGAIN;
321         ENTRY;
322
323         /* send action to all registered archive_ids */
324         down_read(&cdt->cdt_agent_lock);
325         list_for_each_entry(ha, &cdt->cdt_agents, ha_list) {
326                 for (i = 0; (i < ha->ha_archive_cnt); i++) {
327                         /* only send once for each archive_id */
328                         if (BIT(ha->ha_archive_id[i]) & archive_mask)
329                                 continue;
330                         archive_mask |= BIT(ha->ha_archive_id[i]);
331
332                         /* XXX: it could make sense to gather all
333                          * actions for the same archive_id like in
334                          * mdt_hsm_add_actions() ?? */
335                         rc = mdt_agent_record_add(mti->mti_env, mti->mti_mdt,
336                                                   ha->ha_archive_id[i], 0,
337                                                   hai);
338                         if (rc) {
339                                 CERROR("%s: unable to add HSM remove request "
340                                        "for "DFID": rc=%d\n",
341                                        mdt_obd_name(mti->mti_mdt),
342                                        PFID(&hai->hai_fid), rc);
343                                 break;
344                         } else {
345                                 CDEBUG(D_HSM, "%s: added HSM remove request "
346                                        "for "DFID", archive_id=%d\n",
347                                        mdt_obd_name(mti->mti_mdt),
348                                        PFID(&hai->hai_fid),
349                                        ha->ha_archive_id[i]);
350                         }
351                 }
352                 /* early exit from loop due to error? */
353                 if (i != ha->ha_archive_cnt)
354                         break;
355         }
356         up_read(&cdt->cdt_agent_lock);
357
358         RETURN(rc);
359 }
360
361 /**
362  * send a HAL to the agent
363  * \param mti [IN] context
364  * \param hal [IN] request (can be a kuc payload)
365  * \param purge [IN] purge mode (no record)
366  * \retval 0 success
367  * \retval -ve failure
368  * This function supposes:
369  *  - all actions are for the same archive number
370  *  - in case of cancel, all cancel are for the same agent
371  * This implies that request split has to be done
372  *  before when building the hal
373  */
374 int mdt_hsm_agent_send(struct mdt_thread_info *mti,
375                        struct hsm_action_list *hal, bool purge)
376 {
377         struct obd_export       *exp;
378         struct mdt_device       *mdt = mti->mti_mdt;
379         struct coordinator      *cdt = &mti->mti_mdt->mdt_coordinator;
380         struct hsm_action_list  *buf = NULL;
381         struct hsm_action_item  *hai;
382         struct obd_uuid          uuid;
383         int                      len, i, rc = 0;
384         bool                     fail_request;
385         bool                     is_registered = false;
386         ENTRY;
387
388         rc = mdt_hsm_find_best_agent(cdt, hal->hal_archive_id, &uuid);
389         if (rc && hal->hal_archive_id == 0) {
390                 uint notrmcount = 0;
391                 int rc2 = 0;
392
393                 /* special case of remove requests with no archive_id specified,
394                  * and no agent registered to serve all archives, then create a
395                  * set of new requests, each to be sent to each registered
396                  * archives.
397                  * Todo so, find all HSMA_REMOVE entries, and then :
398                  *     _ set completed status as SUCCESS (or FAIL?)
399                  *     _ create a new LLOG record for each archive_id
400                  *       presently being served by any CT
401                  */
402                 hai = hai_first(hal);
403                 for (i = 0; i < hal->hal_count; i++,
404                      hai = hai_next(hai)) {
405                         struct hsm_record_update update;
406
407                         /* only removes are concerned */
408                         if (hai->hai_action != HSMA_REMOVE) {
409                                 /* count if other actions than HSMA_REMOVE,
410                                  * to return original error/rc */
411                                 notrmcount++;
412                                 continue;
413                         }
414
415                         /* send remove request to all registered archive_ids */
416                         rc2 = mdt_hsm_send_action_to_each_archive(mti, hai);
417                         if (rc2)
418                                 break;
419
420                         /* only update original request as SUCCEED if it has
421                          * been successfully broadcasted to all available
422                          * archive_ids
423                          * XXX: this should only cause duplicates to be sent,
424                          * unless a method to record already successfully
425                          * reached archive_ids is implemented */
426
427                         update.cookie = hai->hai_cookie;
428                         update.status = ARS_SUCCEED;
429                         rc2 = mdt_agent_record_update(mti->mti_env, mdt,
430                                                       &update, 1);
431                         if (rc2) {
432                                 CERROR("%s: mdt_agent_record_update() "
433                                       "failed, cannot update "
434                                       "status to %s for cookie "
435                                       "%#llx: rc = %d\n",
436                                       mdt_obd_name(mdt),
437                                       agent_req_status2name(ARS_SUCCEED),
438                                       hai->hai_cookie, rc2);
439                                 break;
440                         }
441                 }
442                 /* only remove requests with archive_id=0 */
443                 if (notrmcount == 0)
444                         RETURN(rc2);
445
446         }
447
448         if (rc) {
449                 CERROR("%s: Cannot find agent for archive %d: rc = %d\n",
450                        mdt_obd_name(mdt), hal->hal_archive_id, rc);
451                 RETURN(rc);
452         }
453
454         CDEBUG(D_HSM, "Agent %s selected for archive %d\n", obd_uuid2str(&uuid),
455                hal->hal_archive_id);
456
457         len = hal_size(hal);
458         buf = kuc_alloc(len, KUC_TRANSPORT_HSM, HMT_ACTION_LIST);
459         if (IS_ERR(buf))
460                 RETURN(PTR_ERR(buf));
461         memcpy(buf, hal, len);
462
463         /* Check if request is still valid (cf file hsm flags) */
464         fail_request = false;
465         hai = hai_first(hal);
466         for (i = 0; i < hal->hal_count; i++, hai = hai_next(hai)) {
467                 struct mdt_object *obj;
468                 struct md_hsm hsm;
469
470                 if (hai->hai_action == HSMA_CANCEL)
471                         continue;
472
473                 obj = mdt_hsm_get_md_hsm(mti, &hai->hai_fid, &hsm);
474                 if (!IS_ERR(obj)) {
475                         mdt_object_put(mti->mti_env, obj);
476                 } else if (PTR_ERR(obj) == -ENOENT) {
477                         struct hsm_record_update update = {
478                                 .cookie = hai->hai_cookie,
479                                 .status = ARS_FAILED,
480                         };
481
482                         if (hai->hai_action == HSMA_REMOVE)
483                                 continue;
484
485                         fail_request = true;
486                         rc = mdt_agent_record_update(mti->mti_env, mdt,
487                                                      &update, 1);
488                         if (rc < 0) {
489                                 CERROR("%s: mdt_agent_record_update() failed, "
490                                        "cannot update status to %s for cookie "
491                                        "%#llx: rc = %d\n",
492                                        mdt_obd_name(mdt),
493                                        agent_req_status2name(ARS_FAILED),
494                                        hai->hai_cookie, rc);
495                                 GOTO(out_buf, rc);
496                         }
497
498                         continue;
499                 } else {
500                         GOTO(out_buf, rc = PTR_ERR(obj));
501                 }
502
503                 if (!mdt_hsm_is_action_compat(hai, hal->hal_archive_id,
504                                               hal->hal_flags, &hsm)) {
505                         struct hsm_record_update update = {
506                                 .cookie = hai->hai_cookie,
507                                 .status = ARS_FAILED,
508                         };
509
510                         /* incompatible request, we abort the request */
511                         /* next time coordinator will wake up, it will
512                          * make the same HAL with valid only
513                          * records */
514                         fail_request = true;
515                         rc = mdt_agent_record_update(mti->mti_env, mdt,
516                                                      &update, 1);
517                         if (rc) {
518                                 CERROR("%s: mdt_agent_record_update() failed, "
519                                        "cannot update status to %s for cookie "
520                                        "%#llx: rc = %d\n",
521                                        mdt_obd_name(mdt),
522                                        agent_req_status2name(ARS_FAILED),
523                                        hai->hai_cookie, rc);
524                                 GOTO(out_buf, rc);
525                         }
526
527                         /* if restore and record status updated, give
528                          * back granted layout lock */
529                         if (hai->hai_action == HSMA_RESTORE)
530                                 cdt_restore_handle_del(mti, cdt, &hai->hai_fid);
531                 }
532         }
533
534         /* we found incompatible requests, so the HAL cannot be sent
535          * as is. Bad records have been invalidated in llog.
536          * Valid one will be reschedule next time coordinator will wake up
537          * So no need the rebuild a full valid HAL now
538          */
539         if (fail_request)
540                 GOTO(out_buf, rc = 0);
541
542         /* Cancel memory registration is useless for purge
543          * non registration avoid a deadlock :
544          * in case of failure we have to take the write lock
545          * to remove entry which conflict with the read loack needed
546          * by purge
547          */
548         if (!purge) {
549                 /* set is_registered even if failure because we may have
550                  * partial work done */
551                 is_registered = true;
552                 rc = mdt_hsm_add_hal(mti, hal, &uuid);
553                 if (rc)
554                         GOTO(out_buf, rc);
555         }
556
557         /* Uses the ldlm reverse import; this rpc will be seen by
558          *  the ldlm_callback_handler. Note this sends a request RPC
559          * from a server (MDT) to a client (MDC), backwards of normal comms.
560          */
561         exp = obd_uuid_lookup(mdt2obd_dev(mdt), &uuid);
562         if (exp == NULL || exp->exp_disconnected) {
563                 if (exp != NULL)
564                         class_export_put(exp);
565                 /* This should clean up agents on evicted exports */
566                 rc = -ENOENT;
567                 CERROR("%s: agent uuid (%s) not found, unregistering:"
568                        " rc = %d\n",
569                        mdt_obd_name(mdt), obd_uuid2str(&uuid), rc);
570                 mdt_hsm_agent_unregister(mti, &uuid);
571                 GOTO(out, rc);
572         }
573
574         /* send request to agent */
575         rc = do_set_info_async(exp->exp_imp_reverse, LDLM_SET_INFO,
576                                LUSTRE_OBD_VERSION,
577                                sizeof(KEY_HSM_COPYTOOL_SEND),
578                                KEY_HSM_COPYTOOL_SEND,
579                                kuc_len(len), kuc_ptr(buf), NULL);
580
581         if (rc)
582                 CERROR("%s: cannot send request to agent '%s': rc = %d\n",
583                        mdt_obd_name(mdt), obd_uuid2str(&uuid), rc);
584
585         class_export_put(exp);
586
587         if (rc == -EPIPE) {
588                 CDEBUG(D_HSM, "Lost connection to agent '%s', unregistering\n",
589                        obd_uuid2str(&uuid));
590                 mdt_hsm_agent_unregister(mti, &uuid);
591         }
592
593 out:
594         if (rc != 0 && is_registered) {
595                 /* in case of error, we have to unregister requests */
596                 hai = hai_first(hal);
597                 for (i = 0; i < hal->hal_count; i++, hai = hai_next(hai)) {
598                         if (hai->hai_action == HSMA_CANCEL)
599                                 continue;
600                         mdt_cdt_remove_request(cdt, hai->hai_cookie);
601                 }
602         }
603
604 out_buf:
605         kuc_free(buf, len);
606
607         RETURN(rc);
608 }
609
610 /**
611  * seq_file method called to start access to debugfs file
612  */
613 static void *mdt_hsm_agent_debugfs_start(struct seq_file *s, loff_t *off)
614 {
615         struct mdt_device       *mdt = s->private;
616         struct coordinator      *cdt = &mdt->mdt_coordinator;
617         struct list_head        *pos;
618         loff_t                   i;
619         ENTRY;
620
621         down_read(&cdt->cdt_agent_lock);
622
623         if (list_empty(&cdt->cdt_agents))
624                 RETURN(NULL);
625
626         if (*off == 0)
627                 RETURN(SEQ_START_TOKEN);
628
629         i = 0;
630         list_for_each(pos, &cdt->cdt_agents) {
631                 i++;
632                 if (i >= *off)
633                         RETURN(pos);
634         }
635
636         RETURN(NULL);
637 }
638
639 /**
640  * seq_file method called to get next item
641  * just returns NULL at eof
642  */
643 static void *mdt_hsm_agent_debugfs_next(struct seq_file *s, void *v, loff_t *p)
644 {
645         struct mdt_device       *mdt = s->private;
646         struct coordinator      *cdt = &mdt->mdt_coordinator;
647         struct list_head        *pos = v;
648         ENTRY;
649
650         if (pos == SEQ_START_TOKEN)
651                 pos = cdt->cdt_agents.next;
652         else
653                 pos = pos->next;
654
655         (*p)++;
656         if (pos != &cdt->cdt_agents)
657                 RETURN(pos);
658
659         RETURN(NULL);
660 }
661
662 /**
663  */
664 static int mdt_hsm_agent_debugfs_show(struct seq_file *s, void *v)
665 {
666         struct list_head        *pos = v;
667         struct hsm_agent        *ha;
668         int                      i;
669         ENTRY;
670
671         if (pos == SEQ_START_TOKEN)
672                 RETURN(0);
673
674         ha = list_entry(pos, struct hsm_agent, ha_list);
675         seq_printf(s, "uuid=%s archive_id=", ha->ha_uuid.uuid);
676         if (ha->ha_archive_cnt == 0) {
677                 seq_printf(s, "ANY");
678         } else {
679                 seq_printf(s, "%d", ha->ha_archive_id[0]);
680                 for (i = 1; i < ha->ha_archive_cnt; i++)
681                         seq_printf(s, ",%d", ha->ha_archive_id[i]);
682         }
683
684         seq_printf(s, " requests=[current:%d ok:%d errors:%d]\n",
685                    atomic_read(&ha->ha_requests),
686                    atomic_read(&ha->ha_success),
687                    atomic_read(&ha->ha_failure));
688         RETURN(0);
689 }
690
691 /**
692  * seq_file method called to stop access to debugfs file
693  */
694 static void mdt_hsm_agent_debugfs_stop(struct seq_file *s, void *v)
695 {
696         struct mdt_device       *mdt = s->private;
697         struct coordinator      *cdt = &mdt->mdt_coordinator;
698
699         up_read(&cdt->cdt_agent_lock);
700 }
701
702 /* hsm agent list debugfs functions */
703 static const struct seq_operations mdt_hsm_agent_debugfs_ops = {
704         .start  = mdt_hsm_agent_debugfs_start,
705         .next   = mdt_hsm_agent_debugfs_next,
706         .show   = mdt_hsm_agent_debugfs_show,
707         .stop   = mdt_hsm_agent_debugfs_stop,
708 };
709
710 /**
711  * public function called at open of debugfs file to get
712  * list of agents
713  */
714 static int ldebugfs_open_hsm_agent(struct inode *inode, struct file *file)
715 {
716         struct seq_file *s;
717         int              rc;
718         ENTRY;
719
720         rc = seq_open(file, &mdt_hsm_agent_debugfs_ops);
721         if (rc)
722                 RETURN(rc);
723
724         s = file->private_data;
725         s->private = inode->i_private;
726
727         RETURN(rc);
728 }
729
730 /* methods to access hsm agent list */
731 const struct file_operations mdt_hsm_agent_fops = {
732         .owner          = THIS_MODULE,
733         .open           = ldebugfs_open_hsm_agent,
734         .read           = seq_read,
735         .llseek         = seq_lseek,
736         .release        = seq_release,
737 };