Whamcloud - gitweb
LU-2675 obdclass: remove uses of lov_stripe_md
[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 #ifdef HAVE_LINUX_UNISTD_H
50 #include <linux/unistd.h>
51 #else
52 #include <unistd.h>
53 #endif
54
55 #include <liblustre.h>
56 #include <lnet/lnetctl.h>
57 #include <obd.h>
58 #include <lustre/lustreapi.h>
59 #include "lustreapi_internal.h"
60
61 #define OPEN_BY_FID_PATH dot_lustre_name"/fid"
62
63 /****** HSM Copytool API ********/
64 #define CT_PRIV_MAGIC 0xC0BE2001
65 struct hsm_copytool_private {
66         int                      magic;
67         char                    *mnt;
68         int                      mnt_fd;
69         int                      open_by_fid_fd;
70         lustre_kernelcomm        kuc;
71         __u32                    archives;
72 };
73
74 #define CP_PRIV_MAGIC 0x19880429
75 struct hsm_copyaction_private {
76         __u32                                    magic;
77         __s32                                    data_fd;
78         const struct hsm_copytool_private       *ct_priv;
79         struct hsm_copy                          copy;
80         struct stat                              stat;
81 };
82
83 #include <libcfs/libcfs.h>
84
85 /** Register a copytool
86  * \param[out] priv Opaque private control structure
87  * \param mnt Lustre filesystem mount point
88  * \param flags Open flags, currently unused (e.g. O_NONBLOCK)
89  * \param archive_count
90  * \param archives Which archive numbers this copytool is responsible for
91  */
92 int llapi_hsm_copytool_register(struct hsm_copytool_private **priv,
93                                 const char *mnt, int flags, int archive_count,
94                                 int *archives)
95 {
96         struct hsm_copytool_private     *ct;
97         int                              rc;
98
99         if (archive_count > 0 && archives == NULL) {
100                 llapi_err_noerrno(LLAPI_MSG_ERROR,
101                                   "NULL archive numbers");
102                 return -EINVAL;
103         }
104
105         ct = calloc(1, sizeof(*ct));
106         if (ct == NULL)
107                 return -ENOMEM;
108
109         ct->magic = CT_PRIV_MAGIC;
110         ct->mnt_fd = -1;
111         ct->open_by_fid_fd = -1;
112         ct->kuc.lk_rfd = LK_NOFD;
113         ct->kuc.lk_wfd = LK_NOFD;
114
115         ct->mnt = strdup(mnt);
116         if (ct->mnt == NULL) {
117                 rc = -ENOMEM;
118                 goto out_err;
119         }
120
121         ct->mnt_fd = open(ct->mnt, O_RDONLY);
122         if (ct->mnt_fd < 0) {
123                 rc = -errno;
124                 goto out_err;
125         }
126
127         ct->open_by_fid_fd = openat(ct->mnt_fd, OPEN_BY_FID_PATH, O_RDONLY);
128         if (ct->open_by_fid_fd < 0) {
129                 rc = -errno;
130                 goto out_err;
131         }
132
133         /* no archives specified means "match all". */
134         ct->archives = 0;
135         for (rc = 0; rc < archive_count; rc++) {
136                 if (archives[rc] > 8 * sizeof(ct->archives)) {
137                         llapi_err_noerrno(LLAPI_MSG_ERROR,
138                                           "maximum of %zu archives supported",
139                                           8 * sizeof(ct->archives));
140                         goto out_err;
141                 }
142                 /* in the list we have a all archive wildcard
143                  * so move to all archives mode
144                  */
145                 if (archives[rc] == 0) {
146                         ct->archives = 0;
147                         archive_count = 0;
148                         break;
149                 }
150                 ct->archives |= (1 << (archives[rc] - 1));
151         }
152
153         rc = libcfs_ukuc_start(&ct->kuc, KUC_GRP_HSM);
154         if (rc < 0)
155                 goto out_err;
156
157         /* Storing archive(s) in lk_data; see mdc_ioc_hsm_ct_start */
158         ct->kuc.lk_data = ct->archives;
159         rc = ioctl(ct->mnt_fd, LL_IOC_HSM_CT_START, &ct->kuc);
160         if (rc < 0) {
161                 rc = -errno;
162                 llapi_error(LLAPI_MSG_ERROR, rc,
163                             "cannot start copytool on '%s'", mnt);
164                 goto out_err;
165         } else {
166                 rc = 0;
167         }
168
169         /* Only the kernel reference keeps the write side open */
170         close(ct->kuc.lk_wfd);
171         ct->kuc.lk_wfd = LK_NOFD;
172         if (rc < 0)
173                 goto out_kuc;
174
175         *priv = ct;
176         return 0;
177
178 out_kuc:
179         /* cleanup the kuc channel */
180         libcfs_ukuc_stop(&ct->kuc);
181
182 out_err:
183         if (!(ct->mnt_fd < 0))
184                 close(ct->mnt_fd);
185
186         if (!(ct->open_by_fid_fd < 0))
187                 close(ct->open_by_fid_fd);
188
189         if (ct->mnt != NULL)
190                 free(ct->mnt);
191
192         free(ct);
193
194         return rc;
195 }
196
197 /** Deregister a copytool
198  * Note: under Linux, until llapi_hsm_copytool_unregister is called
199  * (or the program is killed), the libcfs module will be referenced
200  * and unremovable, even after Lustre services stop.
201  */
202 int llapi_hsm_copytool_unregister(struct hsm_copytool_private **priv)
203 {
204         struct hsm_copytool_private *ct;
205
206         if (priv == NULL || *priv == NULL)
207                 return -EINVAL;
208
209         ct = *priv;
210         if (ct->magic != CT_PRIV_MAGIC)
211                 return -EINVAL;
212
213         /* Tell the kernel to stop sending us messages */
214         ct->kuc.lk_flags = LK_FLG_STOP;
215         ioctl(ct->mnt_fd, LL_IOC_HSM_CT_START, &ct->kuc);
216
217         /* Shut down the kernelcomms */
218         libcfs_ukuc_stop(&ct->kuc);
219
220         close(ct->open_by_fid_fd);
221         close(ct->mnt_fd);
222         free(ct->mnt);
223         free(ct);
224         *priv = NULL;
225
226         return 0;
227 }
228
229 /** Wait for the next hsm_action_list
230  * \param ct Opaque private control structure
231  * \param halh Action list handle, will be allocated here
232  * \param msgsize Number of bytes in the message, will be set here
233  * \return 0 valid message received; halh and msgsize are set
234  *         <0 error code
235  */
236 int llapi_hsm_copytool_recv(struct hsm_copytool_private *ct,
237                             struct hsm_action_list **halh, int *msgsize)
238 {
239         struct kuc_hdr          *kuch;
240         struct hsm_action_list  *hal;
241         int                      rc = 0;
242
243         if (ct == NULL || ct->magic != CT_PRIV_MAGIC)
244                 return -EINVAL;
245
246         if (halh == NULL || msgsize == NULL)
247                 return -EINVAL;
248
249         kuch = malloc(HAL_MAXSIZE + sizeof(*kuch));
250         if (kuch == NULL)
251                 return -ENOMEM;
252
253         rc = libcfs_ukuc_msg_get(&ct->kuc, (char *)kuch,
254                                  HAL_MAXSIZE + sizeof(*kuch),
255                                  KUC_TRANSPORT_HSM);
256         if (rc < 0)
257                 goto out_free;
258
259         /* Handle generic messages */
260         if (kuch->kuc_transport == KUC_TRANSPORT_GENERIC &&
261             kuch->kuc_msgtype == KUC_MSG_SHUTDOWN) {
262                 rc = -ESHUTDOWN;
263                 goto out_free;
264         }
265
266         if (kuch->kuc_transport != KUC_TRANSPORT_HSM ||
267             kuch->kuc_msgtype != HMT_ACTION_LIST) {
268                 llapi_err_noerrno(LLAPI_MSG_ERROR,
269                                   "Unknown HSM message type %d:%d\n",
270                                   kuch->kuc_transport, kuch->kuc_msgtype);
271                 rc = -EPROTO;
272                 goto out_free;
273         }
274
275         if (kuch->kuc_msglen < sizeof(*kuch) + sizeof(*hal)) {
276                 llapi_err_noerrno(LLAPI_MSG_ERROR, "Short HSM message %d",
277                                   kuch->kuc_msglen);
278                 rc = -EPROTO;
279                 goto out_free;
280         }
281
282         /* Our message is a hsm_action_list. Use pointer math to skip
283         * kuch_hdr and point directly to the message payload.
284         */
285         hal = (struct hsm_action_list *)(kuch + 1);
286
287         /* Check that we have registered for this archive #
288          * if 0 registered, we serve any archive */
289         if (ct->archives &&
290             ((1 << (hal->hal_archive_id - 1)) & ct->archives) == 0) {
291                 llapi_err_noerrno(LLAPI_MSG_INFO,
292                                   "This copytool does not service archive #%d,"
293                                   " ignoring this request."
294                                   " Mask of served archive is 0x%.8X",
295                                   hal->hal_archive_id, ct->archives);
296                 rc = -EAGAIN;
297
298                 goto out_free;
299         }
300
301         *halh = hal;
302         *msgsize = kuch->kuc_msglen - sizeof(*kuch);
303         return 0;
304
305 out_free:
306         *halh = NULL;
307         *msgsize = 0;
308         free(kuch);
309         return rc;
310 }
311
312 /** Release the action list when done with it. */
313 void llapi_hsm_action_list_free(struct hsm_action_list **hal)
314 {
315         /* Reuse the llapi_changelog_free function */
316         llapi_changelog_free((struct changelog_ext_rec **)hal);
317 }
318
319 /** Get parent path from mount point and fid.
320  *
321  * \param mnt        Filesystem root path.
322  * \param fid        Object FID.
323  * \param parent     Destination buffer.
324  * \param parent_len Destination buffer size.
325  * \return 0 on success.
326  */
327 static int fid_parent(const char *mnt, const lustre_fid *fid, char *parent,
328                       size_t parent_len)
329 {
330         int              rc;
331         int              linkno = 0;
332         long long        recno = -1;
333         char             file[PATH_MAX];
334         char             strfid[FID_NOBRACE_LEN + 1];
335         char            *ptr;
336
337         snprintf(strfid, sizeof(strfid), DFID_NOBRACE, PFID(fid));
338
339         rc = llapi_fid2path(mnt, strfid, file, sizeof(file),
340                             &recno, &linkno);
341         if (rc < 0)
342                 return rc;
343
344         /* fid2path returns a relative path */
345         rc = snprintf(parent, parent_len, "%s/%s", mnt, file);
346         if (rc >= parent_len)
347                 return -ENAMETOOLONG;
348
349         /* remove file name */
350         ptr = strrchr(parent, '/');
351         if (ptr == NULL || ptr == parent) {
352                 rc = -EINVAL;
353         } else {
354                 *ptr = '\0';
355                 rc = 0;
356         }
357
358         return rc;
359 }
360
361 static int ct_open_by_fid(const struct hsm_copytool_private *ct,
362                           const struct lu_fid *fid, int open_flags)
363 {
364         char fid_name[FID_NOBRACE_LEN + 1];
365
366         snprintf(fid_name, sizeof(fid_name), DFID_NOBRACE, PFID(fid));
367
368         return openat(ct->open_by_fid_fd, fid_name, open_flags);
369 }
370
371 static int ct_stat_by_fid(const struct hsm_copytool_private *ct,
372                           const struct lu_fid *fid,
373                           struct stat *buf)
374 {
375         char fid_name[FID_NOBRACE_LEN + 1];
376
377         snprintf(fid_name, sizeof(fid_name), DFID_NOBRACE, PFID(fid));
378
379         return fstatat(ct->open_by_fid_fd, fid_name, buf, 0);
380 }
381
382 /** Create the destination volatile file for a restore operation.
383  *
384  * \param hcp        Private copyaction handle.
385  * \param mdt_index  MDT index where to create the volatile file.
386  * \param flags      Volatile file creation flags.
387  * \return 0 on success.
388  */
389 static int create_restore_volatile(struct hsm_copyaction_private *hcp,
390                                    int mdt_index, int open_flags)
391 {
392         int                      rc;
393         int                      fd;
394         char                     parent[PATH_MAX + 1];
395         const char              *mnt = hcp->ct_priv->mnt;
396         struct hsm_action_item  *hai = &hcp->copy.hc_hai;
397
398         rc = fid_parent(mnt, &hai->hai_fid, parent, sizeof(parent));
399         if (rc < 0) {
400                 /* fid_parent() failed, try to keep on going */
401                 llapi_error(LLAPI_MSG_ERROR, rc,
402                             "cannot get parent path to restore "DFID" "
403                             "using '%s'", PFID(&hai->hai_fid), mnt);
404                 snprintf(parent, sizeof(parent), "%s", mnt);
405         }
406
407         fd = llapi_create_volatile_idx(parent, mdt_index, open_flags);
408         if (fd < 0)
409                 return fd;
410
411         rc = fchown(fd, hcp->stat.st_uid, hcp->stat.st_gid);
412         if (rc < 0)
413                 goto err_cleanup;
414
415         rc = llapi_fd2fid(fd, &hai->hai_dfid);
416         if (rc < 0)
417                 goto err_cleanup;
418
419         hcp->data_fd = fd;
420
421         return 0;
422
423 err_cleanup:
424         hcp->data_fd = -1;
425         close(fd);
426
427         return rc;
428 }
429
430 /** Start processing an HSM action.
431  * Should be called by copytools just before starting handling a request.
432  * It could be skipped if copytool only want to directly report an error,
433  * \see llapi_hsm_action_end().
434  *
435  * \param hcp                Opaque action handle to be passed to
436  *                           llapi_hsm_action_progress and llapi_hsm_action_end.
437  * \param ct                 Copytool handle acquired at registration.
438  * \param hai                The hsm_action_item describing the request.
439  * \param restore_mdt_index  On restore: MDT index where to create the volatile
440  *                           file. Use -1 for default.
441  * \param restore_open_flags On restore: volatile file creation mode. Use
442  *                           O_LOV_DELAY_CREATE to manually set the LOVEA
443  *                           afterwards.
444  * \param is_error           Whether this call is just to report an error.
445  *
446  * \return 0 on success.
447  */
448 int llapi_hsm_action_begin(struct hsm_copyaction_private **phcp,
449                            const struct hsm_copytool_private *ct,
450                            const struct hsm_action_item *hai,
451                            int restore_mdt_index, int restore_open_flags,
452                            bool is_error)
453 {
454         struct hsm_copyaction_private   *hcp;
455         int                              rc;
456
457         hcp = calloc(1, sizeof(*hcp));
458         if (hcp == NULL)
459                 return -ENOMEM;
460
461         hcp->data_fd = -1;
462         hcp->ct_priv = ct;
463         hcp->copy.hc_hai = *hai;
464         hcp->copy.hc_hai.hai_len = sizeof(*hai);
465
466         if (is_error)
467                 goto ok_out;
468
469         if (hai->hai_action == HSMA_RESTORE) {
470                 rc = ct_stat_by_fid(hcp->ct_priv, &hai->hai_fid, &hcp->stat);
471                 if (rc < 0)
472                         goto err_out;
473
474                 rc = create_restore_volatile(hcp, restore_mdt_index,
475                                              restore_open_flags);
476                 if (rc < 0)
477                         goto err_out;
478         }
479
480         rc = ioctl(ct->mnt_fd, LL_IOC_HSM_COPY_START, &hcp->copy);
481         if (rc < 0) {
482                 rc = -errno;
483                 goto err_out;
484         }
485
486 ok_out:
487         hcp->magic = CP_PRIV_MAGIC;
488         *phcp = hcp;
489         return 0;
490
491 err_out:
492         if (!(hcp->data_fd < 0))
493                 close(hcp->data_fd);
494
495         free(hcp);
496
497         return rc;
498 }
499
500 /** Terminate an HSM action processing.
501  * Should be called by copytools just having finished handling the request.
502  * \param hdl[in,out]  Handle returned by llapi_hsm_action_start.
503  * \param he[in]       The final range of copied data (for copy actions).
504  * \param errval[in]   The status code of the operation.
505  * \param flags[in]    The flags about the termination status (HP_FLAG_RETRY if
506  *                     the error is retryable).
507  *
508  * \return 0 on success.
509  */
510 int llapi_hsm_action_end(struct hsm_copyaction_private **phcp,
511                          const struct hsm_extent *he, int hp_flags, int errval)
512 {
513         struct hsm_copyaction_private   *hcp;
514         struct hsm_action_item          *hai;
515         int                              rc;
516
517         if (phcp == NULL || *phcp == NULL || he == NULL)
518                 return -EINVAL;
519
520         hcp = *phcp;
521
522         if (hcp->magic != CP_PRIV_MAGIC)
523                 return -EINVAL;
524
525         hai = &hcp->copy.hc_hai;
526
527         if (hai->hai_action == HSMA_RESTORE && errval == 0) {
528                 struct timeval tv[2];
529
530                 /* Set {a,m}time of volatile file to that of original. */
531                 tv[0].tv_sec = hcp->stat.st_atime;
532                 tv[0].tv_usec = 0;
533                 tv[1].tv_sec = hcp->stat.st_mtime;
534                 tv[1].tv_usec = 0;
535                 if (futimes(hcp->data_fd, tv) < 0) {
536                         errval = -errno;
537                         goto end;
538                 }
539
540                 rc = fsync(hcp->data_fd);
541                 if (rc < 0) {
542                         errval = -errno;
543                         goto end;
544                 }
545         }
546
547 end:
548         /* In some cases, like restore, 2 FIDs are used.
549          * Set the right FID to use here. */
550         if (hai->hai_action == HSMA_ARCHIVE || hai->hai_action == HSMA_RESTORE)
551                 hai->hai_fid = hai->hai_dfid;
552
553         /* Fill the last missing data that will be needed by
554          * kernel to send a hsm_progress. */
555         hcp->copy.hc_flags  = hp_flags;
556         hcp->copy.hc_errval = abs(errval);
557
558         hcp->copy.hc_hai.hai_extent = *he;
559
560         rc = ioctl(hcp->ct_priv->mnt_fd, LL_IOC_HSM_COPY_END, &hcp->copy);
561         if (rc) {
562                 rc = -errno;
563                 goto err_cleanup;
564         }
565
566 err_cleanup:
567         if (!(hcp->data_fd < 0))
568                 close(hcp->data_fd);
569
570         free(hcp);
571         *phcp = NULL;
572
573         return rc;
574 }
575
576 /** Notify a progress in processing an HSM action.
577  * \param hdl[in,out]   handle returned by llapi_hsm_action_start.
578  * \param he[in]        the range of copied data (for copy actions).
579  * \param hp_flags[in]  HSM progress flags.
580  * \return 0 on success.
581  */
582 int llapi_hsm_action_progress(struct hsm_copyaction_private *hcp,
583                               const struct hsm_extent *he, int hp_flags)
584 {
585         int                      rc;
586         struct hsm_progress      hp;
587         struct hsm_action_item  *hai;
588
589         if (hcp == NULL || he == NULL)
590                 return -EINVAL;
591
592         if (hcp->magic != CP_PRIV_MAGIC)
593                 return -EINVAL;
594
595         hai = &hcp->copy.hc_hai;
596
597         memset(&hp, 0, sizeof(hp));
598
599         hp.hp_cookie = hai->hai_cookie;
600         hp.hp_flags  = hp_flags;
601
602         /* Progress is made on the data fid */
603         hp.hp_fid = hai->hai_dfid;
604         hp.hp_extent = *he;
605
606         rc = ioctl(hcp->ct_priv->mnt_fd, LL_IOC_HSM_PROGRESS, &hp);
607         if (rc < 0)
608                 rc = -errno;
609
610         return rc;
611 }
612
613 /** Get the fid of object to be used for copying data.
614  * @return error code if the action is not a copy operation.
615  */
616 int llapi_hsm_action_get_dfid(const struct hsm_copyaction_private *hcp,
617                               lustre_fid *fid)
618 {
619         const struct hsm_action_item    *hai = &hcp->copy.hc_hai;
620
621         if (hcp->magic != CP_PRIV_MAGIC)
622                 return -EINVAL;
623
624         if (hai->hai_action != HSMA_RESTORE && hai->hai_action != HSMA_ARCHIVE)
625                 return -EINVAL;
626
627         *fid = hai->hai_dfid;
628
629         return 0;
630 }
631
632 /**
633  * Get a file descriptor to be used for copying data. It's up to the
634  * caller to close the FDs obtained from this function.
635  *
636  * @retval a file descriptor on success.
637  * @retval a negative error code on failure.
638  */
639 int llapi_hsm_action_get_fd(const struct hsm_copyaction_private *hcp)
640 {
641         const struct hsm_action_item    *hai = &hcp->copy.hc_hai;
642
643         if (hcp->magic != CP_PRIV_MAGIC)
644                 return -EINVAL;
645
646         if (hai->hai_action == HSMA_ARCHIVE)
647                 return ct_open_by_fid(hcp->ct_priv, &hai->hai_dfid,
648                                 O_RDONLY | O_NOATIME | O_NOFOLLOW | O_NONBLOCK);
649         else if (hai->hai_action == HSMA_RESTORE)
650                 return dup(hcp->data_fd);
651         else
652                 return -EINVAL;
653 }
654
655 /**
656  * Import an existing hsm-archived file into Lustre.
657  *
658  * Caller must access file by (returned) newfid value from now on.
659  *
660  * \param dst      path to Lustre destination (e.g. /mnt/lustre/my/file).
661  * \param archive  archive number.
662  * \param st       struct stat buffer containing file ownership, perm, etc.
663  * \param stripe_* Striping options.  Currently ignored, since the restore
664  *                 operation will set the striping.  In V2, this striping might
665  *                 be used.
666  * \param newfid[out] Filled with new Lustre fid.
667  */
668 int llapi_hsm_import(const char *dst, int archive, const struct stat *st,
669                      unsigned long long stripe_size, int stripe_offset,
670                      int stripe_count, int stripe_pattern, char *pool_name,
671                      lustre_fid *newfid)
672 {
673         struct hsm_user_import   hui;
674         int                      fd;
675         int                      rc = 0;
676
677         if (stripe_pattern == 0)
678                 stripe_pattern = LOV_PATTERN_RAID0;
679
680         /* Create a non-striped file */
681         fd = llapi_file_open_pool(dst, O_CREAT | O_WRONLY, st->st_mode,
682                                   stripe_size, stripe_offset, stripe_count,
683                                   stripe_pattern | LOV_PATTERN_F_RELEASED,
684                                   pool_name);
685         if (fd < 0) {
686                 llapi_error(LLAPI_MSG_ERROR, -errno,
687                             "cannot create '%s' for import", dst);
688                 return -errno;
689         }
690
691         /* Get the new fid in Lustre. Caller needs to use this fid
692            from now on. */
693         rc = llapi_fd2fid(fd, newfid);
694         if (rc != 0) {
695                 llapi_error(LLAPI_MSG_ERROR, rc,
696                             "cannot get fid of '%s' for import", dst);
697                 goto out_unlink;
698         }
699
700         hui.hui_uid = st->st_uid;
701         hui.hui_gid = st->st_gid;
702         hui.hui_mode = st->st_mode;
703         hui.hui_size = st->st_size;
704         hui.hui_archive_id = archive;
705         hui.hui_atime = st->st_atime;
706         hui.hui_atime_ns = st->st_atim.tv_nsec;
707         hui.hui_mtime = st->st_mtime;
708         hui.hui_mtime_ns = st->st_mtim.tv_nsec;
709         rc = ioctl(fd, LL_IOC_HSM_IMPORT, &hui);
710         if (rc != 0) {
711                 llapi_error(LLAPI_MSG_ERROR, rc, "cannot import '%s'", dst);
712                 rc = -errno;
713                 goto out_unlink;
714         }
715
716 out_unlink:
717         if (fd >= 0)
718                 close(fd);
719         if (rc)
720                 unlink(dst);
721         return rc;
722 }
723
724 /**
725  * Return the current HSM states and HSM requests related to file pointed by \a
726  * path.
727  *
728  * \param hus  Should be allocated by caller. Will be filled with current file
729  *             states.
730  *
731  * \retval 0 on success.
732  * \retval -errno on error.
733  */
734 int llapi_hsm_state_get_fd(int fd, struct hsm_user_state *hus)
735 {
736         int rc;
737
738         rc = ioctl(fd, LL_IOC_HSM_STATE_GET, hus);
739         /* If error, save errno value */
740         rc = rc ? -errno : 0;
741
742         return rc;
743 }
744
745 /**
746  * Return the current HSM states and HSM requests related to file pointed by \a
747  * path.
748  *
749  * see llapi_hsm_state_get_fd() for args use and return
750  */
751 int llapi_hsm_state_get(const char *path, struct hsm_user_state *hus)
752 {
753         int fd;
754         int rc;
755
756         fd = open(path, O_RDONLY | O_NONBLOCK);
757         if (fd < 0)
758                 return -errno;
759
760         rc = llapi_hsm_state_get_fd(fd, hus);
761
762         close(fd);
763         return rc;
764 }
765
766 /**
767  * Set HSM states of file pointed by \a fd
768  *
769  * Using the provided bitmasks, the current HSM states for this file will be
770  * changed. \a archive_id could be used to change the archive number also. Set
771  * it to 0 if you do not want to change it.
772  *
773  * \param setmask      Bitmask for flag to be set.
774  * \param clearmask    Bitmask for flag to be cleared.
775  * \param archive_id  Archive number identifier to use. 0 means no change.
776  *
777  * \retval 0 on success.
778  * \retval -errno on error.
779  */
780 int llapi_hsm_state_set_fd(int fd, __u64 setmask, __u64 clearmask,
781                            __u32 archive_id)
782 {
783         struct hsm_state_set     hss;
784         int                      rc;
785
786         hss.hss_valid = HSS_SETMASK|HSS_CLEARMASK;
787         hss.hss_setmask = setmask;
788         hss.hss_clearmask = clearmask;
789         /* Change archive_id if provided. We can only change
790          * to set something different than 0. */
791         if (archive_id > 0) {
792                 hss.hss_valid |= HSS_ARCHIVE_ID;
793                 hss.hss_archive_id = archive_id;
794         }
795         rc = ioctl(fd, LL_IOC_HSM_STATE_SET, &hss);
796         /* If error, save errno value */
797         rc = rc ? -errno : 0;
798
799         return rc;
800 }
801
802 /**
803  * Set HSM states of file pointed by \a path.
804  *
805  * see llapi_hsm_state_set_fd() for args use and return
806  */
807 int llapi_hsm_state_set(const char *path, __u64 setmask, __u64 clearmask,
808                         __u32 archive_id)
809 {
810         int fd;
811         int rc;
812
813         fd = open(path, O_WRONLY | O_LOV_DELAY_CREATE | O_NONBLOCK);
814         if (fd < 0)
815                 return -errno;
816
817         rc = llapi_hsm_state_set_fd(fd, setmask, clearmask, archive_id);
818
819         close(fd);
820         return rc;
821 }
822
823 /**
824  * Return the current HSM request related to file pointed by \a path.
825  *
826  * \param hca  Should be allocated by caller. Will be filled with current file
827  *             actions.
828  *
829  * \retval 0 on success.
830  * \retval -errno on error.
831  */
832 int llapi_hsm_current_action(const char *path, struct hsm_current_action *hca)
833 {
834         int fd;
835         int rc;
836
837         fd = open(path, O_RDONLY | O_NONBLOCK);
838         if (fd < 0)
839                 return -errno;
840
841         rc = ioctl(fd, LL_IOC_HSM_ACTION, hca);
842         /* If error, save errno value */
843         rc = rc ? -errno : 0;
844
845         close(fd);
846         return rc;
847 }
848
849 /**
850  * Allocate a hsm_user_request with the specified carateristics.
851  * This structure should be freed with free().
852  *
853  * \return an allocated structure on success, NULL otherwise.
854  */
855 struct hsm_user_request *llapi_hsm_user_request_alloc(int itemcount,
856                                                       int data_len)
857 {
858         int len = 0;
859
860         len += sizeof(struct hsm_user_request);
861         len += sizeof(struct hsm_user_item) * itemcount;
862         len += data_len;
863
864         return (struct hsm_user_request *)malloc(len);
865 }
866
867 /**
868  * Send a HSM request to Lustre, described in \param request.
869  *
870  * \param path    Fullpath to the file to operate on.
871  * \param request The request, allocated with llapi_hsm_user_request_alloc().
872  *
873  * \return 0 on success, an error code otherwise.
874  */
875 int llapi_hsm_request(const char *path, const struct hsm_user_request *request)
876 {
877         int rc;
878         int fd;
879
880         rc = get_root_path(WANT_FD, NULL, &fd, (char *)path, -1);
881         if (rc)
882                 return rc;
883
884         rc = ioctl(fd, LL_IOC_HSM_REQUEST, request);
885         /* If error, save errno value */
886         rc = rc ? -errno : 0;
887
888         close(fd);
889         return rc;
890 }
891