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