Whamcloud - gitweb
e21b4b7889a87a8d981714d217f184bd40b5869b
[fs/lustre-release.git] / lustre / tests / llapi_hsm_test.c
1 /*
2  * GPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 only,
8  * as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License version 2 for more details (a copy is included
14  * in the LICENSE file that accompanied this code).
15  *
16  * You should have received a copy of the GNU General Public License
17  * version 2 along with this program; If not, see
18  * http://www.gnu.org/licenses/gpl-2.0.html
19  *
20  * GPL HEADER END
21  */
22
23 /* Copyright 2014 Cray Inc, all rights reserved. */
24 /* Some portions are extracted from llapi_layout_test.c */
25
26 /* The purpose of this test is to check some HSM functions. HSM must
27  * be enabled before running it:
28  *   echo enabled > /proc/fs/lustre/mdt/lustre-MDT0000/hsm_control
29  */
30
31 /* All tests return 0 on success and non zero on error. The program will
32  * exit as soon a non zero error is returned. */
33
34 #include <stdlib.h>
35 #include <errno.h>
36 #include <getopt.h>
37 #include <fcntl.h>
38 #include <unistd.h>
39 #include <poll.h>
40 #include <time.h>
41
42 #include <lustre/lustreapi.h>
43
44 static char fsmountdir[PATH_MAX];      /* Lustre mountpoint */
45 static char *lustre_dir;               /* Test directory inside Lustre */
46
47 #define ERROR(fmt, ...)                                                 \
48         fprintf(stderr, "%s: %s:%d: %s: " fmt "\n",                     \
49                 program_invocation_short_name, __FILE__, __LINE__,      \
50                 __func__, ## __VA_ARGS__);
51
52 #define DIE(fmt, ...)                           \
53         do {                                    \
54                 ERROR(fmt, ## __VA_ARGS__);     \
55                 exit(EXIT_FAILURE);             \
56         } while (0)
57
58 #define ASSERTF(cond, fmt, ...)                                         \
59         do {                                                            \
60                 if (!(cond))                                            \
61                         DIE("assertion '%s' failed: "fmt,               \
62                             #cond, ## __VA_ARGS__);                     \
63         } while (0)                                                     \
64
65 #define PERFORM(testfn) \
66         do {                                                            \
67                 fprintf(stderr, "Starting test " #testfn " at %llu\n",  \
68                         (unsigned long long)time(NULL));                \
69                 testfn();                                               \
70                 fprintf(stderr, "Finishing test " #testfn " at %llu\n", \
71                        (unsigned long long)time(NULL));                 \
72         } while (0)
73
74 /* Register and unregister 2000 times. Ensures there is no fd leak
75  * since there is usually 1024 fd per process. */
76 int test1(void)
77 {
78         int i;
79         int rc;
80         struct hsm_copytool_private *ctdata;
81
82         for (i = 0; i < 2000; i++) {
83                 rc = llapi_hsm_copytool_register(&ctdata, fsmountdir,
84                                                  0, NULL, 0);
85                 ASSERTF(rc == 0,
86                         "llapi_hsm_copytool_register failed: %s, loop=%d",
87                         strerror(-rc), i);
88
89                 rc = llapi_hsm_copytool_unregister(&ctdata);
90                 ASSERTF(rc == 0,
91                         "llapi_hsm_copytool_unregister failed: %s, loop=%d",
92                         strerror(-rc), i);
93         }
94
95         return 0;
96 }
97
98 /* Re-register */
99 int test2(void)
100 {
101         int rc;
102         struct hsm_copytool_private *ctdata1;
103         struct hsm_copytool_private *ctdata2;
104
105         rc = llapi_hsm_copytool_register(&ctdata1, fsmountdir, 0, NULL, 0);
106         ASSERTF(rc == 0, "llapi_hsm_copytool_register failed: %s",
107                 strerror(-rc));
108
109         rc = llapi_hsm_copytool_register(&ctdata2, fsmountdir, 0, NULL, 0);
110         ASSERTF(rc == 0, "llapi_hsm_copytool_register failed: %s",
111                 strerror(-rc));
112
113         rc = llapi_hsm_copytool_unregister(&ctdata2);
114         ASSERTF(rc == 0, "llapi_hsm_copytool_unregister failed: %s",
115                 strerror(-rc));
116
117         rc = llapi_hsm_copytool_unregister(&ctdata1);
118         ASSERTF(rc == 0, "llapi_hsm_copytool_unregister failed: %s",
119                 strerror(-rc));
120
121         return 0;
122 }
123
124 /* Bad parameters to llapi_hsm_copytool_register(). */
125 int test3(void)
126 {
127         int rc;
128         struct hsm_copytool_private *ctdata;
129         int archives[33];
130
131         rc = llapi_hsm_copytool_register(&ctdata, fsmountdir, 1, NULL, 0);
132         ASSERTF(rc == -EINVAL, "llapi_hsm_copytool_register error: %s",
133                 strerror(-rc));
134
135         rc = llapi_hsm_copytool_register(&ctdata, fsmountdir, 33, NULL, 0);
136         ASSERTF(rc == -EINVAL, "llapi_hsm_copytool_register error: %s",
137                 strerror(-rc));
138
139         memset(archives, 1, sizeof(archives));
140         rc = llapi_hsm_copytool_register(&ctdata, fsmountdir, 34, archives, 0);
141         ASSERTF(rc == -EINVAL, "llapi_hsm_copytool_register error: %s",
142                 strerror(-rc));
143
144 #if 0
145         /* BUG? Should that fail or not? */
146         rc = llapi_hsm_copytool_register(&ctdata, fsmountdir, -1, NULL, 0);
147         ASSERTF(rc == -EINVAL, "llapi_hsm_copytool_register error: %s",
148                 strerror(-rc));
149 #endif
150
151         memset(archives, -1, sizeof(archives));
152         rc = llapi_hsm_copytool_register(&ctdata, fsmountdir, 1, archives, 0);
153         ASSERTF(rc == -EINVAL, "llapi_hsm_copytool_register error: %s",
154                 strerror(-rc));
155
156         rc = llapi_hsm_copytool_register(&ctdata, "/tmp", 0, NULL, 0);
157         ASSERTF(rc == -ENOENT, "llapi_hsm_copytool_register error: %s",
158                 strerror(-rc));
159
160         return 0;
161 }
162
163 /* Bad parameters to llapi_hsm_copytool_unregister(). */
164 int test4(void)
165 {
166         int rc;
167
168         rc = llapi_hsm_copytool_unregister(NULL);
169         ASSERTF(rc == -EINVAL, "llapi_hsm_copytool_unregister error: %s",
170                 strerror(-rc));
171
172         return 0;
173 }
174
175 /* Test llapi_hsm_copytool_recv in non blocking mode */
176 int test5(void)
177 {
178         int rc;
179         int i;
180         struct hsm_copytool_private *ctdata;
181         struct hsm_action_list  *hal;
182         int msgsize;
183
184         rc = llapi_hsm_copytool_register(&ctdata, fsmountdir,
185                                          0, NULL, O_NONBLOCK);
186         ASSERTF(rc == 0, "llapi_hsm_copytool_unregister failed: %s",
187                 strerror(-rc));
188
189         /* Hopefully there is nothing lingering */
190         for (i = 0; i < 1000; i++) {
191                 rc = llapi_hsm_copytool_recv(ctdata, &hal, &msgsize);
192                 ASSERTF(rc == -EWOULDBLOCK, "llapi_hsm_copytool_recv error: %s",
193                         strerror(-rc));
194         }
195
196         rc = llapi_hsm_copytool_unregister(&ctdata);
197         ASSERTF(rc == 0, "llapi_hsm_copytool_unregister failed: %s",
198                 strerror(-rc));
199
200         return 0;
201 }
202
203 /* Test llapi_hsm_copytool_recv with bogus parameters */
204 int test6(void)
205 {
206         struct hsm_copytool_private *ctdata;
207         struct hsm_action_list *hal;
208         int rc;
209         int msgsize;
210
211         rc = llapi_hsm_copytool_register(&ctdata, fsmountdir, 0, NULL, 0);
212         ASSERTF(rc == 0, "llapi_hsm_copytool_unregister failed: %s",
213                 strerror(-rc));
214
215         rc = llapi_hsm_copytool_recv(NULL, &hal, &msgsize);
216         ASSERTF(rc == -EINVAL, "llapi_hsm_copytool_recv error: %s",
217                 strerror(-rc));
218
219         rc = llapi_hsm_copytool_recv(ctdata, NULL, &msgsize);
220         ASSERTF(rc == -EINVAL, "llapi_hsm_copytool_recv error: %s",
221                 strerror(-rc));
222
223         rc = llapi_hsm_copytool_recv(ctdata, &hal, NULL);
224         ASSERTF(rc == -EINVAL, "llapi_hsm_copytool_recv error: %s",
225                 strerror(-rc));
226
227         rc = llapi_hsm_copytool_recv(ctdata, NULL, NULL);
228         ASSERTF(rc == -EINVAL, "llapi_hsm_copytool_recv error: %s",
229                 strerror(-rc));
230
231         rc = llapi_hsm_copytool_unregister(&ctdata);
232         ASSERTF(rc == 0, "llapi_hsm_copytool_unregister failed: %s",
233                 strerror(-rc));
234
235         return 0;
236 }
237
238 /* Test polling (without actual traffic) */
239 int test7(void)
240 {
241         int rc;
242         struct hsm_copytool_private *ctdata;
243         struct hsm_action_list  *hal;
244         int msgsize;
245         int fd;
246         struct pollfd fds[1];
247
248         rc = llapi_hsm_copytool_register(&ctdata, fsmountdir,
249                                          0, NULL, O_NONBLOCK);
250         ASSERTF(rc == 0, "llapi_hsm_copytool_register failed: %s",
251                 strerror(-rc));
252
253         fd = llapi_hsm_copytool_get_fd(ctdata);
254         ASSERTF(fd >= 0, "llapi_hsm_copytool_get_fd failed: %s",
255                 strerror(-rc));
256
257         /* Ensure it's read-only */
258         rc = write(fd, &rc, 1);
259         ASSERTF(rc == -1 && errno == EBADF, "write error: %d, %s",
260                 rc, strerror(errno));
261
262         rc = llapi_hsm_copytool_recv(ctdata, &hal, &msgsize);
263         ASSERTF(rc == -EWOULDBLOCK, "llapi_hsm_copytool_recv error: %s",
264                 strerror(-rc));
265
266         fds[0].fd = fd;
267         fds[0].events = POLLIN;
268         rc = poll(fds, 1, 10);
269         ASSERTF(rc == 0, "poll failed: %d, %s",
270                 rc, strerror(errno)); /* no event */
271
272         rc = llapi_hsm_copytool_unregister(&ctdata);
273         ASSERTF(rc == 0, "llapi_hsm_copytool_unregister failed: %s",
274                 strerror(-rc));
275
276         return 0;
277 }
278
279 /* Create the testfile of a given length. It returns a valid file
280  * descriptor. */
281 static char testfile[PATH_MAX];
282 static int create_testfile(size_t length)
283 {
284         int rc;
285         int fd;
286
287         rc = snprintf(testfile, sizeof(testfile), "%s/hsm_check_test",
288                       lustre_dir);
289         ASSERTF((rc > 0 && rc < sizeof(testfile)), "invalid name for testfile");
290
291         /* Remove old test file, if any. */
292         unlink(testfile);
293
294         /* Use truncate so we can create a file (almost) as big as we
295          * want, while taking 0 bytes of data. */
296         fd = creat(testfile, S_IRWXU);
297         ASSERTF(fd >= 0, "create failed for '%s': %s",
298                 testfile, strerror(errno));
299
300         rc = ftruncate(fd, length);
301         ASSERTF(rc == 0, "ftruncate failed for '%s': %s",
302                 testfile, strerror(errno));
303
304         return fd;
305 }
306
307 /* Test llapi_hsm_state_get. */
308 void test50(void)
309 {
310         struct hsm_user_state hus;
311         int rc;
312         int fd;
313
314         fd = create_testfile(100);
315
316         /* With fd variant */
317         rc = llapi_hsm_state_get_fd(fd, &hus);
318         ASSERTF(rc == 0, "llapi_hsm_state_get_fd failed: %s", strerror(-rc));
319         ASSERTF(hus.hus_states == 0, "state=%u", hus.hus_states);
320
321         rc = llapi_hsm_state_get_fd(fd, NULL);
322         ASSERTF(rc == -EFAULT, "llapi_hsm_state_get_fd error: %s",
323                 strerror(-rc));
324
325         rc = close(fd);
326         ASSERTF(rc == 0, "close failed: %s", strerror(errno));
327
328         /* Without fd */
329         rc = llapi_hsm_state_get(testfile, &hus);
330         ASSERTF(rc == 0, "llapi_hsm_state_get failed: %s", strerror(-rc));
331         ASSERTF(hus.hus_states == 0, "state=%u", hus.hus_states);
332
333         rc = llapi_hsm_state_get(testfile, NULL);
334         ASSERTF(rc == -EFAULT, "llapi_hsm_state_get error: %s",
335                 strerror(-rc));
336
337         memset(&hus, 0xaa, sizeof(hus));
338         rc = llapi_hsm_state_get(testfile, &hus);
339         ASSERTF(rc == 0, "llapi_hsm_state_get failed: %s", strerror(-rc));
340         ASSERTF(hus.hus_states == 0, "state=%u", hus.hus_states);
341         ASSERTF(hus.hus_archive_id == 0, "archive_id=%u", hus.hus_archive_id);
342         ASSERTF(hus.hus_in_progress_state == 0, "hus_in_progress_state=%u",
343                 hus.hus_in_progress_state);
344         ASSERTF(hus.hus_in_progress_action == 0, "hus_in_progress_action=%u",
345                 hus.hus_in_progress_action);
346 }
347
348 /* Test llapi_hsm_state_set. */
349 void test51(void)
350 {
351         int rc;
352         int fd;
353         int i;
354         struct hsm_user_state hus;
355
356         fd = create_testfile(100);
357
358         rc = llapi_hsm_state_set_fd(fd, 0, 0, 0);
359         ASSERTF(rc == 0, "llapi_hsm_state_set_fd failed: %s", strerror(-rc));
360
361         /* Set archive id */
362         for (i = 0; i <= 32; i++) {
363                 rc = llapi_hsm_state_set_fd(fd, HS_EXISTS, 0, i);
364                 ASSERTF(rc == 0, "llapi_hsm_state_set_fd failed: %s",
365                         strerror(-rc));
366
367                 rc = llapi_hsm_state_get_fd(fd, &hus);
368                 ASSERTF(rc == 0, "llapi_hsm_state_set_fd failed: %s",
369                         strerror(-rc));
370                 ASSERTF(hus.hus_states == HS_EXISTS, "state=%u",
371                         hus.hus_states);
372                 ASSERTF(hus.hus_archive_id == i, "archive_id=%u, i=%d",
373                         hus.hus_archive_id, i);
374         }
375
376         /* Bugs following. This should not succeed. Builds the following file:
377          *
378          *   $ ../utils/lfs hsm_state /mnt/lustre/hsm_check_test
379          *
380          *   /mnt/lustre/hsm_check_test: (0x8008007d) released exists
381          *     archived never_release never_archive lost_from_hsm,
382          *     archive_id:-1789
383          */
384
385         /* Invalid archive numbers */
386         rc = llapi_hsm_state_set_fd(fd, HS_EXISTS, 0, 33);
387         ASSERTF(rc == 0, "llapi_hsm_state_set_fd failed: %s", strerror(-rc));
388
389         rc = llapi_hsm_state_set_fd(fd, HS_EXISTS, 0, 151);
390         ASSERTF(rc == 0, "llapi_hsm_state_set_fd failed: %s", strerror(-rc));
391
392         rc = llapi_hsm_state_set_fd(fd, HS_EXISTS, 0, -1789);
393         ASSERTF(rc == 0, "llapi_hsm_state_set_fd failed: %s", strerror(-rc));
394
395         /* Setable + Unsettable flags */
396         rc = llapi_hsm_state_set_fd(fd, HS_DIRTY, 0, 0);
397         ASSERTF(rc == 0, "llapi_hsm_state_set_fd failed: %s", strerror(-rc));
398
399         rc = llapi_hsm_state_set_fd(fd, 0, HS_DIRTY, 0);
400         ASSERTF(rc == 0, "llapi_hsm_state_set_fd failed: %s", strerror(-rc));
401
402         rc = llapi_hsm_state_set_fd(fd, HS_ARCHIVED, 0, 0);
403         ASSERTF(rc == 0, "llapi_hsm_state_set_fd failed: %s", strerror(-rc));
404
405         rc = llapi_hsm_state_set_fd(fd, HS_RELEASED, 0, 0);
406         ASSERTF(rc == 0, "llapi_hsm_state_set_fd failed: %s", strerror(-rc));
407
408         rc = llapi_hsm_state_set_fd(fd, HS_NORELEASE, 0, 0);
409         ASSERTF(rc == 0, "llapi_hsm_state_set_fd failed: %s", strerror(-rc));
410
411         rc = llapi_hsm_state_set_fd(fd, HS_NOARCHIVE, 0, 0);
412         ASSERTF(rc == 0, "llapi_hsm_state_set_fd failed: %s", strerror(-rc));
413
414         rc = llapi_hsm_state_set_fd(fd, HS_LOST, 0, 0);
415         ASSERTF(rc == 0, "llapi_hsm_state_set_fd failed: %s", strerror(-rc));
416
417         /* Bogus flags for good measure. */
418         rc = llapi_hsm_state_set_fd(fd, 0x00080000, 0, 0);
419         ASSERTF(rc == 0, "llapi_hsm_state_set_fd failed: %s", strerror(-rc));
420
421         rc = llapi_hsm_state_set_fd(fd, 0x80000000, 0, 0);
422         ASSERTF(rc == 0, "llapi_hsm_state_set_fd failed: %s", strerror(-rc));
423
424         close(fd);
425 }
426
427 /* Test llapi_hsm_current_action */
428 void test52(void)
429 {
430         int rc;
431         int fd;
432         struct hsm_current_action hca;
433
434         /* No fd equivalent, so close it. */
435         fd = create_testfile(100);
436         close(fd);
437
438         rc = llapi_hsm_current_action(testfile, &hca);
439         ASSERTF(rc == 0, "llapi_hsm_current_action failed: %s", strerror(-rc));
440         ASSERTF(hca.hca_state, "hca_state=%u", hca.hca_state);
441         ASSERTF(hca.hca_action, "hca_state=%u", hca.hca_action);
442
443         rc = llapi_hsm_current_action(testfile, NULL);
444         ASSERTF(rc == -EFAULT, "llapi_hsm_current_action failed: %s",
445                 strerror(-rc));
446 }
447
448 /* Helper to simulate archiving a file. No actual data movement
449  * happens. */
450 void (*helper_progress)(struct hsm_copyaction_private *hcp);
451 void helper_archiving(const size_t length)
452 {
453         int rc;
454         int fd;
455         struct hsm_copytool_private *ctdata;
456         struct hsm_user_request *hur;
457         struct hsm_action_list  *hal;
458         struct hsm_action_item  *hai;
459         int                      msgsize;
460         struct hsm_copyaction_private *hcp;
461         struct hsm_user_state hus;
462
463         fd = create_testfile(length);
464
465         rc = llapi_hsm_copytool_register(&ctdata, fsmountdir,
466                                          0, NULL, 0);
467         ASSERTF(rc == 0, "llapi_hsm_copytool_register failed: %s",
468                 strerror(-rc));
469
470         /* Create and send the archive request. */
471         hur = llapi_hsm_user_request_alloc(1, 0);
472         ASSERTF(hur != NULL, "llapi_hsm_user_request_alloc returned NULL");
473
474         hur->hur_request.hr_action = HUA_ARCHIVE;
475         hur->hur_request.hr_archive_id = 1;
476         hur->hur_request.hr_flags = 0;
477         hur->hur_request.hr_itemcount = 1;
478         hur->hur_request.hr_data_len = 0;
479         hur->hur_user_item[0].hui_extent.length = -1;
480
481         rc = llapi_fd2fid(fd, &hur->hur_user_item[0].hui_fid);
482         ASSERTF(rc == 0, "llapi_fd2fid failed: %s", strerror(-rc));
483
484         close(fd);
485
486         rc = llapi_hsm_request(testfile, hur);
487         ASSERTF(rc == 0, "llapi_hsm_request failed: %s", strerror(-rc));
488
489         free(hur);
490
491         /* Read the request */
492         rc = llapi_hsm_copytool_recv(ctdata, &hal, &msgsize);
493         ASSERTF(rc == 0, "llapi_hsm_copytool_recv failed: %s", strerror(-rc));
494         ASSERTF(hal->hal_count == 1, "hal_count=%d", hal->hal_count);
495
496         hai = hai_first(hal);
497         ASSERTF(hai != NULL, "hai_first returned NULL");
498         ASSERTF(hai->hai_action == HSMA_ARCHIVE,
499                 "hai_action=%d", hai->hai_action);
500
501         /* "Begin" archiving */
502         hcp = NULL;
503         rc = llapi_hsm_action_begin(&hcp, ctdata, hai, -1, 0, false);
504         ASSERTF(rc == 0, "llapi_hsm_action_begin failed: %s", strerror(-rc));
505         ASSERTF(hcp != NULL, "hcp is NULL");
506
507         if (helper_progress)
508                 helper_progress(hcp);
509
510         /* Done archiving */
511         rc = llapi_hsm_action_end(&hcp, &hai->hai_extent, 0, 0);
512         ASSERTF(rc == 0, "llapi_hsm_action_end failed: %s", strerror(-rc));
513         ASSERTF(hcp == NULL, "hcp is NULL");
514
515         /* Close HSM client */
516         rc = llapi_hsm_copytool_unregister(&ctdata);
517         ASSERTF(rc == 0, "llapi_hsm_copytool_unregister failed: %s",
518                 strerror(-rc));
519
520         /* Final check */
521         rc = llapi_hsm_state_get(testfile, &hus);
522         ASSERTF(rc == 0, "llapi_hsm_state_get failed: %s", strerror(-rc));
523         ASSERTF(hus.hus_states == (HS_EXISTS | HS_ARCHIVED),
524                 "state=%u", hus.hus_states);
525 }
526
527 /* Simple archive. No progress. */
528 void test100(void)
529 {
530         const size_t length = 100;
531         helper_progress = NULL;
532         helper_archiving(length);
533 }
534
535 /* Archive, with a report every byte. */
536 void test101(void)
537 {
538         const size_t length = 1000;
539
540         void test101_progress(struct hsm_copyaction_private *hcp)
541         {
542                 int i;
543                 int rc;
544                 struct hsm_extent he;
545                 struct hsm_current_action hca;
546
547                 /* Report progress. 1 byte at a time :) */
548                 for (i = 0; i < length; i++) {
549                         he.offset = i;
550                         he.length = 1;
551                         rc = llapi_hsm_action_progress(hcp, &he, length, 0);
552                         ASSERTF(rc == 0, "llapi_hsm_action_progress failed: %s",
553                                 strerror(-rc));
554                 }
555
556                 rc = llapi_hsm_current_action(testfile, &hca);
557                 ASSERTF(rc == 0, "llapi_hsm_current_action failed: %s",
558                         strerror(-rc));
559                 ASSERTF(hca.hca_state == HPS_RUNNING,
560                         "hca_state=%u", hca.hca_state);
561                 ASSERTF(hca.hca_action == HUA_ARCHIVE,
562                         "hca_state=%u", hca.hca_action);
563                 ASSERTF(hca.hca_location.length == length,
564                         "length=%llu", hca.hca_location.length);
565         }
566
567         helper_progress = test101_progress;
568         helper_archiving(length);
569 }
570
571 /* Archive, with a report every byte, backwards. */
572 void test102(void)
573 {
574         const size_t length = 1000;
575
576         void test102_progress(struct hsm_copyaction_private *hcp)
577         {
578                 int i;
579                 int rc;
580                 struct hsm_extent he;
581                 struct hsm_current_action hca;
582
583                 /* Report progress. 1 byte at a time :) */
584                 for (i = length-1; i >= 0; i--) {
585                         he.offset = i;
586                         he.length = 1;
587                         rc = llapi_hsm_action_progress(hcp, &he, length, 0);
588                         ASSERTF(rc == 0, "llapi_hsm_action_progress failed: %s",
589                                 strerror(-rc));
590                 }
591
592                 rc = llapi_hsm_current_action(testfile, &hca);
593                 ASSERTF(rc == 0, "llapi_hsm_current_action failed: %s",
594                         strerror(-rc));
595                 ASSERTF(hca.hca_state == HPS_RUNNING,
596                         "hca_state=%u", hca.hca_state);
597                 ASSERTF(hca.hca_action == HUA_ARCHIVE,
598                         "hca_state=%u", hca.hca_action);
599                 ASSERTF(hca.hca_location.length == length,
600                         "length=%llu", hca.hca_location.length);
601         }
602
603         helper_progress = test102_progress;
604         helper_archiving(length);
605 }
606
607 /* Archive, with a single report. */
608 void test103(void)
609 {
610         const size_t length = 1000;
611
612         void test103_progress(struct hsm_copyaction_private *hcp)
613         {
614                 int rc;
615                 struct hsm_extent he;
616                 struct hsm_current_action hca;
617
618                 he.offset = 0;
619                 he.length = length;
620                 rc = llapi_hsm_action_progress(hcp, &he, length, 0);
621                 ASSERTF(rc == 0, "llapi_hsm_action_progress failed: %s",
622                         strerror(-rc));
623
624                 rc = llapi_hsm_current_action(testfile, &hca);
625                 ASSERTF(rc == 0, "llapi_hsm_current_action failed: %s",
626                         strerror(-rc));
627                 ASSERTF(hca.hca_state == HPS_RUNNING,
628                         "hca_state=%u", hca.hca_state);
629                 ASSERTF(hca.hca_action == HUA_ARCHIVE,
630                         "hca_state=%u", hca.hca_action);
631                 ASSERTF(hca.hca_location.length == length,
632                         "length=%llu", hca.hca_location.length);
633         }
634
635         helper_progress = test103_progress;
636         helper_archiving(length);
637 }
638
639 /* Archive, with 2 reports. */
640 void test104(void)
641 {
642         const size_t length = 1000;
643
644         void test104_progress(struct hsm_copyaction_private *hcp)
645         {
646                 int rc;
647                 struct hsm_extent he;
648                 struct hsm_current_action hca;
649
650                 he.offset = 0;
651                 he.length = length/2;
652                 rc = llapi_hsm_action_progress(hcp, &he, length, 0);
653                 ASSERTF(rc == 0, "llapi_hsm_action_progress failed: %s",
654                         strerror(-rc));
655
656                 he.offset = length/2;
657                 he.length = length/2;
658                 rc = llapi_hsm_action_progress(hcp, &he, length, 0);
659                 ASSERTF(rc == 0, "llapi_hsm_action_progress failed: %s",
660                         strerror(-rc));
661
662                 rc = llapi_hsm_current_action(testfile, &hca);
663                 ASSERTF(rc == 0, "llapi_hsm_current_action failed: %s",
664                         strerror(-rc));
665                 ASSERTF(hca.hca_state == HPS_RUNNING,
666                         "hca_state=%u", hca.hca_state);
667                 ASSERTF(hca.hca_action == HUA_ARCHIVE,
668                         "hca_state=%u", hca.hca_action);
669                 ASSERTF(hca.hca_location.length == length,
670                         "length=%llu", hca.hca_location.length);
671         }
672
673         helper_progress = test104_progress;
674         helper_archiving(length);
675 }
676
677 /* Archive, with 1 bogus report. */
678 void test105(void)
679 {
680         const size_t length = 1000;
681
682         void test105_progress(struct hsm_copyaction_private *hcp)
683         {
684                 int rc;
685                 struct hsm_extent he;
686                 struct hsm_current_action hca;
687
688                 he.offset = 2*length;
689                 he.length = 10*length;
690                 rc = llapi_hsm_action_progress(hcp, &he, length, 0);
691                 ASSERTF(rc == 0, "llapi_hsm_action_progress failed: %s",
692                         strerror(-rc));
693
694                 rc = llapi_hsm_current_action(testfile, &hca);
695                 ASSERTF(rc == 0, "llapi_hsm_current_action failed: %s",
696                         strerror(-rc));
697                 ASSERTF(hca.hca_state == HPS_RUNNING,
698                         "hca_state=%u", hca.hca_state);
699                 ASSERTF(hca.hca_action == HUA_ARCHIVE,
700                         "hca_state=%u", hca.hca_action);
701
702                 /* BUG - offset should be 2*length, or length should
703                  * be 8*length */
704                 ASSERTF(hca.hca_location.length == 10*length,
705                         "length=%llu", hca.hca_location.length);
706         }
707
708         helper_progress = test105_progress;
709         helper_archiving(length);
710 }
711
712 /* Archive, with 1 empty report. */
713 void test106(void)
714 {
715         const size_t length = 1000;
716
717         void test106_progress(struct hsm_copyaction_private *hcp)
718         {
719                 int rc;
720                 struct hsm_extent he;
721                 struct hsm_current_action hca;
722
723                 he.offset = 0;
724                 he.length = 0;
725                 rc = llapi_hsm_action_progress(hcp, &he, length, 0);
726                 ASSERTF(rc == 0, "llapi_hsm_action_progress failed: %s",
727                         strerror(-rc));
728
729                 rc = llapi_hsm_current_action(testfile, &hca);
730                 ASSERTF(rc == 0, "llapi_hsm_current_action failed: %s",
731                         strerror(-rc));
732                 ASSERTF(hca.hca_state == HPS_RUNNING,
733                         "hca_state=%u", hca.hca_state);
734                 ASSERTF(hca.hca_action == HUA_ARCHIVE,
735                         "hca_state=%u", hca.hca_action);
736                 ASSERTF(hca.hca_location.length == 0,
737                         "length=%llu", hca.hca_location.length);
738         }
739
740         helper_progress = test106_progress;
741         helper_archiving(length);
742 }
743
744 /* Archive, with 1 bogus report. */
745 void test107(void)
746 {
747         const size_t length = 1000;
748
749         void test107_progress(struct hsm_copyaction_private *hcp)
750         {
751                 int rc;
752                 struct hsm_extent he;
753                 struct hsm_current_action hca;
754
755                 he.offset = -1;
756                 he.length = 10;
757                 rc = llapi_hsm_action_progress(hcp, &he, length, 0);
758                 ASSERTF(rc == -EINVAL, "llapi_hsm_action_progress error: %s",
759                         strerror(-rc));
760
761                 rc = llapi_hsm_current_action(testfile, &hca);
762                 ASSERTF(rc == 0, "llapi_hsm_current_action failed: %s",
763                         strerror(-rc));
764                 ASSERTF(hca.hca_state == HPS_RUNNING,
765                         "hca_state=%u", hca.hca_state);
766                 ASSERTF(hca.hca_action == HUA_ARCHIVE,
767                         "hca_state=%u", hca.hca_action);
768                 ASSERTF(hca.hca_location.length == 0,
769                         "length=%llu", hca.hca_location.length);
770         }
771
772         helper_progress = test107_progress;
773         helper_archiving(length);
774 }
775
776 /* Archive, with same report, many times. */
777 void test108(void)
778 {
779         const size_t length = 1000;
780
781         void test108_progress(struct hsm_copyaction_private *hcp)
782         {
783                 int rc;
784                 struct hsm_extent he;
785                 int i;
786                 struct hsm_current_action hca;
787
788                 for (i = 0; i < 1000; i++) {
789                         he.offset = 0;
790                         he.length = length;
791                         rc = llapi_hsm_action_progress(hcp, &he, length, 0);
792                         ASSERTF(rc == 0, "llapi_hsm_action_progress failed: %s",
793                                 strerror(-rc));
794                 }
795
796                 rc = llapi_hsm_current_action(testfile, &hca);
797                 ASSERTF(rc == 0, "llapi_hsm_current_action failed: %s",
798                         strerror(-rc));
799                 ASSERTF(hca.hca_state == HPS_RUNNING,
800                         "hca_state=%u", hca.hca_state);
801                 ASSERTF(hca.hca_action == HUA_ARCHIVE,
802                         "hca_state=%u", hca.hca_action);
803                 ASSERTF(hca.hca_location.length == length,
804                         "length=%llu", hca.hca_location.length);
805         }
806
807         helper_progress = test108_progress;
808         helper_archiving(length);
809 }
810
811 /* Archive, 1 report, with large number. */
812 void test109(void)
813 {
814         const size_t length = 1000;
815
816         void test109_progress(struct hsm_copyaction_private *hcp)
817         {
818                 int rc;
819                 struct hsm_extent he;
820                 struct hsm_current_action hca;
821
822                 he.offset = 0;
823                 he.length = 0xffffffffffffffffULL;
824                 rc = llapi_hsm_action_progress(hcp, &he, length, 0);
825                 ASSERTF(rc == 0, "llapi_hsm_action_progress failed: %s",
826                         strerror(-rc));
827
828                 rc = llapi_hsm_current_action(testfile, &hca);
829                 ASSERTF(rc == 0, "llapi_hsm_current_action failed: %s",
830                         strerror(-rc));
831                 ASSERTF(hca.hca_state == HPS_RUNNING,
832                         "hca_state=%u", hca.hca_state);
833                 ASSERTF(hca.hca_action == HUA_ARCHIVE,
834                         "hca_state=%u", hca.hca_action);
835                 ASSERTF(hca.hca_location.length == 0xffffffffffffffffULL,
836                         "length=%llu", hca.hca_location.length);
837         }
838
839         helper_progress = test109_progress;
840         helper_archiving(length);
841 }
842
843 /* Archive, with 10 reports, checking progress. */
844 void test110(void)
845 {
846         const size_t length = 1000;
847
848         void test110_progress(struct hsm_copyaction_private *hcp)
849         {
850                 int rc;
851                 int i;
852                 struct hsm_extent he;
853                 struct hsm_current_action hca;
854
855                 for (i = 0; i < 10; i++) {
856                         he.offset = i*length/10;
857                         he.length = length/10;
858                         rc = llapi_hsm_action_progress(hcp, &he, length, 0);
859                         ASSERTF(rc == 0, "llapi_hsm_action_progress failed: %s",
860                                 strerror(-rc));
861
862                         rc = llapi_hsm_current_action(testfile, &hca);
863                         ASSERTF(rc == 0, "llapi_hsm_current_action failed: %s",
864                                 strerror(-rc));
865                         ASSERTF(hca.hca_state == HPS_RUNNING,
866                                 "hca_state=%u", hca.hca_state);
867                         ASSERTF(hca.hca_action == HUA_ARCHIVE,
868                                 "hca_state=%u", hca.hca_action);
869                         ASSERTF(hca.hca_location.length == (i+1)*length/10,
870                                 "i=%d, length=%llu",
871                                 i, hca.hca_location.length);
872                 }
873         }
874
875         helper_progress = test110_progress;
876         helper_archiving(length);
877 }
878
879 /* Archive, with 10 reports in reverse order, checking progress. */
880 void test111(void)
881 {
882         const size_t length = 1000;
883
884         void test111_progress(struct hsm_copyaction_private *hcp)
885         {
886                 int rc;
887                 int i;
888                 struct hsm_extent he;
889                 struct hsm_current_action hca;
890
891                 for (i = 0; i < 10; i++) {
892                         he.offset = (9-i)*length/10;
893                         he.length = length/10;
894                         rc = llapi_hsm_action_progress(hcp, &he, length, 0);
895                         ASSERTF(rc == 0, "llapi_hsm_action_progress failed: %s",
896                                 strerror(-rc));
897
898                         rc = llapi_hsm_current_action(testfile, &hca);
899                         ASSERTF(rc == 0, "llapi_hsm_current_action failed: %s",
900                                 strerror(-rc));
901                         ASSERTF(hca.hca_state == HPS_RUNNING,
902                                 "hca_state=%u", hca.hca_state);
903                         ASSERTF(hca.hca_action == HUA_ARCHIVE,
904                                 "hca_state=%u", hca.hca_action);
905                         ASSERTF(hca.hca_location.length == (i+1)*length/10,
906                                 "i=%d, length=%llu",
907                                 i, hca.hca_location.length);
908                 }
909         }
910
911         helper_progress = test111_progress;
912         helper_archiving(length);
913 }
914
915 /* Archive, with 10 reports, and duplicating them, checking
916  * progress. */
917 void test112(void)
918 {
919         const size_t length = 1000;
920
921         void test112_progress(struct hsm_copyaction_private *hcp)
922         {
923                 int rc;
924                 int i;
925                 struct hsm_extent he;
926                 struct hsm_current_action hca;
927
928                 for (i = 0; i < 10; i++) {
929                         he.offset = i*length/10;
930                         he.length = length/10;
931                         rc = llapi_hsm_action_progress(hcp, &he, length, 0);
932                         ASSERTF(rc == 0, "llapi_hsm_action_progress failed: %s",
933                                 strerror(-rc));
934
935                         rc = llapi_hsm_current_action(testfile, &hca);
936                         ASSERTF(rc == 0, "llapi_hsm_current_action failed: %s",
937                                 strerror(-rc));
938                         ASSERTF(hca.hca_state == HPS_RUNNING,
939                                 "hca_state=%u", hca.hca_state);
940                         ASSERTF(hca.hca_action == HUA_ARCHIVE,
941                                 "hca_state=%u", hca.hca_action);
942                         ASSERTF(hca.hca_location.length == (i+1)*length/10,
943                                 "i=%d, length=%llu",
944                                 i, hca.hca_location.length);
945                 }
946
947                 for (i = 0; i < 10; i++) {
948                         he.offset = i*length/10;
949                         he.length = length/10;
950                         rc = llapi_hsm_action_progress(hcp, &he, length, 0);
951                         ASSERTF(rc == 0, "llapi_hsm_action_progress failed: %s",
952                                 strerror(-rc));
953
954                         rc = llapi_hsm_current_action(testfile, &hca);
955                         ASSERTF(rc == 0, "llapi_hsm_current_action failed: %s",
956                                 strerror(-rc));
957                         ASSERTF(hca.hca_state == HPS_RUNNING,
958                                 "hca_state=%u", hca.hca_state);
959                         ASSERTF(hca.hca_action == HUA_ARCHIVE,
960                                 "hca_state=%u", hca.hca_action);
961                         ASSERTF(hca.hca_location.length == length,
962                                 "i=%d, length=%llu",
963                                 i, hca.hca_location.length);
964                 }
965
966         }
967
968         helper_progress = test112_progress;
969         helper_archiving(length);
970 }
971
972 static void usage(char *prog)
973 {
974         fprintf(stderr, "Usage: %s [-d lustre_dir]\n", prog);
975         exit(EXIT_FAILURE);
976 }
977
978 static void process_args(int argc, char *argv[])
979 {
980         int c;
981
982         while ((c = getopt(argc, argv, "d:")) != -1) {
983                 switch (c) {
984                 case 'd':
985                         lustre_dir = optarg;
986                         break;
987                 case '?':
988                 default:
989                         fprintf(stderr, "Unknown option '%c'\n", optopt);
990                         usage(argv[0]);
991                         break;
992                 }
993         }
994 }
995
996 int main(int argc, char *argv[])
997 {
998         char fsname[8];
999         int rc;
1000
1001         process_args(argc, argv);
1002         if (lustre_dir == NULL)
1003                 lustre_dir = "/mnt/lustre";
1004
1005         rc = llapi_search_mounts(lustre_dir, 0, fsmountdir, fsname);
1006         if (rc != 0) {
1007                 fprintf(stderr, "Error: %s: not a Lustre filesystem\n",
1008                         lustre_dir);
1009                 return EXIT_FAILURE;
1010         }
1011
1012         /* Play nice with Lustre test scripts. Non-line buffered output
1013          * stream under I/O redirection may appear incorrectly. */
1014         setvbuf(stdout, NULL, _IOLBF, 0);
1015
1016         PERFORM(test1);
1017         PERFORM(test2);
1018         PERFORM(test3);
1019         PERFORM(test4);
1020         PERFORM(test5);
1021         PERFORM(test6);
1022         PERFORM(test7);
1023         PERFORM(test50);
1024         PERFORM(test51);
1025         PERFORM(test52);
1026         PERFORM(test100);
1027         PERFORM(test101);
1028         PERFORM(test102);
1029         PERFORM(test103);
1030         PERFORM(test104);
1031         PERFORM(test105);
1032         PERFORM(test106);
1033         PERFORM(test107);
1034         PERFORM(test108);
1035         PERFORM(test109);
1036         PERFORM(test110);
1037         PERFORM(test111);
1038         PERFORM(test112);
1039
1040         return EXIT_SUCCESS;
1041 }