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