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>
58 #include <lustre/lustreapi.h>
59 #include "lustreapi_internal.h"
61 #define OPEN_BY_FID_PATH dot_lustre_name"/fid"
63 /****** HSM Copytool API ********/
64 #define CT_PRIV_MAGIC 0xC0BE2001
65 struct hsm_copytool_private {
70 lustre_kernelcomm kuc;
74 #define CP_PRIV_MAGIC 0x19880429
75 struct hsm_copyaction_private {
78 const struct hsm_copytool_private *ct_priv;
83 #include <libcfs/libcfs.h>
85 /** Register a copytool
86 * \param[out] priv Opaque private control structure
87 * \param mnt Lustre filesystem mount point
88 * \param flags Open flags, currently unused (e.g. O_NONBLOCK)
89 * \param archive_count
90 * \param archives Which archive numbers this copytool is responsible for
92 int llapi_hsm_copytool_register(struct hsm_copytool_private **priv,
93 const char *mnt, int flags, int archive_count,
96 struct hsm_copytool_private *ct;
99 if (archive_count > 0 && archives == NULL) {
100 llapi_err_noerrno(LLAPI_MSG_ERROR,
101 "NULL archive numbers");
105 ct = calloc(1, sizeof(*ct));
109 ct->magic = CT_PRIV_MAGIC;
111 ct->open_by_fid_fd = -1;
112 ct->kuc.lk_rfd = LK_NOFD;
113 ct->kuc.lk_wfd = LK_NOFD;
115 ct->mnt = strdup(mnt);
116 if (ct->mnt == NULL) {
121 ct->mnt_fd = open(ct->mnt, O_RDONLY);
122 if (ct->mnt_fd < 0) {
127 ct->open_by_fid_fd = openat(ct->mnt_fd, OPEN_BY_FID_PATH, O_RDONLY);
128 if (ct->open_by_fid_fd < 0) {
133 /* no archives specified means "match all". */
135 for (rc = 0; rc < archive_count; rc++) {
136 if (archives[rc] > 8 * sizeof(ct->archives)) {
137 llapi_err_noerrno(LLAPI_MSG_ERROR,
138 "maximum of %zu archives supported",
139 8 * sizeof(ct->archives));
142 /* in the list we have a all archive wildcard
143 * so move to all archives mode
145 if (archives[rc] == 0) {
150 ct->archives |= (1 << (archives[rc] - 1));
153 rc = libcfs_ukuc_start(&ct->kuc, KUC_GRP_HSM);
157 /* Storing archive(s) in lk_data; see mdc_ioc_hsm_ct_start */
158 ct->kuc.lk_data = ct->archives;
159 rc = ioctl(ct->mnt_fd, LL_IOC_HSM_CT_START, &ct->kuc);
162 llapi_error(LLAPI_MSG_ERROR, rc,
163 "cannot start copytool on '%s'", mnt);
169 /* Only the kernel reference keeps the write side open */
170 close(ct->kuc.lk_wfd);
171 ct->kuc.lk_wfd = LK_NOFD;
179 /* cleanup the kuc channel */
180 libcfs_ukuc_stop(&ct->kuc);
183 if (!(ct->mnt_fd < 0))
186 if (!(ct->open_by_fid_fd < 0))
187 close(ct->open_by_fid_fd);
197 /** Deregister a copytool
198 * Note: under Linux, until llapi_hsm_copytool_unregister is called
199 * (or the program is killed), the libcfs module will be referenced
200 * and unremovable, even after Lustre services stop.
202 int llapi_hsm_copytool_unregister(struct hsm_copytool_private **priv)
204 struct hsm_copytool_private *ct;
206 if (priv == NULL || *priv == NULL)
210 if (ct->magic != CT_PRIV_MAGIC)
213 /* Tell the kernel to stop sending us messages */
214 ct->kuc.lk_flags = LK_FLG_STOP;
215 ioctl(ct->mnt_fd, LL_IOC_HSM_CT_START, &ct->kuc);
217 /* Shut down the kernelcomms */
218 libcfs_ukuc_stop(&ct->kuc);
220 close(ct->open_by_fid_fd);
229 /** Wait for the next hsm_action_list
230 * \param ct Opaque private control structure
231 * \param halh Action list handle, will be allocated here
232 * \param msgsize Number of bytes in the message, will be set here
233 * \return 0 valid message received; halh and msgsize are set
236 int llapi_hsm_copytool_recv(struct hsm_copytool_private *ct,
237 struct hsm_action_list **halh, int *msgsize)
239 struct kuc_hdr *kuch;
240 struct hsm_action_list *hal;
243 if (ct == NULL || ct->magic != CT_PRIV_MAGIC)
246 if (halh == NULL || msgsize == NULL)
249 kuch = malloc(HAL_MAXSIZE + sizeof(*kuch));
253 rc = libcfs_ukuc_msg_get(&ct->kuc, (char *)kuch,
254 HAL_MAXSIZE + sizeof(*kuch),
259 /* Handle generic messages */
260 if (kuch->kuc_transport == KUC_TRANSPORT_GENERIC &&
261 kuch->kuc_msgtype == KUC_MSG_SHUTDOWN) {
266 if (kuch->kuc_transport != KUC_TRANSPORT_HSM ||
267 kuch->kuc_msgtype != HMT_ACTION_LIST) {
268 llapi_err_noerrno(LLAPI_MSG_ERROR,
269 "Unknown HSM message type %d:%d\n",
270 kuch->kuc_transport, kuch->kuc_msgtype);
275 if (kuch->kuc_msglen < sizeof(*kuch) + sizeof(*hal)) {
276 llapi_err_noerrno(LLAPI_MSG_ERROR, "Short HSM message %d",
282 /* Our message is a hsm_action_list. Use pointer math to skip
283 * kuch_hdr and point directly to the message payload.
285 hal = (struct hsm_action_list *)(kuch + 1);
287 /* Check that we have registered for this archive #
288 * if 0 registered, we serve any archive */
290 ((1 << (hal->hal_archive_id - 1)) & ct->archives) == 0) {
291 llapi_err_noerrno(LLAPI_MSG_INFO,
292 "This copytool does not service archive #%d,"
293 " ignoring this request."
294 " Mask of served archive is 0x%.8X",
295 hal->hal_archive_id, ct->archives);
302 *msgsize = kuch->kuc_msglen - sizeof(*kuch);
312 /** Release the action list when done with it. */
313 void llapi_hsm_action_list_free(struct hsm_action_list **hal)
315 /* Reuse the llapi_changelog_free function */
316 llapi_changelog_free((struct changelog_ext_rec **)hal);
319 /** Get parent path from mount point and fid.
321 * \param mnt Filesystem root path.
322 * \param fid Object FID.
323 * \param parent Destination buffer.
324 * \param parent_len Destination buffer size.
325 * \return 0 on success.
327 static int fid_parent(const char *mnt, const lustre_fid *fid, char *parent,
332 long long recno = -1;
334 char strfid[FID_NOBRACE_LEN + 1];
337 snprintf(strfid, sizeof(strfid), DFID_NOBRACE, PFID(fid));
339 rc = llapi_fid2path(mnt, strfid, file, sizeof(file),
344 /* fid2path returns a relative path */
345 rc = snprintf(parent, parent_len, "%s/%s", mnt, file);
346 if (rc >= parent_len)
347 return -ENAMETOOLONG;
349 /* remove file name */
350 ptr = strrchr(parent, '/');
351 if (ptr == NULL || ptr == parent) {
361 static int ct_open_by_fid(const struct hsm_copytool_private *ct,
362 const struct lu_fid *fid, int open_flags)
364 char fid_name[FID_NOBRACE_LEN + 1];
366 snprintf(fid_name, sizeof(fid_name), DFID_NOBRACE, PFID(fid));
368 return openat(ct->open_by_fid_fd, fid_name, open_flags);
371 static int ct_stat_by_fid(const struct hsm_copytool_private *ct,
372 const struct lu_fid *fid,
375 char fid_name[FID_NOBRACE_LEN + 1];
377 snprintf(fid_name, sizeof(fid_name), DFID_NOBRACE, PFID(fid));
379 return fstatat(ct->open_by_fid_fd, fid_name, buf, 0);
382 /** Create the destination volatile file for a restore operation.
384 * \param hcp Private copyaction handle.
385 * \param mdt_index MDT index where to create the volatile file.
386 * \param flags Volatile file creation flags.
387 * \return 0 on success.
389 static int create_restore_volatile(struct hsm_copyaction_private *hcp,
390 int mdt_index, int open_flags)
394 char parent[PATH_MAX + 1];
395 const char *mnt = hcp->ct_priv->mnt;
396 struct hsm_action_item *hai = &hcp->copy.hc_hai;
398 rc = fid_parent(mnt, &hai->hai_fid, parent, sizeof(parent));
400 /* fid_parent() failed, try to keep on going */
401 llapi_error(LLAPI_MSG_ERROR, rc,
402 "cannot get parent path to restore "DFID" "
403 "using '%s'", PFID(&hai->hai_fid), mnt);
404 snprintf(parent, sizeof(parent), "%s", mnt);
407 fd = llapi_create_volatile_idx(parent, mdt_index, open_flags);
411 rc = fchown(fd, hcp->stat.st_uid, hcp->stat.st_gid);
415 rc = llapi_fd2fid(fd, &hai->hai_dfid);
430 /** Start processing an HSM action.
431 * Should be called by copytools just before starting handling a request.
432 * It could be skipped if copytool only want to directly report an error,
433 * \see llapi_hsm_action_end().
435 * \param hcp Opaque action handle to be passed to
436 * llapi_hsm_action_progress and llapi_hsm_action_end.
437 * \param ct Copytool handle acquired at registration.
438 * \param hai The hsm_action_item describing the request.
439 * \param restore_mdt_index On restore: MDT index where to create the volatile
440 * file. Use -1 for default.
441 * \param restore_open_flags On restore: volatile file creation mode. Use
442 * O_LOV_DELAY_CREATE to manually set the LOVEA
444 * \param is_error Whether this call is just to report an error.
446 * \return 0 on success.
448 int llapi_hsm_action_begin(struct hsm_copyaction_private **phcp,
449 const struct hsm_copytool_private *ct,
450 const struct hsm_action_item *hai,
451 int restore_mdt_index, int restore_open_flags,
454 struct hsm_copyaction_private *hcp;
457 hcp = calloc(1, sizeof(*hcp));
463 hcp->copy.hc_hai = *hai;
464 hcp->copy.hc_hai.hai_len = sizeof(*hai);
469 if (hai->hai_action == HSMA_RESTORE) {
470 rc = ct_stat_by_fid(hcp->ct_priv, &hai->hai_fid, &hcp->stat);
474 rc = create_restore_volatile(hcp, restore_mdt_index,
480 rc = ioctl(ct->mnt_fd, LL_IOC_HSM_COPY_START, &hcp->copy);
487 hcp->magic = CP_PRIV_MAGIC;
492 if (!(hcp->data_fd < 0))
500 /** Terminate an HSM action processing.
501 * Should be called by copytools just having finished handling the request.
502 * \param hdl[in,out] Handle returned by llapi_hsm_action_start.
503 * \param he[in] The final range of copied data (for copy actions).
504 * \param errval[in] The status code of the operation.
505 * \param flags[in] The flags about the termination status (HP_FLAG_RETRY if
506 * the error is retryable).
508 * \return 0 on success.
510 int llapi_hsm_action_end(struct hsm_copyaction_private **phcp,
511 const struct hsm_extent *he, int hp_flags, int errval)
513 struct hsm_copyaction_private *hcp;
514 struct hsm_action_item *hai;
517 if (phcp == NULL || *phcp == NULL || he == NULL)
522 if (hcp->magic != CP_PRIV_MAGIC)
525 hai = &hcp->copy.hc_hai;
527 if (hai->hai_action == HSMA_RESTORE && errval == 0) {
528 struct timeval tv[2];
530 /* Set {a,m}time of volatile file to that of original. */
531 tv[0].tv_sec = hcp->stat.st_atime;
533 tv[1].tv_sec = hcp->stat.st_mtime;
535 if (futimes(hcp->data_fd, tv) < 0) {
540 rc = fsync(hcp->data_fd);
548 /* In some cases, like restore, 2 FIDs are used.
549 * Set the right FID to use here. */
550 if (hai->hai_action == HSMA_ARCHIVE || hai->hai_action == HSMA_RESTORE)
551 hai->hai_fid = hai->hai_dfid;
553 /* Fill the last missing data that will be needed by
554 * kernel to send a hsm_progress. */
555 hcp->copy.hc_flags = hp_flags;
556 hcp->copy.hc_errval = abs(errval);
558 hcp->copy.hc_hai.hai_extent = *he;
560 rc = ioctl(hcp->ct_priv->mnt_fd, LL_IOC_HSM_COPY_END, &hcp->copy);
567 if (!(hcp->data_fd < 0))
576 /** Notify a progress in processing an HSM action.
577 * \param hdl[in,out] handle returned by llapi_hsm_action_start.
578 * \param he[in] the range of copied data (for copy actions).
579 * \param hp_flags[in] HSM progress flags.
580 * \return 0 on success.
582 int llapi_hsm_action_progress(struct hsm_copyaction_private *hcp,
583 const struct hsm_extent *he, int hp_flags)
586 struct hsm_progress hp;
587 struct hsm_action_item *hai;
589 if (hcp == NULL || he == NULL)
592 if (hcp->magic != CP_PRIV_MAGIC)
595 hai = &hcp->copy.hc_hai;
597 memset(&hp, 0, sizeof(hp));
599 hp.hp_cookie = hai->hai_cookie;
600 hp.hp_flags = hp_flags;
602 /* Progress is made on the data fid */
603 hp.hp_fid = hai->hai_dfid;
606 rc = ioctl(hcp->ct_priv->mnt_fd, LL_IOC_HSM_PROGRESS, &hp);
613 /** Get the fid of object to be used for copying data.
614 * @return error code if the action is not a copy operation.
616 int llapi_hsm_action_get_dfid(const struct hsm_copyaction_private *hcp,
619 const struct hsm_action_item *hai = &hcp->copy.hc_hai;
621 if (hcp->magic != CP_PRIV_MAGIC)
624 if (hai->hai_action != HSMA_RESTORE && hai->hai_action != HSMA_ARCHIVE)
627 *fid = hai->hai_dfid;
633 * Get a file descriptor to be used for copying data. It's up to the
634 * caller to close the FDs obtained from this function.
636 * @retval a file descriptor on success.
637 * @retval a negative error code on failure.
639 int llapi_hsm_action_get_fd(const struct hsm_copyaction_private *hcp)
641 const struct hsm_action_item *hai = &hcp->copy.hc_hai;
643 if (hcp->magic != CP_PRIV_MAGIC)
646 if (hai->hai_action == HSMA_ARCHIVE)
647 return ct_open_by_fid(hcp->ct_priv, &hai->hai_dfid,
648 O_RDONLY | O_NOATIME | O_NOFOLLOW | O_NONBLOCK);
649 else if (hai->hai_action == HSMA_RESTORE)
650 return dup(hcp->data_fd);
656 * Import an existing hsm-archived file into Lustre.
658 * Caller must access file by (returned) newfid value from now on.
660 * \param dst path to Lustre destination (e.g. /mnt/lustre/my/file).
661 * \param archive archive number.
662 * \param st struct stat buffer containing file ownership, perm, etc.
663 * \param stripe_* Striping options. Currently ignored, since the restore
664 * operation will set the striping. In V2, this striping might
666 * \param newfid[out] Filled with new Lustre fid.
668 int llapi_hsm_import(const char *dst, int archive, const struct stat *st,
669 unsigned long long stripe_size, int stripe_offset,
670 int stripe_count, int stripe_pattern, char *pool_name,
673 struct hsm_user_import hui;
677 if (stripe_pattern == 0)
678 stripe_pattern = LOV_PATTERN_RAID0;
680 /* Create a non-striped file */
681 fd = llapi_file_open_pool(dst, O_CREAT | O_WRONLY, st->st_mode,
682 stripe_size, stripe_offset, stripe_count,
683 stripe_pattern | LOV_PATTERN_F_RELEASED,
686 llapi_error(LLAPI_MSG_ERROR, -errno,
687 "cannot create '%s' for import", dst);
691 /* Get the new fid in Lustre. Caller needs to use this fid
693 rc = llapi_fd2fid(fd, newfid);
695 llapi_error(LLAPI_MSG_ERROR, rc,
696 "cannot get fid of '%s' for import", dst);
700 hui.hui_uid = st->st_uid;
701 hui.hui_gid = st->st_gid;
702 hui.hui_mode = st->st_mode;
703 hui.hui_size = st->st_size;
704 hui.hui_archive_id = archive;
705 hui.hui_atime = st->st_atime;
706 hui.hui_atime_ns = st->st_atim.tv_nsec;
707 hui.hui_mtime = st->st_mtime;
708 hui.hui_mtime_ns = st->st_mtim.tv_nsec;
709 rc = ioctl(fd, LL_IOC_HSM_IMPORT, &hui);
711 llapi_error(LLAPI_MSG_ERROR, rc, "cannot import '%s'", dst);
725 * Return the current HSM states and HSM requests related to file pointed by \a
728 * \param hus Should be allocated by caller. Will be filled with current file
731 * \retval 0 on success.
732 * \retval -errno on error.
734 int llapi_hsm_state_get_fd(int fd, struct hsm_user_state *hus)
738 rc = ioctl(fd, LL_IOC_HSM_STATE_GET, hus);
739 /* If error, save errno value */
740 rc = rc ? -errno : 0;
746 * Return the current HSM states and HSM requests related to file pointed by \a
749 * see llapi_hsm_state_get_fd() for args use and return
751 int llapi_hsm_state_get(const char *path, struct hsm_user_state *hus)
756 fd = open(path, O_RDONLY | O_NONBLOCK);
760 rc = llapi_hsm_state_get_fd(fd, hus);
767 * Set HSM states of file pointed by \a fd
769 * Using the provided bitmasks, the current HSM states for this file will be
770 * changed. \a archive_id could be used to change the archive number also. Set
771 * it to 0 if you do not want to change it.
773 * \param setmask Bitmask for flag to be set.
774 * \param clearmask Bitmask for flag to be cleared.
775 * \param archive_id Archive number identifier to use. 0 means no change.
777 * \retval 0 on success.
778 * \retval -errno on error.
780 int llapi_hsm_state_set_fd(int fd, __u64 setmask, __u64 clearmask,
783 struct hsm_state_set hss;
786 hss.hss_valid = HSS_SETMASK|HSS_CLEARMASK;
787 hss.hss_setmask = setmask;
788 hss.hss_clearmask = clearmask;
789 /* Change archive_id if provided. We can only change
790 * to set something different than 0. */
791 if (archive_id > 0) {
792 hss.hss_valid |= HSS_ARCHIVE_ID;
793 hss.hss_archive_id = archive_id;
795 rc = ioctl(fd, LL_IOC_HSM_STATE_SET, &hss);
796 /* If error, save errno value */
797 rc = rc ? -errno : 0;
803 * Set HSM states of file pointed by \a path.
805 * see llapi_hsm_state_set_fd() for args use and return
807 int llapi_hsm_state_set(const char *path, __u64 setmask, __u64 clearmask,
813 fd = open(path, O_WRONLY | O_LOV_DELAY_CREATE | O_NONBLOCK);
817 rc = llapi_hsm_state_set_fd(fd, setmask, clearmask, archive_id);
824 * Return the current HSM request related to file pointed by \a path.
826 * \param hca Should be allocated by caller. Will be filled with current file
829 * \retval 0 on success.
830 * \retval -errno on error.
832 int llapi_hsm_current_action(const char *path, struct hsm_current_action *hca)
837 fd = open(path, O_RDONLY | O_NONBLOCK);
841 rc = ioctl(fd, LL_IOC_HSM_ACTION, hca);
842 /* If error, save errno value */
843 rc = rc ? -errno : 0;
850 * Allocate a hsm_user_request with the specified carateristics.
851 * This structure should be freed with free().
853 * \return an allocated structure on success, NULL otherwise.
855 struct hsm_user_request *llapi_hsm_user_request_alloc(int itemcount,
860 len += sizeof(struct hsm_user_request);
861 len += sizeof(struct hsm_user_item) * itemcount;
864 return (struct hsm_user_request *)malloc(len);
868 * Send a HSM request to Lustre, described in \param request.
870 * \param path Fullpath to the file to operate on.
871 * \param request The request, allocated with llapi_hsm_user_request_alloc().
873 * \return 0 on success, an error code otherwise.
875 int llapi_hsm_request(const char *path, const struct hsm_user_request *request)
880 rc = get_root_path(WANT_FD, NULL, &fd, (char *)path, -1);
884 rc = ioctl(fd, LL_IOC_HSM_REQUEST, request);
885 /* If error, save errno value */
886 rc = rc ? -errno : 0;