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(void **priv, char *fsname, int flags,
80 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 /* ignore if it was already registered on coordinator */
134 /* Only the kernel reference keeps the write side open */
135 close(ct->kuc.lk_wfd);
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(void **priv)
157 struct hsm_copytool_private *ct;
159 ct = (struct hsm_copytool_private *)priv;
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 priv 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(void *priv, struct hsm_action_list **halh,
186 struct hsm_copytool_private *ct;
187 struct kuc_hdr *kuch;
188 struct hsm_action_list *hal;
191 ct = (struct hsm_copytool_private *)priv;
192 if (!ct || (ct->magic != CT_PRIV_MAGIC))
194 if (halh == NULL || msgsize == NULL)
197 kuch = malloc(HAL_MAXSIZE + sizeof(*kuch));
201 rc = libcfs_ukuc_msg_get(&ct->kuc, (char *)kuch,
202 HAL_MAXSIZE + sizeof(*kuch),
207 /* Handle generic messages */
208 if (kuch->kuc_transport == KUC_TRANSPORT_GENERIC &&
209 kuch->kuc_msgtype == KUC_MSG_SHUTDOWN) {
214 if (kuch->kuc_transport != KUC_TRANSPORT_HSM ||
215 kuch->kuc_msgtype != HMT_ACTION_LIST) {
216 llapi_err_noerrno(LLAPI_MSG_ERROR,
217 "Unknown HSM message type %d:%d\n",
218 kuch->kuc_transport, kuch->kuc_msgtype);
223 if (kuch->kuc_msglen < sizeof(*kuch) + sizeof(*hal)) {
224 llapi_err_noerrno(LLAPI_MSG_ERROR, "Short HSM message %d",
230 /* Our message is a hsm_action_list. Use pointer math to skip
231 * kuch_hdr and point directly to the message payload.
233 hal = (struct hsm_action_list *)(kuch + 1);
235 /* Check that we have registered for this archive #
236 * if 0 registered, we serve any archive */
238 ((1 << (hal->hal_archive_id - 1)) & ct->archives) == 0) {
239 llapi_err_noerrno(LLAPI_MSG_INFO,
240 "This copytool does not service archive #%d,"
241 " ignoring this request."
242 " Mask of served archive is 0x%.8X",
243 hal->hal_archive_id, ct->archives);
250 *msgsize = kuch->kuc_msglen - sizeof(*kuch);
260 /** Release the action list when done with it. */
261 int llapi_hsm_copytool_free(struct hsm_action_list **hal)
263 /* Reuse the llapi_changelog_free function */
264 return llapi_changelog_free((struct changelog_ext_rec **)hal);
269 * Should be called by copytools just before starting handling a request.
270 * It could be skipped if copytool only want to directly report an error,
271 * \see llapi_hsm_copy_end().
273 * \param mnt Mount point of the corresponding Lustre filesystem.
274 * \param hai The hsm_action_item describing the request they will handle.
275 * \param copy Updated by this call. Caller will passed it to
276 * llapi_hsm_copy_end()
278 * \return 0 on success.
280 int llapi_hsm_copy_start(char *mnt, struct hsm_copy *copy,
281 const struct hsm_action_item *hai)
286 if (memcpy(©->hc_hai, hai, sizeof(*hai)) == NULL)
289 rc = get_root_path(WANT_FD, NULL, &fd, mnt, -1);
293 rc = ioctl(fd, LL_IOC_HSM_COPY_START, copy);
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;
344 rc = get_root_path(WANT_FD, NULL, &fd, mnt, -1);
348 rc = ioctl(fd, LL_IOC_HSM_COPY_END, copy);
359 * Copytool progress reporting.
361 * \a hp->hp_errval should be EAGAIN until action is completely finished.
363 * \return 0 on success, an error code otherwise.
365 int llapi_hsm_progress(char *mnt, struct hsm_progress *hp)
370 rc = get_root_path(WANT_FD, NULL, &fd, mnt, -1);
374 rc = ioctl(fd, LL_IOC_HSM_PROGRESS, hp);
375 /* If error, save errno value */
376 rc = rc ? -errno : 0;
383 * Import an existing hsm-archived file into Lustre.
385 * Caller must access file by (returned) newfid value from now on.
387 * \param dst path to Lustre destination (e.g. /mnt/lustre/my/file).
388 * \param archive archive number.
389 * \param st struct stat buffer containing file ownership, perm, etc.
390 * \param stripe_* Striping options. Currently ignored, since the restore
391 * operation will set the striping. In V2, this striping might
393 * \param newfid[out] Filled with new Lustre fid.
395 int llapi_hsm_import(const char *dst, int archive, struct stat *st,
396 unsigned long long stripe_size, int stripe_offset,
397 int stripe_count, int stripe_pattern, char *pool_name,
404 /* Create a non-striped file */
405 fd = open(dst, O_CREAT | O_EXCL | O_LOV_DELAY_CREATE | O_NONBLOCK,
412 /* set size on MDT */
413 if (truncate(dst, st->st_size) != 0) {
418 rc = llapi_hsm_state_set(dst, HS_EXISTS | HS_RELEASED | HS_ARCHIVED, 0,
423 /* Get the new fid in the archive. Caller needs to use this fid
425 rc = llapi_path2fid(dst, newfid);
429 /* Copy the file attributes */
430 time.actime = st->st_atime;
431 time.modtime = st->st_mtime;
432 if (utime(dst, &time) == -1 ||
433 chmod(dst, st->st_mode) == -1 ||
434 chown(dst, st->st_uid, st->st_gid) == -1) {
435 /* we might fail here because we change perms/owner */
447 * Return the current HSM states and HSM requests related to file pointed by \a
450 * \param hus Should be allocated by caller. Will be filled with current file
453 * \retval 0 on success.
454 * \retval -errno on error.
456 int llapi_hsm_state_get(const char *path, struct hsm_user_state *hus)
461 fd = open(path, O_RDONLY | O_NONBLOCK);
465 rc = ioctl(fd, LL_IOC_HSM_STATE_GET, hus);
466 /* If error, save errno value */
467 rc = rc ? -errno : 0;
474 * Set HSM states of file pointed by \a path.
476 * Using the provided bitmasks, the current HSM states for this file will be
477 * changed. \a archive_id could be used to change the archive number also. Set
478 * it to 0 if you do not want to change it.
480 * \param setmask Bitmask for flag to be set.
481 * \param clearmask Bitmask for flag to be cleared.
482 * \param archive_id Archive number identifier to use. 0 means no change.
484 * \retval 0 on success.
485 * \retval -errno on error.
487 int llapi_hsm_state_set(const char *path, __u64 setmask, __u64 clearmask,
490 struct hsm_state_set hss;
494 fd = open(path, O_WRONLY | O_LOV_DELAY_CREATE | O_NONBLOCK);
498 hss.hss_valid = HSS_SETMASK|HSS_CLEARMASK;
499 hss.hss_setmask = setmask;
500 hss.hss_clearmask = clearmask;
501 /* Change archive_id if provided. We can only change
502 * to set something different than 0. */
503 if (archive_id > 0) {
504 hss.hss_valid |= HSS_ARCHIVE_ID;
505 hss.hss_archive_id = archive_id;
507 rc = ioctl(fd, LL_IOC_HSM_STATE_SET, &hss);
508 /* If error, save errno value */
509 rc = rc ? -errno : 0;
517 * Return the current HSM request related to file pointed by \a path.
519 * \param hca Should be allocated by caller. Will be filled with current file
522 * \retval 0 on success.
523 * \retval -errno on error.
525 int llapi_hsm_current_action(const char *path, struct hsm_current_action *hca)
530 fd = open(path, O_RDONLY | O_NONBLOCK);
534 rc = ioctl(fd, LL_IOC_HSM_ACTION, hca);
535 /* If error, save errno value */
536 rc = rc ? -errno : 0;
543 * Allocate a hsm_user_request with the specified carateristics.
544 * This structure should be freed with free().
546 * \return an allocated structure on success, NULL otherwise.
548 struct hsm_user_request *llapi_hsm_user_request_alloc(int itemcount,
553 len += sizeof(struct hsm_user_request);
554 len += sizeof(struct hsm_user_item) * itemcount;
557 return (struct hsm_user_request *)malloc(len);
561 * Send a HSM request to Lustre, described in \param request.
563 * This request should be allocated with llapi_hsm_user_request_alloc().
565 * \param mnt Should be the Lustre moint point.
566 * \return 0 on success, an error code otherwise.
568 int llapi_hsm_request(char *mnt, struct hsm_user_request *request)
573 rc = get_root_path(WANT_FD, NULL, &fd, mnt, -1);
577 rc = ioctl(fd, LL_IOC_HSM_REQUEST, request);
578 /* If error, save errno value */
579 rc = rc ? -errno : 0;