Whamcloud - gitweb
LU-1338 hsm: HSM flags feature
[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 /**
73  * Update on-disk HSM attributes.
74  */
75 int mdt_hsm_attr_set(struct mdt_thread_info *info, struct mdt_object *obj,
76                      struct md_hsm *mh)
77 {
78         struct md_object        *next = mdt_object_child(obj);
79         struct lu_buf           *buf = &info->mti_buf;
80         struct hsm_attrs        *attrs;
81         int                      rc;
82         ENTRY;
83
84         attrs = (struct hsm_attrs *)info->mti_xattr_buf;
85         CLASSERT(sizeof(info->mti_xattr_buf) >= sizeof(*attrs));
86
87         /* pack HSM attributes */
88         lustre_hsm2buf(info->mti_xattr_buf, mh);
89
90         /* update SOM attributes */
91         buf->lb_buf = attrs;
92         buf->lb_len = sizeof(*attrs);
93         rc = mo_xattr_set(info->mti_env, next, buf, XATTR_NAME_HSM, 0);
94
95         RETURN(rc);
96 }
97
98 /**
99  * Extract information coming from a copytool and asks coordinator to update
100  * a request status depending on the update content.
101  *
102  * Copytools could use this to report failure in their process.
103  *
104  * This is HSM_PROGRESS RPC handler.
105  */
106 int mdt_hsm_progress(struct mdt_thread_info *info)
107 {
108         struct hsm_progress_kernel      *hpk;
109         int                              rc;
110         ENTRY;
111
112         hpk = req_capsule_client_get(info->mti_pill, &RMF_MDS_HSM_PROGRESS);
113         LASSERT(hpk);
114
115         CDEBUG(D_HSM, "Progress on "DFID": len="LPU64" err=%d\n",
116                PFID(&hpk->hpk_fid), hpk->hpk_extent.length, hpk->hpk_errval);
117
118         if (hpk->hpk_errval)
119                 CDEBUG(D_HSM, "Copytool progress on "DFID" failed (%d); %s.\n",
120                        PFID(&hpk->hpk_fid), hpk->hpk_errval,
121                        hpk->hpk_flags & HP_FLAG_RETRY ? "will retry" : "fatal");
122
123         if (hpk->hpk_flags & HP_FLAG_COMPLETED)
124                 CDEBUG(D_HSM, "Finished "DFID" (%d) cancel cookie="LPX64"\n",
125                        PFID(&hpk->hpk_fid), hpk->hpk_errval, hpk->hpk_cookie);
126
127         rc = mdt_hsm_coordinator_update(info, hpk);
128
129         RETURN(rc);
130 }
131
132 int mdt_hsm_ct_register(struct mdt_thread_info *info)
133 {
134         struct ptlrpc_request *req = mdt_info_req(info);
135         __u32 *archives;
136         int rc;
137         ENTRY;
138
139         archives = req_capsule_client_get(info->mti_pill, &RMF_MDS_HSM_ARCHIVE);
140         LASSERT(archives);
141
142         /* XXX: directly include this function here? */
143         rc = mdt_hsm_agent_register_mask(info, &req->rq_export->exp_client_uuid,
144                                          *archives);
145
146         RETURN(rc);
147 }
148
149 int mdt_hsm_ct_unregister(struct mdt_thread_info *info)
150 {
151         struct ptlrpc_request *req = mdt_info_req(info);
152         int rc;
153         ENTRY;
154
155         /* XXX: directly include this function here? */
156         rc = mdt_hsm_agent_unregister(info, &req->rq_export->exp_client_uuid);
157
158         RETURN(rc);
159 }
160
161
162 /**
163  * Retrieve the current HSM flags, archive id and undergoing HSM requests for
164  * the fid provided in RPC body.
165  *
166  * Current requests are read from coordinator states.
167  *
168  * This is MDS_HSM_STATE_GET RPC handler.
169  */
170 int mdt_hsm_state_get(struct mdt_thread_info *info)
171 {
172         struct mdt_object       *obj = info->mti_object;
173         struct md_attr          *ma  = &info->mti_attr;
174         struct hsm_user_state   *hus;
175         struct mdt_lock_handle  *lh;
176         int                      rc;
177         ENTRY;
178
179         lh = &info->mti_lh[MDT_LH_CHILD];
180         mdt_lock_reg_init(lh, LCK_PR);
181         rc = mdt_object_lock(info, obj, lh, MDS_INODELOCK_LOOKUP,
182                              MDT_LOCAL_LOCK);
183         if (rc)
184                 RETURN(rc);
185
186         /* Only valid if client is remote */
187         rc = mdt_init_ucred(info, (struct mdt_body *)info->mti_body);
188         if (rc)
189                 GOTO(out_unlock, rc = err_serious(rc));
190
191         ma->ma_valid = 0;
192         ma->ma_need = MA_HSM;
193         rc = mdt_attr_get_complex(info, obj, ma);
194         if (rc)
195                 GOTO(out_ucred, rc);
196
197         if (req_capsule_get_size(info->mti_pill, &RMF_CAPA1, RCL_CLIENT))
198                 mdt_set_capainfo(info, 0, &info->mti_body->fid1,
199                             req_capsule_client_get(info->mti_pill, &RMF_CAPA1));
200
201         hus = req_capsule_server_get(info->mti_pill, &RMF_HSM_USER_STATE);
202         LASSERT(hus);
203
204         /* Current HSM flags */
205         hus->hus_states = ma->ma_hsm.mh_flags;
206         hus->hus_archive_id = ma->ma_hsm.mh_arch_id;
207
208         EXIT;
209 out_ucred:
210         mdt_exit_ucred(info);
211 out_unlock:
212         mdt_object_unlock(info, obj, lh, 1);
213         return rc;
214 }
215
216 /**
217  * Change HSM state and archive number of a file.
218  *
219  * Archive number is changed iif the value is not 0.
220  * The new flagset that will be computed should result in a coherent state.
221  * This function checks that are flags are compatible.
222  *
223  * This is MDS_HSM_STATE_SET RPC handler.
224  */
225 int mdt_hsm_state_set(struct mdt_thread_info *info)
226 {
227         struct mdt_object       *obj = info->mti_object;
228         struct md_attr          *ma = &info->mti_attr;
229         struct hsm_state_set    *hss;
230         struct mdt_lock_handle  *lh;
231         int                      rc;
232         __u64                    flags;
233         ENTRY;
234
235         lh = &info->mti_lh[MDT_LH_CHILD];
236         mdt_lock_reg_init(lh, LCK_PW);
237         rc = mdt_object_lock(info, obj, lh, MDS_INODELOCK_LOOKUP,
238                              MDT_LOCAL_LOCK);
239         if (rc)
240                 RETURN(rc);
241
242         /* Only valid if client is remote */
243         rc = mdt_init_ucred(info, (struct mdt_body *)info->mti_body);
244         if (rc)
245                 GOTO(out_obj, rc = err_serious(rc));
246
247         /* Read current HSM info */
248         ma->ma_valid = 0;
249         ma->ma_need = MA_HSM;
250         rc = mdt_attr_get_complex(info, obj, ma);
251         if (rc)
252                 GOTO(out_ucred, rc);
253
254         hss = req_capsule_client_get(info->mti_pill, &RMF_HSM_STATE_SET);
255         LASSERT(hss);
256
257         if (req_capsule_get_size(info->mti_pill, &RMF_CAPA1, RCL_CLIENT))
258                 mdt_set_capainfo(info, 0, &info->mti_body->fid1,
259                             req_capsule_client_get(info->mti_pill, &RMF_CAPA1));
260
261         /* Change HSM flags depending on provided masks */
262         if (hss->hss_valid & HSS_SETMASK)
263                 ma->ma_hsm.mh_flags |= hss->hss_setmask;
264         if (hss->hss_valid & HSS_CLEARMASK)
265                 ma->ma_hsm.mh_flags &= ~hss->hss_clearmask;
266
267         /* Change archive_id if provided. */
268         if (hss->hss_valid & HSS_ARCHIVE_ID) {
269                 if (!(ma->ma_hsm.mh_flags & HS_EXISTS)) {
270                         CDEBUG(D_HSM, "Could not set an archive number for "
271                                DFID "if HSM EXISTS flag is not set.\n",
272                                PFID(&info->mti_body->fid1));
273                         GOTO(out_ucred, rc);
274                 }
275                 ma->ma_hsm.mh_arch_id = hss->hss_archive_id;
276         }
277
278         /* Check for inconsistant HSM flagset.
279          * DIRTY without EXISTS: no dirty if no archive was created.
280          * DIRTY and RELEASED: a dirty file could not be released.
281          * RELEASED without ARCHIVED: do not release a non-archived file.
282          * LOST without ARCHIVED: cannot lost a non-archived file.
283          */
284         flags = ma->ma_hsm.mh_flags;
285         if (((flags & HS_DIRTY) && !(flags & HS_EXISTS)) ||
286             ((flags & HS_RELEASED) && (flags & HS_DIRTY)) ||
287             ((flags & HS_RELEASED) && !(flags & HS_ARCHIVED)) ||
288             ((flags & HS_LOST)     && !(flags & HS_ARCHIVED))) {
289                 CDEBUG(D_HSM, "Incompatible flag change on "DFID
290                               "flags="LPX64"\n",
291                        PFID(&info->mti_body->fid1), flags);
292                 GOTO(out_ucred, rc = -EINVAL);
293         }
294
295         /* Save the modified flags */
296         rc = mdt_hsm_attr_set(info, obj, &ma->ma_hsm);
297         if (rc)
298                 GOTO(out_ucred, rc);
299
300         EXIT;
301
302 out_ucred:
303         mdt_exit_ucred(info);
304 out_obj:
305         mdt_object_unlock(info, obj, lh, 1);
306         return rc;
307 }