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