Whamcloud - gitweb
face8368366a585cf55331b88fbff25adee63fb5
[fs/lustre-release.git] / lustre / mdt / mdt_hsm.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  * Copyright (c) 2012, Intel Corporation.
24  * Use is subject to license terms.
25  * Copyright (c) 2011, 2012 Commissariat a l'energie atomique et aux energies
26  *                          alternatives
27  */
28 /*
29  * lustre/mdt/mdt_hsm.c
30  *
31  * Lustre Metadata Target (mdt) request handler
32  *
33  * Author: Aurelien Degremont <aurelien.degremont@cea.fr>
34  * Author: JC Lafoucriere <jacques-charles.lafoucriere@cea.fr>
35  */
36
37 #ifndef EXPORT_SYMTAB
38 # define EXPORT_SYMTAB
39 #endif
40 #define DEBUG_SUBSYSTEM S_MDS
41
42 #include "mdt_internal.h"
43
44 /*
45  * fake functions, will be replace by real one with HSM Coordinator patch
46  */
47
48 int mdt_hsm_copytool_send(struct obd_export *exp)
49 {
50         return 0;
51 }
52
53 static int mdt_hsm_coordinator_update(struct mdt_thread_info *info,
54                                       struct hsm_progress_kernel *pgs)
55 {
56         return 0;
57 }
58
59 static int mdt_hsm_agent_register_mask(struct mdt_thread_info *info,
60                                        struct obd_uuid *uuid,
61                                        __u32 archive_mask)
62 {
63         return 0;
64 }
65
66 static int mdt_hsm_agent_unregister(struct mdt_thread_info *info,
67                                     struct obd_uuid *uuid)
68 {
69         return 0;
70 }
71
72 static int mdt_hsm_coordinator_get_actions(struct mdt_thread_info *mti,
73                                            struct hsm_action_list *hal)
74 {
75         return 0;
76 }
77
78 static int mdt_hsm_coordinator_actions(struct mdt_thread_info *info,
79                                        struct hsm_action_list *hal,
80                                        __u64 *compound_id,
81                                        int mti_attr_is_valid)
82 {
83         return 0;
84 }
85
86 /**
87  * Update on-disk HSM attributes.
88  */
89 int mdt_hsm_attr_set(struct mdt_thread_info *info, struct mdt_object *obj,
90                      struct md_hsm *mh)
91 {
92         struct md_object        *next = mdt_object_child(obj);
93         struct lu_buf           *buf = &info->mti_buf;
94         struct hsm_attrs        *attrs;
95         int                      rc;
96         ENTRY;
97
98         attrs = (struct hsm_attrs *)info->mti_xattr_buf;
99         CLASSERT(sizeof(info->mti_xattr_buf) >= sizeof(*attrs));
100
101         /* pack HSM attributes */
102         lustre_hsm2buf(info->mti_xattr_buf, mh);
103
104         /* update SOM attributes */
105         buf->lb_buf = attrs;
106         buf->lb_len = sizeof(*attrs);
107         rc = mo_xattr_set(info->mti_env, next, buf, XATTR_NAME_HSM, 0);
108
109         RETURN(rc);
110 }
111
112 /**
113  * Extract information coming from a copytool and asks coordinator to update
114  * a request status depending on the update content.
115  *
116  * Copytools could use this to report failure in their process.
117  *
118  * This is HSM_PROGRESS RPC handler.
119  */
120 int mdt_hsm_progress(struct mdt_thread_info *info)
121 {
122         struct hsm_progress_kernel      *hpk;
123         int                              rc;
124         ENTRY;
125
126         hpk = req_capsule_client_get(info->mti_pill, &RMF_MDS_HSM_PROGRESS);
127         LASSERT(hpk);
128
129         CDEBUG(D_HSM, "Progress on "DFID": len="LPU64" err=%d\n",
130                PFID(&hpk->hpk_fid), hpk->hpk_extent.length, hpk->hpk_errval);
131
132         if (hpk->hpk_errval)
133                 CDEBUG(D_HSM, "Copytool progress on "DFID" failed (%d); %s.\n",
134                        PFID(&hpk->hpk_fid), hpk->hpk_errval,
135                        hpk->hpk_flags & HP_FLAG_RETRY ? "will retry" : "fatal");
136
137         if (hpk->hpk_flags & HP_FLAG_COMPLETED)
138                 CDEBUG(D_HSM, "Finished "DFID" (%d) cancel cookie="LPX64"\n",
139                        PFID(&hpk->hpk_fid), hpk->hpk_errval, hpk->hpk_cookie);
140
141         rc = mdt_hsm_coordinator_update(info, hpk);
142
143         RETURN(rc);
144 }
145
146 int mdt_hsm_ct_register(struct mdt_thread_info *info)
147 {
148         struct ptlrpc_request *req = mdt_info_req(info);
149         __u32 *archives;
150         int rc;
151         ENTRY;
152
153         archives = req_capsule_client_get(info->mti_pill, &RMF_MDS_HSM_ARCHIVE);
154         LASSERT(archives);
155
156         /* XXX: directly include this function here? */
157         rc = mdt_hsm_agent_register_mask(info, &req->rq_export->exp_client_uuid,
158                                          *archives);
159
160         RETURN(rc);
161 }
162
163 int mdt_hsm_ct_unregister(struct mdt_thread_info *info)
164 {
165         struct ptlrpc_request *req = mdt_info_req(info);
166         int rc;
167         ENTRY;
168
169         /* XXX: directly include this function here? */
170         rc = mdt_hsm_agent_unregister(info, &req->rq_export->exp_client_uuid);
171
172         RETURN(rc);
173 }
174
175
176 /**
177  * Retrieve the current HSM flags, archive id and undergoing HSM requests for
178  * the fid provided in RPC body.
179  *
180  * Current requests are read from coordinator states.
181  *
182  * This is MDS_HSM_STATE_GET RPC handler.
183  */
184 int mdt_hsm_state_get(struct mdt_thread_info *info)
185 {
186         struct mdt_object       *obj = info->mti_object;
187         struct md_attr          *ma  = &info->mti_attr;
188         struct hsm_user_state   *hus;
189         struct mdt_lock_handle  *lh;
190         int                      rc;
191         ENTRY;
192
193         lh = &info->mti_lh[MDT_LH_CHILD];
194         mdt_lock_reg_init(lh, LCK_PR);
195         rc = mdt_object_lock(info, obj, lh, MDS_INODELOCK_LOOKUP,
196                              MDT_LOCAL_LOCK);
197         if (rc)
198                 RETURN(rc);
199
200         /* Only valid if client is remote */
201         rc = mdt_init_ucred(info, (struct mdt_body *)info->mti_body);
202         if (rc)
203                 GOTO(out_unlock, rc = err_serious(rc));
204
205         ma->ma_valid = 0;
206         ma->ma_need = MA_HSM;
207         rc = mdt_attr_get_complex(info, obj, ma);
208         if (rc)
209                 GOTO(out_ucred, rc);
210
211         if (req_capsule_get_size(info->mti_pill, &RMF_CAPA1, RCL_CLIENT))
212                 mdt_set_capainfo(info, 0, &info->mti_body->fid1,
213                             req_capsule_client_get(info->mti_pill, &RMF_CAPA1));
214
215         hus = req_capsule_server_get(info->mti_pill, &RMF_HSM_USER_STATE);
216         LASSERT(hus);
217
218         /* Current HSM flags */
219         hus->hus_states = ma->ma_hsm.mh_flags;
220         hus->hus_archive_id = ma->ma_hsm.mh_arch_id;
221
222         EXIT;
223 out_ucred:
224         mdt_exit_ucred(info);
225 out_unlock:
226         mdt_object_unlock(info, obj, lh, 1);
227         return rc;
228 }
229
230 /**
231  * Change HSM state and archive number of a file.
232  *
233  * Archive number is changed iif the value is not 0.
234  * The new flagset that will be computed should result in a coherent state.
235  * This function checks that are flags are compatible.
236  *
237  * This is MDS_HSM_STATE_SET RPC handler.
238  */
239 int mdt_hsm_state_set(struct mdt_thread_info *info)
240 {
241         struct mdt_object       *obj = info->mti_object;
242         struct md_attr          *ma = &info->mti_attr;
243         struct hsm_state_set    *hss;
244         struct mdt_lock_handle  *lh;
245         int                      rc;
246         __u64                    flags;
247         ENTRY;
248
249         lh = &info->mti_lh[MDT_LH_CHILD];
250         mdt_lock_reg_init(lh, LCK_PW);
251         rc = mdt_object_lock(info, obj, lh, MDS_INODELOCK_LOOKUP,
252                              MDT_LOCAL_LOCK);
253         if (rc)
254                 RETURN(rc);
255
256         /* Only valid if client is remote */
257         rc = mdt_init_ucred(info, (struct mdt_body *)info->mti_body);
258         if (rc)
259                 GOTO(out_obj, rc = err_serious(rc));
260
261         /* Read current HSM info */
262         ma->ma_valid = 0;
263         ma->ma_need = MA_HSM;
264         rc = mdt_attr_get_complex(info, obj, ma);
265         if (rc)
266                 GOTO(out_ucred, rc);
267
268         hss = req_capsule_client_get(info->mti_pill, &RMF_HSM_STATE_SET);
269         LASSERT(hss);
270
271         if (req_capsule_get_size(info->mti_pill, &RMF_CAPA1, RCL_CLIENT))
272                 mdt_set_capainfo(info, 0, &info->mti_body->fid1,
273                             req_capsule_client_get(info->mti_pill, &RMF_CAPA1));
274
275         /* Change HSM flags depending on provided masks */
276         if (hss->hss_valid & HSS_SETMASK)
277                 ma->ma_hsm.mh_flags |= hss->hss_setmask;
278         if (hss->hss_valid & HSS_CLEARMASK)
279                 ma->ma_hsm.mh_flags &= ~hss->hss_clearmask;
280
281         /* Change archive_id if provided. */
282         if (hss->hss_valid & HSS_ARCHIVE_ID) {
283                 if (!(ma->ma_hsm.mh_flags & HS_EXISTS)) {
284                         CDEBUG(D_HSM, "Could not set an archive number for "
285                                DFID "if HSM EXISTS flag is not set.\n",
286                                PFID(&info->mti_body->fid1));
287                         GOTO(out_ucred, rc);
288                 }
289                 ma->ma_hsm.mh_arch_id = hss->hss_archive_id;
290         }
291
292         /* Check for inconsistant HSM flagset.
293          * DIRTY without EXISTS: no dirty if no archive was created.
294          * DIRTY and RELEASED: a dirty file could not be released.
295          * RELEASED without ARCHIVED: do not release a non-archived file.
296          * LOST without ARCHIVED: cannot lost a non-archived file.
297          */
298         flags = ma->ma_hsm.mh_flags;
299         if (((flags & HS_DIRTY) && !(flags & HS_EXISTS)) ||
300             ((flags & HS_RELEASED) && (flags & HS_DIRTY)) ||
301             ((flags & HS_RELEASED) && !(flags & HS_ARCHIVED)) ||
302             ((flags & HS_LOST)     && !(flags & HS_ARCHIVED))) {
303                 CDEBUG(D_HSM, "Incompatible flag change on "DFID
304                               "flags="LPX64"\n",
305                        PFID(&info->mti_body->fid1), flags);
306                 GOTO(out_ucred, rc = -EINVAL);
307         }
308
309         /* Save the modified flags */
310         rc = mdt_hsm_attr_set(info, obj, &ma->ma_hsm);
311         if (rc)
312                 GOTO(out_ucred, rc);
313
314         EXIT;
315
316 out_ucred:
317         mdt_exit_ucred(info);
318 out_obj:
319         mdt_object_unlock(info, obj, lh, 1);
320         return rc;
321 }
322
323 /**
324  * Retrieve undergoing HSM requests for the fid provided in RPC body.
325  * Current requests are read from coordinator states.
326  *
327  * This is MDS_HSM_ACTION RPC handler.
328  */
329 int mdt_hsm_action(struct mdt_thread_info *info)
330 {
331         struct hsm_current_action       *hca;
332         struct hsm_action_list          *hal = NULL;
333         struct hsm_action_item          *hai;
334         int                              rc, len;
335         ENTRY;
336
337         /* Only valid if client is remote */
338         rc = mdt_init_ucred(info, (struct mdt_body *)info->mti_body);
339         if (rc)
340                 RETURN(rc = err_serious(rc));
341
342         if (req_capsule_get_size(info->mti_pill, &RMF_CAPA1, RCL_CLIENT))
343                 mdt_set_capainfo(info, 0, &info->mti_body->fid1,
344                                  req_capsule_client_get(info->mti_pill,
345                                                         &RMF_CAPA1));
346
347         hca = req_capsule_server_get(info->mti_pill,
348                                      &RMF_MDS_HSM_CURRENT_ACTION);
349         LASSERT(hca);
350
351         /* Coordinator information */
352         len = sizeof(*hal) + MTI_NAME_MAXLEN /* fsname */ +
353                 cfs_size_round(sizeof(*hai));
354
355         OBD_ALLOC(hal, len);
356         if (hal == NULL)
357                 GOTO(out_ucred, -ENOMEM);
358
359         hal->hal_version = HAL_VERSION;
360         hal->hal_archive_id = 0;
361         hal->hal_flags = 0;
362         obd_uuid2fsname(hal->hal_fsname, mdt2obd_dev(info->mti_mdt)->obd_name,
363                         MTI_NAME_MAXLEN);
364         hal->hal_count = 1;
365         hai = hai_zero(hal);
366         hai->hai_action = HSMA_NONE;
367         hai->hai_cookie = 0;
368         hai->hai_gid = 0;
369         hai->hai_fid = info->mti_body->fid1;
370         hai->hai_len = sizeof(*hai);
371
372         rc = mdt_hsm_coordinator_get_actions(info, hal);
373         if (rc)
374                 GOTO(out_free, rc);
375
376         /* cookie is used to give back request status */
377         if (hai->hai_cookie == 0)
378                 hca->hca_state = HPS_WAITING;
379         else
380                 hca->hca_state = HPS_RUNNING;
381
382         switch (hai->hai_action) {
383         case HSMA_NONE:
384                 hca->hca_action = HUA_NONE;
385                 break;
386         case HSMA_ARCHIVE:
387                 hca->hca_action = HUA_ARCHIVE;
388                 break;
389         case HSMA_RESTORE:
390                 hca->hca_action = HUA_RESTORE;
391                 break;
392         case HSMA_REMOVE:
393                 hca->hca_action = HUA_REMOVE;
394                 break;
395         case HSMA_CANCEL:
396                 hca->hca_action = HUA_CANCEL;
397                 break;
398         default:
399                 hca->hca_action = HUA_NONE;
400                 CERROR("%s: Unknown hsm action: %d on "DFID"\n",
401                        mdt2obd_dev(info->mti_mdt)->obd_name,
402                        hai->hai_action, PFID(&hai->hai_fid));
403                 break;
404         }
405
406         hca->hca_location = hai->hai_extent;
407
408         EXIT;
409 out_free:
410         OBD_FREE(hal, len);
411 out_ucred:
412         mdt_exit_ucred(info);
413         return rc;
414 }
415
416 /**
417  * Process the HSM actions described in a struct hsm_user_request.
418  *
419  * The action described in hur will be send to coordinator to be saved and
420  * processed later or either handled directly if hur.hur_action is HUA_RELEASE.
421  *
422  * This is MDS_HSM_REQUEST RPC handler.
423  */
424 int mdt_hsm_request(struct mdt_thread_info *info)
425 {
426         struct req_capsule              *pill = info->mti_pill;
427         struct mdt_body                 *body;
428         struct hsm_request              *hr;
429         struct hsm_user_item            *hui;
430         struct hsm_action_list          *hal;
431         struct hsm_action_item          *hai;
432         char                            *opaque;
433         enum hsm_copytool_action         action = HSMA_NONE;
434         __u64                            compound_id;
435         int                              len, i, rc;
436         ENTRY;
437
438         body = req_capsule_client_get(pill, &RMF_MDT_BODY);
439         LASSERT(body);
440
441         hr = req_capsule_client_get(pill, &RMF_MDS_HSM_REQUEST);
442         LASSERT(hr);
443
444         hui = req_capsule_client_get(pill, &RMF_MDS_HSM_USER_ITEM);
445         LASSERT(hui);
446
447         opaque = req_capsule_client_get(pill, &RMF_GENERIC_DATA);
448         LASSERT(opaque);
449
450         /* Sanity check. Nothing to do with an empty list */
451         if (hr->hr_itemcount == 0)
452                 RETURN(0);
453
454         /* Only valid if client is remote */
455         rc = mdt_init_ucred(info, body);
456         if (rc)
457                 RETURN(err_serious(rc));
458
459         switch (hr->hr_action) {
460         /* code to be removed in hsm1_merge and final patch */
461         case HUA_RELEASE:
462                 CERROR("Release action is not working in hsm1_coord\n");
463                 GOTO(out_ucred, rc = -EINVAL);
464                 break;
465         /* end of code to be removed */
466         case HUA_ARCHIVE:
467                 action = HSMA_ARCHIVE;
468                 break;
469         case HUA_RESTORE:
470                 action = HSMA_RESTORE;
471                 break;
472         case HUA_REMOVE:
473                 action = HSMA_REMOVE;
474                 break;
475         case HUA_CANCEL:
476                 action = HSMA_CANCEL;
477                 break;
478         default:
479                 CERROR("Unknown hsm action: %d\n", hr->hr_action);
480                 GOTO(out_ucred, rc = -EINVAL);
481         }
482
483         len = sizeof(*hal) + MTI_NAME_MAXLEN /* fsname */ +
484                 cfs_size_round(sizeof(*hai) * hr->hr_itemcount) +
485                 cfs_size_round(hr->hr_data_len * hr->hr_itemcount);
486
487         OBD_ALLOC(hal, len);
488         if (hal == NULL)
489                 GOTO(out_ucred, rc = -ENOMEM);
490
491         hal->hal_version = HAL_VERSION;
492         hal->hal_archive_id = hr->hr_archive_id;
493         hal->hal_flags = hr->hr_flags;
494         obd_uuid2fsname(hal->hal_fsname, mdt2obd_dev(info->mti_mdt)->obd_name,
495                         MTI_NAME_MAXLEN);
496
497         hal->hal_count = hr->hr_itemcount;
498         hai = hai_zero(hal);
499         for (i = 0; i < hr->hr_itemcount; i++) {
500                 hai->hai_action = action;
501                 hai->hai_cookie = 0;
502                 hai->hai_gid = 0;
503                 hai->hai_fid = hui[i].hui_fid;
504                 hai->hai_extent = hui[i].hui_extent;
505                 memcpy(hai->hai_data, opaque, hr->hr_data_len);
506                 hai->hai_len = sizeof(*hai) + hr->hr_data_len;
507                 hai = hai_next(hai);
508         }
509
510         rc = mdt_hsm_coordinator_actions(info, hal, &compound_id, 0);
511         /* ENODATA error code is needed only for implicit requests */
512         if (rc == -ENODATA)
513                 rc = 0;
514
515         OBD_FREE(hal, len);
516         EXIT;
517 out_ucred:
518         mdt_exit_ucred(info);
519         return rc;
520 }
521