X-Git-Url: https://git.whamcloud.com/?a=blobdiff_plain;f=lustre%2Futils%2Fliblustreapi_hsm.c;h=78ab4d87f61bd1d87c4c0db64f63a23653e871a0;hb=1305c503ce158b3a8a65b8f03b54a3f4894c5108;hp=3f1b8b9fe2282b39dce381a652050a327c4bfb17;hpb=45c9ef1dfff207086665c764c7d500c00aa03c7f;p=fs%2Flustre-release.git diff --git a/lustre/utils/liblustreapi_hsm.c b/lustre/utils/liblustreapi_hsm.c index 3f1b8b9..78ab4d8 100644 --- a/lustre/utils/liblustreapi_hsm.c +++ b/lustre/utils/liblustreapi_hsm.c @@ -6,6 +6,8 @@ * (C) Copyright 2012 Commissariat a l'energie atomique et aux energies * alternatives * + * Copyright (c) 2013, 2014, Intel Corporation. + * * All rights reserved. This program and the accompanying materials * are made available under the terms of the GNU Lesser General Public License * (LGPL) version 2.1 or (at your discretion) any later version. @@ -41,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -53,9 +56,8 @@ #include #endif -#include #include -#include +#include #include #include "lustreapi_internal.h" @@ -66,9 +68,10 @@ struct hsm_copytool_private { int magic; char *mnt; + struct kuc_hdr *kuch; int mnt_fd; int open_by_fid_fd; - lustre_kernelcomm kuc; + struct lustre_kernelcomm kuc; __u32 archives; }; @@ -78,11 +81,9 @@ struct hsm_copyaction_private { __s32 data_fd; const struct hsm_copytool_private *ct_priv; struct hsm_copy copy; - struct stat stat; + lstat_t stat; }; -#include - enum ct_progress_type { CT_START = 0, CT_RUNNING = 50, @@ -113,7 +114,8 @@ enum ct_event { }; /* initialized in llapi_hsm_register_event_fifo() */ -FILE *llapi_hsm_event_fp; +static int llapi_hsm_event_fd = -1; +static bool created_hsm_event_fifo; static inline const char *llapi_hsm_ct_ev2str(int type) { @@ -169,16 +171,18 @@ static inline const char *llapi_hsm_ct_ev2str(int type) * \retval 0 on success. * \retval -errno on error. */ -int llapi_hsm_write_json_event(struct llapi_json_item_list **event) +static int llapi_hsm_write_json_event(struct llapi_json_item_list **event) { int rc; char time_string[40]; + char json_buf[PIPE_BUF]; + FILE *buf_file; time_t event_time = time(0); struct tm time_components; struct llapi_json_item_list *json_items; - /* Noop unless the event fp was initialized */ - if (llapi_hsm_event_fp == NULL) + /* Noop unless the event fd was initialized */ + if (llapi_hsm_event_fd < 0) return 0; if (event == NULL || *event == NULL) @@ -203,21 +207,24 @@ int llapi_hsm_write_json_event(struct llapi_json_item_list **event) return rc; } - rc = llapi_json_write_list(event, llapi_hsm_event_fp); - if (rc < 0) { - /* Ignore write failures due to missing reader. */ - if (rc == -EPIPE) - return 0; + buf_file = fmemopen(json_buf, sizeof(json_buf), "w"); + if (buf_file == NULL) + return -errno; - /* Skip llapi_error() here because there's no point - * in creating a JSON-formatted error message about - * failing to write a JSON-formatted message. - */ - fprintf(stderr, - "\nFATAL ERROR IN llapi_hsm_write_list(): rc %d", rc); + rc = llapi_json_write_list(event, buf_file); + if (rc < 0) { + fclose(buf_file); return rc; } + fclose(buf_file); + + if (write(llapi_hsm_event_fd, json_buf, strlen(json_buf)) < 0) { + /* Ignore write failures due to missing reader. */ + if (errno != EPIPE) + return -errno; + } + return 0; } @@ -232,14 +239,18 @@ int llapi_hsm_write_json_event(struct llapi_json_item_list **event) * \retval 0 on success. * \retval -errno on error. */ -int llapi_hsm_log_ct_registration(struct hsm_copytool_private **priv, - __u32 event_type) +static int llapi_hsm_log_ct_registration(struct hsm_copytool_private **priv, + __u32 event_type) { int rc; char agent_uuid[UUID_MAX]; struct hsm_copytool_private *ct; struct llapi_json_item_list *json_items; + /* Noop unless the event fd was initialized */ + if (llapi_hsm_event_fd < 0) + return 0; + if (priv == NULL || *priv == NULL) return -EINVAL; @@ -304,16 +315,28 @@ out_free: * llapi_hsm_write_json_event: * * Copytool registration and deregistration: - * {"event_time": "2014-02-26 14:58:01 -0500", "event_type": "REGISTER", "archive": 0, "mount_point": "/mnt/lustre", "uuid": "80379a60-1f8a-743f-daf2-307cde793ec2"} - * {"event_time": "2014-02-26 14:58:01 -0500", "event_type": "UNREGISTER", "archive": 0, "mount_point": "/mnt/lustre", "uuid": "80379a60-1f8a-743f-daf2-307cde793ec2"} + * {"event_time": "2014-02-26 14:58:01 -0500", "event_type": "REGISTER", + * "archive": 0, "mount_point": "/mnt/lustre", + * "uuid": "80379a60-1f8a-743f-daf2-307cde793ec2"} + * {"event_time": "2014-02-26 14:58:01 -0500", "event_type": "UNREGISTER", + * "archive": 0, "mount_point": "/mnt/lustre", + * "uuid": "80379a60-1f8a-743f-daf2-307cde793ec2"} * * An archive action, start to completion: - * {"event_time": "2014-02-26 14:50:13 -0500", "event_type": "ARCHIVE_START", "total_bytes": 0, "lustre_path": "d71.sanity-hsm/f71.sanity-hsm", "source_fid": "0x2000013a1:0x2:0x0", "data_fid": "0x2000013a1:0x2:0x0"} - * {"event_time": "2014-02-26 14:50:18 -0500", "event_type": "ARCHIVE_RUNNING", "current_bytes": 5242880, "total_bytes": 39000000, "lustre_path": "d71.sanity-hsm/f71.sanity-hsm", "source_fid": "0x2000013a1:0x2:0x0", "data_fid": "0x2000013a1:0x2:0x0"} - * {"event_time": "2014-02-26 14:50:50 -0500", "event_type": "ARCHIVE_FINISH", "source_fid": "0x2000013a1:0x2:0x0", "data_fid": "0x2000013a1:0x2:0x0"} + * {"event_time": "2014-02-26 14:50:13 -0500", "event_type": "ARCHIVE_START", + * "total_bytes": 0, "lustre_path": "d71.sanity-hsm/f71.sanity-hsm", + * "source_fid": "0x2000013a1:0x2:0x0", "data_fid": "0x2000013a1:0x2:0x0"} + * {"event_time": "2014-02-26 14:50:18 -0500", "event_type": "ARCHIVE_RUNNING", + * "current_bytes": 5242880, "total_bytes": 39000000, + * "lustre_path": "d71.sanity-hsm/f71.sanity-hsm", + * "source_fid": "0x2000013a1:0x2:0x0", "data_fid": "0x2000013a1:0x2:0x0"} + * {"event_time": "2014-02-26 14:50:50 -0500", "event_type": "ARCHIVE_FINISH", + * "source_fid": "0x2000013a1:0x2:0x0", "data_fid": "0x2000013a1:0x2:0x0"} * * A log message: - * {"event_time": "2014-02-26 14:50:13 -0500", "event_type": "LOGGED_MESSAGE", "level": "INFO", "message": "lhsmtool_posix[59401]: copytool fs=lustre archive#=2 item_count=1"} + * {"event_time": "2014-02-26 14:50:13 -0500", "event_type": "LOGGED_MESSAGE", + * "level": "INFO", + * "message": "lhsmtool_posix[42]: copytool fs=lustre archive#=2 item_count=1"} * * \param hcp Opaque action handle returned by * llapi_hsm_action_start. @@ -325,9 +348,10 @@ out_free: * \retval 0 on success. * \retval -errno on error. */ -int llapi_hsm_log_ct_progress(struct hsm_copyaction_private **phcp, - const struct hsm_action_item *hai, __u32 progress_type, - __u64 total, __u64 current) +static int llapi_hsm_log_ct_progress(struct hsm_copyaction_private **phcp, + const struct hsm_action_item *hai, + __u32 progress_type, + __u64 total, __u64 current) { int rc; int linkno = 0; @@ -337,6 +361,10 @@ int llapi_hsm_log_ct_progress(struct hsm_copyaction_private **phcp, struct hsm_copyaction_private *hcp; struct llapi_json_item_list *json_items; + /* Noop unless the event fd was initialized */ + if (llapi_hsm_event_fd < 0) + return 0; + if (phcp == NULL || *phcp == NULL) return -EINVAL; @@ -441,9 +469,9 @@ out_free: * \retval 0 on success. * \retval -errno on error. */ -int llapi_hsm_register_event_fifo(char *path) +int llapi_hsm_register_event_fifo(const char *path) { - int read_fd, write_fd; + int read_fd; struct stat statbuf; /* Create the FIFO if necessary. */ @@ -463,6 +491,8 @@ int llapi_hsm_register_event_fifo(char *path) "not a pipe or has a wrong mode", path); return -errno; } + } else { + created_hsm_event_fifo = true; } /* Open the FIFO for read so that the subsequent open for write @@ -476,8 +506,8 @@ int llapi_hsm_register_event_fifo(char *path) /* Open the FIFO for writes, but don't block on waiting * for a reader. */ - write_fd = open(path, O_WRONLY | O_NONBLOCK); - if (write_fd < 0) { + llapi_hsm_event_fd = open(path, O_WRONLY | O_NONBLOCK); + if (llapi_hsm_event_fd < 0) { llapi_error(LLAPI_MSG_ERROR, errno, "cannot open(%s) for write", path); return -errno; @@ -488,19 +518,9 @@ int llapi_hsm_register_event_fifo(char *path) * events are lost. NOTE: Only one reader at a time! */ close(read_fd); - llapi_hsm_event_fp = fdopen(write_fd, "w"); - if (llapi_hsm_event_fp == NULL) { - llapi_error(LLAPI_MSG_ERROR, errno, - "cannot fdopen(%s) for write", path); - return -errno; - } - /* Ignore SIGPIPEs -- can occur if the reader goes away. */ signal(SIGPIPE, SIG_IGN); - /* Don't buffer the event stream. */ - setbuf(llapi_hsm_event_fp, NULL); - return 0; } @@ -512,18 +532,21 @@ int llapi_hsm_register_event_fifo(char *path) * \retval 0 on success. * \retval -errno on error. */ -int llapi_hsm_unregister_event_fifo(char *path) +int llapi_hsm_unregister_event_fifo(const char *path) { - /* Noop unless the event fp was initialized */ - if (llapi_hsm_event_fp == NULL) + /* Noop unless the event fd was initialized */ + if (llapi_hsm_event_fd < 0) return 0; - if (fclose(llapi_hsm_event_fp) != 0) + if (close(llapi_hsm_event_fd) < 0) return -errno; - unlink(path); + if (created_hsm_event_fifo) { + unlink(path); + created_hsm_event_fifo = false; + } - llapi_hsm_event_fp = NULL; + llapi_hsm_event_fd = -1; return 0; } @@ -550,8 +573,8 @@ void llapi_hsm_log_error(enum llapi_message_level level, int _rc, va_list args2; struct llapi_json_item_list *json_items; - /* Noop unless the event fp was initialized */ - if (llapi_hsm_event_fp == NULL) + /* Noop unless the event fd was initialized */ + if (llapi_hsm_event_fd < 0) return; rc = llapi_json_init_list(&json_items); @@ -631,15 +654,20 @@ out_free: } /** Register a copytool - * \param[out] priv Opaque private control structure - * \param mnt Lustre filesystem mount point - * \param flags Open flags, currently unused (e.g. O_NONBLOCK) - * \param archive_count - * \param archives Which archive numbers this copytool is responsible for + * \param[out] priv Opaque private control structure + * \param mnt Lustre filesystem mount point + * \param archive_count Number of valid archive IDs in \a archives + * \param archives Which archive numbers this copytool is + * responsible for + * \param rfd_flags flags applied to read fd of pipe + * (e.g. O_NONBLOCK) + * + * \retval 0 on success. + * \retval -errno on error. */ int llapi_hsm_copytool_register(struct hsm_copytool_private **priv, - const char *mnt, int flags, int archive_count, - int *archives) + const char *mnt, int archive_count, + int *archives, int rfd_flags) { struct hsm_copytool_private *ct; int rc; @@ -650,6 +678,13 @@ int llapi_hsm_copytool_register(struct hsm_copytool_private **priv, return -EINVAL; } + if (archive_count > LL_HSM_MAX_ARCHIVE) { + llapi_err_noerrno(LLAPI_MSG_ERROR, "%d requested when maximum " + "of %zu archives supported", archive_count, + LL_HSM_MAX_ARCHIVE); + return -EINVAL; + } + ct = calloc(1, sizeof(*ct)); if (ct == NULL) return -ENOMEM; @@ -666,6 +701,12 @@ int llapi_hsm_copytool_register(struct hsm_copytool_private **priv, goto out_err; } + ct->kuch = malloc(HAL_MAXSIZE + sizeof(*ct->kuch)); + if (ct->kuch == NULL) { + rc = -ENOMEM; + goto out_err; + } + ct->mnt_fd = open(ct->mnt, O_RDONLY); if (ct->mnt_fd < 0) { rc = -errno; @@ -681,13 +722,14 @@ int llapi_hsm_copytool_register(struct hsm_copytool_private **priv, /* no archives specified means "match all". */ ct->archives = 0; for (rc = 0; rc < archive_count; rc++) { - if (archives[rc] > 8 * sizeof(ct->archives)) { - llapi_err_noerrno(LLAPI_MSG_ERROR, - "maximum of %zu archives supported", - 8 * sizeof(ct->archives)); + if ((archives[rc] > LL_HSM_MAX_ARCHIVE) || (archives[rc] < 0)) { + llapi_err_noerrno(LLAPI_MSG_ERROR, "%d requested when " + "archive id [0 - %zu] is supported", + archives[rc], LL_HSM_MAX_ARCHIVE); + rc = -EINVAL; goto out_err; } - /* in the list we have a all archive wildcard + /* in the list we have an all archive wildcard * so move to all archives mode */ if (archives[rc] == 0) { @@ -698,7 +740,7 @@ int llapi_hsm_copytool_register(struct hsm_copytool_private **priv, ct->archives |= (1 << (archives[rc] - 1)); } - rc = libcfs_ukuc_start(&ct->kuc, KUC_GRP_HSM); + rc = libcfs_ukuc_start(&ct->kuc, KUC_GRP_HSM, rfd_flags); if (rc < 0) goto out_err; @@ -709,9 +751,7 @@ int llapi_hsm_copytool_register(struct hsm_copytool_private **priv, rc = -errno; llapi_error(LLAPI_MSG_ERROR, rc, "cannot start copytool on '%s'", mnt); - goto out_err; - } else { - rc = 0; + goto out_kuc; } llapi_hsm_log_ct_registration(&ct, CT_REGISTER); @@ -719,10 +759,8 @@ int llapi_hsm_copytool_register(struct hsm_copytool_private **priv, /* Only the kernel reference keeps the write side open */ close(ct->kuc.lk_wfd); ct->kuc.lk_wfd = LK_NOFD; - if (rc < 0) - goto out_kuc; - *priv = ct; + return 0; out_kuc: @@ -736,8 +774,9 @@ out_err: if (!(ct->open_by_fid_fd < 0)) close(ct->open_by_fid_fd); - if (ct->mnt != NULL) - free(ct->mnt); + free(ct->mnt); + + free(ct->kuch); free(ct); @@ -772,18 +811,34 @@ int llapi_hsm_copytool_unregister(struct hsm_copytool_private **priv) close(ct->open_by_fid_fd); close(ct->mnt_fd); free(ct->mnt); + free(ct->kuch); free(ct); *priv = NULL; return 0; } +/** Returns a file descriptor to poll/select on. + * \param ct Opaque private control structure + * \retval -EINVAL on error + * \retval the file descriptor for reading HSM events from the kernel + */ +int llapi_hsm_copytool_get_fd(struct hsm_copytool_private *ct) +{ + if (ct == NULL || ct->magic != CT_PRIV_MAGIC) + return -EINVAL; + + return libcfs_ukuc_get_rfd(&ct->kuc); +} + /** Wait for the next hsm_action_list * \param ct Opaque private control structure * \param halh Action list handle, will be allocated here * \param msgsize Number of bytes in the message, will be set here * \return 0 valid message received; halh and msgsize are set * <0 error code + * Note: The application must not call llapi_hsm_copytool_recv until it has + * cleared the data in ct->kuch from the previous call. */ int llapi_hsm_copytool_recv(struct hsm_copytool_private *ct, struct hsm_action_list **halh, int *msgsize) @@ -798,21 +853,20 @@ int llapi_hsm_copytool_recv(struct hsm_copytool_private *ct, if (halh == NULL || msgsize == NULL) return -EINVAL; - kuch = malloc(HAL_MAXSIZE + sizeof(*kuch)); - if (kuch == NULL) - return -ENOMEM; + kuch = ct->kuch; +repeat: rc = libcfs_ukuc_msg_get(&ct->kuc, (char *)kuch, HAL_MAXSIZE + sizeof(*kuch), KUC_TRANSPORT_HSM); if (rc < 0) - goto out_free; + goto out_err; /* Handle generic messages */ if (kuch->kuc_transport == KUC_TRANSPORT_GENERIC && kuch->kuc_msgtype == KUC_MSG_SHUTDOWN) { rc = -ESHUTDOWN; - goto out_free; + goto out_err; } if (kuch->kuc_transport != KUC_TRANSPORT_HSM || @@ -821,14 +875,14 @@ int llapi_hsm_copytool_recv(struct hsm_copytool_private *ct, "Unknown HSM message type %d:%d\n", kuch->kuc_transport, kuch->kuc_msgtype); rc = -EPROTO; - goto out_free; + goto out_err; } if (kuch->kuc_msglen < sizeof(*kuch) + sizeof(*hal)) { llapi_err_noerrno(LLAPI_MSG_ERROR, "Short HSM message %d", kuch->kuc_msglen); rc = -EPROTO; - goto out_free; + goto out_err; } /* Our message is a hsm_action_list. Use pointer math to skip @@ -845,29 +899,20 @@ int llapi_hsm_copytool_recv(struct hsm_copytool_private *ct, " ignoring this request." " Mask of served archive is 0x%.8X", hal->hal_archive_id, ct->archives); - rc = -EAGAIN; - goto out_free; + goto repeat; } *halh = hal; *msgsize = kuch->kuc_msglen - sizeof(*kuch); return 0; -out_free: +out_err: *halh = NULL; *msgsize = 0; - free(kuch); return rc; } -/** Release the action list when done with it. */ -void llapi_hsm_action_list_free(struct hsm_action_list **hal) -{ - /* Reuse the llapi_changelog_free function */ - llapi_changelog_free((struct changelog_ext_rec **)hal); -} - /** Get parent path from mount point and fid. * * \param mnt Filesystem root path. @@ -914,21 +959,60 @@ static int ct_open_by_fid(const struct hsm_copytool_private *ct, const struct lu_fid *fid, int open_flags) { char fid_name[FID_NOBRACE_LEN + 1]; + int fd; snprintf(fid_name, sizeof(fid_name), DFID_NOBRACE, PFID(fid)); - return openat(ct->open_by_fid_fd, fid_name, open_flags); + fd = openat(ct->open_by_fid_fd, fid_name, open_flags); + return fd < 0 ? -errno : fd; } -static int ct_stat_by_fid(const struct hsm_copytool_private *ct, - const struct lu_fid *fid, - struct stat *buf) +/** + * Get metadata attributes of file by FID. + * + * Use the IOC_MDC_GETFILEINFO ioctl (to send a MDS_GETATTR_NAME RPC) + * to get the attributes of the file identified by \a fid. This + * returns only the attributes stored on the MDT and avoids taking + * layout locks or accessing OST objects. It also bypasses the inode + * cache. Attributes are returned in \a st. + */ +static int ct_md_getattr(const struct hsm_copytool_private *ct, + const struct lu_fid *fid, + lstat_t *st) { - char fid_name[FID_NOBRACE_LEN + 1]; + struct lov_user_mds_data *lmd; + size_t lmd_size; + int rc; - snprintf(fid_name, sizeof(fid_name), DFID_NOBRACE, PFID(fid)); + lmd_size = sizeof(lmd->lmd_st) + + lov_user_md_size(LOV_MAX_STRIPE_COUNT, LOV_USER_MAGIC_V3); + + if (lmd_size < sizeof(lmd->lmd_st) + XATTR_SIZE_MAX) + lmd_size = sizeof(lmd->lmd_st) + XATTR_SIZE_MAX; + + if (lmd_size < FID_NOBRACE_LEN + 1) + lmd_size = FID_NOBRACE_LEN + 1; + + lmd = malloc(lmd_size); + if (lmd == NULL) + return -ENOMEM; + + snprintf((char *)lmd, lmd_size, DFID_NOBRACE, PFID(fid)); + + rc = ioctl(ct->open_by_fid_fd, IOC_MDC_GETFILEINFO, lmd); + if (rc != 0) { + rc = -errno; + llapi_error(LLAPI_MSG_ERROR, rc, + "cannot get metadata attributes of "DFID" in '%s'", + PFID(fid), ct->mnt); + goto out; + } + + *st = lmd->lmd_st; +out: + free(lmd); - return fstatat(ct->open_by_fid_fd, fid_name, buf, 0); + return rc; } /** Create the destination volatile file for a restore operation. @@ -1019,7 +1103,7 @@ int llapi_hsm_action_begin(struct hsm_copyaction_private **phcp, goto ok_out; if (hai->hai_action == HSMA_RESTORE) { - rc = ct_stat_by_fid(hcp->ct_priv, &hai->hai_fid, &hcp->stat); + rc = ct_md_getattr(hcp->ct_priv, &hai->hai_fid, &hcp->stat); if (rc < 0) goto err_out; @@ -1199,17 +1283,20 @@ int llapi_hsm_action_get_dfid(const struct hsm_copyaction_private *hcp, int llapi_hsm_action_get_fd(const struct hsm_copyaction_private *hcp) { const struct hsm_action_item *hai = &hcp->copy.hc_hai; + int fd; if (hcp->magic != CP_PRIV_MAGIC) return -EINVAL; - if (hai->hai_action == HSMA_ARCHIVE) + if (hai->hai_action == HSMA_ARCHIVE) { return ct_open_by_fid(hcp->ct_priv, &hai->hai_dfid, O_RDONLY | O_NOATIME | O_NOFOLLOW | O_NONBLOCK); - else if (hai->hai_action == HSMA_RESTORE) - return dup(hcp->data_fd); - else + } else if (hai->hai_action == HSMA_RESTORE) { + fd = dup(hcp->data_fd); + return fd < 0 ? -errno : fd; + } else { return -EINVAL; + } } /** @@ -1243,9 +1330,9 @@ int llapi_hsm_import(const char *dst, int archive, const struct stat *st, stripe_pattern | LOV_PATTERN_F_RELEASED, pool_name); if (fd < 0) { - llapi_error(LLAPI_MSG_ERROR, -errno, + llapi_error(LLAPI_MSG_ERROR, fd, "cannot create '%s' for import", dst); - return -errno; + return fd; } /* Get the new fid in Lustre. Caller needs to use this fid @@ -1268,8 +1355,8 @@ int llapi_hsm_import(const char *dst, int archive, const struct stat *st, hui.hui_mtime_ns = st->st_mtim.tv_nsec; rc = ioctl(fd, LL_IOC_HSM_IMPORT, &hui); if (rc != 0) { - llapi_error(LLAPI_MSG_ERROR, rc, "cannot import '%s'", dst); rc = -errno; + llapi_error(LLAPI_MSG_ERROR, rc, "cannot import '%s'", dst); goto out_unlink; }