Whamcloud - gitweb
LU-3789 mgs: Add deprecation warning for "lctl conf_param"
[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 %zu 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 = LK_NOFD;
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  * \param mdt_index  MDT index where to create the volatile file.
345  * \param flags      Volatile file creation flags.
346  * \return 0 on success.
347  */
348 static int create_restore_volatile(struct hsm_copyaction_private *hcp,
349                                    int mdt_index, int flags)
350 {
351         int                      rc;
352         int                      fd;
353         char                     parent[PATH_MAX + 1];
354         const char              *mnt = hcp->ct_priv->mnt;
355         struct hsm_action_item  *hai = &hcp->copy.hc_hai;
356
357         rc = fid_parent(mnt, &hai->hai_fid, parent, sizeof(parent));
358         if (rc < 0) {
359                 /* fid_parent() failed, try to keep on going */
360                 llapi_error(LLAPI_MSG_ERROR, rc,
361                             "cannot get parent path to restore "DFID
362                             "using '%s'", PFID(&hai->hai_fid), mnt);
363                 snprintf(parent, sizeof(parent), "%s", mnt);
364         }
365
366         fd = llapi_create_volatile_idx(parent, mdt_index, flags);
367         if (fd < 0)
368                 return fd;
369
370         rc = llapi_fd2fid(fd, &hai->hai_dfid);
371         if (rc < 0)
372                 goto err_cleanup;
373
374         hcp->data_fd = fd;
375
376         return 0;
377
378 err_cleanup:
379         hcp->data_fd = -1;
380         close(fd);
381
382         return rc;
383 }
384
385 /** Start processing an HSM action.
386  * Should be called by copytools just before starting handling a request.
387  * It could be skipped if copytool only want to directly report an error,
388  * \see llapi_hsm_action_end().
389  *
390  * \param hcp                Opaque action handle to be passed to
391  *                           llapi_hsm_action_progress and llapi_hsm_action_end.
392  * \param ct                 Copytool handle acquired at registration.
393  * \param hai                The hsm_action_item describing the request.
394  * \param restore_mdt_index  On restore: MDT index where to create the volatile
395  *                           file. Use -1 for default.
396  * \param restore_open_flags On restore: volatile file creation mode. Use
397  *                           O_LOV_DELAY_CREATE to manually set the LOVEA
398  *                           afterwards.
399  * \param is_error           Whether this call is just to report an error.
400  *
401  * \return 0 on success.
402  */
403 int llapi_hsm_action_begin(struct hsm_copyaction_private **phcp,
404                            const struct hsm_copytool_private *ct,
405                            const struct hsm_action_item *hai,
406                            int restore_mdt_index, int restore_open_flags,
407                            bool is_error)
408 {
409         struct hsm_copyaction_private   *hcp;
410         int                              rc;
411
412         hcp = calloc(1, sizeof(*hcp));
413         if (hcp == NULL)
414                 return -ENOMEM;
415
416         hcp->data_fd = -1;
417         hcp->ct_priv = ct;
418         hcp->copy.hc_hai = *hai;
419         hcp->copy.hc_hai.hai_len = sizeof(*hai);
420
421         if (is_error)
422                 goto ok_out;
423
424         if (hai->hai_action == HSMA_RESTORE) {
425                 rc = create_restore_volatile(hcp, restore_mdt_index,
426                                              restore_open_flags);
427                 if (rc < 0)
428                         goto err_out;
429         }
430
431         rc = ioctl(ct->mnt_fd, LL_IOC_HSM_COPY_START, &hcp->copy);
432         if (rc < 0) {
433                 rc = -errno;
434                 goto err_out;
435         }
436
437 ok_out:
438         hcp->magic = CP_PRIV_MAGIC;
439         *phcp = hcp;
440         return 0;
441
442 err_out:
443         if (!(hcp->data_fd < 0))
444                 close(hcp->data_fd);
445
446         free(hcp);
447
448         return rc;
449 }
450
451 /** Terminate an HSM action processing.
452  * Should be called by copytools just having finished handling the request.
453  * \param hdl[in,out]  Handle returned by llapi_hsm_action_start.
454  * \param he[in]       The final range of copied data (for copy actions).
455  * \param errval[in]   The status code of the operation.
456  * \param flags[in]    The flags about the termination status (HP_FLAG_RETRY if
457  *                     the error is retryable).
458  *
459  * \return 0 on success.
460  */
461 int llapi_hsm_action_end(struct hsm_copyaction_private **phcp,
462                          const struct hsm_extent *he, int flags, int errval)
463 {
464         struct hsm_copyaction_private   *hcp;
465         struct hsm_action_item          *hai;
466         int                              rc;
467
468         if (phcp == NULL || *phcp == NULL || he == NULL)
469                 return -EINVAL;
470
471         hcp = *phcp;
472
473         if (hcp->magic != CP_PRIV_MAGIC)
474                 return -EINVAL;
475
476         hai = &hcp->copy.hc_hai;
477
478         /* In some cases, like restore, 2 FIDs are used.
479          * Set the right FID to use here. */
480         if (hai->hai_action == HSMA_ARCHIVE || hai->hai_action == HSMA_RESTORE)
481                 hai->hai_fid = hai->hai_dfid;
482
483         /* Fill the last missing data that will be needed by
484          * kernel to send a hsm_progress. */
485         hcp->copy.hc_flags  = flags;
486         hcp->copy.hc_errval = abs(errval);
487
488         hcp->copy.hc_hai.hai_extent = *he;
489
490         rc = ioctl(hcp->ct_priv->mnt_fd, LL_IOC_HSM_COPY_END, &hcp->copy);
491         if (rc) {
492                 rc = -errno;
493                 goto err_cleanup;
494         }
495
496 err_cleanup:
497         if (!(hcp->data_fd < 0))
498                 close(hcp->data_fd);
499
500         free(hcp);
501         *phcp = NULL;
502
503         return rc;
504 }
505
506 /** Notify a progress in processing an HSM action.
507  * \param hdl[in,out]   handle returned by llapi_hsm_action_start.
508  * \param he[in]        the range of copied data (for copy actions).
509  * \param hp_flags[in]  HSM progress flags.
510  * \return 0 on success.
511  */
512 int llapi_hsm_action_progress(struct hsm_copyaction_private *hcp,
513                               const struct hsm_extent *he, int hp_flags)
514 {
515         int                      rc;
516         struct hsm_progress      hp;
517         struct hsm_action_item  *hai;
518
519         if (hcp == NULL || he == NULL)
520                 return -EINVAL;
521
522         if (hcp->magic != CP_PRIV_MAGIC)
523                 return -EINVAL;
524
525         hai = &hcp->copy.hc_hai;
526
527         memset(&hp, 0, sizeof(hp));
528
529         hp.hp_cookie = hai->hai_cookie;
530         hp.hp_flags  = hp_flags;
531
532         /* Progress is made on the data fid */
533         hp.hp_fid = hai->hai_dfid;
534         hp.hp_extent = *he;
535
536         rc = ioctl(hcp->ct_priv->mnt_fd, LL_IOC_HSM_PROGRESS, &hp);
537         if (rc < 0)
538                 rc = -errno;
539
540         return rc;
541 }
542
543 /** Get the fid of object to be used for copying data.
544  * @return error code if the action is not a copy operation.
545  */
546 int llapi_hsm_action_get_dfid(const struct hsm_copyaction_private *hcp,
547                               lustre_fid *fid)
548 {
549         const struct hsm_action_item    *hai = &hcp->copy.hc_hai;
550
551         if (hcp->magic != CP_PRIV_MAGIC)
552                 return -EINVAL;
553
554         if (hai->hai_action != HSMA_RESTORE && hai->hai_action != HSMA_ARCHIVE)
555                 return -EINVAL;
556
557         *fid = hai->hai_dfid;
558
559         return 0;
560 }
561
562 /**
563  * Get a file descriptor to be used for copying data. It's up to the
564  * caller to close the FDs obtained from this function.
565  *
566  * @retval a file descriptor on success.
567  * @retval a negative error code on failure.
568  */
569 int llapi_hsm_action_get_fd(const struct hsm_copyaction_private *hcp)
570 {
571         const struct hsm_action_item    *hai = &hcp->copy.hc_hai;
572
573         if (hcp->magic != CP_PRIV_MAGIC)
574                 return -EINVAL;
575
576         if (hai->hai_action != HSMA_RESTORE)
577                 return -EINVAL;
578
579         return dup(hcp->data_fd);
580 }
581
582 /**
583  * Import an existing hsm-archived file into Lustre.
584  *
585  * Caller must access file by (returned) newfid value from now on.
586  *
587  * \param dst      path to Lustre destination (e.g. /mnt/lustre/my/file).
588  * \param archive  archive number.
589  * \param st       struct stat buffer containing file ownership, perm, etc.
590  * \param stripe_* Striping options.  Currently ignored, since the restore
591  *                 operation will set the striping.  In V2, this striping might
592  *                 be used.
593  * \param newfid[out] Filled with new Lustre fid.
594  */
595 int llapi_hsm_import(const char *dst, int archive, const struct stat *st,
596                      unsigned long long stripe_size, int stripe_offset,
597                      int stripe_count, int stripe_pattern, char *pool_name,
598                      lustre_fid *newfid)
599 {
600         struct hsm_user_import   hui;
601         int                      fd;
602         int                      rc = 0;
603
604         if (stripe_pattern == 0)
605                 stripe_pattern = LOV_PATTERN_RAID0;
606
607         /* Create a non-striped file */
608         fd = llapi_file_open_pool(dst, O_CREAT | O_WRONLY, st->st_mode,
609                                   stripe_size, stripe_offset, stripe_count,
610                                   stripe_pattern | LOV_PATTERN_F_RELEASED,
611                                   pool_name);
612         if (fd < 0) {
613                 llapi_error(LLAPI_MSG_ERROR, -errno,
614                             "cannot create '%s' for import", dst);
615                 return -errno;
616         }
617
618         /* Get the new fid in Lustre. Caller needs to use this fid
619            from now on. */
620         rc = llapi_fd2fid(fd, newfid);
621         if (rc != 0) {
622                 llapi_error(LLAPI_MSG_ERROR, rc,
623                             "cannot get fid of '%s' for import", dst);
624                 goto out_unlink;
625         }
626
627         hui.hui_uid = st->st_uid;
628         hui.hui_gid = st->st_gid;
629         hui.hui_mode = st->st_mode;
630         hui.hui_size = st->st_size;
631         hui.hui_archive_id = archive;
632         hui.hui_atime = st->st_atime;
633         hui.hui_atime_ns = st->st_atim.tv_nsec;
634         hui.hui_mtime = st->st_mtime;
635         hui.hui_mtime_ns = st->st_mtim.tv_nsec;
636         rc = ioctl(fd, LL_IOC_HSM_IMPORT, &hui);
637         if (rc != 0) {
638                 llapi_error(LLAPI_MSG_ERROR, rc, "cannot import '%s'", dst);
639                 rc = -errno;
640                 goto out_unlink;
641         }
642
643 out_unlink:
644         if (fd >= 0)
645                 close(fd);
646         if (rc)
647                 unlink(dst);
648         return rc;
649 }
650
651 /**
652  * Return the current HSM states and HSM requests related to file pointed by \a
653  * path.
654  *
655  * \param hus  Should be allocated by caller. Will be filled with current file
656  *             states.
657  *
658  * \retval 0 on success.
659  * \retval -errno on error.
660  */
661 int llapi_hsm_state_get_fd(int fd, struct hsm_user_state *hus)
662 {
663         int rc;
664
665         rc = ioctl(fd, LL_IOC_HSM_STATE_GET, hus);
666         /* If error, save errno value */
667         rc = rc ? -errno : 0;
668
669         return rc;
670 }
671
672 /**
673  * Return the current HSM states and HSM requests related to file pointed by \a
674  * path.
675  *
676  * see llapi_hsm_state_get_fd() for args use and return
677  */
678 int llapi_hsm_state_get(const char *path, struct hsm_user_state *hus)
679 {
680         int fd;
681         int rc;
682
683         fd = open(path, O_RDONLY | O_NONBLOCK);
684         if (fd < 0)
685                 return -errno;
686
687         rc = llapi_hsm_state_get_fd(fd, hus);
688
689         close(fd);
690         return rc;
691 }
692
693 /**
694  * Set HSM states of file pointed by \a fd
695  *
696  * Using the provided bitmasks, the current HSM states for this file will be
697  * changed. \a archive_id could be used to change the archive number also. Set
698  * it to 0 if you do not want to change it.
699  *
700  * \param setmask      Bitmask for flag to be set.
701  * \param clearmask    Bitmask for flag to be cleared.
702  * \param archive_id  Archive number identifier to use. 0 means no change.
703  *
704  * \retval 0 on success.
705  * \retval -errno on error.
706  */
707 int llapi_hsm_state_set_fd(int fd, __u64 setmask, __u64 clearmask,
708                            __u32 archive_id)
709 {
710         struct hsm_state_set     hss;
711         int                      rc;
712
713         hss.hss_valid = HSS_SETMASK|HSS_CLEARMASK;
714         hss.hss_setmask = setmask;
715         hss.hss_clearmask = clearmask;
716         /* Change archive_id if provided. We can only change
717          * to set something different than 0. */
718         if (archive_id > 0) {
719                 hss.hss_valid |= HSS_ARCHIVE_ID;
720                 hss.hss_archive_id = archive_id;
721         }
722         rc = ioctl(fd, LL_IOC_HSM_STATE_SET, &hss);
723         /* If error, save errno value */
724         rc = rc ? -errno : 0;
725
726         return rc;
727 }
728
729 /**
730  * Set HSM states of file pointed by \a path.
731  *
732  * see llapi_hsm_state_set_fd() for args use and return
733  */
734 int llapi_hsm_state_set(const char *path, __u64 setmask, __u64 clearmask,
735                         __u32 archive_id)
736 {
737         int fd;
738         int rc;
739
740         fd = open(path, O_WRONLY | O_LOV_DELAY_CREATE | O_NONBLOCK);
741         if (fd < 0)
742                 return -errno;
743
744         rc = llapi_hsm_state_set_fd(fd, setmask, clearmask, archive_id);
745
746         close(fd);
747         return rc;
748 }
749
750 /**
751  * Return the current HSM request related to file pointed by \a path.
752  *
753  * \param hca  Should be allocated by caller. Will be filled with current file
754  *             actions.
755  *
756  * \retval 0 on success.
757  * \retval -errno on error.
758  */
759 int llapi_hsm_current_action(const char *path, struct hsm_current_action *hca)
760 {
761         int fd;
762         int rc;
763
764         fd = open(path, O_RDONLY | O_NONBLOCK);
765         if (fd < 0)
766                 return -errno;
767
768         rc = ioctl(fd, LL_IOC_HSM_ACTION, hca);
769         /* If error, save errno value */
770         rc = rc ? -errno : 0;
771
772         close(fd);
773         return rc;
774 }
775
776 /**
777  * Allocate a hsm_user_request with the specified carateristics.
778  * This structure should be freed with free().
779  *
780  * \return an allocated structure on success, NULL otherwise.
781  */
782 struct hsm_user_request *llapi_hsm_user_request_alloc(int itemcount,
783                                                       int data_len)
784 {
785         int len = 0;
786
787         len += sizeof(struct hsm_user_request);
788         len += sizeof(struct hsm_user_item) * itemcount;
789         len += data_len;
790
791         return (struct hsm_user_request *)malloc(len);
792 }
793
794 /**
795  * Send a HSM request to Lustre, described in \param request.
796  *
797  * \param path    Fullpath to the file to operate on.
798  * \param request The request, allocated with llapi_hsm_user_request_alloc().
799  *
800  * \return 0 on success, an error code otherwise.
801  */
802 int llapi_hsm_request(const char *path, const struct hsm_user_request *request)
803 {
804         int rc;
805         int fd;
806
807         rc = get_root_path(WANT_FD, NULL, &fd, (char *)path, -1);
808         if (rc)
809                 return rc;
810
811         rc = ioctl(fd, LL_IOC_HSM_REQUEST, request);
812         /* If error, save errno value */
813         rc = rc ? -errno : 0;
814
815         close(fd);
816         return rc;
817 }
818