Whamcloud - gitweb
c32fcfedc4bb8b888a112a0b002eab8be4e47017
[fs/lustre-release.git] / lustre / utils / liblustreapi_hsm.c
1 /*
2  * LGPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * (C) Copyright 2012 Commissariat a l'energie atomique et aux energies
7  *     alternatives
8  *
9  * All rights reserved. This program and the accompanying materials
10  * are made available under the terms of the GNU Lesser General Public License
11  * (LGPL) version 2.1 or (at your discretion) any later version.
12  * (LGPL) version 2.1 accompanies this distribution, and is available at
13  * http://www.gnu.org/licenses/lgpl-2.1.html
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18  * Lesser General Public License for more details.
19  *
20  * LGPL HEADER END
21  */
22 /*
23  * lustre/utils/liblustreapi_hsm.c
24  *
25  * lustreapi library for hsm calls
26  *
27  * Author: Aurelien Degremont <aurelien.degremont@cea.fr>
28  * Author: JC Lafoucriere <jacques-charles.lafoucriere@cea.fr>
29  * Author: Thomas leibovici <thomas.leibovici@cea.fr>
30  */
31
32 #include <stdlib.h>
33 #include <stdio.h>
34 #include <string.h>
35 #include <stddef.h>
36 #include <sys/ioctl.h>
37 #include <unistd.h>
38 #include <malloc.h>
39 #include <errno.h>
40 #include <dirent.h>
41 #include <stdarg.h>
42 #include <sys/stat.h>
43 #include <sys/types.h>
44 #include <utime.h>
45 #include <sys/syscall.h>
46 #include <fnmatch.h>
47 #include <glob.h>
48 #ifdef HAVE_LINUX_UNISTD_H
49 #include <linux/unistd.h>
50 #else
51 #include <unistd.h>
52 #endif
53
54 #include <liblustre.h>
55 #include <lnet/lnetctl.h>
56 #include <obd.h>
57 #include <obd_lov.h>
58 #include <lustre/lustreapi.h>
59 #include "lustreapi_internal.h"
60
61 /*
62  * fake functions, real one will come with HSM flags patch
63  */
64 static int llapi_hsm_state_set(const char *path, __u64 setmask, __u64 clearmask,
65                                __u32 archive_num)
66 {
67         return 0;
68 }
69
70 /****** HSM Copytool API ********/
71 #define CT_PRIV_MAGIC 0xC0BE2001
72 struct hsm_copytool_private {
73         int                      magic;
74         char                    *fsname;
75         lustre_kernelcomm        kuc;
76         __u32                    archives;
77 };
78
79 #include <libcfs/libcfs.h>
80
81 /** Register a copytool
82  * \param[out] priv Opaque private control structure
83  * \param fsname Lustre filesystem
84  * \param flags Open flags, currently unused (e.g. O_NONBLOCK)
85  * \param archive_count
86  * \param archives Which archive numbers this copytool is responsible for
87  */
88 int llapi_hsm_copytool_start(void **priv, char *fsname, int flags,
89                              int archive_count, int *archives)
90 {
91         struct hsm_copytool_private     *ct;
92         int                              rc;
93
94         if (archive_count > 0 && archives == NULL) {
95                 llapi_err_noerrno(LLAPI_MSG_ERROR,
96                                   "NULL archive numbers");
97                 return -EINVAL;
98         }
99
100         ct = calloc(1, sizeof(*ct));
101         if (ct == NULL)
102                 return -ENOMEM;
103
104         ct->fsname = malloc(strlen(fsname) + 1);
105         if (ct->fsname == NULL) {
106                 rc = -ENOMEM;
107                 goto out_err;
108         }
109         strcpy(ct->fsname, fsname);
110         ct->magic = CT_PRIV_MAGIC;
111
112         /* no archives specified means "match all". */
113         ct->archives = 0;
114         for (rc = 0; rc < archive_count; rc++) {
115                 if (archives[rc] > 8 * sizeof(ct->archives)) {
116                         llapi_err_noerrno(LLAPI_MSG_ERROR,
117                                           "Maximum of %d archives supported",
118                                           8 * sizeof(ct->archives));
119                         goto out_err;
120                 }
121                 /* in the list we have a all archive wildcard
122                  * so move to all archives mode
123                  */
124                 if (archives[rc] == 0) {
125                         ct->archives = 0;
126                         archive_count = 0;
127                         break;
128                 }
129                 ct->archives |= (1 << (archives[rc] - 1));
130         }
131
132         rc = libcfs_ukuc_start(&ct->kuc, KUC_GRP_HSM);
133         if (rc < 0)
134                 goto out_err;
135
136         /* Storing archive(s) in lk_data; see mdc_ioc_hsm_ct_start */
137         ct->kuc.lk_data = ct->archives;
138         rc = root_ioctl(ct->fsname, LL_IOC_HSM_CT_START, &(ct->kuc), NULL,
139                         WANT_ERROR);
140         /* ignore if it was already registered on coordinator */
141         if (rc == -EEXIST)
142                 rc = 0;
143         /* Only the kernel reference keeps the write side open */
144         close(ct->kuc.lk_wfd);
145         ct->kuc.lk_wfd = 0;
146         if (rc < 0)
147                 goto out_err;
148
149         *priv = ct;
150         return 0;
151
152 out_err:
153         if (ct->fsname)
154                 free(ct->fsname);
155         free(ct);
156         return rc;
157 }
158
159 /** Deregister a copytool
160  * Note: under Linux, until llapi_hsm_copytool_fini is called (or the program is
161  * killed), the libcfs module will be referenced and unremovable,
162  * even after Lustre services stop.
163  */
164 int llapi_hsm_copytool_fini(void **priv)
165 {
166         struct hsm_copytool_private *ct;
167
168         ct = (struct hsm_copytool_private *)priv;
169         if (!ct || (ct->magic != CT_PRIV_MAGIC))
170                 return -EINVAL;
171
172         /* Tell the kernel to stop sending us messages */
173         ct->kuc.lk_flags = LK_FLG_STOP;
174         root_ioctl(ct->fsname, LL_IOC_HSM_CT_START, &(ct->kuc), NULL, 0);
175
176         /* Shut down the kernelcomms */
177         libcfs_ukuc_stop(&ct->kuc);
178
179         free(ct->fsname);
180         free(ct);
181         *priv = NULL;
182         return 0;
183 }
184
185 /** Wait for the next hsm_action_list
186  * \param priv Opaque private control structure
187  * \param halh Action list handle, will be allocated here
188  * \param msgsize Number of bytes in the message, will be set here
189  * \return 0 valid message received; halh and msgsize are set
190  *         <0 error code
191  */
192 int llapi_hsm_copytool_recv(void *priv, struct hsm_action_list **halh,
193                             int *msgsize)
194 {
195         struct hsm_copytool_private     *ct;
196         struct kuc_hdr                  *kuch;
197         struct hsm_action_list          *hal;
198         int                              rc = 0;
199
200         ct = (struct hsm_copytool_private *)priv;
201         if (!ct || (ct->magic != CT_PRIV_MAGIC))
202                 return -EINVAL;
203         if (halh == NULL || msgsize == NULL)
204                 return -EINVAL;
205
206         kuch = malloc(HAL_MAXSIZE + sizeof(*kuch));
207         if (kuch == NULL)
208                 return -ENOMEM;
209
210         rc = libcfs_ukuc_msg_get(&ct->kuc, (char *)kuch,
211                                  HAL_MAXSIZE + sizeof(*kuch),
212                                  KUC_TRANSPORT_HSM);
213         if (rc < 0)
214                 goto out_free;
215
216         /* Handle generic messages */
217         if (kuch->kuc_transport == KUC_TRANSPORT_GENERIC &&
218             kuch->kuc_msgtype == KUC_MSG_SHUTDOWN) {
219                 rc = -ESHUTDOWN;
220                 goto out_free;
221         }
222
223         if (kuch->kuc_transport != KUC_TRANSPORT_HSM ||
224             kuch->kuc_msgtype != HMT_ACTION_LIST) {
225                 llapi_err_noerrno(LLAPI_MSG_ERROR,
226                                   "Unknown HSM message type %d:%d\n",
227                                   kuch->kuc_transport, kuch->kuc_msgtype);
228                 rc = -EPROTO;
229                 goto out_free;
230         }
231
232         if (kuch->kuc_msglen < sizeof(*kuch) + sizeof(*hal)) {
233                 llapi_err_noerrno(LLAPI_MSG_ERROR, "Short HSM message %d",
234                                   kuch->kuc_msglen);
235                 rc = -EPROTO;
236                 goto out_free;
237         }
238
239         /* Our message is a hsm_action_list. Use pointer math to skip
240         * kuch_hdr and point directly to the message payload.
241         */
242         hal = (struct hsm_action_list *)(kuch + 1);
243
244         /* Check that we have registered for this archive #
245          * if 0 registered, we serve any archive */
246         if (ct->archives &&
247             ((1 << (hal->hal_archive_num - 1)) & ct->archives) == 0) {
248                 llapi_err_noerrno(LLAPI_MSG_INFO,
249                                   "This copytool does not service archive #%d,"
250                                   " ignoring this request."
251                                   " Mask of served archive is 0x%.8X",
252                                   hal->hal_archive_num, ct->archives);
253                 rc = -EAGAIN;
254
255                 goto out_free;
256         }
257
258         *halh = hal;
259         *msgsize = kuch->kuc_msglen - sizeof(*kuch);
260         return 0;
261
262 out_free:
263         *halh = NULL;
264         *msgsize = 0;
265         free(kuch);
266         return rc;
267 }
268
269 /** Release the action list when done with it. */
270 int llapi_hsm_copytool_free(struct hsm_action_list **hal)
271 {
272         /* Reuse the llapi_changelog_free function */
273         return llapi_changelog_free((struct changelog_ext_rec **)hal);
274 }
275
276
277 /**
278  * Should be called by copytools just before starting handling a request.
279  * It could be skipped if copytool only want to directly report an error,
280  * \see llapi_hsm_copy_end().
281  *
282  * \param mnt   Mount point of the corresponding Lustre filesystem.
283  * \param hai   The hsm_action_item describing the request they will handle.
284  * \param copy  Updated by this call. Caller will passed it to
285  *              llapi_hsm_copy_end()
286  *
287  * \return 0 on success.
288  */
289 int llapi_hsm_copy_start(char *mnt, struct hsm_copy *copy,
290                          const struct hsm_action_item *hai)
291 {
292         int     fd;
293         int     rc;
294
295         if (memcpy(&copy->hc_hai, hai, sizeof(*hai)) == NULL)
296                 RETURN(-EFAULT);
297
298         rc = get_root_path(WANT_FD, NULL, &fd, mnt, -1);
299         if (rc)
300                 return rc;
301
302         rc = ioctl(fd, LL_IOC_HSM_COPY_START, copy);
303         close(fd);
304
305         return rc;
306 }
307
308 /**
309  * Should be called by copytools just having finished handling the request.
310  *
311  * \param mnt   Mount point of the corresponding Lustre filesystem.
312  * \param copy  The element used when calling llapi_hsm_copy_start()
313  * \param hp    A hsm_progress structure describing the final state of the
314  *              request.
315  *
316  * There is a special case which can be used only when the copytool cannot
317  * start the copy at all and want to directly return an error. In this case,
318  * simply fill \a hp structure and set \a copy to NULL. It is useless to call
319  * llapi_hsm_copy_start() in this case.
320  *
321  * \return 0 on success.
322  */
323 int llapi_hsm_copy_end(char *mnt, struct hsm_copy *copy,
324                        const struct hsm_progress *hp)
325 {
326         int     end_only = 0;
327         int     fd;
328         int     rc;
329
330         /* llapi_hsm_copy_start() was skipped, so alloc copy. It will
331          * only be used to give the needed progress information. */
332         if (copy == NULL) {
333                 /* This is only ok if there is an error. */
334                 if (hp->hp_errval == 0)
335                         return -EINVAL;
336
337                 copy = (struct hsm_copy *)malloc(sizeof(*copy));
338                 if (copy == NULL)
339                         return -ENOMEM;
340                 end_only = 1;
341                 copy->hc_hai.hai_cookie = hp->hp_cookie;
342                 copy->hc_hai.hai_fid = hp->hp_fid;
343                 copy->hc_hai.hai_action = HSMA_NONE;
344         }
345
346         /* Fill the last missing data that will be needed by kernel
347          * to send a hsm_progress. */
348         copy->hc_flags = hp->hp_flags;
349         copy->hc_errval = hp->hp_errval;
350         /* Update hai if it has changed since start */
351         copy->hc_hai.hai_extent = hp->hp_extent;
352
353         rc = get_root_path(WANT_FD, NULL, &fd, mnt, -1);
354         if (rc)
355                 goto out_free;
356
357         rc = ioctl(fd, LL_IOC_HSM_COPY_END, copy);
358         close(fd);
359
360 out_free:
361         if (end_only)
362                 free(copy);
363
364         return rc;
365 }
366
367 /**
368  * Copytool progress reporting.
369  *
370  * \a hp->hp_errval should be EAGAIN until action is completely finished.
371  *
372  * \return 0 on success, an error code otherwise.
373  */
374 int llapi_hsm_progress(char *mnt, struct hsm_progress *hp)
375 {
376         int     fd;
377         int     rc;
378
379         rc = get_root_path(WANT_FD, NULL, &fd, mnt, -1);
380         if (rc)
381                 return rc;
382
383         rc = ioctl(fd, LL_IOC_HSM_PROGRESS, hp);
384         /* If error, save errno value */
385         rc = rc ? -errno : 0;
386
387         close(fd);
388         return rc;
389 }
390
391 /**
392  * Import an existing hsm-archived file into Lustre.
393  *
394  * Caller must access file by (returned) newfid value from now on.
395  *
396  * \param dst      path to Lustre destination (e.g. /mnt/lustre/my/file).
397  * \param archive  archive number.
398  * \param st       struct stat buffer containing file ownership, perm, etc.
399  * \param stripe_* Striping options.  Currently ignored, since the restore
400  *                 operation will set the striping.  In V2, this striping might
401  *                 be used.
402  * \param newfid[out] Filled with new Lustre fid.
403  */
404 int llapi_hsm_import(const char *dst, int archive, struct stat *st,
405                      unsigned long long stripe_size, int stripe_offset,
406                      int stripe_count, int stripe_pattern, char *pool_name,
407                      lustre_fid *newfid)
408 {
409         struct utimbuf  time;
410         int             fd;
411         int             rc = 0;
412
413         /* Create a non-striped file */
414         fd = open(dst, O_CREAT | O_EXCL | O_LOV_DELAY_CREATE | O_NONBLOCK,
415                   st->st_mode);
416
417         if (fd < 0)
418                 return -errno;
419         close(fd);
420
421         /* set size on MDT */
422         if (truncate(dst, st->st_size) != 0) {
423                 rc = -errno;
424                 goto out_unlink;
425         }
426         /* Mark archived */
427         rc = llapi_hsm_state_set(dst, HS_EXISTS | HS_RELEASED | HS_ARCHIVED, 0,
428                                  archive);
429         if (rc)
430                 goto out_unlink;
431
432         /* Get the new fid in the archive. Caller needs to use this fid
433            from now on. */
434         rc = llapi_path2fid(dst, newfid);
435         if (rc)
436                 goto out_unlink;
437
438         /* Copy the file attributes */
439         time.actime = st->st_atime;
440         time.modtime = st->st_mtime;
441         if (utime(dst, &time) == -1 ||
442                 chmod(dst, st->st_mode) == -1 ||
443                 chown(dst, st->st_uid, st->st_gid) == -1) {
444                 /* we might fail here because we change perms/owner */
445                 rc = -errno;
446                 goto out_unlink;
447         }
448
449 out_unlink:
450         if (rc)
451                 unlink(dst);
452         return rc;
453 }
454