Whamcloud - gitweb
LU-3711 mdt: default archive id is tunable
[fs/lustre-release.git] / lustre / mdt / mdt_hsm_cdt_client.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_client.c
29  *
30  * Lustre HSM Coordinator
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 <obd_lov.h>
43 #include <lprocfs_status.h>
44 #include <lustre_log.h>
45 #include "mdt_internal.h"
46
47 /**
48  * data passed to llog_cat_process() callback
49  * to find compatible requests
50  */
51 struct hsm_compat_data_cb {
52         struct coordinator      *cdt;
53         struct hsm_action_list  *hal;
54 };
55
56 /**
57  * llog_cat_process() callback, used to find record
58  * compatibles with a new hsm_action_list
59  * \param env [IN] environment
60  * \param llh [IN] llog handle
61  * \param hdr [IN] llog record
62  * \param data [IN] cb data = hsm_compat_data_cb
63  * \retval 0 success
64  * \retval -ve failure
65  */
66 static int hsm_find_compatible_cb(const struct lu_env *env,
67                                   struct llog_handle *llh,
68                                   struct llog_rec_hdr *hdr, void *data)
69 {
70         struct llog_agent_req_rec       *larr;
71         struct hsm_compat_data_cb       *hcdcb;
72         struct hsm_action_item          *hai;
73         int                              i;
74         ENTRY;
75
76         larr = (struct llog_agent_req_rec *)hdr;
77         hcdcb = data;
78         /* a compatible request must be WAITING or STARTED
79          * and not a cancel */
80         if ((larr->arr_status != ARS_WAITING &&
81              larr->arr_status != ARS_STARTED) ||
82             larr->arr_hai.hai_action == HSMA_CANCEL)
83                 RETURN(0);
84
85         hai = hai_first(hcdcb->hal);
86         for (i = 0; i < hcdcb->hal->hal_count; i++, hai = hai_next(hai)) {
87                 /* if request is a CANCEL:
88                  * if cookie set in the request, there is no need to find a
89                  * compatible one, the cookie in the request is directly used.
90                  * if cookie is not set, we use the FID to find the request
91                  * to cancel (the "compatible" one)
92                  * if the caller sets the cookie, we assume he also sets the
93                  * arr_archive_id
94                  */
95                 if (hai->hai_action == HSMA_CANCEL && hai->hai_cookie != 0)
96                         continue;
97
98                 if (!lu_fid_eq(&hai->hai_fid, &larr->arr_hai.hai_fid))
99                         continue;
100
101                 /* HSMA_NONE is used to find running request for some FID */
102                 if (hai->hai_action == HSMA_NONE) {
103                         hcdcb->hal->hal_archive_id = larr->arr_archive_id;
104                         hcdcb->hal->hal_flags = larr->arr_flags;
105                         *hai = larr->arr_hai;
106                         continue;
107                 }
108                 /* in V1 we do not manage partial transfer
109                  * so extent is always whole file
110                  */
111                 hai->hai_cookie = larr->arr_hai.hai_cookie;
112                 /* we read the archive number from the request we cancel */
113                 if (hai->hai_action == HSMA_CANCEL &&
114                     hcdcb->hal->hal_archive_id == 0)
115                         hcdcb->hal->hal_archive_id = larr->arr_archive_id;
116         }
117         RETURN(0);
118 }
119
120 /**
121  * find compatible requests already recorded
122  * \param env [IN] environment
123  * \param mdt [IN] MDT device
124  * \param hal [IN/OUT] new request
125  *    cookie set to compatible found or to 0 if not found
126  *    for cancel request, see callback hsm_find_compatible_cb()
127  * \retval 0 success
128  * \retval -ve failure
129  */
130 static int hsm_find_compatible(const struct lu_env *env, struct mdt_device *mdt,
131                                struct hsm_action_list *hal)
132 {
133         struct hsm_action_item          *hai;
134         struct hsm_compat_data_cb        hcdcb;
135         int                              rc, i, ok_cnt;
136         ENTRY;
137
138         ok_cnt = 0;
139         hai = hai_first(hal);
140         for (i = 0; i < hal->hal_count; i++, hai = hai_next(hai)) {
141                 /* in a cancel request hai_cookie may be set by caller to
142                  * show the request to be canceled
143                  * if not we need to search by FID
144                  */
145                 if (hai->hai_action == HSMA_CANCEL && hai->hai_cookie != 0)
146                         ok_cnt++;
147                 else
148                         hai->hai_cookie = 0;
149         }
150
151         /* if all requests are cancel with cookie, no need to find compatible */
152         if (ok_cnt == hal->hal_count)
153                 RETURN(0);
154
155         hcdcb.cdt = &mdt->mdt_coordinator;
156         hcdcb.hal = hal;
157
158         rc = cdt_llog_process(env, mdt, hsm_find_compatible_cb, &hcdcb);
159
160         RETURN(rc);
161 }
162
163 /**
164  * check if an action is really needed
165  * \param hai [IN] request description
166  * \param hal_an [IN] request archive number (not used)
167  * \param rq_flags [IN] request flags
168  * \param hsm [IN] file HSM metadata
169  * \retval boolean
170  */
171 static bool hsm_action_is_needed(struct hsm_action_item *hai, int hal_an,
172                                  __u64 rq_flags, struct md_hsm *hsm)
173 {
174         bool     is_needed = false;
175         int      hsm_flags;
176         ENTRY;
177
178         if (rq_flags & HSM_FORCE_ACTION)
179                 RETURN(true);
180
181         hsm_flags = hsm->mh_flags;
182         switch (hai->hai_action) {
183         case HSMA_ARCHIVE:
184                 if (hsm_flags & HS_DIRTY || !(hsm_flags & HS_ARCHIVED))
185                         is_needed = true;
186                 break;
187         case HSMA_RESTORE:
188                 /* if file is dirty we must return an error, this function
189                  * cannot, so we ask for an action and
190                  * mdt_hsm_is_action_compat() will return an error
191                  */
192                 if (hsm_flags & (HS_RELEASED | HS_DIRTY))
193                         is_needed = true;
194                 break;
195         case HSMA_REMOVE:
196                 if (hsm_flags & (HS_ARCHIVED | HS_EXISTS))
197                         is_needed = true;
198                 break;
199         case HSMA_CANCEL:
200                 is_needed = true;
201                 break;
202         }
203         CDEBUG(D_HSM, "fid="DFID" action=%s rq_flags="LPX64
204                       " extent="LPX64"-"LPX64" hsm_flags=%X %s\n",
205                       PFID(&hai->hai_fid),
206                       hsm_copytool_action2name(hai->hai_action), rq_flags,
207                       hai->hai_extent.offset, hai->hai_extent.length,
208                       hsm->mh_flags,
209                       (is_needed ? "action needed" : "no action needed"));
210
211         RETURN(is_needed);
212 }
213
214 /**
215  * test sanity of an hal
216  * FID must be valid
217  * action must be known
218  * \param hal [IN]
219  * \retval boolean
220  */
221 static bool hal_is_sane(struct hsm_action_list *hal)
222 {
223         int                      i;
224         struct hsm_action_item  *hai;
225         ENTRY;
226
227         if (hal->hal_count == 0)
228                 RETURN(false);
229
230         hai = hai_first(hal);
231         for (i = 0; i < hal->hal_count; i++, hai = hai_next(hai)) {
232                 if (!fid_is_sane(&hai->hai_fid))
233                         RETURN(false);
234                 switch (hai->hai_action) {
235                 case HSMA_NONE:
236                 case HSMA_ARCHIVE:
237                 case HSMA_RESTORE:
238                 case HSMA_REMOVE:
239                 case HSMA_CANCEL:
240                         break;
241                 default:
242                         RETURN(false);
243                 }
244         }
245         RETURN(true);
246 }
247
248 /*
249  * Coordinator external API
250  */
251
252 /**
253  * register a list of requests
254  * \param mti [IN]
255  * \param hal [IN] list of requests
256  * \param compound_id [OUT] id of the compound request
257  * \retval 0 success
258  * \retval -ve failure
259  * in case of restore, caller must hold layout lock
260  */
261 int mdt_hsm_add_actions(struct mdt_thread_info *mti,
262                         struct hsm_action_list *hal, __u64 *compound_id)
263 {
264         struct mdt_device       *mdt = mti->mti_mdt;
265         struct coordinator      *cdt = &mdt->mdt_coordinator;
266         struct hsm_action_item  *hai;
267         struct mdt_object       *obj = NULL;
268         int                      rc = 0, i;
269         struct md_hsm            mh;
270         bool                     is_restore = false;
271         ENTRY;
272
273         /* no coordinator started, so we cannot serve requests */
274         if (cdt->cdt_state == CDT_STOPPED)
275                 RETURN(-EAGAIN);
276
277         if (!hal_is_sane(hal))
278                 RETURN(-EINVAL);
279
280         *compound_id = atomic_inc_return(&cdt->cdt_compound_id);
281
282         /* search for compatible request, if found hai_cookie is set
283          * to the request cookie
284          * it is also used to set the cookie for cancel request by FID
285          */
286         rc = hsm_find_compatible(mti->mti_env, mdt, hal);
287         if (rc)
288                 GOTO(out, rc);
289
290         hai = hai_first(hal);
291         for (i = 0; i < hal->hal_count; i++, hai = hai_next(hai)) {
292                 int archive_id;
293                 __u64 flags;
294
295                 /* default archive number is the one explicitly specified */
296                 archive_id = hal->hal_archive_id;
297                 flags = hal->hal_flags;
298
299                 /* by default, data FID is same as Lustre FID */
300                 /* the volatile data FID will be created by copy tool and
301                  * send from the agent through the progress call */
302                 hai->hai_dfid = hai->hai_fid;
303
304                 /* done here to manage first and redundant requests cases */
305                 if (hai->hai_action == HSMA_RESTORE)
306                         is_restore = true;
307
308                 /* test result of hsm_find_compatible()
309                  * if request redundant or cancel of nothing
310                  * do not record
311                  */
312                 /* redundant case */
313                 if (hai->hai_action != HSMA_CANCEL && hai->hai_cookie != 0)
314                         continue;
315                 /* cancel nothing case */
316                 if (hai->hai_action == HSMA_CANCEL && hai->hai_cookie == 0)
317                         continue;
318
319                 /* new request or cancel request
320                  * we search for HSM status flags to check for compatibility
321                  * if restore, we take the layout lock
322                  */
323
324                 /* if action is cancel, also no need to check */
325                 if (hai->hai_action == HSMA_CANCEL)
326                         goto record;
327
328                 /* get HSM attributes */
329                 obj = mdt_hsm_get_md_hsm(mti, &hai->hai_fid, &mh);
330                 if (IS_ERR(obj) || obj == NULL) {
331                         /* in case of archive remove, Lustre file
332                          * is not mandatory */
333                         if (hai->hai_action == HSMA_REMOVE)
334                                 goto record;
335                         if (obj == NULL)
336                                 GOTO(out, rc = -ENOENT);
337                         GOTO(out, rc = PTR_ERR(obj));
338                 }
339                 mdt_object_put(mti->mti_env, obj);
340
341                 /* Check if an action is needed, compare request
342                  * and HSM flags status */
343                 if (!hsm_action_is_needed(hai, archive_id, flags, &mh))
344                         continue;
345
346                 /* Check if file request is compatible with HSM flags status
347                  * and stop at first incompatible
348                  */
349                 if (!mdt_hsm_is_action_compat(hai, archive_id, flags, &mh))
350                         GOTO(out, rc = -EPERM);
351
352                 /* for cancel archive number is taken from canceled request
353                  * for other request, we take from lma if not specified,
354                  * or we use the default if none found in lma
355                  * this works also for archive because the default value is 0
356                  * /!\ there is a side effect: in case of restore on multiple
357                  * files which are in different backend, the initial compound
358                  * request will be split in multiple requests because we cannot
359                  * warranty an agent can serve any combinaison of archive
360                  * backend
361                  */
362                 if (hai->hai_action != HSMA_CANCEL && archive_id == 0) {
363                         if (mh.mh_arch_id != 0)
364                                 archive_id = mh.mh_arch_id;
365                         else
366                                 archive_id = cdt->cdt_archive_id;
367                 }
368
369                 /* if restore, take an exclusive lock on layout */
370                 if (hai->hai_action == HSMA_RESTORE) {
371                         struct cdt_restore_handle       *crh;
372                         struct mdt_object               *child;
373
374                         OBD_SLAB_ALLOC_PTR(crh, mdt_hsm_cdt_kmem);
375                         if (crh == NULL)
376                                 GOTO(out, rc = -ENOMEM);
377
378                         crh->crh_fid = hai->hai_fid;
379                         /* in V1 only whole file is supported
380                         crh->extent.start = hai->hai_extent.offset;
381                         crh->extent.end = hai->hai_extent.offset +
382                                             hai->hai_extent.length;
383                          */
384                         crh->crh_extent.start = 0;
385                         crh->crh_extent.end = OBD_OBJECT_EOF;
386
387                         mdt_lock_reg_init(&crh->crh_lh, LCK_EX);
388                         child = mdt_object_find_lock(mti, &crh->crh_fid,
389                                                      &crh->crh_lh,
390                                                      MDS_INODELOCK_LAYOUT);
391                         if (IS_ERR(child)) {
392                                 rc = PTR_ERR(child);
393                                 CERROR("%s: cannot take layout lock for "
394                                        DFID": rc = %d\n", mdt_obd_name(mdt),
395                                        PFID(&crh->crh_fid), rc);
396                                 OBD_SLAB_FREE_PTR(crh, mdt_hsm_cdt_kmem);
397                                 GOTO(out, rc);
398                         }
399                         /* we choose to not keep a keep a reference
400                          * on the object during the restore time which can be
401                          * very long */
402                         mdt_object_put(mti->mti_env, child);
403
404                         mutex_lock(&cdt->cdt_restore_lock);
405                         list_add_tail(&crh->crh_list, &cdt->cdt_restore_hdl);
406                         mutex_unlock(&cdt->cdt_restore_lock);
407                 }
408 record:
409                 /* record request */
410                 rc = mdt_agent_record_add(mti->mti_env, mdt, *compound_id,
411                                           archive_id, flags, hai);
412                 if (rc)
413                         GOTO(out, rc);
414         }
415         if (is_restore &&
416             (cdt->cdt_policy & CDT_NONBLOCKING_RESTORE))
417                 rc = -ENODATA;
418         else
419                 rc = 0;
420
421         GOTO(out, rc);
422 out:
423         /* if work has been added, wake up coordinator */
424         if (rc == 0 || rc == -ENODATA)
425                 mdt_hsm_cdt_wakeup(mdt);
426
427         return rc;
428 }
429
430 /**
431  * get running action on a FID list or from cookie
432  * \param mti [IN]
433  * \param hal [IN/OUT] requests
434  * \retval 0 success
435  * \retval -ve failure
436  */
437 int mdt_hsm_get_running(struct mdt_thread_info *mti,
438                         struct hsm_action_list *hal)
439 {
440         struct mdt_device       *mdt = mti->mti_mdt;
441         struct coordinator      *cdt = &mdt->mdt_coordinator;
442         struct hsm_action_item  *hai;
443         int                      i;
444         ENTRY;
445
446         hai = hai_first(hal);
447         for (i = 0; i < hal->hal_count; i++, hai = hai_next(hai)) {
448                 struct cdt_agent_req *car;
449
450                 if (!fid_is_sane(&hai->hai_fid))
451                         RETURN(-EINVAL);
452
453                 car = mdt_cdt_find_request(cdt, 0, &hai->hai_fid);
454                 if (car == NULL) {
455                         hai->hai_cookie = 0;
456                         hai->hai_action = HSMA_NONE;
457                 } else {
458                         *hai = *car->car_hai;
459                         mdt_cdt_put_request(car);
460                 }
461         }
462         RETURN(0);
463 }
464
465 /**
466  * check if a restore is running on a FID
467  * this is redundant with mdt_hsm_coordinator_get_running()
468  * but as it can be called frequently when getting attr
469  * we make an optimized/simpler version only for a FID
470  * \param mti [IN]
471  * \param fid [IN] file FID
472  * \retval boolean
473  */
474 bool mdt_hsm_restore_is_running(struct mdt_thread_info *mti,
475                                 const struct lu_fid *fid)
476 {
477         struct mdt_device               *mdt = mti->mti_mdt;
478         struct coordinator              *cdt = &mdt->mdt_coordinator;
479         struct cdt_restore_handle       *crh;
480         bool                             rc = false;
481         ENTRY;
482
483         if (!fid_is_sane(fid))
484                 RETURN(rc);
485
486         mutex_lock(&cdt->cdt_restore_lock);
487         list_for_each_entry(crh, &cdt->cdt_restore_hdl, crh_list) {
488                 if (lu_fid_eq(&crh->crh_fid, fid)) {
489                         rc = true;
490                         break;
491                 }
492         }
493         mutex_unlock(&cdt->cdt_restore_lock);
494         RETURN(rc);
495 }
496
497 /**
498  * get registered action on a FID list
499  * \param mti [IN]
500  * \param hal [IN/OUT] requests
501  * \retval 0 success
502  * \retval -ve failure
503  */
504 int mdt_hsm_get_actions(struct mdt_thread_info *mti,
505                         struct hsm_action_list *hal)
506 {
507         struct mdt_device       *mdt = mti->mti_mdt;
508         struct coordinator      *cdt = &mdt->mdt_coordinator;
509         struct hsm_action_item  *hai;
510         int                      i, rc;
511         ENTRY;
512
513         hai = hai_first(hal);
514         for (i = 0; i < hal->hal_count; i++, hai = hai_next(hai)) {
515                 hai->hai_action = HSMA_NONE;
516                 if (!fid_is_sane(&hai->hai_fid))
517                         RETURN(-EINVAL);
518         }
519
520         /* 1st we search in recorded requests */
521         rc = hsm_find_compatible(mti->mti_env, mdt, hal);
522         /* if llog file is not created, no action is recorded */
523         if (rc == -ENOENT)
524                 RETURN(0);
525
526         if (rc)
527                 RETURN(rc);
528
529         /* 2nd we search if the request are running
530          * cookie is cleared to tell to caller, the request is
531          * waiting
532          * we could in place use the record status, but in the future
533          * we may want do give back dynamic informations on the
534          * running request
535          */
536         hai = hai_first(hal);
537         for (i = 0; i < hal->hal_count; i++, hai = hai_next(hai)) {
538                 struct cdt_agent_req *car;
539
540                 car = mdt_cdt_find_request(cdt, hai->hai_cookie, NULL);
541                 if (car == NULL) {
542                         hai->hai_cookie = 0;
543                 } else {
544                         __u64 data_moved;
545
546                         mdt_cdt_get_work_done(car, &data_moved);
547                         /* this is just to give the volume of data moved
548                          * it means data_moved data have been moved from the
549                          * original request but we do not know which one
550                          */
551                         hai->hai_extent.length = data_moved;
552                         mdt_cdt_put_request(car);
553                 }
554         }
555
556         RETURN(0);
557 }
558