Whamcloud - gitweb
94bc265e8f8b56d473725b9ff4777d5d19c76db9
[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, 2016, 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 <obd_support.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=%#llx/%#llx"
56                " status=%s action=%s archive#=%d flags=%#llx"
57                " create=%llu change=%llu"
58                " extent=%#llx-%#llx gid=%#llx 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  * \param rw [IN] cdt_llog_lock mode (READ or WRITE)
84  * \retval 0 success
85  * \retval -ve failure
86  */
87 int cdt_llog_process(const struct lu_env *env, struct mdt_device *mdt,
88                      llog_cb_t cb, void *data, int rw)
89 {
90         struct obd_device       *obd = mdt2obd_dev(mdt);
91         struct llog_ctxt        *lctxt = NULL;
92         struct coordinator      *cdt = &mdt->mdt_coordinator;
93         int                      rc;
94         ENTRY;
95
96         lctxt = llog_get_context(obd, LLOG_AGENT_ORIG_CTXT);
97         if (lctxt == NULL || lctxt->loc_handle == NULL)
98                 RETURN(-ENOENT);
99
100         if (rw == READ)
101                 down_read(&cdt->cdt_llog_lock);
102         else
103                 down_write(&cdt->cdt_llog_lock);
104
105         rc = llog_cat_process(env, lctxt->loc_handle, cb, data, 0, 0);
106         if (rc < 0)
107                 CERROR("%s: failed to process HSM_ACTIONS llog (rc=%d)\n",
108                         mdt_obd_name(mdt), rc);
109         else
110                 rc = 0;
111
112         llog_ctxt_put(lctxt);
113
114         if (rw == READ)
115                 up_read(&cdt->cdt_llog_lock);
116         else
117                 up_write(&cdt->cdt_llog_lock);
118
119         RETURN(rc);
120 }
121
122 /**
123  * add an entry in agent llog
124  * \param env [IN] environment
125  * \param mdt [IN] PDT device
126  * \param compound_id [IN] global id associated with the record
127  * \param archive_id [IN] backend archive number
128  * \param hai [IN] record to register
129  * \retval 0 success
130  * \retval -ve failure
131  */
132 int mdt_agent_record_add(const struct lu_env *env,
133                          struct mdt_device *mdt,
134                          __u64 compound_id, __u32 archive_id,
135                          __u64 flags, struct hsm_action_item *hai)
136 {
137         struct obd_device               *obd = mdt2obd_dev(mdt);
138         struct coordinator              *cdt = &mdt->mdt_coordinator;
139         struct llog_ctxt                *lctxt = NULL;
140         struct llog_agent_req_rec       *larr;
141         int                              rc;
142         int                              sz;
143         ENTRY;
144
145         sz = llog_data_len(sizeof(*larr) + hai->hai_len - sizeof(*hai));
146         OBD_ALLOC(larr, sz);
147         if (!larr)
148                 RETURN(-ENOMEM);
149         larr->arr_hdr.lrh_len = sz;
150         larr->arr_hdr.lrh_type = HSM_AGENT_REC;
151         larr->arr_status = ARS_WAITING;
152         larr->arr_compound_id = compound_id;
153         larr->arr_archive_id = archive_id;
154         larr->arr_flags = flags;
155         larr->arr_req_create = cfs_time_current_sec();
156         larr->arr_req_change = larr->arr_req_create;
157         memcpy(&larr->arr_hai, hai, hai->hai_len);
158
159         lctxt = llog_get_context(obd, LLOG_AGENT_ORIG_CTXT);
160         if (lctxt == NULL || lctxt->loc_handle == NULL)
161                 GOTO(free, rc = -ENOENT);
162
163         down_write(&cdt->cdt_llog_lock);
164
165         /* in case of cancel request, the cookie is already set to the
166          * value of the request cookie to be cancelled
167          * so we do not change it */
168         if (hai->hai_action == HSMA_CANCEL) {
169                 larr->arr_hai.hai_cookie = hai->hai_cookie;
170         } else {
171                 cdt->cdt_last_cookie++;
172                 larr->arr_hai.hai_cookie = cdt->cdt_last_cookie;
173         }
174
175         rc = llog_cat_add(env, lctxt->loc_handle, &larr->arr_hdr, NULL);
176         if (rc > 0)
177                 rc = 0;
178
179         up_write(&cdt->cdt_llog_lock);
180         llog_ctxt_put(lctxt);
181
182         EXIT;
183 free:
184         OBD_FREE(larr, sz);
185         return rc;
186 }
187
188 /**
189  * data passed to llog_cat_process() callback
190  * to find requests
191  */
192 struct data_update_cb {
193         struct mdt_device       *mdt;
194         __u64                   *cookies;
195         int                      cookies_count;
196         int                      cookies_done;
197         enum agent_req_status    status;
198         cfs_time_t               change_time;
199 };
200
201 /**
202  *  llog_cat_process() callback, used to update a record
203  * \param env [IN] environment
204  * \param llh [IN] llog handle
205  * \param hdr [IN] llog record
206  * \param data [IN] cb data = data_update_cb
207  * \retval 0 success
208  * \retval -ve failure
209  */
210 static int mdt_agent_record_update_cb(const struct lu_env *env,
211                                       struct llog_handle *llh,
212                                       struct llog_rec_hdr *hdr,
213                                       void *data)
214 {
215         struct llog_agent_req_rec       *larr;
216         struct data_update_cb           *ducb;
217         int                              rc, i;
218         ENTRY;
219
220         larr = (struct llog_agent_req_rec *)hdr;
221         ducb = data;
222
223         /* check if all done */
224         if (ducb->cookies_count == ducb->cookies_done)
225                 RETURN(LLOG_PROC_BREAK);
226
227         /* if record is in final state, never change */
228         /* if record is a cancel request, it cannot be canceled
229          * this is to manage the following case:
230          * when a request is canceled, we have 2 records with the
231          * the same cookie : the one to cancel and the cancel request
232          * the 1st has to be set to ARS_CANCELED and the 2nd to ARS_SUCCEED
233          */
234         if (agent_req_in_final_state(larr->arr_status) ||
235             (larr->arr_hai.hai_action == HSMA_CANCEL &&
236              ducb->status == ARS_CANCELED))
237                 RETURN(0);
238
239         rc = 0;
240         for (i = 0 ; i < ducb->cookies_count ; i++) {
241                 CDEBUG(D_HSM, "%s: search %#llx, found %#llx\n",
242                        mdt_obd_name(ducb->mdt), ducb->cookies[i],
243                        larr->arr_hai.hai_cookie);
244                 if (larr->arr_hai.hai_cookie == ducb->cookies[i]) {
245
246                         larr->arr_status = ducb->status;
247                         larr->arr_req_change = ducb->change_time;
248                         rc = llog_write(env, llh, hdr, hdr->lrh_index);
249                         ducb->cookies_done++;
250                         break;
251                 }
252         }
253
254         if (rc < 0)
255                 CERROR("%s: mdt_agent_llog_update_rec() failed, rc = %d\n",
256                        mdt_obd_name(ducb->mdt), rc);
257
258         RETURN(rc);
259 }
260
261 /**
262  * update an entry in agent llog
263  * \param env [IN] environment
264  * \param mdt [IN] MDT device
265  * \param cookie [IN] entries to update
266  *    log cookie are returned by register
267  * \param status [IN] new status of the request
268  * \retval 0 success
269  * \retval -ve failure
270  */
271 int mdt_agent_record_update(const struct lu_env *env, struct mdt_device *mdt,
272                             __u64 *cookies, int cookies_count,
273                             enum agent_req_status status)
274 {
275         struct data_update_cb    ducb;
276         int                      rc;
277         ENTRY;
278
279         ducb.mdt = mdt;
280         ducb.cookies = cookies;
281         ducb.cookies_count = cookies_count;
282         ducb.cookies_done = 0;
283         ducb.status = status;
284         ducb.change_time = cfs_time_current_sec();
285
286         rc = cdt_llog_process(env, mdt, mdt_agent_record_update_cb, &ducb,
287                               WRITE);
288         if (rc < 0)
289                 CERROR("%s: cdt_llog_process() failed, rc=%d, cannot update "
290                        "status to %s for %d cookies, done %d\n",
291                        mdt_obd_name(mdt), rc,
292                        agent_req_status2name(status),
293                        cookies_count, ducb.cookies_done);
294         RETURN(rc);
295 }
296
297 /*
298  * Agent actions /proc seq_file methods
299  * As llog processing uses a callback for each entry, we cannot do a sequential
300  * read. To limit calls to llog_cat_process (it spawns a thread), we fill
301  * multiple record in seq_file buffer in one show call.
302  * op->start() sets the iterator up and returns the first element of sequence
303  * op->stop() shuts it down.
304  * op->show() iterate llog and print element into the buffer.
305  * In case of error ->start() and ->next() return ERR_PTR(error)
306  * In the end of sequence they return %NULL
307  * op->show() returns 0 in case of success and negative number in case of error.
308  *
309  */
310 /**
311  * seq_file iterator for agent_action entry
312  */
313 #define AGENT_ACTIONS_IT_MAGIC 0x19660426
314 struct agent_action_iterator {
315         int                      aai_magic;      /**< magic number */
316         bool                     aai_eof;        /**< all done */
317         struct lu_env            aai_env;        /**< lustre env for llog */
318         struct mdt_device       *aai_mdt;        /**< metadata device */
319         struct llog_ctxt        *aai_ctxt;       /**< llog context */
320         int                      aai_cat_index;  /**< cata idx already shown */
321         int                      aai_index;      /**< idx in cata shown */
322 };
323
324 /**
325  * seq_file method called to start access to /proc file
326  * get llog context + llog handle
327  */
328 static void *mdt_hsm_actions_proc_start(struct seq_file *s, loff_t *pos)
329 {
330         struct agent_action_iterator    *aai = s->private;
331         ENTRY;
332
333         LASSERTF(aai->aai_magic == AGENT_ACTIONS_IT_MAGIC, "%08X\n",
334                  aai->aai_magic);
335
336         aai->aai_ctxt = llog_get_context(mdt2obd_dev(aai->aai_mdt),
337                                          LLOG_AGENT_ORIG_CTXT);
338         if (aai->aai_ctxt == NULL || aai->aai_ctxt->loc_handle == NULL) {
339                 CERROR("llog_get_context() failed\n");
340                 RETURN(ERR_PTR(-ENOENT));
341         }
342
343         CDEBUG(D_HSM, "llog successfully initialized, start from %lld\n",
344                *pos);
345         /* first call = rewind */
346         if (*pos == 0) {
347                 aai->aai_cat_index = 0;
348                 aai->aai_index = 0;
349                 aai->aai_eof = false;
350                 *pos = 1;
351         }
352
353         if (aai->aai_eof)
354                 RETURN(NULL);
355
356         RETURN(aai);
357 }
358
359 static void *mdt_hsm_actions_proc_next(struct seq_file *s, void *v,
360                                          loff_t *pos)
361 {
362         RETURN(NULL);
363 }
364
365 /**
366  *  llog_cat_process() callback, used to fill a seq_file buffer
367  */
368 static int hsm_actions_show_cb(const struct lu_env *env,
369                                  struct llog_handle *llh,
370                                  struct llog_rec_hdr *hdr,
371                                  void *data)
372 {
373         struct llog_agent_req_rec    *larr = (struct llog_agent_req_rec *)hdr;
374         struct seq_file              *s = data;
375         struct agent_action_iterator *aai;
376         int                           sz;
377         char                          buf[12];
378         ENTRY;
379
380         aai = s->private;
381         LASSERTF(aai->aai_magic == AGENT_ACTIONS_IT_MAGIC, "%08X\n",
382                  aai->aai_magic);
383
384         /* if rec already printed => skip */
385         if (unlikely(llh->lgh_hdr->llh_cat_idx < aai->aai_cat_index))
386                 RETURN(0);
387
388         if (unlikely(llh->lgh_hdr->llh_cat_idx == aai->aai_cat_index &&
389                      hdr->lrh_index <= aai->aai_index))
390                 RETURN(0);
391
392         sz = larr->arr_hai.hai_len - sizeof(larr->arr_hai);
393         seq_printf(s, "lrh=[type=%X len=%d idx=%d/%d] fid="DFID
394                    " dfid="DFID" compound/cookie=%#llx/%#llx"
395                    " action=%s archive#=%d flags=%#llx"
396                    " extent=%#llx-%#llx"
397                    " gid=%#llx datalen=%d status=%s data=[%s]\n",
398                    hdr->lrh_type, hdr->lrh_len,
399                    llh->lgh_hdr->llh_cat_idx, hdr->lrh_index,
400                    PFID(&larr->arr_hai.hai_fid),
401                    PFID(&larr->arr_hai.hai_dfid),
402                    larr->arr_compound_id, larr->arr_hai.hai_cookie,
403                    hsm_copytool_action2name(larr->arr_hai.hai_action),
404                    larr->arr_archive_id,
405                    larr->arr_flags,
406                    larr->arr_hai.hai_extent.offset,
407                    larr->arr_hai.hai_extent.length,
408                    larr->arr_hai.hai_gid, sz,
409                    agent_req_status2name(larr->arr_status),
410                    hai_dump_data_field(&larr->arr_hai, buf, sizeof(buf)));
411
412         aai->aai_cat_index = llh->lgh_hdr->llh_cat_idx;
413         aai->aai_index = hdr->lrh_index;
414
415         RETURN(0);
416 }
417
418 /**
419  * mdt_hsm_actions_proc_show() is called at for each seq record
420  * process the llog, with a cb which fill the file_seq buffer
421  * to be faster, one show will fill multiple records
422  */
423 static int mdt_hsm_actions_proc_show(struct seq_file *s, void *v)
424 {
425         struct agent_action_iterator    *aai = s->private;
426         struct coordinator              *cdt = &aai->aai_mdt->mdt_coordinator;
427         int                              rc;
428         ENTRY;
429
430         LASSERTF(aai->aai_magic == AGENT_ACTIONS_IT_MAGIC, "%08X\n",
431                  aai->aai_magic);
432
433         CDEBUG(D_HSM, "show from cat %d index %d eof=%d\n",
434                aai->aai_cat_index, aai->aai_index, aai->aai_eof);
435         if (aai->aai_eof)
436                 RETURN(0);
437
438         down_read(&cdt->cdt_llog_lock);
439         rc = llog_cat_process(&aai->aai_env, aai->aai_ctxt->loc_handle,
440                               hsm_actions_show_cb, s,
441                               aai->aai_cat_index, aai->aai_index);
442         up_read(&cdt->cdt_llog_lock);
443         if (rc == 0) /* all llog parsed */
444                 aai->aai_eof = true;
445         if (rc == LLOG_PROC_BREAK) /* buffer full */
446                 rc = 0;
447         RETURN(rc);
448 }
449
450 /**
451  * seq_file method called to stop access to /proc file
452  * clean + put llog context
453  */
454 static void mdt_hsm_actions_proc_stop(struct seq_file *s, void *v)
455 {
456         struct agent_action_iterator *aai = s->private;
457         ENTRY;
458
459         LASSERTF(aai->aai_magic == AGENT_ACTIONS_IT_MAGIC, "%08X\n",
460                  aai->aai_magic);
461
462         if (aai->aai_ctxt)
463                 llog_ctxt_put(aai->aai_ctxt);
464
465         EXIT;
466         return;
467 }
468
469 static const struct seq_operations mdt_hsm_actions_proc_ops = {
470         .start  = mdt_hsm_actions_proc_start,
471         .next   = mdt_hsm_actions_proc_next,
472         .show   = mdt_hsm_actions_proc_show,
473         .stop   = mdt_hsm_actions_proc_stop,
474 };
475
476 static int lprocfs_open_hsm_actions(struct inode *inode, struct file *file)
477 {
478         struct agent_action_iterator    *aai;
479         struct seq_file                 *s;
480         int                              rc;
481         struct mdt_device               *mdt;
482         ENTRY;
483
484         rc = seq_open(file, &mdt_hsm_actions_proc_ops);
485         if (rc)
486                 RETURN(rc);
487
488         OBD_ALLOC_PTR(aai);
489         if (aai == NULL)
490                 GOTO(err, rc = -ENOMEM);
491
492         aai->aai_magic = AGENT_ACTIONS_IT_MAGIC;
493         rc = lu_env_init(&aai->aai_env, LCT_LOCAL);
494         if (rc)
495                 GOTO(err, rc);
496
497         /* mdt is saved in proc_dir_entry->data by
498          * mdt_coordinator_procfs_init() calling lprocfs_register()
499          */
500         mdt = (struct mdt_device *)PDE_DATA(inode);
501         aai->aai_mdt = mdt;
502         s = file->private_data;
503         s->private = aai;
504
505         GOTO(out, rc = 0);
506
507 err:
508         lprocfs_seq_release(inode, file);
509         if (aai && aai->aai_env.le_ses)
510                 OBD_FREE_PTR(aai->aai_env.le_ses);
511         if (aai)
512                 OBD_FREE_PTR(aai);
513 out:
514         return rc;
515 }
516
517 /**
518  * lprocfs_release_hsm_actions() is called at end of /proc access.
519  * It frees allocated resources and calls cleanup lprocfs methods.
520  */
521 static int lprocfs_release_hsm_actions(struct inode *inode, struct file *file)
522 {
523         struct seq_file                 *seq = file->private_data;
524         struct agent_action_iterator    *aai = seq->private;
525
526         if (aai) {
527                 lu_env_fini(&aai->aai_env);
528                 OBD_FREE_PTR(aai);
529         }
530
531         return lprocfs_seq_release(inode, file);
532 }
533
534 /* Methods to access HSM action list LLOG through /proc */
535 const struct file_operations mdt_hsm_actions_fops = {
536         .owner          = THIS_MODULE,
537         .open           = lprocfs_open_hsm_actions,
538         .read           = seq_read,
539         .llseek         = seq_lseek,
540         .release        = lprocfs_release_hsm_actions,
541 };
542