Whamcloud - gitweb
LU-3709 mdt: CDT cleanup follow-on patch
[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  */
27 /*
28  * lustre/mdt/mdt_agent_actions.c
29  *
30  * Lustre HSM
31  *
32  * Author: Jacques-Charles Lafoucriere <jacques-charles.lafoucriere@cea.fr>
33  * Author: Aurelien Degremont <aurelien.degremont@cea.fr>
34  */
35
36 #define DEBUG_SUBSYSTEM S_MDS
37
38 #include <obd_support.h>
39 #include <lustre_net.h>
40 #include <lustre_export.h>
41 #include <obd.h>
42 #include <lprocfs_status.h>
43 #include <lustre_log.h>
44 #include "mdt_internal.h"
45
46 void dump_llog_agent_req_rec(const char *prefix,
47                              const struct llog_agent_req_rec *larr)
48 {
49         char    buf[12];
50         int     sz;
51
52         sz = larr->arr_hai.hai_len - sizeof(larr->arr_hai);
53         CDEBUG(D_HSM, "%slrh=[type=%X len=%d idx=%d] fid="DFID
54                " dfid="DFID
55                " compound/cookie="LPX64"/"LPX64
56                " status=%s action=%s archive#=%d flags="LPX64
57                " create="LPU64" change="LPU64
58                " extent="LPX64"-"LPX64" gid="LPX64" datalen=%d"
59                " data=[%s]\n",
60                prefix,
61                larr->arr_hdr.lrh_type,
62                larr->arr_hdr.lrh_len, larr->arr_hdr.lrh_index,
63                PFID(&larr->arr_hai.hai_fid),
64                PFID(&larr->arr_hai.hai_dfid),
65                larr->arr_compound_id, larr->arr_hai.hai_cookie,
66                agent_req_status2name(larr->arr_status),
67                hsm_copytool_action2name(larr->arr_hai.hai_action),
68                larr->arr_archive_id,
69                larr->arr_flags,
70                larr->arr_req_create, larr->arr_req_change,
71                larr->arr_hai.hai_extent.offset,
72                larr->arr_hai.hai_extent.length,
73                larr->arr_hai.hai_gid, sz,
74                hai_dump_data_field(&larr->arr_hai, buf, sizeof(buf)));
75 }
76
77 /*
78  * process the actions llog
79  * \param env [IN] environment
80  * \param mdt [IN] MDT device
81  * \param cb [IN] llog callback funtion
82  * \param data [IN] llog callback  data
83  * \retval 0 success
84  * \retval -ve failure
85  */
86 int cdt_llog_process(const struct lu_env *env, struct mdt_device *mdt,
87                      llog_cb_t cb, void *data)
88 {
89         struct obd_device       *obd = mdt2obd_dev(mdt);
90         struct llog_ctxt        *lctxt = NULL;
91         struct coordinator      *cdt = &mdt->mdt_coordinator;
92         int                      rc;
93         ENTRY;
94
95         lctxt = llog_get_context(obd, LLOG_AGENT_ORIG_CTXT);
96         if (lctxt == NULL || lctxt->loc_handle == NULL)
97                 RETURN(-ENOENT);
98
99         mutex_lock(&cdt->cdt_llog_lock);
100
101         rc = llog_cat_process(env, lctxt->loc_handle, cb, data, 0, 0);
102         if (rc < 0)
103                 CERROR("%s: failed to process HSM_ACTIONS llog (rc=%d)\n",
104                         mdt_obd_name(mdt), rc);
105         else
106                 rc = 0;
107
108         llog_ctxt_put(lctxt);
109         mutex_unlock(&cdt->cdt_llog_lock);
110         RETURN(rc);
111 }
112
113 /**
114  * add an entry in agent llog
115  * \param env [IN] environment
116  * \param mdt [IN] PDT device
117  * \param compound_id [IN] global id associated with the record
118  * \param archive_id [IN] backend archive number
119  * \param hai [IN] record to register
120  * \retval 0 success
121  * \retval -ve failure
122  */
123 int mdt_agent_record_add(const struct lu_env *env,
124                          struct mdt_device *mdt,
125                          __u64 compound_id, __u32 archive_id,
126                          __u64 flags, struct hsm_action_item *hai)
127 {
128         struct obd_device               *obd = mdt2obd_dev(mdt);
129         struct coordinator              *cdt = &mdt->mdt_coordinator;
130         struct llog_ctxt                *lctxt = NULL;
131         struct llog_agent_req_rec       *larr;
132         int                              rc;
133         int                              sz;
134         ENTRY;
135
136         sz = llog_data_len(sizeof(*larr) + hai->hai_len - sizeof(*hai));
137         OBD_ALLOC(larr, sz);
138         if (!larr)
139                 RETURN(-ENOMEM);
140         larr->arr_hdr.lrh_len = sz;
141         larr->arr_hdr.lrh_type = HSM_AGENT_REC;
142         larr->arr_status = ARS_WAITING;
143         larr->arr_compound_id = compound_id;
144         larr->arr_archive_id = archive_id;
145         larr->arr_flags = flags;
146         larr->arr_req_create = cfs_time_current_sec();
147         larr->arr_req_change = larr->arr_req_create;
148         memcpy(&larr->arr_hai, hai, hai->hai_len);
149
150         lctxt = llog_get_context(obd, LLOG_AGENT_ORIG_CTXT);
151         if (lctxt == NULL || lctxt->loc_handle == NULL)
152                 GOTO(free, rc = -ENOENT);
153
154         mutex_lock(&cdt->cdt_llog_lock);
155
156         /* in case of cancel request, the cookie is already set to the
157          * value of the request cookie to be cancelled
158          * so we do not change it */
159         if (hai->hai_action != HSMA_CANCEL) {
160                 cdt->cdt_last_cookie++;
161                 hai->hai_cookie = cdt->cdt_last_cookie;
162         }
163         larr->arr_hai.hai_cookie = hai->hai_cookie;
164         rc = llog_cat_add(env, lctxt->loc_handle, &larr->arr_hdr, NULL, NULL);
165         if (rc > 0)
166                 rc = 0;
167
168         mutex_unlock(&cdt->cdt_llog_lock);
169         llog_ctxt_put(lctxt);
170
171         EXIT;
172 free:
173         OBD_FREE(larr, sz);
174         return rc;
175 }
176
177 /**
178  * data passed to llog_cat_process() callback
179  * to find requests
180  */
181 struct data_update_cb {
182         struct mdt_device       *mdt;
183         __u64                   *cookies;
184         int                      cookies_count;
185         int                      cookies_done;
186         enum agent_req_status    status;
187         cfs_time_t               change_time;
188 };
189
190 /**
191  *  llog_cat_process() callback, used to update a record
192  * \param env [IN] environment
193  * \param llh [IN] llog handle
194  * \param hdr [IN] llog record
195  * \param data [IN] cb data = data_update_cb
196  * \retval 0 success
197  * \retval -ve failure
198  */
199 static int mdt_agent_record_update_cb(const struct lu_env *env,
200                                       struct llog_handle *llh,
201                                       struct llog_rec_hdr *hdr,
202                                       void *data)
203 {
204         struct llog_agent_req_rec       *larr;
205         struct data_update_cb           *ducb;
206         int                              rc, i;
207         int                              found;
208         ENTRY;
209
210         larr = (struct llog_agent_req_rec *)hdr;
211         ducb = data;
212         found = 0;
213
214         /* check if all done */
215         if (ducb->cookies_count == ducb->cookies_done)
216                 RETURN(LLOG_PROC_BREAK);
217
218         /* if record is in final state, never change */
219         /* if record is a cancel request, it cannot be canceled
220          * this is to manage the following case:
221          * when a request is canceled, we have 2 records with the
222          * the same cookie : the one to cancel and the cancel request
223          * the 1st has to be set to ARS_CANCELED and the 2nd to ARS_SUCCEED
224          */
225         if (agent_req_in_final_state(larr->arr_status) ||
226             (larr->arr_hai.hai_action == HSMA_CANCEL &&
227              ducb->status == ARS_CANCELED))
228                 RETURN(0);
229
230         rc = 0;
231         for (i = 0 ; i < ducb->cookies_count ; i++) {
232                 CDEBUG(D_HSM, "%s: search "LPX64", found "LPX64"\n",
233                        mdt_obd_name(ducb->mdt), ducb->cookies[i],
234                        larr->arr_hai.hai_cookie);
235                 if (larr->arr_hai.hai_cookie == ducb->cookies[i]) {
236
237                         larr->arr_status = ducb->status;
238                         larr->arr_req_change = ducb->change_time;
239                         rc = mdt_agent_llog_update_rec(env, ducb->mdt, llh,
240                                                        larr);
241                         ducb->cookies_done++;
242                         found = 1;
243                         break;
244                 }
245         }
246
247         if (rc < 0)
248                 CERROR("%s: mdt_agent_llog_update_rec() failed, rc = %d\n",
249                        mdt_obd_name(ducb->mdt), rc);
250
251         if (found == 1)
252                 RETURN(LLOG_DEL_RECORD);
253
254         RETURN(rc);
255 }
256
257 /**
258  * update an entry in agent llog
259  * \param env [IN] environment
260  * \param mdt [IN] MDT device
261  * \param cookie [IN] entries to update
262  *    log cookie are returned by register
263  * \param status [IN] new status of the request
264  * \retval 0 success
265  * \retval -ve failure
266  */
267 int mdt_agent_record_update(const struct lu_env *env, struct mdt_device *mdt,
268                             __u64 *cookies, int cookies_count,
269                             enum agent_req_status status)
270 {
271         struct data_update_cb    ducb;
272         int                      rc;
273         ENTRY;
274
275         ducb.mdt = mdt;
276         ducb.cookies = cookies;
277         ducb.cookies_count = cookies_count;
278         ducb.cookies_done = 0;
279         ducb.status = status;
280         ducb.change_time = cfs_time_current_sec();
281
282         rc = cdt_llog_process(env, mdt, mdt_agent_record_update_cb, &ducb);
283         if (rc < 0)
284                 CERROR("%s: cdt_llog_process() failed, rc=%d, cannot update "
285                        "status to %s for %d cookies, done %d\n",
286                        mdt_obd_name(mdt), rc,
287                        agent_req_status2name(status),
288                        cookies_count, ducb.cookies_done);
289         RETURN(rc);
290 }
291
292 /**
293  * update a llog record
294  *  cdt_llog_lock must be hold
295  * \param env [IN] environment
296  * \param mdt [IN] mdt device
297  * \param llh [IN] llog handle, must be a catalog handle
298  * \param larr [IN] record
299  * \retval 0 success
300  * \retval -ve failure
301  */
302 int mdt_agent_llog_update_rec(const struct lu_env *env,
303                               struct mdt_device *mdt, struct llog_handle *llh,
304                               struct llog_agent_req_rec *larr)
305 {
306         struct llog_rec_hdr      saved_hdr;
307         int                      rc;
308         ENTRY;
309
310         /* saved old record info */
311         saved_hdr = larr->arr_hdr;
312         /* add new record with updated values */
313         larr->arr_hdr.lrh_id = 0;
314         larr->arr_hdr.lrh_index = 0;
315         rc = llog_cat_add(env, llh->u.phd.phd_cat_handle, &larr->arr_hdr,
316                           NULL, NULL);
317         larr->arr_hdr = saved_hdr;
318         RETURN(rc);
319 }
320
321 /*
322  * Agent actions /proc seq_file methods
323  * As llog processing uses a callback for each entry, we cannot do a sequential
324  * read. To limit calls to llog_cat_process (it spawns a thread), we fill
325  * multiple record in seq_file buffer in one show call.
326  * op->start() sets the iterator up and returns the first element of sequence
327  * op->stop() shuts it down.
328  * op->next() returns the next element of sequence.
329  * op->show() prints element into the buffer.
330  * In case of error ->start() and ->next() return ERR_PTR(error)
331  * In the end of sequence they return %NULL
332  * op->show() returns 0 in case of success and negative number in case of error.
333  *
334  */
335 /**
336  * seq_file iterator for agent_action entry
337  */
338 #define AGENT_ACTIONS_IT_MAGIC 0x19660426
339 struct agent_action_iterator {
340         int                      aai_magic;      /**< magic number */
341         struct lu_env            aai_env;        /**< lustre env for llog */
342         struct obd_device       *aai_obd;        /**< metadata device */
343         struct llog_ctxt        *aai_ctxt;       /**< llog context */
344         int                      aai_index_done; /**< idx already shown */
345         int                      aai_index_cb;   /**< current idx in loop cb */
346         int                      aai_eof;        /**< all done */
347 };
348
349 /**
350  * seq_file method called to start access to /proc file
351  * get llog context + llog handle
352  */
353 static void *mdt_agent_actions_proc_start(struct seq_file *s, loff_t *pos)
354 {
355         struct agent_action_iterator    *aai = s->private;
356         ENTRY;
357
358         LASSERTF(aai->aai_magic == AGENT_ACTIONS_IT_MAGIC, "%08X",
359                  aai->aai_magic);
360
361         aai->aai_ctxt = llog_get_context(aai->aai_obd, LLOG_AGENT_ORIG_CTXT);
362         if (aai->aai_ctxt == NULL || aai->aai_ctxt->loc_handle == NULL) {
363                 CERROR("llog_get_context() failed\n");
364                 RETURN(ERR_PTR(-ENOENT));
365         }
366
367         CDEBUG(D_HSM, "llog succesfully initialized, start from "LPD64"\n",
368                *pos);
369         /* first call = rewind */
370         if (*pos == 0) {
371                 aai->aai_index_done = 0;
372                 aai->aai_eof = 0;
373                 *pos = 1;
374         }
375
376         RETURN(aai);
377 }
378
379 /**
380  * seq_file method called to get next item
381  * just returns NULL at eof
382  * (seq_file buffer filling is done in llog_cat_process() callback)
383  */
384 static void *mdt_agent_actions_proc_next(struct seq_file *s, void *v,
385                                          loff_t *pos)
386 {
387         struct agent_action_iterator *aai = s->private;
388         ENTRY;
389
390         LASSERTF(aai->aai_magic == AGENT_ACTIONS_IT_MAGIC, "%08X",
391                  aai->aai_magic);
392
393         CDEBUG(D_HSM, "set current="LPD64" to done=%d, eof=%d\n",
394                *pos, aai->aai_index_done, aai->aai_eof);
395         (*pos) = aai->aai_index_done;
396
397         if (aai->aai_eof)
398                 RETURN(NULL);
399
400         RETURN(aai);
401 }
402
403 /**
404  *  llog_cat_process() callback, used to fill a seq_file buffer
405  */
406 static int agent_actions_show_cb(const struct lu_env *env,
407                                  struct llog_handle *llh,
408                                  struct llog_rec_hdr *hdr,
409                                  void *data)
410 {
411         struct llog_agent_req_rec    *larr = (struct llog_agent_req_rec *)hdr;
412         struct seq_file              *s = data;
413         struct agent_action_iterator *aai;
414         int                           rc, sz;
415         char                          buf[12];
416         ENTRY;
417
418         aai = s->private;
419         LASSERTF(aai->aai_magic == AGENT_ACTIONS_IT_MAGIC, "%08X",
420                  aai->aai_magic);
421
422         aai->aai_index_cb++;
423         /* if rec already printed => skip */
424         if (aai->aai_index_cb <= aai->aai_index_done)
425                 RETURN(0);
426
427         sz = larr->arr_hai.hai_len - sizeof(larr->arr_hai);
428         rc = seq_printf(s, "lrh=[type=%X len=%d idx=%d] fid="DFID
429                         " dfid="DFID
430                         " compound/cookie="LPX64"/"LPX64
431                         " action=%s archive#=%d flags="LPX64
432                         " extent="LPX64"-"LPX64
433                         " gid="LPX64" datalen=%d status=%s"
434                         " data=[%s]\n",
435                         larr->arr_hdr.lrh_type,
436                         larr->arr_hdr.lrh_len, larr->arr_hdr.lrh_index,
437                         PFID(&larr->arr_hai.hai_fid),
438                         PFID(&larr->arr_hai.hai_dfid),
439                         larr->arr_compound_id, larr->arr_hai.hai_cookie,
440                         hsm_copytool_action2name(larr->arr_hai.hai_action),
441                         larr->arr_archive_id,
442                         larr->arr_flags,
443                         larr->arr_hai.hai_extent.offset,
444                         larr->arr_hai.hai_extent.length,
445                         larr->arr_hai.hai_gid, sz,
446                         agent_req_status2name(larr->arr_status),
447                         hai_dump_data_field(&larr->arr_hai, buf, sizeof(buf)));
448         if (rc >= 0) {
449                 aai->aai_index_done++;
450                 RETURN(0);
451         }
452         /* buffer is full, stop filling */
453         RETURN(LLOG_PROC_BREAK);
454 }
455
456 /**
457  * mdt_agent_actions_proc_show() is called at for each seq record
458  * process the llog, with a cb which fill the file_seq buffer
459  * to be faster, one show will fill multiple records
460  */
461 static int mdt_agent_actions_proc_show(struct seq_file *s, void *v)
462 {
463         struct agent_action_iterator    *aai = s->private;
464         int                              rc;
465         ENTRY;
466
467         LASSERTF(aai->aai_magic == AGENT_ACTIONS_IT_MAGIC, "%08X",
468                  aai->aai_magic);
469
470         CDEBUG(D_HSM, "show from done=%d, eof=%d\n",
471                aai->aai_index_done, aai->aai_eof);
472         if (aai->aai_eof)
473                 RETURN(0);
474
475         aai->aai_index_cb = 0;
476         rc = llog_cat_process(&aai->aai_env, aai->aai_ctxt->loc_handle,
477                               agent_actions_show_cb, s, 0, 0);
478         /* was all llog parsed? */
479         if (rc == 0)
480                 aai->aai_eof = 1;
481         /* not enough room in buffer? */
482         if (rc == LLOG_PROC_BREAK)
483                 RETURN(0);
484         /* error */
485         RETURN(rc);
486 }
487
488 /**
489  * seq_file method called to stop access to /proc file
490  * clean + put llog context
491  */
492 static void mdt_agent_actions_proc_stop(struct seq_file *s, void *v)
493 {
494         struct agent_action_iterator *aai = s->private;
495         ENTRY;
496
497         LASSERTF(aai->aai_magic == AGENT_ACTIONS_IT_MAGIC, "%08X",
498                  aai->aai_magic);
499
500         if (aai->aai_ctxt)
501                 llog_ctxt_put(aai->aai_ctxt);
502
503         EXIT;
504         return;
505 }
506
507 static const struct seq_operations mdt_agent_actions_proc_ops = {
508         .start  = mdt_agent_actions_proc_start,
509         .next   = mdt_agent_actions_proc_next,
510         .show   = mdt_agent_actions_proc_show,
511         .stop   = mdt_agent_actions_proc_stop,
512 };
513
514 static int lprocfs_open_agent_actions(struct inode *inode, struct file *file)
515 {
516         struct agent_action_iterator    *aai;
517         struct seq_file                 *s;
518         int                              rc;
519         struct mdt_device               *mdt;
520         ENTRY;
521
522         if (LPROCFS_ENTRY_AND_CHECK(PDE(inode)))
523                 RETURN(-ENOENT);
524
525         rc = seq_open(file, &mdt_agent_actions_proc_ops);
526         if (rc) {
527                 LPROCFS_EXIT();
528                 RETURN(rc);
529         }
530
531         OBD_ALLOC_PTR(aai);
532         if (aai == NULL)
533                 GOTO(err, rc = -ENOMEM);
534
535         aai->aai_magic = AGENT_ACTIONS_IT_MAGIC;
536         rc = lu_env_init(&aai->aai_env, LCT_LOCAL);
537         if (rc)
538                 GOTO(err, rc);
539
540         /* mdt is saved in proc_dir_entry->data by
541          * mdt_coordinator_procfs_init() calling lprocfs_register()
542          */
543         mdt = (struct mdt_device *)PDE(inode)->data;
544         aai->aai_obd = mdt2obd_dev(mdt);
545         s = file->private_data;
546         s->private = aai;
547
548         GOTO(out, rc = 0);
549
550 err:
551         lprocfs_seq_release(inode, file);
552         if (aai && aai->aai_env.le_ses)
553                 OBD_FREE_PTR(aai->aai_env.le_ses);
554         if (aai)
555                 OBD_FREE_PTR(aai);
556 out:
557         return rc;
558 }
559
560 /**
561  * lprocfs_release_agent_actions() is called at end of /proc access
562  * free alloacted ressources and call cleanup lprocfs methods
563  */
564 static int lprocfs_release_agent_actions(struct inode *inode, struct file *file)
565 {
566         struct seq_file                 *seq = file->private_data;
567         struct agent_action_iterator    *aai = seq->private;
568
569         if (aai) {
570                 lu_env_fini(&aai->aai_env);
571                 OBD_FREE_PTR(aai);
572         }
573
574         return lprocfs_seq_release(inode, file);
575 }
576
577 /* methods to access agent actions llog through /proc */
578 const struct file_operations mdt_agent_actions_fops = {
579         .owner          = THIS_MODULE,
580         .open           = lprocfs_open_agent_actions,
581         .read           = seq_read,
582         .llseek         = seq_lseek,
583         .release        = lprocfs_release_agent_actions,
584 };
585