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);
292 /* If error, return errno value */
293 rc = rc ? -errno : 0;
300 * Should be called by copytools just having finished handling the request.
302 * \param mnt Mount point of the corresponding Lustre filesystem.
303 * \param copy The element used when calling llapi_hsm_copy_start()
304 * \param hp A hsm_progress structure describing the final state of the
307 * There is a special case which can be used only when the copytool cannot
308 * start the copy at all and want to directly return an error. In this case,
309 * simply fill \a hp structure and set \a copy to NULL. It is useless to call
310 * llapi_hsm_copy_start() in this case.
312 * \return 0 on success.
314 int llapi_hsm_copy_end(char *mnt, struct hsm_copy *copy,
315 const struct hsm_progress *hp)
321 /* llapi_hsm_copy_start() was skipped, so alloc copy. It will
322 * only be used to give the needed progress information. */
324 /* This is only ok if there is an error. */
325 if (hp->hp_errval == 0)
328 copy = (struct hsm_copy *)malloc(sizeof(*copy));
332 copy->hc_hai.hai_cookie = hp->hp_cookie;
333 copy->hc_hai.hai_fid = hp->hp_fid;
334 copy->hc_hai.hai_action = HSMA_NONE;
337 /* Fill the last missing data that will be needed by kernel
338 * to send a hsm_progress. */
339 copy->hc_flags = hp->hp_flags;
340 copy->hc_errval = hp->hp_errval;
341 /* Update hai if it has changed since start */
342 copy->hc_hai.hai_extent = hp->hp_extent;
343 /* In some cases, like restore, 2 FIDs are used. hp knows the right FID
345 copy->hc_hai.hai_fid = hp->hp_fid;
347 rc = get_root_path(WANT_FD, NULL, &fd, mnt, -1);
351 rc = ioctl(fd, LL_IOC_HSM_COPY_END, copy);
352 /* If error, return errno value */
353 rc = rc ? -errno : 0;
364 * Copytool progress reporting.
366 * \a hp->hp_errval should be EAGAIN until action is completely finished.
368 * \return 0 on success, an error code otherwise.
370 int llapi_hsm_progress(char *mnt, struct hsm_progress *hp)
375 rc = get_root_path(WANT_FD, NULL, &fd, mnt, -1);
379 rc = ioctl(fd, LL_IOC_HSM_PROGRESS, hp);
380 /* If error, save errno value */
381 rc = rc ? -errno : 0;
388 * Import an existing hsm-archived file into Lustre.
390 * Caller must access file by (returned) newfid value from now on.
392 * \param dst path to Lustre destination (e.g. /mnt/lustre/my/file).
393 * \param archive archive number.
394 * \param st struct stat buffer containing file ownership, perm, etc.
395 * \param stripe_* Striping options. Currently ignored, since the restore
396 * operation will set the striping. In V2, this striping might
398 * \param newfid[out] Filled with new Lustre fid.
400 int llapi_hsm_import(const char *dst, int archive, struct stat *st,
401 unsigned long long stripe_size, int stripe_offset,
402 int stripe_count, int stripe_pattern, char *pool_name,
409 /* Create a non-striped file */
410 fd = open(dst, O_CREAT | O_EXCL | O_LOV_DELAY_CREATE | O_NONBLOCK,
417 /* set size on MDT */
418 if (truncate(dst, st->st_size) != 0) {
423 rc = llapi_hsm_state_set(dst, HS_EXISTS | HS_RELEASED | HS_ARCHIVED, 0,
428 /* Get the new fid in the archive. Caller needs to use this fid
430 rc = llapi_path2fid(dst, newfid);
434 /* Copy the file attributes */
435 time.actime = st->st_atime;
436 time.modtime = st->st_mtime;
437 if (utime(dst, &time) == -1 ||
438 chmod(dst, st->st_mode) == -1 ||
439 chown(dst, st->st_uid, st->st_gid) == -1) {
440 /* we might fail here because we change perms/owner */
452 * Return the current HSM states and HSM requests related to file pointed by \a
455 * \param hus Should be allocated by caller. Will be filled with current file
458 * \retval 0 on success.
459 * \retval -errno on error.
461 int llapi_hsm_state_get(const char *path, struct hsm_user_state *hus)
466 fd = open(path, O_RDONLY | O_NONBLOCK);
470 rc = ioctl(fd, LL_IOC_HSM_STATE_GET, hus);
471 /* If error, save errno value */
472 rc = rc ? -errno : 0;
479 * Set HSM states of file pointed by \a path.
481 * Using the provided bitmasks, the current HSM states for this file will be
482 * changed. \a archive_id could be used to change the archive number also. Set
483 * it to 0 if you do not want to change it.
485 * \param setmask Bitmask for flag to be set.
486 * \param clearmask Bitmask for flag to be cleared.
487 * \param archive_id Archive number identifier to use. 0 means no change.
489 * \retval 0 on success.
490 * \retval -errno on error.
492 int llapi_hsm_state_set(const char *path, __u64 setmask, __u64 clearmask,
495 struct hsm_state_set hss;
499 fd = open(path, O_WRONLY | O_LOV_DELAY_CREATE | O_NONBLOCK);
503 hss.hss_valid = HSS_SETMASK|HSS_CLEARMASK;
504 hss.hss_setmask = setmask;
505 hss.hss_clearmask = clearmask;
506 /* Change archive_id if provided. We can only change
507 * to set something different than 0. */
508 if (archive_id > 0) {
509 hss.hss_valid |= HSS_ARCHIVE_ID;
510 hss.hss_archive_id = archive_id;
512 rc = ioctl(fd, LL_IOC_HSM_STATE_SET, &hss);
513 /* If error, save errno value */
514 rc = rc ? -errno : 0;
522 * Return the current HSM request related to file pointed by \a path.
524 * \param hca Should be allocated by caller. Will be filled with current file
527 * \retval 0 on success.
528 * \retval -errno on error.
530 int llapi_hsm_current_action(const char *path, struct hsm_current_action *hca)
535 fd = open(path, O_RDONLY | O_NONBLOCK);
539 rc = ioctl(fd, LL_IOC_HSM_ACTION, hca);
540 /* If error, save errno value */
541 rc = rc ? -errno : 0;
548 * Allocate a hsm_user_request with the specified carateristics.
549 * This structure should be freed with free().
551 * \return an allocated structure on success, NULL otherwise.
553 struct hsm_user_request *llapi_hsm_user_request_alloc(int itemcount,
558 len += sizeof(struct hsm_user_request);
559 len += sizeof(struct hsm_user_item) * itemcount;
562 return (struct hsm_user_request *)malloc(len);
566 * Send a HSM request to Lustre, described in \param request.
568 * This request should be allocated with llapi_hsm_user_request_alloc().
570 * \param mnt Should be the Lustre moint point.
571 * \return 0 on success, an error code otherwise.
573 int llapi_hsm_request(char *mnt, struct hsm_user_request *request)
578 rc = get_root_path(WANT_FD, NULL, &fd, mnt, -1);
582 rc = ioctl(fd, LL_IOC_HSM_REQUEST, request);
583 /* If error, save errno value */
584 rc = rc ? -errno : 0;