Whamcloud - gitweb
6b1acf03e6ef1311b71a0e26b97295804d1fd4d3
[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_hsm_cdt_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);
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);
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->show() iterate llog and print element into the buffer.
329  * In case of error ->start() and ->next() return ERR_PTR(error)
330  * In the end of sequence they return %NULL
331  * op->show() returns 0 in case of success and negative number in case of error.
332  *
333  */
334 /**
335  * seq_file iterator for agent_action entry
336  */
337 #define AGENT_ACTIONS_IT_MAGIC 0x19660426
338 struct agent_action_iterator {
339         int                      aai_magic;      /**< magic number */
340         bool                     aai_eof;        /**< all done */
341         struct lu_env            aai_env;        /**< lustre env for llog */
342         struct mdt_device       *aai_mdt;        /**< metadata device */
343         struct llog_ctxt        *aai_ctxt;       /**< llog context */
344         int                      aai_cat_index;  /**< cata idx already shown */
345         int                      aai_index;      /**< idx in cata shown */
346 };
347
348 /**
349  * seq_file method called to start access to /proc file
350  * get llog context + llog handle
351  */
352 static void *mdt_hsm_actions_proc_start(struct seq_file *s, loff_t *pos)
353 {
354         struct agent_action_iterator    *aai = s->private;
355         ENTRY;
356
357         LASSERTF(aai->aai_magic == AGENT_ACTIONS_IT_MAGIC, "%08X",
358                  aai->aai_magic);
359
360         aai->aai_ctxt = llog_get_context(mdt2obd_dev(aai->aai_mdt),
361                                          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_cat_index = 0;
372                 aai->aai_index = -1;
373                 aai->aai_eof = false;
374                 *pos = 1;
375         }
376
377         if (aai->aai_eof)
378                 RETURN(NULL);
379
380         RETURN(aai);
381 }
382
383 static void *mdt_hsm_actions_proc_next(struct seq_file *s, void *v,
384                                          loff_t *pos)
385 {
386         RETURN(NULL);
387 }
388
389 /**
390  *  llog_cat_process() callback, used to fill a seq_file buffer
391  */
392 static int hsm_actions_show_cb(const struct lu_env *env,
393                                  struct llog_handle *llh,
394                                  struct llog_rec_hdr *hdr,
395                                  void *data)
396 {
397         struct llog_agent_req_rec    *larr = (struct llog_agent_req_rec *)hdr;
398         struct seq_file              *s = data;
399         struct agent_action_iterator *aai;
400         int                           rc, sz;
401         size_t                        count;
402         char                          buf[12];
403         ENTRY;
404
405         aai = s->private;
406         LASSERTF(aai->aai_magic == AGENT_ACTIONS_IT_MAGIC, "%08X",
407                  aai->aai_magic);
408
409         /* if rec already printed => skip */
410         if (unlikely(llh->lgh_hdr->llh_cat_idx < aai->aai_cat_index))
411                 RETURN(0);
412
413         if (unlikely(llh->lgh_hdr->llh_cat_idx == aai->aai_cat_index &&
414                      hdr->lrh_index <= aai->aai_index))
415                 RETURN(0);
416
417         count = s->count;
418         sz = larr->arr_hai.hai_len - sizeof(larr->arr_hai);
419         rc = seq_printf(s, "lrh=[type=%X len=%d idx=%d/%d] fid="DFID
420                         " dfid="DFID
421                         " compound/cookie="LPX64"/"LPX64
422                         " action=%s archive#=%d flags="LPX64
423                         " extent="LPX64"-"LPX64
424                         " gid="LPX64" datalen=%d status=%s"
425                         " data=[%s]\n",
426                         hdr->lrh_type, hdr->lrh_len,
427                         llh->lgh_hdr->llh_cat_idx, hdr->lrh_index,
428                         PFID(&larr->arr_hai.hai_fid),
429                         PFID(&larr->arr_hai.hai_dfid),
430                         larr->arr_compound_id, larr->arr_hai.hai_cookie,
431                         hsm_copytool_action2name(larr->arr_hai.hai_action),
432                         larr->arr_archive_id,
433                         larr->arr_flags,
434                         larr->arr_hai.hai_extent.offset,
435                         larr->arr_hai.hai_extent.length,
436                         larr->arr_hai.hai_gid, sz,
437                         agent_req_status2name(larr->arr_status),
438                         hai_dump_data_field(&larr->arr_hai, buf, sizeof(buf)));
439         if (rc == 0) {
440                 aai->aai_cat_index = llh->lgh_hdr->llh_cat_idx;
441                 aai->aai_index = hdr->lrh_index;
442         } else {
443                 if (s->count == s->size && count > 0) /* rewind the buffer */
444                         s->count = count;
445                 rc = LLOG_PROC_BREAK;
446         }
447         RETURN(rc);
448 }
449
450 /**
451  * mdt_hsm_actions_proc_show() is called at for each seq record
452  * process the llog, with a cb which fill the file_seq buffer
453  * to be faster, one show will fill multiple records
454  */
455 static int mdt_hsm_actions_proc_show(struct seq_file *s, void *v)
456 {
457         struct agent_action_iterator    *aai = s->private;
458         struct coordinator              *cdt = &aai->aai_mdt->mdt_coordinator;
459         int                              rc;
460         ENTRY;
461
462         LASSERTF(aai->aai_magic == AGENT_ACTIONS_IT_MAGIC, "%08X",
463                  aai->aai_magic);
464
465         CDEBUG(D_HSM, "show from cat %d index %d eof=%d\n",
466                aai->aai_cat_index, aai->aai_index, aai->aai_eof);
467         if (aai->aai_eof)
468                 RETURN(0);
469
470         mutex_lock(&cdt->cdt_llog_lock);
471         rc = llog_cat_process(&aai->aai_env, aai->aai_ctxt->loc_handle,
472                               hsm_actions_show_cb, s,
473                               aai->aai_cat_index, aai->aai_index + 1);
474         mutex_unlock(&cdt->cdt_llog_lock);
475         if (rc == 0) /* all llog parsed */
476                 aai->aai_eof = true;
477         if (rc == LLOG_PROC_BREAK) /* buffer full */
478                 rc = 0;
479         RETURN(rc);
480 }
481
482 /**
483  * seq_file method called to stop access to /proc file
484  * clean + put llog context
485  */
486 static void mdt_hsm_actions_proc_stop(struct seq_file *s, void *v)
487 {
488         struct agent_action_iterator *aai = s->private;
489         ENTRY;
490
491         LASSERTF(aai->aai_magic == AGENT_ACTIONS_IT_MAGIC, "%08X",
492                  aai->aai_magic);
493
494         if (aai->aai_ctxt)
495                 llog_ctxt_put(aai->aai_ctxt);
496
497         EXIT;
498         return;
499 }
500
501 static const struct seq_operations mdt_hsm_actions_proc_ops = {
502         .start  = mdt_hsm_actions_proc_start,
503         .next   = mdt_hsm_actions_proc_next,
504         .show   = mdt_hsm_actions_proc_show,
505         .stop   = mdt_hsm_actions_proc_stop,
506 };
507
508 static int lprocfs_open_hsm_actions(struct inode *inode, struct file *file)
509 {
510         struct agent_action_iterator    *aai;
511         struct seq_file                 *s;
512         int                              rc;
513         struct mdt_device               *mdt;
514         ENTRY;
515
516         rc = seq_open(file, &mdt_hsm_actions_proc_ops);
517         if (rc)
518                 RETURN(rc);
519
520         OBD_ALLOC_PTR(aai);
521         if (aai == NULL)
522                 GOTO(err, rc = -ENOMEM);
523
524         aai->aai_magic = AGENT_ACTIONS_IT_MAGIC;
525         rc = lu_env_init(&aai->aai_env, LCT_LOCAL);
526         if (rc)
527                 GOTO(err, rc);
528
529         /* mdt is saved in proc_dir_entry->data by
530          * mdt_coordinator_procfs_init() calling lprocfs_register()
531          */
532         mdt = (struct mdt_device *)PDE_DATA(inode);
533         aai->aai_mdt = mdt;
534         s = file->private_data;
535         s->private = aai;
536
537         GOTO(out, rc = 0);
538
539 err:
540         lprocfs_seq_release(inode, file);
541         if (aai && aai->aai_env.le_ses)
542                 OBD_FREE_PTR(aai->aai_env.le_ses);
543         if (aai)
544                 OBD_FREE_PTR(aai);
545 out:
546         return rc;
547 }
548
549 /**
550  * lprocfs_release_hsm_actions() is called at end of /proc access.
551  * It frees allocated ressources and calls cleanup lprocfs methods.
552  */
553 static int lprocfs_release_hsm_actions(struct inode *inode, struct file *file)
554 {
555         struct seq_file                 *seq = file->private_data;
556         struct agent_action_iterator    *aai = seq->private;
557
558         if (aai) {
559                 lu_env_fini(&aai->aai_env);
560                 OBD_FREE_PTR(aai);
561         }
562
563         return lprocfs_seq_release(inode, file);
564 }
565
566 /* Methods to access HSM action list LLOG through /proc */
567 const struct file_operations mdt_hsm_actions_fops = {
568         .owner          = THIS_MODULE,
569         .open           = lprocfs_open_hsm_actions,
570         .read           = seq_read,
571         .llseek         = seq_lseek,
572         .release        = lprocfs_release_hsm_actions,
573 };
574