4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * (C) Copyright 2012 Commissariat a l'energie atomique et aux energies
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
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.
23 * lustre/utils/liblustreapi_hsm.c
25 * lustreapi library for hsm calls
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 * Author: Henri Doreau <henri.doreau@cea.fr>
37 #include <sys/ioctl.h>
44 #include <sys/types.h>
46 #include <sys/syscall.h>
49 #ifdef HAVE_LINUX_UNISTD_H
50 #include <linux/unistd.h>
55 #include <liblustre.h>
56 #include <lnet/lnetctl.h>
59 #include <lustre/lustreapi.h>
60 #include "lustreapi_internal.h"
62 /****** HSM Copytool API ********/
63 #define CT_PRIV_MAGIC 0xC0BE2001
64 struct hsm_copytool_private {
68 lustre_kernelcomm kuc;
72 #define CP_PRIV_MAGIC 0x19880429
73 struct hsm_copyaction_private {
76 const struct hsm_copytool_private *ct_priv;
80 #include <libcfs/libcfs.h>
82 /** Register a copytool
83 * \param[out] priv Opaque private control structure
84 * \param mnt Lustre filesystem mount point
85 * \param flags Open flags, currently unused (e.g. O_NONBLOCK)
86 * \param archive_count
87 * \param archives Which archive numbers this copytool is responsible for
89 int llapi_hsm_copytool_register(struct hsm_copytool_private **priv,
90 const char *mnt, int flags, int archive_count,
93 struct hsm_copytool_private *ct;
96 if (archive_count > 0 && archives == NULL) {
97 llapi_err_noerrno(LLAPI_MSG_ERROR,
98 "NULL archive numbers");
102 ct = calloc(1, sizeof(*ct));
106 ct->mnt_fd = open(mnt, O_DIRECTORY | O_RDONLY | O_NONBLOCK);
107 if (ct->mnt_fd < 0) {
112 ct->mnt = strdup(mnt);
113 if (ct->mnt == NULL) {
118 ct->magic = CT_PRIV_MAGIC;
120 /* no archives specified means "match all". */
122 for (rc = 0; rc < archive_count; rc++) {
123 if (archives[rc] > 8 * sizeof(ct->archives)) {
124 llapi_err_noerrno(LLAPI_MSG_ERROR,
125 "Maximum of %d archives supported",
126 8 * sizeof(ct->archives));
129 /* in the list we have a all archive wildcard
130 * so move to all archives mode
132 if (archives[rc] == 0) {
137 ct->archives |= (1 << (archives[rc] - 1));
140 rc = libcfs_ukuc_start(&ct->kuc, KUC_GRP_HSM);
144 /* Storing archive(s) in lk_data; see mdc_ioc_hsm_ct_start */
145 ct->kuc.lk_data = ct->archives;
146 rc = ioctl(ct->mnt_fd, LL_IOC_HSM_CT_START, &ct->kuc);
149 llapi_error(LLAPI_MSG_ERROR, rc,
150 "cannot start copytool on '%s'", mnt);
156 /* Only the kernel reference keeps the write side open */
157 close(ct->kuc.lk_wfd);
166 /* cleanup the kuc channel */
167 libcfs_ukuc_stop(&ct->kuc);
170 if (!(ct->mnt_fd < 0))
178 /** Deregister a copytool
179 * Note: under Linux, until llapi_hsm_copytool_unregister is called
180 * (or the program is killed), the libcfs module will be referenced
181 * and unremovable, even after Lustre services stop.
183 int llapi_hsm_copytool_unregister(struct hsm_copytool_private **priv)
185 struct hsm_copytool_private *ct;
187 if (priv == NULL || *priv == NULL)
191 if (ct->magic != CT_PRIV_MAGIC)
194 /* Tell the kernel to stop sending us messages */
195 ct->kuc.lk_flags = LK_FLG_STOP;
196 ioctl(ct->mnt_fd, LL_IOC_HSM_CT_START, &ct->kuc);
198 /* Shut down the kernelcomms */
199 libcfs_ukuc_stop(&ct->kuc);
209 /** Wait for the next hsm_action_list
210 * \param ct Opaque private control structure
211 * \param halh Action list handle, will be allocated here
212 * \param msgsize Number of bytes in the message, will be set here
213 * \return 0 valid message received; halh and msgsize are set
216 int llapi_hsm_copytool_recv(struct hsm_copytool_private *ct,
217 struct hsm_action_list **halh, int *msgsize)
219 struct kuc_hdr *kuch;
220 struct hsm_action_list *hal;
223 if (ct == NULL || ct->magic != CT_PRIV_MAGIC)
226 if (halh == NULL || msgsize == NULL)
229 kuch = malloc(HAL_MAXSIZE + sizeof(*kuch));
233 rc = libcfs_ukuc_msg_get(&ct->kuc, (char *)kuch,
234 HAL_MAXSIZE + sizeof(*kuch),
239 /* Handle generic messages */
240 if (kuch->kuc_transport == KUC_TRANSPORT_GENERIC &&
241 kuch->kuc_msgtype == KUC_MSG_SHUTDOWN) {
246 if (kuch->kuc_transport != KUC_TRANSPORT_HSM ||
247 kuch->kuc_msgtype != HMT_ACTION_LIST) {
248 llapi_err_noerrno(LLAPI_MSG_ERROR,
249 "Unknown HSM message type %d:%d\n",
250 kuch->kuc_transport, kuch->kuc_msgtype);
255 if (kuch->kuc_msglen < sizeof(*kuch) + sizeof(*hal)) {
256 llapi_err_noerrno(LLAPI_MSG_ERROR, "Short HSM message %d",
262 /* Our message is a hsm_action_list. Use pointer math to skip
263 * kuch_hdr and point directly to the message payload.
265 hal = (struct hsm_action_list *)(kuch + 1);
267 /* Check that we have registered for this archive #
268 * if 0 registered, we serve any archive */
270 ((1 << (hal->hal_archive_id - 1)) & ct->archives) == 0) {
271 llapi_err_noerrno(LLAPI_MSG_INFO,
272 "This copytool does not service archive #%d,"
273 " ignoring this request."
274 " Mask of served archive is 0x%.8X",
275 hal->hal_archive_id, ct->archives);
282 *msgsize = kuch->kuc_msglen - sizeof(*kuch);
292 /** Release the action list when done with it. */
293 void llapi_hsm_action_list_free(struct hsm_action_list **hal)
295 /* Reuse the llapi_changelog_free function */
296 llapi_changelog_free((struct changelog_ext_rec **)hal);
299 /** Get parent path from mount point and fid.
301 * \param mnt Filesystem root path.
302 * \param fid Object FID.
303 * \param parent Destination buffer.
304 * \param parent_len Destination buffer size.
305 * \return 0 on success.
307 static int fid_parent(const char *mnt, const lustre_fid *fid, char *parent,
312 long long recno = -1;
314 char strfid[FID_NOBRACE_LEN + 1];
317 snprintf(strfid, sizeof(strfid), DFID_NOBRACE, PFID(fid));
319 rc = llapi_fid2path(mnt, strfid, file, sizeof(file),
324 /* fid2path returns a relative path */
325 rc = snprintf(parent, parent_len, "%s/%s", mnt, file);
326 if (rc >= parent_len)
327 return -ENAMETOOLONG;
329 /* remove file name */
330 ptr = strrchr(parent, '/');
331 if (ptr == NULL || ptr == parent) {
341 /** Create the destination volatile file for a restore operation.
343 * \param hcp Private copyaction handle.
344 * \return 0 on success.
346 static int create_restore_volatile(struct hsm_copyaction_private *hcp)
350 char parent[PATH_MAX + 1];
351 const char *mnt = hcp->ct_priv->mnt;
352 struct hsm_action_item *hai = &hcp->copy.hc_hai;
354 rc = fid_parent(mnt, &hai->hai_fid, parent, sizeof(parent));
356 /* fid_parent() failed, try to keep on going */
357 llapi_error(LLAPI_MSG_ERROR, rc,
358 "cannot get parent path to restore "DFID
359 "using '%s'", PFID(&hai->hai_fid), mnt);
360 snprintf(parent, sizeof(parent), "%s", mnt);
363 fd = llapi_create_volatile_idx(parent, 0, O_LOV_DELAY_CREATE);
367 rc = llapi_fd2fid(fd, &hai->hai_dfid);
382 /** Start processing an HSM action.
383 * Should be called by copytools just before starting handling a request.
384 * It could be skipped if copytool only want to directly report an error,
385 * \see llapi_hsm_action_end().
387 * \param hcp Opaque action handle to be passed to
388 * llapi_hsm_action_progress and llapi_hsm_action_end.
389 * \param ct Copytool handle acquired at registration.
390 * \param hai The hsm_action_item describing the request.
391 * \param is_error Whether this call is just to report an error.
393 * \return 0 on success.
395 int llapi_hsm_action_begin(struct hsm_copyaction_private **phcp,
396 const struct hsm_copytool_private *ct,
397 const struct hsm_action_item *hai, bool is_error)
399 struct hsm_copyaction_private *hcp;
402 hcp = calloc(1, sizeof(*hcp));
408 hcp->copy.hc_hai = *hai;
409 hcp->copy.hc_hai.hai_len = sizeof(*hai);
414 if (hai->hai_action == HSMA_RESTORE) {
415 rc = create_restore_volatile(hcp);
420 rc = ioctl(ct->mnt_fd, LL_IOC_HSM_COPY_START, &hcp->copy);
427 hcp->magic = CP_PRIV_MAGIC;
432 if (!(hcp->data_fd < 0))
440 /** Terminate an HSM action processing.
441 * Should be called by copytools just having finished handling the request.
442 * \param hdl[in,out] Handle returned by llapi_hsm_action_start.
443 * \param he[in] The final range of copied data (for copy actions).
444 * \param errval[in] The status code of the operation.
445 * \param flags[in] The flags about the termination status (HP_FLAG_RETRY if
446 * the error is retryable).
448 * \return 0 on success.
450 int llapi_hsm_action_end(struct hsm_copyaction_private **phcp,
451 const struct hsm_extent *he, int flags, int errval)
453 struct hsm_copyaction_private *hcp;
454 struct hsm_action_item *hai;
457 if (phcp == NULL || *phcp == NULL || he == NULL)
462 if (hcp->magic != CP_PRIV_MAGIC)
465 hai = &hcp->copy.hc_hai;
467 /* In some cases, like restore, 2 FIDs are used.
468 * Set the right FID to use here. */
469 if (hai->hai_action == HSMA_ARCHIVE || hai->hai_action == HSMA_RESTORE)
470 hai->hai_fid = hai->hai_dfid;
472 /* Fill the last missing data that will be needed by
473 * kernel to send a hsm_progress. */
474 hcp->copy.hc_flags = flags;
475 hcp->copy.hc_errval = abs(errval);
477 hcp->copy.hc_hai.hai_extent = *he;
479 rc = ioctl(hcp->ct_priv->mnt_fd, LL_IOC_HSM_COPY_END, &hcp->copy);
486 if (!(hcp->data_fd < 0))
495 /** Notify a progress in processing an HSM action.
496 * \param hdl[in,out] handle returned by llapi_hsm_action_start.
497 * \param he[in] the range of copied data (for copy actions).
498 * \param hp_flags[in] HSM progress flags.
499 * \return 0 on success.
501 int llapi_hsm_action_progress(struct hsm_copyaction_private *hcp,
502 const struct hsm_extent *he, int hp_flags)
505 struct hsm_progress hp;
506 struct hsm_action_item *hai;
508 if (hcp == NULL || he == NULL)
511 if (hcp->magic != CP_PRIV_MAGIC)
514 hai = &hcp->copy.hc_hai;
516 memset(&hp, 0, sizeof(hp));
518 hp.hp_cookie = hai->hai_cookie;
519 hp.hp_flags = hp_flags;
521 /* Progress is made on the data fid */
522 hp.hp_fid = hai->hai_dfid;
525 rc = ioctl(hcp->ct_priv->mnt_fd, LL_IOC_HSM_PROGRESS, &hp);
532 /** Get the fid of object to be used for copying data.
533 * @return error code if the action is not a copy operation.
535 int llapi_hsm_action_get_dfid(const struct hsm_copyaction_private *hcp,
538 const struct hsm_action_item *hai = &hcp->copy.hc_hai;
540 if (hcp->magic != CP_PRIV_MAGIC)
543 if (hai->hai_action != HSMA_RESTORE && hai->hai_action != HSMA_ARCHIVE)
546 *fid = hai->hai_dfid;
552 * Get a file descriptor to be used for copying data. It's up to the
553 * caller to close the FDs obtained from this function.
555 * @retval a file descriptor on success.
556 * @retval a negative error code on failure.
558 int llapi_hsm_action_get_fd(const struct hsm_copyaction_private *hcp)
560 const struct hsm_action_item *hai = &hcp->copy.hc_hai;
562 if (hcp->magic != CP_PRIV_MAGIC)
565 if (hai->hai_action != HSMA_RESTORE)
568 return dup(hcp->data_fd);
572 * Import an existing hsm-archived file into Lustre.
574 * Caller must access file by (returned) newfid value from now on.
576 * \param dst path to Lustre destination (e.g. /mnt/lustre/my/file).
577 * \param archive archive number.
578 * \param st struct stat buffer containing file ownership, perm, etc.
579 * \param stripe_* Striping options. Currently ignored, since the restore
580 * operation will set the striping. In V2, this striping might
582 * \param newfid[out] Filled with new Lustre fid.
584 int llapi_hsm_import(const char *dst, int archive, const struct stat *st,
585 unsigned long long stripe_size, int stripe_offset,
586 int stripe_count, int stripe_pattern, char *pool_name,
589 struct hsm_user_import hui;
593 if (stripe_pattern == 0)
594 stripe_pattern = LOV_PATTERN_RAID0;
596 /* Create a non-striped file */
597 fd = llapi_file_open_pool(dst, O_CREAT | O_WRONLY, st->st_mode,
598 stripe_size, stripe_offset, stripe_count,
599 stripe_pattern | LOV_PATTERN_F_RELEASED,
602 llapi_error(LLAPI_MSG_ERROR, -errno,
603 "cannot create '%s' for import", dst);
607 /* Get the new fid in Lustre. Caller needs to use this fid
609 rc = llapi_fd2fid(fd, newfid);
611 llapi_error(LLAPI_MSG_ERROR, rc,
612 "cannot get fid of '%s' for import", dst);
616 hui.hui_uid = st->st_uid;
617 hui.hui_gid = st->st_gid;
618 hui.hui_mode = st->st_mode;
619 hui.hui_size = st->st_size;
620 hui.hui_archive_id = archive;
621 hui.hui_atime = st->st_atime;
622 hui.hui_atime_ns = st->st_atim.tv_nsec;
623 hui.hui_mtime = st->st_mtime;
624 hui.hui_mtime_ns = st->st_mtim.tv_nsec;
625 rc = ioctl(fd, LL_IOC_HSM_IMPORT, &hui);
627 llapi_error(LLAPI_MSG_ERROR, rc, "cannot import '%s'", dst);
641 * Return the current HSM states and HSM requests related to file pointed by \a
644 * \param hus Should be allocated by caller. Will be filled with current file
647 * \retval 0 on success.
648 * \retval -errno on error.
650 int llapi_hsm_state_get_fd(int fd, struct hsm_user_state *hus)
654 rc = ioctl(fd, LL_IOC_HSM_STATE_GET, hus);
655 /* If error, save errno value */
656 rc = rc ? -errno : 0;
662 * Return the current HSM states and HSM requests related to file pointed by \a
665 * see llapi_hsm_state_get_fd() for args use and return
667 int llapi_hsm_state_get(const char *path, struct hsm_user_state *hus)
672 fd = open(path, O_RDONLY | O_NONBLOCK);
676 rc = llapi_hsm_state_get_fd(fd, hus);
683 * Set HSM states of file pointed by \a fd
685 * Using the provided bitmasks, the current HSM states for this file will be
686 * changed. \a archive_id could be used to change the archive number also. Set
687 * it to 0 if you do not want to change it.
689 * \param setmask Bitmask for flag to be set.
690 * \param clearmask Bitmask for flag to be cleared.
691 * \param archive_id Archive number identifier to use. 0 means no change.
693 * \retval 0 on success.
694 * \retval -errno on error.
696 int llapi_hsm_state_set_fd(int fd, __u64 setmask, __u64 clearmask,
699 struct hsm_state_set hss;
702 hss.hss_valid = HSS_SETMASK|HSS_CLEARMASK;
703 hss.hss_setmask = setmask;
704 hss.hss_clearmask = clearmask;
705 /* Change archive_id if provided. We can only change
706 * to set something different than 0. */
707 if (archive_id > 0) {
708 hss.hss_valid |= HSS_ARCHIVE_ID;
709 hss.hss_archive_id = archive_id;
711 rc = ioctl(fd, LL_IOC_HSM_STATE_SET, &hss);
712 /* If error, save errno value */
713 rc = rc ? -errno : 0;
719 * Set HSM states of file pointed by \a path.
721 * see llapi_hsm_state_set_fd() for args use and return
723 int llapi_hsm_state_set(const char *path, __u64 setmask, __u64 clearmask,
729 fd = open(path, O_WRONLY | O_LOV_DELAY_CREATE | O_NONBLOCK);
733 rc = llapi_hsm_state_set_fd(fd, setmask, clearmask, archive_id);
740 * Return the current HSM request related to file pointed by \a path.
742 * \param hca Should be allocated by caller. Will be filled with current file
745 * \retval 0 on success.
746 * \retval -errno on error.
748 int llapi_hsm_current_action(const char *path, struct hsm_current_action *hca)
753 fd = open(path, O_RDONLY | O_NONBLOCK);
757 rc = ioctl(fd, LL_IOC_HSM_ACTION, hca);
758 /* If error, save errno value */
759 rc = rc ? -errno : 0;
766 * Allocate a hsm_user_request with the specified carateristics.
767 * This structure should be freed with free().
769 * \return an allocated structure on success, NULL otherwise.
771 struct hsm_user_request *llapi_hsm_user_request_alloc(int itemcount,
776 len += sizeof(struct hsm_user_request);
777 len += sizeof(struct hsm_user_item) * itemcount;
780 return (struct hsm_user_request *)malloc(len);
784 * Send a HSM request to Lustre, described in \param request.
786 * \param path Fullpath to the file to operate on.
787 * \param request The request, allocated with llapi_hsm_user_request_alloc().
789 * \return 0 on success, an error code otherwise.
791 int llapi_hsm_request(const char *path, const struct hsm_user_request *request)
796 rc = get_root_path(WANT_FD, NULL, &fd, (char *)path, -1);
800 rc = ioctl(fd, LL_IOC_HSM_REQUEST, request);
801 /* If error, save errno value */
802 rc = rc ? -errno : 0;