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 #define OPEN_BY_FID_PATH dot_lustre_name"/fid"
64 /****** HSM Copytool API ********/
65 #define CT_PRIV_MAGIC 0xC0BE2001
66 struct hsm_copytool_private {
71 lustre_kernelcomm kuc;
75 #define CP_PRIV_MAGIC 0x19880429
76 struct hsm_copyaction_private {
79 const struct hsm_copytool_private *ct_priv;
84 #include <libcfs/libcfs.h>
86 /** Register a copytool
87 * \param[out] priv Opaque private control structure
88 * \param mnt Lustre filesystem mount point
89 * \param flags Open flags, currently unused (e.g. O_NONBLOCK)
90 * \param archive_count
91 * \param archives Which archive numbers this copytool is responsible for
93 int llapi_hsm_copytool_register(struct hsm_copytool_private **priv,
94 const char *mnt, int flags, int archive_count,
97 struct hsm_copytool_private *ct;
100 if (archive_count > 0 && archives == NULL) {
101 llapi_err_noerrno(LLAPI_MSG_ERROR,
102 "NULL archive numbers");
106 ct = calloc(1, sizeof(*ct));
110 ct->magic = CT_PRIV_MAGIC;
112 ct->open_by_fid_fd = -1;
113 ct->kuc.lk_rfd = LK_NOFD;
114 ct->kuc.lk_wfd = LK_NOFD;
116 ct->mnt = strdup(mnt);
117 if (ct->mnt == NULL) {
122 ct->mnt_fd = open(ct->mnt, O_RDONLY);
123 if (ct->mnt_fd < 0) {
128 ct->open_by_fid_fd = openat(ct->mnt_fd, OPEN_BY_FID_PATH, O_RDONLY);
129 if (ct->open_by_fid_fd < 0) {
134 /* no archives specified means "match all". */
136 for (rc = 0; rc < archive_count; rc++) {
137 if (archives[rc] > 8 * sizeof(ct->archives)) {
138 llapi_err_noerrno(LLAPI_MSG_ERROR,
139 "maximum of %zu archives supported",
140 8 * sizeof(ct->archives));
143 /* in the list we have a all archive wildcard
144 * so move to all archives mode
146 if (archives[rc] == 0) {
151 ct->archives |= (1 << (archives[rc] - 1));
154 rc = libcfs_ukuc_start(&ct->kuc, KUC_GRP_HSM);
158 /* Storing archive(s) in lk_data; see mdc_ioc_hsm_ct_start */
159 ct->kuc.lk_data = ct->archives;
160 rc = ioctl(ct->mnt_fd, LL_IOC_HSM_CT_START, &ct->kuc);
163 llapi_error(LLAPI_MSG_ERROR, rc,
164 "cannot start copytool on '%s'", mnt);
170 /* Only the kernel reference keeps the write side open */
171 close(ct->kuc.lk_wfd);
172 ct->kuc.lk_wfd = LK_NOFD;
180 /* cleanup the kuc channel */
181 libcfs_ukuc_stop(&ct->kuc);
184 if (!(ct->mnt_fd < 0))
187 if (!(ct->open_by_fid_fd < 0))
188 close(ct->open_by_fid_fd);
198 /** Deregister a copytool
199 * Note: under Linux, until llapi_hsm_copytool_unregister is called
200 * (or the program is killed), the libcfs module will be referenced
201 * and unremovable, even after Lustre services stop.
203 int llapi_hsm_copytool_unregister(struct hsm_copytool_private **priv)
205 struct hsm_copytool_private *ct;
207 if (priv == NULL || *priv == NULL)
211 if (ct->magic != CT_PRIV_MAGIC)
214 /* Tell the kernel to stop sending us messages */
215 ct->kuc.lk_flags = LK_FLG_STOP;
216 ioctl(ct->mnt_fd, LL_IOC_HSM_CT_START, &ct->kuc);
218 /* Shut down the kernelcomms */
219 libcfs_ukuc_stop(&ct->kuc);
221 close(ct->open_by_fid_fd);
230 /** Wait for the next hsm_action_list
231 * \param ct Opaque private control structure
232 * \param halh Action list handle, will be allocated here
233 * \param msgsize Number of bytes in the message, will be set here
234 * \return 0 valid message received; halh and msgsize are set
237 int llapi_hsm_copytool_recv(struct hsm_copytool_private *ct,
238 struct hsm_action_list **halh, int *msgsize)
240 struct kuc_hdr *kuch;
241 struct hsm_action_list *hal;
244 if (ct == NULL || ct->magic != CT_PRIV_MAGIC)
247 if (halh == NULL || msgsize == NULL)
250 kuch = malloc(HAL_MAXSIZE + sizeof(*kuch));
254 rc = libcfs_ukuc_msg_get(&ct->kuc, (char *)kuch,
255 HAL_MAXSIZE + sizeof(*kuch),
260 /* Handle generic messages */
261 if (kuch->kuc_transport == KUC_TRANSPORT_GENERIC &&
262 kuch->kuc_msgtype == KUC_MSG_SHUTDOWN) {
267 if (kuch->kuc_transport != KUC_TRANSPORT_HSM ||
268 kuch->kuc_msgtype != HMT_ACTION_LIST) {
269 llapi_err_noerrno(LLAPI_MSG_ERROR,
270 "Unknown HSM message type %d:%d\n",
271 kuch->kuc_transport, kuch->kuc_msgtype);
276 if (kuch->kuc_msglen < sizeof(*kuch) + sizeof(*hal)) {
277 llapi_err_noerrno(LLAPI_MSG_ERROR, "Short HSM message %d",
283 /* Our message is a hsm_action_list. Use pointer math to skip
284 * kuch_hdr and point directly to the message payload.
286 hal = (struct hsm_action_list *)(kuch + 1);
288 /* Check that we have registered for this archive #
289 * if 0 registered, we serve any archive */
291 ((1 << (hal->hal_archive_id - 1)) & ct->archives) == 0) {
292 llapi_err_noerrno(LLAPI_MSG_INFO,
293 "This copytool does not service archive #%d,"
294 " ignoring this request."
295 " Mask of served archive is 0x%.8X",
296 hal->hal_archive_id, ct->archives);
303 *msgsize = kuch->kuc_msglen - sizeof(*kuch);
313 /** Release the action list when done with it. */
314 void llapi_hsm_action_list_free(struct hsm_action_list **hal)
316 /* Reuse the llapi_changelog_free function */
317 llapi_changelog_free((struct changelog_ext_rec **)hal);
320 /** Get parent path from mount point and fid.
322 * \param mnt Filesystem root path.
323 * \param fid Object FID.
324 * \param parent Destination buffer.
325 * \param parent_len Destination buffer size.
326 * \return 0 on success.
328 static int fid_parent(const char *mnt, const lustre_fid *fid, char *parent,
333 long long recno = -1;
335 char strfid[FID_NOBRACE_LEN + 1];
338 snprintf(strfid, sizeof(strfid), DFID_NOBRACE, PFID(fid));
340 rc = llapi_fid2path(mnt, strfid, file, sizeof(file),
345 /* fid2path returns a relative path */
346 rc = snprintf(parent, parent_len, "%s/%s", mnt, file);
347 if (rc >= parent_len)
348 return -ENAMETOOLONG;
350 /* remove file name */
351 ptr = strrchr(parent, '/');
352 if (ptr == NULL || ptr == parent) {
362 static int ct_open_by_fid(const struct hsm_copytool_private *ct,
363 const struct lu_fid *fid, int open_flags)
365 char fid_name[FID_NOBRACE_LEN + 1];
367 snprintf(fid_name, sizeof(fid_name), DFID_NOBRACE, PFID(fid));
369 return openat(ct->open_by_fid_fd, fid_name, open_flags);
372 static int ct_stat_by_fid(const struct hsm_copytool_private *ct,
373 const struct lu_fid *fid,
376 char fid_name[FID_NOBRACE_LEN + 1];
378 snprintf(fid_name, sizeof(fid_name), DFID_NOBRACE, PFID(fid));
380 return fstatat(ct->open_by_fid_fd, fid_name, buf, 0);
383 /** Create the destination volatile file for a restore operation.
385 * \param hcp Private copyaction handle.
386 * \param mdt_index MDT index where to create the volatile file.
387 * \param flags Volatile file creation flags.
388 * \return 0 on success.
390 static int create_restore_volatile(struct hsm_copyaction_private *hcp,
391 int mdt_index, int open_flags)
395 char parent[PATH_MAX + 1];
396 const char *mnt = hcp->ct_priv->mnt;
397 struct hsm_action_item *hai = &hcp->copy.hc_hai;
399 rc = fid_parent(mnt, &hai->hai_fid, parent, sizeof(parent));
401 /* fid_parent() failed, try to keep on going */
402 llapi_error(LLAPI_MSG_ERROR, rc,
403 "cannot get parent path to restore "DFID" "
404 "using '%s'", PFID(&hai->hai_fid), mnt);
405 snprintf(parent, sizeof(parent), "%s", mnt);
408 fd = llapi_create_volatile_idx(parent, mdt_index, open_flags);
412 rc = fchown(fd, hcp->stat.st_uid, hcp->stat.st_gid);
416 rc = llapi_fd2fid(fd, &hai->hai_dfid);
431 /** Start processing an HSM action.
432 * Should be called by copytools just before starting handling a request.
433 * It could be skipped if copytool only want to directly report an error,
434 * \see llapi_hsm_action_end().
436 * \param hcp Opaque action handle to be passed to
437 * llapi_hsm_action_progress and llapi_hsm_action_end.
438 * \param ct Copytool handle acquired at registration.
439 * \param hai The hsm_action_item describing the request.
440 * \param restore_mdt_index On restore: MDT index where to create the volatile
441 * file. Use -1 for default.
442 * \param restore_open_flags On restore: volatile file creation mode. Use
443 * O_LOV_DELAY_CREATE to manually set the LOVEA
445 * \param is_error Whether this call is just to report an error.
447 * \return 0 on success.
449 int llapi_hsm_action_begin(struct hsm_copyaction_private **phcp,
450 const struct hsm_copytool_private *ct,
451 const struct hsm_action_item *hai,
452 int restore_mdt_index, int restore_open_flags,
455 struct hsm_copyaction_private *hcp;
458 hcp = calloc(1, sizeof(*hcp));
464 hcp->copy.hc_hai = *hai;
465 hcp->copy.hc_hai.hai_len = sizeof(*hai);
470 if (hai->hai_action == HSMA_RESTORE) {
471 rc = ct_stat_by_fid(hcp->ct_priv, &hai->hai_fid, &hcp->stat);
475 rc = create_restore_volatile(hcp, restore_mdt_index,
481 rc = ioctl(ct->mnt_fd, LL_IOC_HSM_COPY_START, &hcp->copy);
488 hcp->magic = CP_PRIV_MAGIC;
493 if (!(hcp->data_fd < 0))
501 /** Terminate an HSM action processing.
502 * Should be called by copytools just having finished handling the request.
503 * \param hdl[in,out] Handle returned by llapi_hsm_action_start.
504 * \param he[in] The final range of copied data (for copy actions).
505 * \param errval[in] The status code of the operation.
506 * \param flags[in] The flags about the termination status (HP_FLAG_RETRY if
507 * the error is retryable).
509 * \return 0 on success.
511 int llapi_hsm_action_end(struct hsm_copyaction_private **phcp,
512 const struct hsm_extent *he, int hp_flags, int errval)
514 struct hsm_copyaction_private *hcp;
515 struct hsm_action_item *hai;
518 if (phcp == NULL || *phcp == NULL || he == NULL)
523 if (hcp->magic != CP_PRIV_MAGIC)
526 hai = &hcp->copy.hc_hai;
528 if (hai->hai_action == HSMA_RESTORE && errval == 0) {
529 struct timeval tv[2];
531 /* Set {a,m}time of volatile file to that of original. */
532 tv[0].tv_sec = hcp->stat.st_atime;
534 tv[1].tv_sec = hcp->stat.st_mtime;
536 if (futimes(hcp->data_fd, tv) < 0) {
541 rc = fsync(hcp->data_fd);
549 /* In some cases, like restore, 2 FIDs are used.
550 * Set the right FID to use here. */
551 if (hai->hai_action == HSMA_ARCHIVE || hai->hai_action == HSMA_RESTORE)
552 hai->hai_fid = hai->hai_dfid;
554 /* Fill the last missing data that will be needed by
555 * kernel to send a hsm_progress. */
556 hcp->copy.hc_flags = hp_flags;
557 hcp->copy.hc_errval = abs(errval);
559 hcp->copy.hc_hai.hai_extent = *he;
561 rc = ioctl(hcp->ct_priv->mnt_fd, LL_IOC_HSM_COPY_END, &hcp->copy);
568 if (!(hcp->data_fd < 0))
577 /** Notify a progress in processing an HSM action.
578 * \param hdl[in,out] handle returned by llapi_hsm_action_start.
579 * \param he[in] the range of copied data (for copy actions).
580 * \param hp_flags[in] HSM progress flags.
581 * \return 0 on success.
583 int llapi_hsm_action_progress(struct hsm_copyaction_private *hcp,
584 const struct hsm_extent *he, int hp_flags)
587 struct hsm_progress hp;
588 struct hsm_action_item *hai;
590 if (hcp == NULL || he == NULL)
593 if (hcp->magic != CP_PRIV_MAGIC)
596 hai = &hcp->copy.hc_hai;
598 memset(&hp, 0, sizeof(hp));
600 hp.hp_cookie = hai->hai_cookie;
601 hp.hp_flags = hp_flags;
603 /* Progress is made on the data fid */
604 hp.hp_fid = hai->hai_dfid;
607 rc = ioctl(hcp->ct_priv->mnt_fd, LL_IOC_HSM_PROGRESS, &hp);
614 /** Get the fid of object to be used for copying data.
615 * @return error code if the action is not a copy operation.
617 int llapi_hsm_action_get_dfid(const struct hsm_copyaction_private *hcp,
620 const struct hsm_action_item *hai = &hcp->copy.hc_hai;
622 if (hcp->magic != CP_PRIV_MAGIC)
625 if (hai->hai_action != HSMA_RESTORE && hai->hai_action != HSMA_ARCHIVE)
628 *fid = hai->hai_dfid;
634 * Get a file descriptor to be used for copying data. It's up to the
635 * caller to close the FDs obtained from this function.
637 * @retval a file descriptor on success.
638 * @retval a negative error code on failure.
640 int llapi_hsm_action_get_fd(const struct hsm_copyaction_private *hcp)
642 const struct hsm_action_item *hai = &hcp->copy.hc_hai;
644 if (hcp->magic != CP_PRIV_MAGIC)
647 if (hai->hai_action == HSMA_ARCHIVE)
648 return ct_open_by_fid(hcp->ct_priv, &hai->hai_dfid,
649 O_RDONLY | O_NOATIME | O_NOFOLLOW | O_NONBLOCK);
650 else if (hai->hai_action == HSMA_RESTORE)
651 return dup(hcp->data_fd);
657 * Import an existing hsm-archived file into Lustre.
659 * Caller must access file by (returned) newfid value from now on.
661 * \param dst path to Lustre destination (e.g. /mnt/lustre/my/file).
662 * \param archive archive number.
663 * \param st struct stat buffer containing file ownership, perm, etc.
664 * \param stripe_* Striping options. Currently ignored, since the restore
665 * operation will set the striping. In V2, this striping might
667 * \param newfid[out] Filled with new Lustre fid.
669 int llapi_hsm_import(const char *dst, int archive, const struct stat *st,
670 unsigned long long stripe_size, int stripe_offset,
671 int stripe_count, int stripe_pattern, char *pool_name,
674 struct hsm_user_import hui;
678 if (stripe_pattern == 0)
679 stripe_pattern = LOV_PATTERN_RAID0;
681 /* Create a non-striped file */
682 fd = llapi_file_open_pool(dst, O_CREAT | O_WRONLY, st->st_mode,
683 stripe_size, stripe_offset, stripe_count,
684 stripe_pattern | LOV_PATTERN_F_RELEASED,
687 llapi_error(LLAPI_MSG_ERROR, -errno,
688 "cannot create '%s' for import", dst);
692 /* Get the new fid in Lustre. Caller needs to use this fid
694 rc = llapi_fd2fid(fd, newfid);
696 llapi_error(LLAPI_MSG_ERROR, rc,
697 "cannot get fid of '%s' for import", dst);
701 hui.hui_uid = st->st_uid;
702 hui.hui_gid = st->st_gid;
703 hui.hui_mode = st->st_mode;
704 hui.hui_size = st->st_size;
705 hui.hui_archive_id = archive;
706 hui.hui_atime = st->st_atime;
707 hui.hui_atime_ns = st->st_atim.tv_nsec;
708 hui.hui_mtime = st->st_mtime;
709 hui.hui_mtime_ns = st->st_mtim.tv_nsec;
710 rc = ioctl(fd, LL_IOC_HSM_IMPORT, &hui);
712 llapi_error(LLAPI_MSG_ERROR, rc, "cannot import '%s'", dst);
726 * Return the current HSM states and HSM requests related to file pointed by \a
729 * \param hus Should be allocated by caller. Will be filled with current file
732 * \retval 0 on success.
733 * \retval -errno on error.
735 int llapi_hsm_state_get_fd(int fd, struct hsm_user_state *hus)
739 rc = ioctl(fd, LL_IOC_HSM_STATE_GET, hus);
740 /* If error, save errno value */
741 rc = rc ? -errno : 0;
747 * Return the current HSM states and HSM requests related to file pointed by \a
750 * see llapi_hsm_state_get_fd() for args use and return
752 int llapi_hsm_state_get(const char *path, struct hsm_user_state *hus)
757 fd = open(path, O_RDONLY | O_NONBLOCK);
761 rc = llapi_hsm_state_get_fd(fd, hus);
768 * Set HSM states of file pointed by \a fd
770 * Using the provided bitmasks, the current HSM states for this file will be
771 * changed. \a archive_id could be used to change the archive number also. Set
772 * it to 0 if you do not want to change it.
774 * \param setmask Bitmask for flag to be set.
775 * \param clearmask Bitmask for flag to be cleared.
776 * \param archive_id Archive number identifier to use. 0 means no change.
778 * \retval 0 on success.
779 * \retval -errno on error.
781 int llapi_hsm_state_set_fd(int fd, __u64 setmask, __u64 clearmask,
784 struct hsm_state_set hss;
787 hss.hss_valid = HSS_SETMASK|HSS_CLEARMASK;
788 hss.hss_setmask = setmask;
789 hss.hss_clearmask = clearmask;
790 /* Change archive_id if provided. We can only change
791 * to set something different than 0. */
792 if (archive_id > 0) {
793 hss.hss_valid |= HSS_ARCHIVE_ID;
794 hss.hss_archive_id = archive_id;
796 rc = ioctl(fd, LL_IOC_HSM_STATE_SET, &hss);
797 /* If error, save errno value */
798 rc = rc ? -errno : 0;
804 * Set HSM states of file pointed by \a path.
806 * see llapi_hsm_state_set_fd() for args use and return
808 int llapi_hsm_state_set(const char *path, __u64 setmask, __u64 clearmask,
814 fd = open(path, O_WRONLY | O_LOV_DELAY_CREATE | O_NONBLOCK);
818 rc = llapi_hsm_state_set_fd(fd, setmask, clearmask, archive_id);
825 * Return the current HSM request related to file pointed by \a path.
827 * \param hca Should be allocated by caller. Will be filled with current file
830 * \retval 0 on success.
831 * \retval -errno on error.
833 int llapi_hsm_current_action(const char *path, struct hsm_current_action *hca)
838 fd = open(path, O_RDONLY | O_NONBLOCK);
842 rc = ioctl(fd, LL_IOC_HSM_ACTION, hca);
843 /* If error, save errno value */
844 rc = rc ? -errno : 0;
851 * Allocate a hsm_user_request with the specified carateristics.
852 * This structure should be freed with free().
854 * \return an allocated structure on success, NULL otherwise.
856 struct hsm_user_request *llapi_hsm_user_request_alloc(int itemcount,
861 len += sizeof(struct hsm_user_request);
862 len += sizeof(struct hsm_user_item) * itemcount;
865 return (struct hsm_user_request *)malloc(len);
869 * Send a HSM request to Lustre, described in \param request.
871 * \param path Fullpath to the file to operate on.
872 * \param request The request, allocated with llapi_hsm_user_request_alloc().
874 * \return 0 on success, an error code otherwise.
876 int llapi_hsm_request(const char *path, const struct hsm_user_request *request)
881 rc = get_root_path(WANT_FD, NULL, &fd, (char *)path, -1);
885 rc = ioctl(fd, LL_IOC_HSM_REQUEST, request);
886 /* If error, save errno value */
887 rc = rc ? -errno : 0;