From: Andreas Dilger Date: Fri, 13 Sep 2019 23:27:23 +0000 (-0600) Subject: LU-11380 llapi: add llapi_fid_parse() helper X-Git-Tag: 2.13.51~159 X-Git-Url: https://git.whamcloud.com/?p=fs%2Flustre-release.git;a=commitdiff_plain;h=21d671b3af09af65d38a454e677c5da9830e0c7a LU-11380 llapi: add llapi_fid_parse() helper Split the llapi_* FID handling functions to a separate file rather than continually increasing the size of liblustrepai.c. Add llapi_fid_parse() to parse a string to binary struct lu_fid. Signed-off-by: Andreas Dilger Change-Id: I15abfaf888a5474d62feebab4e8db543ba3ebbe5 Reviewed-on: https://review.whamcloud.com/36184 Tested-by: jenkins Reviewed-by: Olaf Faaland-LLNL Reviewed-by: Jian Yu Tested-by: Maloo Reviewed-by: James Simmons Reviewed-by: Oleg Drokin --- diff --git a/lustre/doc/Makefile.am b/lustre/doc/Makefile.am index 3e908f2..fbb3458 100644 --- a/lustre/doc/Makefile.am +++ b/lustre/doc/Makefile.am @@ -71,6 +71,7 @@ MANFILES = \ lhbadm.8 \ llapi_create_volatile_param.3 \ llapi_fd2parent.3 \ + llapi_fid_parse.3 \ llapi_file_create.3 \ llapi_file_create_foreign.3 \ llapi_file_get_stripe.3 \ diff --git a/lustre/doc/llapi_fid_parse.3 b/lustre/doc/llapi_fid_parse.3 new file mode 100644 index 0000000..2889ba8 --- /dev/null +++ b/lustre/doc/llapi_fid_parse.3 @@ -0,0 +1,86 @@ +.TH lustreapi 3 "2019 Sep 13" Lustre user application interface library +.SH NAME +llapi_fid_parse \- parse ASCII FID string into binary lu_fid +.SH SYNOPSIS +.nf +.B #include +.sp +.BI "int llapi_fid_parse(const char *" fidstr ", struct lu_fid *" fid , +.BI " char **" endptr ");" +.sp +.fi +.SH DESCRIPTION +.LP +.B llapi_fid_parse() +converts an ASCII FID string into a binary +.B struct lu_fid +for use in other interfaces such as +.BR llapi_layout_get_by_fid() . +.I fidstr +should contain three numbers in the form +.IR fid_seq : fid_oid : fid_ver +and may optionally be enclosed in square braces +.BR [] . +It will skip any leading whitespace before the FID. +.LP +If +.I endptr +is not NULL, +.B llapi_fid_parse() +stores the address of the first invalid character in +.IR *endptr , +or the character immediately following the end of the parsed FID. +.SH RETURN VALUES +.LP +.B llapi_fid_parse() +returns: +.TP +0 +on success, +.TP +<0 +a negative errno on failure and sets errno. +.SH ERRORS +.TP 15 +.SM EINVAL +.I fidstr +is NULL or does not contain a valid FID format. +.TP +.SM ERANGE +.I fidstr +contains numeric values that exceed valid values for a component. +.SH "EXAMPLE" +.nf +#include + +int main(int argc, char *argv[]) +{ + char fidstr = "[0x200000004:0x2:0x0] [0x200000400:0x345:0x0]"; + struct lu_fid fid1, fid2; + char *end; + int rc; + + fidstr = argv[1]; + rc = llapi_fid_parse(fidstr, &fid1, &end); + if (rc < 0) { + fprintf(stderr, "invalid first FID '%s': %s\\n", + fidstr, strerror(-rc)); + return -1; + } + + fidstr = end; + rc = llapi_fid_parse(fidstr, &fid2, &end); + if (rc < 0) { + fprintf(stderr, "invalid second FID '%s': %s\\n", + fidstr, strerror(-rc)); + return -1; + } + + printf("fid1=" DFID " fid2="DFID"\\n", PFID(&fid1), PFID(&fid2)); + return 0; +} +.fi +.SH "SEE ALSO" +.BR lustre (7), +.BR llapi_path2parent (3), +.BR lustreapi (7) diff --git a/lustre/doc/lustreapi.7 b/lustre/doc/lustreapi.7 index b733832..47f06ee 100644 --- a/lustre/doc/lustreapi.7 +++ b/lustre/doc/lustreapi.7 @@ -14,6 +14,7 @@ quotas, file layouts, etc). See the referenced man pages for details. .BR llapi_create_volatile_param (3), .BR llapi_fd2parent (3), .BR llapi_fid2path (3), +.BR llapi_fid_parse (3), .BR llapi_file_create (3), .BR llapi_file_get_stripe (3), .BR llapi_file_open (3), diff --git a/lustre/include/lustre/lustreapi.h b/lustre/include/lustre/lustreapi.h index 237dc65..bd1f940 100644 --- a/lustre/include/lustre/lustreapi.h +++ b/lustre/include/lustre/lustreapi.h @@ -409,6 +409,7 @@ int llapi_target_iterate(int type_num, char **obd_type, void *args, int llapi_get_connect_flags(const char *mnt, __u64 *flags); int llapi_cp(int argc, char *argv[]); int llapi_ls(int argc, char *argv[]); +int llapi_fid_parse(const char *fidstr, struct lu_fid *fid, char **endptr); int llapi_fid2path(const char *device, const char *fidstr, char *path, int pathlen, long long *recno, int *linkno); int llapi_path2fid(const char *path, struct lu_fid *fid); diff --git a/lustre/utils/LCOPYING b/lustre/utils/LCOPYING index 5e37211..105f1fd 100644 --- a/lustre/utils/LCOPYING +++ b/lustre/utils/LCOPYING @@ -1,4 +1,5 @@ This licence file applies to new library files: +lustre/utils/liblustreapi_fid.c lustre/utils/liblustreapi_hsm.c lustre/utils/liblustreapi_json.c lustre/utils/liblustreapi_layout.c diff --git a/lustre/utils/Makefile.am b/lustre/utils/Makefile.am index 8704f5b..9cb0e6f 100644 --- a/lustre/utils/Makefile.am +++ b/lustre/utils/Makefile.am @@ -96,7 +96,7 @@ liblustreapi_la_SOURCES = liblustreapi.c liblustreapi_hsm.c \ liblustreapi_json.c liblustreapi_layout.c \ liblustreapi_lease.c liblustreapi_util.c \ liblustreapi_kernelconn.c liblustreapi_param.c \ - liblustreapi_mirror.c \ + liblustreapi_mirror.c liblustreapi_fid.c \ liblustreapi_ladvise.c liblustreapi_chlg.c \ liblustreapi_heat.c liblustreapi_pcc.c liblustreapi_la_LDFLAGS = $(LIBREADLINE) -version-info 1:0:0 \ diff --git a/lustre/utils/lfs.c b/lustre/utils/lfs.c index c96afdf..c815e1c 100644 --- a/lustre/utils/lfs.c +++ b/lustre/utils/lfs.c @@ -8195,16 +8195,10 @@ static int fill_hur_item(struct hsm_user_request *hur, unsigned int idx, hui->hui_extent.length = -1; if (mntpath != NULL) { - if (*fname == '[') - fname++; - rc = sscanf(fname, SFID, RFID(&hui->hui_fid)); - if (rc == 3) { - rc = 0; - } else { + rc = llapi_fid_parse(fname, &hui->hui_fid, NULL); + if (rc) fprintf(stderr, "hsm: '%s' is not a valid FID\n", fname); - rc = -EINVAL; - } } else { rc = lfs_hsm_prepare_file(fname, &hui->hui_fid, last_dev); } diff --git a/lustre/utils/lhsmtool_posix.c b/lustre/utils/lhsmtool_posix.c index 152dc81..5dbe904 100644 --- a/lustre/utils/lhsmtool_posix.c +++ b/lustre/utils/lhsmtool_posix.c @@ -1542,10 +1542,9 @@ static int ct_import_recurse(const char *relpath) if (relpath == NULL) return -EINVAL; - /* Is relpath a FID? In which case SFID should expand to three - * elements. */ - rc = sscanf(relpath, SFID, RFID(&import_fid)); - if (rc == 3) + /* Is relpath a FID? */ + rc = llapi_fid_parse(relpath, &import_fid, NULL); + if (!rc) return ct_import_fid(&import_fid); srcpath = path_concat(opt.o_hsm_root, relpath); @@ -1692,8 +1691,9 @@ static int ct_rebind_list(const char *list) /* each line consists of 2 FID */ while ((r = getline(&line, &line_size, filp)) != -1) { - struct lu_fid old_fid; - struct lu_fid new_fid; + struct lu_fid old_fid; + struct lu_fid new_fid; + char *next_fid; /* Ignore empty and commented out ('#...') lines. */ if (should_ignore_line(line)) @@ -1701,12 +1701,17 @@ static int ct_rebind_list(const char *list) nl++; - rc = sscanf(line, SFID" "SFID, RFID(&old_fid), RFID(&new_fid)); - if (rc != 6 || !fid_is_file(&old_fid) || - !fid_is_file(&new_fid)) { - CT_ERROR(EINVAL, - "'%s' FID expected near '%s', line %u", - list, line, nl); + rc = llapi_fid_parse(line, &old_fid, &next_fid); + if (rc) + goto error; + rc = llapi_fid_parse(next_fid, &new_fid, NULL); + if (rc) + goto error; + if (!fid_is_file(&old_fid) || !fid_is_file(&new_fid)) + rc = -EINVAL; + if (rc) { +error: CT_ERROR(rc, "%s:%u: two FIDs expected in '%s'", + list, nl, line); err_major++; continue; } @@ -1730,23 +1735,25 @@ static int ct_rebind_list(const char *list) static int ct_rebind(void) { - int rc; + int rc; if (opt.o_dst) { 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)) { + rc = llapi_fid_parse(opt.o_src, &old_fid, NULL); + if (!rc && !fid_is_file(&old_fid)) rc = -EINVAL; - CT_ERROR(rc, "'%s' invalid FID format", opt.o_src); + if (rc) { + CT_ERROR(rc, "invalid source FID '%s'", opt.o_src); return rc; } - if (sscanf(opt.o_dst, SFID, RFID(&new_fid)) != 3 || - !fid_is_file(&new_fid)) { + rc = llapi_fid_parse(opt.o_dst, &new_fid, NULL); + if (!rc && !fid_is_file(&new_fid)) rc = -EINVAL; - CT_ERROR(rc, "'%s' invalid FID format", opt.o_dst); + if (rc) { + CT_ERROR(rc, "invalid destination FID '%s'", opt.o_dst); return rc; } diff --git a/lustre/utils/liblustreapi.c b/lustre/utils/liblustreapi.c index 754536f..726b520 100644 --- a/lustre/utils/liblustreapi.c +++ b/lustre/utils/liblustreapi.c @@ -5499,248 +5499,6 @@ int llapi_quotactl(char *mnt, struct if_quotactl *qctl) return rc; } -/* Print mdtname 'name' into 'buf' using 'format'. Add -MDT0000 if needed. - * format must have %s%s, buf must be > 16 - * Eg: if name = "lustre-MDT0000", "lustre", or "lustre-MDT0000_UUID" - * then buf = "lustre-MDT0000" - */ -static int get_mdtname(char *name, char *format, char *buf) -{ - char suffix[]="-MDT0000"; - int len = strlen(name); - - if ((len > 5) && (strncmp(name + len - 5, "_UUID", 5) == 0)) { - name[len - 5] = '\0'; - len -= 5; - } - - if (len > 8) { - if ((len <= 16) && strncmp(name + len - 8, "-MDT", 4) == 0) { - suffix[0] = '\0'; - } else { - /* Not enough room to add suffix */ - llapi_err_noerrno(LLAPI_MSG_ERROR, - "Invalid MDT name |%s|", name); - return -EINVAL; - } - } - - return sprintf(buf, format, name, suffix); -} - -/** ioctl on filsystem root, with mdtindex sent as data - * \param mdtname path, fsname, or mdtname (lutre-MDT0004) - * \param mdtidxp pointer to integer within data to be filled in with the - * mdt index (0 if no mdt is specified). NULL won't be filled. - */ -int root_ioctl(const char *mdtname, int opc, void *data, int *mdtidxp, - int want_error) -{ - char fsname[20]; - char *ptr; - int fd, rc; - long index; - - /* Take path, fsname, or MDTname. Assume MDT0000 in the former cases. - Open root and parse mdt index. */ - if (mdtname[0] == '/') { - index = 0; - rc = get_root_path(WANT_FD | want_error, NULL, &fd, - (char *)mdtname, -1); - } else { - if (get_mdtname((char *)mdtname, "%s%s", fsname) < 0) - return -EINVAL; - ptr = fsname + strlen(fsname) - 8; - *ptr = '\0'; - index = strtol(ptr + 4, NULL, 16); - rc = get_root_path(WANT_FD | want_error, fsname, &fd, NULL, -1); - } - if (rc < 0) { - if (want_error) - llapi_err_noerrno(LLAPI_MSG_ERROR, - "Can't open %s: %d\n", mdtname, rc); - return rc; - } - - if (mdtidxp) - *mdtidxp = index; - - rc = ioctl(fd, opc, data); - if (rc == -1) - rc = -errno; - else - rc = 0; - close(fd); - return rc; -} - -int llapi_fid2path(const char *device, const char *fidstr, char *buf, - int buflen, long long *recno, int *linkno) -{ - const char *fidstr_orig = fidstr; - struct lu_fid fid; - struct getinfo_fid2path *gf; - char *a; - char *b; - int rc; - - while (*fidstr == '[') - fidstr++; - - sscanf(fidstr, SFID, RFID(&fid)); - if (!fid_is_sane(&fid)) { - llapi_err_noerrno(LLAPI_MSG_ERROR, - "bad FID format '%s', should be [seq:oid:ver]" - " (e.g. "DFID")\n", fidstr_orig, - (unsigned long long)FID_SEQ_NORMAL, 2, 0); - return -EINVAL; - } - - 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; - - /* Take path or fsname */ - rc = root_ioctl(device, OBD_IOC_FID2PATH, gf, NULL, 0); - if (rc) - goto out_free; - - b = buf; - /* strip out instances of // */ - for (a = gf->gf_u.gf_path; *a != '\0'; a++) { - if ((*a == '/') && (*(a + 1) == '/')) - continue; - *b = *a; - b++; - } - *b = '\0'; - - if (buf[0] == '\0') { /* ROOT path */ - buf[0] = '/'; - buf[1] = '\0'; - } - - *recno = gf->gf_recno; - *linkno = gf->gf_linkno; - -out_free: - free(gf); - return rc; -} - -static int fid_from_lma(const char *path, int fd, struct lu_fid *fid) -{ - char buf[512]; - struct lustre_mdt_attrs *lma; - int rc; - - if (path == NULL) - rc = fgetxattr(fd, XATTR_NAME_LMA, buf, sizeof(buf)); - else - rc = lgetxattr(path, XATTR_NAME_LMA, buf, sizeof(buf)); - if (rc < 0) - return -errno; - lma = (struct lustre_mdt_attrs *)buf; - fid_le_to_cpu(fid, &lma->lma_self_fid); - return 0; -} - -int llapi_get_mdt_index_by_fid(int fd, const struct lu_fid *fid, - int *mdt_index) -{ - int rc; - - rc = ioctl(fd, LL_IOC_FID2MDTIDX, fid); - if (rc < 0) - return -errno; - - *mdt_index = rc; - - return rc; -} - -int llapi_fd2fid(int fd, struct lu_fid *fid) -{ - int rc; - - memset(fid, 0, sizeof(*fid)); - - rc = ioctl(fd, LL_IOC_PATH2FID, fid) < 0 ? -errno : 0; - if (rc == -EINVAL || rc == -ENOTTY) - rc = fid_from_lma(NULL, fd, fid); - - return rc; -} - -int llapi_path2fid(const char *path, struct lu_fid *fid) -{ - int fd, rc; - - memset(fid, 0, sizeof(*fid)); - fd = open(path, O_RDONLY | O_NONBLOCK | O_NOFOLLOW); - if (fd < 0) { - if (errno == ELOOP || errno == ENXIO) - return fid_from_lma(path, -1, fid); - return -errno; - } - - rc = llapi_fd2fid(fd, fid); - if (rc == -EINVAL || rc == -ENOTTY) - rc = fid_from_lma(path, -1, fid); - - close(fd); - return rc; -} - -int llapi_fd2parent(int fd, unsigned int linkno, struct lu_fid *parent_fid, - char *name, size_t name_size) -{ - struct getparent *gp; - int rc; - - gp = malloc(sizeof(*gp) + name_size); - if (gp == NULL) - return -ENOMEM; - - gp->gp_linkno = linkno; - gp->gp_name_size = name_size; - - rc = ioctl(fd, LL_IOC_GETPARENT, gp); - if (rc < 0) { - rc = -errno; - goto err_free; - } - - *parent_fid = gp->gp_fid; - - strncpy(name, gp->gp_name, name_size); - name[name_size - 1] = '\0'; - -err_free: - free(gp); - return rc; -} - -int llapi_path2parent(const char *path, unsigned int linkno, - struct lu_fid *parent_fid, char *name, size_t name_size) -{ - int fd; - int rc; - - fd = open(path, O_RDONLY | O_NONBLOCK | O_NOFOLLOW); - if (fd < 0) - return -errno; - - rc = llapi_fd2parent(fd, linkno, parent_fid, name, name_size); - close(fd); - return rc; -} - int llapi_get_connect_flags(const char *mnt, __u64 *flags) { int root; @@ -6068,32 +5826,6 @@ out: } /** - * Attempt to open a file with Lustre file identifier \a fid - * and return an open file descriptor. - * - * \param[in] lustre_dir path within Lustre filesystem containing \a fid - * \param[in] fid Lustre file identifier of file to open - * \param[in] flags open() flags - * - * \retval non-negative file descriptor on successful open - * \retval -1 if an error occurred - */ -int llapi_open_by_fid(const char *lustre_dir, const struct lu_fid *fid, - int flags) -{ - char mntdir[PATH_MAX]; - char path[PATH_MAX + 64]; - int rc; - - rc = llapi_search_mounts(lustre_dir, 0, mntdir, NULL); - if (rc != 0) - return -1; - - snprintf(path, sizeof(path), "%s/.lustre/fid/"DFID, mntdir, PFID(fid)); - return open(path, flags); -} - -/** * Take group lock. * * \param fd File to lock. diff --git a/lustre/utils/liblustreapi_fid.c b/lustre/utils/liblustreapi_fid.c new file mode 100644 index 0000000..0034714 --- /dev/null +++ b/lustre/utils/liblustreapi_fid.c @@ -0,0 +1,450 @@ +/* + * LGPL HEADER START + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * 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. + * (LGPL) version 2.1 accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl-2.1.html + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * LGPL HEADER END + */ +/* + * lustre/utils/liblustreapi_fid.c + * + * lustreapi library for FID mapping calls for determining the pathname + * of Lustre files from the File IDentifier. + * + * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. + * Use is subject to license terms. + * + * Copyright (c) 2011, 2017, Intel Corporation. + * + * Copyright (c) 2018, 2019, Data Direct Networks + */ + +/* for O_DIRECTORY */ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include "lustreapi_internal.h" + +/* strip instances of // (DNE striped directory) when copying to reply buffer */ +static int copy_strip_dne_path(const char *src, char *tgt, size_t tgtlen) +{ + const char *a; + char *b; + + for (a = src, b = tgt; *a != '\0' && b - tgt < tgtlen; a++) { + if (*a == '/' && *(a + 1) == '/') + continue; + *b = *a; + b++; + } + if (b - tgt >= tgtlen) { + errno = ERANGE; + return -errno; + } + + *b = '\0'; + + if (tgt[0] == '\0') { /* ROOT path */ + tgt[0] = '/'; + tgt[1] = '\0'; + } + + return 0; +} + +/** + * parse a FID from a string into a binary lu_fid + * + * Only the format of the FID is checked, not whether the numeric value + * contains a valid FID sequence or object ID or version. Optional leading + * whitespace and '[' from the standard FID format are skipped. + * + * \param[in] fidstr string to be parsed + * \param[out] fid Lustre File IDentifier + * \param[out] endptr pointer to first invalid/unused character in @fidstr + * + * \retval 0 on success + * \retval -errno on failure + */ +int llapi_fid_parse(const char *fidstr, struct lu_fid *fid, char **endptr) +{ + unsigned long long val; + bool bracket = false; + char *end = (char *)fidstr; + int rc = 0; + + if (!fidstr || !fid) { + rc = -EINVAL; + goto out; + } + + while (isspace(*fidstr)) + fidstr++; + while (*fidstr == '[') { + bracket = true; + fidstr++; + } + + /* Parse the FID fields individually with strtoull() instead of a + * single call to sscanf() so that the character after the FID can + * be returned in @endptr, in case the string has more to parse. + * If values are present, but too large for the field, continue + * parsing to consume the whole FID and return -ERANGE at the end. + */ + errno = 0; + val = strtoull(fidstr, &end, 0); + if ((val == 0 && errno == EINVAL) || *end != ':') { + rc = -EINVAL; + goto out; + } + if (val >= UINT64_MAX) + rc = -ERANGE; + else + fid->f_seq = val; + + fidstr = end + 1; /* skip first ':', checked above */ + errno = 0; + val = strtoull(fidstr, &end, 0); + if ((val == 0 && errno == EINVAL) || *end != ':') { + rc = -EINVAL; + goto out; + } + if (val > UINT32_MAX) + rc = -ERANGE; + else + fid->f_oid = val; + + fidstr = end + 1; /* skip second ':', checked above */ + errno = 0; + val = strtoull(fidstr, &end, 0); + if (val == 0 && errno == EINVAL) { + rc = -EINVAL; + goto out; + } + if (val > UINT32_MAX) + rc = -ERANGE; + else + fid->f_ver = val; + + if (bracket && *end == ']') + end++; +out: + if (endptr) + *endptr = end; + + errno = -rc; + return rc; +} + +/* Print mdtname 'name' into 'buf' using 'format'. Add -MDT0000 if needed. + * format must have %s%s, buf must be > 16 + * Eg: if name = "lustre-MDT0000", "lustre", or "lustre-MDT0000_UUID" + * then buf = "lustre-MDT0000" + */ +static int get_mdtname(char *name, char *format, char *buf) +{ + char suffix[] = "-MDT0000"; + int len = strlen(name); + + if (len > 5 && strncmp(name + len - 5, "_UUID", 5) == 0) { + name[len - 5] = '\0'; + len -= 5; + } + + if (len > 8) { + if ((len <= 16) && strncmp(name + len - 8, "-MDT", 4) == 0) { + suffix[0] = '\0'; + } else { + /* Not enough room to add suffix */ + llapi_err_noerrno(LLAPI_MSG_ERROR, + "Invalid MDT name |%s|", name); + return -EINVAL; + } + } + + return sprintf(buf, format, name, suffix); +} + +/** ioctl on filsystem root, with mdtindex sent as data + * \param mdtname path, fsname, or mdtname (lutre-MDT0004) + * \param mdtidxp pointer to integer within data to be filled in with the + * mdt index (0 if no mdt is specified). NULL won't be filled. + */ +int root_ioctl(const char *mdtname, int opc, void *data, int *mdtidxp, + int want_error) +{ + char fsname[20]; + char *ptr; + int fd, rc; + long index; + + /* Take path, fsname, or MDTname. Assume MDT0000 in former cases. + * Open root and parse mdt index. + */ + if (mdtname[0] == '/') { + index = 0; + rc = get_root_path(WANT_FD | want_error, NULL, &fd, + (char *)mdtname, -1); + } else { + if (get_mdtname((char *)mdtname, "%s%s", fsname) < 0) + return -EINVAL; + ptr = fsname + strlen(fsname) - 8; + *ptr = '\0'; + index = strtol(ptr + 4, NULL, 16); + rc = get_root_path(WANT_FD | want_error, fsname, &fd, NULL, -1); + } + if (rc < 0) { + if (want_error) + llapi_err_noerrno(LLAPI_MSG_ERROR, + "Can't open %s: %d\n", mdtname, rc); + return rc; + } + + if (mdtidxp) + *mdtidxp = index; + + rc = ioctl(fd, opc, data); + if (rc == -1) + rc = -errno; + else + rc = 0; + close(fd); + return rc; +} + +int llapi_fid2path(const char *device, const char *fidstr, char *path, + int pathlen, long long *recno, int *linkno) +{ + struct lu_fid fid; + struct getinfo_fid2path *gf; + int rc; + + if (!path || pathlen <= 1) { + rc = -EINVAL; + goto out; + } + + rc = llapi_fid_parse(fidstr, &fid, NULL); + if (!rc && !fid_is_sane(&fid)) { + rc = -EINVAL; + goto out; + } + if (rc) { + llapi_err_noerrno(LLAPI_MSG_ERROR, + "bad FID format '%s', should be [seq:oid:ver] (e.g. "DFID")\n", + fidstr, + (unsigned long long)FID_SEQ_NORMAL, 2, 0); + goto out; + } + + gf = malloc(sizeof(*gf) + pathlen); + if (gf == NULL) { + rc = -ENOMEM; + goto out; + } + + gf->gf_fid = fid; + if (recno) + gf->gf_recno = *recno; + if (linkno) + gf->gf_linkno = *linkno; + gf->gf_pathlen = pathlen; + + /* Take path or fsname */ + rc = root_ioctl(device, OBD_IOC_FID2PATH, gf, NULL, 0); + if (rc) + goto out_free; + + rc = copy_strip_dne_path(gf->gf_u.gf_path, path, pathlen); + + if (recno) + *recno = gf->gf_recno; + if (linkno) + *linkno = gf->gf_linkno; + +out_free: + free(gf); +out: + errno = -rc; + return rc; +} + +static int fid_from_lma(const char *path, int fd, struct lu_fid *fid) +{ + char buf[512]; + struct lustre_mdt_attrs *lma; + int rc = -1; + + if (fd >= 0) + rc = fgetxattr(fd, XATTR_NAME_LMA, buf, sizeof(buf)); + else if (path) + rc = lgetxattr(path, XATTR_NAME_LMA, buf, sizeof(buf)); + else + errno = EINVAL; + if (rc < 0) + return -errno; + + lma = (struct lustre_mdt_attrs *)buf; + fid_le_to_cpu(fid, &lma->lma_self_fid); + + return 0; +} + +int llapi_get_mdt_index_by_fid(int fd, const struct lu_fid *fid, + int *mdt_index) +{ + int rc; + + rc = ioctl(fd, LL_IOC_FID2MDTIDX, fid); + if (rc < 0) + return -errno; + + if (mdt_index) + *mdt_index = rc; + + return rc; +} + +int llapi_fd2fid(int fd, struct lu_fid *fid) +{ + int rc; + + memset(fid, 0, sizeof(*fid)); + + rc = ioctl(fd, LL_IOC_PATH2FID, fid) < 0 ? -errno : 0; + /* Allow extracting the FID from an ldiskfs-mounted filesystem */ + if (rc < 0) { + if (errno == EINVAL || errno == ENOTTY) + rc = fid_from_lma(NULL, fd, fid); + else + rc = -errno; + } + + return rc; +} + +int llapi_path2fid(const char *path, struct lu_fid *fid) +{ + int fd, rc; + + fd = open(path, O_RDONLY | O_NONBLOCK | O_NOFOLLOW); + if (fd >= 0) { + rc = llapi_fd2fid(fd, fid); + close(fd); + } else { + memset(fid, 0, sizeof(*fid)); + rc = -errno; + } + + if (rc == -ELOOP || rc == -ENXIO || rc == -EINVAL || rc == -ENOTTY) + rc = fid_from_lma(path, -1, fid); + + return rc; +} + +int llapi_fd2parent(int fd, unsigned int linkno, struct lu_fid *parent_fid, + char *name, size_t name_size) +{ + struct getparent *gp; + int rc; + + if (name && name_size <= 1) { + errno = EOVERFLOW; + return -errno; + } + + gp = malloc(sizeof(*gp) + name_size); + if (gp == NULL) { + errno = ENOMEM; + return -errno; + } + + gp->gp_linkno = linkno; + gp->gp_name_size = name_size; + + rc = ioctl(fd, LL_IOC_GETPARENT, gp); + if (rc < 0) { + rc = -errno; + goto err_free; + } + + if (parent_fid) + *parent_fid = gp->gp_fid; + + if (name) + rc = copy_strip_dne_path(gp->gp_name, name, name_size); + +err_free: + free(gp); + return rc; +} + +int llapi_path2parent(const char *path, unsigned int linkno, + struct lu_fid *parent_fid, char *name, size_t name_size) +{ + int fd; + int rc; + + fd = open(path, O_RDONLY | O_NONBLOCK | O_NOFOLLOW); + if (fd < 0) + return -errno; + + rc = llapi_fd2parent(fd, linkno, parent_fid, name, name_size); + close(fd); + + return rc; +} + +/** + * Attempt to open a file with Lustre file identifier \a fid + * and return an open file descriptor. + * + * \param[in] lustre_dir path within Lustre filesystem containing \a fid + * \param[in] fid Lustre file identifier of file to open + * \param[in] flags open() flags + * + * \retval non-negative file descriptor on successful open + * \retval negative errno if an error occurred + */ +int llapi_open_by_fid(const char *lustre_dir, const struct lu_fid *fid, + int flags) +{ + char mntdir[PATH_MAX]; + char path[PATH_MAX + 64]; + int rc; + + rc = llapi_search_mounts(lustre_dir, 0, mntdir, NULL); + if (rc) + return rc; + + snprintf(path, sizeof(path), "%s/.lustre/fid/"DFID, mntdir, PFID(fid)); + rc = open(path, flags); + if (rc < 0) + rc = -errno; + + return rc; +} diff --git a/lustre/utils/obd.c b/lustre/utils/obd.c index 15ff456..1e34654 100644 --- a/lustre/utils/obd.c +++ b/lustre/utils/obd.c @@ -5268,7 +5268,7 @@ int jt_get_obj_version(int argc, char **argv) } argc -= optind; - argv += optind; + fidstr = *(argv + optind); if (!(id != ULLONG_MAX && group != ULLONG_MAX && argc == 0) && !(id == ULLONG_MAX && group == ULLONG_MAX && argc == 1)) @@ -5277,18 +5277,20 @@ int jt_get_obj_version(int argc, char **argv) memset(&data, 0, sizeof data); data.ioc_dev = cur_device; if (argc == 1) { - fidstr = *argv; - while (*fidstr == '[') - fidstr++; - sscanf(fidstr, SFID, RFID(&fid)); + rc = llapi_fid_parse(fidstr, &fid, NULL); + if (rc) { + fprintf(stderr, "%s: error parsing FID '%s': %s\n", + jt_cmdname(argv[0]), fidstr, strerror(-rc)); + return rc; + } - data.ioc_inlbuf1 = (char *) &fid; - data.ioc_inllen1 = sizeof fid; + data.ioc_inlbuf1 = (char *)&fid; + data.ioc_inllen1 = sizeof(fid); } else { - data.ioc_inlbuf3 = (char *) &id; - data.ioc_inllen3 = sizeof id; - data.ioc_inlbuf4 = (char *) &group; - data.ioc_inllen4 = sizeof group; + data.ioc_inlbuf3 = (char *)&id; + data.ioc_inllen3 = sizeof(id); + data.ioc_inlbuf4 = (char *)&group; + data.ioc_inllen4 = sizeof(group); } data.ioc_inlbuf2 = (char *) &version; data.ioc_inllen2 = sizeof version;