Whamcloud - gitweb
3f1b8b9fe2282b39dce381a652050a327c4bfb17
[fs/lustre-release.git] / lustre / utils / liblustreapi_hsm.c
1 /*
2  * LGPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * (C) Copyright 2012 Commissariat a l'energie atomique et aux energies
7  *     alternatives
8  *
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
14  *
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.
19  *
20  * LGPL HEADER END
21  */
22 /*
23  * lustre/utils/liblustreapi_hsm.c
24  *
25  * lustreapi library for hsm calls
26  *
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>
31  */
32
33 #include <stdlib.h>
34 #include <stdio.h>
35 #include <string.h>
36 #include <stddef.h>
37 #include <sys/ioctl.h>
38 #include <unistd.h>
39 #include <malloc.h>
40 #include <errno.h>
41 #include <dirent.h>
42 #include <stdarg.h>
43 #include <sys/stat.h>
44 #include <sys/types.h>
45 #include <utime.h>
46 #include <sys/syscall.h>
47 #include <fnmatch.h>
48 #include <glob.h>
49 #include <signal.h>
50 #ifdef HAVE_LINUX_UNISTD_H
51 #include <linux/unistd.h>
52 #else
53 #include <unistd.h>
54 #endif
55
56 #include <liblustre.h>
57 #include <lnet/lnetctl.h>
58 #include <obd.h>
59 #include <lustre/lustreapi.h>
60 #include "lustreapi_internal.h"
61
62 #define OPEN_BY_FID_PATH dot_lustre_name"/fid"
63
64 /****** HSM Copytool API ********/
65 #define CT_PRIV_MAGIC 0xC0BE2001
66 struct hsm_copytool_private {
67         int                      magic;
68         char                    *mnt;
69         int                      mnt_fd;
70         int                      open_by_fid_fd;
71         lustre_kernelcomm        kuc;
72         __u32                    archives;
73 };
74
75 #define CP_PRIV_MAGIC 0x19880429
76 struct hsm_copyaction_private {
77         __u32                                    magic;
78         __s32                                    data_fd;
79         const struct hsm_copytool_private       *ct_priv;
80         struct hsm_copy                          copy;
81         struct stat                              stat;
82 };
83
84 #include <libcfs/libcfs.h>
85
86 enum ct_progress_type {
87         CT_START        = 0,
88         CT_RUNNING      = 50,
89         CT_FINISH       = 100,
90         CT_CANCEL       = 150,
91         CT_ERROR        = 175
92 };
93
94 enum ct_event {
95         CT_REGISTER             = 1,
96         CT_UNREGISTER           = 2,
97         CT_ARCHIVE_START        = HSMA_ARCHIVE,
98         CT_ARCHIVE_RUNNING      = HSMA_ARCHIVE + CT_RUNNING,
99         CT_ARCHIVE_FINISH       = HSMA_ARCHIVE + CT_FINISH,
100         CT_ARCHIVE_CANCEL       = HSMA_ARCHIVE + CT_CANCEL,
101         CT_ARCHIVE_ERROR        = HSMA_ARCHIVE + CT_ERROR,
102         CT_RESTORE_START        = HSMA_RESTORE,
103         CT_RESTORE_RUNNING      = HSMA_RESTORE + CT_RUNNING,
104         CT_RESTORE_FINISH       = HSMA_RESTORE + CT_FINISH,
105         CT_RESTORE_CANCEL       = HSMA_RESTORE + CT_CANCEL,
106         CT_RESTORE_ERROR        = HSMA_RESTORE + CT_ERROR,
107         CT_REMOVE_START         = HSMA_REMOVE,
108         CT_REMOVE_RUNNING       = HSMA_REMOVE + CT_RUNNING,
109         CT_REMOVE_FINISH        = HSMA_REMOVE + CT_FINISH,
110         CT_REMOVE_CANCEL        = HSMA_REMOVE + CT_CANCEL,
111         CT_REMOVE_ERROR         = HSMA_REMOVE + CT_ERROR,
112         CT_EVENT_MAX
113 };
114
115 /* initialized in llapi_hsm_register_event_fifo() */
116 FILE *llapi_hsm_event_fp;
117
118 static inline const char *llapi_hsm_ct_ev2str(int type)
119 {
120         switch (type) {
121         case CT_REGISTER:
122                 return "REGISTER";
123         case CT_UNREGISTER:
124                 return "UNREGISTER";
125         case CT_ARCHIVE_START:
126                 return "ARCHIVE_START";
127         case CT_ARCHIVE_RUNNING:
128                 return "ARCHIVE_RUNNING";
129         case CT_ARCHIVE_FINISH:
130                 return "ARCHIVE_FINISH";
131         case CT_ARCHIVE_CANCEL:
132                 return "ARCHIVE_CANCEL";
133         case CT_ARCHIVE_ERROR:
134                 return "ARCHIVE_ERROR";
135         case CT_RESTORE_START:
136                 return "RESTORE_START";
137         case CT_RESTORE_RUNNING:
138                 return "RESTORE_RUNNING";
139         case CT_RESTORE_FINISH:
140                 return "RESTORE_FINISH";
141         case CT_RESTORE_CANCEL:
142                 return "RESTORE_CANCEL";
143         case CT_RESTORE_ERROR:
144                 return "RESTORE_ERROR";
145         case CT_REMOVE_START:
146                 return "REMOVE_START";
147         case CT_REMOVE_RUNNING:
148                 return "REMOVE_RUNNING";
149         case CT_REMOVE_FINISH:
150                 return "REMOVE_FINISH";
151         case CT_REMOVE_CANCEL:
152                 return "REMOVE_CANCEL";
153         case CT_REMOVE_ERROR:
154                 return "REMOVE_ERROR";
155         default:
156                 llapi_err_noerrno(LLAPI_MSG_ERROR,
157                                   "Unknown event type: %d", type);
158                 return NULL;
159         }
160 }
161
162 /**
163  * Writes a JSON event to the monitor FIFO. Noop if no FIFO has been
164  * registered.
165  *
166  * \param event              A list of llapi_json_items comprising a
167  *                           single JSON-formatted event.
168  *
169  * \retval 0 on success.
170  * \retval -errno on error.
171  */
172 int llapi_hsm_write_json_event(struct llapi_json_item_list **event)
173 {
174         int                             rc;
175         char                            time_string[40];
176         time_t                          event_time = time(0);
177         struct tm                       time_components;
178         struct llapi_json_item_list     *json_items;
179
180         /* Noop unless the event fp was initialized */
181         if (llapi_hsm_event_fp == NULL)
182                 return 0;
183
184         if (event == NULL || *event == NULL)
185                 return -EINVAL;
186
187         json_items = *event;
188
189         localtime_r(&event_time, &time_components);
190
191         if (strftime(time_string, sizeof(time_string), "%Y-%m-%d %T %z",
192                      &time_components) == 0) {
193                 rc = -EINVAL;
194                 llapi_error(LLAPI_MSG_ERROR, rc, "strftime() failed");
195                 return rc;
196         }
197
198         rc = llapi_json_add_item(&json_items, "event_time", LLAPI_JSON_STRING,
199                                  time_string);
200         if (rc < 0) {
201                 llapi_error(LLAPI_MSG_ERROR, -rc, "error in "
202                             "llapi_json_add_item()");
203                 return rc;
204         }
205
206         rc = llapi_json_write_list(event, llapi_hsm_event_fp);
207         if (rc < 0) {
208                 /* Ignore write failures due to missing reader. */
209                 if (rc == -EPIPE)
210                         return 0;
211
212                 /* Skip llapi_error() here because there's no point
213                  * in creating a JSON-formatted error message about
214                  * failing to write a JSON-formatted message.
215                  */
216                 fprintf(stderr,
217                         "\nFATAL ERROR IN llapi_hsm_write_list(): rc %d", rc);
218                 return rc;
219         }
220
221         return 0;
222 }
223
224 /**
225  * Hook for llapi_hsm_copytool_register and llapi_hsm_copytool_unregister
226  * to generate JSON events suitable for consumption by a copytool
227  * monitoring process.
228  *
229  * \param priv               Opaque private control structure.
230  * \param event_type         The type of event (register or unregister).
231  *
232  * \retval 0 on success.
233  * \retval -errno on error.
234  */
235 int llapi_hsm_log_ct_registration(struct hsm_copytool_private **priv,
236                                   __u32 event_type)
237 {
238         int                             rc;
239         char                            agent_uuid[UUID_MAX];
240         struct hsm_copytool_private     *ct;
241         struct llapi_json_item_list     *json_items;
242
243         if (priv == NULL || *priv == NULL)
244                 return -EINVAL;
245
246         ct = *priv;
247         if (ct->magic != CT_PRIV_MAGIC)
248                 return -EINVAL;
249
250         if (event_type != CT_REGISTER && event_type != CT_UNREGISTER)
251                 return -EINVAL;
252
253         rc = llapi_json_init_list(&json_items);
254         if (rc < 0)
255                 goto err;
256
257         rc = llapi_get_agent_uuid(ct->mnt, agent_uuid, sizeof(agent_uuid));
258         if (rc < 0)
259                 goto err;
260         llapi_chomp_string(agent_uuid);
261
262         rc = llapi_json_add_item(&json_items, "uuid", LLAPI_JSON_STRING,
263                                  agent_uuid);
264         if (rc < 0)
265                 goto err;
266
267         rc = llapi_json_add_item(&json_items, "mount_point", LLAPI_JSON_STRING,
268                                  ct->mnt);
269         if (rc < 0)
270                 goto err;
271
272         rc = llapi_json_add_item(&json_items, "archive", LLAPI_JSON_INTEGER,
273                                  &ct->archives);
274         if (rc < 0)
275                 goto err;
276
277         rc = llapi_json_add_item(&json_items, "event_type", LLAPI_JSON_STRING,
278                                  (char *)llapi_hsm_ct_ev2str(event_type));
279         if (rc < 0)
280                 goto err;
281
282         rc = llapi_hsm_write_json_event(&json_items);
283         if (rc < 0)
284                 goto err;
285
286         goto out_free;
287
288 err:
289         llapi_error(LLAPI_MSG_ERROR, rc, "error in "
290                     "llapi_hsm_log_ct_registration()");
291
292 out_free:
293         if (json_items != NULL)
294                 llapi_json_destroy_list(&json_items);
295
296         return rc;
297 }
298
299 /**
300  * Given a copytool progress update, construct a JSON event suitable for
301  * consumption by a copytool monitoring process.
302  *
303  * Examples of various events generated here and written by
304  * llapi_hsm_write_json_event:
305  *
306  * Copytool registration and deregistration:
307  * {"event_time": "2014-02-26 14:58:01 -0500", "event_type": "REGISTER", "archive": 0, "mount_point": "/mnt/lustre", "uuid": "80379a60-1f8a-743f-daf2-307cde793ec2"}
308  * {"event_time": "2014-02-26 14:58:01 -0500", "event_type": "UNREGISTER", "archive": 0, "mount_point": "/mnt/lustre", "uuid": "80379a60-1f8a-743f-daf2-307cde793ec2"}
309  *
310  * An archive action, start to completion:
311  * {"event_time": "2014-02-26 14:50:13 -0500", "event_type": "ARCHIVE_START", "total_bytes": 0, "lustre_path": "d71.sanity-hsm/f71.sanity-hsm", "source_fid": "0x2000013a1:0x2:0x0", "data_fid": "0x2000013a1:0x2:0x0"}
312  * {"event_time": "2014-02-26 14:50:18 -0500", "event_type": "ARCHIVE_RUNNING", "current_bytes": 5242880, "total_bytes": 39000000, "lustre_path": "d71.sanity-hsm/f71.sanity-hsm", "source_fid": "0x2000013a1:0x2:0x0", "data_fid": "0x2000013a1:0x2:0x0"}
313  * {"event_time": "2014-02-26 14:50:50 -0500", "event_type": "ARCHIVE_FINISH", "source_fid": "0x2000013a1:0x2:0x0", "data_fid": "0x2000013a1:0x2:0x0"}
314  *
315  * A log message:
316  * {"event_time": "2014-02-26 14:50:13 -0500", "event_type": "LOGGED_MESSAGE", "level": "INFO", "message": "lhsmtool_posix[59401]: copytool fs=lustre archive#=2 item_count=1"}
317  *
318  * \param hcp                Opaque action handle returned by
319  *                           llapi_hsm_action_start.
320  * \param hai                The hsm_action_item describing the request.
321  * \param progress_type      The ct_progress_type describing the update.
322  * \param total              The total expected bytes for the request.
323  * \param current            The current copied byte count for the request.
324  *
325  * \retval 0 on success.
326  * \retval -errno on error.
327  */
328 int llapi_hsm_log_ct_progress(struct hsm_copyaction_private **phcp,
329                     const struct hsm_action_item *hai, __u32 progress_type,
330                     __u64 total, __u64 current)
331 {
332         int                             rc;
333         int                             linkno = 0;
334         long long                       recno = -1;
335         char                            lustre_path[PATH_MAX];
336         char                            strfid[FID_NOBRACE_LEN + 1];
337         struct hsm_copyaction_private   *hcp;
338         struct llapi_json_item_list     *json_items;
339
340         if (phcp == NULL || *phcp == NULL)
341                 return -EINVAL;
342
343         hcp = *phcp;
344
345         rc = llapi_json_init_list(&json_items);
346         if (rc < 0)
347                 goto err;
348
349         snprintf(strfid, sizeof(strfid), DFID_NOBRACE, PFID(&hai->hai_dfid));
350         rc = llapi_json_add_item(&json_items, "data_fid",
351                                  LLAPI_JSON_STRING, strfid);
352         if (rc < 0)
353                 goto err;
354
355         snprintf(strfid, sizeof(strfid), DFID_NOBRACE, PFID(&hai->hai_fid));
356         rc = llapi_json_add_item(&json_items, "source_fid",
357                                  LLAPI_JSON_STRING, strfid);
358         if (rc < 0)
359                 goto err;
360
361         if (hcp->copy.hc_errval == ECANCELED) {
362                 progress_type = CT_CANCEL;
363                 goto cancel;
364         }
365
366         if (hcp->copy.hc_errval != 0) {
367                 progress_type = CT_ERROR;
368
369                 rc = llapi_json_add_item(&json_items, "errno",
370                                          LLAPI_JSON_INTEGER,
371                                          &hcp->copy.hc_errval);
372                 if (rc < 0)
373                         goto err;
374
375                 rc = llapi_json_add_item(&json_items, "error",
376                                          LLAPI_JSON_STRING,
377                                          strerror(hcp->copy.hc_errval));
378                 if (rc < 0)
379                         goto err;
380
381                 goto cancel;
382         }
383
384         /* lustre_path isn't available after a restore completes */
385         /* total_bytes isn't available after a restore or archive completes */
386         if (progress_type != CT_FINISH) {
387                 rc = llapi_fid2path(hcp->ct_priv->mnt, strfid, lustre_path,
388                                     sizeof(lustre_path), &recno, &linkno);
389                 if (rc < 0)
390                         goto err;
391
392                 rc = llapi_json_add_item(&json_items, "lustre_path",
393                                          LLAPI_JSON_STRING, lustre_path);
394                 if (rc < 0)
395                         goto err;
396
397                 rc = llapi_json_add_item(&json_items, "total_bytes",
398                                          LLAPI_JSON_BIGNUM, &total);
399                 if (rc < 0)
400                         goto err;
401         }
402
403         if (progress_type == CT_RUNNING)
404                 rc = llapi_json_add_item(&json_items, "current_bytes",
405                                          LLAPI_JSON_BIGNUM, &current);
406                 if (rc < 0)
407                         goto err;
408
409 cancel:
410         rc = llapi_json_add_item(&json_items, "event_type", LLAPI_JSON_STRING,
411                                  (char *)llapi_hsm_ct_ev2str(hai->hai_action +
412                                                              progress_type));
413         if (rc < 0)
414                 goto err;
415
416         rc = llapi_hsm_write_json_event(&json_items);
417         if (rc < 0)
418                 goto err;
419
420         goto out_free;
421
422 err:
423         llapi_error(LLAPI_MSG_ERROR, rc, "error in "
424                     "llapi_hsm_log_ct_progress()");
425
426 out_free:
427         if (json_items != NULL)
428                 llapi_json_destroy_list(&json_items);
429
430         return rc;
431 }
432
433 /**
434  * Given a path to a FIFO, create a filehandle for nonblocking writes to it.
435  * Intended to be used for copytool monitoring processes that read an
436  * event stream from the FIFO. Events written in the absence of a reader
437  * are lost.
438  *
439  * \param path               Path to monitor FIFO.
440  *
441  * \retval 0 on success.
442  * \retval -errno on error.
443  */
444 int llapi_hsm_register_event_fifo(char *path)
445 {
446         int read_fd, write_fd;
447         struct stat statbuf;
448
449         /* Create the FIFO if necessary. */
450         if ((mkfifo(path, 0644) < 0) && (errno != EEXIST)) {
451                 llapi_error(LLAPI_MSG_ERROR, errno, "mkfifo(%s) failed", path);
452                 return -errno;
453         }
454         if (errno == EEXIST) {
455                 if (stat(path, &statbuf) < 0) {
456                         llapi_error(LLAPI_MSG_ERROR, errno, "mkfifo(%s) failed",
457                                     path);
458                         return -errno;
459                 }
460                 if (!S_ISFIFO(statbuf.st_mode) ||
461                     ((statbuf.st_mode & 0777) != 0644)) {
462                         llapi_error(LLAPI_MSG_ERROR, errno, "%s exists but is "
463                                     "not a pipe or has a wrong mode", path);
464                         return -errno;
465                 }
466         }
467
468         /* Open the FIFO for read so that the subsequent open for write
469          * doesn't immediately fail. */
470         read_fd = open(path, O_RDONLY | O_NONBLOCK);
471         if (read_fd < 0) {
472                 llapi_error(LLAPI_MSG_ERROR, errno,
473                             "cannot open(%s) for read", path);
474                 return -errno;
475         }
476
477         /* Open the FIFO for writes, but don't block on waiting
478          * for a reader. */
479         write_fd = open(path, O_WRONLY | O_NONBLOCK);
480         if (write_fd < 0) {
481                 llapi_error(LLAPI_MSG_ERROR, errno,
482                             "cannot open(%s) for write", path);
483                 return -errno;
484         }
485
486         /* Now close the reader. An external monitoring process can
487          * now open the FIFO for reads. If no reader comes along the
488          * events are lost. NOTE: Only one reader at a time! */
489         close(read_fd);
490
491         llapi_hsm_event_fp = fdopen(write_fd, "w");
492         if (llapi_hsm_event_fp == NULL) {
493                 llapi_error(LLAPI_MSG_ERROR, errno,
494                             "cannot fdopen(%s) for write", path);
495                 return -errno;
496         }
497
498         /* Ignore SIGPIPEs -- can occur if the reader goes away. */
499         signal(SIGPIPE, SIG_IGN);
500
501         /* Don't buffer the event stream. */
502         setbuf(llapi_hsm_event_fp, NULL);
503
504         return 0;
505 }
506
507 /**
508  * Given a path to a FIFO, close its filehandle and delete the FIFO.
509  *
510  * \param path               Path to monitor FIFO.
511  *
512  * \retval 0 on success.
513  * \retval -errno on error.
514  */
515 int llapi_hsm_unregister_event_fifo(char *path)
516 {
517         /* Noop unless the event fp was initialized */
518         if (llapi_hsm_event_fp == NULL)
519                 return 0;
520
521         if (fclose(llapi_hsm_event_fp) != 0)
522                 return -errno;
523
524         unlink(path);
525
526         llapi_hsm_event_fp = NULL;
527
528         return 0;
529 }
530
531 /**
532  * Custom logging callback to be used when a monitoring FIFO has been
533  * registered. Formats log entries as JSON events suitable for
534  * consumption by a copytool monitoring process.
535  *
536  * \param level              The message loglevel.
537  * \param _rc                The returncode associated with the message.
538  * \param fmt                The message format string.
539  * \param args               Arguments to be formatted by the format string.
540  *
541  * \retval None.
542  */
543 void llapi_hsm_log_error(enum llapi_message_level level, int _rc,
544                          const char *fmt, va_list args)
545 {
546         int                             rc;
547         int                             msg_len;
548         int                             real_level;
549         char                            *msg = NULL;
550         va_list                         args2;
551         struct llapi_json_item_list     *json_items;
552
553         /* Noop unless the event fp was initialized */
554         if (llapi_hsm_event_fp == NULL)
555                 return;
556
557         rc = llapi_json_init_list(&json_items);
558         if (rc < 0)
559                 goto err;
560
561         if ((level & LLAPI_MSG_NO_ERRNO) == 0) {
562                 rc = llapi_json_add_item(&json_items, "errno",
563                                          LLAPI_JSON_INTEGER,
564                                          &_rc);
565                 if (rc < 0)
566                         goto err;
567
568                 rc = llapi_json_add_item(&json_items, "error",
569                                          LLAPI_JSON_STRING,
570                                          strerror(abs(_rc)));
571                 if (rc < 0)
572                         goto err;
573         }
574
575         va_copy(args2, args);
576         msg_len = vsnprintf(NULL, 0, fmt, args2) + 1;
577         va_end(args2);
578         if (msg_len >= 0) {
579                 msg = (char *) alloca(msg_len);
580                 if (msg == NULL) {
581                         rc = -ENOMEM;
582                         goto err;
583                 }
584
585                 rc = vsnprintf(msg, msg_len, fmt, args);
586                 if (rc < 0)
587                         goto err;
588
589                 rc = llapi_json_add_item(&json_items, "message",
590                                          LLAPI_JSON_STRING,
591                                          msg);
592                 if (rc < 0)
593                         goto err;
594         } else {
595                 rc = llapi_json_add_item(&json_items, "message",
596                                          LLAPI_JSON_STRING,
597                                          "INTERNAL ERROR: message failed");
598                 if (rc < 0)
599                         goto err;
600         }
601
602         real_level = level & LLAPI_MSG_NO_ERRNO;
603         real_level = real_level > 0 ? level - LLAPI_MSG_NO_ERRNO : level;
604
605         rc = llapi_json_add_item(&json_items, "level", LLAPI_JSON_STRING,
606                                  (void *)llapi_msg_level2str(real_level));
607         if (rc < 0)
608                 goto err;
609
610         rc = llapi_json_add_item(&json_items, "event_type", LLAPI_JSON_STRING,
611                                  "LOGGED_MESSAGE");
612         if (rc < 0)
613                 goto err;
614
615         rc = llapi_hsm_write_json_event(&json_items);
616         if (rc < 0)
617                 goto err;
618
619         goto out_free;
620
621 err:
622         /* Write directly to stderr to avoid llapi_error, which now
623          * emits JSON event messages. */
624         fprintf(stderr, "\nFATAL ERROR IN llapi_hsm_log_error(): rc %d,", rc);
625
626 out_free:
627         if (json_items != NULL)
628                 llapi_json_destroy_list(&json_items);
629
630         return;
631 }
632
633 /** Register a copytool
634  * \param[out] priv Opaque private control structure
635  * \param mnt Lustre filesystem mount point
636  * \param flags Open flags, currently unused (e.g. O_NONBLOCK)
637  * \param archive_count
638  * \param archives Which archive numbers this copytool is responsible for
639  */
640 int llapi_hsm_copytool_register(struct hsm_copytool_private **priv,
641                                 const char *mnt, int flags, int archive_count,
642                                 int *archives)
643 {
644         struct hsm_copytool_private     *ct;
645         int                              rc;
646
647         if (archive_count > 0 && archives == NULL) {
648                 llapi_err_noerrno(LLAPI_MSG_ERROR,
649                                   "NULL archive numbers");
650                 return -EINVAL;
651         }
652
653         ct = calloc(1, sizeof(*ct));
654         if (ct == NULL)
655                 return -ENOMEM;
656
657         ct->magic = CT_PRIV_MAGIC;
658         ct->mnt_fd = -1;
659         ct->open_by_fid_fd = -1;
660         ct->kuc.lk_rfd = LK_NOFD;
661         ct->kuc.lk_wfd = LK_NOFD;
662
663         ct->mnt = strdup(mnt);
664         if (ct->mnt == NULL) {
665                 rc = -ENOMEM;
666                 goto out_err;
667         }
668
669         ct->mnt_fd = open(ct->mnt, O_RDONLY);
670         if (ct->mnt_fd < 0) {
671                 rc = -errno;
672                 goto out_err;
673         }
674
675         ct->open_by_fid_fd = openat(ct->mnt_fd, OPEN_BY_FID_PATH, O_RDONLY);
676         if (ct->open_by_fid_fd < 0) {
677                 rc = -errno;
678                 goto out_err;
679         }
680
681         /* no archives specified means "match all". */
682         ct->archives = 0;
683         for (rc = 0; rc < archive_count; rc++) {
684                 if (archives[rc] > 8 * sizeof(ct->archives)) {
685                         llapi_err_noerrno(LLAPI_MSG_ERROR,
686                                           "maximum of %zu archives supported",
687                                           8 * sizeof(ct->archives));
688                         goto out_err;
689                 }
690                 /* in the list we have a all archive wildcard
691                  * so move to all archives mode
692                  */
693                 if (archives[rc] == 0) {
694                         ct->archives = 0;
695                         archive_count = 0;
696                         break;
697                 }
698                 ct->archives |= (1 << (archives[rc] - 1));
699         }
700
701         rc = libcfs_ukuc_start(&ct->kuc, KUC_GRP_HSM);
702         if (rc < 0)
703                 goto out_err;
704
705         /* Storing archive(s) in lk_data; see mdc_ioc_hsm_ct_start */
706         ct->kuc.lk_data = ct->archives;
707         rc = ioctl(ct->mnt_fd, LL_IOC_HSM_CT_START, &ct->kuc);
708         if (rc < 0) {
709                 rc = -errno;
710                 llapi_error(LLAPI_MSG_ERROR, rc,
711                             "cannot start copytool on '%s'", mnt);
712                 goto out_err;
713         } else {
714                 rc = 0;
715         }
716
717         llapi_hsm_log_ct_registration(&ct, CT_REGISTER);
718
719         /* Only the kernel reference keeps the write side open */
720         close(ct->kuc.lk_wfd);
721         ct->kuc.lk_wfd = LK_NOFD;
722         if (rc < 0)
723                 goto out_kuc;
724
725         *priv = ct;
726         return 0;
727
728 out_kuc:
729         /* cleanup the kuc channel */
730         libcfs_ukuc_stop(&ct->kuc);
731
732 out_err:
733         if (!(ct->mnt_fd < 0))
734                 close(ct->mnt_fd);
735
736         if (!(ct->open_by_fid_fd < 0))
737                 close(ct->open_by_fid_fd);
738
739         if (ct->mnt != NULL)
740                 free(ct->mnt);
741
742         free(ct);
743
744         return rc;
745 }
746
747 /** Deregister a copytool
748  * Note: under Linux, until llapi_hsm_copytool_unregister is called
749  * (or the program is killed), the libcfs module will be referenced
750  * and unremovable, even after Lustre services stop.
751  */
752 int llapi_hsm_copytool_unregister(struct hsm_copytool_private **priv)
753 {
754         struct hsm_copytool_private *ct;
755
756         if (priv == NULL || *priv == NULL)
757                 return -EINVAL;
758
759         ct = *priv;
760         if (ct->magic != CT_PRIV_MAGIC)
761                 return -EINVAL;
762
763         /* Tell the kernel to stop sending us messages */
764         ct->kuc.lk_flags = LK_FLG_STOP;
765         ioctl(ct->mnt_fd, LL_IOC_HSM_CT_START, &ct->kuc);
766
767         /* Shut down the kernelcomms */
768         libcfs_ukuc_stop(&ct->kuc);
769
770         llapi_hsm_log_ct_registration(&ct, CT_UNREGISTER);
771
772         close(ct->open_by_fid_fd);
773         close(ct->mnt_fd);
774         free(ct->mnt);
775         free(ct);
776         *priv = NULL;
777
778         return 0;
779 }
780
781 /** Wait for the next hsm_action_list
782  * \param ct Opaque private control structure
783  * \param halh Action list handle, will be allocated here
784  * \param msgsize Number of bytes in the message, will be set here
785  * \return 0 valid message received; halh and msgsize are set
786  *         <0 error code
787  */
788 int llapi_hsm_copytool_recv(struct hsm_copytool_private *ct,
789                             struct hsm_action_list **halh, int *msgsize)
790 {
791         struct kuc_hdr          *kuch;
792         struct hsm_action_list  *hal;
793         int                      rc = 0;
794
795         if (ct == NULL || ct->magic != CT_PRIV_MAGIC)
796                 return -EINVAL;
797
798         if (halh == NULL || msgsize == NULL)
799                 return -EINVAL;
800
801         kuch = malloc(HAL_MAXSIZE + sizeof(*kuch));
802         if (kuch == NULL)
803                 return -ENOMEM;
804
805         rc = libcfs_ukuc_msg_get(&ct->kuc, (char *)kuch,
806                                  HAL_MAXSIZE + sizeof(*kuch),
807                                  KUC_TRANSPORT_HSM);
808         if (rc < 0)
809                 goto out_free;
810
811         /* Handle generic messages */
812         if (kuch->kuc_transport == KUC_TRANSPORT_GENERIC &&
813             kuch->kuc_msgtype == KUC_MSG_SHUTDOWN) {
814                 rc = -ESHUTDOWN;
815                 goto out_free;
816         }
817
818         if (kuch->kuc_transport != KUC_TRANSPORT_HSM ||
819             kuch->kuc_msgtype != HMT_ACTION_LIST) {
820                 llapi_err_noerrno(LLAPI_MSG_ERROR,
821                                   "Unknown HSM message type %d:%d\n",
822                                   kuch->kuc_transport, kuch->kuc_msgtype);
823                 rc = -EPROTO;
824                 goto out_free;
825         }
826
827         if (kuch->kuc_msglen < sizeof(*kuch) + sizeof(*hal)) {
828                 llapi_err_noerrno(LLAPI_MSG_ERROR, "Short HSM message %d",
829                                   kuch->kuc_msglen);
830                 rc = -EPROTO;
831                 goto out_free;
832         }
833
834         /* Our message is a hsm_action_list. Use pointer math to skip
835         * kuch_hdr and point directly to the message payload.
836         */
837         hal = (struct hsm_action_list *)(kuch + 1);
838
839         /* Check that we have registered for this archive #
840          * if 0 registered, we serve any archive */
841         if (ct->archives &&
842             ((1 << (hal->hal_archive_id - 1)) & ct->archives) == 0) {
843                 llapi_err_noerrno(LLAPI_MSG_INFO,
844                                   "This copytool does not service archive #%d,"
845                                   " ignoring this request."
846                                   " Mask of served archive is 0x%.8X",
847                                   hal->hal_archive_id, ct->archives);
848                 rc = -EAGAIN;
849
850                 goto out_free;
851         }
852
853         *halh = hal;
854         *msgsize = kuch->kuc_msglen - sizeof(*kuch);
855         return 0;
856
857 out_free:
858         *halh = NULL;
859         *msgsize = 0;
860         free(kuch);
861         return rc;
862 }
863
864 /** Release the action list when done with it. */
865 void llapi_hsm_action_list_free(struct hsm_action_list **hal)
866 {
867         /* Reuse the llapi_changelog_free function */
868         llapi_changelog_free((struct changelog_ext_rec **)hal);
869 }
870
871 /** Get parent path from mount point and fid.
872  *
873  * \param mnt        Filesystem root path.
874  * \param fid        Object FID.
875  * \param parent     Destination buffer.
876  * \param parent_len Destination buffer size.
877  * \return 0 on success.
878  */
879 static int fid_parent(const char *mnt, const lustre_fid *fid, char *parent,
880                       size_t parent_len)
881 {
882         int              rc;
883         int              linkno = 0;
884         long long        recno = -1;
885         char             file[PATH_MAX];
886         char             strfid[FID_NOBRACE_LEN + 1];
887         char            *ptr;
888
889         snprintf(strfid, sizeof(strfid), DFID_NOBRACE, PFID(fid));
890
891         rc = llapi_fid2path(mnt, strfid, file, sizeof(file),
892                             &recno, &linkno);
893         if (rc < 0)
894                 return rc;
895
896         /* fid2path returns a relative path */
897         rc = snprintf(parent, parent_len, "%s/%s", mnt, file);
898         if (rc >= parent_len)
899                 return -ENAMETOOLONG;
900
901         /* remove file name */
902         ptr = strrchr(parent, '/');
903         if (ptr == NULL || ptr == parent) {
904                 rc = -EINVAL;
905         } else {
906                 *ptr = '\0';
907                 rc = 0;
908         }
909
910         return rc;
911 }
912
913 static int ct_open_by_fid(const struct hsm_copytool_private *ct,
914                           const struct lu_fid *fid, int open_flags)
915 {
916         char fid_name[FID_NOBRACE_LEN + 1];
917
918         snprintf(fid_name, sizeof(fid_name), DFID_NOBRACE, PFID(fid));
919
920         return openat(ct->open_by_fid_fd, fid_name, open_flags);
921 }
922
923 static int ct_stat_by_fid(const struct hsm_copytool_private *ct,
924                           const struct lu_fid *fid,
925                           struct stat *buf)
926 {
927         char fid_name[FID_NOBRACE_LEN + 1];
928
929         snprintf(fid_name, sizeof(fid_name), DFID_NOBRACE, PFID(fid));
930
931         return fstatat(ct->open_by_fid_fd, fid_name, buf, 0);
932 }
933
934 /** Create the destination volatile file for a restore operation.
935  *
936  * \param hcp        Private copyaction handle.
937  * \param mdt_index  MDT index where to create the volatile file.
938  * \param flags      Volatile file creation flags.
939  * \return 0 on success.
940  */
941 static int create_restore_volatile(struct hsm_copyaction_private *hcp,
942                                    int mdt_index, int open_flags)
943 {
944         int                      rc;
945         int                      fd;
946         char                     parent[PATH_MAX + 1];
947         const char              *mnt = hcp->ct_priv->mnt;
948         struct hsm_action_item  *hai = &hcp->copy.hc_hai;
949
950         rc = fid_parent(mnt, &hai->hai_fid, parent, sizeof(parent));
951         if (rc < 0) {
952                 /* fid_parent() failed, try to keep on going */
953                 llapi_error(LLAPI_MSG_ERROR, rc,
954                             "cannot get parent path to restore "DFID" "
955                             "using '%s'", PFID(&hai->hai_fid), mnt);
956                 snprintf(parent, sizeof(parent), "%s", mnt);
957         }
958
959         fd = llapi_create_volatile_idx(parent, mdt_index, open_flags);
960         if (fd < 0)
961                 return fd;
962
963         rc = fchown(fd, hcp->stat.st_uid, hcp->stat.st_gid);
964         if (rc < 0)
965                 goto err_cleanup;
966
967         rc = llapi_fd2fid(fd, &hai->hai_dfid);
968         if (rc < 0)
969                 goto err_cleanup;
970
971         hcp->data_fd = fd;
972
973         return 0;
974
975 err_cleanup:
976         hcp->data_fd = -1;
977         close(fd);
978
979         return rc;
980 }
981
982 /** Start processing an HSM action.
983  * Should be called by copytools just before starting handling a request.
984  * It could be skipped if copytool only want to directly report an error,
985  * \see llapi_hsm_action_end().
986  *
987  * \param hcp                Opaque action handle to be passed to
988  *                           llapi_hsm_action_progress and llapi_hsm_action_end.
989  * \param ct                 Copytool handle acquired at registration.
990  * \param hai                The hsm_action_item describing the request.
991  * \param restore_mdt_index  On restore: MDT index where to create the volatile
992  *                           file. Use -1 for default.
993  * \param restore_open_flags On restore: volatile file creation mode. Use
994  *                           O_LOV_DELAY_CREATE to manually set the LOVEA
995  *                           afterwards.
996  * \param is_error           Whether this call is just to report an error.
997  *
998  * \return 0 on success.
999  */
1000 int llapi_hsm_action_begin(struct hsm_copyaction_private **phcp,
1001                            const struct hsm_copytool_private *ct,
1002                            const struct hsm_action_item *hai,
1003                            int restore_mdt_index, int restore_open_flags,
1004                            bool is_error)
1005 {
1006         struct hsm_copyaction_private   *hcp;
1007         int                              rc;
1008
1009         hcp = calloc(1, sizeof(*hcp));
1010         if (hcp == NULL)
1011                 return -ENOMEM;
1012
1013         hcp->data_fd = -1;
1014         hcp->ct_priv = ct;
1015         hcp->copy.hc_hai = *hai;
1016         hcp->copy.hc_hai.hai_len = sizeof(*hai);
1017
1018         if (is_error)
1019                 goto ok_out;
1020
1021         if (hai->hai_action == HSMA_RESTORE) {
1022                 rc = ct_stat_by_fid(hcp->ct_priv, &hai->hai_fid, &hcp->stat);
1023                 if (rc < 0)
1024                         goto err_out;
1025
1026                 rc = create_restore_volatile(hcp, restore_mdt_index,
1027                                              restore_open_flags);
1028                 if (rc < 0)
1029                         goto err_out;
1030         }
1031
1032         rc = ioctl(ct->mnt_fd, LL_IOC_HSM_COPY_START, &hcp->copy);
1033         if (rc < 0) {
1034                 rc = -errno;
1035                 goto err_out;
1036         }
1037
1038         llapi_hsm_log_ct_progress(&hcp, hai, CT_START, 0, 0);
1039
1040 ok_out:
1041         hcp->magic = CP_PRIV_MAGIC;
1042         *phcp = hcp;
1043         return 0;
1044
1045 err_out:
1046         if (!(hcp->data_fd < 0))
1047                 close(hcp->data_fd);
1048
1049         free(hcp);
1050
1051         return rc;
1052 }
1053
1054 /** Terminate an HSM action processing.
1055  * Should be called by copytools just having finished handling the request.
1056  * \param hdl[in,out]  Handle returned by llapi_hsm_action_start.
1057  * \param he[in]       The final range of copied data (for copy actions).
1058  * \param errval[in]   The status code of the operation.
1059  * \param flags[in]    The flags about the termination status (HP_FLAG_RETRY if
1060  *                     the error is retryable).
1061  *
1062  * \return 0 on success.
1063  */
1064 int llapi_hsm_action_end(struct hsm_copyaction_private **phcp,
1065                          const struct hsm_extent *he, int hp_flags, int errval)
1066 {
1067         struct hsm_copyaction_private   *hcp;
1068         struct hsm_action_item          *hai;
1069         int                              rc;
1070
1071         if (phcp == NULL || *phcp == NULL || he == NULL)
1072                 return -EINVAL;
1073
1074         hcp = *phcp;
1075
1076         if (hcp->magic != CP_PRIV_MAGIC)
1077                 return -EINVAL;
1078
1079         hai = &hcp->copy.hc_hai;
1080
1081         if (hai->hai_action == HSMA_RESTORE && errval == 0) {
1082                 struct timeval tv[2];
1083
1084                 /* Set {a,m}time of volatile file to that of original. */
1085                 tv[0].tv_sec = hcp->stat.st_atime;
1086                 tv[0].tv_usec = 0;
1087                 tv[1].tv_sec = hcp->stat.st_mtime;
1088                 tv[1].tv_usec = 0;
1089                 if (futimes(hcp->data_fd, tv) < 0) {
1090                         errval = -errno;
1091                         goto end;
1092                 }
1093
1094                 rc = fsync(hcp->data_fd);
1095                 if (rc < 0) {
1096                         errval = -errno;
1097                         goto end;
1098                 }
1099         }
1100
1101 end:
1102         /* In some cases, like restore, 2 FIDs are used.
1103          * Set the right FID to use here. */
1104         if (hai->hai_action == HSMA_ARCHIVE || hai->hai_action == HSMA_RESTORE)
1105                 hai->hai_fid = hai->hai_dfid;
1106
1107         /* Fill the last missing data that will be needed by
1108          * kernel to send a hsm_progress. */
1109         hcp->copy.hc_flags  = hp_flags;
1110         hcp->copy.hc_errval = abs(errval);
1111
1112         hcp->copy.hc_hai.hai_extent = *he;
1113
1114         rc = ioctl(hcp->ct_priv->mnt_fd, LL_IOC_HSM_COPY_END, &hcp->copy);
1115         if (rc) {
1116                 rc = -errno;
1117                 goto err_cleanup;
1118         }
1119
1120         llapi_hsm_log_ct_progress(&hcp, hai, CT_FINISH, 0, 0);
1121
1122 err_cleanup:
1123         if (!(hcp->data_fd < 0))
1124                 close(hcp->data_fd);
1125
1126         free(hcp);
1127         *phcp = NULL;
1128
1129         return rc;
1130 }
1131
1132 /** Notify a progress in processing an HSM action.
1133  * \param hdl[in,out]   handle returned by llapi_hsm_action_start.
1134  * \param he[in]        the range of copied data (for copy actions).
1135  * \param total[in]     the expected total of copied data (for copy actions).
1136  * \param hp_flags[in]  HSM progress flags.
1137  * \return 0 on success.
1138  */
1139 int llapi_hsm_action_progress(struct hsm_copyaction_private *hcp,
1140                               const struct hsm_extent *he, __u64 total,
1141                               int hp_flags)
1142 {
1143         int                      rc;
1144         struct hsm_progress      hp;
1145         struct hsm_action_item  *hai;
1146
1147         if (hcp == NULL || he == NULL)
1148                 return -EINVAL;
1149
1150         if (hcp->magic != CP_PRIV_MAGIC)
1151                 return -EINVAL;
1152
1153         hai = &hcp->copy.hc_hai;
1154
1155         memset(&hp, 0, sizeof(hp));
1156
1157         hp.hp_cookie = hai->hai_cookie;
1158         hp.hp_flags  = hp_flags;
1159
1160         /* Progress is made on the data fid */
1161         hp.hp_fid = hai->hai_dfid;
1162         hp.hp_extent = *he;
1163
1164         rc = ioctl(hcp->ct_priv->mnt_fd, LL_IOC_HSM_PROGRESS, &hp);
1165         if (rc < 0)
1166                 rc = -errno;
1167
1168         llapi_hsm_log_ct_progress(&hcp, hai, CT_RUNNING, total, he->length);
1169
1170         return rc;
1171 }
1172
1173 /** Get the fid of object to be used for copying data.
1174  * @return error code if the action is not a copy operation.
1175  */
1176 int llapi_hsm_action_get_dfid(const struct hsm_copyaction_private *hcp,
1177                               lustre_fid *fid)
1178 {
1179         const struct hsm_action_item    *hai = &hcp->copy.hc_hai;
1180
1181         if (hcp->magic != CP_PRIV_MAGIC)
1182                 return -EINVAL;
1183
1184         if (hai->hai_action != HSMA_RESTORE && hai->hai_action != HSMA_ARCHIVE)
1185                 return -EINVAL;
1186
1187         *fid = hai->hai_dfid;
1188
1189         return 0;
1190 }
1191
1192 /**
1193  * Get a file descriptor to be used for copying data. It's up to the
1194  * caller to close the FDs obtained from this function.
1195  *
1196  * @retval a file descriptor on success.
1197  * @retval a negative error code on failure.
1198  */
1199 int llapi_hsm_action_get_fd(const struct hsm_copyaction_private *hcp)
1200 {
1201         const struct hsm_action_item    *hai = &hcp->copy.hc_hai;
1202
1203         if (hcp->magic != CP_PRIV_MAGIC)
1204                 return -EINVAL;
1205
1206         if (hai->hai_action == HSMA_ARCHIVE)
1207                 return ct_open_by_fid(hcp->ct_priv, &hai->hai_dfid,
1208                                 O_RDONLY | O_NOATIME | O_NOFOLLOW | O_NONBLOCK);
1209         else if (hai->hai_action == HSMA_RESTORE)
1210                 return dup(hcp->data_fd);
1211         else
1212                 return -EINVAL;
1213 }
1214
1215 /**
1216  * Import an existing hsm-archived file into Lustre.
1217  *
1218  * Caller must access file by (returned) newfid value from now on.
1219  *
1220  * \param dst      path to Lustre destination (e.g. /mnt/lustre/my/file).
1221  * \param archive  archive number.
1222  * \param st       struct stat buffer containing file ownership, perm, etc.
1223  * \param stripe_* Striping options.  Currently ignored, since the restore
1224  *                 operation will set the striping.  In V2, this striping might
1225  *                 be used.
1226  * \param newfid[out] Filled with new Lustre fid.
1227  */
1228 int llapi_hsm_import(const char *dst, int archive, const struct stat *st,
1229                      unsigned long long stripe_size, int stripe_offset,
1230                      int stripe_count, int stripe_pattern, char *pool_name,
1231                      lustre_fid *newfid)
1232 {
1233         struct hsm_user_import   hui;
1234         int                      fd;
1235         int                      rc = 0;
1236
1237         if (stripe_pattern == 0)
1238                 stripe_pattern = LOV_PATTERN_RAID0;
1239
1240         /* Create a non-striped file */
1241         fd = llapi_file_open_pool(dst, O_CREAT | O_WRONLY, st->st_mode,
1242                                   stripe_size, stripe_offset, stripe_count,
1243                                   stripe_pattern | LOV_PATTERN_F_RELEASED,
1244                                   pool_name);
1245         if (fd < 0) {
1246                 llapi_error(LLAPI_MSG_ERROR, -errno,
1247                             "cannot create '%s' for import", dst);
1248                 return -errno;
1249         }
1250
1251         /* Get the new fid in Lustre. Caller needs to use this fid
1252            from now on. */
1253         rc = llapi_fd2fid(fd, newfid);
1254         if (rc != 0) {
1255                 llapi_error(LLAPI_MSG_ERROR, rc,
1256                             "cannot get fid of '%s' for import", dst);
1257                 goto out_unlink;
1258         }
1259
1260         hui.hui_uid = st->st_uid;
1261         hui.hui_gid = st->st_gid;
1262         hui.hui_mode = st->st_mode;
1263         hui.hui_size = st->st_size;
1264         hui.hui_archive_id = archive;
1265         hui.hui_atime = st->st_atime;
1266         hui.hui_atime_ns = st->st_atim.tv_nsec;
1267         hui.hui_mtime = st->st_mtime;
1268         hui.hui_mtime_ns = st->st_mtim.tv_nsec;
1269         rc = ioctl(fd, LL_IOC_HSM_IMPORT, &hui);
1270         if (rc != 0) {
1271                 llapi_error(LLAPI_MSG_ERROR, rc, "cannot import '%s'", dst);
1272                 rc = -errno;
1273                 goto out_unlink;
1274         }
1275
1276 out_unlink:
1277         if (fd >= 0)
1278                 close(fd);
1279         if (rc)
1280                 unlink(dst);
1281         return rc;
1282 }
1283
1284 /**
1285  * Return the current HSM states and HSM requests related to file pointed by \a
1286  * path.
1287  *
1288  * \param hus  Should be allocated by caller. Will be filled with current file
1289  *             states.
1290  *
1291  * \retval 0 on success.
1292  * \retval -errno on error.
1293  */
1294 int llapi_hsm_state_get_fd(int fd, struct hsm_user_state *hus)
1295 {
1296         int rc;
1297
1298         rc = ioctl(fd, LL_IOC_HSM_STATE_GET, hus);
1299         /* If error, save errno value */
1300         rc = rc ? -errno : 0;
1301
1302         return rc;
1303 }
1304
1305 /**
1306  * Return the current HSM states and HSM requests related to file pointed by \a
1307  * path.
1308  *
1309  * see llapi_hsm_state_get_fd() for args use and return
1310  */
1311 int llapi_hsm_state_get(const char *path, struct hsm_user_state *hus)
1312 {
1313         int fd;
1314         int rc;
1315
1316         fd = open(path, O_RDONLY | O_NONBLOCK);
1317         if (fd < 0)
1318                 return -errno;
1319
1320         rc = llapi_hsm_state_get_fd(fd, hus);
1321
1322         close(fd);
1323         return rc;
1324 }
1325
1326 /**
1327  * Set HSM states of file pointed by \a fd
1328  *
1329  * Using the provided bitmasks, the current HSM states for this file will be
1330  * changed. \a archive_id could be used to change the archive number also. Set
1331  * it to 0 if you do not want to change it.
1332  *
1333  * \param setmask      Bitmask for flag to be set.
1334  * \param clearmask    Bitmask for flag to be cleared.
1335  * \param archive_id  Archive number identifier to use. 0 means no change.
1336  *
1337  * \retval 0 on success.
1338  * \retval -errno on error.
1339  */
1340 int llapi_hsm_state_set_fd(int fd, __u64 setmask, __u64 clearmask,
1341                            __u32 archive_id)
1342 {
1343         struct hsm_state_set     hss;
1344         int                      rc;
1345
1346         hss.hss_valid = HSS_SETMASK|HSS_CLEARMASK;
1347         hss.hss_setmask = setmask;
1348         hss.hss_clearmask = clearmask;
1349         /* Change archive_id if provided. We can only change
1350          * to set something different than 0. */
1351         if (archive_id > 0) {
1352                 hss.hss_valid |= HSS_ARCHIVE_ID;
1353                 hss.hss_archive_id = archive_id;
1354         }
1355         rc = ioctl(fd, LL_IOC_HSM_STATE_SET, &hss);
1356         /* If error, save errno value */
1357         rc = rc ? -errno : 0;
1358
1359         return rc;
1360 }
1361
1362 /**
1363  * Set HSM states of file pointed by \a path.
1364  *
1365  * see llapi_hsm_state_set_fd() for args use and return
1366  */
1367 int llapi_hsm_state_set(const char *path, __u64 setmask, __u64 clearmask,
1368                         __u32 archive_id)
1369 {
1370         int fd;
1371         int rc;
1372
1373         fd = open(path, O_WRONLY | O_LOV_DELAY_CREATE | O_NONBLOCK);
1374         if (fd < 0)
1375                 return -errno;
1376
1377         rc = llapi_hsm_state_set_fd(fd, setmask, clearmask, archive_id);
1378
1379         close(fd);
1380         return rc;
1381 }
1382
1383 /**
1384  * Return the current HSM request related to file pointed by \a path.
1385  *
1386  * \param hca  Should be allocated by caller. Will be filled with current file
1387  *             actions.
1388  *
1389  * \retval 0 on success.
1390  * \retval -errno on error.
1391  */
1392 int llapi_hsm_current_action(const char *path, struct hsm_current_action *hca)
1393 {
1394         int fd;
1395         int rc;
1396
1397         fd = open(path, O_RDONLY | O_NONBLOCK);
1398         if (fd < 0)
1399                 return -errno;
1400
1401         rc = ioctl(fd, LL_IOC_HSM_ACTION, hca);
1402         /* If error, save errno value */
1403         rc = rc ? -errno : 0;
1404
1405         close(fd);
1406         return rc;
1407 }
1408
1409 /**
1410  * Allocate a hsm_user_request with the specified carateristics.
1411  * This structure should be freed with free().
1412  *
1413  * \return an allocated structure on success, NULL otherwise.
1414  */
1415 struct hsm_user_request *llapi_hsm_user_request_alloc(int itemcount,
1416                                                       int data_len)
1417 {
1418         int len = 0;
1419
1420         len += sizeof(struct hsm_user_request);
1421         len += sizeof(struct hsm_user_item) * itemcount;
1422         len += data_len;
1423
1424         return (struct hsm_user_request *)malloc(len);
1425 }
1426
1427 /**
1428  * Send a HSM request to Lustre, described in \param request.
1429  *
1430  * \param path    Fullpath to the file to operate on.
1431  * \param request The request, allocated with llapi_hsm_user_request_alloc().
1432  *
1433  * \return 0 on success, an error code otherwise.
1434  */
1435 int llapi_hsm_request(const char *path, const struct hsm_user_request *request)
1436 {
1437         int rc;
1438         int fd;
1439
1440         rc = get_root_path(WANT_FD, NULL, &fd, (char *)path, -1);
1441         if (rc)
1442                 return rc;
1443
1444         rc = ioctl(fd, LL_IOC_HSM_REQUEST, request);
1445         /* If error, save errno value */
1446         rc = rc ? -errno : 0;
1447
1448         close(fd);
1449         return rc;
1450 }
1451