Whamcloud - gitweb
3dc19b98fb04065d11817b443900b47d2f3ee653
[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 /**
79  * Update on-disk HSM attributes.
80  */
81 int mdt_hsm_attr_set(struct mdt_thread_info *info, struct mdt_object *obj,
82                      struct md_hsm *mh)
83 {
84         struct md_object        *next = mdt_object_child(obj);
85         struct lu_buf           *buf = &info->mti_buf;
86         struct hsm_attrs        *attrs;
87         int                      rc;
88         ENTRY;
89
90         attrs = (struct hsm_attrs *)info->mti_xattr_buf;
91         CLASSERT(sizeof(info->mti_xattr_buf) >= sizeof(*attrs));
92
93         /* pack HSM attributes */
94         lustre_hsm2buf(info->mti_xattr_buf, mh);
95
96         /* update SOM attributes */
97         buf->lb_buf = attrs;
98         buf->lb_len = sizeof(*attrs);
99         rc = mo_xattr_set(info->mti_env, next, buf, XATTR_NAME_HSM, 0);
100
101         RETURN(rc);
102 }
103
104 /**
105  * Extract information coming from a copytool and asks coordinator to update
106  * a request status depending on the update content.
107  *
108  * Copytools could use this to report failure in their process.
109  *
110  * This is HSM_PROGRESS RPC handler.
111  */
112 int mdt_hsm_progress(struct mdt_thread_info *info)
113 {
114         struct hsm_progress_kernel      *hpk;
115         int                              rc;
116         ENTRY;
117
118         hpk = req_capsule_client_get(info->mti_pill, &RMF_MDS_HSM_PROGRESS);
119         LASSERT(hpk);
120
121         CDEBUG(D_HSM, "Progress on "DFID": len="LPU64" err=%d\n",
122                PFID(&hpk->hpk_fid), hpk->hpk_extent.length, hpk->hpk_errval);
123
124         if (hpk->hpk_errval)
125                 CDEBUG(D_HSM, "Copytool progress on "DFID" failed (%d); %s.\n",
126                        PFID(&hpk->hpk_fid), hpk->hpk_errval,
127                        hpk->hpk_flags & HP_FLAG_RETRY ? "will retry" : "fatal");
128
129         if (hpk->hpk_flags & HP_FLAG_COMPLETED)
130                 CDEBUG(D_HSM, "Finished "DFID" (%d) cancel cookie="LPX64"\n",
131                        PFID(&hpk->hpk_fid), hpk->hpk_errval, hpk->hpk_cookie);
132
133         rc = mdt_hsm_coordinator_update(info, hpk);
134
135         RETURN(rc);
136 }
137
138 int mdt_hsm_ct_register(struct mdt_thread_info *info)
139 {
140         struct ptlrpc_request *req = mdt_info_req(info);
141         __u32 *archives;
142         int rc;
143         ENTRY;
144
145         archives = req_capsule_client_get(info->mti_pill, &RMF_MDS_HSM_ARCHIVE);
146         LASSERT(archives);
147
148         /* XXX: directly include this function here? */
149         rc = mdt_hsm_agent_register_mask(info, &req->rq_export->exp_client_uuid,
150                                          *archives);
151
152         RETURN(rc);
153 }
154
155 int mdt_hsm_ct_unregister(struct mdt_thread_info *info)
156 {
157         struct ptlrpc_request *req = mdt_info_req(info);
158         int rc;
159         ENTRY;
160
161         /* XXX: directly include this function here? */
162         rc = mdt_hsm_agent_unregister(info, &req->rq_export->exp_client_uuid);
163
164         RETURN(rc);
165 }
166
167
168 /**
169  * Retrieve the current HSM flags, archive id and undergoing HSM requests for
170  * the fid provided in RPC body.
171  *
172  * Current requests are read from coordinator states.
173  *
174  * This is MDS_HSM_STATE_GET RPC handler.
175  */
176 int mdt_hsm_state_get(struct mdt_thread_info *info)
177 {
178         struct mdt_object       *obj = info->mti_object;
179         struct md_attr          *ma  = &info->mti_attr;
180         struct hsm_user_state   *hus;
181         struct mdt_lock_handle  *lh;
182         int                      rc;
183         ENTRY;
184
185         lh = &info->mti_lh[MDT_LH_CHILD];
186         mdt_lock_reg_init(lh, LCK_PR);
187         rc = mdt_object_lock(info, obj, lh, MDS_INODELOCK_LOOKUP,
188                              MDT_LOCAL_LOCK);
189         if (rc)
190                 RETURN(rc);
191
192         /* Only valid if client is remote */
193         rc = mdt_init_ucred(info, (struct mdt_body *)info->mti_body);
194         if (rc)
195                 GOTO(out_unlock, rc = err_serious(rc));
196
197         ma->ma_valid = 0;
198         ma->ma_need = MA_HSM;
199         rc = mdt_attr_get_complex(info, obj, ma);
200         if (rc)
201                 GOTO(out_ucred, rc);
202
203         if (req_capsule_get_size(info->mti_pill, &RMF_CAPA1, RCL_CLIENT))
204                 mdt_set_capainfo(info, 0, &info->mti_body->fid1,
205                             req_capsule_client_get(info->mti_pill, &RMF_CAPA1));
206
207         hus = req_capsule_server_get(info->mti_pill, &RMF_HSM_USER_STATE);
208         LASSERT(hus);
209
210         /* Current HSM flags */
211         hus->hus_states = ma->ma_hsm.mh_flags;
212         hus->hus_archive_id = ma->ma_hsm.mh_arch_id;
213
214         EXIT;
215 out_ucred:
216         mdt_exit_ucred(info);
217 out_unlock:
218         mdt_object_unlock(info, obj, lh, 1);
219         return rc;
220 }
221
222 /**
223  * Change HSM state and archive number of a file.
224  *
225  * Archive number is changed iif the value is not 0.
226  * The new flagset that will be computed should result in a coherent state.
227  * This function checks that are flags are compatible.
228  *
229  * This is MDS_HSM_STATE_SET RPC handler.
230  */
231 int mdt_hsm_state_set(struct mdt_thread_info *info)
232 {
233         struct mdt_object       *obj = info->mti_object;
234         struct md_attr          *ma = &info->mti_attr;
235         struct hsm_state_set    *hss;
236         struct mdt_lock_handle  *lh;
237         int                      rc;
238         __u64                    flags;
239         ENTRY;
240
241         lh = &info->mti_lh[MDT_LH_CHILD];
242         mdt_lock_reg_init(lh, LCK_PW);
243         rc = mdt_object_lock(info, obj, lh, MDS_INODELOCK_LOOKUP,
244                              MDT_LOCAL_LOCK);
245         if (rc)
246                 RETURN(rc);
247
248         /* Only valid if client is remote */
249         rc = mdt_init_ucred(info, (struct mdt_body *)info->mti_body);
250         if (rc)
251                 GOTO(out_obj, rc = err_serious(rc));
252
253         /* Read current HSM info */
254         ma->ma_valid = 0;
255         ma->ma_need = MA_HSM;
256         rc = mdt_attr_get_complex(info, obj, ma);
257         if (rc)
258                 GOTO(out_ucred, rc);
259
260         hss = req_capsule_client_get(info->mti_pill, &RMF_HSM_STATE_SET);
261         LASSERT(hss);
262
263         if (req_capsule_get_size(info->mti_pill, &RMF_CAPA1, RCL_CLIENT))
264                 mdt_set_capainfo(info, 0, &info->mti_body->fid1,
265                             req_capsule_client_get(info->mti_pill, &RMF_CAPA1));
266
267         /* Change HSM flags depending on provided masks */
268         if (hss->hss_valid & HSS_SETMASK)
269                 ma->ma_hsm.mh_flags |= hss->hss_setmask;
270         if (hss->hss_valid & HSS_CLEARMASK)
271                 ma->ma_hsm.mh_flags &= ~hss->hss_clearmask;
272
273         /* Change archive_id if provided. */
274         if (hss->hss_valid & HSS_ARCHIVE_ID) {
275                 if (!(ma->ma_hsm.mh_flags & HS_EXISTS)) {
276                         CDEBUG(D_HSM, "Could not set an archive number for "
277                                DFID "if HSM EXISTS flag is not set.\n",
278                                PFID(&info->mti_body->fid1));
279                         GOTO(out_ucred, rc);
280                 }
281                 ma->ma_hsm.mh_arch_id = hss->hss_archive_id;
282         }
283
284         /* Check for inconsistant HSM flagset.
285          * DIRTY without EXISTS: no dirty if no archive was created.
286          * DIRTY and RELEASED: a dirty file could not be released.
287          * RELEASED without ARCHIVED: do not release a non-archived file.
288          * LOST without ARCHIVED: cannot lost a non-archived file.
289          */
290         flags = ma->ma_hsm.mh_flags;
291         if (((flags & HS_DIRTY) && !(flags & HS_EXISTS)) ||
292             ((flags & HS_RELEASED) && (flags & HS_DIRTY)) ||
293             ((flags & HS_RELEASED) && !(flags & HS_ARCHIVED)) ||
294             ((flags & HS_LOST)     && !(flags & HS_ARCHIVED))) {
295                 CDEBUG(D_HSM, "Incompatible flag change on "DFID
296                               "flags="LPX64"\n",
297                        PFID(&info->mti_body->fid1), flags);
298                 GOTO(out_ucred, rc = -EINVAL);
299         }
300
301         /* Save the modified flags */
302         rc = mdt_hsm_attr_set(info, obj, &ma->ma_hsm);
303         if (rc)
304                 GOTO(out_ucred, rc);
305
306         EXIT;
307
308 out_ucred:
309         mdt_exit_ucred(info);
310 out_obj:
311         mdt_object_unlock(info, obj, lh, 1);
312         return rc;
313 }
314
315 /**
316  * Retrieve undergoing HSM requests for the fid provided in RPC body.
317  * Current requests are read from coordinator states.
318  *
319  * This is MDS_HSM_ACTION RPC handler.
320  */
321 int mdt_hsm_action(struct mdt_thread_info *info)
322 {
323         struct hsm_current_action       *hca;
324         struct hsm_action_list          *hal = NULL;
325         struct hsm_action_item          *hai;
326         int                              rc, len;
327         ENTRY;
328
329         /* Only valid if client is remote */
330         rc = mdt_init_ucred(info, (struct mdt_body *)info->mti_body);
331         if (rc)
332                 RETURN(rc = err_serious(rc));
333
334         if (req_capsule_get_size(info->mti_pill, &RMF_CAPA1, RCL_CLIENT))
335                 mdt_set_capainfo(info, 0, &info->mti_body->fid1,
336                                  req_capsule_client_get(info->mti_pill,
337                                                         &RMF_CAPA1));
338
339         hca = req_capsule_server_get(info->mti_pill,
340                                      &RMF_MDS_HSM_CURRENT_ACTION);
341         LASSERT(hca);
342
343         /* Coordinator information */
344         len = sizeof(*hal) + MTI_NAME_MAXLEN /* fsname */ +
345                 cfs_size_round(sizeof(*hai));
346
347         OBD_ALLOC(hal, len);
348         if (hal == NULL)
349                 GOTO(out_ucred, -ENOMEM);
350
351         hal->hal_version = HAL_VERSION;
352         hal->hal_archive_num = 0;
353         hal->hal_flags = 0;
354         obd_uuid2fsname(hal->hal_fsname, mdt2obd_dev(info->mti_mdt)->obd_name,
355                         MTI_NAME_MAXLEN);
356         hal->hal_count = 1;
357         hai = hai_zero(hal);
358         hai->hai_action = HSMA_NONE;
359         hai->hai_cookie = 0;
360         hai->hai_gid = 0;
361         hai->hai_fid = info->mti_body->fid1;
362         hai->hai_len = sizeof(*hai);
363
364         rc = mdt_hsm_coordinator_get_actions(info, hal);
365         if (rc)
366                 GOTO(out_free, rc);
367
368         /* cookie is used to give back request status */
369         if (hai->hai_cookie == 0)
370                 hca->hca_state = HPS_WAITING;
371         else
372                 hca->hca_state = HPS_RUNNING;
373
374         switch (hai->hai_action) {
375         case HSMA_NONE:
376                 hca->hca_action = HUA_NONE;
377                 break;
378         case HSMA_ARCHIVE:
379                 hca->hca_action = HUA_ARCHIVE;
380                 break;
381         case HSMA_RESTORE:
382                 hca->hca_action = HUA_RESTORE;
383                 break;
384         case HSMA_REMOVE:
385                 hca->hca_action = HUA_REMOVE;
386                 break;
387         case HSMA_CANCEL:
388                 hca->hca_action = HUA_CANCEL;
389                 break;
390         default:
391                 hca->hca_action = HUA_NONE;
392                 CERROR("%s: Unknown hsm action: %d on "DFID"\n",
393                        mdt2obd_dev(info->mti_mdt)->obd_name,
394                        hai->hai_action, PFID(&hai->hai_fid));
395                 break;
396         }
397
398         hca->hca_location = hai->hai_extent;
399
400         EXIT;
401 out_free:
402         OBD_FREE(hal, len);
403 out_ucred:
404         mdt_exit_ucred(info);
405         return rc;
406 }