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"
62 * fake functions, real one will come with HSM flags patch
64 static int llapi_hsm_state_set(const char *path, __u64 setmask, __u64 clearmask,
70 /****** HSM Copytool API ********/
71 #define CT_PRIV_MAGIC 0xC0BE2001
72 struct hsm_copytool_private {
75 lustre_kernelcomm kuc;
79 #include <libcfs/libcfs.h>
81 /** Register a copytool
82 * \param[out] priv Opaque private control structure
83 * \param fsname Lustre filesystem
84 * \param flags Open flags, currently unused (e.g. O_NONBLOCK)
85 * \param archive_count
86 * \param archives Which archive numbers this copytool is responsible for
88 int llapi_hsm_copytool_start(void **priv, char *fsname, int flags,
89 int archive_count, int *archives)
91 struct hsm_copytool_private *ct;
94 if (archive_count > 0 && archives == NULL) {
95 llapi_err_noerrno(LLAPI_MSG_ERROR,
96 "NULL archive numbers");
100 ct = calloc(1, sizeof(*ct));
104 ct->fsname = malloc(strlen(fsname) + 1);
105 if (ct->fsname == NULL) {
109 strcpy(ct->fsname, fsname);
110 ct->magic = CT_PRIV_MAGIC;
112 /* no archives specified means "match all". */
114 for (rc = 0; rc < archive_count; rc++) {
115 if (archives[rc] > 8 * sizeof(ct->archives)) {
116 llapi_err_noerrno(LLAPI_MSG_ERROR,
117 "Maximum of %d archives supported",
118 8 * sizeof(ct->archives));
121 /* in the list we have a all archive wildcard
122 * so move to all archives mode
124 if (archives[rc] == 0) {
129 ct->archives |= (1 << (archives[rc] - 1));
132 rc = libcfs_ukuc_start(&ct->kuc, KUC_GRP_HSM);
136 /* Storing archive(s) in lk_data; see mdc_ioc_hsm_ct_start */
137 ct->kuc.lk_data = ct->archives;
138 rc = root_ioctl(ct->fsname, LL_IOC_HSM_CT_START, &(ct->kuc), NULL,
140 /* ignore if it was already registered on coordinator */
143 /* Only the kernel reference keeps the write side open */
144 close(ct->kuc.lk_wfd);
159 /** Deregister a copytool
160 * Note: under Linux, until llapi_hsm_copytool_fini is called (or the program is
161 * killed), the libcfs module will be referenced and unremovable,
162 * even after Lustre services stop.
164 int llapi_hsm_copytool_fini(void **priv)
166 struct hsm_copytool_private *ct;
168 ct = (struct hsm_copytool_private *)priv;
169 if (!ct || (ct->magic != CT_PRIV_MAGIC))
172 /* Tell the kernel to stop sending us messages */
173 ct->kuc.lk_flags = LK_FLG_STOP;
174 root_ioctl(ct->fsname, LL_IOC_HSM_CT_START, &(ct->kuc), NULL, 0);
176 /* Shut down the kernelcomms */
177 libcfs_ukuc_stop(&ct->kuc);
185 /** Wait for the next hsm_action_list
186 * \param priv Opaque private control structure
187 * \param halh Action list handle, will be allocated here
188 * \param msgsize Number of bytes in the message, will be set here
189 * \return 0 valid message received; halh and msgsize are set
192 int llapi_hsm_copytool_recv(void *priv, struct hsm_action_list **halh,
195 struct hsm_copytool_private *ct;
196 struct kuc_hdr *kuch;
197 struct hsm_action_list *hal;
200 ct = (struct hsm_copytool_private *)priv;
201 if (!ct || (ct->magic != CT_PRIV_MAGIC))
203 if (halh == NULL || msgsize == NULL)
206 kuch = malloc(HAL_MAXSIZE + sizeof(*kuch));
210 rc = libcfs_ukuc_msg_get(&ct->kuc, (char *)kuch,
211 HAL_MAXSIZE + sizeof(*kuch),
216 /* Handle generic messages */
217 if (kuch->kuc_transport == KUC_TRANSPORT_GENERIC &&
218 kuch->kuc_msgtype == KUC_MSG_SHUTDOWN) {
223 if (kuch->kuc_transport != KUC_TRANSPORT_HSM ||
224 kuch->kuc_msgtype != HMT_ACTION_LIST) {
225 llapi_err_noerrno(LLAPI_MSG_ERROR,
226 "Unknown HSM message type %d:%d\n",
227 kuch->kuc_transport, kuch->kuc_msgtype);
232 if (kuch->kuc_msglen < sizeof(*kuch) + sizeof(*hal)) {
233 llapi_err_noerrno(LLAPI_MSG_ERROR, "Short HSM message %d",
239 /* Our message is a hsm_action_list. Use pointer math to skip
240 * kuch_hdr and point directly to the message payload.
242 hal = (struct hsm_action_list *)(kuch + 1);
244 /* Check that we have registered for this archive #
245 * if 0 registered, we serve any archive */
247 ((1 << (hal->hal_archive_num - 1)) & ct->archives) == 0) {
248 llapi_err_noerrno(LLAPI_MSG_INFO,
249 "This copytool does not service archive #%d,"
250 " ignoring this request."
251 " Mask of served archive is 0x%.8X",
252 hal->hal_archive_num, ct->archives);
259 *msgsize = kuch->kuc_msglen - sizeof(*kuch);
269 /** Release the action list when done with it. */
270 int llapi_hsm_copytool_free(struct hsm_action_list **hal)
272 /* Reuse the llapi_changelog_free function */
273 return llapi_changelog_free((struct changelog_ext_rec **)hal);
278 * Should be called by copytools just before starting handling a request.
279 * It could be skipped if copytool only want to directly report an error,
280 * \see llapi_hsm_copy_end().
282 * \param mnt Mount point of the corresponding Lustre filesystem.
283 * \param hai The hsm_action_item describing the request they will handle.
284 * \param copy Updated by this call. Caller will passed it to
285 * llapi_hsm_copy_end()
287 * \return 0 on success.
289 int llapi_hsm_copy_start(char *mnt, struct hsm_copy *copy,
290 const struct hsm_action_item *hai)
295 if (memcpy(©->hc_hai, hai, sizeof(*hai)) == NULL)
298 rc = get_root_path(WANT_FD, NULL, &fd, mnt, -1);
302 rc = ioctl(fd, LL_IOC_HSM_COPY_START, copy);
309 * Should be called by copytools just having finished handling the request.
311 * \param mnt Mount point of the corresponding Lustre filesystem.
312 * \param copy The element used when calling llapi_hsm_copy_start()
313 * \param hp A hsm_progress structure describing the final state of the
316 * There is a special case which can be used only when the copytool cannot
317 * start the copy at all and want to directly return an error. In this case,
318 * simply fill \a hp structure and set \a copy to NULL. It is useless to call
319 * llapi_hsm_copy_start() in this case.
321 * \return 0 on success.
323 int llapi_hsm_copy_end(char *mnt, struct hsm_copy *copy,
324 const struct hsm_progress *hp)
330 /* llapi_hsm_copy_start() was skipped, so alloc copy. It will
331 * only be used to give the needed progress information. */
333 /* This is only ok if there is an error. */
334 if (hp->hp_errval == 0)
337 copy = (struct hsm_copy *)malloc(sizeof(*copy));
341 copy->hc_hai.hai_cookie = hp->hp_cookie;
342 copy->hc_hai.hai_fid = hp->hp_fid;
343 copy->hc_hai.hai_action = HSMA_NONE;
346 /* Fill the last missing data that will be needed by kernel
347 * to send a hsm_progress. */
348 copy->hc_flags = hp->hp_flags;
349 copy->hc_errval = hp->hp_errval;
350 /* Update hai if it has changed since start */
351 copy->hc_hai.hai_extent = hp->hp_extent;
353 rc = get_root_path(WANT_FD, NULL, &fd, mnt, -1);
357 rc = ioctl(fd, LL_IOC_HSM_COPY_END, copy);
368 * Copytool progress reporting.
370 * \a hp->hp_errval should be EAGAIN until action is completely finished.
372 * \return 0 on success, an error code otherwise.
374 int llapi_hsm_progress(char *mnt, struct hsm_progress *hp)
379 rc = get_root_path(WANT_FD, NULL, &fd, mnt, -1);
383 rc = ioctl(fd, LL_IOC_HSM_PROGRESS, hp);
384 /* If error, save errno value */
385 rc = rc ? -errno : 0;
392 * Import an existing hsm-archived file into Lustre.
394 * Caller must access file by (returned) newfid value from now on.
396 * \param dst path to Lustre destination (e.g. /mnt/lustre/my/file).
397 * \param archive archive number.
398 * \param st struct stat buffer containing file ownership, perm, etc.
399 * \param stripe_* Striping options. Currently ignored, since the restore
400 * operation will set the striping. In V2, this striping might
402 * \param newfid[out] Filled with new Lustre fid.
404 int llapi_hsm_import(const char *dst, int archive, struct stat *st,
405 unsigned long long stripe_size, int stripe_offset,
406 int stripe_count, int stripe_pattern, char *pool_name,
413 /* Create a non-striped file */
414 fd = open(dst, O_CREAT | O_EXCL | O_LOV_DELAY_CREATE | O_NONBLOCK,
421 /* set size on MDT */
422 if (truncate(dst, st->st_size) != 0) {
427 rc = llapi_hsm_state_set(dst, HS_EXISTS | HS_RELEASED | HS_ARCHIVED, 0,
432 /* Get the new fid in the archive. Caller needs to use this fid
434 rc = llapi_path2fid(dst, newfid);
438 /* Copy the file attributes */
439 time.actime = st->st_atime;
440 time.modtime = st->st_mtime;
441 if (utime(dst, &time) == -1 ||
442 chmod(dst, st->st_mode) == -1 ||
443 chown(dst, st->st_uid, st->st_gid) == -1) {
444 /* we might fail here because we change perms/owner */