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