X-Git-Url: https://git.whamcloud.com/?p=fs%2Flustre-release.git;a=blobdiff_plain;f=lustre%2Futils%2Flhsmtool_posix.c;h=d3633d6cf3b5a31a916b610189cae23a2b9379ca;hp=8c8ac002cbc6aacae2dc1391ebf0bb6c976fd671;hb=971b0393a6d0e45051c9875efa2c7179cbf7d4c5;hpb=8dfee22dd5a896144fb913f5f9f0e8f5c0e4ed86 diff --git a/lustre/utils/lhsmtool_posix.c b/lustre/utils/lhsmtool_posix.c index 8c8ac00..d3633d6 100644 --- a/lustre/utils/lhsmtool_posix.c +++ b/lustre/utils/lhsmtool_posix.c @@ -23,6 +23,7 @@ * (C) Copyright 2012 Commissariat a l'energie atomique et aux energies * alternatives * + * Copyright (c) 2013, 2016, Intel Corporation. */ /* HSM copytool program for POSIX filesystem-based HSM's. * @@ -36,16 +37,27 @@ #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif +#include +#include #include #include #include +#include #include #include +#include +#include +#include +#include #include +#include +#include #include #include #include -#include + +#include +#include #include /* Progress reporting period */ @@ -57,11 +69,9 @@ #define ONE_MB 0x100000 -/* copytool uses a 32b bitmask field to register with kuc - * archive num = 0 => all - * archive num from 1 to 32 - */ -#define MAX_ARCHIVE_CNT (sizeof(__u32) * 8) +#ifndef NSEC_PER_SEC +# define NSEC_PER_SEC 1000000000UL +#endif enum ct_action { CA_IMPORT = 1, @@ -78,13 +88,14 @@ struct options { int o_verbose; int o_copy_xattrs; int o_archive_cnt; - int o_archive_id[MAX_ARCHIVE_CNT]; + int o_archive_id[LL_HSM_MAX_ARCHIVE]; int o_report_int; unsigned long long o_bandwidth; size_t o_chunk_size; enum ct_action o_action; char *o_event_fifo; char *o_mnt; + int o_mnt_fd; char *o_hsm_root; char *o_src; /* for import, or rebind */ char *o_dst; /* for import, or rebind */ @@ -115,27 +126,34 @@ static char fs_name[MAX_OBD_NAME + 1]; static struct hsm_copytool_private *ctdata; +static inline double ct_now(void) +{ + struct timeval tv; + + gettimeofday(&tv, NULL); + + return tv.tv_sec + 0.000001 * tv.tv_usec; +} -#define CT_ERROR(_rc, _format, ...) \ +#define CT_ERROR(_rc, _format, ...) \ llapi_error(LLAPI_MSG_ERROR, _rc, \ - "%s[%ld]: "_format, \ - cmd_name, syscall(SYS_gettid), ## __VA_ARGS__) -#define CT_DEBUG(_format, ...) \ + "%f %s[%ld]: "_format, \ + ct_now(), cmd_name, syscall(SYS_gettid), ## __VA_ARGS__) + +#define CT_DEBUG(_format, ...) \ llapi_error(LLAPI_MSG_DEBUG | LLAPI_MSG_NO_ERRNO, 0, \ - "%s[%ld]: "_format, \ - cmd_name, syscall(SYS_gettid), ## __VA_ARGS__) + "%f %s[%ld]: "_format, \ + ct_now(), cmd_name, syscall(SYS_gettid), ## __VA_ARGS__) + #define CT_WARN(_format, ...) \ llapi_error(LLAPI_MSG_WARN | LLAPI_MSG_NO_ERRNO, 0, \ - "%s[%ld]: "_format, \ - cmd_name, syscall(SYS_gettid), ## __VA_ARGS__) -#define CT_TRACE(_format, ...) \ + "%f %s[%ld]: "_format, \ + ct_now(), cmd_name, syscall(SYS_gettid), ## __VA_ARGS__) + +#define CT_TRACE(_format, ...) \ llapi_error(LLAPI_MSG_INFO | LLAPI_MSG_NO_ERRNO, 0, \ - "%s[%ld]: "_format, \ - cmd_name, syscall(SYS_gettid), ## __VA_ARGS__) -#define CT_PRINTF(_format, ...) \ - llapi_printf(LLAPI_MSG_NORMAL, \ - "%s[%ld]: "_format, \ - cmd_name, syscall(SYS_gettid), ## __VA_ARGS__) + "%f %s[%ld]: "_format, \ + ct_now(), cmd_name, syscall(SYS_gettid), ## __VA_ARGS__) static void usage(const char *name, int rc) { @@ -192,35 +210,46 @@ static void usage(const char *name, int rc) static int ct_parseopts(int argc, char * const *argv) { struct option long_opts[] = { - {"abort-on-error", no_argument, &opt.o_abort_on_error, 1}, - {"abort_on_error", no_argument, &opt.o_abort_on_error, 1}, - {"archive", required_argument, NULL, 'A'}, - {"bandwidth", required_argument, NULL, 'b'}, - {"chunk-size", required_argument, NULL, 'c'}, - {"chunk_size", required_argument, NULL, 'c'}, - {"daemon", no_argument, &opt.o_daemonize, 1}, - {"event-fifo", required_argument, NULL, 'f'}, - {"event_fifo", required_argument, NULL, 'f'}, - {"dry-run", no_argument, &opt.o_dry_run, 1}, - {"help", no_argument, NULL, 'h'}, - {"hsm-root", required_argument, NULL, 'p'}, - {"hsm_root", required_argument, NULL, 'p'}, - {"import", no_argument, NULL, 'i'}, - {"max-sequence", no_argument, NULL, 'M'}, - {"max_sequence", no_argument, NULL, 'M'}, - {"no-attr", no_argument, &opt.o_copy_attrs, 0}, - {"no_attr", no_argument, &opt.o_copy_attrs, 0}, - {"no-shadow", no_argument, &opt.o_shadow_tree, 0}, - {"no_shadow", no_argument, &opt.o_shadow_tree, 0}, - {"no-xattr", no_argument, &opt.o_copy_xattrs, 0}, - {"no_xattr", no_argument, &opt.o_copy_xattrs, 0}, - {"quiet", no_argument, NULL, 'q'}, - {"rebind", no_argument, NULL, 'r'}, - {"update-interval", required_argument, NULL, 'u'}, - {"update_interval", required_argument, NULL, 'u'}, - {"verbose", no_argument, NULL, 'v'}, - {0, 0, 0, 0} - }; + { .val = 1, .name = "abort-on-error", + .flag = &opt.o_abort_on_error, .has_arg = no_argument }, + { .val = 1, .name = "abort_on_error", + .flag = &opt.o_abort_on_error, .has_arg = no_argument }, + { .val = 'A', .name = "archive", .has_arg = required_argument }, + { .val = 'b', .name = "bandwidth", .has_arg = required_argument }, + { .val = 'c', .name = "chunk-size", .has_arg = required_argument }, + { .val = 'c', .name = "chunk_size", .has_arg = required_argument }, + { .val = 1, .name = "daemon", .has_arg = no_argument, + .flag = &opt.o_daemonize }, + { .val = 'f', .name = "event-fifo", .has_arg = required_argument }, + { .val = 'f', .name = "event_fifo", .has_arg = required_argument }, + { .val = 1, .name = "dry-run", .has_arg = no_argument, + .flag = &opt.o_dry_run }, + { .val = 'h', .name = "help", .has_arg = no_argument }, + { .val = 'i', .name = "import", .has_arg = no_argument }, + { .val = 'M', .name = "max-sequence", .has_arg = no_argument }, + { .val = 'M', .name = "max_sequence", .has_arg = no_argument }, + { .val = 0, .name = "no-attr", .has_arg = no_argument, + .flag = &opt.o_copy_attrs }, + { .val = 0, .name = "no_attr", .has_arg = no_argument, + .flag = &opt.o_copy_attrs }, + { .val = 0, .name = "no-shadow", .has_arg = no_argument, + .flag = &opt.o_shadow_tree }, + { .val = 0, .name = "no_shadow", .has_arg = no_argument, + .flag = &opt.o_shadow_tree }, + { .val = 0, .name = "no-xattr", .has_arg = no_argument, + .flag = &opt.o_copy_xattrs }, + { .val = 0, .name = "no_xattr", .has_arg = no_argument, + .flag = &opt.o_copy_xattrs }, + { .val = 'p', .name = "hsm-root", .has_arg = required_argument }, + { .val = 'p', .name = "hsm_root", .has_arg = required_argument }, + { .val = 'q', .name = "quiet", .has_arg = no_argument }, + { .val = 'r', .name = "rebind", .has_arg = no_argument }, + { .val = 'u', .name = "update-interval", + .has_arg = required_argument }, + { .val = 'u', .name = "update_interval", + .has_arg = required_argument }, + { .val = 'v', .name = "verbose", .has_arg = no_argument }, + { .name = NULL } }; int c, rc; unsigned long long value; unsigned long long unit; @@ -230,11 +259,11 @@ static int ct_parseopts(int argc, char * const *argv) long_opts, NULL)) != -1) { switch (c) { case 'A': - if ((opt.o_archive_cnt >= MAX_ARCHIVE_CNT) || - (atoi(optarg) >= MAX_ARCHIVE_CNT)) { + if ((opt.o_archive_cnt >= LL_HSM_MAX_ARCHIVE) || + (atoi(optarg) >= LL_HSM_MAX_ARCHIVE)) { rc = -E2BIG; CT_ERROR(rc, "archive number must be less" - "than %zu", MAX_ARCHIVE_CNT); + "than %zu", LL_HSM_MAX_ARCHIVE); return rc; } opt.o_archive_id[opt.o_archive_cnt] = atoi(optarg); @@ -331,11 +360,12 @@ static int ct_parseopts(int argc, char * const *argv) } opt.o_mnt = argv[optind]; + opt.o_mnt_fd = -1; CT_TRACE("action=%d src=%s dst=%s mount_point=%s", opt.o_action, opt.o_src, opt.o_dst, opt.o_mnt); - if (!opt.o_dry_run && opt.o_hsm_root == NULL) { + if (opt.o_hsm_root == NULL) { rc = -EINVAL; CT_ERROR(rc, "must specify a root directory for the backend"); return rc; @@ -366,6 +396,9 @@ static int ct_mkdir_p(const char *path) int rc; ptr = strdup(path); + if (ptr == NULL) + return -errno; + saved = ptr; while (*ptr == '/') ptr++; @@ -485,45 +518,13 @@ static int ct_restore_stripe(const char *src, const char *dst, int dst_fd, rc = fsetxattr(dst_fd, XATTR_LUSTRE_LOV, lovea, lovea_size, XATTR_CREATE); if (rc < 0) { - CT_ERROR(errno, "cannot set lov EA on '%s'", dst); rc = -errno; + CT_ERROR(rc, "cannot set lov EA on '%s'", dst); } return rc; } -static void bandwidth_ctl_delay(int wsize) -{ - static unsigned long long tot_bytes; - static time_t start_time; - static time_t last_time; - time_t now = time(0); - double tot_time; - double excess; - unsigned int sleep_time; - - if (now > last_time + 5) { - tot_bytes = 0; - start_time = last_time = now; - } - - tot_bytes += wsize; - tot_time = now - start_time; - if (tot_time < 1) - tot_time = 1; - - excess = tot_bytes - tot_time * opt.o_bandwidth; - sleep_time = excess * 1000000 / opt.o_bandwidth; - if ((now - start_time) % 10 == 1) - CT_TRACE("bandwith control: excess=%E sleep for %dus", excess, - sleep_time); - - if (excess > 0) - usleep(sleep_time); - - last_time = now; -} - static int ct_copy_data(struct hsm_copyaction_private *hcp, const char *src, const char *dst, int src_fd, int dst_fd, const struct hsm_action_item *hai, long hal_flags) @@ -534,11 +535,14 @@ static int ct_copy_data(struct hsm_copyaction_private *hcp, const char *src, struct stat dst_st; char *buf = NULL; __u64 write_total = 0; - __u64 length; - time_t last_print_time = time(NULL); + __u64 length = hai->hai_extent.length; + time_t last_report_time; int rc = 0; - - CT_TRACE("going to copy data from '%s' to '%s'", src, dst); + double start_ct_now = ct_now(); + /* Bandwidth Control */ + time_t start_time; + time_t now; + time_t last_bw_print; if (fstat(src_fd, &src_st) < 0) { rc = -errno; @@ -552,6 +556,15 @@ static int ct_copy_data(struct hsm_copyaction_private *hcp, const char *src, return rc; } + if (hai->hai_extent.offset > (__u64)src_st.st_size) { + rc = -EINVAL; + CT_ERROR(rc, "Trying to start reading past end (%ju > " + "%jd) of '%s' source file", + (uintmax_t)hai->hai_extent.offset, + (intmax_t)src_st.st_size, src); + return rc; + } + if (fstat(dst_fd, &dst_st) < 0) { rc = -errno; CT_ERROR(rc, "cannot stat '%s'", dst); @@ -564,17 +577,11 @@ static int ct_copy_data(struct hsm_copyaction_private *hcp, const char *src, return rc; } - rc = lseek(src_fd, hai->hai_extent.offset, SEEK_SET); - if (rc < 0) { - rc = -errno; - CT_ERROR(rc, - "cannot seek for read to "LPU64" (len %jd) in '%s'", - hai->hai_extent.offset, (intmax_t)src_st.st_size, src); - return rc; - } - /* Don't read beyond a given extent */ - length = min(hai->hai_extent.length, src_st.st_size); + if (length > src_st.st_size - hai->hai_extent.offset) + length = src_st.st_size - hai->hai_extent.offset; + + start_time = last_bw_print = last_report_time = time(NULL); he.offset = offset; he.length = 0; @@ -595,7 +602,8 @@ static int ct_copy_data(struct hsm_copyaction_private *hcp, const char *src, goto out; } - CT_DEBUG("Going to copy "LPU64" bytes %s -> %s\n", length, src, dst); + CT_TRACE("start copy of %ju bytes from '%s' to '%s'", + (uintmax_t)length, src, dst); while (write_total < length) { ssize_t rsize; @@ -624,14 +632,54 @@ static int ct_copy_data(struct hsm_copyaction_private *hcp, const char *src, write_total += wsize; offset += wsize; - if (opt.o_bandwidth != 0) - /* sleep if needed, to honor bandwidth limits */ - bandwidth_ctl_delay(wsize); + now = time(NULL); + /* sleep if needed, to honor bandwidth limits */ + if (opt.o_bandwidth != 0) { + unsigned long long write_theory; + + write_theory = (now - start_time) * opt.o_bandwidth; + + if (write_theory < write_total) { + unsigned long long excess; + struct timespec delay; + + excess = write_total - write_theory; - if (time(0) >= last_print_time + opt.o_report_int) { - last_print_time = time(0); - CT_TRACE("%%"LPU64" ", 100 * write_total / length); - he.length = write_total; + delay.tv_sec = excess / opt.o_bandwidth; + delay.tv_nsec = (excess % opt.o_bandwidth) * + NSEC_PER_SEC / opt.o_bandwidth; + + if (now >= last_bw_print + opt.o_report_int) { + CT_TRACE("bandwith control: %lluB/s " + "excess=%llu sleep for " + "%lld.%09lds", + opt.o_bandwidth, excess, + (long long)delay.tv_sec, + delay.tv_nsec); + last_bw_print = now; + } + + do { + rc = nanosleep(&delay, &delay); + } while (rc < 0 && errno == EINTR); + if (rc < 0) { + CT_ERROR(errno, "delay for bandwidth " + "control failed to sleep: " + "residual=%lld.%09lds", + (long long)delay.tv_sec, + delay.tv_nsec); + rc = 0; + } + } + } + + now = time(NULL); + if (now >= last_report_time + opt.o_report_int) { + last_report_time = now; + CT_TRACE("%%%ju ", (uintmax_t)(100 * write_total / length)); + /* only give the length of the write since the last + * progress report */ + he.length = offset - he.offset; rc = llapi_hsm_action_progress(hcp, &he, length, 0); if (rc < 0) { /* Action has been canceled or something wrong @@ -640,6 +688,7 @@ static int ct_copy_data(struct hsm_copyaction_private *hcp, const char *src, " '%s'->'%s' failed", src, dst); goto out; } + he.offset = offset; } rc = 0; } @@ -668,6 +717,9 @@ out: if (buf != NULL) free(buf); + CT_TRACE("copied %ju bytes in %f seconds", + (uintmax_t)length, ct_now() - start_ct_now); + return rc; } @@ -742,14 +794,14 @@ static int ct_copy_xattr(const char *src, const char *dst, int src_fd, } static int ct_path_lustre(char *buf, int sz, const char *mnt, - const lustre_fid *fid) + const struct lu_fid *fid) { return snprintf(buf, sz, "%s/%s/fid/"DFID_NOBRACE, mnt, dot_lustre_name, PFID(fid)); } static int ct_path_archive(char *buf, int sz, const char *archive_dir, - const lustre_fid *fid) + const struct lu_fid *fid) { return snprintf(buf, sz, "%s/%04x/%04x/%04x/%04x/%04x/%04x/" DFID_NOBRACE, archive_dir, @@ -800,8 +852,8 @@ static int ct_fini(struct hsm_copyaction_private **phcp, int rc; CT_TRACE("Action completed, notifying coordinator " - "cookie="LPX64", FID="DFID", hp_flags=%d err=%d", - hai->hai_cookie, PFID(&hai->hai_fid), + "cookie=%#jx, FID="DFID", hp_flags=%d err=%d", + (uintmax_t)hai->hai_cookie, PFID(&hai->hai_fid), hp_flags, -ct_rc); ct_path_lustre(lstr, sizeof(lstr), opt.o_mnt, &hai->hai_fid); @@ -819,8 +871,8 @@ static int ct_fini(struct hsm_copyaction_private **phcp, rc = llapi_hsm_action_end(phcp, &hai->hai_extent, hp_flags, abs(ct_rc)); if (rc == -ECANCELED) CT_ERROR(rc, "completed action on '%s' has been canceled: " - "cookie="LPX64", FID="DFID, lstr, hai->hai_cookie, - PFID(&hai->hai_fid)); + "cookie=%#jx, FID="DFID, lstr, + (uintmax_t)hai->hai_cookie, PFID(&hai->hai_fid)); else if (rc < 0) CT_ERROR(rc, "llapi_hsm_action_end() on '%s' failed", lstr); else @@ -834,7 +886,8 @@ static int ct_archive(const struct hsm_action_item *hai, const long hal_flags) { struct hsm_copyaction_private *hcp = NULL; char src[PATH_MAX]; - char dst[PATH_MAX] = ""; + char dst[PATH_MAX + 4] = ""; + char root[PATH_MAX] = ""; int rc; int rcf = 0; bool rename_needed = false; @@ -852,14 +905,16 @@ static int ct_archive(const struct hsm_action_item *hai, const long hal_flags) * destination = lustre FID */ ct_path_lustre(src, sizeof(src), opt.o_mnt, &hai->hai_dfid); - ct_path_archive(dst, sizeof(dst), opt.o_hsm_root, &hai->hai_fid); + ct_path_archive(root, sizeof(root), opt.o_hsm_root, &hai->hai_fid); if (hai->hai_extent.length == -1) { /* whole file, write it to tmp location and atomically * replace old archived file */ - strncat(dst, "_tmp", sizeof(dst) - strlen(dst) - 1); + snprintf(dst, sizeof(dst), "%s_tmp", root); /* we cannot rely on the same test because ct_copy_data() * updates hai_extent.length */ rename_needed = true; + } else { + snprintf(dst, sizeof(dst), "%s", root); } CT_TRACE("archiving '%s' to '%s'", src, dst); @@ -877,12 +932,12 @@ static int ct_archive(const struct hsm_action_item *hai, const long hal_flags) src_fd = llapi_hsm_action_get_fd(hcp); if (src_fd < 0) { - rc = -errno; + rc = src_fd; CT_ERROR(rc, "cannot open '%s' for read", src); goto fini_major; } - open_flags = O_WRONLY | O_NOFOLLOW | O_NONBLOCK; + open_flags = O_WRONLY | O_NOFOLLOW; /* If extent is specified, don't truncate an old archived copy */ open_flags |= ((hai->hai_extent.length == -1) ? O_TRUNC : 0) | O_CREAT; @@ -1081,7 +1136,7 @@ static int ct_restore(const struct hsm_action_item *hai, const long hal_flags) int hp_flags = 0; int src_fd = -1; int dst_fd = -1; - int mdt_index = -1; /* Not implemented */ + int mdt_index = -1; int open_flags = 0; bool set_lovea; struct lu_fid dfid; @@ -1093,6 +1148,13 @@ static int ct_restore(const struct hsm_action_item *hai, const long hal_flags) /* build backend file name from released file FID */ ct_path_archive(src, sizeof(src), opt.o_hsm_root, &hai->hai_fid); + rc = llapi_get_mdt_index_by_fid(opt.o_mnt_fd, &hai->hai_fid, + &mdt_index); + if (rc < 0) { + CT_ERROR(rc, "cannot get mdt index "DFID"", + PFID(&hai->hai_fid)); + return rc; + } /* restore loads and sets the LOVEA w/o interpreting it to avoid * dependency on the structure format. */ rc = ct_load_stripe(src, lov_buf, &lov_size); @@ -1128,7 +1190,7 @@ static int ct_restore(const struct hsm_action_item *hai, const long hal_flags) goto fini; } - src_fd = open(src, O_RDONLY | O_NOATIME | O_NONBLOCK | O_NOFOLLOW); + src_fd = open(src, O_RDONLY | O_NOATIME | O_NOFOLLOW); if (src_fd < 0) { rc = -errno; CT_ERROR(rc, "cannot open '%s' for read", src); @@ -1136,6 +1198,11 @@ static int ct_restore(const struct hsm_action_item *hai, const long hal_flags) } dst_fd = llapi_hsm_action_get_fd(hcp); + if (dst_fd < 0) { + rc = dst_fd; + CT_ERROR(rc, "cannot open '%s' for write", dst); + goto fini; + } if (set_lovea) { /* the layout cannot be allocated through .fid so we have to @@ -1178,7 +1245,7 @@ fini: static int ct_remove(const struct hsm_action_item *hai, const long hal_flags) { struct hsm_copyaction_private *hcp = NULL; - char dst[PATH_MAX]; + char dst[PATH_MAX], attr[PATH_MAX + 4]; int rc; rc = ct_begin(&hcp, hai); @@ -1202,11 +1269,11 @@ static int ct_remove(const struct hsm_action_item *hai, const long hal_flags) goto fini; } - strncat(dst, ".lov", sizeof(dst) - strlen(dst) - 1); - rc = unlink(dst); + snprintf(attr, sizeof(attr), "%s.lov", dst); + rc = unlink(attr); if (rc < 0) { rc = -errno; - CT_ERROR(rc, "cannot unlink '%s'", dst); + CT_ERROR(rc, "cannot unlink '%s'", attr); err_minor++; goto fini; } @@ -1229,9 +1296,9 @@ static int ct_process_item(struct hsm_action_item *hai, const long hal_flags) int linkno = 0; sprintf(fid, DFID, PFID(&hai->hai_fid)); - CT_TRACE("'%s' action %s reclen %d, cookie="LPX64, + CT_TRACE("'%s' action %s reclen %d, cookie=%#jx", fid, hsm_copytool_action2name(hai->hai_action), - hai->hai_len, hai->hai_cookie); + hai->hai_len, (uintmax_t)hai->hai_cookie); rc = llapi_fid2path(opt.o_mnt, fid, path, sizeof(path), &recno, &linkno); if (rc < 0) @@ -1332,7 +1399,7 @@ static int ct_process_item_async(const struct hsm_action_item *hai, static int ct_import_one(const char *src, const char *dst) { char newarc[PATH_MAX]; - lustre_fid fid; + struct lu_fid fid; struct stat st; int rc; @@ -1390,7 +1457,7 @@ static char *path_concat(const char *dirname, const char *basename) return result; } -static int ct_import_fid(const lustre_fid *import_fid) +static int ct_import_fid(const struct lu_fid *import_fid) { char fid_path[PATH_MAX]; int rc; @@ -1414,9 +1481,9 @@ static int ct_import_fid(const lustre_fid *import_fid) static int ct_import_recurse(const char *relpath) { DIR *dir; - struct dirent ent, *cookie = NULL; + struct dirent *ent; char *srcpath, *newpath; - lustre_fid import_fid; + struct lu_fid import_fid; int rc; if (relpath == NULL) @@ -1451,31 +1518,20 @@ static int ct_import_recurse(const char *relpath) } free(srcpath); - while (1) { - rc = readdir_r(dir, &ent, &cookie); - if (rc != 0) { - rc = -errno; - CT_ERROR(rc, "cannot readdir_r '%s'", relpath); - err_major++; - goto out; - } else if ((rc == 0) && (cookie == NULL)) { - /* end of directory */ - break; - } - - if (!strcmp(ent.d_name, ".") || - !strcmp(ent.d_name, "..")) + while ((ent = readdir(dir)) != NULL) { + if (!strcmp(ent->d_name, ".") || + !strcmp(ent->d_name, "..")) continue; /* New relative path */ - newpath = path_concat(relpath, ent.d_name); + newpath = path_concat(relpath, ent->d_name); if (newpath == NULL) { err_major++; rc = -ENOMEM; goto out; } - if (ent.d_type == DT_DIR) { + if (ent->d_type == DT_DIR) { rc = ct_import_recurse(newpath); } else { char src[PATH_MAX]; @@ -1510,7 +1566,8 @@ out: return rc; } -static int ct_rebind_one(const lustre_fid *old_fid, const lustre_fid *new_fid) +static int ct_rebind_one(const struct lu_fid *old_fid, + const struct lu_fid *new_fid) { char src[PATH_MAX]; char dst[PATH_MAX]; @@ -1522,6 +1579,9 @@ static int ct_rebind_one(const lustre_fid *old_fid, const lustre_fid *new_fid) ct_path_archive(dst, sizeof(dst), opt.o_hsm_root, new_fid); if (!opt.o_dry_run) { + char src_attr[PATH_MAX + 4]; + char dst_attr[PATH_MAX + 4]; + ct_mkdir_p(dst); if (rename(src, dst)) { rc = -errno; @@ -1529,16 +1589,17 @@ static int ct_rebind_one(const lustre_fid *old_fid, const lustre_fid *new_fid) return -errno; } /* rename lov file */ - strncat(src, ".lov", sizeof(src) - strlen(src) - 1); - strncat(dst, ".lov", sizeof(dst) - strlen(dst) - 1); - if (rename(src, dst)) - CT_ERROR(errno, "cannot rename '%s' to '%s'", src, dst); + snprintf(src_attr, sizeof(src_attr), "%s.lov", src); + snprintf(dst_attr, sizeof(dst_attr), "%s.lov", dst); + if (rename(src_attr, dst_attr)) + CT_ERROR(errno, "cannot rename '%s' to '%s'", + src_attr, dst_attr); } return 0; } -static bool fid_is_file(lustre_fid *fid) +static bool fid_is_file(struct lu_fid *fid) { return fid_is_norm(fid) || fid_is_igif(fid); } @@ -1578,8 +1639,8 @@ static int ct_rebind_list(const char *list) /* each line consists of 2 FID */ while ((r = getline(&line, &line_size, filp)) != -1) { - lustre_fid old_fid; - lustre_fid new_fid; + struct lu_fid old_fid; + struct lu_fid new_fid; /* Ignore empty and commented out ('#...') lines. */ if (should_ignore_line(line)) @@ -1608,7 +1669,7 @@ static int ct_rebind_list(const char *list) if (line) free(line); - /* return 0 if all rebinds were sucessful */ + /* return 0 if all rebinds were successful */ CT_TRACE("%u lines read from '%s', %u rebind successful", nl, list, ok); return ok == nl ? 0 : -1; @@ -1619,8 +1680,8 @@ static int ct_rebind(void) int rc; if (opt.o_dst) { - lustre_fid old_fid; - lustre_fid new_fid; + struct lu_fid old_fid; + struct lu_fid new_fid; if (sscanf(opt.o_src, SFID, RFID(&old_fid)) != 3 || !fid_is_file(&old_fid)) { @@ -1652,7 +1713,7 @@ static int ct_dir_level_max(const char *dirpath, __u16 *sub_seqmax) DIR *dir; int rc; __u16 sub_seq; - struct dirent ent, *cookie = NULL; + struct dirent *ent; *sub_seqmax = 0; @@ -1663,26 +1724,29 @@ static int ct_dir_level_max(const char *dirpath, __u16 *sub_seqmax) return rc; } - while ((rc = readdir_r(dir, &ent, &cookie)) == 0) { - if (cookie == NULL) + do { + errno = 0; + ent = readdir(dir); + if (ent == NULL) { /* end of directory. * rc is 0 and seqmax contains the max value. */ + rc = -errno; + if (rc) + CT_ERROR(rc, "cannot readdir '%s'", dirpath); goto out; + } - if (!strcmp(ent.d_name, ".") || !strcmp(ent.d_name, "..")) + if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..")) continue; - if (sscanf(ent.d_name, "%hx", &sub_seq) != 1) { + if (sscanf(ent->d_name, "%hx", &sub_seq) != 1) { CT_TRACE("'%s' has an unexpected dirname format, " - "skip entry", ent.d_name); + "skip entry", ent->d_name); continue; } if (sub_seq > *sub_seqmax) *sub_seqmax = sub_seq; - } - rc = -errno; - CT_ERROR(rc, "cannot readdir_r '%s'", dirpath); - + } while (1); out: closedir(dir); return rc; @@ -1690,24 +1754,31 @@ out: static int ct_max_sequence(void) { - int rc, i; - char path[PATH_MAX]; - __u64 seq = 0; - __u16 subseq; + int rc, i; + char path[PATH_MAX]; + __u64 seq = 0; + __u16 subseq; - strncpy(path, opt.o_hsm_root, sizeof(path)); + snprintf(path, sizeof(path), "%s", opt.o_hsm_root); /* FID sequence is stored in top-level directory names: * hsm_root/16bits (high weight)/16 bits/16 bits/16 bits (low weight). */ for (i = 0; i < 4; i++) { + size_t path_len; + rc = ct_dir_level_max(path, &subseq); if (rc != 0) return rc; seq |= ((__u64)subseq << ((3 - i) * 16)); - sprintf(path + strlen(path), "/%04x", subseq); + path_len = strlen(path); + rc = snprintf(path + path_len, sizeof(path) - path_len, + "/%04x", subseq); + if (rc >= (sizeof(path) - path_len)) + return -E2BIG; + path[sizeof(path) - 1] = '\0'; } - printf("max_sequence: "LPX64"\n", seq); + printf("max_sequence: %#jx\n", (uintmax_t)seq); return 0; } @@ -1720,13 +1791,18 @@ static void handler(int signal) * does successfully unmount and the mount is actually gone, but the * mtab entry remains. So this just makes mtab happier. */ llapi_hsm_copytool_unregister(&ctdata); + + /* Also remove fifo upon signal as during normal/error exit */ + if (opt.o_event_fifo != NULL) + llapi_hsm_unregister_event_fifo(opt.o_event_fifo); _exit(1); } /* Daemon waits for messages from the kernel; run it in the background. */ static int ct_run(void) { - int rc; + struct sigaction cleanup_sigaction; + int rc; if (opt.o_daemonize) { rc = daemon(1, 1); @@ -1748,21 +1824,25 @@ static int ct_run(void) llapi_error_callback_set(llapi_hsm_log_error); } - rc = llapi_hsm_copytool_register(&ctdata, opt.o_mnt, 0, - opt.o_archive_cnt, opt.o_archive_id); + rc = llapi_hsm_copytool_register(&ctdata, opt.o_mnt, + opt.o_archive_cnt, + opt.o_archive_id, 0); if (rc < 0) { CT_ERROR(rc, "cannot start copytool interface"); return rc; } - signal(SIGINT, handler); - signal(SIGTERM, handler); + memset(&cleanup_sigaction, 0, sizeof(cleanup_sigaction)); + cleanup_sigaction.sa_handler = handler; + sigemptyset(&cleanup_sigaction.sa_mask); + sigaction(SIGINT, &cleanup_sigaction, NULL); + sigaction(SIGTERM, &cleanup_sigaction, NULL); while (1) { - struct hsm_action_list *hal; - struct hsm_action_item *hai; - int msgsize; - int i = 0; + struct hsm_action_list *hal; + struct hsm_action_item *hai; + int msgsize; + int i = 0; CT_TRACE("waiting for message from kernel"); @@ -1770,8 +1850,6 @@ static int ct_run(void) if (rc == -ESHUTDOWN) { CT_TRACE("shutting down"); break; - } else if (rc == -EAGAIN) { - continue; /* msg not for us */ } else if (rc < 0) { CT_WARN("cannot receive action list: %s", strerror(-rc)); @@ -1815,8 +1893,6 @@ static int ct_run(void) hai = hai_next(hai); } - llapi_hsm_action_list_free(&hal); - if (opt.o_abort_on_error && err_major) break; } @@ -1846,7 +1922,15 @@ static int ct_setup(void) if (rc < 0) { CT_ERROR(rc, "cannot find a Lustre filesystem mounted at '%s'", opt.o_mnt); - return -rc; + return rc; + } + + opt.o_mnt_fd = open(opt.o_mnt, O_RDONLY); + if (opt.o_mnt_fd < 0) { + rc = -errno; + CT_ERROR(rc, "cannot open mount point at '%s'", + opt.o_mnt); + return rc; } return rc; @@ -1856,13 +1940,22 @@ static int ct_cleanup(void) { int rc; - if (arc_fd < 0) - return 0; + if (opt.o_mnt_fd >= 0) { + rc = close(opt.o_mnt_fd); + if (rc < 0) { + rc = -errno; + CT_ERROR(rc, "cannot close mount point"); + return rc; + } + } - if (close(arc_fd) < 0) { - rc = -errno; - CT_ERROR(rc, "cannot close archive root directory"); - return rc; + if (arc_fd >= 0) { + rc = close(arc_fd); + if (rc < 0) { + rc = -errno; + CT_ERROR(rc, "cannot close archive root directory"); + return rc; + } } return 0; @@ -1872,14 +1965,16 @@ int main(int argc, char **argv) { int rc; - strncpy(cmd_name, basename(argv[0]), sizeof(cmd_name)); + snprintf(cmd_name, sizeof(cmd_name), "%s", basename(argv[0])); rc = ct_parseopts(argc, argv); if (rc < 0) { CT_WARN("try '%s --help' for more information", cmd_name); return -rc; } - ct_setup(); + rc = ct_setup(); + if (rc < 0) + goto error_cleanup; switch (opt.o_action) { case CA_IMPORT: @@ -1901,6 +1996,7 @@ int main(int argc, char **argv) " rc=%d (%s)", err_major, err_minor, rc, strerror(-rc)); +error_cleanup: ct_cleanup(); return -rc;