Whamcloud - gitweb
LU-3363 api: HSM import uses new released pattern
[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 /****** HSM Copytool API ********/
62 #define CT_PRIV_MAGIC 0xC0BE2001
63 struct hsm_copytool_private {
64         int                      magic;
65         char                    *fsname;
66         lustre_kernelcomm        kuc;
67         __u32                    archives;
68 };
69
70 #include <libcfs/libcfs.h>
71
72 /** Register a copytool
73  * \param[out] priv Opaque private control structure
74  * \param fsname Lustre filesystem
75  * \param flags Open flags, currently unused (e.g. O_NONBLOCK)
76  * \param archive_count
77  * \param archives Which archive numbers this copytool is responsible for
78  */
79 int llapi_hsm_copytool_start(struct hsm_copytool_private **priv, char *fsname,
80                              int flags, int archive_count, int *archives)
81 {
82         struct hsm_copytool_private     *ct;
83         int                              rc;
84
85         if (archive_count > 0 && archives == NULL) {
86                 llapi_err_noerrno(LLAPI_MSG_ERROR,
87                                   "NULL archive numbers");
88                 return -EINVAL;
89         }
90
91         ct = calloc(1, sizeof(*ct));
92         if (ct == NULL)
93                 return -ENOMEM;
94
95         ct->fsname = malloc(strlen(fsname) + 1);
96         if (ct->fsname == NULL) {
97                 rc = -ENOMEM;
98                 goto out_err;
99         }
100         strcpy(ct->fsname, fsname);
101         ct->magic = CT_PRIV_MAGIC;
102
103         /* no archives specified means "match all". */
104         ct->archives = 0;
105         for (rc = 0; rc < archive_count; rc++) {
106                 if (archives[rc] > 8 * sizeof(ct->archives)) {
107                         llapi_err_noerrno(LLAPI_MSG_ERROR,
108                                           "Maximum of %d archives supported",
109                                           8 * sizeof(ct->archives));
110                         goto out_err;
111                 }
112                 /* in the list we have a all archive wildcard
113                  * so move to all archives mode
114                  */
115                 if (archives[rc] == 0) {
116                         ct->archives = 0;
117                         archive_count = 0;
118                         break;
119                 }
120                 ct->archives |= (1 << (archives[rc] - 1));
121         }
122
123         rc = libcfs_ukuc_start(&ct->kuc, KUC_GRP_HSM);
124         if (rc < 0)
125                 goto out_err;
126
127         /* Storing archive(s) in lk_data; see mdc_ioc_hsm_ct_start */
128         ct->kuc.lk_data = ct->archives;
129         rc = root_ioctl(ct->fsname, LL_IOC_HSM_CT_START, &(ct->kuc), NULL,
130                         WANT_ERROR);
131         /* Only the kernel reference keeps the write side open */
132         close(ct->kuc.lk_wfd);
133         ct->kuc.lk_wfd = 0;
134         if (rc < 0)
135                 goto out_kuc;
136
137         *priv = ct;
138         return 0;
139
140 out_kuc:
141         /* cleanup the kuc channel */
142         libcfs_ukuc_stop(&ct->kuc);
143 out_err:
144         if (ct->fsname)
145                 free(ct->fsname);
146         free(ct);
147         return rc;
148 }
149
150 /** Deregister a copytool
151  * Note: under Linux, until llapi_hsm_copytool_fini is called (or the program is
152  * killed), the libcfs module will be referenced and unremovable,
153  * even after Lustre services stop.
154  */
155 int llapi_hsm_copytool_fini(struct hsm_copytool_private **priv)
156 {
157         struct hsm_copytool_private *ct;
158
159         ct = *priv;
160         if (!ct || (ct->magic != CT_PRIV_MAGIC))
161                 return -EINVAL;
162
163         /* Tell the kernel to stop sending us messages */
164         ct->kuc.lk_flags = LK_FLG_STOP;
165         root_ioctl(ct->fsname, LL_IOC_HSM_CT_START, &(ct->kuc), NULL, 0);
166
167         /* Shut down the kernelcomms */
168         libcfs_ukuc_stop(&ct->kuc);
169
170         free(ct->fsname);
171         free(ct);
172         *priv = NULL;
173         return 0;
174 }
175
176 /** Wait for the next hsm_action_list
177  * \param ct Opaque private control structure
178  * \param halh Action list handle, will be allocated here
179  * \param msgsize Number of bytes in the message, will be set here
180  * \return 0 valid message received; halh and msgsize are set
181  *         <0 error code
182  */
183 int llapi_hsm_copytool_recv(struct hsm_copytool_private *ct,
184                             struct hsm_action_list **halh, int *msgsize)
185 {
186         struct kuc_hdr                  *kuch;
187         struct hsm_action_list          *hal;
188         int                              rc = 0;
189
190         if (!ct || (ct->magic != CT_PRIV_MAGIC))
191                 return -EINVAL;
192         if (halh == NULL || msgsize == NULL)
193                 return -EINVAL;
194
195         kuch = malloc(HAL_MAXSIZE + sizeof(*kuch));
196         if (kuch == NULL)
197                 return -ENOMEM;
198
199         rc = libcfs_ukuc_msg_get(&ct->kuc, (char *)kuch,
200                                  HAL_MAXSIZE + sizeof(*kuch),
201                                  KUC_TRANSPORT_HSM);
202         if (rc < 0)
203                 goto out_free;
204
205         /* Handle generic messages */
206         if (kuch->kuc_transport == KUC_TRANSPORT_GENERIC &&
207             kuch->kuc_msgtype == KUC_MSG_SHUTDOWN) {
208                 rc = -ESHUTDOWN;
209                 goto out_free;
210         }
211
212         if (kuch->kuc_transport != KUC_TRANSPORT_HSM ||
213             kuch->kuc_msgtype != HMT_ACTION_LIST) {
214                 llapi_err_noerrno(LLAPI_MSG_ERROR,
215                                   "Unknown HSM message type %d:%d\n",
216                                   kuch->kuc_transport, kuch->kuc_msgtype);
217                 rc = -EPROTO;
218                 goto out_free;
219         }
220
221         if (kuch->kuc_msglen < sizeof(*kuch) + sizeof(*hal)) {
222                 llapi_err_noerrno(LLAPI_MSG_ERROR, "Short HSM message %d",
223                                   kuch->kuc_msglen);
224                 rc = -EPROTO;
225                 goto out_free;
226         }
227
228         /* Our message is a hsm_action_list. Use pointer math to skip
229         * kuch_hdr and point directly to the message payload.
230         */
231         hal = (struct hsm_action_list *)(kuch + 1);
232
233         /* Check that we have registered for this archive #
234          * if 0 registered, we serve any archive */
235         if (ct->archives &&
236             ((1 << (hal->hal_archive_id - 1)) & ct->archives) == 0) {
237                 llapi_err_noerrno(LLAPI_MSG_INFO,
238                                   "This copytool does not service archive #%d,"
239                                   " ignoring this request."
240                                   " Mask of served archive is 0x%.8X",
241                                   hal->hal_archive_id, ct->archives);
242                 rc = -EAGAIN;
243
244                 goto out_free;
245         }
246
247         *halh = hal;
248         *msgsize = kuch->kuc_msglen - sizeof(*kuch);
249         return 0;
250
251 out_free:
252         *halh = NULL;
253         *msgsize = 0;
254         free(kuch);
255         return rc;
256 }
257
258 /** Release the action list when done with it. */
259 int llapi_hsm_copytool_free(struct hsm_action_list **hal)
260 {
261         /* Reuse the llapi_changelog_free function */
262         return llapi_changelog_free((struct changelog_ext_rec **)hal);
263 }
264
265
266 /**
267  * Should be called by copytools just before starting handling a request.
268  * It could be skipped if copytool only want to directly report an error,
269  * \see llapi_hsm_copy_end().
270  *
271  * \param mnt   Mount point of the corresponding Lustre filesystem.
272  * \param hai   The hsm_action_item describing the request they will handle.
273  * \param copy  Updated by this call. Caller will passed it to
274  *              llapi_hsm_copy_end()
275  *
276  * \return 0 on success.
277  */
278 int llapi_hsm_copy_start(char *mnt, struct hsm_copy *copy,
279                          const struct hsm_action_item *hai)
280 {
281         int     fd;
282         int     rc;
283
284         if (memcpy(&copy->hc_hai, hai, sizeof(*hai)) == NULL)
285                 RETURN(-EFAULT);
286
287         rc = get_root_path(WANT_FD, NULL, &fd, mnt, -1);
288         if (rc)
289                 return rc;
290
291         rc = ioctl(fd, LL_IOC_HSM_COPY_START, copy);
292         /* If error, return errno value */
293         rc = rc ? -errno : 0;
294         close(fd);
295
296         return rc;
297 }
298
299 /**
300  * Should be called by copytools just having finished handling the request.
301  *
302  * \param mnt   Mount point of the corresponding Lustre filesystem.
303  * \param copy  The element used when calling llapi_hsm_copy_start()
304  * \param hp    A hsm_progress structure describing the final state of the
305  *              request.
306  *
307  * There is a special case which can be used only when the copytool cannot
308  * start the copy at all and want to directly return an error. In this case,
309  * simply fill \a hp structure and set \a copy to NULL. It is useless to call
310  * llapi_hsm_copy_start() in this case.
311  *
312  * \return 0 on success.
313  */
314 int llapi_hsm_copy_end(char *mnt, struct hsm_copy *copy,
315                        const struct hsm_progress *hp)
316 {
317         int     end_only = 0;
318         int     fd;
319         int     rc;
320
321         /* llapi_hsm_copy_start() was skipped, so alloc copy. It will
322          * only be used to give the needed progress information. */
323         if (copy == NULL) {
324                 /* This is only ok if there is an error. */
325                 if (hp->hp_errval == 0)
326                         return -EINVAL;
327
328                 copy = (struct hsm_copy *)malloc(sizeof(*copy));
329                 if (copy == NULL)
330                         return -ENOMEM;
331                 end_only = 1;
332                 copy->hc_hai.hai_cookie = hp->hp_cookie;
333                 copy->hc_hai.hai_fid = hp->hp_fid;
334                 copy->hc_hai.hai_action = HSMA_NONE;
335         }
336
337         /* Fill the last missing data that will be needed by kernel
338          * to send a hsm_progress. */
339         copy->hc_flags = hp->hp_flags;
340         copy->hc_errval = hp->hp_errval;
341         /* Update hai if it has changed since start */
342         copy->hc_hai.hai_extent = hp->hp_extent;
343         /* In some cases, like restore, 2 FIDs are used. hp knows the right FID
344          * to use here. */
345         copy->hc_hai.hai_fid = hp->hp_fid;
346
347         rc = get_root_path(WANT_FD, NULL, &fd, mnt, -1);
348         if (rc)
349                 goto out_free;
350
351         rc = ioctl(fd, LL_IOC_HSM_COPY_END, copy);
352         /* If error, return errno value */
353         rc = rc ? -errno : 0;
354         close(fd);
355
356 out_free:
357         if (end_only)
358                 free(copy);
359
360         return rc;
361 }
362
363 /**
364  * Copytool progress reporting.
365  *
366  * \a hp->hp_errval should be EAGAIN until action is completely finished.
367  *
368  * \return 0 on success, an error code otherwise.
369  */
370 int llapi_hsm_progress(char *mnt, struct hsm_progress *hp)
371 {
372         int     fd;
373         int     rc;
374
375         rc = get_root_path(WANT_FD, NULL, &fd, mnt, -1);
376         if (rc)
377                 return rc;
378
379         rc = ioctl(fd, LL_IOC_HSM_PROGRESS, hp);
380         /* If error, save errno value */
381         rc = rc ? -errno : 0;
382
383         close(fd);
384         return rc;
385 }
386
387 /**
388  * Import an existing hsm-archived file into Lustre.
389  *
390  * Caller must access file by (returned) newfid value from now on.
391  *
392  * \param dst      path to Lustre destination (e.g. /mnt/lustre/my/file).
393  * \param archive  archive number.
394  * \param st       struct stat buffer containing file ownership, perm, etc.
395  * \param stripe_* Striping options.  Currently ignored, since the restore
396  *                 operation will set the striping.  In V2, this striping might
397  *                 be used.
398  * \param newfid[out] Filled with new Lustre fid.
399  */
400 int llapi_hsm_import(const char *dst, int archive, const struct stat *st,
401                      unsigned long long stripe_size, int stripe_offset,
402                      int stripe_count, int stripe_pattern, char *pool_name,
403                      lustre_fid *newfid)
404 {
405         struct hsm_user_import   hui;
406         int                      fd;
407         int                      rc = 0;
408
409         if (stripe_pattern == 0)
410                 stripe_pattern = LOV_PATTERN_RAID0;
411
412         /* Create a non-striped file */
413         fd = llapi_file_open_pool(dst, O_CREAT | O_WRONLY, st->st_mode,
414                                   stripe_size, stripe_offset, stripe_count,
415                                   stripe_pattern | LOV_PATTERN_F_RELEASED,
416                                   pool_name);
417         if (fd < 0) {
418                 llapi_error(LLAPI_MSG_ERROR, -errno,
419                             "cannot create '%s' for import", dst);
420                 return -errno;
421         }
422
423         /* Get the new fid in Lustre. Caller needs to use this fid
424            from now on. */
425         rc = llapi_fd2fid(fd, newfid);
426         if (rc != 0) {
427                 llapi_error(LLAPI_MSG_ERROR, rc,
428                             "cannot get fid of '%s' for import", dst);
429                 goto out_unlink;
430         }
431
432         hui.hui_uid = st->st_uid;
433         hui.hui_gid = st->st_gid;
434         hui.hui_mode = st->st_mode;
435         hui.hui_size = st->st_size;
436         hui.hui_archive_id = archive;
437         hui.hui_atime = st->st_atime;
438         hui.hui_atime_ns = st->st_atim.tv_nsec;
439         hui.hui_mtime = st->st_mtime;
440         hui.hui_mtime_ns = st->st_mtim.tv_nsec;
441         rc = ioctl(fd, LL_IOC_HSM_IMPORT, &hui);
442         if (rc != 0) {
443                 llapi_error(LLAPI_MSG_ERROR, rc, "cannot import '%s'", dst);
444                 rc = -errno;
445                 goto out_unlink;
446         }
447
448 out_unlink:
449         if (fd >= 0)
450                 close(fd);
451         if (rc)
452                 unlink(dst);
453         return rc;
454 }
455
456 /**
457  * Return the current HSM states and HSM requests related to file pointed by \a
458  * path.
459  *
460  * \param hus  Should be allocated by caller. Will be filled with current file
461  *             states.
462  *
463  * \retval 0 on success.
464  * \retval -errno on error.
465  */
466 int llapi_hsm_state_get_fd(int fd, struct hsm_user_state *hus)
467 {
468         int rc;
469
470         rc = ioctl(fd, LL_IOC_HSM_STATE_GET, hus);
471         /* If error, save errno value */
472         rc = rc ? -errno : 0;
473
474         return rc;
475 }
476
477 /**
478  * Return the current HSM states and HSM requests related to file pointed by \a
479  * path.
480  *
481  * see llapi_hsm_state_get_fd() for args use and return
482  */
483 int llapi_hsm_state_get(const char *path, struct hsm_user_state *hus)
484 {
485         int fd;
486         int rc;
487
488         fd = open(path, O_RDONLY | O_NONBLOCK);
489         if (fd < 0)
490                 return -errno;
491
492         rc = llapi_hsm_state_get_fd(fd, hus);
493
494         close(fd);
495         return rc;
496 }
497
498 /**
499  * Set HSM states of file pointed by \a fd
500  *
501  * Using the provided bitmasks, the current HSM states for this file will be
502  * changed. \a archive_id could be used to change the archive number also. Set
503  * it to 0 if you do not want to change it.
504  *
505  * \param setmask      Bitmask for flag to be set.
506  * \param clearmask    Bitmask for flag to be cleared.
507  * \param archive_id  Archive number identifier to use. 0 means no change.
508  *
509  * \retval 0 on success.
510  * \retval -errno on error.
511  */
512 int llapi_hsm_state_set_fd(int fd, __u64 setmask, __u64 clearmask,
513                            __u32 archive_id)
514 {
515         struct hsm_state_set     hss;
516         int                      rc;
517
518         hss.hss_valid = HSS_SETMASK|HSS_CLEARMASK;
519         hss.hss_setmask = setmask;
520         hss.hss_clearmask = clearmask;
521         /* Change archive_id if provided. We can only change
522          * to set something different than 0. */
523         if (archive_id > 0) {
524                 hss.hss_valid |= HSS_ARCHIVE_ID;
525                 hss.hss_archive_id = archive_id;
526         }
527         rc = ioctl(fd, LL_IOC_HSM_STATE_SET, &hss);
528         /* If error, save errno value */
529         rc = rc ? -errno : 0;
530
531         return rc;
532 }
533
534 /**
535  * Set HSM states of file pointed by \a path.
536  *
537  * see llapi_hsm_state_set_fd() for args use and return
538  */
539 int llapi_hsm_state_set(const char *path, __u64 setmask, __u64 clearmask,
540                         __u32 archive_id)
541 {
542         int fd;
543         int rc;
544
545         fd = open(path, O_WRONLY | O_LOV_DELAY_CREATE | O_NONBLOCK);
546         if (fd < 0)
547                 return -errno;
548
549         rc = llapi_hsm_state_set_fd(fd, setmask, clearmask, archive_id);
550
551         close(fd);
552         return rc;
553 }
554
555 /**
556  * Return the current HSM request related to file pointed by \a path.
557  *
558  * \param hca  Should be allocated by caller. Will be filled with current file
559  *             actions.
560  *
561  * \retval 0 on success.
562  * \retval -errno on error.
563  */
564 int llapi_hsm_current_action(const char *path, struct hsm_current_action *hca)
565 {
566         int fd;
567         int rc;
568
569         fd = open(path, O_RDONLY | O_NONBLOCK);
570         if (fd < 0)
571                 return -errno;
572
573         rc = ioctl(fd, LL_IOC_HSM_ACTION, hca);
574         /* If error, save errno value */
575         rc = rc ? -errno : 0;
576
577         close(fd);
578         return rc;
579 }
580
581 /**
582  * Allocate a hsm_user_request with the specified carateristics.
583  * This structure should be freed with free().
584  *
585  * \return an allocated structure on success, NULL otherwise.
586  */
587 struct hsm_user_request *llapi_hsm_user_request_alloc(int itemcount,
588                                                       int data_len)
589 {
590         int len = 0;
591
592         len += sizeof(struct hsm_user_request);
593         len += sizeof(struct hsm_user_item) * itemcount;
594         len += data_len;
595
596         return (struct hsm_user_request *)malloc(len);
597 }
598
599 /**
600  * Send a HSM request to Lustre, described in \param request.
601  *
602  * This request should be allocated with llapi_hsm_user_request_alloc().
603  *
604  * \param mnt Should be the Lustre moint point.
605  * \return 0 on success, an error code otherwise.
606  */
607 int llapi_hsm_request(char *mnt, struct hsm_user_request *request)
608 {
609         int rc;
610         int fd;
611
612         rc = get_root_path(WANT_FD, NULL, &fd, mnt, -1);
613         if (rc)
614                 return rc;
615
616         rc = ioctl(fd, LL_IOC_HSM_REQUEST, request);
617         /* If error, save errno value */
618         rc = rc ? -errno : 0;
619
620         close(fd);
621         return rc;
622 }
623