X-Git-Url: https://git.whamcloud.com/?p=fs%2Flustre-release.git;a=blobdiff_plain;f=lustre%2Futils%2Fliblustreapi.c;h=ca5debe6f3bfeb0d840eca9d6ad0d47bce68dd3d;hp=754536f1178dbaacacbf7fccfb7f0aa26f1f8bd9;hb=9b0b7264a8d7a6a2abe681d15fefc88c27d20c1e;hpb=c1d0a355a6a64ec97c9f56c38ba036e5e50cd8c4 diff --git a/lustre/utils/liblustreapi.c b/lustre/utils/liblustreapi.c index 754536f..ca5debe 100644 --- a/lustre/utils/liblustreapi.c +++ b/lustre/utils/liblustreapi.c @@ -27,7 +27,6 @@ */ /* * This file is part of Lustre, http://www.lustre.org/ - * Lustre is a trademark of Sun Microsystems, Inc. * * lustre/utils/liblustreapi.c * @@ -63,6 +62,7 @@ #include #include #include /* for dirname() */ +#include #ifdef HAVE_LINUX_UNISTD_H #include #else @@ -80,18 +80,14 @@ #include #include #include "lustreapi_internal.h" +#include "lstddef.h" static int llapi_msg_level = LLAPI_MSG_MAX; const char *liblustreapi_cmd; -char *mdt_hash_name[] = { "none", - LMV_HASH_NAME_ALL_CHARS, - LMV_HASH_NAME_FNV_1A_64, -}; - struct lustre_foreign_type lu_foreign_types[] = { {.lft_type = LU_FOREIGN_TYPE_NONE, .lft_name = "none"}, - {.lft_type = LU_FOREIGN_TYPE_DAOS, .lft_name = "daos"}, + {.lft_type = LU_FOREIGN_TYPE_SYMLINK, .lft_name = "symlink"}, /* must be the last element */ {.lft_type = LU_FOREIGN_TYPE_UNKNOWN, .lft_name = NULL} /* array max dimension must be <= UINT32_MAX */ @@ -99,13 +95,13 @@ struct lustre_foreign_type lu_foreign_types[] = { void llapi_msg_set_level(int level) { - /* ensure level is in the good range */ - if (level < LLAPI_MSG_OFF) - llapi_msg_level = LLAPI_MSG_OFF; - else if (level > LLAPI_MSG_MAX) - llapi_msg_level = LLAPI_MSG_MAX; - else - llapi_msg_level = level; + /* ensure level is in the good range */ + if (level < LLAPI_MSG_OFF) + llapi_msg_level = LLAPI_MSG_OFF; + else if (level > LLAPI_MSG_MAX) + llapi_msg_level = LLAPI_MSG_MAX; + else + llapi_msg_level = level; } int llapi_msg_get_level(void) @@ -126,16 +122,36 @@ void llapi_clear_command_name(void) static void error_callback_default(enum llapi_message_level level, int err, const char *fmt, va_list ap) { + bool has_nl = strchr(fmt, '\n') != NULL; + if (liblustreapi_cmd != NULL) fprintf(stderr, "%s %s: ", program_invocation_short_name, liblustreapi_cmd); else fprintf(stderr, "%s: ", program_invocation_short_name); - vfprintf(stderr, fmt, ap); - if (level & LLAPI_MSG_NO_ERRNO) - fprintf(stderr, "\n"); - else + + + if (level & LLAPI_MSG_NO_ERRNO) { + vfprintf(stderr, fmt, ap); + if (!has_nl) + fprintf(stderr, "\n"); + } else { + char *newfmt; + + /* + * Remove trailing linefeed so error string can be appended. + * @fmt is a const string, so we can't modify it directly. + */ + if (has_nl && (newfmt = strdup(fmt))) + *strrchr(newfmt, '\n') = '\0'; + else + newfmt = (char *)fmt; + + vfprintf(stderr, newfmt, ap); + if (newfmt != fmt) + free(newfmt); fprintf(stderr, ": %s (%d)\n", strerror(err), err); + } } static void info_callback_default(enum llapi_message_level level, int err, @@ -302,7 +318,7 @@ int llapi_ioctl_pack(struct obd_ioctl_data *data, char **pbuf, int max_len) if (*pbuf != NULL && data->ioc_len > max_len) { llapi_error(LLAPI_MSG_ERROR, -EINVAL, - "pbuf = %p, ioc_len = %u, max_len = %d\n", + "pbuf = %p, ioc_len = %u, max_len = %d", *pbuf, data->ioc_len, max_len); return -EINVAL; } @@ -384,14 +400,60 @@ int llapi_ioctl_unpack(struct obd_ioctl_data *data, char *pbuf, int max_len) /* XXX: llapi_xxx() functions return negative values upon failure */ -int llapi_stripe_limit_check(unsigned long long stripe_size, int stripe_offset, - int stripe_count, int stripe_pattern) +int llapi_layout_search_ost(__u32 ost, char *pname, char *fsname) +{ + char ostname[MAX_OBD_NAME + 64]; + char *pool_name = pname; + int rc = 0; + + /** + * The current policy is that the pool does not have to exist at the + * setstripe time, see sanity-pfl/-flr tests. + * If this logic will change, re-enable it. + * + * if (pname && strlen(pname) == 0) + */ + pool_name = NULL; + + snprintf(ostname, sizeof(ostname), "%s-OST%04x_UUID", + fsname, ost); + rc = llapi_search_ost(fsname, pool_name, ostname); + if (rc <= 0) { + if (rc == 0) + rc = -ENODEV; + + llapi_error(LLAPI_MSG_ERROR, rc, + "%s: cannot find OST %s in %s", __func__, ostname, + pool_name != NULL ? "pool" : "system"); + return rc; + } + + return 0; +} + +/** + * Verify the setstripe parameters before using. + * This is a pair method for comp_args_to_layout()/llapi_layout_sanity_cb() + * when just 1 component or a non-PFL layout is given. + * + * \param[in] param stripe parameters + * \param[in] pool_name pool name + * \param[in] fsname lustre FS name + * + * \retval 0, success + * < 0, error code on failre + */ +static int llapi_stripe_param_verify(const struct llapi_stripe_param *param, + char **pool_name, + char *fsname) { + int count; static int page_size; int rc = 0; if (page_size == 0) { - /* 64 KB is the largest common page size (on ia64/PPC/ARM), + /* + * 64 KB is the largest common page size (on ia64/PPC/ARM), * but check the local page size just in case. The page_size * will not change for the lifetime of this process at least. */ @@ -403,33 +465,94 @@ int llapi_stripe_limit_check(unsigned long long stripe_size, int stripe_offset, page_size, LOV_MIN_STRIPE_SIZE); } } - if (!llapi_stripe_size_is_aligned(stripe_size)) { + if (!llapi_stripe_size_is_aligned(param->lsp_stripe_size)) { rc = -EINVAL; - llapi_error(LLAPI_MSG_ERROR, rc, "error: bad stripe_size %llu, " - "must be an even multiple of %d bytes", - (unsigned long long)stripe_size, page_size); + llapi_error(LLAPI_MSG_ERROR, rc, + "error: bad stripe_size %llu, must be an even multiple of %d bytes", + param->lsp_stripe_size, page_size); goto out; } - if (!llapi_stripe_index_is_valid(stripe_offset)) { + if (!llapi_stripe_index_is_valid(param->lsp_stripe_offset)) { rc = -EINVAL; llapi_error(LLAPI_MSG_ERROR, rc, "error: bad stripe offset %d", - stripe_offset); + param->lsp_stripe_offset); goto out; } - if (!llapi_stripe_count_is_valid(stripe_count)) { + if (llapi_stripe_size_is_too_big(param->lsp_stripe_size)) { rc = -EINVAL; - llapi_error(LLAPI_MSG_ERROR, rc, "error: bad stripe count %d", - stripe_count); + llapi_error(LLAPI_MSG_ERROR, rc, + "error: stripe size '%llu' over 4GB limit", + param->lsp_stripe_size); goto out; } - if (llapi_stripe_size_is_too_big(stripe_size)) { + + count = param->lsp_stripe_count; + if (param->lsp_stripe_pattern == LOV_PATTERN_MDT) { rc = -EINVAL; llapi_error(LLAPI_MSG_ERROR, rc, - "error: stripe size '%llu' over 4GB limit", - (unsigned long long)stripe_size); + "Invalid pattern: %d, must be specified with -E\n", + param->lsp_stripe_pattern); goto out; + } else { + if (!llapi_stripe_count_is_valid(count)) { + rc = -EINVAL; + llapi_error(LLAPI_MSG_ERROR, rc, + "Invalid stripe count %d\n", count); + goto out; + } + } + + /* Make sure we have a good pool */ + if (*pool_name != NULL) { + if (!llapi_pool_name_is_valid(pool_name, fsname)) { + rc = -EINVAL; + llapi_error(LLAPI_MSG_ERROR, rc, + "Pool '%s' is not on filesystem '%s'", + *pool_name, fsname); + goto out; + } + + /* Make sure the pool exists and is non-empty */ + rc = llapi_search_ost(fsname, *pool_name, NULL); + if (rc < 1) { + char *err = rc == 0 ? "has no OSTs" : "does not exist"; + + rc = -EINVAL; + llapi_error(LLAPI_MSG_ERROR, rc, "pool '%s.%s' %s", + fsname, *pool_name, err); + goto out; + } + rc = 0; } + /* sanity check of target list */ + if (param->lsp_is_specific) { + bool found = false; + int i; + + for (i = 0; i < count; i++) { + rc = llapi_layout_search_ost(param->lsp_osts[i], + *pool_name, fsname); + if (rc) + goto out; + + /* Make sure stripe offset is in OST list. */ + if (param->lsp_osts[i] == param->lsp_stripe_offset) + found = true; + } + if (!found) { + rc = -EINVAL; + llapi_error(LLAPI_MSG_ERROR, rc, + "%s: stripe offset '%d' is not in the target list", + __func__, param->lsp_stripe_offset); + goto out; + } + } else if (param->lsp_stripe_offset != -1) { + rc = llapi_layout_search_ost(param->lsp_stripe_offset, + *pool_name, fsname); + if (rc) + goto out; + } out: errno = -rc; return rc; @@ -516,23 +639,21 @@ static int get_param_lmv(const char *path, const char *param, static int get_mds_md_size(const char *path) { - char buf[PATH_MAX], inst[PATH_MAX]; int md_size = lov_user_md_size(LOV_MAX_STRIPE_COUNT, LOV_USER_MAGIC_V3); - int rc; - - rc = llapi_getname(path, inst, sizeof(inst)); - if (rc != 0) - return rc; - /* Get the max ea size from llite parameters. */ - rc = get_lustre_param_value("llite", inst, FILTER_BY_EXACT, - "max_easize", buf, sizeof(buf)); - if (rc != 0) - return rc; + /* + * Rather than open the file and do the ioctl to get the + * instance name and close the file and search for the param + * file and open the param file and read the param file and + * parse the value and close the param file, let's just return + * a large enough value. It's 2020, RAM is cheap and this is + * much faster. + */ - rc = atoi(buf); + if (md_size < XATTR_SIZE_MAX) + md_size = XATTR_SIZE_MAX; - return rc > 0 ? rc : md_size; + return md_size; } int llapi_get_agent_uuid(char *path, char *buf, size_t bufsize) @@ -555,9 +676,9 @@ int llapi_file_open_param(const char *name, int flags, mode_t mode, const struct llapi_stripe_param *param) { char fsname[MAX_OBD_NAME + 1] = { 0 }; - char *pool_name = param->lsp_pool; struct lov_user_md *lum = NULL; - size_t lum_size = sizeof(*lum); + char *pool_name = param->lsp_pool; + size_t lum_size; int fd, rc; /* Make sure we are on a Lustre file system */ @@ -570,80 +691,17 @@ int llapi_file_open_param(const char *name, int flags, mode_t mode, } /* Check if the stripe pattern is sane. */ - rc = llapi_stripe_limit_check(param->lsp_stripe_size, - param->lsp_stripe_offset, - param->lsp_stripe_count, - param->lsp_stripe_pattern); + rc = llapi_stripe_param_verify(param, &pool_name, fsname); if (rc != 0) return rc; - /* Make sure we have a good pool */ - if (pool_name != NULL) { - /* in case user gives the full pool name ., - * strip the fsname */ - char *ptr = strchr(pool_name, '.'); - if (ptr != NULL) { - *ptr = '\0'; - if (strcmp(pool_name, fsname) != 0) { - *ptr = '.'; - llapi_err_noerrno(LLAPI_MSG_ERROR, - "Pool '%s' is not on filesystem '%s'", - pool_name, fsname); - return -EINVAL; - } - pool_name = ptr + 1; - } - - /* Make sure the pool exists and is non-empty */ - rc = llapi_search_ost(fsname, pool_name, NULL); - if (rc < 1) { - char *err = rc == 0 ? "has no OSTs" : "does not exist"; - - llapi_err_noerrno(LLAPI_MSG_ERROR, "pool '%s.%s' %s", - fsname, pool_name, err); - return -EINVAL; - } - - lum_size = sizeof(struct lov_user_md_v3); - } - - /* sanity check of target list */ - if (param->lsp_is_specific) { - char ostname[MAX_OBD_NAME + 64]; - bool found = false; - int i; - - for (i = 0; i < param->lsp_stripe_count; i++) { - snprintf(ostname, sizeof(ostname), "%s-OST%04x_UUID", - fsname, param->lsp_osts[i]); - rc = llapi_search_ost(fsname, pool_name, ostname); - if (rc <= 0) { - if (rc == 0) - rc = -ENODEV; - - llapi_error(LLAPI_MSG_ERROR, rc, - "%s: cannot find OST %s in %s", - __func__, ostname, - pool_name != NULL ? - "pool" : "system"); - return rc; - } - - /* Make sure stripe offset is in OST list. */ - if (param->lsp_osts[i] == param->lsp_stripe_offset) - found = true; - } - if (!found) { - llapi_error(LLAPI_MSG_ERROR, -EINVAL, - "%s: stripe offset '%d' is not in the " - "target list", - __func__, param->lsp_stripe_offset); - return -EINVAL; - } - + if (param->lsp_is_specific) lum_size = lov_user_md_size(param->lsp_stripe_count, LOV_USER_MAGIC_SPECIFIC); - } + else if (pool_name) + lum_size = sizeof(struct lov_user_md_v3); + else + lum_size = sizeof(*lum); lum = calloc(1, lum_size); if (lum == NULL) @@ -683,9 +741,11 @@ retry_open: lumv3->lmm_magic = LOV_USER_MAGIC_SPECIFIC; if (pool_name == NULL) { - /* LOV_USER_MAGIC_SPECIFIC uses v3 format plus specified + /* + * LOV_USER_MAGIC_SPECIFIC uses v3 format plus specified * OST list, therefore if pool is not specified we have - * to pack a null pool name for placeholder. */ + * to pack a null pool name for placeholder. + */ memset(lumv3->lmm_pool_name, 0, LOV_MAXPOOLNAME); } @@ -694,11 +754,15 @@ retry_open: } if (ioctl(fd, LL_IOC_LOV_SETSTRIPE, lum) != 0) { - char *errmsg = "stripe already set"; + char errmsg[512] = "stripe already set"; rc = -errno; if (errno != EEXIST && errno != EALREADY) - errmsg = strerror(errno); + strncpy(errmsg, strerror(errno), sizeof(errmsg) - 1); + if (rc == -EREMOTEIO) + snprintf(errmsg, sizeof(errmsg), + "inactive OST among your specified %d OST(s)", + param->lsp_stripe_count); llapi_err_noerrno(LLAPI_MSG_ERROR, "setstripe error for '%s': %s", name, errmsg); @@ -712,6 +776,18 @@ retry_open: return fd; } +int llapi_file_is_encrypted(int fd) +{ + unsigned long flags; + int rc; + + rc = ioctl(fd, FS_IOC_GETFLAGS, &flags); + if (rc == -1) + return -errno; + + return !!(flags & LUSTRE_ENCRYPT_FL); +} + int llapi_file_open_pool(const char *name, int flags, int mode, unsigned long long stripe_size, int stripe_offset, int stripe_count, int stripe_pattern, char *pool_name) @@ -727,12 +803,12 @@ int llapi_file_open_pool(const char *name, int flags, int mode, } int llapi_file_open(const char *name, int flags, int mode, - unsigned long long stripe_size, int stripe_offset, - int stripe_count, int stripe_pattern) + unsigned long long stripe_size, int stripe_offset, + int stripe_count, int stripe_pattern) { - return llapi_file_open_pool(name, flags, mode, stripe_size, - stripe_offset, stripe_count, - stripe_pattern, NULL); + return llapi_file_open_pool(name, flags, mode, stripe_size, + stripe_offset, stripe_count, + stripe_pattern, NULL); } int llapi_file_create_foreign(const char *name, mode_t mode, __u32 type, @@ -810,34 +886,34 @@ out_err: } int llapi_file_create(const char *name, unsigned long long stripe_size, - int stripe_offset, int stripe_count, int stripe_pattern) + int stripe_offset, int stripe_count, int stripe_pattern) { - int fd; + int fd; - fd = llapi_file_open_pool(name, O_CREAT | O_WRONLY, 0644, stripe_size, - stripe_offset, stripe_count, stripe_pattern, - NULL); - if (fd < 0) - return fd; + fd = llapi_file_open_pool(name, O_CREAT | O_WRONLY, 0644, stripe_size, + stripe_offset, stripe_count, stripe_pattern, + NULL); + if (fd < 0) + return fd; - close(fd); - return 0; + close(fd); + return 0; } int llapi_file_create_pool(const char *name, unsigned long long stripe_size, - int stripe_offset, int stripe_count, - int stripe_pattern, char *pool_name) + int stripe_offset, int stripe_count, + int stripe_pattern, char *pool_name) { - int fd; + int fd; - fd = llapi_file_open_pool(name, O_CREAT | O_WRONLY, 0644, stripe_size, - stripe_offset, stripe_count, stripe_pattern, - pool_name); - if (fd < 0) - return fd; + fd = llapi_file_open_pool(name, O_CREAT | O_WRONLY, 0644, stripe_size, + stripe_offset, stripe_count, stripe_pattern, + pool_name); + if (fd < 0) + return fd; - close(fd); - return 0; + close(fd); + return 0; } static int verify_dir_param(const char *name, @@ -865,8 +941,10 @@ static int verify_dir_param(const char *name, /* Make sure we have a good pool */ if (pool_name != NULL) { - /* in case user gives the full pool name ., - * strip the fsname */ + /* + * in case user gives the full pool name ., + * strip the fsname + */ char *ptr = strchr(pool_name, '.'); if (ptr != NULL) { @@ -920,8 +998,7 @@ static int verify_dir_param(const char *name, } if (!found) { llapi_error(LLAPI_MSG_ERROR, -EINVAL, - "%s: stripe offset '%d' is not in the " - "target list", + "%s: stripe offset '%d' is not in the target list", __func__, param->lsp_stripe_offset); return -EINVAL; } @@ -938,6 +1015,8 @@ static inline void param2lmu(struct lmv_user_md *lmu, lmu->lum_stripe_count = param->lsp_stripe_count; lmu->lum_stripe_offset = param->lsp_stripe_offset; lmu->lum_hash_type = param->lsp_stripe_pattern; + lmu->lum_max_inherit = param->lsp_max_inherit; + lmu->lum_max_inherit_rr = param->lsp_max_inherit_rr; if (param->lsp_pool != NULL) strncpy(lmu->lum_pool_name, param->lsp_pool, LOV_MAXPOOLNAME); if (param->lsp_is_specific) { @@ -975,6 +1054,7 @@ int llapi_dir_set_default_lmv(const char *name, rc = ioctl(fd, LL_IOC_LMV_SET_DEFAULT_STRIPE, &lmu); if (rc < 0) { char *errmsg = "stripe already set"; + rc = -errno; if (errno != EEXIST && errno != EALREADY) errmsg = strerror(errno); @@ -1061,6 +1141,9 @@ int llapi_dir_create(const char *name, mode_t mode, data.ioc_inlbuf2 = (char *)lmu; data.ioc_inllen2 = lmu_size; data.ioc_type = mode; + if (param->lsp_is_create) + /* borrow obdo1.o_flags to store this flag */ + data.ioc_obdo1.o_flags = OBD_FL_OBDMDEXISTS; rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf)); if (rc) { llapi_error(LLAPI_MSG_ERROR, rc, @@ -1124,10 +1207,10 @@ int llapi_dir_create_foreign(const char *name, mode_t mode, __u32 type, if (len > XATTR_SIZE_MAX - offsetof(struct lmv_foreign_md, lfm_value) || len <= 0) { rc = -EINVAL; - llapi_error(LLAPI_MSG_ERROR, rc, "invalid LOV EA length %zu " - "(must be 0 < len < %zu)\n", len, - XATTR_SIZE_MAX - - offsetof(struct lmv_foreign_md, lfm_value)); + llapi_error(LLAPI_MSG_ERROR, rc, + "invalid LOV EA length %zu (must be 0 < len < %zu)", + len, XATTR_SIZE_MAX - + offsetof(struct lmv_foreign_md, lfm_value)); return rc; } lfm_size = len + offsetof(struct lmv_foreign_md, lfm_value); @@ -1209,47 +1292,6 @@ int llapi_dir_create_pool(const char *name, int mode, int stripe_offset, return llapi_dir_create(name, mode, ¶m); } -int llapi_direntry_remove(char *dname) -{ - char *dirpath = NULL; - char *namepath = NULL; - char *dir; - char *filename; - int fd = -1; - int rc = 0; - - dirpath = strdup(dname); - namepath = strdup(dname); - if (!dirpath || !namepath) - return -ENOMEM; - - filename = basename(namepath); - - dir = dirname(dirpath); - - fd = open(dir, O_DIRECTORY | O_RDONLY); - if (fd < 0) { - rc = -errno; - llapi_error(LLAPI_MSG_ERROR, rc, "unable to open '%s'", - filename); - goto out; - } - - if (ioctl(fd, LL_IOC_REMOVE_ENTRY, filename)) { - char *errmsg = strerror(errno); - llapi_err_noerrno(LLAPI_MSG_ERROR, - "error on ioctl %#jx for '%s' (%d): %s", - (uintmax_t)LL_IOC_LMV_SETSTRIPE, filename, - fd, errmsg); - } -out: - free(dirpath); - free(namepath); - if (fd != -1) - close(fd); - return rc; -} - /* * Find the fsname, the full path, and/or an open fd. * Either the fsname or path must not be NULL @@ -1260,11 +1302,11 @@ int get_root_path(int want, char *fsname, int *outfd, char *path, int index) char buf[PATH_MAX], mntdir[PATH_MAX]; char *ptr, *ptr_end; FILE *fp; - int idx = 0, len = 0, mntlen, fd; + int idx = 0, mntlen = 0, fd; int rc = -ENODEV; int fsnamelen, mountlen; - /* get the mount point */ + /* get the mount point */ fp = setmntent(PROC_MOUNTS, "r"); if (fp == NULL) { rc = -EIO; @@ -1272,23 +1314,25 @@ int get_root_path(int want, char *fsname, int *outfd, char *path, int index) "cannot retrieve filesystem mount point"); return rc; } - while (1) { - if (getmntent_r(fp, &mnt, buf, sizeof(buf)) == NULL) - break; + while (1) { + if (getmntent_r(fp, &mnt, buf, sizeof(buf)) == NULL) + break; - if (!llapi_is_lustre_mnt(&mnt)) - continue; + if (!llapi_is_lustre_mnt(&mnt)) + continue; - if ((want & WANT_INDEX) && (idx++ != index)) - continue; + if ((want & WANT_INDEX) && (idx++ != index)) + continue; - mntlen = strlen(mnt.mnt_dir); + mntlen = strlen(mnt.mnt_dir); ptr = strchr(mnt.mnt_fsname, '/'); while (ptr && *ptr == '/') ptr++; - /* thanks to the call to llapi_is_lustre_mnt() above, + /* + * thanks to the call to llapi_is_lustre_mnt() above, * we are sure that mnt.mnt_fsname contains ":/", - * so ptr should never be NULL */ + * so ptr should never be NULL + */ if (ptr == NULL) continue; ptr_end = ptr; @@ -1297,13 +1341,13 @@ int get_root_path(int want, char *fsname, int *outfd, char *path, int index) /* Check the fsname for a match, if given */ mountlen = ptr_end - ptr; - if (!(want & WANT_FSNAME) && fsname != NULL && + if (!(want & WANT_FSNAME) && fsname != NULL && (fsnamelen = strlen(fsname)) > 0 && (fsnamelen != mountlen || (strncmp(ptr, fsname, mountlen) != 0))) - continue; + continue; - /* If the path isn't set return the first one we find */ + /* If the path isn't set return the first one we find */ if (path == NULL || strlen(path) == 0) { strncpy(mntdir, mnt.mnt_dir, sizeof(mntdir) - 1); mntdir[sizeof(mntdir) - 1] = '\0'; @@ -1314,16 +1358,19 @@ int get_root_path(int want, char *fsname, int *outfd, char *path, int index) rc = 0; break; /* Otherwise find the longest matching path */ - } else if ((strlen(path) >= mntlen) && (mntlen >= len) && + } else if ((strlen(path) >= mntlen) && (strncmp(mnt.mnt_dir, path, mntlen) == 0)) { + /* check the path format */ + if (strlen(path) > mntlen && path[mntlen] != '/') + continue; strncpy(mntdir, mnt.mnt_dir, sizeof(mntdir) - 1); mntdir[sizeof(mntdir) - 1] = '\0'; - len = mntlen; if ((want & WANT_FSNAME) && fsname != NULL) { strncpy(fsname, ptr, mountlen); fsname[mountlen] = '\0'; } rc = 0; + break; } } endmntent(fp); @@ -1331,16 +1378,15 @@ int get_root_path(int want, char *fsname, int *outfd, char *path, int index) /* Found it */ if (rc == 0) { if ((want & WANT_PATH) && path != NULL) { - strncpy(path, mntdir, PATH_MAX); - path[strlen(mntdir)] = '\0'; + strncpy(path, mntdir, mntlen); + path[mntlen] = '\0'; } if (want & WANT_FD) { fd = open(mntdir, O_RDONLY | O_DIRECTORY | O_NONBLOCK); if (fd < 0) { rc = -errno; llapi_error(LLAPI_MSG_ERROR, rc, - "cannot open '%s': %s", mntdir, - strerror(-rc)); + "cannot open '%s'", mntdir); } else { *outfd = fd; @@ -1366,29 +1412,30 @@ int get_root_path(int want, char *fsname, int *outfd, char *path, int index) * See function lfs_osts in lfs.c for an example of the index use. */ int llapi_search_mounts(const char *pathname, int index, char *mntdir, - char *fsname) + char *fsname) { - int want = WANT_PATH, idx = -1; + int want = WANT_PATH, idx = -1; - if (!pathname || pathname[0] == '\0') { - want |= WANT_INDEX; - idx = index; - } else - strcpy(mntdir, pathname); + if (!pathname || pathname[0] == '\0') { + want |= WANT_INDEX; + idx = index; + } else { + strcpy(mntdir, pathname); + } - if (fsname) - want |= WANT_FSNAME; - return get_root_path(want, fsname, NULL, mntdir, idx); + if (fsname) + want |= WANT_FSNAME; + return get_root_path(want, fsname, NULL, mntdir, idx); } /* Given a path, find the corresponding Lustre fsname */ int llapi_search_fsname(const char *pathname, char *fsname) { - char *path; - int rc; + char *path; + int rc; - path = realpath(pathname, NULL); - if (path == NULL) { + path = realpath(pathname, NULL); + if (path == NULL) { char tmp[PATH_MAX - 1]; char buf[PATH_MAX]; char *ptr; @@ -1396,10 +1443,12 @@ int llapi_search_fsname(const char *pathname, char *fsname) tmp[0] = '\0'; buf[0] = '\0'; if (pathname[0] != '/') { - /* Need an absolute path, but realpath() only works for + /* + * 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. */ + * case the relative pathname contains ".." in it. + */ char realpath[PATH_MAX - 1]; if (getcwd(realpath, sizeof(realpath) - 2) == NULL) { @@ -1454,44 +1503,12 @@ int llapi_search_fsname(const char *pathname, char *fsname) int llapi_search_rootpath(char *pathname, const char *fsname) { - /* pathname can be used as an argument by get_root_path(), - * clear it for safety */ - pathname[0] = 0; - return get_root_path(WANT_PATH, (char *)fsname, NULL, pathname, -1); -} - -int llapi_getname(const char *path, char *buf, size_t size) -{ - struct obd_uuid uuid_buf; - char *uuid = uuid_buf.uuid; - char *cfg_instance; - int rc, len, fsname_len; - - memset(&uuid_buf, 0, sizeof(uuid_buf)); - rc = llapi_file_get_lov_uuid(path, &uuid_buf); - if (rc) - return rc; - /* - * We want to turn testfs-clilov-ffff88002738bc00 into - * testfs-ffff88002738bc00 in a portable way that doesn't depend - * on what is after "-clilov-" as it may change in the future. - * Unfortunately, the "fsname" part may contain a dash, so we - * can't just skip to the first dash, and the "instance" may be a - * UUID in the future, so we can't necessarily go to the last dash. + * pathname can be used as an argument by get_root_path(), + * clear it for safety */ - cfg_instance = strstr(uuid, "-clilov-"); - if (!cfg_instance) - return -EINVAL; - - fsname_len = cfg_instance - uuid; - cfg_instance += strlen("-clilov-"); - len = snprintf(buf, size, "%.*s-%s", fsname_len, uuid, cfg_instance); - - if (len >= size) - rc = -ENAMETOOLONG; - - return rc; + pathname[0] = 0; + return get_root_path(WANT_PATH, (char *)fsname, NULL, pathname, -1); } /** @@ -1506,7 +1523,7 @@ int llapi_getname(const char *path, char *buf, size_t size) * \retval -error failure */ int llapi_get_poolmembers(const char *poolname, char **members, - int list_size, char *buffer, int buffer_size) + int list_size, char *buffer, int buffer_size) { char fsname[PATH_MAX]; char *pool, *tmp; @@ -1549,31 +1566,31 @@ int llapi_get_poolmembers(const char *poolname, char **members, return rc; } - rc = 0; - while (fgets(buf, sizeof(buf), fd) != NULL) { - if (nb_entries >= list_size) { - rc = -EOVERFLOW; - break; - } + rc = 0; + while (fgets(buf, sizeof(buf), fd) != NULL) { + if (nb_entries >= list_size) { + rc = -EOVERFLOW; + break; + } buf[sizeof(buf) - 1] = '\0'; - /* remove '\n' */ - tmp = strchr(buf, '\n'); - if (tmp != NULL) - *tmp='\0'; - if (used + strlen(buf) + 1 > buffer_size) { - rc = -EOVERFLOW; - break; - } - - strcpy(buffer + used, buf); - members[nb_entries] = buffer + used; - used += strlen(buf) + 1; - nb_entries++; - rc = nb_entries; - } - - fclose(fd); - return rc; + /* remove '\n' */ + tmp = strchr(buf, '\n'); + if (tmp != NULL) + *tmp = '\0'; + if (used + strlen(buf) + 1 > buffer_size) { + rc = -EOVERFLOW; + break; + } + + strcpy(buffer + used, buf); + members[nb_entries] = buffer + used; + used += strlen(buf) + 1; + nb_entries++; + rc = nb_entries; + } + + fclose(fd); + return rc; } /** @@ -1588,7 +1605,7 @@ int llapi_get_poolmembers(const char *poolname, char **members, * \retval -error failure */ int llapi_get_poollist(const char *name, char **poollist, int list_size, - char *buffer, int buffer_size) + char *buffer, int buffer_size) { glob_t pathname; char *fsname; @@ -1652,17 +1669,17 @@ int llapi_get_poollist(const char *name, char **poollist, int list_size, goto free_dir; } - /* ignore . and .. */ + /* ignore . and .. */ if (!strcmp(pool->d_name, ".") || !strcmp(pool->d_name, "..")) - continue; + continue; - /* check output bounds */ + /* check output bounds */ if (nb_entries >= list_size) { rc = -EOVERFLOW; goto free_dir_no_msg; } - /* +2 for '.' and final '\0' */ + /* +2 for '.' and final '\0' */ if (used + strlen(pool->d_name) + strlen(fsname) + 2 > buffer_size) { rc = -EOVERFLOW; @@ -1670,9 +1687,9 @@ int llapi_get_poollist(const char *name, char **poollist, int list_size, } sprintf(buffer + used, "%s.%s", fsname, pool->d_name); - poollist[nb_entries] = buffer + used; + poollist[nb_entries] = buffer + used; used += strlen(pool->d_name) + strlen(fsname) + 2; - nb_entries++; + nb_entries++; } while (1); free_dir: @@ -1694,12 +1711,42 @@ free_path: /* wrapper for lfs.c and obd.c */ int llapi_poollist(const char *name) { - /* list of pool names (assume that pool count is smaller - than OST count) */ + int poolcount, rc, i; + char *buf, **pools; + + rc = llapi_get_poolbuf(name, &buf, &pools, &poolcount); + if (rc) + return rc; + + for (i = 0; i < poolcount; i++) + llapi_printf(LLAPI_MSG_NORMAL, "%s\n", pools[i]); + free(buf); + + return 0; +} + +/** + * Get buffer that holds uuids and the list of pools in a filesystem. + * + * \param name filesystem name or path + * \param buf bufffer that has to be freed if function returns 0 + * \param pools pointer to the list of pools in buffer + * \param poolcount number of pools + * + * \return 0 when found at least 1 pool, i.e. poolcount > 0 + * \retval -error failure + */ +int llapi_get_poolbuf(const char *name, char **buf, + char ***pools, int *poolcount) +{ + /* + * list of pool names (assume that pool count is smaller + * than OST count) + */ char **list, *buffer = NULL, *fsname = (char *)name; char *poolname = NULL, *tmp = NULL, data[16]; enum param_filter type = FILTER_BY_PATH; - int obdcount, bufsize, rc, nb, i; + int obdcount, bufsize, rc, nb; if (name == NULL) return -EINVAL; @@ -1721,50 +1768,61 @@ int llapi_poollist(const char *name) goto err; obdcount = atoi(data); - /* Allocate space for each fsname-OST0000_UUID, 1 per OST, - * and also an array to store the pointers for all that - * allocated space. */ + /* + * Allocate space for each fsname-OST0000_UUID, 1 per OST, + * and also an array to store the pointers for all that + * allocated space. + */ retry_get_pools: - bufsize = sizeof(struct obd_uuid) * obdcount; - buffer = realloc(tmp, bufsize + sizeof(*list) * obdcount); - if (buffer == NULL) { - rc = -ENOMEM; - goto err; - } - list = (char **) (buffer + bufsize); - - if (!poolname) { - /* name is a path or fsname */ - nb = llapi_get_poollist(name, list, obdcount, - buffer, bufsize); - } else { - /* name is a pool name (.) */ - nb = llapi_get_poolmembers(name, list, obdcount, - buffer, bufsize); - } - - if (nb == -EOVERFLOW) { - obdcount *= 2; - tmp = buffer; - goto retry_get_pools; - } - - for (i = 0; i < nb; i++) - llapi_printf(LLAPI_MSG_NORMAL, "%s\n", list[i]); - rc = (nb < 0 ? nb : 0); + bufsize = sizeof(struct obd_uuid) * obdcount; + buffer = realloc(tmp, bufsize + sizeof(*list) * obdcount); + if (buffer == NULL) { + rc = -ENOMEM; + goto err; + } + list = (char **) (buffer + bufsize); + + if (!poolname) { + /* name is a path or fsname */ + nb = llapi_get_poollist(name, list, obdcount, + buffer, bufsize); + } else { + /* name is a pool name (.) */ + nb = llapi_get_poolmembers(name, list, obdcount, + buffer, bufsize); + } + + if (nb == -EOVERFLOW) { + obdcount *= 2; + tmp = buffer; + goto retry_get_pools; + } + + rc = (nb < 0 ? nb : 0); + if (!rc) { + *buf = buffer; + *pools = list; + *poolcount = nb; + } err: - if (buffer) - free(buffer); + /* Don't free buffer, it will be used later */ + if (rc && buffer) + free(buffer); if (fsname != NULL && type == FILTER_BY_FS_NAME) free(fsname); return rc; } -typedef int (semantic_func_t)(char *path, DIR *parent, DIR **d, +typedef int (semantic_func_t)(char *path, int p, int *d, void *data, struct dirent64 *de); #define OBD_NOT_FOUND (-1) +static bool lmv_is_foreign(__u32 magic) +{ + return magic == LMV_MAGIC_FOREIGN; +} + static void find_param_fini(struct find_param *param) { if (param->fp_migrate) @@ -1830,37 +1888,40 @@ static int common_param_init(struct find_param *param, char *path) return 0; } -static int cb_common_fini(char *path, DIR *parent, DIR **dirp, void *data, +static int cb_common_fini(char *path, int p, int *dp, void *data, struct dirent64 *de) { struct find_param *param = data; - param->fp_depth--; + param->fp_depth--; return 0; } /* set errno upon failure */ -static DIR *opendir_parent(const char *path) +static int open_parent(const char *path) { char *path_copy; char *parent_path; - DIR *parent; + int parent; path_copy = strdup(path); if (path_copy == NULL) - return NULL; + return -1; parent_path = dirname(path_copy); - parent = opendir(parent_path); + parent = open(parent_path, O_RDONLY|O_NDELAY|O_DIRECTORY); free(path_copy); return parent; } -static int cb_get_dirstripe(char *path, DIR *d, struct find_param *param) +static int cb_get_dirstripe(char *path, int *d, struct find_param *param) { int ret; + bool did_nofollow = false; + if (!d || *d < 0) + return -ENOTDIR; again: param->fp_lmv_md->lum_stripe_count = param->fp_lmv_stripe_count; if (param->fp_get_default_lmv) @@ -1868,13 +1929,42 @@ again: else param->fp_lmv_md->lum_magic = LMV_MAGIC_V1; - ret = ioctl(dirfd(d), LL_IOC_LMV_GETSTRIPE, param->fp_lmv_md); + ret = ioctl(*d, LL_IOC_LMV_GETSTRIPE, param->fp_lmv_md); + + /* if ENOTTY likely to be a fake symlink, so try again after + * new open() with O_NOFOLLOW, but only once to prevent any + * loop like for the path of a file/dir not on Lustre !! + */ + if (ret < 0 && errno == ENOTTY && !did_nofollow) { + int fd, ret2; + + did_nofollow = true; + fd = open(path, O_RDONLY | O_NOFOLLOW); + if (fd < 0) { + /* restore original errno */ + errno = ENOTTY; + return ret; + } + + /* close original fd and set new */ + close(*d); + *d = fd; + ret2 = ioctl(fd, LL_IOC_LMV_GETSTRIPE, param->fp_lmv_md); + if (ret2 < 0 && errno != E2BIG) { + /* restore original errno */ + errno = ENOTTY; + return ret; + } + /* LMV is ok or need to handle E2BIG case now */ + ret = ret2; + } + if (errno == E2BIG && ret != 0) { int stripe_count; int lmv_size; /* if foreign LMV case, fake stripes number */ - if (param->fp_lmv_md->lum_magic == LMV_MAGIC_FOREIGN) { + if (lmv_is_foreign(param->fp_lmv_md->lum_magic)) { struct lmv_foreign_md *lfm; lfm = (struct lmv_foreign_md *)param->fp_lmv_md; @@ -1886,8 +1976,7 @@ again: stripe_count = lmv_foreign_to_md_stripes(size); } else { llapi_error(LLAPI_MSG_ERROR, -EINVAL, - "error: invalid %d foreign size " - "returned from ioctl", + "error: invalid %d foreign size returned from ioctl", lfm->lfm_length); return -EINVAL; } @@ -1911,6 +2000,7 @@ again: } goto again; } + return ret; } @@ -1990,30 +2080,55 @@ int get_lmd_info_fd(const char *path, int parent_fd, int dir_fd, return -EINVAL; if (dir_fd >= 0) { - /* LL_IOC_MDC_GETINFO operates on the current directory inode + /* + * LL_IOC_MDC_GETINFO operates on the current directory inode * and returns struct lov_user_mds_data, while * LL_IOC_LOV_GETSTRIPE returns only struct lov_user_md. */ if (type == GET_LMD_INFO) - cmd = use_old_ioctl ? LL_IOC_MDC_GETINFO_OLD : - LL_IOC_MDC_GETINFO; + cmd = use_old_ioctl ? LL_IOC_MDC_GETINFO_V1 : + LL_IOC_MDC_GETINFO_V2; else cmd = LL_IOC_LOV_GETSTRIPE; retry_getinfo: ret = ioctl(dir_fd, cmd, lmdbuf); - if (ret < 0 && errno == ENOTTY && cmd == LL_IOC_MDC_GETINFO) { - cmd = LL_IOC_MDC_GETINFO_OLD; + if (ret < 0 && errno == ENOTTY && + cmd == LL_IOC_MDC_GETINFO_V2) { + cmd = LL_IOC_MDC_GETINFO_V1; use_old_ioctl = true; goto retry_getinfo; } - if (cmd == LL_IOC_MDC_GETINFO_OLD && !ret) + if (cmd == LL_IOC_MDC_GETINFO_V1 && !ret) ret = convert_lmdbuf_v1v2(lmdbuf, lmdlen); + + if (ret < 0 && errno == ENOTTY && type == GET_LMD_STRIPE) { + int dir_fd2; + + /* retry ioctl() after new open() with O_NOFOLLOW + * just in case it could be a fake symlink + * need using a new open() as dir_fd is being closed + * by caller + */ + + dir_fd2 = open(path, O_RDONLY | O_NDELAY | O_NOFOLLOW); + if (dir_fd2 < 0) { + /* return original error */ + errno = ENOTTY; + } else { + ret = ioctl(dir_fd2, cmd, lmdbuf); + /* pass new errno or success back to caller */ + + close(dir_fd2); + } + } + } else if (parent_fd >= 0) { const char *fname = strrchr(path, '/'); - /* IOC_MDC_GETFILEINFO takes as input the filename (relative to + /* + * IOC_MDC_GETFILEINFO takes as input the filename (relative to * the parent directory) and returns struct lov_user_mds_data, * while IOC_MDC_GETFILESTRIPE returns only struct lov_user_md. * @@ -2033,21 +2148,21 @@ retry_getinfo: errno = EINVAL; else { if (type == GET_LMD_INFO) - cmd = use_old_ioctl ? IOC_MDC_GETFILEINFO_OLD : - IOC_MDC_GETFILEINFO; + cmd = use_old_ioctl ? IOC_MDC_GETFILEINFO_V1 : + IOC_MDC_GETFILEINFO_V2; else cmd = IOC_MDC_GETFILESTRIPE; retry_getfileinfo: ret = ioctl(parent_fd, cmd, lmdbuf); if (ret < 0 && errno == ENOTTY && - cmd == IOC_MDC_GETFILEINFO) { - cmd = IOC_MDC_GETFILEINFO_OLD; + cmd == IOC_MDC_GETFILEINFO_V2) { + cmd = IOC_MDC_GETFILEINFO_V1; use_old_ioctl = true; goto retry_getfileinfo; } - if (cmd == IOC_MDC_GETFILEINFO_OLD && !ret) + if (cmd == IOC_MDC_GETFILEINFO_V1 && !ret) ret = convert_lmdbuf_v1v2(lmdbuf, lmdlen); } } @@ -2056,7 +2171,8 @@ retry_getfileinfo: if (errno == ENOTTY) { lstat_t st; - /* ioctl is not supported, it is not a lustre fs. + /* + * ioctl is not supported, it is not a lustre fs. * Do the regular lstat(2) instead. */ ret = lstat_f(path, &st); @@ -2068,7 +2184,8 @@ retry_getfileinfo: } convert_lmd_statx(lmd, &st, true); - /* It may be wrong to set use_old_ioctl with true as + /* + * It may be wrong to set use_old_ioctl with true as * the file is not a lustre fs. So reset it with false * directly here. */ @@ -2089,55 +2206,103 @@ retry_getfileinfo: return ret; } -static int get_lmd_info(char *path, DIR *parent, DIR *dir, void *lmdbuf, - int lmdlen, enum get_lmd_info_type type) -{ - int parent_fd = -1; - int dir_fd = -1; - - if (parent) - parent_fd = dirfd(parent); - if (dir) - dir_fd = dirfd(dir); - - return get_lmd_info_fd(path, parent_fd, dir_fd, lmdbuf, lmdlen, type); -} - -static int llapi_semantic_traverse(char *path, int size, DIR *parent, +static int llapi_semantic_traverse(char *path, int size, int parent, semantic_func_t sem_init, semantic_func_t sem_fini, void *data, struct dirent64 *de) { struct find_param *param = (struct find_param *)data; struct dirent64 *dent; - int len, ret; - DIR *d, *p = NULL; + int len, ret, d, p = -1; + DIR *dir = NULL; ret = 0; len = strlen(path); - d = opendir(path); - if (!d && errno != ENOTDIR) { - ret = -errno; - llapi_error(LLAPI_MSG_ERROR, ret, "%s: Failed to open '%s'", - __func__, path); - return ret; - } else if (!d && !parent) { - /* ENOTDIR. Open the parent dir. */ - p = opendir_parent(path); - if (!p) { - ret = -errno; - goto out; + d = open(path, O_RDONLY|O_NDELAY|O_DIRECTORY); + /* if an invalid fake dir symlink, opendir() will return EINVAL + * instead of ENOTDIR. If a valid but dangling faked or real file/dir + * symlink ENOENT will be returned. For a valid/resolved fake or real + * file symlink ENOTDIR will be returned as for a regular file. + * opendir() will be successful for a valid and resolved fake or real + * dir simlink or a regular dir. + */ + if (d == -1 && errno != ENOTDIR && errno != EINVAL && errno != ENOENT) { + ret = -errno; + llapi_error(LLAPI_MSG_ERROR, ret, "%s: Failed to open '%s'", + __func__, path); + return ret; + } else if (d == -1) { + if (errno == ENOENT || errno == EINVAL) { + int old_errno = errno; + + /* try to open with O_NOFOLLOW this will help + * differentiate fake vs real symlinks + * it is ok to not use O_DIRECTORY with O_RDONLY + * and it will prevent the need to deal with ENOTDIR + * error, instead of ELOOP, being returned by recent + * kernels for real symlinks + */ + d = open(path, O_RDONLY|O_NDELAY|O_NOFOLLOW); + /* if a dangling real symlink should return ELOOP, or + * again ENOENT if really non-existing path, or E...?? + * So return original error. If success or ENOTDIR, path + * is likely to be a fake dir/file symlink, so continue + */ + if (d == -1) { + ret = -old_errno; + goto out; + } + } - } - if (sem_init && (ret = sem_init(path, parent ?: p, &d, data, de))) - goto err; + /* ENOTDIR */ + if (parent == -1 && d == -1) { + /* Open the parent dir. */ + p = open_parent(path); + if (p == -1) { + ret = -errno; + goto out; + } + } + } else { /* d != -1 */ + int d2; + + /* try to reopen dir with O_NOFOLLOW just in case of a foreign + * symlink dir + */ + d2 = open(path, O_RDONLY|O_NDELAY|O_NOFOLLOW); + if (d2 != -1) { + close(d); + d = d2; + } else { + /* continue with d */ + errno = 0; + } + } + + if (sem_init) { + ret = sem_init(path, (parent != -1) ? parent : p, &d, data, de); + if (ret) + goto err; + } + + if (d == -1) + goto out; + + dir = fdopendir(d); + if (dir == NULL) { + /* ENOTDIR if fake symlink, do not consider it as an error */ + if (errno != ENOTDIR) + llapi_error(LLAPI_MSG_ERROR, errno, + "fdopendir() failed"); + else + errno = 0; - if (d == NULL) goto out; + } - while ((dent = readdir64(d)) != NULL) { + while ((dent = readdir64(dir)) != NULL) { int rc; if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, "..")) @@ -2146,32 +2311,32 @@ static int llapi_semantic_traverse(char *path, int size, DIR *parent, path[len] = 0; if ((len + dent->d_reclen + 2) > size) { llapi_err_noerrno(LLAPI_MSG_ERROR, - "error: %s: string buffer too small", - __func__); + "error: %s: string buffer too small for %s", + __func__, path); break; } strcat(path, "/"); strcat(path, dent->d_name); if (dent->d_type == DT_UNKNOWN) { - lstatx_t *stx = ¶m->fp_lmd->lmd_stx; + struct lov_user_mds_data *lmd = param->fp_lmd; - rc = get_lmd_info(path, d, NULL, param->fp_lmd, - param->fp_lum_size, GET_LMD_INFO); + rc = get_lmd_info_fd(path, d, -1, param->fp_lmd, + param->fp_lum_size, GET_LMD_INFO); if (rc == 0) - dent->d_type = IFTODT(stx->stx_mode); + dent->d_type = IFTODT(lmd->lmd_stx.stx_mode); else if (ret == 0) ret = rc; if (rc == -ENOENT) continue; } - switch (dent->d_type) { - case DT_UNKNOWN: - llapi_err_noerrno(LLAPI_MSG_ERROR, - "error: %s: '%s' is UNKNOWN type %d", - __func__, dent->d_name, dent->d_type); - break; + switch (dent->d_type) { + case DT_UNKNOWN: + llapi_err_noerrno(LLAPI_MSG_ERROR, + "error: %s: '%s' is UNKNOWN type %d", + __func__, dent->d_name, dent->d_type); + break; case DT_DIR: rc = llapi_semantic_traverse(path, size, d, sem_init, sem_fini, data, dent); @@ -2189,84 +2354,103 @@ static int llapi_semantic_traverse(char *path, int size, DIR *parent, } if (sem_fini && rc == 0) sem_fini(path, d, NULL, data, dent); - } - } + } + } out: - path[len] = 0; + path[len] = 0; if (sem_fini) sem_fini(path, parent, &d, data, de); err: - if (d) - closedir(d); - if (p) - closedir(p); + if (d != -1) { + if (dir) + closedir(dir); + else + close(d); + } + if (p != -1) + close(p); return ret; } static int param_callback(char *path, semantic_func_t sem_init, - semantic_func_t sem_fini, struct find_param *param) + semantic_func_t sem_fini, struct find_param *param) { - int ret, len = strlen(path); - char *buf; + int ret, len = strlen(path); + char *buf; - if (len > PATH_MAX) { - ret = -EINVAL; - llapi_error(LLAPI_MSG_ERROR, ret, - "Path name '%s' is too long", path); - return ret; - } + if (len > PATH_MAX) { + ret = -EINVAL; + llapi_error(LLAPI_MSG_ERROR, ret, + "Path name '%s' is too long", path); + return ret; + } - buf = (char *)malloc(PATH_MAX + 1); - if (!buf) - return -ENOMEM; + buf = (char *)malloc(2 * PATH_MAX); + if (!buf) + return -ENOMEM; snprintf(buf, PATH_MAX + 1, "%s", path); - ret = common_param_init(param, buf); - if (ret) - goto out; + ret = common_param_init(param, buf); + if (ret) + goto out; param->fp_depth = 0; - ret = llapi_semantic_traverse(buf, PATH_MAX + 1, NULL, sem_init, - sem_fini, param, NULL); + ret = llapi_semantic_traverse(buf, 2 * PATH_MAX, -1, sem_init, + sem_fini, param, NULL); out: - find_param_fini(param); - free(buf); - return ret < 0 ? ret : 0; + find_param_fini(param); + free(buf); + return ret < 0 ? ret : 0; } int llapi_file_fget_lov_uuid(int fd, struct obd_uuid *lov_name) { - int rc = ioctl(fd, OBD_IOC_GETNAME, lov_name); + int rc; + rc = ioctl(fd, OBD_IOC_GETDTNAME, lov_name); + if (rc && errno == ENOTTY) + rc = ioctl(fd, OBD_IOC_GETNAME_OLD, lov_name); if (rc) { rc = -errno; llapi_error(LLAPI_MSG_ERROR, rc, "cannot get lov name"); } + return rc; } int llapi_file_fget_lmv_uuid(int fd, struct obd_uuid *lov_name) { - int rc = ioctl(fd, OBD_IOC_GETMDNAME, lov_name); - if (rc) { - rc = -errno; - llapi_error(LLAPI_MSG_ERROR, rc, "error: can't get lmv name."); - } - return rc; + int rc; + + rc = ioctl(fd, OBD_IOC_GETMDNAME, lov_name); + if (rc) { + rc = -errno; + llapi_error(LLAPI_MSG_ERROR, rc, "error: can't get lmv name."); + } + + return rc; } int llapi_file_get_lov_uuid(const char *path, struct obd_uuid *lov_uuid) { int fd, rc; - fd = open(path, O_RDONLY | O_NONBLOCK); + /* do not follow faked symlinks */ + fd = open(path, O_RDONLY | O_NONBLOCK | O_NOFOLLOW); if (fd < 0) { - rc = -errno; - llapi_error(LLAPI_MSG_ERROR, rc, "cannot open '%s'", path); - return rc; + /* real symlink should have failed with ELOOP so retry without + * O_NOFOLLOW just in case + */ + fd = open(path, O_RDONLY | O_NONBLOCK); + if (fd < 0) { + rc = -errno; + llapi_error(LLAPI_MSG_ERROR, rc, "cannot open '%s'", + path); + return rc; + } } rc = llapi_file_fget_lov_uuid(fd, lov_uuid); @@ -2293,8 +2477,8 @@ int llapi_file_get_lmv_uuid(const char *path, struct obd_uuid *lov_uuid) } enum tgt_type { - LOV_TYPE = 1, - LMV_TYPE + LOV_TYPE = 1, + LMV_TYPE }; /* @@ -2304,7 +2488,7 @@ enum tgt_type { * the ost_count set to number of available obd uuids. */ static int llapi_get_target_uuids(int fd, struct obd_uuid *uuidp, - int *ost_count, enum tgt_type type) + int *ost_count, enum tgt_type type) { char buf[PATH_MAX], format[32]; int rc = 0, index = 0; @@ -2339,15 +2523,15 @@ static int llapi_get_target_uuids(int fd, struct obd_uuid *uuidp, while (fgets(buf, sizeof(buf), fp) != NULL) { if (uuidp && (index < *ost_count)) { if (sscanf(buf, format, &index, uuidp[index].uuid) < 2) - break; - } - index++; - } + break; + } + index++; + } - fclose(fp); + fclose(fp); - if (uuidp && (index > *ost_count)) - rc = -EOVERFLOW; + if (uuidp && (index > *ost_count)) + rc = -EOVERFLOW; *ost_count = index; free_param: @@ -2357,7 +2541,7 @@ free_param: int llapi_lov_get_uuids(int fd, struct obd_uuid *uuidp, int *ost_count) { - return llapi_get_target_uuids(fd, uuidp, ost_count, LOV_TYPE); + return llapi_get_target_uuids(fd, uuidp, ost_count, LOV_TYPE); } int llapi_get_obd_count(char *mnt, int *count, int is_mdt) @@ -2381,31 +2565,36 @@ int llapi_get_obd_count(char *mnt, int *count, int is_mdt) return rc; } -/* Check if user specified value matches a real uuid. Ignore _UUID, +/* + * Check if user specified value matches a real uuid. Ignore _UUID, * -osc-4ba41334, other trailing gunk in comparison. * @param real_uuid ends in "_UUID" * @param search_uuid may or may not end in "_UUID" */ int llapi_uuid_match(char *real_uuid, char *search_uuid) { - int cmplen = strlen(real_uuid); - int searchlen = strlen(search_uuid); + int cmplen = strlen(real_uuid); + int searchlen = strlen(search_uuid); - if (cmplen > 5 && strcmp(real_uuid + cmplen - 5, "_UUID") == 0) - cmplen -= 5; - if (searchlen > 5 && strcmp(search_uuid + searchlen - 5, "_UUID") == 0) - searchlen -= 5; + if (cmplen > 5 && strcmp(real_uuid + cmplen - 5, "_UUID") == 0) + cmplen -= 5; + if (searchlen > 5 && strcmp(search_uuid + searchlen - 5, "_UUID") == 0) + searchlen -= 5; - /* The UUIDs may legitimately be different lengths, if - * the system was upgraded from an older version. */ - if (cmplen != searchlen) - return 0; + /* + * The UUIDs may legitimately be different lengths, if + * the system was upgraded from an older version. + */ + if (cmplen != searchlen) + return 0; - return (strncmp(search_uuid, real_uuid, cmplen) == 0); + return (strncmp(search_uuid, real_uuid, cmplen) == 0); } -/* Here, param->fp_obd_uuid points to a single obduuid, the index of which is - * returned in param->fp_obd_index */ +/* + * Here, param->fp_obd_uuid points to a single obduuid, the index of which is + * returned in param->fp_obd_index + */ static int setup_obd_uuid(int fd, char *dname, struct find_param *param) { struct obd_uuid obd_uuid; @@ -2477,7 +2666,7 @@ static int setup_obd_uuid(int fd, char *dname, struct find_param *param) } param->fp_obds_printed = 1; - fclose(fp); + fclose(fp); if (param->fp_obd_uuid && (param->fp_obd_index == OBD_NOT_FOUND)) { llapi_err_noerrno(LLAPI_MSG_ERROR, @@ -2490,18 +2679,20 @@ free_param: return rc; } -/* In this case, param->fp_obd_uuid will be an array of obduuids and +/* + * In this case, param->fp_obd_uuid will be an array of obduuids and * obd index for all these obduuids will be returned in - * param->fp_obd_indexes */ -static int setup_indexes(DIR *dir, char *path, struct obd_uuid *obduuids, - int num_obds, int **obdindexes, int *obdindex, - enum tgt_type type) + * param->fp_obd_indexes + */ +static int setup_indexes(int d, char *path, struct obd_uuid *obduuids, + int num_obds, int **obdindexes, int *obdindex, + enum tgt_type type) { int ret, obdcount, obd_valid = 0, obdnum; long i; - struct obd_uuid *uuids = NULL; - char buf[16]; - int *indexes; + struct obd_uuid *uuids = NULL; + char buf[16]; + int *indexes; if (type == LOV_TYPE) ret = get_param_lov(path, "numobd", buf, sizeof(buf)); @@ -2516,7 +2707,7 @@ static int setup_indexes(DIR *dir, char *path, struct obd_uuid *obduuids, return -ENOMEM; retry_get_uuids: - ret = llapi_get_target_uuids(dirfd(dir), uuids, &obdcount, type); + ret = llapi_get_target_uuids(d, uuids, &obdcount, type); if (ret) { if (ret == -EOVERFLOW) { struct obd_uuid *uuids_temp; @@ -2534,30 +2725,30 @@ retry_get_uuids: goto out_free; } - indexes = malloc(num_obds * sizeof(*obdindex)); - if (indexes == NULL) { - ret = -ENOMEM; - goto out_free; - } - - for (obdnum = 0; obdnum < num_obds; obdnum++) { - char *end = NULL; - - /* The user may have specified a simple index */ - i = strtol(obduuids[obdnum].uuid, &end, 0); - if (end && *end == '\0' && i < obdcount) { - indexes[obdnum] = i; - obd_valid++; - } else { - for (i = 0; i < obdcount; i++) { - if (llapi_uuid_match(uuids[i].uuid, - obduuids[obdnum].uuid)) { - indexes[obdnum] = i; - obd_valid++; - break; - } - } - } + indexes = malloc(num_obds * sizeof(*obdindex)); + if (indexes == NULL) { + ret = -ENOMEM; + goto out_free; + } + + for (obdnum = 0; obdnum < num_obds; obdnum++) { + char *end = NULL; + + /* The user may have specified a simple index */ + i = strtol(obduuids[obdnum].uuid, &end, 0); + if (end && *end == '\0' && i < obdcount) { + indexes[obdnum] = i; + obd_valid++; + } else { + for (i = 0; i < obdcount; i++) { + if (llapi_uuid_match(uuids[i].uuid, + obduuids[obdnum].uuid)) { + indexes[obdnum] = i; + obd_valid++; + break; + } + } + } if (i >= obdcount) { indexes[obdnum] = OBD_NOT_FOUND; llapi_err_noerrno(LLAPI_MSG_ERROR, @@ -2567,25 +2758,25 @@ retry_get_uuids: } } - if (obd_valid == 0) - *obdindex = OBD_NOT_FOUND; - else - *obdindex = obd_valid; + if (obd_valid == 0) + *obdindex = OBD_NOT_FOUND; + else + *obdindex = obd_valid; - *obdindexes = indexes; + *obdindexes = indexes; out_free: - if (uuids) - free(uuids); + if (uuids) + free(uuids); - return ret; + return ret; } -static int setup_target_indexes(DIR *dir, char *path, struct find_param *param) +static int setup_target_indexes(int d, char *path, struct find_param *param) { - int ret = 0; + int ret = 0; if (param->fp_mdt_uuid) { - ret = setup_indexes(dir, path, param->fp_mdt_uuid, + ret = setup_indexes(d, path, param->fp_mdt_uuid, param->fp_num_mdts, ¶m->fp_mdt_indexes, ¶m->fp_mdt_index, LMV_TYPE); @@ -2594,7 +2785,7 @@ static int setup_target_indexes(DIR *dir, char *path, struct find_param *param) } if (param->fp_obd_uuid) { - ret = setup_indexes(dir, path, param->fp_obd_uuid, + ret = setup_indexes(d, path, param->fp_obd_uuid, param->fp_num_obds, ¶m->fp_obd_indexes, ¶m->fp_obd_index, LOV_TYPE); @@ -2628,9 +2819,9 @@ int llapi_ostlist(char *path, struct find_param *param) * using pathname. */ static int sattr_get_defaults(const char *const fsname, - unsigned int *scount, - unsigned int *ssize, - unsigned int *soffset) + unsigned int *scount, + unsigned int *ssize, + unsigned int *soffset) { char val[PATH_MAX]; int rc; @@ -2672,51 +2863,51 @@ 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) { - rc = llapi_search_fsname(pathname, fsname_buf); - if (rc) - return rc; - } else { + 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) { + rc = llapi_search_fsname(pathname, fsname_buf); + if (rc) + return rc; + } else { snprintf(fsname_buf, sizeof(fsname_buf), "%s", fsname); - } + } if (strncmp(fsname_buf, cache.fsname, sizeof(fsname_buf) - 1) != 0) { - /* - * Ensure all 3 sattrs (count, size, and offset) are - * successfully retrieved and stored in tmp before writing to - * cache. - */ + /* + * Ensure all 3 sattrs (count, size, and offset) are + * successfully retrieved and stored in tmp before writing to + * cache. + */ rc = sattr_get_defaults(fsname_buf, &tmp[0], &tmp[1], &tmp[2]); - if (rc != 0) - return rc; + if (rc != 0) + return rc; - cache.stripecount = tmp[0]; - cache.stripesize = tmp[1]; - cache.stripeoffset = tmp[2]; + cache.stripecount = tmp[0]; + cache.stripesize = tmp[1]; + cache.stripeoffset = tmp[2]; snprintf(cache.fsname, sizeof(cache.fsname), "%s", fsname_buf); - } + } - if (scount) - *scount = cache.stripecount; - if (ssize) - *ssize = cache.stripesize; - if (soffset) - *soffset = cache.stripeoffset; + if (scount) + *scount = cache.stripecount; + if (ssize) + *ssize = cache.stripesize; + if (soffset) + *soffset = cache.stripeoffset; - return 0; + return 0; } static char *layout2name(__u32 layout_pattern) @@ -2780,7 +2971,8 @@ static void lov_dump_user_lmm_header(struct lov_user_md *lum, char *path, space, prefix, (uintmax_t)lmm_oi_id(&lum->lmm_oi)); } - if ((verbose & (VERBOSE_DETAIL | VERBOSE_DFID)) && !is_dir) { + + if (verbose & (VERBOSE_DETAIL | VERBOSE_DFID)) { __u64 seq; __u32 oid; __u32 ver; @@ -2788,28 +2980,51 @@ static void lov_dump_user_lmm_header(struct lov_user_md *lum, char *path, if (verbose & ~VERBOSE_DFID) llapi_printf(LLAPI_MSG_NORMAL, "%slmm_fid: ", space); - /* This needs a bit of hand-holding since old 1.x lmm_oi - * have { oi.oi_id = mds_inum, oi.oi_seq = 0 } and 2.x lmm_oi - * have { oi.oi_id = mds_oid, oi.oi_seq = mds_seq } instead of - * a real FID. Ideally the 2.x code would have stored this - * like a FID with { oi_id = mds_seq, oi_seq = mds_oid } so the - * ostid union lu_fid { f_seq = mds_seq, f_oid = mds_oid } - * worked properly (especially since IGIF FIDs use mds_inum as - * the FID SEQ), but unfortunately that didn't happen. - * - * Print it to look like an IGIF FID, even though the fields - * are reversed on disk, so that it makes sense to userspace. - * - * Don't use ostid_id() and ostid_seq(), since they assume the - * oi_fid fields are in the right order. This is why there are - * separate lmm_oi_seq() and lmm_oi_id() routines for this. - * - * For newer layout types hopefully this will be a real FID. */ - seq = lmm_oi_seq(&lum->lmm_oi) == 0 ? - lmm_oi_id(&lum->lmm_oi) : lmm_oi_seq(&lum->lmm_oi); - oid = lmm_oi_seq(&lum->lmm_oi) == 0 ? - 0 : (__u32)lmm_oi_id(&lum->lmm_oi); - ver = (__u32)(lmm_oi_id(&lum->lmm_oi) >> 32); + + if (is_dir) { + struct lu_fid dir_fid; + + rc = llapi_path2fid(path, &dir_fid); + if (rc) + llapi_error(LLAPI_MSG_ERROR, rc, + "Cannot determine directory fid."); + + seq = dir_fid.f_seq; + oid = dir_fid.f_oid; + ver = dir_fid.f_ver; + } else { + /* + * This needs a bit of hand-holding since old 1.x + * lmm_oi have { oi.oi_id = mds_inum, oi.oi_seq = 0 } + * and 2.x lmm_oi have { oi.oi_id = mds_oid, + * oi.oi_seq = mds_seq } instead of a real FID. + * Ideally the 2.x code would have stored this like a + * FID with { oi_id = mds_seq, oi_seq = mds_oid } so + * the ostid union lu_fid { f_seq = mds_seq, + * f_oid = mds_oid } worked properly (especially since + * IGIF FIDs use mds_inum as the FID SEQ), but + * unfortunately that didn't happen. + * + * Print it to look like an IGIF FID, even though the + * fields are reversed on disk, so that it makes sense + * to userspace. + * + * Don't use ostid_id() and ostid_seq(), since they + * assume the oi_fid fields are in the right order. + * This is why there are separate lmm_oi_seq() and + * lmm_oi_id() routines for this. + * + * For newer layout types hopefully this will be a + * real FID. + */ + seq = lmm_oi_seq(&lum->lmm_oi) == 0 ? + lmm_oi_id(&lum->lmm_oi) : + lmm_oi_seq(&lum->lmm_oi); + oid = lmm_oi_seq(&lum->lmm_oi) == 0 ? + 0 : (__u32)lmm_oi_id(&lum->lmm_oi); + ver = (__u32)(lmm_oi_id(&lum->lmm_oi) >> 32); + } + if (yaml) llapi_printf(LLAPI_MSG_NORMAL, DFID_NOBRACE"\n", (unsigned long long)seq, oid, ver); @@ -2826,6 +3041,7 @@ static void lov_dump_user_lmm_header(struct lov_user_md *lum, char *path, if (!is_raw && lum->lmm_stripe_count == 0 && lov_pattern(lum->lmm_pattern) != LOV_PATTERN_MDT) { unsigned int scount; + rc = sattr_cache_get_defaults(NULL, path, &scount, NULL, NULL); @@ -2834,8 +3050,7 @@ static void lov_dump_user_lmm_header(struct lov_user_md *lum, char *path, scount); else llapi_error(LLAPI_MSG_ERROR, rc, - "Cannot determine default" - " stripe count."); + "Cannot determine default stripe count."); } else { llapi_printf(LLAPI_MSG_NORMAL, "%d", extension ? 0 : @@ -2863,14 +3078,14 @@ static void lov_dump_user_lmm_header(struct lov_user_md *lum, char *path, space, prefix); if (is_dir && !is_raw && lum->lmm_stripe_size == 0) { unsigned int ssize; + rc = sattr_cache_get_defaults(NULL, path, NULL, &ssize, NULL); if (rc == 0) llapi_printf(LLAPI_MSG_NORMAL, "%u", ssize); else llapi_error(LLAPI_MSG_ERROR, rc, - "Cannot determine default" - " stripe size."); + "Cannot determine default stripe size."); } else { /* Extension size is in KiB */ llapi_printf(LLAPI_MSG_NORMAL, "%llu", @@ -3012,6 +3227,7 @@ void lov_dump_user_lmm_v1v3(struct lov_user_md *lum, char *pool_name, space, i, idx, PFID(&fid)); } else { char fmt[48]; + sprintf(fmt, "%s%s%s\n", "\t%6u\t%14llu\t%#13llx\t", (fid_seq_is_rsvd(gr) || @@ -3076,7 +3292,7 @@ void lmv_dump_user_lmm(struct lmv_user_md *lum, char *pool_name, llapi_printf(LLAPI_MSG_NORMAL, "%s", separator); if (verbose & ~VERBOSE_STRIPE_COUNT) llapi_printf(LLAPI_MSG_NORMAL, "lmv_stripe_count: "); - llapi_printf(LLAPI_MSG_NORMAL, "%u", + llapi_printf(LLAPI_MSG_NORMAL, "%d", (int)lum->lum_stripe_count); if ((verbose & VERBOSE_STRIPE_OFFSET) && !yaml) separator = " "; @@ -3115,10 +3331,56 @@ void lmv_dump_user_lmm(struct lmv_user_md *lum, char *pool_name, llapi_printf(LLAPI_MSG_NORMAL, ",bad_type"); if (flags & LMV_HASH_FLAG_LOST_LMV) llapi_printf(LLAPI_MSG_NORMAL, ",lost_lmv"); - separator = "\n"; + if (flags & LMV_HASH_FLAG_FIXED) + llapi_printf(LLAPI_MSG_NORMAL, ",fixed"); + if (flags & ~LMV_HASH_FLAG_KNOWN) + llapi_printf(LLAPI_MSG_NORMAL, ",unknown_%04x", + flags & ~LMV_HASH_FLAG_KNOWN); + + if (verbose & VERBOSE_HASH_TYPE && !yaml) + separator = " "; + else + separator = "\n"; + } + + if ((verbose & VERBOSE_INHERIT) && lum->lum_magic == LMV_USER_MAGIC) { + llapi_printf(LLAPI_MSG_NORMAL, "%s", separator); + if (verbose & ~VERBOSE_INHERIT) + llapi_printf(LLAPI_MSG_NORMAL, "lmv_max_inherit: "); + if (lum->lum_max_inherit == LMV_INHERIT_UNLIMITED) + llapi_printf(LLAPI_MSG_NORMAL, "-1"); + else if (lum->lum_max_inherit == LMV_INHERIT_NONE) + llapi_printf(LLAPI_MSG_NORMAL, "0"); + else + llapi_printf(LLAPI_MSG_NORMAL, "%hhu", + lum->lum_max_inherit); + if (verbose & VERBOSE_INHERIT && !yaml) + separator = " "; + else + separator = "\n"; + } + if ((verbose & VERBOSE_INHERIT_RR) && + lum->lum_magic == LMV_USER_MAGIC && + lum->lum_stripe_offset == LMV_OFFSET_DEFAULT) { + llapi_printf(LLAPI_MSG_NORMAL, "%s", separator); + if (verbose & ~VERBOSE_INHERIT_RR) + llapi_printf(LLAPI_MSG_NORMAL, "lmv_max_inherit_rr: "); + if (lum->lum_max_inherit_rr == LMV_INHERIT_RR_UNLIMITED) + llapi_printf(LLAPI_MSG_NORMAL, "-1"); + else if (lum->lum_max_inherit_rr == LMV_INHERIT_RR_NONE) + llapi_printf(LLAPI_MSG_NORMAL, "0"); + else + llapi_printf(LLAPI_MSG_NORMAL, "%hhu", + lum->lum_max_inherit_rr); + if (verbose & VERBOSE_INHERIT_RR && !yaml) + separator = " "; + else + separator = "\n"; } + separator = "\n"; + if (verbose & VERBOSE_OBJID && lum->lum_magic != LMV_USER_MAGIC) { llapi_printf(LLAPI_MSG_NORMAL, "%s", separator); if (lum->lum_stripe_count > 0) @@ -3127,13 +3389,13 @@ void lmv_dump_user_lmm(struct lmv_user_md *lum, char *pool_name, for (i = 0; i < lum->lum_stripe_count; i++) { int idx = objects[i].lum_mds; struct lu_fid *fid = &objects[i].lum_fid; + if ((obdindex == OBD_NOT_FOUND) || (obdindex == idx)) llapi_printf(LLAPI_MSG_NORMAL, "%6u\t\t "DFID"\t\t%s\n", idx, PFID(fid), obdindex == idx ? " *" : ""); } - } if ((verbose & VERBOSE_POOL) && pool_name != NULL && @@ -3342,7 +3604,8 @@ static void lov_dump_comp_v1_entry(struct find_param *param, } } -/* Check if the value matches 1 of the given criteria (e.g. --atime +/-N). +/* + * Check if the value matches 1 of the given criteria (e.g. --atime +/-N). * @mds indicates if this is MDS timestamps and there are attributes on OSTs. * * The result is -1 if it does not match, 0 if not yet clear, 1 if matches. @@ -3360,7 +3623,8 @@ static void lov_dump_comp_v1_entry(struct find_param *param, * 9 | file < limit; sign < 0 | ? / -1 | * -------------------------------------- * Note: 5th actually means that the value is within the interval - * (limit - margin, limit]. */ + * (limit - margin, limit]. + */ static int find_value_cmp(unsigned long long file, unsigned long long limit, int sign, int negopt, unsigned long long margin, bool mds) @@ -3406,7 +3670,7 @@ static inline void lov_v1v3_pool_name(struct lov_user_md *v1, char *pool_name) { if (v1->lmm_magic == LOV_USER_MAGIC_V3) - snprintf(pool_name, LOV_MAXPOOLNAME, "%s", + snprintf(pool_name, LOV_MAXPOOLNAME + 1, "%s", ((struct lov_user_md_v3 *)v1)->lmm_pool_name); else pool_name[0] = '\0'; @@ -3898,8 +4162,8 @@ static void llapi_lov_dump_user_lmm(struct find_param *param, char *path, lmv_dump_foreign_lmm(param, path, flags); break; default: - llapi_printf(LLAPI_MSG_NORMAL, "unknown lmm_magic: %#x " - "(expecting one of %#x %#x %#x %#x)\n", + llapi_printf(LLAPI_MSG_NORMAL, + "unknown lmm_magic: %#x (expecting one of %#x %#x %#x %#x)\n", *(__u32 *)¶m->fp_lmd->lmd_lmm, LOV_USER_MAGIC_V1, LOV_USER_MAGIC_V3, LMV_USER_MAGIC, LMV_MAGIC_V1); @@ -3907,7 +4171,7 @@ static void llapi_lov_dump_user_lmm(struct find_param *param, char *path, } } -int llapi_file_get_stripe(const char *path, struct lov_user_md *lum) +static int llapi_file_get_stripe1(const char *path, struct lov_user_md *lum) { const char *fname; char *dname; @@ -3949,51 +4213,80 @@ out_free: return rc; } +int llapi_file_get_stripe(const char *path, struct lov_user_md *lum) +{ + char *canon_path = NULL; + int rc, rc2; + + rc = llapi_file_get_stripe1(path, lum); + if (!(rc == -ENOTTY || rc == -ENODATA)) + goto out; + + /* Handle failure due to symlinks by dereferencing path manually. */ + canon_path = canonicalize_file_name(path); + if (canon_path == NULL) + goto out; /* Keep original rc. */ + + rc2 = llapi_file_get_stripe1(canon_path, lum); + if (rc2 < 0) + goto out; /* Keep original rc. */ + + rc = 0; +out: + free(canon_path); + + return rc; +} + int llapi_file_lookup(int dirfd, const char *name) { - struct obd_ioctl_data data = { 0 }; - char rawbuf[8192]; - char *buf = rawbuf; - int rc; + struct obd_ioctl_data data = { 0 }; + char rawbuf[8192]; + char *buf = rawbuf; + int rc; - if (dirfd < 0 || name == NULL) - return -EINVAL; + if (dirfd < 0 || name == NULL) + return -EINVAL; - data.ioc_version = OBD_IOCTL_VERSION; - data.ioc_len = sizeof(data); - data.ioc_inlbuf1 = (char *)name; - data.ioc_inllen1 = strlen(name) + 1; + data.ioc_version = OBD_IOCTL_VERSION; + data.ioc_len = sizeof(data); + data.ioc_inlbuf1 = (char *)name; + data.ioc_inllen1 = strlen(name) + 1; rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf)); - if (rc) { - llapi_error(LLAPI_MSG_ERROR, rc, - "error: IOC_MDC_LOOKUP pack failed for '%s': rc %d", - name, rc); - return rc; - } + if (rc) { + llapi_error(LLAPI_MSG_ERROR, rc, + "error: IOC_MDC_LOOKUP pack failed for '%s': rc %d", + name, rc); + return rc; + } - rc = ioctl(dirfd, IOC_MDC_LOOKUP, buf); - if (rc < 0) - rc = -errno; - return rc; + rc = ioctl(dirfd, IOC_MDC_LOOKUP, buf); + if (rc < 0) + rc = -errno; + return rc; } -/* Check if the file time matches all the given criteria (e.g. --atime +/-N). +/* + * Check if the file time matches all the given criteria (e.g. --atime +/-N). * Return -1 or 1 if file timestamp does not or does match the given criteria * correspondingly. Return 0 if the MDS time is being checked and there are * attributes on OSTs and it is not yet clear if the timespamp matches. * * If 0 is returned, we need to do another RPC to the OSTs to obtain the - * updated timestamps. */ -static int find_time_check(lstatx_t *stx, struct find_param *param, int mds) + * updated timestamps. + */ +static int find_time_check(struct find_param *param, int mds) { + struct lov_user_mds_data *lmd = param->fp_lmd; int rc = 1; int rc2; /* Check if file is accepted. */ if (param->fp_atime) { - rc2 = find_value_cmp(stx->stx_atime.tv_sec, param->fp_atime, - param->fp_asign, param->fp_exclude_atime, + rc2 = find_value_cmp(lmd->lmd_stx.stx_atime.tv_sec, + param->fp_atime, param->fp_asign, + param->fp_exclude_atime, param->fp_time_margin, mds); if (rc2 < 0) return rc2; @@ -4001,27 +4294,33 @@ static int find_time_check(lstatx_t *stx, struct find_param *param, int mds) } if (param->fp_mtime) { - rc2 = find_value_cmp(stx->stx_mtime.tv_sec, param->fp_mtime, - param->fp_msign, param->fp_exclude_mtime, + rc2 = find_value_cmp(lmd->lmd_stx.stx_mtime.tv_sec, + param->fp_mtime, param->fp_msign, + param->fp_exclude_mtime, param->fp_time_margin, mds); if (rc2 < 0) return rc2; - /* If the previous check matches, but this one is not yet clear, - * we should return 0 to do an RPC on OSTs. */ + /* + * If the previous check matches, but this one is not yet clear, + * we should return 0 to do an RPC on OSTs. + */ if (rc == 1) rc = rc2; } if (param->fp_ctime) { - rc2 = find_value_cmp(stx->stx_ctime.tv_sec, param->fp_ctime, - param->fp_csign, param->fp_exclude_ctime, + rc2 = find_value_cmp(lmd->lmd_stx.stx_ctime.tv_sec, + param->fp_ctime, param->fp_csign, + param->fp_exclude_ctime, param->fp_time_margin, mds); if (rc2 < 0) return rc2; - /* If the previous check matches, but this one is not yet clear, - * we should return 0 to do an RPC on OSTs. */ + /* + * If the previous check matches, but this one is not yet clear, + * we should return 0 to do an RPC on OSTs. + */ if (rc == 1) rc = rc2; } @@ -4029,6 +4328,79 @@ static int find_time_check(lstatx_t *stx, struct find_param *param, int mds) return rc; } +static int find_newerxy_check(struct find_param *param, int mds, bool from_mdt) +{ + struct lov_user_mds_data *lmd = param->fp_lmd; + int i; + int rc = 1; + int rc2; + + for (i = 0; i < 2; i++) { + /* Check if file is accepted. */ + if (param->fp_newery[NEWERXY_ATIME][i]) { + rc2 = find_value_cmp(lmd->lmd_stx.stx_atime.tv_sec, + param->fp_newery[NEWERXY_ATIME][i], + -1, i, 0, mds); + if (rc2 < 0) + return rc2; + rc = rc2; + } + + if (param->fp_newery[NEWERXY_MTIME][i]) { + rc2 = find_value_cmp(lmd->lmd_stx.stx_mtime.tv_sec, + param->fp_newery[NEWERXY_MTIME][i], + -1, i, 0, mds); + if (rc2 < 0) + return rc2; + + /* + * If the previous check matches, but this one is not + * yet clear, we should return 0 to do an RPC on OSTs. + */ + if (rc == 1) + rc = rc2; + } + + if (param->fp_newery[NEWERXY_CTIME][i]) { + rc2 = find_value_cmp(lmd->lmd_stx.stx_ctime.tv_sec, + param->fp_newery[NEWERXY_CTIME][i], + -1, i, 0, mds); + if (rc2 < 0) + return rc2; + + /* + * If the previous check matches, but this one is not + * yet clear, we should return 0 to do an RPC on OSTs. + */ + if (rc == 1) + rc = rc2; + } + + /* + * File birth time (btime) can get from MDT directly. + * if @from_mdt is true, it means the input file attributs are + * obtained directly from MDT. + * Thus, if @from_mdt is false, we should skip the following + * btime check. + */ + if (!from_mdt) + continue; + + if (param->fp_newery[NEWERXY_BTIME][i]) { + if (!(lmd->lmd_stx.stx_mask & STATX_BTIME)) + return -EOPNOTSUPP; + + rc2 = find_value_cmp(lmd->lmd_stx.stx_btime.tv_sec, + param->fp_newery[NEWERXY_BTIME][i], + -1, i, 0, 0); + if (rc2 < 0) + return rc2; + } + } + + return rc; +} + /** * Check whether the stripes matches the indexes user provided * 1 : matched @@ -4038,22 +4410,24 @@ static int check_obd_match(struct find_param *param) { struct lov_user_ost_data_v1 *objects; struct lov_comp_md_v1 *comp_v1 = NULL; - struct lov_user_md_v1 *v1 = ¶m->fp_lmd->lmd_lmm; - lstatx_t *stx = ¶m->fp_lmd->lmd_stx; + struct lov_user_mds_data *lmd = param->fp_lmd; + struct lov_user_md_v1 *v1 = &lmd->lmd_lmm; int i, j, k, count = 1; if (param->fp_obd_uuid && param->fp_obd_index == OBD_NOT_FOUND) return 0; - if (!S_ISREG(stx->stx_mode)) + if (!S_ISREG(lmd->lmd_stx.stx_mode)) return 0; /* exclude foreign */ if (v1->lmm_magic == LOV_USER_MAGIC_FOREIGN) return param->fp_exclude_obd; - /* Only those files should be accepted, which have a - * stripe on the specified OST. */ + /* + * Only those files should be accepted, which have a + * stripe on the specified OST. + */ if (v1->lmm_magic == LOV_USER_MAGIC_COMP_V1) { comp_v1 = (struct lov_comp_md_v1 *)v1; count = comp_v1->lcm_entry_count; @@ -4104,28 +4478,35 @@ static int check_mdt_match(struct find_param *param) * not active, just print the object affected by this * failed target **/ -static int print_failed_tgt(struct find_param *param, char *path, int type) +static void print_failed_tgt(struct find_param *param, char *path, int type) { - struct obd_statfs stat_buf; - struct obd_uuid uuid_buf; - int ret; - - if (type != LL_STATFS_LOV && type != LL_STATFS_LMV) - return -EINVAL; + struct obd_statfs stat_buf; + struct obd_uuid uuid_buf; + int tgt_nr, i, *indexes; + int ret = 0; - memset(&stat_buf, 0, sizeof(struct obd_statfs)); - memset(&uuid_buf, 0, sizeof(struct obd_uuid)); - ret = llapi_obd_statfs(path, type, - param->fp_obd_index, &stat_buf, - &uuid_buf); - if (ret) { - llapi_printf(LLAPI_MSG_NORMAL, - "obd_uuid: %s failed %s ", - param->fp_obd_uuid->uuid, - strerror(errno)); + if (type != LL_STATFS_LOV && type != LL_STATFS_LMV) { + llapi_error(LLAPI_MSG_NORMAL, ret, "%s: wrong statfs type(%d)", + __func__, type); + return; } - return ret; + tgt_nr = (type == LL_STATFS_LOV) ? param->fp_obd_index : + param->fp_mdt_index; + indexes = (type == LL_STATFS_LOV) ? param->fp_obd_indexes : + param->fp_mdt_indexes; + + for (i = 0; i < tgt_nr; i++) { + memset(&stat_buf, 0, sizeof(struct obd_statfs)); + memset(&uuid_buf, 0, sizeof(struct obd_uuid)); + + ret = llapi_obd_statfs(path, type, indexes[i], &stat_buf, + &uuid_buf); + if (ret) + llapi_error(LLAPI_MSG_NORMAL, ret, + "%s: obd_uuid: %s failed", + __func__, param->fp_obd_uuid->uuid); + } } static int find_check_stripe_size(struct find_param *param) @@ -4275,7 +4656,8 @@ static int find_check_layout(struct find_param *param) return -1; } -/* if no type specified, check/exclude all foreign +/* + * if no type specified, check/exclude all foreign * if type specified, check all foreign&type and exclude !foreign + foreign&type */ static int find_check_foreign(struct find_param *param) @@ -4288,28 +4670,28 @@ static int find_check_foreign(struct find_param *param) if (param->fp_foreign_type == LU_FOREIGN_TYPE_UNKNOWN) return param->fp_exclude_foreign ? 1 : -1; return -1; - } else { - if (param->fp_foreign_type == LU_FOREIGN_TYPE_UNKNOWN || - lfm->lfm_type == param->fp_foreign_type) - return param->fp_exclude_foreign ? -1 : 1; - return param->fp_exclude_foreign ? 1 : -1; } + + if (param->fp_foreign_type == LU_FOREIGN_TYPE_UNKNOWN || + lfm->lfm_type == param->fp_foreign_type) + return param->fp_exclude_foreign ? -1 : 1; + return param->fp_exclude_foreign ? 1 : -1; } if (S_ISDIR(param->fp_lmd->lmd_stx.stx_mode)) { struct lmv_foreign_md *lfm; lfm = (void *)param->fp_lmv_md; - if (lfm->lfm_magic != LMV_MAGIC_FOREIGN) { + if (lmv_is_foreign(lfm->lfm_magic)) { if (param->fp_foreign_type == LU_FOREIGN_TYPE_UNKNOWN) return param->fp_exclude_foreign ? 1 : -1; return -1; - } else { - if (param->fp_foreign_type == LU_FOREIGN_TYPE_UNKNOWN || - lfm->lfm_type == param->fp_foreign_type) - return param->fp_exclude_foreign ? -1 : 1; - return param->fp_exclude_foreign ? 1 : -1; } + + if (param->fp_foreign_type == LU_FOREIGN_TYPE_UNKNOWN || + lfm->lfm_type == param->fp_foreign_type) + return param->fp_exclude_foreign ? -1 : 1; + return param->fp_exclude_foreign ? 1 : -1; } return -1; } @@ -4317,38 +4699,45 @@ static int find_check_foreign(struct find_param *param) static int find_check_pool(struct find_param *param) { struct lov_comp_md_v1 *comp_v1 = NULL; - struct lov_user_md_v1 *v1 = ¶m->fp_lmd->lmd_lmm; - struct lov_user_md_v3 *v3 = (void *)v1; + struct lov_user_md_v3 *v3 = (void *)¶m->fp_lmd->lmd_lmm; int i, count = 1; bool found = false; - if (v1->lmm_magic == LOV_USER_MAGIC_COMP_V1) { - comp_v1 = (struct lov_comp_md_v1 *)v1; + if (v3->lmm_magic == LOV_USER_MAGIC_COMP_V1) { + comp_v1 = (struct lov_comp_md_v1 *)v3; count = comp_v1->lcm_entry_count; /* empty requested pool is taken as no pool search */ - if (count == 0 && param->fp_poolname[0] == '\0') + if (count == 0 && param->fp_poolname[0] == '\0') { found = true; + goto found; + } } for (i = 0; i < count; i++) { - if (comp_v1 != NULL) - v1 = lov_comp_entry(comp_v1, i); + if (comp_v1 != NULL) { + if (!(comp_v1->lcm_entries[i].lcme_flags & + LCME_FL_INIT)) + continue; - if (v1->lmm_magic == LOV_USER_MAGIC_FOREIGN) + v3 = (void *)lov_comp_entry(comp_v1, i); + } + + if (v3->lmm_magic == LOV_USER_MAGIC_FOREIGN) continue; - if (((v1->lmm_magic == LOV_USER_MAGIC_V1) && + if (((v3->lmm_magic == LOV_USER_MAGIC_V1) && (param->fp_poolname[0] == '\0')) || - ((v1->lmm_magic == LOV_USER_MAGIC_V3) && + ((v3->lmm_magic == LOV_USER_MAGIC_V3) && (strncmp(v3->lmm_pool_name, param->fp_poolname, LOV_MAXPOOLNAME) == 0)) || - ((v1->lmm_magic == LOV_USER_MAGIC_V3) && + ((v3->lmm_magic == LOV_USER_MAGIC_V3) && (strcmp(param->fp_poolname, "*") == 0))) { found = true; break; } } +found: if ((found && !param->fp_exclude_pool) || (!found && param->fp_exclude_pool)) return 1; @@ -4358,9 +4747,9 @@ static int find_check_pool(struct find_param *param) static int find_check_comp_options(struct find_param *param) { - lstatx_t *stx = ¶m->fp_lmd->lmd_stx; struct lov_comp_md_v1 *comp_v1, *forged_v1 = NULL; - struct lov_user_md_v1 *v1 = ¶m->fp_lmd->lmd_lmm; + struct lov_user_mds_data *lmd = param->fp_lmd; + struct lov_user_md_v1 *v1 = &lmd->lmd_lmm; struct lov_comp_md_entry_v1 *entry; int i, ret = 0; @@ -4376,7 +4765,8 @@ static int find_check_comp_options(struct find_param *param) comp_v1 = forged_v1; comp_v1->lcm_entry_count = 1; entry = &comp_v1->lcm_entries[0]; - entry->lcme_flags = S_ISDIR(stx->stx_mode) ? 0 : LCME_FL_INIT; + entry->lcme_flags = S_ISDIR(lmd->lmd_stx.stx_mode) ? + 0 : LCME_FL_INIT; entry->lcme_extent.e_start = 0; entry->lcme_extent.e_end = LUSTRE_EOF; } @@ -4490,7 +4880,7 @@ static int fget_projid(int fd, int *projid) struct fsxattr fsx; int rc; - rc = ioctl(fd, LL_IOC_FSGETXATTR, &fsx); + rc = ioctl(fd, FS_IOC_FSGETXATTR, &fsx); if (rc) return -errno; @@ -4498,13 +4888,42 @@ static int fget_projid(int fd, int *projid) return 0; } -static int cb_find_init(char *path, DIR *parent, DIR **dirp, +/* + * Check that the file's permissions in *st matches the one in find_param + */ +static int check_file_permissions(const struct find_param *param, + mode_t mode) +{ + int decision = 0; + + mode &= 07777; + + switch (param->fp_perm_sign) { + case LFS_FIND_PERM_EXACT: + decision = (mode == param->fp_perm); + break; + case LFS_FIND_PERM_ALL: + decision = ((mode & param->fp_perm) == param->fp_perm); + break; + case LFS_FIND_PERM_ANY: + decision = ((mode & param->fp_perm) != 0); + break; + } + + if ((param->fp_exclude_perm && decision) + || (!param->fp_exclude_perm && !decision)) + return -1; + else + return 1; +} + +static int cb_find_init(char *path, int p, int *dp, void *data, struct dirent64 *de) { struct find_param *param = (struct find_param *)data; - DIR *dir = dirp == NULL ? NULL : *dirp; + struct lov_user_mds_data *lmd = param->fp_lmd; + int d = dp == NULL ? -1 : *dp; int decision = 1; /* 1 is accepted; -1 is rejected. */ - lstatx_t *stx = ¶m->fp_lmd->lmd_stx; int lustre_fs = 1; int checked_type = 0; int ret = 0; @@ -4512,12 +4931,13 @@ static int cb_find_init(char *path, DIR *parent, DIR **dirp, __u64 flags; int fd = -2; - if (parent == NULL && dir == NULL) + if (p == -1 && d == -1) return -EINVAL; /* If a regular expression is presented, make the initial decision */ if (param->fp_pattern != NULL) { char *fname = strrchr(path, '/'); + fname = (fname == NULL ? path : fname + 1); ret = fnmatch(param->fp_pattern, fname, 0); if ((ret == FNM_NOMATCH && !param->fp_exclude_pattern) || @@ -4526,61 +4946,117 @@ static int cb_find_init(char *path, DIR *parent, DIR **dirp, } /* See if we can check the file type from the dirent. */ - if (param->fp_type != 0 && de != NULL && de->d_type != DT_UNKNOWN) { - checked_type = 1; + if (de != NULL && de->d_type != DT_UNKNOWN) { + if (param->fp_type != 0) { + checked_type = 1; - if (DTTOIF(de->d_type) == param->fp_type) { - if (param->fp_exclude_type) - goto decided; - } else { - if (!param->fp_exclude_type) - goto decided; + if (DTTOIF(de->d_type) == param->fp_type) { + if (param->fp_exclude_type) + goto decided; + } else { + if (!param->fp_exclude_type) + goto decided; + } } + if ((param->fp_check_mdt_count || param->fp_hash_type || + param->fp_check_hash_flag) && de->d_type != DT_DIR) + goto decided; } ret = 0; - /* Request MDS for the stat info if some of these parameters need - * to be compared. */ + /* + * Request MDS for the stat info if some of these parameters need + * to be compared. + */ if (param->fp_obd_uuid || param->fp_mdt_uuid || param->fp_check_uid || param->fp_check_gid || + param->fp_newerxy || param->fp_btime || param->fp_atime || param->fp_mtime || param->fp_ctime || param->fp_check_size || param->fp_check_blocks || find_check_lmm_info(param) || - param->fp_check_mdt_count || param->fp_check_hash_type) + param->fp_check_mdt_count || param->fp_hash_type || + param->fp_check_hash_flag || param->fp_perm_sign) decision = 0; if (param->fp_type != 0 && checked_type == 0) - decision = 0; + decision = 0; if (decision == 0) { - if (dir && (param->fp_check_mdt_count || - param->fp_check_hash_type || param->fp_check_foreign)) { + if (d != -1 && + (param->fp_check_mdt_count || param->fp_hash_type || + param->fp_check_hash_flag || param->fp_check_foreign)) { param->fp_get_lmv = 1; - ret = cb_get_dirstripe(path, dir, param); + ret = cb_get_dirstripe(path, &d, param); if (ret != 0) { - /* XXX this works to decide for foreign - * criterion only - */ - if (errno == ENODATA && - param->fp_check_foreign) { - if (param->fp_exclude_foreign) - goto foreign; - goto decided; + if (errno == ENODATA) { + ret = 0; + if (param->fp_check_mdt_count || + param->fp_hash_type || + param->fp_check_hash_flag) { + param->fp_lmv_md->lum_stripe_count = 0; + param->fp_lmv_md->lum_hash_type = 0; + } + if (param->fp_check_foreign) { + if (param->fp_exclude_foreign) + goto print; + goto decided; + } + } else { + return ret; } - return ret; + } + + if (param->fp_check_mdt_count) { + if (lmv_is_foreign(param->fp_lmv_md->lum_magic)) + goto decided; + + decision = find_value_cmp(param->fp_lmv_md->lum_stripe_count, + param->fp_mdt_count, + param->fp_mdt_count_sign, + param->fp_exclude_mdt_count, 1, 0); + if (decision == -1) + goto decided; + } + + if (param->fp_hash_type) { + __u32 found; + __u32 type = param->fp_lmv_md->lum_hash_type & + LMV_HASH_TYPE_MASK; + + if (lmv_is_foreign(param->fp_lmv_md->lum_magic)) + goto decided; + + found = (1 << type) & param->fp_hash_type; + if ((found && param->fp_exclude_hash_type) || + (!found && !param->fp_exclude_hash_type)) + goto decided; + } + + if (param->fp_check_hash_flag) { + __u32 flags = param->fp_lmv_md->lum_hash_type & + ~LMV_HASH_TYPE_MASK; + + if (lmv_is_foreign(param->fp_lmv_md->lum_magic)) + goto decided; + + if (!(flags & param->fp_hash_inflags) || + (flags & param->fp_hash_exflags)) + goto decided; } } param->fp_lmd->lmd_lmm.lmm_magic = 0; - ret = get_lmd_info(path, parent, dir, param->fp_lmd, - param->fp_lum_size, GET_LMD_INFO); + ret = get_lmd_info_fd(path, p, d, param->fp_lmd, + param->fp_lum_size, GET_LMD_INFO); if (ret == 0 && param->fp_lmd->lmd_lmm.lmm_magic == 0 && find_check_lmm_info(param)) { struct lov_user_md *lmm = ¶m->fp_lmd->lmd_lmm; - /* We need to "fake" the "use the default" values - * since the lmm struct is zeroed out at this point. */ + /* + * We need to "fake" the "use the default" values + * since the lmm struct is zeroed out at this point. + */ lmm->lmm_magic = LOV_USER_MAGIC_V1; lmm->lmm_pattern = LOV_PATTERN_DEFAULT; if (!param->fp_raw) @@ -4591,16 +5067,18 @@ static int cb_find_init(char *path, DIR *parent, DIR **dirp, lmm->lmm_stripe_offset = -1; } if (ret == 0 && param->fp_mdt_uuid != NULL) { - if (dir != NULL) { - ret = llapi_file_fget_mdtidx(dirfd(dir), + if (d != -1) { + ret = llapi_file_fget_mdtidx(d, ¶m->fp_file_mdt_index); - } else if (S_ISREG(stx->stx_mode)) { - /* FIXME: we could get the MDT index from the + } else if (S_ISREG(lmd->lmd_stx.stx_mode)) { + /* + * FIXME: we could get the MDT index from the * file's FID in lmd->lmd_lmm.lmm_oi without * opening the file, once we are sure that * LFSCK2 (2.6) has fixed up pre-2.0 LOV EAs. * That would still be an ioctl() to map the - * FID to the MDT, but not an open RPC. */ + * FID to the MDT, but not an open RPC. + */ fd = open(path, O_RDONLY); if (fd > 0) { ret = llapi_file_fget_mdtidx(fd, @@ -4609,9 +5087,11 @@ static int cb_find_init(char *path, DIR *parent, DIR **dirp, ret = -errno; } } else { - /* For a special file, we assume it resides on - * the same MDT as the parent directory. */ - ret = llapi_file_fget_mdtidx(dirfd(parent), + /* + * For a special file, we assume it resides on + * the same MDT as the parent directory. + */ + ret = llapi_file_fget_mdtidx(p, ¶m->fp_file_mdt_index); } } @@ -4627,8 +5107,19 @@ static int cb_find_init(char *path, DIR *parent, DIR **dirp, } } + /* Check the file permissions from the stat info */ + if (param->fp_perm_sign) { + decision = check_file_permissions(param, lmd->lmd_stx.stx_mode); + if (decision == -1) + goto decided; + } + if (param->fp_type && !checked_type) { - if ((stx->stx_mode & S_IFMT) == param->fp_type) { + if ((param->fp_check_mdt_count || param->fp_check_hash_flag || + param->fp_hash_type) && !S_ISDIR(lmd->lmd_stx.stx_mode)) + goto decided; + + if ((lmd->lmd_stx.stx_mode & S_IFMT) == param->fp_type) { if (param->fp_exclude_type) goto decided; } else { @@ -4637,11 +5128,11 @@ static int cb_find_init(char *path, DIR *parent, DIR **dirp, } } - /* Prepare odb. */ + /* Prepare odb. */ if (param->fp_obd_uuid || param->fp_mdt_uuid) { if (lustre_fs && param->fp_got_uuids && - param->fp_dev != makedev(stx->stx_dev_major, - stx->stx_dev_minor)) { + param->fp_dev != makedev(lmd->lmd_stx.stx_dev_major, + lmd->lmd_stx.stx_dev_minor)) { /* A lustre/lustre mount point is crossed. */ param->fp_got_uuids = 0; param->fp_obds_printed = 0; @@ -4650,20 +5141,20 @@ static int cb_find_init(char *path, DIR *parent, DIR **dirp, } if (lustre_fs && !param->fp_got_uuids) { - ret = setup_target_indexes(dir ? dir : parent, path, + ret = setup_target_indexes((d != -1) ? d : p, path, param); if (ret) goto out; - param->fp_dev = makedev(stx->stx_dev_major, - stx->stx_dev_minor); + param->fp_dev = makedev(lmd->lmd_stx.stx_dev_major, + lmd->lmd_stx.stx_dev_minor); } else if (!lustre_fs && param->fp_got_uuids) { /* A lustre/non-lustre mount point is crossed. */ param->fp_got_uuids = 0; param->fp_mdt_index = OBD_NOT_FOUND; param->fp_obd_index = OBD_NOT_FOUND; - } - } + } + } if (param->fp_check_foreign) { decision = find_check_foreign(param); @@ -4691,57 +5182,30 @@ static int cb_find_init(char *path, DIR *parent, DIR **dirp, goto decided; } - if (param->fp_check_mdt_count) { - if (param->fp_lmv_md->lum_magic == LMV_MAGIC_FOREIGN) { - decision = -1; - goto decided; - } - - decision = find_value_cmp( - param->fp_lmv_md->lum_stripe_count, - param->fp_mdt_count, - param->fp_mdt_count_sign, - param->fp_exclude_mdt_count, 1, 0); - if (decision == -1) - goto decided; - } - if (param->fp_check_layout) { decision = find_check_layout(param); if (decision == -1) goto decided; } - if (param->fp_check_hash_type) { - __u32 found; - - if (param->fp_lmv_md->lum_magic == LMV_MAGIC_FOREIGN) { - decision = -1; - goto decided; - } - - found = param->fp_lmv_md->lum_hash_type & param->fp_hash_type; - if ((found && param->fp_exclude_hash_type) || - (!found && !param->fp_exclude_hash_type)) { - decision = -1; - goto decided; - } - } - /* If an OBD UUID is specified but none matches, skip this file. */ if ((param->fp_obd_uuid && param->fp_obd_index == OBD_NOT_FOUND) || (param->fp_mdt_uuid && param->fp_mdt_index == OBD_NOT_FOUND)) goto decided; - /* If an OST or MDT UUID is given, and some OST matches, - * check it here. */ + /* + * If an OST or MDT UUID is given, and some OST matches, + * check it here. + */ if (param->fp_obd_index != OBD_NOT_FOUND || param->fp_mdt_index != OBD_NOT_FOUND) { if (param->fp_obd_uuid) { if (check_obd_match(param)) { - /* If no mdtuuid is given, we are done. + /* + * If no mdtuuid is given, we are done. * Otherwise, fall through to the mdtuuid - * check below. */ + * check below. + */ if (!param->fp_mdt_uuid) goto obd_matches; } else { @@ -4758,7 +5222,7 @@ static int cb_find_init(char *path, DIR *parent, DIR **dirp, obd_matches: if (param->fp_check_uid) { - if (stx->stx_uid == param->fp_uid) { + if (lmd->lmd_stx.stx_uid == param->fp_uid) { if (param->fp_exclude_uid) goto decided; } else { @@ -4768,7 +5232,7 @@ obd_matches: } if (param->fp_check_gid) { - if (stx->stx_gid == param->fp_gid) { + if (lmd->lmd_stx.stx_gid == param->fp_gid) { if (param->fp_exclude_gid) goto decided; } else { @@ -4820,49 +5284,80 @@ obd_matches: /* Check the time on mds. */ decision = 1; if (param->fp_atime || param->fp_mtime || param->fp_ctime) { - int for_mds; + int for_mds; for_mds = lustre_fs ? - (S_ISREG(stx->stx_mode) && stripe_count) : 0; - decision = find_time_check(stx, param, for_mds); + (S_ISREG(lmd->lmd_stx.stx_mode) && stripe_count) : 0; + decision = find_time_check(param, for_mds); if (decision == -1) goto decided; } + if (param->fp_btime) { + if (!(lmd->lmd_stx.stx_mask & STATX_BTIME)) { + ret = -EOPNOTSUPP; + goto out; + } + + decision = find_value_cmp(lmd->lmd_stx.stx_btime.tv_sec, + param->fp_btime, param->fp_bsign, + param->fp_exclude_btime, + param->fp_time_margin, 0); + if (decision == -1) + goto decided; + } + + if (param->fp_newerxy) { + int for_mds; + + for_mds = lustre_fs ? + (S_ISREG(lmd->lmd_stx.stx_mode) && stripe_count) : 0; + decision = find_newerxy_check(param, for_mds, true); + if (decision == -1) + goto decided; + if (decision < 0) { + ret = decision; + goto out; + } + } + flags = param->fp_lmd->lmd_flags; if (param->fp_check_size && - ((S_ISREG(stx->stx_mode) && stripe_count) || - S_ISDIR(stx->stx_mode)) && + ((S_ISREG(lmd->lmd_stx.stx_mode) && stripe_count) || + S_ISDIR(lmd->lmd_stx.stx_mode)) && !(flags & OBD_MD_FLSIZE || (param->fp_lazy && flags & OBD_MD_FLLAZYSIZE))) decision = 0; if (param->fp_check_blocks && - ((S_ISREG(stx->stx_mode) && stripe_count) || - S_ISDIR(stx->stx_mode)) && + ((S_ISREG(lmd->lmd_stx.stx_mode) && stripe_count) || + S_ISDIR(lmd->lmd_stx.stx_mode)) && !(flags & OBD_MD_FLBLOCKS || (param->fp_lazy && flags & OBD_MD_FLLAZYBLOCKS))) decision = 0; - /* If file still fits the request, ask ost for updated info. + /* + * If file still fits the request, ask ost for updated info. * The regular stat is almost of the same speed as some new * 'glimpse-size-ioctl'. */ if (!decision) { lstat_t st; - /* For regular files with the stripe the decision may have not - * been taken yet if *time or size is to be checked. */ + /* + * For regular files with the stripe the decision may have not + * been taken yet if *time or size is to be checked. + */ if (param->fp_obd_index != OBD_NOT_FOUND) - print_failed_tgt(param, path, LL_STATFS_LOV); + print_failed_tgt(param, path, LL_STATFS_LOV); if (param->fp_mdt_index != OBD_NOT_FOUND) - print_failed_tgt(param, path, LL_STATFS_LMV); + print_failed_tgt(param, path, LL_STATFS_LMV); - if (dir != NULL) - ret = fstat_f(dirfd(dir), &st); + if (d != -1) + ret = fstat_f(d, &st); else if (de != NULL) - ret = fstatat_f(dirfd(parent), de->d_name, &st, + ret = fstatat_f(p, de->d_name, &st, AT_SYMLINK_NOFOLLOW); else ret = lstat_f(path, &st); @@ -4884,13 +5379,24 @@ obd_matches: convert_lmd_statx(param->fp_lmd, &st, true); /* Check the time on osc. */ - decision = find_time_check(stx, param, 0); + decision = find_time_check(param, 0); if (decision == -1) goto decided; + + if (param->fp_newerxy) { + decision = find_newerxy_check(param, 0, false); + if (decision == -1) + goto decided; + if (decision < 0) { + ret = decision; + goto out; + } + } } if (param->fp_check_size) { - decision = find_value_cmp(stx->stx_size, param->fp_size, + decision = find_value_cmp(lmd->lmd_stx.stx_size, + param->fp_size, param->fp_size_sign, param->fp_exclude_size, param->fp_size_units, 0); @@ -4899,7 +5405,7 @@ obd_matches: } if (param->fp_check_blocks) { /* convert st_blocks to bytes */ - decision = find_value_cmp(stx->stx_blocks * 512, + decision = find_value_cmp(lmd->lmd_stx.stx_blocks * 512, param->fp_blocks, param->fp_blocks_sign, param->fp_exclude_blocks, @@ -4908,12 +5414,9 @@ obd_matches: goto decided; } -foreign: - llapi_printf(LLAPI_MSG_NORMAL, "%s", path); - if (param->fp_zero_end) - llapi_printf(LLAPI_MSG_NORMAL, "%c", '\0'); - else - llapi_printf(LLAPI_MSG_NORMAL, "\n"); +print: + llapi_printf(LLAPI_MSG_NORMAL, "%s%c", path, + param->fp_zero_end ? '\0' : '\n'); decided: ret = 0; @@ -4929,34 +5432,33 @@ out: return ret; } -static int cb_migrate_mdt_init(char *path, DIR *parent, DIR **dirp, +static int cb_migrate_mdt_init(char *path, int p, int *dp, void *param_data, struct dirent64 *de) { struct find_param *param = (struct find_param *)param_data; struct lmv_user_md *lmu = param->fp_lmv_md; - DIR *tmp_parent = parent; + int tmp_p = p; char raw[MAX_IOC_BUFLEN] = {'\0'}; char *rawbuf = raw; struct obd_ioctl_data data = { 0 }; - int fd; int ret; char *path_copy; char *filename; bool retry = false; - if (parent == NULL && dirp == NULL) + if (p == -1 && dp == NULL) return -EINVAL; if (!lmu) return -EINVAL; - if (dirp != NULL) - closedir(*dirp); + if (dp != NULL && *dp != -1) + close(*dp); - if (parent == NULL) { - tmp_parent = opendir_parent(path); - if (tmp_parent == NULL) { - *dirp = NULL; + if (p == -1) { + tmp_p = open_parent(path); + if (tmp_p == -1) { + *dp = -1; ret = -errno; llapi_error(LLAPI_MSG_ERROR, ret, "can not open %s", path); @@ -4964,8 +5466,6 @@ static int cb_migrate_mdt_init(char *path, DIR *parent, DIR **dirp, } } - fd = dirfd(tmp_parent); - path_copy = strdup(path); filename = basename(path_copy); @@ -4974,36 +5474,40 @@ static int cb_migrate_mdt_init(char *path, DIR *parent, DIR **dirp, data.ioc_inlbuf2 = (char *)lmu; data.ioc_inllen2 = lmv_user_md_size(lmu->lum_stripe_count, lmu->lum_magic); + /* reach bottom? */ + if (param->fp_depth == param->fp_max_depth) + data.ioc_type = MDS_MIGRATE_NSONLY; ret = llapi_ioctl_pack(&data, &rawbuf, sizeof(raw)); if (ret != 0) { llapi_error(LLAPI_MSG_ERROR, ret, - "llapi_obd_statfs: error packing ioctl data"); + "%s: error packing ioctl data", __func__); goto out; } migrate: - ret = ioctl(fd, LL_IOC_MIGRATE, rawbuf); + ret = ioctl(tmp_p, LL_IOC_MIGRATE, rawbuf); if (ret != 0) { if (errno == EBUSY && !retry) { - /* because migrate may not be able to lock all involved + /* + * because migrate may not be able to lock all involved * objects in order, for some of them it try lock, while * there may be conflicting COS locks and cause migrate * fail with EBUSY, hope a sync() could cause - * transaction commit and release these COS locks. */ + * transaction commit and release these COS locks. + */ sync(); retry = true; goto migrate; } else if (errno == EALREADY) { if (param->fp_verbose & VERBOSE_DETAIL) llapi_printf(LLAPI_MSG_NORMAL, - "%s was migrated to MDT%d already\n", + "%s migrated to MDT%d already\n", path, lmu->lum_stripe_offset); ret = 0; } else { ret = -errno; - llapi_error(LLAPI_MSG_ERROR, ret, - "%s migrate failed: %s (%d)\n", - path, strerror(-ret), ret); + llapi_error(LLAPI_MSG_ERROR, ret, "%s migrate failed", + path); goto out; } } else if (param->fp_verbose & VERBOSE_DETAIL) { @@ -5014,22 +5518,29 @@ migrate: } out: - if (dirp != NULL) { - /* If the directory is being migration, we need + /* Do not get down anymore? */ + if (param->fp_depth == param->fp_max_depth) + ret = 1; + param->fp_depth++; + + if (dp != NULL) { + /* + * If the directory is being migration, we need * close the directory after migration, * so the old directory cache will be cleanup * on the client side, and re-open to get the - * new directory handle */ - *dirp = opendir(path); - if (*dirp == NULL) { + * new directory handle + */ + *dp = open(path, O_RDONLY|O_NDELAY|O_DIRECTORY); + if (*dp == -1) { ret = -errno; llapi_error(LLAPI_MSG_ERROR, ret, "%s: Failed to open '%s'", __func__, path); } } - if (parent == NULL) - closedir(tmp_parent); + if (p == -1) + close(tmp_p); free(path_copy); @@ -5037,7 +5548,7 @@ out: } /* dir migration finished, shrink its stripes */ -static int cb_migrate_mdt_fini(char *path, DIR *parent, DIR **dirp, void *data, +static int cb_migrate_mdt_fini(char *path, int p, int *dp, void *data, struct dirent64 *de) { struct find_param *param = data; @@ -5048,13 +5559,13 @@ static int cb_migrate_mdt_fini(char *path, DIR *parent, DIR **dirp, void *data, if (de && de->d_type != DT_DIR) goto out; - if (*dirp) { + if (*dp != -1) { /* * close it before setxattr because the latter may destroy the * original object, and cause close fail. */ - ret = closedir(*dirp); - *dirp = NULL; + ret = close(*dp); + *dp = -1; if (ret) goto out; } @@ -5063,7 +5574,7 @@ static int cb_migrate_mdt_fini(char *path, DIR *parent, DIR **dirp, void *data, if (ret == -EALREADY) ret = 0; out: - cb_common_fini(path, parent, dirp, data, de); + cb_common_fini(path, p, dp, data, de); return ret; } @@ -5080,7 +5591,8 @@ int llapi_mv(char *path, struct find_param *param) if (!printed) { llapi_error(LLAPI_MSG_ERROR, -ESTALE, - "llapi_mv() is deprecated, use llapi_migrate_mdt()\n"); + "%s() is deprecated, use llapi_migrate_mdt() instead", + __func__); printed = true; } #endif @@ -5089,7 +5601,7 @@ int llapi_mv(char *path, struct find_param *param) int llapi_find(char *path, struct find_param *param) { - return param_callback(path, cb_find_init, cb_common_fini, param); + return param_callback(path, cb_find_init, cb_common_fini, param); } /* @@ -5099,25 +5611,25 @@ int llapi_find(char *path, struct find_param *param) */ int llapi_file_fget_mdtidx(int fd, int *mdtidx) { - if (ioctl(fd, LL_IOC_GET_MDTIDX, mdtidx) < 0) - return -errno; - return 0; + if (ioctl(fd, LL_IOC_GET_MDTIDX, mdtidx) < 0) + return -errno; + return 0; } -static int cb_get_mdt_index(char *path, DIR *parent, DIR **dirp, void *data, +static int cb_get_mdt_index(char *path, int p, int *dp, void *data, struct dirent64 *de) { struct find_param *param = (struct find_param *)data; - DIR *d = dirp == NULL ? NULL : *dirp; + int d = dp == NULL ? -1 : *dp; int ret; int mdtidx; - if (parent == NULL && d == NULL) + if (p == -1 && d == -1) return -EINVAL; - if (d != NULL) { - ret = llapi_file_fget_mdtidx(dirfd(d), &mdtidx); - } else /* if (parent) */ { + if (d != -1) { + ret = llapi_file_fget_mdtidx(d, &mdtidx); + } else /* if (p != -1) */ { int fd; fd = open(path, O_RDONLY | O_NOCTTY); @@ -5168,40 +5680,57 @@ out: return 0; } -static int cb_getstripe(char *path, DIR *parent, DIR **dirp, void *data, +static int cb_getstripe(char *path, int p, int *dp, void *data, struct dirent64 *de) { - struct find_param *param = (struct find_param *)data; - DIR *d = dirp == NULL ? NULL : *dirp; - int ret = 0; + struct find_param *param = (struct find_param *)data; + int d = dp == NULL ? -1 : *dp; + int ret = 0; - if (parent == NULL && d == NULL) + if (p == -1 && d == -1) return -EINVAL; if (param->fp_obd_uuid) { param->fp_quiet = 1; - ret = setup_obd_uuid(d ? dirfd(d) : dirfd(parent), path, param); + ret = setup_obd_uuid(d != -1 ? d : p, path, param); if (ret) return ret; } - if (d && (param->fp_get_lmv || param->fp_get_default_lmv)) - ret = cb_get_dirstripe(path, d, param); - else if (d || - (parent && !param->fp_get_lmv && !param->fp_get_default_lmv)) - ret = get_lmd_info(path, parent, d, ¶m->fp_lmd->lmd_lmm, - param->fp_lum_size, GET_LMD_STRIPE); - else + if (d != -1 && (param->fp_get_lmv || param->fp_get_default_lmv)) + ret = cb_get_dirstripe(path, &d, param); + else if (d != -1 || + (p != -1 && !param->fp_get_lmv && !param->fp_get_default_lmv)) + ret = get_lmd_info_fd(path, p, d, ¶m->fp_lmd->lmd_lmm, + param->fp_lum_size, GET_LMD_STRIPE); + else if (d == -1 && (param->fp_get_lmv || param->fp_get_default_lmv)) { + /* in case of a dangling or valid faked symlink dir, opendir() + * should have return either EINVAL or ENOENT, so let's try + * to get LMV just in case, and by opening it as a file but + * with O_NOFOLLOW ... + */ + int fd = open(path, O_RDONLY | O_NOFOLLOW); + + if (fd == -1) + return 0; + ret = cb_get_dirstripe(path, &fd, param); + if (ret == 0) + llapi_lov_dump_user_lmm(param, path, LDF_IS_DIR); + close(fd); + return 0; + } else return 0; - if (ret) { - if (errno == ENODATA && d != NULL) { - /* We need to "fake" the "use the default" values + if (ret) { + if (errno == ENODATA && d != -1) { + /* + * 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. */ + * prefix to be displayed. + */ if (param->fp_get_default_lmv) { struct lmv_user_md *lum = param->fp_lmv_md; @@ -5213,7 +5742,7 @@ static int cb_getstripe(char *path, DIR *parent, DIR **dirp, void *data, struct lmv_user_md *lum = param->fp_lmv_md; int mdtidx; - ret = llapi_file_fget_mdtidx(dirfd(d), &mdtidx); + ret = llapi_file_fget_mdtidx(d, &mdtidx); if (ret != 0) goto err_out; lum->lum_magic = LMV_MAGIC_V1; @@ -5233,36 +5762,37 @@ static int cb_getstripe(char *path, DIR *parent, DIR **dirp, void *data, lmm->lmm_stripe_offset = -1; goto dump; } - } else if (errno == ENODATA && parent != NULL) { + } else if (errno == ENODATA && p != -1) { if (!param->fp_obd_uuid && !param->fp_mdt_uuid) - llapi_printf(LLAPI_MSG_NORMAL, - "%s has no stripe info\n", path); - goto out; - } else if (errno == ENOENT) { - llapi_error(LLAPI_MSG_WARN, -ENOENT, - "warning: %s: %s does not exist", - __func__, path); - goto out; - } else if (errno == ENOTTY) { - ret = -errno; - llapi_error(LLAPI_MSG_ERROR, ret, - "%s: '%s' not on a Lustre fs?", - __func__, path); - } else { - ret = -errno; + llapi_printf(LLAPI_MSG_NORMAL, + "%s has no stripe info\n", path); + goto out; + } else if (errno == ENOENT) { + llapi_error(LLAPI_MSG_WARN, -ENOENT, + "warning: %s: %s does not exist", + __func__, path); + goto out; + } else if (errno == ENOTTY) { + ret = -errno; + llapi_error(LLAPI_MSG_ERROR, ret, + "%s: '%s' not on a Lustre fs?", + __func__, path); + } else { + ret = -errno; err_out: llapi_error(LLAPI_MSG_ERROR, ret, "error: %s: %s failed for %s", - __func__, d ? "LL_IOC_LOV_GETSTRIPE" : - "IOC_MDC_GETFILESTRIPE", path); + __func__, d != -1 ? + "LL_IOC_LOV_GETSTRIPE" : + "IOC_MDC_GETFILESTRIPE", path); } - return ret; - } + return ret; + } dump: if (!(param->fp_verbose & VERBOSE_MDTINDEX)) - llapi_lov_dump_user_lmm(param, path, d ? LDF_IS_DIR : 0); + llapi_lov_dump_user_lmm(param, path, d != -1 ? LDF_IS_DIR : 0); out: /* Do not get down anymore? */ @@ -5277,33 +5807,33 @@ out: int llapi_getstripe(char *path, struct find_param *param) { return param_callback(path, (param->fp_verbose & VERBOSE_MDTINDEX) ? - cb_get_mdt_index : cb_getstripe, - cb_common_fini, param); + cb_get_mdt_index : cb_getstripe, + cb_common_fini, param); } int llapi_obd_fstatfs(int fd, __u32 type, __u32 index, struct obd_statfs *stat_buf, struct obd_uuid *uuid_buf) { char raw[MAX_IOC_BUFLEN] = {'\0'}; - char *rawbuf = raw; - struct obd_ioctl_data data = { 0 }; - int rc = 0; - - data.ioc_inlbuf1 = (char *)&type; - data.ioc_inllen1 = sizeof(__u32); - data.ioc_inlbuf2 = (char *)&index; - data.ioc_inllen2 = sizeof(__u32); - data.ioc_pbuf1 = (char *)stat_buf; - data.ioc_plen1 = sizeof(struct obd_statfs); - data.ioc_pbuf2 = (char *)uuid_buf; - data.ioc_plen2 = sizeof(struct obd_uuid); + char *rawbuf = raw; + struct obd_ioctl_data data = { 0 }; + int rc = 0; + + data.ioc_inlbuf1 = (char *)&type; + data.ioc_inllen1 = sizeof(__u32); + data.ioc_inlbuf2 = (char *)&index; + data.ioc_inllen2 = sizeof(__u32); + data.ioc_pbuf1 = (char *)stat_buf; + data.ioc_plen1 = sizeof(struct obd_statfs); + data.ioc_pbuf2 = (char *)uuid_buf; + data.ioc_plen2 = sizeof(struct obd_uuid); rc = llapi_ioctl_pack(&data, &rawbuf, sizeof(raw)); - if (rc != 0) { - llapi_error(LLAPI_MSG_ERROR, rc, - "llapi_obd_statfs: error packing ioctl data"); - return rc; - } + if (rc != 0) { + llapi_error(LLAPI_MSG_ERROR, rc, + "%s: error packing ioctl data", __func__); + return rc; + } rc = ioctl(fd, IOC_OBD_STATFS, (void *)rawbuf); @@ -5321,8 +5851,10 @@ int llapi_obd_statfs(char *path, __u32 type, __u32 index, rc = -errno; llapi_error(LLAPI_MSG_ERROR, rc, "error: %s: opening '%s'", __func__, path); - /* If we can't even open a file on the filesystem (e.g. with - * -ESHUTDOWN), force caller to exit or it will loop forever. */ + /* + * If we can't even open a file on the filesystem (e.g. with + * -ESHUTDOWN), force caller to exit or it will loop forever. + */ return -ENODEV; } @@ -5375,7 +5907,7 @@ failed: } int llapi_target_iterate(int type_num, char **obd_type, - void *args, llapi_cb_t cb) + void *args, llapi_cb_t cb) { int i, rc = 0; glob_t param; @@ -5440,23 +5972,22 @@ free_path: } static void do_target_check(char *obd_type_name, char *obd_name, - char *obd_uuid, void *args) + char *obd_uuid, void *args) { - int rc; + int rc; - rc = llapi_ping(obd_type_name, obd_name); - if (rc == ENOTCONN) { - llapi_printf(LLAPI_MSG_NORMAL, "%s inactive.\n", obd_name); - } else if (rc) { - llapi_error(LLAPI_MSG_ERROR, rc, "error: check '%s'", obd_name); - } else { - llapi_printf(LLAPI_MSG_NORMAL, "%s active.\n", obd_name); - } + rc = llapi_ping(obd_type_name, obd_name); + if (rc == ENOTCONN) + llapi_printf(LLAPI_MSG_NORMAL, "%s inactive.\n", obd_name); + else if (rc) + llapi_error(LLAPI_MSG_ERROR, rc, "error: check '%s'", obd_name); + else + llapi_printf(LLAPI_MSG_NORMAL, "%s active.\n", obd_name); } int llapi_target_check(int type_num, char **obd_type, char *dir) { - return llapi_target_iterate(type_num, obd_type, NULL, do_target_check); + return llapi_target_iterate(type_num, obd_type, NULL, do_target_check); } #undef MAX_STRING_SIZE @@ -5470,8 +6001,8 @@ int llapi_is_lustre_mnttype(const char *type) /* Is this a lustre client fs? */ int llapi_is_lustre_mnt(struct mntent *mnt) { - return (llapi_is_lustre_mnttype(mnt->mnt_type) && - strstr(mnt->mnt_fsname, ":/") != NULL); + return (llapi_is_lustre_mnttype(mnt->mnt_type) && + strstr(mnt->mnt_fsname, ":/") != NULL); } int llapi_quotactl(char *mnt, struct if_quotactl *qctl) @@ -5494,253 +6025,14 @@ int llapi_quotactl(char *mnt, struct if_quotactl *qctl) rc = ioctl(root, OBD_IOC_QUOTACTL, qctl); if (rc < 0) rc = -errno; + if (rc == -ENOENT && LUSTRE_Q_CMD_IS_POOL(qctl->qc_cmd)) + llapi_error(LLAPI_MSG_ERROR | LLAPI_MSG_NO_ERRNO, rc, + "Cannot find pool '%s'", qctl->qc_poolname); close(root); 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; @@ -5764,39 +6056,6 @@ int llapi_get_connect_flags(const char *mnt, __u64 *flags) } /** - * Get a 64-bit value representing the version of file data pointed by fd. - * - * Each write or truncate, flushed on OST, will change this value. You can use - * this value to verify if file data was modified. This only checks the file - * data, not metadata. - * - * \param flags 0: no flush pages, usually used it the process has already - * taken locks; - * LL_DV_RD_FLUSH: OSTs will take LCK_PR to flush dirty pages - * from clients; - * LL_DV_WR_FLUSH: OSTs will take LCK_PW to flush all caching - * pages from clients. - * - * \retval 0 on success. - * \retval -errno on error. - */ -int llapi_get_data_version(int fd, __u64 *data_version, __u64 flags) -{ - int rc; - struct ioc_data_version idv; - - idv.idv_flags = (__u32)flags; - - rc = ioctl(fd, LL_IOC_DATA_VERSION, &idv); - if (rc) - rc = -errno; - else - *data_version = idv.idv_version; - - return rc; -} - -/** * Flush cached pages from all clients. * * \param fd File descriptor @@ -5810,327 +6069,3 @@ int llapi_file_flush(int fd) return llapi_get_data_version(fd, &dv, LL_DV_WR_FLUSH); } -/* - * Fetch layout version from OST objects. Layout version on OST objects are - * only set when the file is a mirrored file AND after the file has been - * written at least once. - * - * It actually fetches the least layout version from the objects. - */ -int llapi_get_ost_layout_version(int fd, __u32 *layout_version) -{ - int rc; - struct ioc_data_version idv = { 0 }; - - rc = ioctl(fd, LL_IOC_DATA_VERSION, &idv); - if (rc) - rc = -errno; - else - *layout_version = idv.idv_layout_version; - - return rc; -} - -/* - * Create a file without any name and open it for read/write - * - * - file is created as if it were a standard file in the given \a directory - * - file does not appear in \a directory and mtime does not change because - * the filename is handled specially by the Lustre MDS. - * - file is destroyed at final close - * - * \param[in] directory directory from which to inherit layout/MDT idx - * \param[in] mdt_idx MDT index on which the file is created, - * \a idx == -1 means no specific MDT is requested - * \param[in] mode standard open(2) mode - * \param[in] stripe_param stripe parameters. May be NULL. - * - * \retval a file descriptor on success. - * \retval -errno on error. - */ -int llapi_create_volatile_param(const char *directory, int mdt_idx, - int open_flags, mode_t mode, - const struct llapi_stripe_param *stripe_param) -{ - char file_path[PATH_MAX]; - int saved_errno = errno; - int fd; - unsigned int rnumber; - int rc; - - do { - rnumber = random(); - if (mdt_idx == -1) - rc = snprintf(file_path, sizeof(file_path), - "%s/" LUSTRE_VOLATILE_HDR "::%.4X", - directory, rnumber); - else - rc = snprintf(file_path, sizeof(file_path), - "%s/" LUSTRE_VOLATILE_HDR ":%.4X:%.4X", - directory, mdt_idx, rnumber); - - if (rc < 0 || rc >= sizeof(file_path)) - return -ENAMETOOLONG; - - /* - * Either open O_WRONLY or O_RDWR, creating RDONLY - * is non-sensical here - */ - if ((open_flags & O_ACCMODE) == O_RDONLY) - open_flags = O_RDWR | (open_flags & ~O_ACCMODE); - - open_flags |= O_CREAT | O_EXCL | O_NOFOLLOW; - - if (stripe_param != NULL) { - fd = llapi_file_open_param(file_path, open_flags, - mode, stripe_param); - if (fd < 0) - rc = fd; - } else { - fd = open(file_path, open_flags, mode); - if (fd < 0) - rc = -errno; - } - } while (fd < 0 && rc == -EEXIST); - - if (fd < 0) { - llapi_error(LLAPI_MSG_ERROR, rc, - "Cannot create volatile file '%s' in '%s'", - file_path + strlen(directory) + 1 + - LUSTRE_VOLATILE_HDR_LEN, - directory); - return rc; - } - - /* - * Unlink file in case this wasn't a Lustre filesystem and the magic - * volatile filename wasn't handled as intended. The effect is the - * same. If volatile open was supported then we expect unlink() to - * return -ENOENT. - */ - (void)unlink(file_path); - - /* - * Since we are returning successfully we restore errno (and - * mask out possible EEXIST from open() and ENOENT from unlink(). - */ - errno = saved_errno; - - return fd; -} - -/* - * Create a file without any name open it for read/write - * - * - file is created as if it were a standard file in the given \a directory - * - file does not appear in \a directory and mtime does not change because - * the filename is handled specially by the Lustre MDS. - * - file is removed at final close - * - file modes are rw------- since it doesn't make sense to have a read-only - * or write-only file that cannot be opened again. - * - if user wants another mode it must use fchmod() on the open file, no - * security problems arise because it cannot be opened by another process. - * - * \param[in] directory directory from which to inherit layout/MDT idx - * \param[in] idx MDT index on which the file is created, - * \a idx == -1 means no specific MDT is requested - * \param[in] open_flags standard open(2) flags - * - * \retval a file descriptor on success. - * \retval -errno on error. - */ -int llapi_create_volatile_idx(const char *directory, int mdt_idx, - int open_flags) -{ - return llapi_create_volatile_param(directory, mdt_idx, open_flags, - S_IRUSR | S_IWUSR, NULL); -} - -/** - * Swap the layouts between 2 file descriptors - * the 2 files must be open for writing - * first fd received the ioctl, second fd is passed as arg - * this is assymetric but avoid use of root path for ioctl - */ -int llapi_fswap_layouts_grouplock(int fd1, int fd2, __u64 dv1, __u64 dv2, - int gid, __u64 flags) -{ - struct lustre_swap_layouts lsl; - struct stat st1; - struct stat st2; - int rc; - - if (flags & (SWAP_LAYOUTS_KEEP_ATIME | SWAP_LAYOUTS_KEEP_MTIME)) { - rc = fstat(fd1, &st1); - if (rc < 0) - return -errno; - - rc = fstat(fd2, &st2); - if (rc < 0) - return -errno; - } - lsl.sl_fd = fd2; - lsl.sl_flags = flags; - lsl.sl_gid = gid; - lsl.sl_dv1 = dv1; - lsl.sl_dv2 = dv2; - rc = ioctl(fd1, LL_IOC_LOV_SWAP_LAYOUTS, &lsl); - if (rc < 0) - return -errno; - - if (flags & (SWAP_LAYOUTS_KEEP_ATIME | SWAP_LAYOUTS_KEEP_MTIME)) { - struct timeval tv1[2]; - struct timeval tv2[2]; - - memset(tv1, 0, sizeof(tv1)); - memset(tv2, 0, sizeof(tv2)); - - if (flags & SWAP_LAYOUTS_KEEP_ATIME) { - tv1[0].tv_sec = st1.st_atime; - tv2[0].tv_sec = st2.st_atime; - } else { - tv1[0].tv_sec = st2.st_atime; - tv2[0].tv_sec = st1.st_atime; - } - - if (flags & SWAP_LAYOUTS_KEEP_MTIME) { - tv1[1].tv_sec = st1.st_mtime; - tv2[1].tv_sec = st2.st_mtime; - } else { - tv1[1].tv_sec = st2.st_mtime; - tv2[1].tv_sec = st1.st_mtime; - } - - rc = futimes(fd1, tv1); - if (rc < 0) - return -errno; - - rc = futimes(fd2, tv2); - if (rc < 0) - return -errno; - } - - return 0; -} - -int llapi_fswap_layouts(int fd1, int fd2, __u64 dv1, __u64 dv2, __u64 flags) -{ - int rc; - int grp_id; - - do - grp_id = random(); - while (grp_id == 0); - - rc = llapi_fswap_layouts_grouplock(fd1, fd2, dv1, dv2, grp_id, flags); - if (rc < 0) - return rc; - - return 0; -} - -/** - * Swap the layouts between 2 files - * the 2 files are open in write - */ -int llapi_swap_layouts(const char *path1, const char *path2, - __u64 dv1, __u64 dv2, __u64 flags) -{ - int fd1, fd2, rc; - - fd1 = open(path1, O_WRONLY | O_LOV_DELAY_CREATE); - if (fd1 < 0) { - rc = -errno; - llapi_error(LLAPI_MSG_ERROR, rc, - "error: cannot open '%s' for write", path1); - goto out; - } - - fd2 = open(path2, O_WRONLY | O_LOV_DELAY_CREATE); - if (fd2 < 0) { - rc = -errno; - llapi_error(LLAPI_MSG_ERROR, rc, - "error: cannot open '%s' for write", path2); - goto out_close; - } - - rc = llapi_fswap_layouts(fd1, fd2, dv1, dv2, flags); - if (rc < 0) - llapi_error(LLAPI_MSG_ERROR, rc, - "error: cannot swap layout between '%s' and '%s'", - path1, path2); - - close(fd2); -out_close: - close(fd1); -out: - 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 -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. - * \param gid Group Identifier. - * - * \retval 0 on success. - * \retval -errno on failure. - */ -int llapi_group_lock(int fd, int gid) -{ - int rc; - - rc = ioctl(fd, LL_IOC_GROUP_LOCK, gid); - if (rc < 0) { - rc = -errno; - llapi_error(LLAPI_MSG_ERROR, rc, "cannot get group lock"); - } - return rc; -} - -/** - * Put group lock. - * - * \param fd File to unlock. - * \param gid Group Identifier. - * - * \retval 0 on success. - * \retval -errno on failure. - */ -int llapi_group_unlock(int fd, int gid) -{ - int rc; - - rc = ioctl(fd, LL_IOC_GROUP_UNLOCK, gid); - if (rc < 0) { - rc = -errno; - llapi_error(LLAPI_MSG_ERROR, rc, "cannot put group lock"); - } - return rc; -}