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>
36 #include <sys/ioctl.h>
43 #include <sys/types.h>
45 #include <sys/syscall.h>
48 #ifdef HAVE_LINUX_UNISTD_H
49 #include <linux/unistd.h>
54 #include <liblustre.h>
55 #include <lnet/lnetctl.h>
58 #include <lustre/lustreapi.h>
59 #include "lustreapi_internal.h"
61 /****** HSM Copytool API ********/
62 #define CT_PRIV_MAGIC 0xC0BE2001
63 struct hsm_copytool_private {
66 lustre_kernelcomm kuc;
70 #include <libcfs/libcfs.h>
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
79 int llapi_hsm_copytool_start(struct hsm_copytool_private **priv, char *fsname,
80 int flags, int archive_count, int *archives)
82 struct hsm_copytool_private *ct;
85 if (archive_count > 0 && archives == NULL) {
86 llapi_err_noerrno(LLAPI_MSG_ERROR,
87 "NULL archive numbers");
91 ct = calloc(1, sizeof(*ct));
95 ct->fsname = malloc(strlen(fsname) + 1);
96 if (ct->fsname == NULL) {
100 strcpy(ct->fsname, fsname);
101 ct->magic = CT_PRIV_MAGIC;
103 /* no archives specified means "match all". */
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));
112 /* in the list we have a all archive wildcard
113 * so move to all archives mode
115 if (archives[rc] == 0) {
120 ct->archives |= (1 << (archives[rc] - 1));
123 rc = libcfs_ukuc_start(&ct->kuc, KUC_GRP_HSM);
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,
131 /* Only the kernel reference keeps the write side open */
132 close(ct->kuc.lk_wfd);
141 /* cleanup the kuc channel */
142 libcfs_ukuc_stop(&ct->kuc);
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.
155 int llapi_hsm_copytool_fini(struct hsm_copytool_private **priv)
157 struct hsm_copytool_private *ct;
160 if (!ct || (ct->magic != CT_PRIV_MAGIC))
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);
167 /* Shut down the kernelcomms */
168 libcfs_ukuc_stop(&ct->kuc);
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
183 int llapi_hsm_copytool_recv(struct hsm_copytool_private *ct,
184 struct hsm_action_list **halh, int *msgsize)
186 struct kuc_hdr *kuch;
187 struct hsm_action_list *hal;
190 if (!ct || (ct->magic != CT_PRIV_MAGIC))
192 if (halh == NULL || msgsize == NULL)
195 kuch = malloc(HAL_MAXSIZE + sizeof(*kuch));
199 rc = libcfs_ukuc_msg_get(&ct->kuc, (char *)kuch,
200 HAL_MAXSIZE + sizeof(*kuch),
205 /* Handle generic messages */
206 if (kuch->kuc_transport == KUC_TRANSPORT_GENERIC &&
207 kuch->kuc_msgtype == KUC_MSG_SHUTDOWN) {
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);
221 if (kuch->kuc_msglen < sizeof(*kuch) + sizeof(*hal)) {
222 llapi_err_noerrno(LLAPI_MSG_ERROR, "Short HSM message %d",
228 /* Our message is a hsm_action_list. Use pointer math to skip
229 * kuch_hdr and point directly to the message payload.
231 hal = (struct hsm_action_list *)(kuch + 1);
233 /* Check that we have registered for this archive #
234 * if 0 registered, we serve any archive */
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);
248 *msgsize = kuch->kuc_msglen - sizeof(*kuch);
258 /** Release the action list when done with it. */
259 int llapi_hsm_copytool_free(struct hsm_action_list **hal)
261 /* Reuse the llapi_changelog_free function */
262 return llapi_changelog_free((struct changelog_ext_rec **)hal);
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().
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()
276 * \return 0 on success.
278 int llapi_hsm_copy_start(char *mnt, struct hsm_copy *copy,
279 const struct hsm_action_item *hai)
284 if (memcpy(©->hc_hai, hai, sizeof(*hai)) == NULL)
287 rc = get_root_path(WANT_FD, NULL, &fd, mnt, -1);
291 rc = ioctl(fd, LL_IOC_HSM_COPY_START, copy);
298 * Should be called by copytools just having finished handling the request.
300 * \param mnt Mount point of the corresponding Lustre filesystem.
301 * \param copy The element used when calling llapi_hsm_copy_start()
302 * \param hp A hsm_progress structure describing the final state of the
305 * There is a special case which can be used only when the copytool cannot
306 * start the copy at all and want to directly return an error. In this case,
307 * simply fill \a hp structure and set \a copy to NULL. It is useless to call
308 * llapi_hsm_copy_start() in this case.
310 * \return 0 on success.
312 int llapi_hsm_copy_end(char *mnt, struct hsm_copy *copy,
313 const struct hsm_progress *hp)
319 /* llapi_hsm_copy_start() was skipped, so alloc copy. It will
320 * only be used to give the needed progress information. */
322 /* This is only ok if there is an error. */
323 if (hp->hp_errval == 0)
326 copy = (struct hsm_copy *)malloc(sizeof(*copy));
330 copy->hc_hai.hai_cookie = hp->hp_cookie;
331 copy->hc_hai.hai_fid = hp->hp_fid;
332 copy->hc_hai.hai_action = HSMA_NONE;
335 /* Fill the last missing data that will be needed by kernel
336 * to send a hsm_progress. */
337 copy->hc_flags = hp->hp_flags;
338 copy->hc_errval = hp->hp_errval;
339 /* Update hai if it has changed since start */
340 copy->hc_hai.hai_extent = hp->hp_extent;
342 rc = get_root_path(WANT_FD, NULL, &fd, mnt, -1);
346 rc = ioctl(fd, LL_IOC_HSM_COPY_END, copy);
357 * Copytool progress reporting.
359 * \a hp->hp_errval should be EAGAIN until action is completely finished.
361 * \return 0 on success, an error code otherwise.
363 int llapi_hsm_progress(char *mnt, struct hsm_progress *hp)
368 rc = get_root_path(WANT_FD, NULL, &fd, mnt, -1);
372 rc = ioctl(fd, LL_IOC_HSM_PROGRESS, hp);
373 /* If error, save errno value */
374 rc = rc ? -errno : 0;
381 * Import an existing hsm-archived file into Lustre.
383 * Caller must access file by (returned) newfid value from now on.
385 * \param dst path to Lustre destination (e.g. /mnt/lustre/my/file).
386 * \param archive archive number.
387 * \param st struct stat buffer containing file ownership, perm, etc.
388 * \param stripe_* Striping options. Currently ignored, since the restore
389 * operation will set the striping. In V2, this striping might
391 * \param newfid[out] Filled with new Lustre fid.
393 int llapi_hsm_import(const char *dst, int archive, struct stat *st,
394 unsigned long long stripe_size, int stripe_offset,
395 int stripe_count, int stripe_pattern, char *pool_name,
402 /* Create a non-striped file */
403 fd = open(dst, O_CREAT | O_EXCL | O_LOV_DELAY_CREATE | O_NONBLOCK,
410 /* set size on MDT */
411 if (truncate(dst, st->st_size) != 0) {
416 rc = llapi_hsm_state_set(dst, HS_EXISTS | HS_RELEASED | HS_ARCHIVED, 0,
421 /* Get the new fid in the archive. Caller needs to use this fid
423 rc = llapi_path2fid(dst, newfid);
427 /* Copy the file attributes */
428 time.actime = st->st_atime;
429 time.modtime = st->st_mtime;
430 if (utime(dst, &time) == -1 ||
431 chmod(dst, st->st_mode) == -1 ||
432 chown(dst, st->st_uid, st->st_gid) == -1) {
433 /* we might fail here because we change perms/owner */
445 * Return the current HSM states and HSM requests related to file pointed by \a
448 * \param hus Should be allocated by caller. Will be filled with current file
451 * \retval 0 on success.
452 * \retval -errno on error.
454 int llapi_hsm_state_get(const char *path, struct hsm_user_state *hus)
459 fd = open(path, O_RDONLY | O_NONBLOCK);
463 rc = ioctl(fd, LL_IOC_HSM_STATE_GET, hus);
464 /* If error, save errno value */
465 rc = rc ? -errno : 0;
472 * Set HSM states of file pointed by \a path.
474 * Using the provided bitmasks, the current HSM states for this file will be
475 * changed. \a archive_id could be used to change the archive number also. Set
476 * it to 0 if you do not want to change it.
478 * \param setmask Bitmask for flag to be set.
479 * \param clearmask Bitmask for flag to be cleared.
480 * \param archive_id Archive number identifier to use. 0 means no change.
482 * \retval 0 on success.
483 * \retval -errno on error.
485 int llapi_hsm_state_set(const char *path, __u64 setmask, __u64 clearmask,
488 struct hsm_state_set hss;
492 fd = open(path, O_WRONLY | O_LOV_DELAY_CREATE | O_NONBLOCK);
496 hss.hss_valid = HSS_SETMASK|HSS_CLEARMASK;
497 hss.hss_setmask = setmask;
498 hss.hss_clearmask = clearmask;
499 /* Change archive_id if provided. We can only change
500 * to set something different than 0. */
501 if (archive_id > 0) {
502 hss.hss_valid |= HSS_ARCHIVE_ID;
503 hss.hss_archive_id = archive_id;
505 rc = ioctl(fd, LL_IOC_HSM_STATE_SET, &hss);
506 /* If error, save errno value */
507 rc = rc ? -errno : 0;
515 * Return the current HSM request related to file pointed by \a path.
517 * \param hca Should be allocated by caller. Will be filled with current file
520 * \retval 0 on success.
521 * \retval -errno on error.
523 int llapi_hsm_current_action(const char *path, struct hsm_current_action *hca)
528 fd = open(path, O_RDONLY | O_NONBLOCK);
532 rc = ioctl(fd, LL_IOC_HSM_ACTION, hca);
533 /* If error, save errno value */
534 rc = rc ? -errno : 0;
541 * Allocate a hsm_user_request with the specified carateristics.
542 * This structure should be freed with free().
544 * \return an allocated structure on success, NULL otherwise.
546 struct hsm_user_request *llapi_hsm_user_request_alloc(int itemcount,
551 len += sizeof(struct hsm_user_request);
552 len += sizeof(struct hsm_user_item) * itemcount;
555 return (struct hsm_user_request *)malloc(len);
559 * Send a HSM request to Lustre, described in \param request.
561 * This request should be allocated with llapi_hsm_user_request_alloc().
563 * \param mnt Should be the Lustre moint point.
564 * \return 0 on success, an error code otherwise.
566 int llapi_hsm_request(char *mnt, struct hsm_user_request *request)
571 rc = get_root_path(WANT_FD, NULL, &fd, mnt, -1);
575 rc = ioctl(fd, LL_IOC_HSM_REQUEST, request);
576 /* If error, save errno value */
577 rc = rc ? -errno : 0;