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 %zu 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);
158 ct->kuc.lk_wfd = LK_NOFD;
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 * \param mdt_index MDT index where to create the volatile file.
345 * \param flags Volatile file creation flags.
346 * \return 0 on success.
348 static int create_restore_volatile(struct hsm_copyaction_private *hcp,
349 int mdt_index, int flags)
353 char parent[PATH_MAX + 1];
354 const char *mnt = hcp->ct_priv->mnt;
355 struct hsm_action_item *hai = &hcp->copy.hc_hai;
357 rc = fid_parent(mnt, &hai->hai_fid, parent, sizeof(parent));
359 /* fid_parent() failed, try to keep on going */
360 llapi_error(LLAPI_MSG_ERROR, rc,
361 "cannot get parent path to restore "DFID
362 "using '%s'", PFID(&hai->hai_fid), mnt);
363 snprintf(parent, sizeof(parent), "%s", mnt);
366 fd = llapi_create_volatile_idx(parent, mdt_index, flags);
370 rc = llapi_fd2fid(fd, &hai->hai_dfid);
385 /** Start processing an HSM action.
386 * Should be called by copytools just before starting handling a request.
387 * It could be skipped if copytool only want to directly report an error,
388 * \see llapi_hsm_action_end().
390 * \param hcp Opaque action handle to be passed to
391 * llapi_hsm_action_progress and llapi_hsm_action_end.
392 * \param ct Copytool handle acquired at registration.
393 * \param hai The hsm_action_item describing the request.
394 * \param restore_mdt_index On restore: MDT index where to create the volatile
395 * file. Use -1 for default.
396 * \param restore_open_flags On restore: volatile file creation mode. Use
397 * O_LOV_DELAY_CREATE to manually set the LOVEA
399 * \param is_error Whether this call is just to report an error.
401 * \return 0 on success.
403 int llapi_hsm_action_begin(struct hsm_copyaction_private **phcp,
404 const struct hsm_copytool_private *ct,
405 const struct hsm_action_item *hai,
406 int restore_mdt_index, int restore_open_flags,
409 struct hsm_copyaction_private *hcp;
412 hcp = calloc(1, sizeof(*hcp));
418 hcp->copy.hc_hai = *hai;
419 hcp->copy.hc_hai.hai_len = sizeof(*hai);
424 if (hai->hai_action == HSMA_RESTORE) {
425 rc = create_restore_volatile(hcp, restore_mdt_index,
431 rc = ioctl(ct->mnt_fd, LL_IOC_HSM_COPY_START, &hcp->copy);
438 hcp->magic = CP_PRIV_MAGIC;
443 if (!(hcp->data_fd < 0))
451 /** Terminate an HSM action processing.
452 * Should be called by copytools just having finished handling the request.
453 * \param hdl[in,out] Handle returned by llapi_hsm_action_start.
454 * \param he[in] The final range of copied data (for copy actions).
455 * \param errval[in] The status code of the operation.
456 * \param flags[in] The flags about the termination status (HP_FLAG_RETRY if
457 * the error is retryable).
459 * \return 0 on success.
461 int llapi_hsm_action_end(struct hsm_copyaction_private **phcp,
462 const struct hsm_extent *he, int flags, int errval)
464 struct hsm_copyaction_private *hcp;
465 struct hsm_action_item *hai;
468 if (phcp == NULL || *phcp == NULL || he == NULL)
473 if (hcp->magic != CP_PRIV_MAGIC)
476 hai = &hcp->copy.hc_hai;
478 /* In some cases, like restore, 2 FIDs are used.
479 * Set the right FID to use here. */
480 if (hai->hai_action == HSMA_ARCHIVE || hai->hai_action == HSMA_RESTORE)
481 hai->hai_fid = hai->hai_dfid;
483 /* Fill the last missing data that will be needed by
484 * kernel to send a hsm_progress. */
485 hcp->copy.hc_flags = flags;
486 hcp->copy.hc_errval = abs(errval);
488 hcp->copy.hc_hai.hai_extent = *he;
490 rc = ioctl(hcp->ct_priv->mnt_fd, LL_IOC_HSM_COPY_END, &hcp->copy);
497 if (!(hcp->data_fd < 0))
506 /** Notify a progress in processing an HSM action.
507 * \param hdl[in,out] handle returned by llapi_hsm_action_start.
508 * \param he[in] the range of copied data (for copy actions).
509 * \param hp_flags[in] HSM progress flags.
510 * \return 0 on success.
512 int llapi_hsm_action_progress(struct hsm_copyaction_private *hcp,
513 const struct hsm_extent *he, int hp_flags)
516 struct hsm_progress hp;
517 struct hsm_action_item *hai;
519 if (hcp == NULL || he == NULL)
522 if (hcp->magic != CP_PRIV_MAGIC)
525 hai = &hcp->copy.hc_hai;
527 memset(&hp, 0, sizeof(hp));
529 hp.hp_cookie = hai->hai_cookie;
530 hp.hp_flags = hp_flags;
532 /* Progress is made on the data fid */
533 hp.hp_fid = hai->hai_dfid;
536 rc = ioctl(hcp->ct_priv->mnt_fd, LL_IOC_HSM_PROGRESS, &hp);
543 /** Get the fid of object to be used for copying data.
544 * @return error code if the action is not a copy operation.
546 int llapi_hsm_action_get_dfid(const struct hsm_copyaction_private *hcp,
549 const struct hsm_action_item *hai = &hcp->copy.hc_hai;
551 if (hcp->magic != CP_PRIV_MAGIC)
554 if (hai->hai_action != HSMA_RESTORE && hai->hai_action != HSMA_ARCHIVE)
557 *fid = hai->hai_dfid;
563 * Get a file descriptor to be used for copying data. It's up to the
564 * caller to close the FDs obtained from this function.
566 * @retval a file descriptor on success.
567 * @retval a negative error code on failure.
569 int llapi_hsm_action_get_fd(const struct hsm_copyaction_private *hcp)
571 const struct hsm_action_item *hai = &hcp->copy.hc_hai;
573 if (hcp->magic != CP_PRIV_MAGIC)
576 if (hai->hai_action != HSMA_RESTORE)
579 return dup(hcp->data_fd);
583 * Import an existing hsm-archived file into Lustre.
585 * Caller must access file by (returned) newfid value from now on.
587 * \param dst path to Lustre destination (e.g. /mnt/lustre/my/file).
588 * \param archive archive number.
589 * \param st struct stat buffer containing file ownership, perm, etc.
590 * \param stripe_* Striping options. Currently ignored, since the restore
591 * operation will set the striping. In V2, this striping might
593 * \param newfid[out] Filled with new Lustre fid.
595 int llapi_hsm_import(const char *dst, int archive, const struct stat *st,
596 unsigned long long stripe_size, int stripe_offset,
597 int stripe_count, int stripe_pattern, char *pool_name,
600 struct hsm_user_import hui;
604 if (stripe_pattern == 0)
605 stripe_pattern = LOV_PATTERN_RAID0;
607 /* Create a non-striped file */
608 fd = llapi_file_open_pool(dst, O_CREAT | O_WRONLY, st->st_mode,
609 stripe_size, stripe_offset, stripe_count,
610 stripe_pattern | LOV_PATTERN_F_RELEASED,
613 llapi_error(LLAPI_MSG_ERROR, -errno,
614 "cannot create '%s' for import", dst);
618 /* Get the new fid in Lustre. Caller needs to use this fid
620 rc = llapi_fd2fid(fd, newfid);
622 llapi_error(LLAPI_MSG_ERROR, rc,
623 "cannot get fid of '%s' for import", dst);
627 hui.hui_uid = st->st_uid;
628 hui.hui_gid = st->st_gid;
629 hui.hui_mode = st->st_mode;
630 hui.hui_size = st->st_size;
631 hui.hui_archive_id = archive;
632 hui.hui_atime = st->st_atime;
633 hui.hui_atime_ns = st->st_atim.tv_nsec;
634 hui.hui_mtime = st->st_mtime;
635 hui.hui_mtime_ns = st->st_mtim.tv_nsec;
636 rc = ioctl(fd, LL_IOC_HSM_IMPORT, &hui);
638 llapi_error(LLAPI_MSG_ERROR, rc, "cannot import '%s'", dst);
652 * Return the current HSM states and HSM requests related to file pointed by \a
655 * \param hus Should be allocated by caller. Will be filled with current file
658 * \retval 0 on success.
659 * \retval -errno on error.
661 int llapi_hsm_state_get_fd(int fd, struct hsm_user_state *hus)
665 rc = ioctl(fd, LL_IOC_HSM_STATE_GET, hus);
666 /* If error, save errno value */
667 rc = rc ? -errno : 0;
673 * Return the current HSM states and HSM requests related to file pointed by \a
676 * see llapi_hsm_state_get_fd() for args use and return
678 int llapi_hsm_state_get(const char *path, struct hsm_user_state *hus)
683 fd = open(path, O_RDONLY | O_NONBLOCK);
687 rc = llapi_hsm_state_get_fd(fd, hus);
694 * Set HSM states of file pointed by \a fd
696 * Using the provided bitmasks, the current HSM states for this file will be
697 * changed. \a archive_id could be used to change the archive number also. Set
698 * it to 0 if you do not want to change it.
700 * \param setmask Bitmask for flag to be set.
701 * \param clearmask Bitmask for flag to be cleared.
702 * \param archive_id Archive number identifier to use. 0 means no change.
704 * \retval 0 on success.
705 * \retval -errno on error.
707 int llapi_hsm_state_set_fd(int fd, __u64 setmask, __u64 clearmask,
710 struct hsm_state_set hss;
713 hss.hss_valid = HSS_SETMASK|HSS_CLEARMASK;
714 hss.hss_setmask = setmask;
715 hss.hss_clearmask = clearmask;
716 /* Change archive_id if provided. We can only change
717 * to set something different than 0. */
718 if (archive_id > 0) {
719 hss.hss_valid |= HSS_ARCHIVE_ID;
720 hss.hss_archive_id = archive_id;
722 rc = ioctl(fd, LL_IOC_HSM_STATE_SET, &hss);
723 /* If error, save errno value */
724 rc = rc ? -errno : 0;
730 * Set HSM states of file pointed by \a path.
732 * see llapi_hsm_state_set_fd() for args use and return
734 int llapi_hsm_state_set(const char *path, __u64 setmask, __u64 clearmask,
740 fd = open(path, O_WRONLY | O_LOV_DELAY_CREATE | O_NONBLOCK);
744 rc = llapi_hsm_state_set_fd(fd, setmask, clearmask, archive_id);
751 * Return the current HSM request related to file pointed by \a path.
753 * \param hca Should be allocated by caller. Will be filled with current file
756 * \retval 0 on success.
757 * \retval -errno on error.
759 int llapi_hsm_current_action(const char *path, struct hsm_current_action *hca)
764 fd = open(path, O_RDONLY | O_NONBLOCK);
768 rc = ioctl(fd, LL_IOC_HSM_ACTION, hca);
769 /* If error, save errno value */
770 rc = rc ? -errno : 0;
777 * Allocate a hsm_user_request with the specified carateristics.
778 * This structure should be freed with free().
780 * \return an allocated structure on success, NULL otherwise.
782 struct hsm_user_request *llapi_hsm_user_request_alloc(int itemcount,
787 len += sizeof(struct hsm_user_request);
788 len += sizeof(struct hsm_user_item) * itemcount;
791 return (struct hsm_user_request *)malloc(len);
795 * Send a HSM request to Lustre, described in \param request.
797 * \param path Fullpath to the file to operate on.
798 * \param request The request, allocated with llapi_hsm_user_request_alloc().
800 * \return 0 on success, an error code otherwise.
802 int llapi_hsm_request(const char *path, const struct hsm_user_request *request)
807 rc = get_root_path(WANT_FD, NULL, &fd, (char *)path, -1);
811 rc = ioctl(fd, LL_IOC_HSM_REQUEST, request);
812 /* If error, save errno value */
813 rc = rc ? -errno : 0;