4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * All rights reserved. This program and the accompanying materials
7 * are made available under the terms of the GNU Lesser General Public License
8 * (LGPL) version 2.1 or (at your discretion) any later version.
9 * (LGPL) version 2.1 accompanies this distribution, and is available at
10 * http://www.gnu.org/licenses/lgpl-2.1.html
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
20 * lustre/utils/liblustreapi_fid.c
22 * lustreapi library for FID mapping calls for determining the pathname
23 * of Lustre files from the File IDentifier.
25 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
26 * Use is subject to license terms.
28 * Copyright (c) 2011, 2017, Intel Corporation.
30 * Copyright (c) 2018, 2019, Data Direct Networks
43 #include <sys/ioctl.h>
44 #include <sys/xattr.h>
47 #include <libcfs/util/ioctl.h>
48 #include <lustre/lustreapi.h>
49 #include <linux/lustre/lustre_fid.h>
50 #include "lustreapi_internal.h"
52 /* strip instances of // (DNE striped directory) when copying to reply buffer */
53 static int copy_strip_dne_path(const char *src, char *tgt, size_t tgtlen)
58 for (a = src, b = tgt; *a != '\0' && b - tgt < tgtlen; a++) {
59 if (*a == '/' && *(a + 1) == '/')
64 if (b - tgt >= tgtlen) {
71 if (tgt[0] == '\0') { /* ROOT path */
80 * parse a FID from a string into a binary lu_fid
82 * Only the format of the FID is checked, not whether the numeric value
83 * contains a valid FID sequence or object ID or version. Optional leading
84 * whitespace and '[' from the standard FID format are skipped.
86 * \param[in] fidstr string to be parsed
87 * \param[out] fid Lustre File IDentifier
88 * \param[out] endptr pointer to first invalid/unused character in @fidstr
90 * \retval 0 on success
91 * \retval -errno on failure
93 int llapi_fid_parse(const char *fidstr, struct lu_fid *fid, char **endptr)
95 unsigned long long val;
97 char *end = (char *)fidstr;
100 if (!fidstr || !fid) {
105 while (isspace(*fidstr))
107 while (*fidstr == '[') {
112 /* Parse the FID fields individually with strtoull() instead of a
113 * single call to sscanf() so that the character after the FID can
114 * be returned in @endptr, in case the string has more to parse.
115 * If values are present, but too large for the field, continue
116 * parsing to consume the whole FID and return -ERANGE at the end.
119 val = strtoull(fidstr, &end, 0);
120 if ((val == 0 && errno == EINVAL) || *end != ':') {
124 if (val >= UINT64_MAX)
129 fidstr = end + 1; /* skip first ':', checked above */
131 val = strtoull(fidstr, &end, 0);
132 if ((val == 0 && errno == EINVAL) || *end != ':') {
136 if (val > UINT32_MAX)
141 fidstr = end + 1; /* skip second ':', checked above */
143 val = strtoull(fidstr, &end, 0);
144 if (val == 0 && errno == EINVAL) {
148 if (val > UINT32_MAX)
153 if (bracket && *end == ']')
163 /* Print mdtname 'name' into 'buf' using 'format'. Add -MDT0000 if needed.
164 * format must have %s%s, buf must be > 16
165 * Eg: if name = "lustre-MDT0000", "lustre", or "lustre-MDT0000_UUID"
166 * then buf = "lustre-MDT0000"
168 static int get_mdtname(char *name, char *format, char *buf)
170 char suffix[] = "-MDT0000";
171 int len = strlen(name);
173 if (len > 5 && strncmp(name + len - 5, "_UUID", 5) == 0) {
174 name[len - 5] = '\0';
179 if ((len <= 16) && strncmp(name + len - 8, "-MDT", 4) == 0) {
182 /* Not enough room to add suffix */
183 llapi_err_noerrno(LLAPI_MSG_ERROR,
184 "Invalid MDT name |%s|", name);
189 return sprintf(buf, format, name, suffix);
192 /** ioctl on filsystem root, with mdtindex sent as data
193 * \param mdtname path, fsname, or mdtname (lutre-MDT0004)
194 * \param mdtidxp pointer to integer within data to be filled in with the
195 * mdt index (0 if no mdt is specified). NULL won't be filled.
197 int root_ioctl(const char *mdtname, int opc, void *data, int *mdtidxp,
205 /* Take path, fsname, or MDTname. Assume MDT0000 in former cases.
206 * Open root and parse mdt index.
208 if (mdtname[0] == '/') {
210 rc = get_root_path(WANT_FD | want_error, NULL, &fd,
211 (char *)mdtname, -1);
213 if (get_mdtname((char *)mdtname, "%s%s", fsname) < 0)
215 ptr = fsname + strlen(fsname) - 8;
217 index = strtol(ptr + 4, NULL, 16);
218 rc = get_root_path(WANT_FD | want_error, fsname, &fd, NULL, -1);
222 llapi_err_noerrno(LLAPI_MSG_ERROR,
223 "Can't open %s: %d\n", mdtname, rc);
230 rc = ioctl(fd, opc, data);
239 int llapi_fid2path(const char *device, const char *fidstr, char *path,
240 int pathlen, long long *recno, int *linkno)
243 struct getinfo_fid2path *gf;
246 if (!path || pathlen <= 1) {
251 rc = llapi_fid_parse(fidstr, &fid, NULL);
252 if (!rc && !fid_is_sane(&fid)) {
257 llapi_err_noerrno(LLAPI_MSG_ERROR,
258 "bad FID format '%s', should be [seq:oid:ver] (e.g. "DFID")\n",
260 (unsigned long long)FID_SEQ_NORMAL, 2, 0);
264 gf = malloc(sizeof(*gf) + pathlen);
272 gf->gf_recno = *recno;
274 gf->gf_linkno = *linkno;
275 gf->gf_pathlen = pathlen;
277 /* Take path or fsname */
278 rc = root_ioctl(device, OBD_IOC_FID2PATH, gf, NULL, 0);
282 rc = copy_strip_dne_path(gf->gf_u.gf_path, path, pathlen);
285 *recno = gf->gf_recno;
287 *linkno = gf->gf_linkno;
296 int llapi_get_mdt_index_by_fid(int fd, const struct lu_fid *fid,
301 rc = ioctl(fd, LL_IOC_FID2MDTIDX, fid);
311 static int fid_from_lma(const char *path, int fd, struct lu_fid *fid)
313 struct lustre_mdt_attrs *lma;
318 rc = fgetxattr(fd, XATTR_NAME_LMA, buf, sizeof(buf));
320 rc = lgetxattr(path, XATTR_NAME_LMA, buf, sizeof(buf));
324 lma = (struct lustre_mdt_attrs *)buf;
325 memcpy(fid, &lma->lma_self_fid, sizeof(lma->lma_self_fid));
329 int llapi_fd2fid(int fd, struct lu_fid *fid)
331 const struct lustre_file_handle *data;
332 struct file_handle *handle;
333 char buffer[sizeof(*handle) + MAX_HANDLE_SZ];
336 memset(fid, 0, sizeof(*fid));
338 /* A lustre file handle should always fit in a 128 bytes long buffer
339 * (which is the value of MAX_HANDLE_SZ at the time this is written)
341 handle = (struct file_handle *)buffer;
342 handle->handle_bytes = MAX_HANDLE_SZ;
344 if (name_to_handle_at(fd, "", handle, &mount_id, AT_EMPTY_PATH)) {
345 if (errno == EOVERFLOW)
346 /* A Lustre file_handle would have fit */
351 if (handle->handle_type != FILEID_LUSTRE)
352 /* Might be a locally mounted Lustre target */
353 return fid_from_lma(NULL, fd, fid);
354 if (handle->handle_bytes < sizeof(*fid))
355 /* Unexpected error try and recover */
356 return fid_from_lma(NULL, fd, fid);
358 /* Parse the FID out of the handle */
359 data = (const struct lustre_file_handle *)handle->f_handle;
360 memcpy(fid, &data->lfh_child, sizeof(data->lfh_child));
365 int llapi_path2fid(const char *path, struct lu_fid *fid)
369 fd = open(path, O_RDONLY | O_PATH | O_CLOEXEC | O_NOFOLLOW);
373 rc = llapi_fd2fid(fd, fid);
377 /* Might be a locally mounted Lustre target
379 * Cannot use `fd' as fgetxattr() does not work on file
380 * descriptor opened with O_PATH
382 rc = fid_from_lma(path, -1, fid);
387 int llapi_fd2parent(int fd, unsigned int linkno, struct lu_fid *parent_fid,
388 char *name, size_t name_size)
390 struct getparent *gp;
393 if (name && name_size <= 1) {
398 gp = malloc(sizeof(*gp) + name_size);
404 gp->gp_linkno = linkno;
405 gp->gp_name_size = name_size;
407 rc = ioctl(fd, LL_IOC_GETPARENT, gp);
414 *parent_fid = gp->gp_fid;
417 rc = copy_strip_dne_path(gp->gp_name, name, name_size);
424 int llapi_path2parent(const char *path, unsigned int linkno,
425 struct lu_fid *parent_fid, char *name, size_t name_size)
430 fd = open(path, O_RDONLY | O_NONBLOCK | O_NOFOLLOW);
434 rc = llapi_fd2parent(fd, linkno, parent_fid, name, name_size);
441 * Attempt to open a file with Lustre file identifier \a fid
442 * and return an open file descriptor.
444 * \param[in] lustre_dir path within Lustre filesystem containing \a fid
445 * \param[in] fid Lustre file identifier of file to open
446 * \param[in] flags open() flags
448 * \retval non-negative file descriptor on successful open
449 * \retval negative errno if an error occurred
451 int llapi_open_by_fid(const char *lustre_dir, const struct lu_fid *fid,
454 char mntdir[PATH_MAX];
455 char path[PATH_MAX + 64];
458 rc = llapi_search_mounts(lustre_dir, 0, mntdir, NULL);
462 snprintf(path, sizeof(path), "%s/.lustre/fid/"DFID, mntdir, PFID(fid));
463 rc = open(path, flags);