X-Git-Url: https://git.whamcloud.com/?p=fs%2Flustre-release.git;a=blobdiff_plain;f=lustre%2Futils%2Fliblustreapi.c;h=1c903f82394b1f8f62d947cb924512e577688505;hp=e28f5337b8dbebbeb3ccfd19ebd84c9636f0d7b9;hb=a77212cd13627b2b9f1835c48599e91c82aeed9d;hpb=0a859380c36ac24871f221b35042f76c56b04438;ds=sidebyside diff --git a/lustre/utils/liblustreapi.c b/lustre/utils/liblustreapi.c index e28f533..1c903f8 100644 --- a/lustre/utils/liblustreapi.c +++ b/lustre/utils/liblustreapi.c @@ -26,7 +26,7 @@ * GPL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved + * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. * Use is subject to license terms. */ /* @@ -592,7 +592,7 @@ int llapi_search_mounts(const char *pathname, int index, char *mntdir, { int want = WANT_PATH, idx = -1; - if (!pathname) { + if (!pathname || pathname[0] == '\0') { want |= WANT_INDEX; idx = index; } else @@ -606,19 +606,42 @@ int llapi_search_mounts(const char *pathname, int index, char *mntdir, /* Given a path, find the corresponding Lustre fsname */ int llapi_search_fsname(const char *pathname, char *fsname) { - char *path = (char*)pathname, buf[PATH_MAX + 1]; + char *path; + int rc; - if (pathname[0] != '/') { /* Need a absolute path */ - memset(buf, '\0', sizeof(buf)); - if (realpath(pathname, buf) == NULL) { - llapi_err(LLAPI_MSG_ERROR, "pathname '%s' cannot expand", - pathname); - return -EINVAL; + path = realpath(pathname, NULL); + if (path == NULL) { + char buf[PATH_MAX + 1], *ptr; + + buf[0] = 0; + if (pathname[0] != '/') { + /* Need an absolute path, but realpath() only works for + * pathnames that actually exist. We go through the + * extra hurdle of dirname(getcwd() + pathname) in + * case the relative pathname contains ".." in it. */ + if (getcwd(buf, sizeof(buf) - 1) == NULL) + return -errno; + strcat(buf, "/"); + } + strncat(buf, pathname, sizeof(buf) - strlen(buf)); + path = realpath(buf, NULL); + if (path == NULL) { + ptr = strrchr(buf, '/'); + if (ptr == NULL) + return -ENOENT; + *ptr = '\0'; + path = realpath(buf, NULL); + if (path == NULL) { + llapi_err(LLAPI_MSG_ERROR, + "pathname '%s' cannot expand", + pathname); + return -errno; + } } - path = buf; } - return get_root_path(WANT_FSNAME | WANT_ERROR, fsname, NULL, - path, -1); + rc = get_root_path(WANT_FSNAME | WANT_ERROR, fsname, NULL, path, -1); + free(path); + return rc; } /* return the first file matching this pattern */ @@ -1357,25 +1380,179 @@ retry_get_uuids: return ret; } -static int cb_ostlist(char *path, DIR *parent, DIR *d, void *data, - struct dirent64 *de) +int llapi_ostlist(char *path, struct find_param *param) { - struct find_param *param = (struct find_param *)data; + DIR *dir; + int ret; - LASSERT(parent != NULL || d != NULL); + dir = opendir(path); + if (dir == NULL) + return -errno; - /* Prepare odb. */ - return setup_obd_uuid(d ? d : parent, path, param); + ret = setup_obd_uuid(dir, path, param); + closedir(dir); + + return ret; } -int llapi_ostlist(char *path, struct find_param *param) +/* + * Given a filesystem name, or a pathname of a file on a lustre filesystem, + * tries to determine the path to the filesystem's clilov directory under /proc + * + * fsname is limited to MTI_NAME_MAXLEN in lustre_idl.h + * The NUL terminator is compensated by the additional "%s" bytes. */ +#define LOV_LEN (sizeof("/proc/fs/lustre/lov/%s-clilov-*") + MTI_NAME_MAXLEN) +static int clilovpath(const char *fsname, const char *const pathname, + char *clilovpath) +{ + int rc; + char pattern[LOV_LEN]; + char buffer[PATH_MAX + 1]; + + if (fsname == NULL) { + if ((rc = llapi_search_fsname(pathname, buffer)) != 0) + return rc; + fsname = buffer; + } + + snprintf(pattern, sizeof(pattern), "/proc/fs/lustre/lov/%s-clilov-*", + fsname); + + if ((rc = first_match(pattern, buffer)) != 0) + return rc; + + strncpy(clilovpath, buffer, sizeof(buffer)); + + return 0; +} + +/* + * Given the path to a stripe attribute proc file, tries to open and + * read the attribute and return the value using the attr parameter + */ +static int sattr_read_attr(const char *const fpath, + unsigned int *attr) +{ + + FILE *f; + char line[PATH_MAX + 1]; + int rc = 0; + + if ((f = fopen(fpath, "r")) == NULL) { + llapi_err(LLAPI_MSG_ERROR, "Cannot open '%s'", fpath); + return errno; + } + + if (fgets(line, sizeof(line), f) != NULL) { + *attr = atoi(line); + } else { + llapi_err(LLAPI_MSG_ERROR, "Cannot read from '%s'", fpath); + rc = 1; + } + + fclose(f); + return rc; +} + +/* + * Tries to determine the default stripe attributes for a given filesystem. The + * filesystem to check should be specified by fsname, or will be determined + * using pathname. + */ +static int sattr_get_defaults(const char *const fsname, + const char *const pathname, + unsigned int *scount, + unsigned int *ssize, + unsigned int *soffset) { - return param_callback(path, cb_ostlist, cb_common_fini, param); + int rc; + char dpath[PATH_MAX + 1]; + char fpath[PATH_MAX + 1]; + + if ((rc = clilovpath(fsname, pathname, dpath)) != 0) + return rc; + + if (scount) { + snprintf(fpath, PATH_MAX, "%s/stripecount", dpath); + if ((rc = sattr_read_attr(fpath, scount)) != 0) + return rc; + } + + if (ssize) { + snprintf(fpath, PATH_MAX, "%s/stripesize", dpath); + if ((rc = sattr_read_attr(fpath, ssize)) != 0) + return rc; + } + + if (soffset) { + snprintf(fpath, PATH_MAX, "%s/stripeoffset", dpath); + if ((rc = sattr_read_attr(fpath, soffset)) != 0) + return rc; + } + + return 0; +} + +/* + * Tries to gather the default stripe attributes for a given filesystem. If + * the attributes can be determined, they are cached for easy retreival the + * next time they are needed. Only a single filesystem's attributes are + * cached at a time. + */ +static int sattr_cache_get_defaults(const char *const fsname, + const char *const pathname, + unsigned int *scount, + unsigned int *ssize, + unsigned int *soffset) +{ + static struct { + char fsname[PATH_MAX + 1]; + unsigned int stripecount; + unsigned int stripesize; + unsigned int stripeoffset; + } cache = { + .fsname = {'\0'} + }; + + int rc; + char fsname_buf[PATH_MAX + 1]; + unsigned int tmp[3]; + + if (fsname == NULL) + llapi_search_fsname(pathname, fsname_buf); + else + strncpy(fsname_buf, fsname, PATH_MAX); + + if (strncmp(fsname_buf, cache.fsname, PATH_MAX) != 0) { + /* + * Ensure all 3 sattrs (count, size, and offset) are + * successfully retrieved and stored in tmp before writing to + * cache. + */ + if ((rc = sattr_get_defaults(fsname_buf, NULL, &tmp[0], + &tmp[1], &tmp[2])) != 0) + return rc; + + cache.stripecount = tmp[0]; + cache.stripesize = tmp[1]; + cache.stripeoffset = tmp[2]; + strncpy(cache.fsname, fsname_buf, PATH_MAX); + } + + if (scount) + *scount = cache.stripecount; + if (ssize) + *ssize = cache.stripesize; + if (soffset) + *soffset = cache.stripeoffset; + + return 0; } static void lov_dump_user_lmm_header(struct lov_user_md *lum, char *path, + struct lov_user_ost_data_v1 *objects, int is_dir, int verbose, int depth, - char *pool_name) + int raw, char *pool_name) { char *prefix = is_dir ? "" : "lmm_"; char nl = is_dir ? ' ' : '\n'; @@ -1402,16 +1579,48 @@ static void lov_dump_user_lmm_header(struct lov_user_md *lum, char *path, if (verbose & ~VERBOSE_COUNT) llapi_printf(LLAPI_MSG_NORMAL, "%sstripe_count: ", prefix); - llapi_printf(LLAPI_MSG_NORMAL, "%hd%c", - (__s16)lum->lmm_stripe_count, nl); + if (is_dir) { + if (!raw && lum->lmm_stripe_count == 0) { + unsigned int scount; + if (sattr_cache_get_defaults(NULL, path, + &scount, NULL, + NULL) == 0) + llapi_printf(LLAPI_MSG_NORMAL, "%u%c", + scount, nl); + else + llapi_err(LLAPI_MSG_ERROR, + "Cannot determine default" + " stripe count."); + } else { + llapi_printf(LLAPI_MSG_NORMAL, "%d%c", + lum->lmm_stripe_count == + (typeof(lum->lmm_stripe_count))(-1) + ? -1 : lum->lmm_stripe_count, nl); + } + } else { + llapi_printf(LLAPI_MSG_NORMAL, "%hd%c", + (__s16)lum->lmm_stripe_count, nl); + } } if (verbose & VERBOSE_SIZE) { if (verbose & ~VERBOSE_SIZE) llapi_printf(LLAPI_MSG_NORMAL, "%sstripe_size: ", prefix); - llapi_printf(LLAPI_MSG_NORMAL, "%u%c", lum->lmm_stripe_size, - nl); + if (is_dir && !raw && lum->lmm_stripe_size == 0) { + unsigned int ssize; + if (sattr_cache_get_defaults(NULL, path, NULL, &ssize, + NULL) == 0) + llapi_printf(LLAPI_MSG_NORMAL, "%u%c", ssize, + nl); + else + llapi_err(LLAPI_MSG_ERROR, + "Cannot determine default" + " stripe size."); + } else { + llapi_printf(LLAPI_MSG_NORMAL, "%u%c", + lum->lmm_stripe_size, nl); + } } if ((verbose & VERBOSE_DETAIL) && !is_dir) { @@ -1423,13 +1632,21 @@ static void lov_dump_user_lmm_header(struct lov_user_md *lum, char *path, if (verbose & ~VERBOSE_OFFSET) llapi_printf(LLAPI_MSG_NORMAL, "%sstripe_offset: ", prefix); - llapi_printf(LLAPI_MSG_NORMAL, "%u%c", - lum->lmm_objects[0].l_ost_idx, nl); + if (is_dir) + llapi_printf(LLAPI_MSG_NORMAL, "%d%c", + lum->lmm_stripe_offset == + (typeof(lum->lmm_stripe_offset))(-1) ? -1 : + lum->lmm_stripe_offset, nl); + else + llapi_printf(LLAPI_MSG_NORMAL, "%u%c", + objects[0].l_ost_idx, nl); } if ((verbose & VERBOSE_POOL) && (pool_name != NULL)) { - llapi_printf(LLAPI_MSG_NORMAL, "pool: %s", pool_name); - is_dir = 1; + if (verbose & ~VERBOSE_POOL) + llapi_printf(LLAPI_MSG_NORMAL, "%spool: ", + prefix); + llapi_printf(LLAPI_MSG_NORMAL, "%s%c", pool_name, nl); } if (is_dir && (verbose != VERBOSE_OBJID)) @@ -1439,7 +1656,7 @@ static void lov_dump_user_lmm_header(struct lov_user_md *lum, char *path, void lov_dump_user_lmm_v1v3(struct lov_user_md *lum, char *pool_name, struct lov_user_ost_data_v1 *objects, char *path, int is_dir, - int obdindex, int depth, int header) + int obdindex, int depth, int header, int raw) { int i, obdstripe = (obdindex != OBD_NOT_FOUND) ? 0 : 1; @@ -1453,8 +1670,8 @@ void lov_dump_user_lmm_v1v3(struct lov_user_md *lum, char *pool_name, } if (obdstripe == 1) - lov_dump_user_lmm_header(lum, path, is_dir, header, depth, - pool_name); + lov_dump_user_lmm_header(lum, path, objects, is_dir, header, + depth, raw, pool_name); if (!is_dir && (header & VERBOSE_OBJID)) { if (obdstripe == 1) @@ -1484,7 +1701,7 @@ void llapi_lov_dump_user_lmm(struct find_param *param, param->lmd->lmd_lmm.lmm_objects, path, is_dir, param->obdindex, param->maxdepth, - param->verbose); + param->verbose, param->raw); break; case LOV_USER_MAGIC_V3: { char pool_name[LOV_MAXPOOLNAME + 1]; @@ -1497,7 +1714,7 @@ void llapi_lov_dump_user_lmm(struct find_param *param, lov_dump_user_lmm_v1v3(¶m->lmd->lmd_lmm, pool_name, objects, path, is_dir, param->obdindex, param->maxdepth, - param->verbose); + param->verbose, param->raw); break; } default: @@ -1597,28 +1814,26 @@ int llapi_file_lookup(int dirfd, const char *name) * Note: 5th actually means that the value is within the interval * (limit - margin, limit]. */ static int find_value_cmp(unsigned int file, unsigned int limit, int sign, - unsigned long long margin, int mds) + int negopt, unsigned long long margin, int mds) { + int ret = -1; + if (sign > 0) { - if (file < limit) - return mds ? 0 : 1; - } - - if (sign == 0) { - if (file <= limit && file + margin > limit) - return mds ? 0 : 1; - if (file + margin <= limit) - return mds ? 0 : -1; - } - - if (sign < 0) { - if (file > limit) - return 1; - if (mds) - return 0; + if (file <= limit) + ret = mds ? 0 : 1; + } else if (sign == 0) { + if (file <= limit && file + margin >= limit) + ret = mds ? 0 : 1; + else if (file + margin <= limit) + ret = mds ? 0 : -1; + } else if (sign < 0) { + if (file >= limit) + ret = 1; + else if (mds) + ret = 0; } - return -1; + return negopt ? ~ret + 1 : ret; } /* Check if the file time matches all the given criteria (e.g. --atime +/-N). @@ -1636,7 +1851,8 @@ static int find_time_check(lstat_t *st, struct find_param *param, int mds) /* Check if file is accepted. */ if (param->atime) { ret = find_value_cmp(st->st_atime, param->atime, - param->asign, 24 * 60 * 60, mds); + param->asign, param->exclude_atime, + 24 * 60 * 60, mds); if (ret < 0) return ret; rc = ret; @@ -1644,7 +1860,8 @@ static int find_time_check(lstat_t *st, struct find_param *param, int mds) if (param->mtime) { ret = find_value_cmp(st->st_mtime, param->mtime, - param->msign, 24 * 60 * 60, mds); + param->msign, param->exclude_mtime, + 24 * 60 * 60, mds); if (ret < 0) return ret; @@ -1656,7 +1873,8 @@ static int find_time_check(lstat_t *st, struct find_param *param, int mds) if (param->ctime) { ret = find_value_cmp(st->st_ctime, param->ctime, - param->csign, 24 * 60 * 60, mds); + param->csign, param->exclude_ctime, + 24 * 60 * 60, mds); if (ret < 0) return ret; @@ -1709,7 +1927,7 @@ static int cb_find_init(char *path, DIR *parent, DIR *dir, /* If a time or OST should be checked, the decision is not taken yet. */ if (param->atime || param->ctime || param->mtime || param->obduuid || - param->size) + param->check_size) decision = 0; ret = 0; @@ -1890,7 +2108,7 @@ obd_matches: 'glimpse-size-ioctl'. */ if (!decision && S_ISREG(st->st_mode) && param->lmd->lmd_lmm.lmm_stripe_count && - (param->size ||param->atime || param->mtime || param->ctime)) { + (param->check_size ||param->atime || param->mtime || param->ctime)) { if (param->obdindex != OBD_NOT_FOUND) { /* Check whether the obd is active or not, if it is * not active, just print the object affected by this @@ -1943,10 +2161,10 @@ obd_matches: goto decided; } - if (param->size) + if (param->check_size) decision = find_value_cmp(st->st_size, param->size, - param->size_sign, param->size_units, - 0); + param->size_sign, param->exclude_size, + param->size_units, 0); print_path: if (decision != -1) { @@ -2073,7 +2291,23 @@ static int cb_getstripe(char *path, DIR *parent, DIR *d, void *data, } if (ret) { - if (errno == ENODATA) { + if (errno == ENODATA && d != NULL) { + /* We need to "fake" the "use the default" values + * since the lmm struct is zeroed out at this point. + * The magic needs to be set in order to satisfy + * a check later on in the code path. + * The object_seq needs to be set for the "(Default)" + * prefix to be displayed. */ + struct lov_user_md *lmm = ¶m->lmd->lmd_lmm; + lmm->lmm_magic = LOV_MAGIC_V1; + if (!param->raw) + lmm->lmm_object_seq = LOV_OBJECT_GROUP_DEFAULT; + lmm->lmm_stripe_count = 0; + lmm->lmm_stripe_size = 0; + lmm->lmm_stripe_offset = -1; + goto dump; + + } else if (errno == ENODATA && parent != NULL) { if (!param->obduuid) llapi_printf(LLAPI_MSG_NORMAL, "%s has no stripe info\n", path); @@ -2097,6 +2331,7 @@ static int cb_getstripe(char *path, DIR *parent, DIR *d, void *data, return ret; } +dump: if (!param->get_mdt_index) llapi_lov_dump_user_lmm(param, path, d ? 1 : 0); @@ -2796,6 +3031,10 @@ static int root_ioctl(const char *mdtname, int opc, void *data, int *mdtidxp, *mdtidxp = index; rc = ioctl(fd, opc, data); + if (rc == -1) + rc = -errno; + else + rc = 0; if (rc && want_error) llapi_err(LLAPI_MSG_ERROR, "ioctl %d err %d", opc, rc); @@ -2824,7 +3063,6 @@ struct changelog_private { int magic; int flags; lustre_kernelcomm kuc; - char *buf; }; /** Start reading from a changelog @@ -2841,16 +3079,10 @@ int llapi_changelog_start(void **priv, int flags, const char *device, int rc; /* Set up the receiver control struct */ - cp = malloc(sizeof(*cp)); + cp = calloc(1, sizeof(*cp)); if (cp == NULL) return -ENOMEM; - cp->buf = malloc(CR_MAXSIZE); - if (cp->buf == NULL) { - rc = -ENOMEM; - goto out_free; - } - cp->magic = CHANGELOG_PRIV_MAGIC; cp->flags = flags; @@ -2876,8 +3108,6 @@ int llapi_changelog_start(void **priv, int flags, const char *device, return 0; out_free: - if (cp->buf) - free(cp->buf); free(cp); return rc; } @@ -2891,7 +3121,6 @@ int llapi_changelog_fini(void **priv) return -EINVAL; libcfs_ukuc_stop(&cp->kuc); - free(cp->buf); free(cp); *priv = NULL; return 0; @@ -2914,14 +3143,17 @@ int llapi_changelog_recv(void *priv, struct changelog_rec **rech) return -EINVAL; if (rech == NULL) return -EINVAL; + kuch = malloc(CR_MAXSIZE + sizeof(*kuch)); + if (kuch == NULL) + return -ENOMEM; repeat: - rc = libcfs_ukuc_msg_get(&cp->kuc, cp->buf, CR_MAXSIZE, + rc = libcfs_ukuc_msg_get(&cp->kuc, (char *)kuch, + CR_MAXSIZE + sizeof(*kuch), KUC_TRANSPORT_CHANGELOG); if (rc < 0) - return rc; + goto out_free; - kuch = (struct kuc_hdr *)cp->buf; if ((kuch->kuc_transport != KUC_TRANSPORT_CHANGELOG) || ((kuch->kuc_msgtype != CL_RECORD) && (kuch->kuc_msgtype != CL_EOF))) { @@ -2942,19 +3174,30 @@ repeat: } } - /* Our message is a changelog_rec */ + /* Our message is a changelog_rec. Use pointer math to skip + * kuch_hdr and point directly to the message payload. + */ *rech = (struct changelog_rec *)(kuch + 1); return 0; out_free: *rech = NULL; + free(kuch); return rc; } /** Release the changelog record when done with it. */ int llapi_changelog_free(struct changelog_rec **rech) { + if (*rech) { + /* We allocated memory starting at the kuc_hdr, but passed + * the consumer a pointer to the payload. + * Use pointer math to get back to the header. + */ + struct kuc_hdr *kuch = (struct kuc_hdr *)*rech - 1; + free(kuch); + } *rech = NULL; return 0; } @@ -2985,10 +3228,9 @@ int llapi_changelog_clear(const char *mdtname, const char *idstr, int llapi_fid2path(const char *device, const char *fidstr, char *buf, int buflen, long long *recno, int *linkno) { - char path[PATH_MAX]; struct lu_fid fid; struct getinfo_fid2path *gf; - int fd, rc; + int rc; while (*fidstr == '[') fidstr++; @@ -3001,28 +3243,19 @@ int llapi_fid2path(const char *device, const char *fidstr, char *buf, return -EINVAL; } - /* Take path or fsname */ - if (device[0] == '/') { - strcpy(path, device); - } else { - rc = get_root_path(WANT_PATH | WANT_ERROR, (char *)device, - NULL, path, -1); - if (rc < 0) - return rc; - } - sprintf(path, "%s/%s/fid/%s", path, dot_lustre_name, fidstr); - fd = open(path, O_RDONLY | O_NONBLOCK); - if (fd < 0) - return -errno; - gf = malloc(sizeof(*gf) + buflen); + if (gf == NULL) + return -ENOMEM; gf->gf_fid = fid; gf->gf_recno = *recno; gf->gf_linkno = *linkno; gf->gf_pathlen = buflen; - rc = ioctl(fd, OBD_IOC_FID2PATH, gf); + + /* Take path or fsname */ + rc = root_ioctl(device, OBD_IOC_FID2PATH, gf, NULL, 0); if (rc) { - llapi_err(LLAPI_MSG_ERROR, "ioctl err %d", rc); + if (rc != -ENOENT) + llapi_err(LLAPI_MSG_ERROR, "ioctl err %d", rc); } else { memcpy(buf, gf->gf_path, gf->gf_pathlen); *recno = gf->gf_recno; @@ -3030,7 +3263,6 @@ int llapi_fid2path(const char *device, const char *fidstr, char *buf, } free(gf); - close(fd); return rc; } @@ -3072,7 +3304,6 @@ int llapi_path2fid(const char *path, lustre_fid *fid) #define CT_PRIV_MAGIC 0xC0BE2001 struct copytool_private { int magic; - char *buf; char *fsname; lustre_kernelcomm kuc; __u32 archives; @@ -3099,13 +3330,12 @@ int llapi_copytool_start(void **priv, char *fsname, int flags, return -EINVAL; } - ct = malloc(sizeof(*ct)); + ct = calloc(1, sizeof(*ct)); if (ct == NULL) return -ENOMEM; - ct->buf = malloc(HAL_MAXSIZE); ct->fsname = malloc(strlen(fsname) + 1); - if (ct->buf == NULL || ct->fsname == NULL) { + if (ct->fsname == NULL) { rc = -ENOMEM; goto out_err; } @@ -3143,8 +3373,6 @@ int llapi_copytool_start(void **priv, char *fsname, int flags, return 0; out_err: - if (ct->buf) - free(ct->buf); if (ct->fsname) free(ct->fsname); free(ct); @@ -3166,7 +3394,6 @@ int llapi_copytool_fini(void **priv) /* Shut down the kernelcomms */ libcfs_ukuc_stop(&ct->kuc); - free(ct->buf); free(ct->fsname); free(ct); *priv = NULL; @@ -3192,13 +3419,17 @@ int llapi_copytool_recv(void *priv, struct hsm_action_list **halh, int *msgsize) if (halh == NULL || msgsize == NULL) return -EINVAL; - rc = libcfs_ukuc_msg_get(&ct->kuc, ct->buf, HAL_MAXSIZE, + kuch = malloc(HAL_MAXSIZE + sizeof(*kuch)); + if (kuch == NULL) + return -ENOMEM; + + rc = libcfs_ukuc_msg_get(&ct->kuc, (char *)kuch, + HAL_MAXSIZE + sizeof(*kuch), KUC_TRANSPORT_HSM); if (rc < 0) - return rc; + goto out_free; /* Handle generic messages */ - kuch = (struct kuc_hdr *)ct->buf; if (kuch->kuc_transport == KUC_TRANSPORT_GENERIC && kuch->kuc_msgtype == KUC_MSG_SHUTDOWN) { rc = -ESHUTDOWN; @@ -3214,8 +3445,9 @@ int llapi_copytool_recv(void *priv, struct hsm_action_list **halh, int *msgsize) goto out_free; } - /* Our message is an hsm_action_list */ - + /* Our message is a hsm_action_list. Use pointer math to skip + * kuch_hdr and point directly to the message payload. + */ hal = (struct hsm_action_list *)(kuch + 1); /* Check that we have registered for this archive # */ @@ -3234,14 +3466,15 @@ int llapi_copytool_recv(void *priv, struct hsm_action_list **halh, int *msgsize) out_free: *halh = NULL; *msgsize = 0; + free(kuch); return rc; } /** Release the action list when done with it. */ int llapi_copytool_free(struct hsm_action_list **hal) { - *hal = NULL; - return 0; + /* Reuse the llapi_changelog_free function */ + return llapi_changelog_free((struct changelog_rec **)hal); } int llapi_get_connect_flags(const char *mnt, __u64 *flags) @@ -3262,3 +3495,31 @@ int llapi_get_connect_flags(const char *mnt, __u64 *flags) "ioctl on %s for getting connect flags failed", mnt); return rc; } + +int llapi_get_version(char *buffer, int buffer_size, + char **version) +{ + int rc; + int fd; + struct obd_ioctl_data *data = (struct obd_ioctl_data *)buffer; + + fd = open(OBD_DEV_PATH, O_RDONLY); + if (fd == -1) + return -errno; + + memset(buffer, 0, buffer_size); + data->ioc_version = OBD_IOCTL_VERSION; + data->ioc_inllen1 = buffer_size - cfs_size_round(sizeof(*data)); + data->ioc_inlbuf1 = buffer + cfs_size_round(sizeof(*data)); + data->ioc_len = obd_ioctl_packlen(data); + + rc = ioctl(fd, OBD_GET_VERSION, buffer); + if (rc == -1) { + rc = errno; + close(fd); + return -rc; + } + close(fd); + *version = data->ioc_bulk; + return 0; +}