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