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