Whamcloud - gitweb
LU-5560 llite: basic support of SELinux in CLIO
[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, 2015 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         /* Invalid archive numbers */
377         rc = llapi_hsm_state_set_fd(fd, HS_EXISTS, 0, 33);
378         ASSERTF(rc == -EINVAL, "llapi_hsm_state_set_fd: %s", strerror(-rc));
379
380         rc = llapi_hsm_state_set_fd(fd, HS_EXISTS, 0, 151);
381         ASSERTF(rc == -EINVAL, "llapi_hsm_state_set_fd: %s", strerror(-rc));
382
383         rc = llapi_hsm_state_set_fd(fd, HS_EXISTS, 0, -1789);
384         ASSERTF(rc == -EINVAL, "llapi_hsm_state_set_fd: %s", strerror(-rc));
385
386         /* Settable flags, with respect of the HSM file state transition rules:
387          *      DIRTY without EXISTS: no dirty if no archive was created
388          *      DIRTY and RELEASED: a dirty file could not be released
389          *      RELEASED without ARCHIVED: do not release a non-archived file
390          *      LOST without ARCHIVED: cannot lost a non-archived file.
391          */
392         rc = llapi_hsm_state_set_fd(fd, HS_DIRTY, 0, 0);
393         ASSERTF(rc == 0, "llapi_hsm_state_set_fd failed: %s", strerror(-rc));
394
395         rc = llapi_hsm_state_set_fd(fd, 0, HS_EXISTS, 0);
396         ASSERTF(rc == -EINVAL, "llapi_hsm_state_set_fd failed: %s",
397                 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, 0, HS_EXISTS, 0);
403         ASSERTF(rc == 0, "llapi_hsm_state_set_fd failed: %s", strerror(-rc));
404
405         rc = llapi_hsm_state_set_fd(fd, HS_DIRTY, 0, 0);
406         ASSERTF(rc == -EINVAL, "llapi_hsm_state_set_fd failed: %s",
407                 strerror(-rc));
408
409         rc = llapi_hsm_state_set_fd(fd, HS_RELEASED, 0, 0);
410         ASSERTF(rc == -EINVAL, "llapi_hsm_state_set_fd failed: %s",
411                 strerror(-rc));
412
413         rc = llapi_hsm_state_set_fd(fd, HS_LOST, 0, 0);
414         ASSERTF(rc == -EINVAL, "llapi_hsm_state_set_fd failed: %s",
415                 strerror(-rc));
416
417         rc = llapi_hsm_state_set_fd(fd, HS_ARCHIVED, 0, 0);
418         ASSERTF(rc == 0, "llapi_hsm_state_set_fd failed: %s", strerror(-rc));
419
420         rc = llapi_hsm_state_set_fd(fd, HS_RELEASED, 0, 0);
421         ASSERTF(rc == 0, "llapi_hsm_state_set_fd failed: %s", strerror(-rc));
422
423         rc = llapi_hsm_state_set_fd(fd, HS_LOST, 0, 0);
424         ASSERTF(rc == 0, "llapi_hsm_state_set_fd failed: %s", strerror(-rc));
425
426         rc = llapi_hsm_state_set_fd(fd, HS_DIRTY|HS_EXISTS, 0, 0);
427         ASSERTF(rc == -EINVAL, "llapi_hsm_state_set_fd failed: %s",
428                 strerror(-rc));
429
430         rc = llapi_hsm_state_set_fd(fd, 0, HS_RELEASED, 0);
431         ASSERTF(rc == 0, "llapi_hsm_state_set_fd failed: %s", strerror(-rc));
432
433         rc = llapi_hsm_state_set_fd(fd, HS_DIRTY|HS_EXISTS, 0, 0);
434         ASSERTF(rc == 0, "llapi_hsm_state_set_fd failed: %s", strerror(-rc));
435
436         rc = llapi_hsm_state_set_fd(fd, 0, HS_ARCHIVED, 0);
437         ASSERTF(rc == -EINVAL, "llapi_hsm_state_set_fd failed: %s",
438                 strerror(-rc));
439
440         rc = llapi_hsm_state_set_fd(fd, 0, HS_LOST, 0);
441         ASSERTF(rc == 0, "llapi_hsm_state_set_fd failed: %s", strerror(-rc));
442
443         rc = llapi_hsm_state_set_fd(fd, 0, HS_ARCHIVED, 0);
444         ASSERTF(rc == 0, "llapi_hsm_state_set_fd failed: %s", strerror(-rc));
445
446         rc = llapi_hsm_state_set_fd(fd, HS_NORELEASE, 0, 0);
447         ASSERTF(rc == 0, "llapi_hsm_state_set_fd failed: %s", strerror(-rc));
448
449         rc = llapi_hsm_state_set_fd(fd, 0, HS_NORELEASE, 0);
450         ASSERTF(rc == 0, "llapi_hsm_state_set_fd failed: %s", strerror(-rc));
451
452         rc = llapi_hsm_state_set_fd(fd, HS_NOARCHIVE, 0, 0);
453         ASSERTF(rc == 0, "llapi_hsm_state_set_fd failed: %s", strerror(-rc));
454
455         rc = llapi_hsm_state_set_fd(fd, 0, HS_NOARCHIVE, 0);
456         ASSERTF(rc == 0, "llapi_hsm_state_set_fd failed: %s", strerror(-rc));
457
458         /* Bogus flags for good measure. */
459         rc = llapi_hsm_state_set_fd(fd, 0x00080000, 0, 0);
460         ASSERTF(rc == -EINVAL, "llapi_hsm_state_set_fd: %s", strerror(-rc));
461
462         rc = llapi_hsm_state_set_fd(fd, 0x80000000, 0, 0);
463         ASSERTF(rc == -EINVAL, "llapi_hsm_state_set_fd: %s", strerror(-rc));
464
465         close(fd);
466 }
467
468 /* Test llapi_hsm_current_action */
469 void test52(void)
470 {
471         int rc;
472         int fd;
473         struct hsm_current_action hca;
474
475         /* No fd equivalent, so close it. */
476         fd = create_testfile(100);
477         close(fd);
478
479         rc = llapi_hsm_current_action(testfile, &hca);
480         ASSERTF(rc == 0, "llapi_hsm_current_action failed: %s", strerror(-rc));
481         ASSERTF(hca.hca_state, "hca_state=%u", hca.hca_state);
482         ASSERTF(hca.hca_action, "hca_state=%u", hca.hca_action);
483
484         rc = llapi_hsm_current_action(testfile, NULL);
485         ASSERTF(rc == -EFAULT, "llapi_hsm_current_action failed: %s",
486                 strerror(-rc));
487 }
488
489 /* Helper to simulate archiving a file. No actual data movement
490  * happens. */
491 void helper_archiving(void (*progress)
492                       (struct hsm_copyaction_private *hcp, size_t length),
493                       const size_t length)
494 {
495         int rc;
496         int fd;
497         struct hsm_copytool_private *ctdata;
498         struct hsm_user_request *hur;
499         struct hsm_action_list  *hal;
500         struct hsm_action_item  *hai;
501         int                      msgsize;
502         struct hsm_copyaction_private *hcp;
503         struct hsm_user_state hus;
504
505         fd = create_testfile(length);
506
507         rc = llapi_hsm_copytool_register(&ctdata, fsmountdir,
508                                          0, NULL, 0);
509         ASSERTF(rc == 0, "llapi_hsm_copytool_register failed: %s",
510                 strerror(-rc));
511
512         /* Create and send the archive request. */
513         hur = llapi_hsm_user_request_alloc(1, 0);
514         ASSERTF(hur != NULL, "llapi_hsm_user_request_alloc returned NULL");
515
516         hur->hur_request.hr_action = HUA_ARCHIVE;
517         hur->hur_request.hr_archive_id = 1;
518         hur->hur_request.hr_flags = 0;
519         hur->hur_request.hr_itemcount = 1;
520         hur->hur_request.hr_data_len = 0;
521         hur->hur_user_item[0].hui_extent.length = -1;
522
523         rc = llapi_fd2fid(fd, &hur->hur_user_item[0].hui_fid);
524         ASSERTF(rc == 0, "llapi_fd2fid failed: %s", strerror(-rc));
525
526         close(fd);
527
528         rc = llapi_hsm_request(testfile, hur);
529         ASSERTF(rc == 0, "llapi_hsm_request failed: %s", strerror(-rc));
530
531         free(hur);
532
533         /* Read the request */
534         rc = llapi_hsm_copytool_recv(ctdata, &hal, &msgsize);
535         ASSERTF(rc == 0, "llapi_hsm_copytool_recv failed: %s", strerror(-rc));
536         ASSERTF(hal->hal_count == 1, "hal_count=%d", hal->hal_count);
537
538         hai = hai_first(hal);
539         ASSERTF(hai != NULL, "hai_first returned NULL");
540         ASSERTF(hai->hai_action == HSMA_ARCHIVE,
541                 "hai_action=%d", hai->hai_action);
542
543         /* "Begin" archiving */
544         hcp = NULL;
545         rc = llapi_hsm_action_begin(&hcp, ctdata, hai, -1, 0, false);
546         ASSERTF(rc == 0, "llapi_hsm_action_begin failed: %s", strerror(-rc));
547         ASSERTF(hcp != NULL, "hcp is NULL");
548
549         if (progress)
550                 progress(hcp, length);
551
552         /* Done archiving */
553         rc = llapi_hsm_action_end(&hcp, &hai->hai_extent, 0, 0);
554         ASSERTF(rc == 0, "llapi_hsm_action_end failed: %s", strerror(-rc));
555         ASSERTF(hcp == NULL, "hcp is NULL");
556
557         /* Close HSM client */
558         rc = llapi_hsm_copytool_unregister(&ctdata);
559         ASSERTF(rc == 0, "llapi_hsm_copytool_unregister failed: %s",
560                 strerror(-rc));
561
562         /* Final check */
563         rc = llapi_hsm_state_get(testfile, &hus);
564         ASSERTF(rc == 0, "llapi_hsm_state_get failed: %s", strerror(-rc));
565         ASSERTF(hus.hus_states == (HS_EXISTS | HS_ARCHIVED),
566                 "state=%u", hus.hus_states);
567 }
568
569 /* Simple archive. No progress. */
570 void test100(void)
571 {
572         const size_t length = 100;
573
574         helper_archiving(NULL, length);
575 }
576
577 /* Archive, with a report every byte. */
578 static void test101_progress(struct hsm_copyaction_private *hcp, size_t length)
579 {
580         int i;
581         int rc;
582         struct hsm_extent he;
583         struct hsm_current_action hca;
584
585         /* Report progress. 1 byte at a time :) */
586         for (i = 0; i < length; i++) {
587                 he.offset = i;
588                 he.length = 1;
589                 rc = llapi_hsm_action_progress(hcp, &he, length, 0);
590                 ASSERTF(rc == 0, "llapi_hsm_action_progress failed: %s",
591                         strerror(-rc));
592         }
593
594         rc = llapi_hsm_current_action(testfile, &hca);
595         ASSERTF(rc == 0, "llapi_hsm_current_action failed: %s",
596                 strerror(-rc));
597         ASSERTF(hca.hca_state == HPS_RUNNING,
598                 "hca_state=%u", hca.hca_state);
599         ASSERTF(hca.hca_action == HUA_ARCHIVE,
600                 "hca_state=%u", hca.hca_action);
601         ASSERTF(hca.hca_location.length == length,
602                 "length=%llu", (unsigned long long)hca.hca_location.length);
603 }
604
605 void test101(void)
606 {
607         const size_t length = 1000;
608
609         helper_archiving(test101_progress, length);
610 }
611
612 /* Archive, with a report every byte, backwards. */
613 static void test102_progress(struct hsm_copyaction_private *hcp, size_t length)
614 {
615         int i;
616         int rc;
617         struct hsm_extent he;
618         struct hsm_current_action hca;
619
620         /* Report progress. 1 byte at a time :) */
621         for (i = length-1; i >= 0; i--) {
622                 he.offset = i;
623                 he.length = 1;
624                 rc = llapi_hsm_action_progress(hcp, &he, length, 0);
625                 ASSERTF(rc == 0, "llapi_hsm_action_progress failed: %s",
626                         strerror(-rc));
627         }
628
629         rc = llapi_hsm_current_action(testfile, &hca);
630         ASSERTF(rc == 0, "llapi_hsm_current_action failed: %s",
631                 strerror(-rc));
632         ASSERTF(hca.hca_state == HPS_RUNNING,
633                 "hca_state=%u", hca.hca_state);
634         ASSERTF(hca.hca_action == HUA_ARCHIVE,
635                 "hca_state=%u", hca.hca_action);
636         ASSERTF(hca.hca_location.length == length,
637                 "length=%llu", (unsigned long long)hca.hca_location.length);
638 }
639
640 void test102(void)
641 {
642         const size_t length = 1000;
643
644         helper_archiving(test102_progress, length);
645 }
646
647 /* Archive, with a single report. */
648 static void test103_progress(struct hsm_copyaction_private *hcp, size_t length)
649 {
650         int rc;
651         struct hsm_extent he;
652         struct hsm_current_action hca;
653
654         he.offset = 0;
655         he.length = length;
656         rc = llapi_hsm_action_progress(hcp, &he, length, 0);
657         ASSERTF(rc == 0, "llapi_hsm_action_progress failed: %s",
658                 strerror(-rc));
659
660         rc = llapi_hsm_current_action(testfile, &hca);
661         ASSERTF(rc == 0, "llapi_hsm_current_action failed: %s",
662                 strerror(-rc));
663         ASSERTF(hca.hca_state == HPS_RUNNING,
664                 "hca_state=%u", hca.hca_state);
665         ASSERTF(hca.hca_action == HUA_ARCHIVE,
666                 "hca_state=%u", hca.hca_action);
667         ASSERTF(hca.hca_location.length == length,
668                 "length=%llu", (unsigned long long)hca.hca_location.length);
669 }
670
671 void test103(void)
672 {
673         const size_t length = 1000;
674
675         helper_archiving(test103_progress, length);
676 }
677
678 /* Archive, with 2 reports. */
679 static void test104_progress(struct hsm_copyaction_private *hcp, size_t length)
680 {
681         int rc;
682         struct hsm_extent he;
683         struct hsm_current_action hca;
684
685         he.offset = 0;
686         he.length = length/2;
687         rc = llapi_hsm_action_progress(hcp, &he, length, 0);
688         ASSERTF(rc == 0, "llapi_hsm_action_progress failed: %s",
689                 strerror(-rc));
690
691         he.offset = length/2;
692         he.length = length/2;
693         rc = llapi_hsm_action_progress(hcp, &he, length, 0);
694         ASSERTF(rc == 0, "llapi_hsm_action_progress failed: %s",
695                 strerror(-rc));
696
697         rc = llapi_hsm_current_action(testfile, &hca);
698         ASSERTF(rc == 0, "llapi_hsm_current_action failed: %s",
699                 strerror(-rc));
700         ASSERTF(hca.hca_state == HPS_RUNNING,
701                 "hca_state=%u", hca.hca_state);
702         ASSERTF(hca.hca_action == HUA_ARCHIVE,
703                 "hca_state=%u", hca.hca_action);
704         ASSERTF(hca.hca_location.length == length,
705                 "length=%llu", (unsigned long long)hca.hca_location.length);
706 }
707
708 void test104(void)
709 {
710         const size_t length = 1000;
711
712         helper_archiving(test104_progress, length);
713 }
714
715 /* Archive, with 1 bogus report. */
716 static void test105_progress(struct hsm_copyaction_private *hcp, size_t length)
717 {
718         int rc;
719         struct hsm_extent he;
720         struct hsm_current_action hca;
721
722         he.offset = 2*length;
723         he.length = 10*length;
724         rc = llapi_hsm_action_progress(hcp, &he, length, 0);
725         ASSERTF(rc == 0, "llapi_hsm_action_progress failed: %s",
726                 strerror(-rc));
727
728         rc = llapi_hsm_current_action(testfile, &hca);
729         ASSERTF(rc == 0, "llapi_hsm_current_action failed: %s",
730                 strerror(-rc));
731         ASSERTF(hca.hca_state == HPS_RUNNING,
732                 "hca_state=%u", hca.hca_state);
733         ASSERTF(hca.hca_action == HUA_ARCHIVE,
734                 "hca_state=%u", hca.hca_action);
735
736         /* BUG - offset should be 2*length, or length should
737          * be 8*length */
738         ASSERTF(hca.hca_location.length == 10*length,
739                 "length=%llu", (unsigned long long)hca.hca_location.length);
740 }
741
742 void test105(void)
743 {
744         const size_t length = 1000;
745
746         helper_archiving(test105_progress, length);
747 }
748
749 /* Archive, with 1 empty report. */
750 static void test106_progress(struct hsm_copyaction_private *hcp, size_t length)
751 {
752         int rc;
753         struct hsm_extent he;
754         struct hsm_current_action hca;
755
756         he.offset = 0;
757         he.length = 0;
758         rc = llapi_hsm_action_progress(hcp, &he, length, 0);
759         ASSERTF(rc == 0, "llapi_hsm_action_progress failed: %s",
760                 strerror(-rc));
761
762         rc = llapi_hsm_current_action(testfile, &hca);
763         ASSERTF(rc == 0, "llapi_hsm_current_action failed: %s",
764                 strerror(-rc));
765         ASSERTF(hca.hca_state == HPS_RUNNING,
766                 "hca_state=%u", hca.hca_state);
767         ASSERTF(hca.hca_action == HUA_ARCHIVE,
768                 "hca_state=%u", hca.hca_action);
769         ASSERTF(hca.hca_location.length == 0,
770                 "length=%llu", (unsigned long long)hca.hca_location.length);
771 }
772
773 void test106(void)
774 {
775         const size_t length = 1000;
776
777         helper_archiving(test106_progress, length);
778 }
779
780 /* Archive, with 1 bogus report. */
781 static void test107_progress(struct hsm_copyaction_private *hcp, size_t length)
782 {
783         int rc;
784         struct hsm_extent he;
785         struct hsm_current_action hca;
786
787         he.offset = -1;
788         he.length = 10;
789         rc = llapi_hsm_action_progress(hcp, &he, length, 0);
790         ASSERTF(rc == -EINVAL, "llapi_hsm_action_progress error: %s",
791                 strerror(-rc));
792
793         rc = llapi_hsm_current_action(testfile, &hca);
794         ASSERTF(rc == 0, "llapi_hsm_current_action failed: %s",
795                 strerror(-rc));
796         ASSERTF(hca.hca_state == HPS_RUNNING,
797                 "hca_state=%u", hca.hca_state);
798         ASSERTF(hca.hca_action == HUA_ARCHIVE,
799                 "hca_state=%u", hca.hca_action);
800         ASSERTF(hca.hca_location.length == 0,
801                 "length=%llu", (unsigned long long)hca.hca_location.length);
802 }
803
804 void test107(void)
805 {
806         const size_t length = 1000;
807
808         helper_archiving(test107_progress, length);
809 }
810
811 /* Archive, with same report, many times. */
812 static void test108_progress(struct hsm_copyaction_private *hcp, size_t length)
813 {
814         int rc;
815         struct hsm_extent he;
816         int i;
817         struct hsm_current_action hca;
818
819         for (i = 0; i < 1000; i++) {
820                 he.offset = 0;
821                 he.length = length;
822                 rc = llapi_hsm_action_progress(hcp, &he, length, 0);
823                 ASSERTF(rc == 0, "llapi_hsm_action_progress failed: %s",
824                         strerror(-rc));
825         }
826
827         rc = llapi_hsm_current_action(testfile, &hca);
828         ASSERTF(rc == 0, "llapi_hsm_current_action failed: %s",
829                 strerror(-rc));
830         ASSERTF(hca.hca_state == HPS_RUNNING,
831                 "hca_state=%u", hca.hca_state);
832         ASSERTF(hca.hca_action == HUA_ARCHIVE,
833                 "hca_state=%u", hca.hca_action);
834         ASSERTF(hca.hca_location.length == length,
835                 "length=%llu", (unsigned long long)hca.hca_location.length);
836 }
837
838 void test108(void)
839 {
840         const size_t length = 1000;
841
842         helper_archiving(test108_progress, length);
843 }
844
845 /* Archive, 1 report, with large number. */
846 static void test109_progress(struct hsm_copyaction_private *hcp, size_t length)
847 {
848         int rc;
849         struct hsm_extent he;
850         struct hsm_current_action hca;
851
852         he.offset = 0;
853         he.length = 0xffffffffffffffffULL;
854         rc = llapi_hsm_action_progress(hcp, &he, length, 0);
855         ASSERTF(rc == 0, "llapi_hsm_action_progress failed: %s",
856                 strerror(-rc));
857
858         rc = llapi_hsm_current_action(testfile, &hca);
859         ASSERTF(rc == 0, "llapi_hsm_current_action failed: %s",
860                 strerror(-rc));
861         ASSERTF(hca.hca_state == HPS_RUNNING,
862                 "hca_state=%u", hca.hca_state);
863         ASSERTF(hca.hca_action == HUA_ARCHIVE,
864                 "hca_state=%u", hca.hca_action);
865         ASSERTF(hca.hca_location.length == 0xffffffffffffffffULL,
866                 "length=%llu", (unsigned long long)hca.hca_location.length);
867 }
868
869 void test109(void)
870 {
871         const size_t length = 1000;
872
873         helper_archiving(test109_progress, length);
874 }
875
876 /* Archive, with 10 reports, checking progress. */
877 static void test110_progress(struct hsm_copyaction_private *hcp, size_t length)
878 {
879         int rc;
880         int i;
881         struct hsm_extent he;
882         struct hsm_current_action hca;
883
884         for (i = 0; i < 10; i++) {
885                 he.offset = i*length/10;
886                 he.length = length/10;
887                 rc = llapi_hsm_action_progress(hcp, &he, length, 0);
888                 ASSERTF(rc == 0, "llapi_hsm_action_progress failed: %s",
889                         strerror(-rc));
890
891                 rc = llapi_hsm_current_action(testfile, &hca);
892                 ASSERTF(rc == 0, "llapi_hsm_current_action failed: %s",
893                         strerror(-rc));
894                 ASSERTF(hca.hca_state == HPS_RUNNING,
895                         "hca_state=%u", hca.hca_state);
896                 ASSERTF(hca.hca_action == HUA_ARCHIVE,
897                         "hca_state=%u", hca.hca_action);
898                 ASSERTF(hca.hca_location.length == (i+1)*length/10,
899                         "i=%d, length=%llu",
900                         i, (unsigned long long)hca.hca_location.length);
901         }
902 }
903
904 void test110(void)
905 {
906         const size_t length = 1000;
907
908         helper_archiving(test110_progress, length);
909 }
910
911 /* Archive, with 10 reports in reverse order, checking progress. */
912 static void test111_progress(struct hsm_copyaction_private *hcp, size_t length)
913 {
914         int rc;
915         int i;
916         struct hsm_extent he;
917         struct hsm_current_action hca;
918
919         for (i = 0; i < 10; i++) {
920                 he.offset = (9-i)*length/10;
921                 he.length = length/10;
922                 rc = llapi_hsm_action_progress(hcp, &he, length, 0);
923                 ASSERTF(rc == 0, "llapi_hsm_action_progress failed: %s",
924                         strerror(-rc));
925
926                 rc = llapi_hsm_current_action(testfile, &hca);
927                 ASSERTF(rc == 0, "llapi_hsm_current_action failed: %s",
928                         strerror(-rc));
929                 ASSERTF(hca.hca_state == HPS_RUNNING,
930                         "hca_state=%u", hca.hca_state);
931                 ASSERTF(hca.hca_action == HUA_ARCHIVE,
932                         "hca_state=%u", hca.hca_action);
933                 ASSERTF(hca.hca_location.length == (i+1)*length/10,
934                         "i=%d, length=%llu",
935                         i, (unsigned long long)hca.hca_location.length);
936         }
937 }
938
939 void test111(void)
940 {
941         const size_t length = 1000;
942
943         helper_archiving(test111_progress, length);
944 }
945
946 /* Archive, with 10 reports, and duplicating them, checking
947  * progress. */
948 static void test112_progress(struct hsm_copyaction_private *hcp, size_t length)
949 {
950         int rc;
951         int i;
952         struct hsm_extent he;
953         struct hsm_current_action hca;
954
955         for (i = 0; i < 10; i++) {
956                 he.offset = i*length/10;
957                 he.length = length/10;
958                 rc = llapi_hsm_action_progress(hcp, &he, length, 0);
959                 ASSERTF(rc == 0, "llapi_hsm_action_progress failed: %s",
960                         strerror(-rc));
961
962                 rc = llapi_hsm_current_action(testfile, &hca);
963                 ASSERTF(rc == 0, "llapi_hsm_current_action failed: %s",
964                         strerror(-rc));
965                 ASSERTF(hca.hca_state == HPS_RUNNING,
966                         "hca_state=%u", hca.hca_state);
967                 ASSERTF(hca.hca_action == HUA_ARCHIVE,
968                         "hca_state=%u", hca.hca_action);
969                 ASSERTF(hca.hca_location.length == (i+1)*length/10,
970                         "i=%d, length=%llu",
971                         i, (unsigned long long)hca.hca_location.length);
972         }
973
974         for (i = 0; i < 10; i++) {
975                 he.offset = i*length/10;
976                 he.length = length/10;
977                 rc = llapi_hsm_action_progress(hcp, &he, length, 0);
978                 ASSERTF(rc == 0, "llapi_hsm_action_progress failed: %s",
979                         strerror(-rc));
980
981                 rc = llapi_hsm_current_action(testfile, &hca);
982                 ASSERTF(rc == 0, "llapi_hsm_current_action failed: %s",
983                         strerror(-rc));
984                 ASSERTF(hca.hca_state == HPS_RUNNING,
985                         "hca_state=%u", hca.hca_state);
986                 ASSERTF(hca.hca_action == HUA_ARCHIVE,
987                         "hca_state=%u", hca.hca_action);
988                 ASSERTF(hca.hca_location.length == length,
989                         "i=%d, length=%llu",
990                         i, (unsigned long long)hca.hca_location.length);
991         }
992 }
993
994 void test112(void)
995 {
996         const size_t length = 1000;
997
998         helper_archiving(test112_progress, length);
999 }
1000
1001 static void usage(char *prog)
1002 {
1003         fprintf(stderr, "Usage: %s [-d lustre_dir]\n", prog);
1004         exit(EXIT_FAILURE);
1005 }
1006
1007 static void process_args(int argc, char *argv[])
1008 {
1009         int c;
1010
1011         while ((c = getopt(argc, argv, "d:")) != -1) {
1012                 switch (c) {
1013                 case 'd':
1014                         lustre_dir = optarg;
1015                         break;
1016                 case '?':
1017                 default:
1018                         fprintf(stderr, "Unknown option '%c'\n", optopt);
1019                         usage(argv[0]);
1020                         break;
1021                 }
1022         }
1023 }
1024
1025 int main(int argc, char *argv[])
1026 {
1027         char fsname[8 + 1];
1028         int rc;
1029
1030         process_args(argc, argv);
1031         if (lustre_dir == NULL)
1032                 lustre_dir = "/mnt/lustre";
1033
1034         rc = llapi_search_mounts(lustre_dir, 0, fsmountdir, fsname);
1035         if (rc != 0) {
1036                 fprintf(stderr, "Error: %s: not a Lustre filesystem\n",
1037                         lustre_dir);
1038                 return EXIT_FAILURE;
1039         }
1040
1041         /* Play nice with Lustre test scripts. Non-line buffered output
1042          * stream under I/O redirection may appear incorrectly. */
1043         setvbuf(stdout, NULL, _IOLBF, 0);
1044
1045         PERFORM(test1);
1046         PERFORM(test2);
1047         PERFORM(test3);
1048         PERFORM(test4);
1049         PERFORM(test5);
1050         PERFORM(test6);
1051         PERFORM(test7);
1052         PERFORM(test50);
1053         PERFORM(test51);
1054         PERFORM(test52);
1055         PERFORM(test100);
1056         PERFORM(test101);
1057         PERFORM(test102);
1058         PERFORM(test103);
1059         PERFORM(test104);
1060         PERFORM(test105);
1061         PERFORM(test106);
1062         PERFORM(test107);
1063         PERFORM(test108);
1064         PERFORM(test109);
1065         PERFORM(test110);
1066         PERFORM(test111);
1067         PERFORM(test112);
1068
1069         return EXIT_SUCCESS;
1070 }