X-Git-Url: https://git.whamcloud.com/?p=fs%2Flustre-release.git;a=blobdiff_plain;f=lustre%2Futils%2Fliblustreapi.c;h=754536f1178dbaacacbf7fccfb7f0aa26f1f8bd9;hp=ca6864f49b77a6b2a3d67df63d9d58f69f7dffd3;hb=c1d0a355a6a6;hpb=8f39c90355f4d60698b4b59d7a49aa1a714282ac diff --git a/lustre/utils/liblustreapi.c b/lustre/utils/liblustreapi.c index ca6864f..754536f 100644 --- a/lustre/utils/liblustreapi.c +++ b/lustre/utils/liblustreapi.c @@ -59,6 +59,7 @@ #include #include #include +#include #include #include #include /* for dirname() */ @@ -68,6 +69,8 @@ #include #endif #include +#include +#include #include #include @@ -83,7 +86,16 @@ const char *liblustreapi_cmd; char *mdt_hash_name[] = { "none", LMV_HASH_NAME_ALL_CHARS, - LMV_HASH_NAME_FNV_1A_64 }; + 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"}, + /* must be the last element */ + {.lft_type = LU_FOREIGN_TYPE_UNKNOWN, .lft_name = NULL} + /* array max dimension must be <= UINT32_MAX */ +}; void llapi_msg_set_level(int level) { @@ -129,11 +141,15 @@ static void error_callback_default(enum llapi_message_level level, int err, static void info_callback_default(enum llapi_message_level level, int err, const char *fmt, va_list ap) { - if (liblustreapi_cmd != NULL) - fprintf(stderr, "%s %s: ", program_invocation_short_name, - liblustreapi_cmd); - else - fprintf(stderr, "%s: ", program_invocation_short_name); + if (err != 0) { + if (liblustreapi_cmd != NULL) { + fprintf(stdout, "%s %s: ", + program_invocation_short_name, + liblustreapi_cmd); + } else { + fprintf(stdout, "%s: ", program_invocation_short_name); + } + } vfprintf(stdout, fmt, ap); } @@ -276,7 +292,7 @@ int llapi_parse_size(const char *optarg, unsigned long long *size, return 0; } -int obd_ioctl_pack(struct obd_ioctl_data *data, char **pbuf, int max_len) +int llapi_ioctl_pack(struct obd_ioctl_data *data, char **pbuf, int max_len) { struct obd_ioctl_data *overlay; char *ptr; @@ -285,8 +301,9 @@ int obd_ioctl_pack(struct obd_ioctl_data *data, char **pbuf, int max_len) data->ioc_version = OBD_IOCTL_VERSION; if (*pbuf != NULL && data->ioc_len > max_len) { - fprintf(stderr, "pbuf = %p, ioc_len = %u, max_len = %d\n", - *pbuf, data->ioc_len, max_len); + llapi_error(LLAPI_MSG_ERROR, -EINVAL, + "pbuf = %p, ioc_len = %u, max_len = %d\n", + *pbuf, data->ioc_len, max_len); return -EINVAL; } @@ -302,28 +319,28 @@ int obd_ioctl_pack(struct obd_ioctl_data *data, char **pbuf, int max_len) ptr = overlay->ioc_bulk; if (data->ioc_inlbuf1) { memcpy(ptr, data->ioc_inlbuf1, data->ioc_inllen1); - ptr += cfs_size_round(data->ioc_inllen1); + ptr += __ALIGN_KERNEL(data->ioc_inllen1, 8); } if (data->ioc_inlbuf2) { memcpy(ptr, data->ioc_inlbuf2, data->ioc_inllen2); - ptr += cfs_size_round(data->ioc_inllen2); + ptr += __ALIGN_KERNEL(data->ioc_inllen2, 8); } if (data->ioc_inlbuf3) { memcpy(ptr, data->ioc_inlbuf3, data->ioc_inllen3); - ptr += cfs_size_round(data->ioc_inllen3); + ptr += __ALIGN_KERNEL(data->ioc_inllen3, 8); } if (data->ioc_inlbuf4) { memcpy(ptr, data->ioc_inlbuf4, data->ioc_inllen4); - ptr += cfs_size_round(data->ioc_inllen4); + ptr += __ALIGN_KERNEL(data->ioc_inllen4, 8); } return 0; } -int obd_ioctl_unpack(struct obd_ioctl_data *data, char *pbuf, int max_len) +int llapi_ioctl_unpack(struct obd_ioctl_data *data, char *pbuf, int max_len) { struct obd_ioctl_data *overlay; char *ptr; @@ -344,22 +361,22 @@ int obd_ioctl_unpack(struct obd_ioctl_data *data, char *pbuf, int max_len) ptr = overlay->ioc_bulk; if (data->ioc_inlbuf1) { memcpy(data->ioc_inlbuf1, ptr, data->ioc_inllen1); - ptr += cfs_size_round(data->ioc_inllen1); + ptr += __ALIGN_KERNEL(data->ioc_inllen1, 8); } if (data->ioc_inlbuf2) { memcpy(data->ioc_inlbuf2, ptr, data->ioc_inllen2); - ptr += cfs_size_round(data->ioc_inllen2); + ptr += __ALIGN_KERNEL(data->ioc_inllen2, 8); } if (data->ioc_inlbuf3) { memcpy(data->ioc_inlbuf3, ptr, data->ioc_inllen3); - ptr += cfs_size_round(data->ioc_inllen3); + ptr += __ALIGN_KERNEL(data->ioc_inllen3, 8); } if (data->ioc_inlbuf4) { memcpy(data->ioc_inlbuf4, ptr, data->ioc_inllen4); - ptr += cfs_size_round(data->ioc_inllen4); + ptr += __ALIGN_KERNEL(data->ioc_inllen4, 8); } return 0; @@ -370,45 +387,52 @@ int obd_ioctl_unpack(struct obd_ioctl_data *data, char *pbuf, int max_len) int llapi_stripe_limit_check(unsigned long long stripe_size, int stripe_offset, int stripe_count, int stripe_pattern) { - int page_size, rc; + static int page_size; + int rc = 0; - /* 64 KB is the largest common page size I'm aware of (on ia64), but - * check the local page size just in case. */ - page_size = LOV_MIN_STRIPE_SIZE; - if (getpagesize() > page_size) { - page_size = getpagesize(); - llapi_err_noerrno(LLAPI_MSG_WARN, - "warning: your page size (%u) is " - "larger than expected (%u)", page_size, - LOV_MIN_STRIPE_SIZE); + if (page_size == 0) { + /* 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. + */ + page_size = LOV_MIN_STRIPE_SIZE; + if (getpagesize() > page_size) { + page_size = getpagesize(); + llapi_err_noerrno(LLAPI_MSG_WARN, + "warning: page size (%u) larger than expected (%u)", + page_size, LOV_MIN_STRIPE_SIZE); + } } if (!llapi_stripe_size_is_aligned(stripe_size)) { rc = -EINVAL; llapi_error(LLAPI_MSG_ERROR, rc, "error: bad stripe_size %llu, " "must be an even multiple of %d bytes", - stripe_size, page_size); - return rc; + (unsigned long long)stripe_size, page_size); + goto out; } if (!llapi_stripe_index_is_valid(stripe_offset)) { rc = -EINVAL; llapi_error(LLAPI_MSG_ERROR, rc, "error: bad stripe offset %d", stripe_offset); - return rc; + goto out; } if (!llapi_stripe_count_is_valid(stripe_count)) { rc = -EINVAL; llapi_error(LLAPI_MSG_ERROR, rc, "error: bad stripe count %d", stripe_count); - return rc; + goto out; } if (llapi_stripe_size_is_too_big(stripe_size)) { rc = -EINVAL; llapi_error(LLAPI_MSG_ERROR, rc, - "warning: stripe size 4G or larger " - "is not currently supported and would wrap"); - return rc; + "error: stripe size '%llu' over 4GB limit", + (unsigned long long)stripe_size); + goto out; } - return 0; + +out: + errno = -rc; + return rc; } int llapi_dir_stripe_limit_check(int stripe_offset, int stripe_count, @@ -498,13 +522,13 @@ static int get_mds_md_size(const char *path) rc = llapi_getname(path, inst, sizeof(inst)); if (rc != 0) - return md_size; + 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 md_size; + return rc; rc = atoi(buf); @@ -516,87 +540,6 @@ int llapi_get_agent_uuid(char *path, char *buf, size_t bufsize) return get_param_lmv(path, "uuid", buf, bufsize); } -/* - * if pool is NULL, search tgtname in target_obd - * if pool is not NULL: - * if pool not found returns errno < 0 - * if tgtname is NULL, returns 1 if pool is not empty and 0 if pool empty - * if tgtname is not NULL, returns 1 if OST is in pool and 0 if not - */ -int llapi_search_tgt(char *fsname, char *poolname, char *tgtname, bool is_mdt) -{ - char buffer[PATH_MAX]; - size_t len = 0; - glob_t param; - FILE *fd; - int rc; - - /* You need one or the other */ - if (poolname == NULL && fsname == NULL) - return -EINVAL; - - if (tgtname != NULL) - len = strlen(tgtname); - - if (poolname == NULL && len == 0) - return -EINVAL; - - /* Search by poolname and fsname if is not NULL */ - if (poolname != NULL) { - rc = poolpath(¶m, fsname, NULL); - if (rc == 0) { - snprintf(buffer, sizeof(buffer), "%s/%s", - param.gl_pathv[0], poolname); - } - } else if (fsname != NULL) { - rc = get_lustre_param_path(is_mdt ? "lmv" : "lov", fsname, - FILTER_BY_FS_NAME, - "target_obd", ¶m); - if (rc == 0) { - strncpy(buffer, param.gl_pathv[0], - sizeof(buffer)); - } - } else { - return -EINVAL; - } - cfs_free_param_data(¶m); - if (rc) - return rc; - - fd = fopen(buffer, "r"); - if (fd == NULL) - return -errno; - - while (fgets(buffer, sizeof(buffer), fd) != NULL) { - if (poolname == NULL) { - char *ptr; - /* Search for an tgtname in the list of targets - * Line format is IDX: fsname-OST/MDTxxxx_UUID STATUS */ - ptr = strchr(buffer, ' '); - if ((ptr != NULL) && - (strncmp(ptr + 1, tgtname, len) == 0)) { - fclose(fd); - return 1; - } - } else { - /* Search for an tgtname in a pool, - * (or an existing non-empty pool if no tgtname) */ - if ((tgtname == NULL) || - (strncmp(buffer, tgtname, len) == 0)) { - fclose(fd); - return 1; - } - } - } - fclose(fd); - return 0; -} - -int llapi_search_ost(char *fsname, char *poolname, char *ostname) -{ - return llapi_search_tgt(fsname, poolname, ostname, false); -} - /** * Open a Lustre file. * @@ -666,7 +609,7 @@ int llapi_file_open_param(const char *name, int flags, mode_t mode, /* sanity check of target list */ if (param->lsp_is_specific) { - char ostname[MAX_OBD_NAME + 1]; + char ostname[MAX_OBD_NAME + 64]; bool found = false; int i; @@ -758,9 +701,7 @@ retry_open: errmsg = strerror(errno); llapi_err_noerrno(LLAPI_MSG_ERROR, - "error on ioctl %#jx for '%s' (%d): %s", - (uintmax_t)LL_IOC_LOV_SETSTRIPE, name, fd, - errmsg); + "setstripe error for '%s': %s", name, errmsg); close(fd); fd = rc; @@ -794,6 +735,80 @@ int llapi_file_open(const char *name, int flags, int mode, stripe_pattern, NULL); } +int llapi_file_create_foreign(const char *name, mode_t mode, __u32 type, + __u32 flags, char *foreign_lov) +{ + size_t len; + struct lov_foreign_md *lfm; + int fd, rc; + + if (foreign_lov == NULL) { + rc = -EINVAL; + llapi_error(LLAPI_MSG_ERROR, rc, + "foreign LOV EA content must be provided"); + goto out_err; + } + + len = strlen(foreign_lov); + if (len > XATTR_SIZE_MAX - offsetof(struct lov_foreign_md, lfm_value) || + len <= 0) { + rc = -EINVAL; + llapi_error(LLAPI_MSG_ERROR, rc, + "foreign LOV EA size %zu (must be 0 < len < %zu)", + len, XATTR_SIZE_MAX - + offsetof(struct lov_foreign_md, lfm_value)); + goto out_err; + } + + lfm = malloc(len + offsetof(struct lov_foreign_md, lfm_value)); + if (lfm == NULL) { + rc = -ENOMEM; + llapi_error(LLAPI_MSG_ERROR, rc, + "failed to allocate lov_foreign_md"); + goto out_err; + } + + fd = open(name, O_WRONLY|O_CREAT|O_LOV_DELAY_CREATE, mode); + if (fd == -1) { + fd = -errno; + llapi_error(LLAPI_MSG_ERROR, fd, "open '%s' failed", name); + goto out_free; + } + + lfm->lfm_magic = LOV_USER_MAGIC_FOREIGN; + lfm->lfm_length = len; + lfm->lfm_type = type; + lfm->lfm_flags = flags; + memcpy(lfm->lfm_value, foreign_lov, len); + + if (ioctl(fd, LL_IOC_LOV_SETSTRIPE, lfm) != 0) { + char *errmsg = "stripe already set"; + + rc = -errno; + if (errno == ENOTTY) + errmsg = "not on a Lustre filesystem"; + else if (errno == EEXIST || errno == EALREADY) + errmsg = "stripe already set"; + else + errmsg = strerror(errno); + + llapi_err_noerrno(LLAPI_MSG_ERROR, + "setstripe error for '%s': %s", name, errmsg); + + close(fd); + fd = rc; + } + +out_free: + free(lfm); + + return fd; + +out_err: + errno = -rc; + return rc; +} + int llapi_file_create(const char *name, unsigned long long stripe_size, int stripe_offset, int stripe_count, int stripe_pattern) { @@ -879,7 +894,7 @@ static int verify_dir_param(const char *name, /* sanity check of target list */ if (param->lsp_is_specific) { - char mdtname[MAX_OBD_NAME + 1]; + char mdtname[MAX_OBD_NAME + 64]; bool found = false; int i; @@ -965,8 +980,8 @@ int llapi_dir_set_default_lmv(const char *name, errmsg = strerror(errno); llapi_err_noerrno(LLAPI_MSG_ERROR, - "error on LL_IOC_LMV_SETSTRIPE '%s' (%d): %s", - name, fd, errmsg); + "default dirstripe error on '%s': %s", + name, errmsg); } close(fd); return rc; @@ -996,11 +1011,11 @@ int llapi_dir_set_default_lmv_stripe(const char *name, int stripe_offset, * \retval 0 on success * \retval negative errno on failure */ -int llapi_dir_create_param(const char *name, mode_t mode, - const struct llapi_stripe_param *param) +int llapi_dir_create(const char *name, mode_t mode, + const struct llapi_stripe_param *param) { struct lmv_user_md *lmu = NULL; - size_t lmu_size = sizeof(*lmu); + size_t lmu_size; struct obd_ioctl_data data = { 0 }; char rawbuf[8192]; char *buf = rawbuf; @@ -1014,9 +1029,10 @@ int llapi_dir_create_param(const char *name, mode_t mode, if (rc) return rc; - if (param->lsp_is_specific) - lmu_size = lmv_user_md_size(param->lsp_stripe_count, - LMV_USER_MAGIC_SPECIFIC); + lmu_size = lmv_user_md_size(param->lsp_stripe_count, + param->lsp_is_specific ? + LMV_USER_MAGIC_SPECIFIC : + LMV_USER_MAGIC); lmu = calloc(1, lmu_size); if (lmu == NULL) @@ -1030,7 +1046,7 @@ int llapi_dir_create_param(const char *name, mode_t mode, namepath = strdup(name); if (!namepath) { - free(namepath); + free(dirpath); free(lmu); return -ENOMEM; } @@ -1045,7 +1061,7 @@ int llapi_dir_create_param(const char *name, mode_t mode, data.ioc_inlbuf2 = (char *)lmu; data.ioc_inllen2 = lmu_size; data.ioc_type = mode; - rc = obd_ioctl_pack(&data, &buf, sizeof(rawbuf)); + rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf)); if (rc) { llapi_error(LLAPI_MSG_ERROR, rc, "error: LL_IOC_LMV_SETSTRIPE pack failed '%s'.", @@ -1062,13 +1078,13 @@ int llapi_dir_create_param(const char *name, mode_t mode, if (ioctl(fd, LL_IOC_LMV_SETSTRIPE, buf)) { char *errmsg = "stripe already set"; + rc = -errno; if (errno != EEXIST && errno != EALREADY) errmsg = strerror(errno); llapi_err_noerrno(LLAPI_MSG_ERROR, - "error on LL_IOC_LMV_SETSTRIPE '%s' (%d): %s", - name, fd, errmsg); + "dirstripe error on '%s': %s", name, errmsg); } close(fd); out: @@ -1078,6 +1094,106 @@ out: return rc; } +/** + * Create a foreign directory. + * + * \param name the name of the directory to be created + * \param mode permission of the file if it is created, see mode in open(2) + * \param type foreign type to be set in LMV EA + * \param flags foreign flags to be set in LMV EA + * \param value foreign pattern to be set in LMV EA + * + * \retval 0 on success + * \retval negative errno on failure + */ +int llapi_dir_create_foreign(const char *name, mode_t mode, __u32 type, + __u32 flags, const char *value) +{ + struct lmv_foreign_md *lfm = NULL; + size_t lfm_size, len; + struct obd_ioctl_data data = { 0 }; + char rawbuf[8192]; + char *buf = rawbuf; + char *dirpath = NULL; + char *namepath = NULL; + char *dir; + char *filename; + int fd, rc; + + len = strlen(value); + 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)); + return rc; + } + lfm_size = len + offsetof(struct lmv_foreign_md, lfm_value); + lfm = calloc(1, lfm_size); + if (lfm == NULL) + return -ENOMEM; + + dirpath = strdup(name); + if (!dirpath) { + free(lfm); + return -ENOMEM; + } + + namepath = strdup(name); + if (!namepath) { + free(dirpath); + free(lfm); + return -ENOMEM; + } + + lfm->lfm_magic = LMV_MAGIC_FOREIGN; + lfm->lfm_length = len; + lfm->lfm_type = type; + lfm->lfm_flags = flags; + memcpy(lfm->lfm_value, value, len); + + filename = basename(namepath); + dir = dirname(dirpath); + + data.ioc_inlbuf1 = (char *)filename; + data.ioc_inllen1 = strlen(filename) + 1; + data.ioc_inlbuf2 = (char *)lfm; + data.ioc_inllen2 = lfm_size; + data.ioc_type = mode; + rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf)); + if (rc) { + llapi_error(LLAPI_MSG_ERROR, rc, + "error: LL_IOC_LMV_SETSTRIPE pack failed '%s'.", + name); + goto out; + } + + fd = open(dir, O_DIRECTORY | O_RDONLY); + if (fd < 0) { + rc = -errno; + llapi_error(LLAPI_MSG_ERROR, rc, "unable to open '%s'", name); + goto out; + } + + if (ioctl(fd, LL_IOC_LMV_SETSTRIPE, buf)) { + char *errmsg = "stripe already set"; + + rc = -errno; + if (errno != EEXIST && errno != EALREADY) + errmsg = strerror(errno); + + llapi_err_noerrno(LLAPI_MSG_ERROR, + "dirstripe error on '%s': %s", name, errmsg); + } + close(fd); +out: + free(namepath); + free(dirpath); + free(lfm); + return rc; +} int llapi_dir_create_pool(const char *name, int mode, int stripe_offset, int stripe_count, int stripe_pattern, @@ -1090,7 +1206,7 @@ int llapi_dir_create_pool(const char *name, int mode, int stripe_offset, .lsp_pool = (char *)pool_name }; - return llapi_dir_create_param(name, mode, ¶m); + return llapi_dir_create(name, mode, ¶m); } int llapi_direntry_remove(char *dname) @@ -1146,6 +1262,7 @@ int get_root_path(int want, char *fsname, int *outfd, char *path, int index) FILE *fp; int idx = 0, len = 0, mntlen, fd; int rc = -ENODEV; + int fsnamelen, mountlen; /* get the mount point */ fp = setmntent(PROC_MOUNTS, "r"); @@ -1179,30 +1296,32 @@ int get_root_path(int want, char *fsname, int *outfd, char *path, int index) ptr_end++; /* Check the fsname for a match, if given */ + mountlen = ptr_end - ptr; if (!(want & WANT_FSNAME) && fsname != NULL && - (strlen(fsname) > 0) && - (strncmp(ptr, fsname, ptr_end - ptr) != 0)) - continue; + (fsnamelen = strlen(fsname)) > 0 && + (fsnamelen != mountlen || + (strncmp(ptr, fsname, mountlen) != 0))) + continue; /* If the path isn't set return the first one we find */ if (path == NULL || strlen(path) == 0) { - strncpy(mntdir, mnt.mnt_dir, strlen(mnt.mnt_dir)); - mntdir[strlen(mnt.mnt_dir)] = '\0'; + strncpy(mntdir, mnt.mnt_dir, sizeof(mntdir) - 1); + mntdir[sizeof(mntdir) - 1] = '\0'; if ((want & WANT_FSNAME) && fsname != NULL) { - strncpy(fsname, ptr, ptr_end - ptr); - fsname[ptr_end - ptr] = '\0'; + strncpy(fsname, ptr, mountlen); + fsname[mountlen] = '\0'; } rc = 0; break; /* Otherwise find the longest matching path */ } else if ((strlen(path) >= mntlen) && (mntlen >= len) && (strncmp(mnt.mnt_dir, path, mntlen) == 0)) { - strncpy(mntdir, mnt.mnt_dir, strlen(mnt.mnt_dir)); - mntdir[strlen(mnt.mnt_dir)] = '\0'; + strncpy(mntdir, mnt.mnt_dir, sizeof(mntdir) - 1); + mntdir[sizeof(mntdir) - 1] = '\0'; len = mntlen; if ((want & WANT_FSNAME) && fsname != NULL) { - strncpy(fsname, ptr, ptr_end - ptr); - fsname[ptr_end - ptr] = '\0'; + strncpy(fsname, ptr, mountlen); + fsname[mountlen] = '\0'; } rc = 0; } @@ -1212,7 +1331,7 @@ 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, strlen(mntdir)); + strncpy(path, mntdir, PATH_MAX); path[strlen(mntdir)] = '\0'; } if (want & WANT_FD) { @@ -1270,30 +1389,37 @@ int llapi_search_fsname(const char *pathname, char *fsname) path = realpath(pathname, NULL); if (path == NULL) { - char buf[PATH_MAX], *ptr; + char tmp[PATH_MAX - 1]; + char buf[PATH_MAX]; + char *ptr; + tmp[0] = '\0'; buf[0] = '\0'; if (pathname[0] != '/') { /* Need an absolute path, but realpath() only works for * pathnames that actually exist. We go through the * extra hurdle of dirname(getcwd() + pathname) in * case the relative pathname contains ".." in it. */ - if (getcwd(buf, sizeof(buf) - 2) == NULL) { + char realpath[PATH_MAX - 1]; + + if (getcwd(realpath, sizeof(realpath) - 2) == NULL) { rc = -errno; llapi_error(LLAPI_MSG_ERROR, rc, "cannot get current working directory"); return rc; } - rc = strlcat(buf, "/", sizeof(buf)); - if (rc >= sizeof(buf)) { + + rc = snprintf(tmp, sizeof(tmp), "%s/", realpath); + if (rc >= sizeof(tmp)) { rc = -E2BIG; llapi_error(LLAPI_MSG_ERROR, rc, "invalid parent path '%s'", - buf); + tmp); return rc; } } - rc = strlcat(buf, pathname, sizeof(buf)); + + rc = snprintf(buf, sizeof(buf), "%s%s", tmp, pathname); if (rc >= sizeof(buf)) { rc = -E2BIG; llapi_error(LLAPI_MSG_ERROR, rc, @@ -1328,31 +1454,44 @@ 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; - int rc, nr; + 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; + memset(&uuid_buf, 0, sizeof(uuid_buf)); + rc = llapi_file_get_lov_uuid(path, &uuid_buf); + if (rc) + return rc; - /* We want to turn lustre-clilov-ffff88002738bc00 into - * lustre-ffff88002738bc00. */ + /* + * 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. + */ + cfg_instance = strstr(uuid, "-clilov-"); + if (!cfg_instance) + return -EINVAL; - nr = snprintf(buf, size, "%.*s-%s", - (int) (strlen(uuid) - 24), uuid, - uuid + strlen(uuid) - 16); + fsname_len = cfg_instance - uuid; + cfg_instance += strlen("-clilov-"); + len = snprintf(buf, size, "%.*s-%s", fsname_len, uuid, cfg_instance); - if (nr >= size) - rc = -ENAMETOOLONG; + if (len >= size) + rc = -ENAMETOOLONG; - return rc; + return rc; } /** @@ -1381,7 +1520,8 @@ int llapi_get_poolmembers(const char *poolname, char **members, /* name is FSNAME.POOLNAME */ if (strlen(poolname) >= sizeof(fsname)) return -EOVERFLOW; - strlcpy(fsname, poolname, sizeof(fsname)); + + snprintf(fsname, sizeof(fsname), "%s", poolname); pool = strchr(fsname, '.'); if (pool == NULL) return -EINVAL; @@ -1450,54 +1590,51 @@ int llapi_get_poolmembers(const char *poolname, char **members, int llapi_get_poollist(const char *name, char **poollist, int list_size, char *buffer, int buffer_size) { - char rname[PATH_MAX]; glob_t pathname; char *fsname; - char *ptr; - DIR *dir; + char *ptr; + DIR *dir; struct dirent *pool; - int rc = 0; - unsigned int nb_entries = 0; - unsigned int used = 0; - unsigned int i; + int rc = 0; + unsigned int nb_entries = 0; + unsigned int used = 0; + unsigned int i; /* initialize output array */ - for (i = 0; i < list_size; i++) - poollist[i] = NULL; - - /* is name a pathname ? */ - ptr = strchr(name, '/'); - if (ptr != NULL) { - /* only absolute pathname is supported */ - if (*name != '/') - return -EINVAL; + for (i = 0; i < list_size; i++) + poollist[i] = NULL; - if (!realpath(name, rname)) { - rc = -errno; - llapi_error(LLAPI_MSG_ERROR, rc, "invalid path '%s'", - name); - return rc; - } + /* is name a pathname ? */ + ptr = strchr(name, '/'); + if (ptr != NULL) { + char fsname_buf[MAXNAMLEN]; - fsname = strdup(rname); + /* We will need fsname for printing later */ + rc = llapi_getname(name, fsname_buf, sizeof(fsname_buf)); + if (rc) + return rc; + + ptr = strrchr(fsname_buf, '-'); + if (ptr) + *ptr = '\0'; + + fsname = strdup(fsname_buf); if (!fsname) return -ENOMEM; - - rc = poolpath(&pathname, NULL, rname); } else { /* name is FSNAME */ fsname = strdup(name); if (!fsname) return -ENOMEM; - rc = poolpath(&pathname, fsname, NULL); } + + rc = poolpath(&pathname, fsname, NULL); if (rc != 0) { llapi_error(LLAPI_MSG_ERROR, rc, "Lustre filesystem '%s' not found", name); goto free_path; } - llapi_printf(LLAPI_MSG_NORMAL, "Pools from %s:\n", fsname); dir = opendir(pathname.gl_pathv[0]); if (dir == NULL) { rc = -errno; @@ -1522,14 +1659,14 @@ int llapi_get_poollist(const char *name, char **poollist, int list_size, /* check output bounds */ if (nb_entries >= list_size) { rc = -EOVERFLOW; - goto free_dir; + goto free_dir_no_msg; } /* +2 for '.' and final '\0' */ if (used + strlen(pool->d_name) + strlen(fsname) + 2 > buffer_size) { rc = -EOVERFLOW; - goto free_dir; + goto free_dir_no_msg; } sprintf(buffer + used, "%s.%s", fsname, pool->d_name); @@ -1542,6 +1679,10 @@ free_dir: if (rc) llapi_error(LLAPI_MSG_ERROR, rc, "Error reading pool list for '%s'", name); + else + llapi_printf(LLAPI_MSG_NORMAL, "Pools from %s:\n", fsname); + +free_dir_no_msg: closedir(dir); free_path: cfs_free_param_data(&pathname); @@ -1624,18 +1765,47 @@ typedef int (semantic_func_t)(char *path, DIR *parent, DIR **d, #define OBD_NOT_FOUND (-1) +static void find_param_fini(struct find_param *param) +{ + if (param->fp_migrate) + return; + + if (param->fp_obd_indexes) { + free(param->fp_obd_indexes); + param->fp_obd_indexes = NULL; + } + + if (param->fp_lmd) { + free(param->fp_lmd); + param->fp_lmd = NULL; + } + + if (param->fp_lmv_md) { + free(param->fp_lmv_md); + param->fp_lmv_md = NULL; + } +} + static int common_param_init(struct find_param *param, char *path) { int lum_size = get_mds_md_size(path); + if (lum_size < 0) + return lum_size; + + /* migrate has fp_lmv_md initialized outside */ + if (param->fp_migrate) + return 0; + if (lum_size < PATH_MAX + 1) lum_size = PATH_MAX + 1; param->fp_lum_size = lum_size; - param->fp_lmd = calloc(1, sizeof(lstat_t) + param->fp_lum_size); + param->fp_lmd = calloc(1, offsetof(typeof(*param->fp_lmd), lmd_lmm) + + lum_size); if (param->fp_lmd == NULL) { llapi_error(LLAPI_MSG_ERROR, -ENOMEM, - "error: allocation of %zu bytes for ioctl", + "error: allocate %zu bytes for layout failed", sizeof(lstat_t) + param->fp_lum_size); return -ENOMEM; } @@ -1643,35 +1813,23 @@ static int common_param_init(struct find_param *param, char *path) param->fp_lmv_stripe_count = 256; param->fp_lmv_md = calloc(1, lmv_user_md_size(param->fp_lmv_stripe_count, - LMV_MAGIC_V1)); + LMV_USER_MAGIC_SPECIFIC)); if (param->fp_lmv_md == NULL) { llapi_error(LLAPI_MSG_ERROR, -ENOMEM, "error: allocation of %d bytes for ioctl", lmv_user_md_size(param->fp_lmv_stripe_count, - LMV_MAGIC_V1)); + LMV_USER_MAGIC_SPECIFIC)); + find_param_fini(param); return -ENOMEM; } param->fp_got_uuids = 0; param->fp_obd_indexes = NULL; param->fp_obd_index = OBD_NOT_FOUND; - if (!param->fp_migrate) - param->fp_mdt_index = OBD_NOT_FOUND; + param->fp_mdt_index = OBD_NOT_FOUND; return 0; } -static void find_param_fini(struct find_param *param) -{ - if (param->fp_obd_indexes) - free(param->fp_obd_indexes); - - if (param->fp_lmd) - free(param->fp_lmd); - - if (param->fp_lmv_md) - free(param->fp_lmv_md); -} - static int cb_common_fini(char *path, DIR *parent, DIR **dirp, void *data, struct dirent64 *de) { @@ -1715,19 +1873,40 @@ again: int stripe_count; int lmv_size; - stripe_count = (__u32)param->fp_lmv_md->lum_stripe_count; + /* if foreign LMV case, fake stripes number */ + if (param->fp_lmv_md->lum_magic == LMV_MAGIC_FOREIGN) { + struct lmv_foreign_md *lfm; + + lfm = (struct lmv_foreign_md *)param->fp_lmv_md; + if (lfm->lfm_length < XATTR_SIZE_MAX - + offsetof(typeof(*lfm), lfm_value)) { + uint32_t size = lfm->lfm_length + + offsetof(typeof(*lfm), lfm_value); + + stripe_count = lmv_foreign_to_md_stripes(size); + } else { + llapi_error(LLAPI_MSG_ERROR, -EINVAL, + "error: invalid %d foreign size " + "returned from ioctl", + lfm->lfm_length); + return -EINVAL; + } + } else { + stripe_count = param->fp_lmv_md->lum_stripe_count; + } if (stripe_count <= param->fp_lmv_stripe_count) return ret; free(param->fp_lmv_md); param->fp_lmv_stripe_count = stripe_count; - lmv_size = lmv_user_md_size(stripe_count, LMV_MAGIC_V1); + lmv_size = lmv_user_md_size(stripe_count, + LMV_USER_MAGIC_SPECIFIC); param->fp_lmv_md = malloc(lmv_size); if (param->fp_lmv_md == NULL) { llapi_error(LLAPI_MSG_ERROR, -ENOMEM, "error: allocation of %d bytes for ioctl", lmv_user_md_size(param->fp_lmv_stripe_count, - LMV_MAGIC_V1)); + LMV_USER_MAGIC_SPECIFIC)); return -ENOMEM; } goto again; @@ -1735,64 +1914,195 @@ again: return ret; } -static int get_lmd_info(char *path, DIR *parent, DIR *dir, - struct lov_user_mds_data *lmd, int lumlen) +static void convert_lmd_statx(struct lov_user_mds_data *lmd_v2, lstat_t *st, + bool strict) +{ + memset(&lmd_v2->lmd_stx, 0, sizeof(lmd_v2->lmd_stx)); + lmd_v2->lmd_stx.stx_blksize = st->st_blksize; + lmd_v2->lmd_stx.stx_nlink = st->st_nlink; + lmd_v2->lmd_stx.stx_uid = st->st_uid; + lmd_v2->lmd_stx.stx_gid = st->st_gid; + lmd_v2->lmd_stx.stx_mode = st->st_mode; + lmd_v2->lmd_stx.stx_ino = st->st_ino; + lmd_v2->lmd_stx.stx_size = st->st_size; + lmd_v2->lmd_stx.stx_blocks = st->st_blocks; + lmd_v2->lmd_stx.stx_atime.tv_sec = st->st_atime; + lmd_v2->lmd_stx.stx_ctime.tv_sec = st->st_ctime; + lmd_v2->lmd_stx.stx_mtime.tv_sec = st->st_mtime; + lmd_v2->lmd_stx.stx_rdev_major = major(st->st_rdev); + lmd_v2->lmd_stx.stx_rdev_minor = minor(st->st_rdev); + lmd_v2->lmd_stx.stx_dev_major = major(st->st_dev); + lmd_v2->lmd_stx.stx_dev_minor = minor(st->st_dev); + lmd_v2->lmd_stx.stx_mask |= STATX_BASIC_STATS; + + lmd_v2->lmd_flags = 0; + if (strict) { + lmd_v2->lmd_flags |= OBD_MD_FLSIZE | OBD_MD_FLBLOCKS; + } else { + lmd_v2->lmd_stx.stx_mask &= ~(STATX_SIZE | STATX_BLOCKS); + if (lmd_v2->lmd_stx.stx_size) + lmd_v2->lmd_flags |= OBD_MD_FLLAZYSIZE; + if (lmd_v2->lmd_stx.stx_blocks) + lmd_v2->lmd_flags |= OBD_MD_FLLAZYBLOCKS; + } + lmd_v2->lmd_flags |= OBD_MD_FLATIME | OBD_MD_FLMTIME | OBD_MD_FLCTIME | + OBD_MD_FLBLKSZ | OBD_MD_FLMODE | OBD_MD_FLTYPE | + OBD_MD_FLUID | OBD_MD_FLGID | OBD_MD_FLNLINK | + OBD_MD_FLRDEV; + +} + +static int convert_lmdbuf_v1v2(void *lmdbuf, int lmdlen) { - lstat_t *st = &lmd->lmd_st; - int ret = 0; + struct lov_user_mds_data_v1 *lmd_v1 = lmdbuf; + struct lov_user_mds_data *lmd_v2 = lmdbuf; + lstat_t st; + int size; - if (parent == NULL && dir == NULL) - return -EINVAL; + size = lov_comp_md_size((struct lov_comp_md_v1 *)&lmd_v1->lmd_lmm); + if (size < 0) + return size; - if (dir) { - ret = ioctl(dirfd(dir), LL_IOC_MDC_GETINFO, (void *)lmd); - } else if (parent) { - char *fname = strrchr(path, '/'); + if (lmdlen < sizeof(lmd_v1->lmd_st) + size) + return -EOVERFLOW; + + st = lmd_v1->lmd_st; + memmove(&lmd_v2->lmd_lmm, &lmd_v1->lmd_lmm, + lmdlen - (&lmd_v2->lmd_lmm - &lmd_v1->lmd_lmm)); + convert_lmd_statx(lmd_v2, &st, false); + lmd_v2->lmd_lmmsize = 0; + lmd_v2->lmd_padding = 0; + + return 0; +} + +int get_lmd_info_fd(const char *path, int parent_fd, int dir_fd, + void *lmdbuf, int lmdlen, enum get_lmd_info_type type) +{ + struct lov_user_mds_data *lmd = lmdbuf; + static bool use_old_ioctl; + unsigned long cmd; + int ret = 0; + + if (parent_fd < 0 && dir_fd < 0) + return -EINVAL; + if (type != GET_LMD_INFO && type != GET_LMD_STRIPE) + return -EINVAL; + + if (dir_fd >= 0) { + /* 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; + 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; + use_old_ioctl = true; + goto retry_getinfo; + } + + if (cmd == LL_IOC_MDC_GETINFO_OLD && !ret) + ret = convert_lmdbuf_v1v2(lmdbuf, lmdlen); + } else if (parent_fd >= 0) { + const char *fname = strrchr(path, '/'); - /* To avoid opening, locking, and closing each file on the - * client if that is not needed. The GETFILEINFO ioctl can - * be done on the patent dir with a single open for all + /* 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. + * + * This avoids opening, locking, and closing each file on the + * client if that is not needed. Multiple of these ioctl() can + * be done on the parent dir with a single open for all * files in that directory, and it also doesn't pollute the * client dcache with millions of dentries when traversing - * a large filesystem. */ + * a large filesystem. + */ fname = (fname == NULL ? path : fname + 1); - /* retrieve needed file info */ - strlcpy((char *)lmd, fname, lumlen); - ret = ioctl(dirfd(parent), IOC_MDC_GETFILEINFO, (void *)lmd); - } - if (ret) { - if (errno == ENOTTY) { - /* ioctl is not supported, it is not a lustre fs. - * Do the regular lstat(2) instead. */ - ret = lstat_f(path, st); - if (ret) { - ret = -errno; - llapi_error(LLAPI_MSG_ERROR, ret, - "error: %s: lstat failed for %s", - __func__, path); - } - } else if (errno == ENOENT) { - ret = -errno; - llapi_error(LLAPI_MSG_WARN, ret, - "warning: %s: %s does not exist", - __func__, path); - } else if (errno != EISDIR) { - ret = -errno; - llapi_error(LLAPI_MSG_ERROR, ret, - "%s ioctl failed for %s.", - dir ? "LL_IOC_MDC_GETINFO" : - "IOC_MDC_GETFILEINFO", path); - } else { + ret = snprintf(lmdbuf, lmdlen, "%s", fname); + if (ret < 0) + errno = -ret; + else if (ret >= lmdlen || ret++ == 0) + errno = EINVAL; + else { + if (type == GET_LMD_INFO) + cmd = use_old_ioctl ? IOC_MDC_GETFILEINFO_OLD : + IOC_MDC_GETFILEINFO; + 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; + use_old_ioctl = true; + goto retry_getfileinfo; + } + + if (cmd == IOC_MDC_GETFILEINFO_OLD && !ret) + ret = convert_lmdbuf_v1v2(lmdbuf, lmdlen); + } + } + + if (ret && type == GET_LMD_INFO) { + if (errno == ENOTTY) { + lstat_t st; + + /* ioctl is not supported, it is not a lustre fs. + * Do the regular lstat(2) instead. + */ + ret = lstat_f(path, &st); + if (ret) { + ret = -errno; + llapi_error(LLAPI_MSG_ERROR, ret, + "error: %s: lstat failed for %s", + __func__, path); + } + + convert_lmd_statx(lmd, &st, true); + /* 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. + */ + use_old_ioctl = false; + } else if (errno == ENOENT) { + ret = -errno; + llapi_error(LLAPI_MSG_WARN, ret, + "warning: %s does not exist", path); + } else if (errno != EISDIR && errno != ENODATA) { ret = -errno; llapi_error(LLAPI_MSG_ERROR, ret, - "error: %s: IOC_MDC_GETFILEINFO failed for %s", - __func__, path); + "%s ioctl failed for %s.", + dir_fd >= 0 ? "LL_IOC_MDC_GETINFO" : + "IOC_MDC_GETFILEINFO", path); } } + 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, semantic_func_t sem_init, semantic_func_t sem_fini, void *data, @@ -1830,30 +2140,26 @@ static int llapi_semantic_traverse(char *path, int size, DIR *parent, while ((dent = readdir64(d)) != NULL) { int rc; - if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, "..")) - continue; - - /* Don't traverse .lustre directory */ - if (!(strcmp(dent->d_name, dot_lustre_name))) - continue; + if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, "..")) + continue; - path[len] = 0; - if ((len + dent->d_reclen + 2) > size) { - llapi_err_noerrno(LLAPI_MSG_ERROR, - "error: %s: string buffer is too small", - __func__); - break; - } - strcat(path, "/"); - strcat(path, dent->d_name); + path[len] = 0; + if ((len + dent->d_reclen + 2) > size) { + llapi_err_noerrno(LLAPI_MSG_ERROR, + "error: %s: string buffer too small", + __func__); + break; + } + strcat(path, "/"); + strcat(path, dent->d_name); - if (dent->d_type == DT_UNKNOWN) { - lstat_t *st = ¶m->fp_lmd->lmd_st; + if (dent->d_type == DT_UNKNOWN) { + lstatx_t *stx = ¶m->fp_lmd->lmd_stx; rc = get_lmd_info(path, d, NULL, param->fp_lmd, - param->fp_lum_size); + param->fp_lum_size, GET_LMD_INFO); if (rc == 0) - dent->d_type = IFTODT(st->st_mode); + dent->d_type = IFTODT(stx->stx_mode); else if (ret == 0) ret = rc; @@ -1876,8 +2182,10 @@ static int llapi_semantic_traverse(char *path, int size, DIR *parent, rc = 0; if (sem_init) { rc = sem_init(path, d, NULL, data, dent); - if (rc < 0 && ret == 0) + if (rc < 0 && ret == 0) { ret = rc; + break; + } } if (sem_fini && rc == 0) sem_fini(path, d, NULL, data, dent); @@ -1914,7 +2222,7 @@ static int param_callback(char *path, semantic_func_t sem_init, if (!buf) return -ENOMEM; - strlcpy(buf, path, PATH_MAX + 1); + snprintf(buf, PATH_MAX + 1, "%s", path); ret = common_param_init(param, buf); if (ret) goto out; @@ -1931,12 +2239,13 @@ out: int llapi_file_fget_lov_uuid(int fd, struct obd_uuid *lov_name) { - int rc = ioctl(fd, OBD_IOC_GETNAME, lov_name); - if (rc) { - rc = -errno; - llapi_error(LLAPI_MSG_ERROR, rc, "error: can't get lov name."); - } - return rc; + int rc = ioctl(fd, OBD_IOC_GETNAME, 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) @@ -1956,7 +2265,7 @@ int llapi_file_get_lov_uuid(const char *path, struct obd_uuid *lov_uuid) fd = open(path, O_RDONLY | O_NONBLOCK); if (fd < 0) { rc = -errno; - llapi_error(LLAPI_MSG_ERROR, rc, "error opening %s", path); + llapi_error(LLAPI_MSG_ERROR, rc, "cannot open '%s'", path); return rc; } @@ -2221,9 +2530,9 @@ retry_get_uuids: ret = -ENOMEM; } - llapi_error(LLAPI_MSG_ERROR, ret, "get ost uuid failed"); - goto out_free; - } + llapi_error(LLAPI_MSG_ERROR, ret, "cannot get ost uuid"); + goto out_free; + } indexes = malloc(num_obds * sizeof(*obdindex)); if (indexes == NULL) { @@ -2249,14 +2558,14 @@ retry_get_uuids: } } } - if (i >= obdcount) { - indexes[obdnum] = OBD_NOT_FOUND; - llapi_err_noerrno(LLAPI_MSG_ERROR, - "error: %s: unknown obduuid: %s", - __func__, obduuids[obdnum].uuid); - ret = -EINVAL; - } - } + if (i >= obdcount) { + indexes[obdnum] = OBD_NOT_FOUND; + llapi_err_noerrno(LLAPI_MSG_ERROR, + "invalid obduuid '%s'", + obduuids[obdnum].uuid); + ret = -EINVAL; + } + } if (obd_valid == 0) *obdindex = OBD_NOT_FOUND; @@ -2381,7 +2690,7 @@ int sattr_cache_get_defaults(const char *const fsname, if (rc) return rc; } else { - strlcpy(fsname_buf, fsname, sizeof(fsname_buf)); + snprintf(fsname_buf, sizeof(fsname_buf), "%s", fsname); } if (strncmp(fsname_buf, cache.fsname, sizeof(fsname_buf) - 1) != 0) { @@ -2397,7 +2706,7 @@ int sattr_cache_get_defaults(const char *const fsname, cache.stripecount = tmp[0]; cache.stripesize = tmp[1]; cache.stripeoffset = tmp[2]; - strlcpy(cache.fsname, fsname_buf, sizeof(cache.fsname)); + snprintf(cache.fsname, sizeof(cache.fsname), "%s", fsname_buf); } if (scount) @@ -2412,12 +2721,15 @@ int sattr_cache_get_defaults(const char *const fsname, static char *layout2name(__u32 layout_pattern) { - if (layout_pattern == LOV_PATTERN_MDT) + if (layout_pattern & LOV_PATTERN_F_RELEASED) + return "released"; + else if (layout_pattern == LOV_PATTERN_MDT) return "mdt"; else if (layout_pattern == LOV_PATTERN_RAID0) return "raid0"; - else if (layout_pattern == (LOV_PATTERN_RAID0 | LOV_PATTERN_F_RELEASED)) - return "released"; + else if (layout_pattern == + (LOV_PATTERN_RAID0 | LOV_PATTERN_OVERSTRIPING)) + return "raid0,overstriped"; else return "unknown"; } @@ -2428,11 +2740,13 @@ enum lov_dump_flags { LDF_INDENT = 0x0004, LDF_SKIP_OBJS = 0x0008, LDF_YAML = 0x0010, + LDF_EXTENSION = 0x0020, }; static void lov_dump_user_lmm_header(struct lov_user_md *lum, char *path, struct lov_user_ost_data_v1 *objects, - int verbose, int depth, char *pool_name, + enum llapi_layout_verbose verbose, + int depth, char *pool_name, enum lov_dump_flags flags) { bool is_dir = flags & LDF_IS_DIR; @@ -2440,6 +2754,7 @@ static void lov_dump_user_lmm_header(struct lov_user_md *lum, char *path, bool indent = flags & LDF_INDENT; bool yaml = flags & LDF_YAML; bool skip_objs = flags & LDF_SKIP_OBJS; + bool extension = flags & LDF_EXTENSION; char *prefix = is_dir ? "" : "lmm_"; char *separator = ""; char *space = indent ? " " : ""; @@ -2497,14 +2812,14 @@ static void lov_dump_user_lmm_header(struct lov_user_md *lum, char *path, ver = (__u32)(lmm_oi_id(&lum->lmm_oi) >> 32); if (yaml) llapi_printf(LLAPI_MSG_NORMAL, DFID_NOBRACE"\n", - seq, oid, ver); + (unsigned long long)seq, oid, ver); else llapi_printf(LLAPI_MSG_NORMAL, DFID"\n", - seq, oid, ver); + (unsigned long long)seq, oid, ver); } - if (verbose & VERBOSE_COUNT) { - if (verbose & ~VERBOSE_COUNT) + if (verbose & VERBOSE_STRIPE_COUNT) { + if (verbose & ~VERBOSE_STRIPE_COUNT) llapi_printf(LLAPI_MSG_NORMAL, "%s%sstripe_count: ", space, prefix); if (is_dir) { @@ -2523,12 +2838,12 @@ static void lov_dump_user_lmm_header(struct lov_user_md *lum, char *path, " stripe count."); } else { llapi_printf(LLAPI_MSG_NORMAL, "%d", - lum->lmm_stripe_count == - (typeof(lum->lmm_stripe_count))(-1) - ? -1 : lum->lmm_stripe_count); + extension ? 0 : + (__s16)lum->lmm_stripe_count); } } else { llapi_printf(LLAPI_MSG_NORMAL, "%hd", + extension ? 0 : (__s16)lum->lmm_stripe_count); } if (!yaml && is_dir) @@ -2537,9 +2852,13 @@ static void lov_dump_user_lmm_header(struct lov_user_md *lum, char *path, separator = "\n"; } - if (verbose & VERBOSE_SIZE) { + if (((verbose & VERBOSE_STRIPE_SIZE) && !extension) || + ((verbose & VERBOSE_EXT_SIZE) && extension)) { llapi_printf(LLAPI_MSG_NORMAL, "%s", separator); - if (verbose & ~VERBOSE_SIZE) + if (verbose & ~VERBOSE_EXT_SIZE && extension) + llapi_printf(LLAPI_MSG_NORMAL, "%s%sextension_size: ", + space, prefix); + if (verbose & ~VERBOSE_STRIPE_SIZE && !extension) llapi_printf(LLAPI_MSG_NORMAL, "%s%sstripe_size: ", space, prefix); if (is_dir && !is_raw && lum->lmm_stripe_size == 0) { @@ -2553,8 +2872,11 @@ static void lov_dump_user_lmm_header(struct lov_user_md *lum, char *path, "Cannot determine default" " stripe size."); } else { - llapi_printf(LLAPI_MSG_NORMAL, "%u", - lum->lmm_stripe_size); + /* Extension size is in KiB */ + llapi_printf(LLAPI_MSG_NORMAL, "%llu", + extension ? + (unsigned long long)(lum->lmm_stripe_size * SEL_UNIT_SIZE) : + (unsigned long long)lum->lmm_stripe_size); } if (!yaml && is_dir) separator = " "; @@ -2562,17 +2884,17 @@ static void lov_dump_user_lmm_header(struct lov_user_md *lum, char *path, separator = "\n"; } - if ((verbose & VERBOSE_LAYOUT)) { + if ((verbose & VERBOSE_PATTERN)) { llapi_printf(LLAPI_MSG_NORMAL, "%s", separator); - if (verbose & ~VERBOSE_LAYOUT) + if (verbose & ~VERBOSE_PATTERN) llapi_printf(LLAPI_MSG_NORMAL, "%s%spattern: ", space, prefix); if (lov_pattern_supported(lum->lmm_pattern)) llapi_printf(LLAPI_MSG_NORMAL, "%s", layout2name(lum->lmm_pattern)); else - llapi_printf(LLAPI_MSG_NORMAL, "%.x", lum->lmm_pattern); - separator = is_dir ? " " : "\n"; + llapi_printf(LLAPI_MSG_NORMAL, "%x", lum->lmm_pattern); + separator = (!yaml && is_dir) ? " " : "\n"; } if ((verbose & VERBOSE_GENERATION) && !is_dir) { @@ -2581,13 +2903,13 @@ static void lov_dump_user_lmm_header(struct lov_user_md *lum, char *path, llapi_printf(LLAPI_MSG_NORMAL, "%s%slayout_gen: ", space, prefix); llapi_printf(LLAPI_MSG_NORMAL, "%u", - (int)lum->lmm_layout_gen); + skip_objs ? 0 : (int)lum->lmm_layout_gen); separator = "\n"; } - if (verbose & VERBOSE_OFFSET) { + if (verbose & VERBOSE_STRIPE_OFFSET) { llapi_printf(LLAPI_MSG_NORMAL, "%s", separator); - if (verbose & ~VERBOSE_OFFSET) + if (verbose & ~VERBOSE_STRIPE_OFFSET) llapi_printf(LLAPI_MSG_NORMAL, "%s%sstripe_offset: ", space, prefix); if (is_dir || skip_objs) @@ -2595,6 +2917,8 @@ static void lov_dump_user_lmm_header(struct lov_user_md *lum, char *path, lum->lmm_stripe_offset == (typeof(lum->lmm_stripe_offset))(-1) ? -1 : lum->lmm_stripe_offset); + else if (lov_pattern(lum->lmm_pattern) == LOV_PATTERN_MDT) + llapi_printf(LLAPI_MSG_NORMAL, "0"); else llapi_printf(LLAPI_MSG_NORMAL, "%u", objects[0].l_ost_idx); @@ -2623,7 +2947,8 @@ static void lov_dump_user_lmm_header(struct lov_user_md *lum, char *path, void lov_dump_user_lmm_v1v3(struct lov_user_md *lum, char *pool_name, struct lov_user_ost_data_v1 *objects, char *path, int obdindex, int depth, - int header, enum lov_dump_flags flags) + enum llapi_layout_verbose verbose, + enum lov_dump_flags flags) { bool is_dir = flags & LDF_IS_DIR; bool indent = flags & LDF_INDENT; @@ -2644,11 +2969,12 @@ void lov_dump_user_lmm_v1v3(struct lov_user_md *lum, char *pool_name, if (!obdstripe) return; - lov_dump_user_lmm_header(lum, path, objects, header, depth, pool_name, + lov_dump_user_lmm_header(lum, path, objects, verbose, depth, pool_name, flags); - if (!is_dir && !skip_objs && (header & VERBOSE_OBJID) && - !(lum->lmm_pattern & LOV_PATTERN_F_RELEASED)) { + if (!is_dir && !skip_objs && (verbose & VERBOSE_OBJID) && + !(lum->lmm_pattern & LOV_PATTERN_F_RELEASED || + lov_pattern(lum->lmm_pattern) == LOV_PATTERN_MDT)) { char *space = " - "; if (indent) @@ -2701,7 +3027,8 @@ void lov_dump_user_lmm_v1v3(struct lov_user_md *lum, char *pool_name, } void lmv_dump_user_lmm(struct lmv_user_md *lum, char *pool_name, - char *path, int obdindex, int depth, int verbose, + char *path, int obdindex, int depth, + enum llapi_layout_verbose verbose, enum lov_dump_flags flags) { struct lmv_user_mds_data *objects = lum->lum_objects; @@ -2736,8 +3063,8 @@ void lmv_dump_user_lmm(struct lmv_user_md *lum, char *pool_name, /* show all information default */ if (!verbose) { if (lum->lum_magic == LMV_USER_MAGIC) - verbose = VERBOSE_POOL | VERBOSE_COUNT | - VERBOSE_OFFSET | VERBOSE_HASH_TYPE; + verbose = VERBOSE_POOL | VERBOSE_STRIPE_COUNT | + VERBOSE_STRIPE_OFFSET | VERBOSE_HASH_TYPE; else verbose = VERBOSE_OBJID; } @@ -2745,21 +3072,21 @@ void lmv_dump_user_lmm(struct lmv_user_md *lum, char *pool_name, if (depth && path && ((verbose != VERBOSE_OBJID))) llapi_printf(LLAPI_MSG_NORMAL, "%s%s\n", prefix, path); - if (verbose & VERBOSE_COUNT) { + if (verbose & VERBOSE_STRIPE_COUNT) { llapi_printf(LLAPI_MSG_NORMAL, "%s", separator); - if (verbose & ~VERBOSE_COUNT) + if (verbose & ~VERBOSE_STRIPE_COUNT) llapi_printf(LLAPI_MSG_NORMAL, "lmv_stripe_count: "); llapi_printf(LLAPI_MSG_NORMAL, "%u", (int)lum->lum_stripe_count); - if ((verbose & VERBOSE_OFFSET) && !yaml) + if ((verbose & VERBOSE_STRIPE_OFFSET) && !yaml) separator = " "; else separator = "\n"; } - if (verbose & VERBOSE_OFFSET) { + if (verbose & VERBOSE_STRIPE_OFFSET) { llapi_printf(LLAPI_MSG_NORMAL, "%s", separator); - if (verbose & ~VERBOSE_OFFSET) + if (verbose & ~VERBOSE_STRIPE_OFFSET) llapi_printf(LLAPI_MSG_NORMAL, "lmv_stripe_offset: "); llapi_printf(LLAPI_MSG_NORMAL, "%d", (int)lum->lum_stripe_offset); @@ -2770,7 +3097,8 @@ void lmv_dump_user_lmm(struct lmv_user_md *lum, char *pool_name, } if (verbose & VERBOSE_HASH_TYPE) { - unsigned int type = lum->lum_hash_type; + unsigned int type = lum->lum_hash_type & LMV_HASH_TYPE_MASK; + unsigned int flags = lum->lum_hash_type & ~LMV_HASH_TYPE_MASK; llapi_printf(LLAPI_MSG_NORMAL, "%s", separator); if (verbose & ~VERBOSE_HASH_TYPE) @@ -2779,9 +3107,16 @@ void lmv_dump_user_lmm(struct lmv_user_md *lum, char *pool_name, llapi_printf(LLAPI_MSG_NORMAL, "%s", mdt_hash_name[type]); else - llapi_printf(LLAPI_MSG_NORMAL, "%d", - (int)type); + llapi_printf(LLAPI_MSG_NORMAL, "%#x", type); + + if (flags & LMV_HASH_FLAG_MIGRATION) + llapi_printf(LLAPI_MSG_NORMAL, ",migrating"); + if (flags & LMV_HASH_FLAG_BAD_TYPE) + llapi_printf(LLAPI_MSG_NORMAL, ",bad_type"); + if (flags & LMV_HASH_FLAG_LOST_LMV) + llapi_printf(LLAPI_MSG_NORMAL, ",lost_lmv"); separator = "\n"; + } if (verbose & VERBOSE_OBJID && lum->lum_magic != LMV_USER_MAGIC) { @@ -2820,7 +3155,7 @@ static void lov_dump_comp_v1_header(struct find_param *param, char *path, { struct lov_comp_md_v1 *comp_v1 = (void *)¶m->fp_lmd->lmd_lmm; int depth = param->fp_max_depth; - int verbose = param->fp_verbose; + enum llapi_layout_verbose verbose = param->fp_verbose; bool yaml = flags & LDF_YAML; if (depth && path && ((verbose != VERBOSE_OBJID) || @@ -2840,8 +3175,8 @@ static void lov_dump_comp_v1_header(struct find_param *param, char *path, "mirrored" : ""); else llapi_printf(LLAPI_MSG_NORMAL, - "%2slcm_flags: %s\n", - " ", lcm_flags_string(comp_v1->lcm_flags)); + "%2slcm_flags: %s\n", " ", + llapi_layout_flags_string(comp_v1->lcm_flags)); } if (verbose & VERBOSE_GENERATION) { @@ -2905,7 +3240,7 @@ static void lov_dump_comp_v1_entry(struct find_param *param, struct lov_comp_md_v1 *comp_v1 = (void *)¶m->fp_lmd->lmd_lmm; struct lov_comp_md_entry_v1 *entry; char *separator = ""; - int verbose = param->fp_verbose; + enum llapi_layout_verbose verbose = param->fp_verbose; bool yaml = flags & LDF_YAML; entry = &comp_v1->lcm_entries[index]; @@ -2927,6 +3262,19 @@ static void lov_dump_comp_v1_entry(struct find_param *param, separator = "\n"; } + if (verbose & VERBOSE_MIRROR_ID) { + llapi_printf(LLAPI_MSG_NORMAL, "%s", separator); + if (verbose & ~VERBOSE_MIRROR_ID) + llapi_printf(LLAPI_MSG_NORMAL, + "%4slcme_mirror_id: ", " "); + if (entry->lcme_id != LCME_ID_INVAL) + llapi_printf(LLAPI_MSG_NORMAL, "%u", + mirror_id_of(entry->lcme_id)); + else + llapi_printf(LLAPI_MSG_NORMAL, "N/A"); + separator = "\n"; + } + if (verbose & VERBOSE_COMP_FLAGS) { llapi_printf(LLAPI_MSG_NORMAL, "%s", separator); if (verbose & ~VERBOSE_COMP_FLAGS) @@ -2935,6 +3283,26 @@ static void lov_dump_comp_v1_entry(struct find_param *param, lcme_flags2str(entry->lcme_flags); separator = "\n"; } + /* print snapshot timestamp if its a nosync comp */ + if ((verbose & VERBOSE_COMP_FLAGS) && + (entry->lcme_flags & LCME_FL_NOSYNC)) { + llapi_printf(LLAPI_MSG_NORMAL, "%s", separator); + if (verbose & ~VERBOSE_COMP_FLAGS) + llapi_printf(LLAPI_MSG_NORMAL, + "%4slcme_timestamp: ", " "); + if (yaml) { + llapi_printf(LLAPI_MSG_NORMAL, "%llu", + (unsigned long long)entry->lcme_timestamp); + } else { + time_t stamp = entry->lcme_timestamp; + char *date_str = asctime(localtime(&stamp)); + + date_str[strlen(date_str) - 1] = '\0'; + llapi_printf(LLAPI_MSG_NORMAL, "'%s'", date_str); + } + + separator = "\n"; + } if (verbose & VERBOSE_COMP_START) { llapi_printf(LLAPI_MSG_NORMAL, "%s", separator); @@ -2942,7 +3310,7 @@ static void lov_dump_comp_v1_entry(struct find_param *param, llapi_printf(LLAPI_MSG_NORMAL, "%4slcme_extent.e_start: ", " "); llapi_printf(LLAPI_MSG_NORMAL, "%llu", - entry->lcme_extent.e_start); + (unsigned long long)entry->lcme_extent.e_start); separator = "\n"; } @@ -2955,7 +3323,7 @@ static void lov_dump_comp_v1_entry(struct find_param *param, llapi_printf(LLAPI_MSG_NORMAL, "%s", "EOF"); else llapi_printf(LLAPI_MSG_NORMAL, "%llu", - entry->lcme_extent.e_end); + (unsigned long long)entry->lcme_extent.e_end); separator = "\n"; } @@ -2995,12 +3363,12 @@ static void lov_dump_comp_v1_entry(struct find_param *param, * (limit - margin, limit]. */ static int find_value_cmp(unsigned long long file, unsigned long long limit, int sign, int negopt, unsigned long long margin, - int mds) + bool mds) { int ret = -1; if (sign > 0) { - /* Drop the fraction of margin (of days). */ + /* Drop the fraction of margin (of days or size). */ if (file + margin <= limit) ret = mds ? 0 : 1; } else if (sign == 0) { @@ -3038,8 +3406,8 @@ static inline void lov_v1v3_pool_name(struct lov_user_md *v1, char *pool_name) { if (v1->lmm_magic == LOV_USER_MAGIC_V3) - strlcpy(pool_name, ((struct lov_user_md_v3 *)v1)->lmm_pool_name, - LOV_MAXPOOLNAME); + snprintf(pool_name, LOV_MAXPOOLNAME, "%s", + ((struct lov_user_md_v3 *)v1)->lmm_pool_name); else pool_name[0] = '\0'; } @@ -3053,7 +3421,8 @@ print_last_init_comp(struct find_param *param) /* print specific component info */ if (param->fp_check_comp_id || param->fp_check_comp_flags || - param->fp_check_comp_start || param->fp_check_comp_end) + param->fp_check_comp_start || param->fp_check_comp_end || + param->fp_check_mirror_id || param->fp_check_mirror_index) return false; return true; @@ -3142,8 +3511,10 @@ static void lov_dump_comp_v1(struct find_param *param, char *path, struct lov_user_md_v1 *v1; char pool_name[LOV_MAXPOOLNAME + 1]; int obdindex = param->fp_obd_index; - int i, j, match; + int i, j, match, ext; bool obdstripe = false; + __u16 mirror_index = 0; + __u16 mirror_id = 0; if (obdindex != OBD_NOT_FOUND) { for (i = 0; !(flags & LDF_IS_DIR) && !obdstripe && @@ -3177,10 +3548,9 @@ static void lov_dump_comp_v1(struct find_param *param, char *path, entry = &comp_v1->lcm_entries[i]; if (param->fp_check_comp_flags) { - if ((param->fp_exclude_comp_flags && - (param->fp_comp_flags & entry->lcme_flags)) || - (!param->fp_exclude_comp_flags && - !(param->fp_comp_flags & entry->lcme_flags))) + if (((param->fp_comp_flags & entry->lcme_flags) != + param->fp_comp_flags) || + (param->fp_comp_neg_flags & entry->lcme_flags)) continue; } @@ -3205,6 +3575,32 @@ static void lov_dump_comp_v1(struct find_param *param, char *path, continue; } + if (param->fp_check_mirror_index) { + if (mirror_id != mirror_id_of(entry->lcme_id)) { + mirror_index++; + mirror_id = mirror_id_of(entry->lcme_id); + } + + match = find_value_cmp(mirror_index, + param->fp_mirror_index, + param->fp_mirror_index_sign, + param->fp_exclude_mirror_index, + 1, 0); + if (match == -1) + continue; + } else if (param->fp_check_mirror_id) { + if (mirror_id != mirror_id_of(entry->lcme_id)) + mirror_id = mirror_id_of(entry->lcme_id); + + match = find_value_cmp(mirror_id, + param->fp_mirror_id, + param->fp_mirror_id_sign, + param->fp_exclude_mirror_id, + 1, 0); + if (match == -1) + continue; + } + if (print_last_init_comp(param)) { /** * if part of stripe info is needed, we'd print only @@ -3212,8 +3608,15 @@ static void lov_dump_comp_v1(struct find_param *param, char *path, */ if (entry->lcme_flags & LCME_FL_INIT) continue; - else - break; + + if (param->fp_verbose & VERBOSE_EXT_SIZE) { + if (entry->lcme_flags & LCME_FL_EXTENSION) + /* moved back below */ + i++; + else + continue; + } + break; } if (entry->lcme_flags & LCME_FL_INIT) { @@ -3243,9 +3646,10 @@ static void lov_dump_comp_v1(struct find_param *param, char *path, objects = lov_v1v3_objects(v1); lov_v1v3_pool_name(v1, pool_name); + ext = entry->lcme_flags & LCME_FL_EXTENSION ? LDF_EXTENSION : 0; lov_dump_user_lmm_v1v3(v1, pool_name, objects, path, obdindex, param->fp_max_depth, param->fp_verbose, - flags); + flags | ext); } if (print_last_init_comp(param)) { /** @@ -3264,9 +3668,11 @@ static void lov_dump_comp_v1(struct find_param *param, char *path, objects = lov_v1v3_objects(v1); lov_v1v3_pool_name(v1, pool_name); + entry = &comp_v1->lcm_entries[i]; + ext = entry->lcme_flags & LCME_FL_EXTENSION ? LDF_EXTENSION : 0; lov_dump_user_lmm_v1v3(v1, pool_name, objects, path, obdindex, param->fp_max_depth, param->fp_verbose, - flags); + flags | ext); } } @@ -3276,7 +3682,7 @@ static void lov_dump_comp_v1(struct find_param *param, char *path, static inline bool has_any_comp_options(struct find_param *param) { - int verbose = param->fp_verbose; + enum llapi_layout_verbose verbose = param->fp_verbose; if (param->fp_check_comp_id || param->fp_check_comp_count || param->fp_check_comp_start || param->fp_check_comp_end || @@ -3301,13 +3707,14 @@ struct lov_user_mds_data *lov_forge_comp_v1(struct lov_user_mds_data *orig, int lum_size = lov_user_md_size(is_dir ? 0 : lum->lmm_stripe_count, lum->lmm_magic); - new = malloc(sizeof(lstat_t) + lum_off + lum_size); + new = malloc(offsetof(typeof(*new), lmd_lmm) + lum_off + lum_size); if (new == NULL) { llapi_printf(LLAPI_MSG_NORMAL, "out of memory\n"); return new; } - memcpy(new, orig, sizeof(lstat_t)); + memcpy(new, orig, sizeof(new->lmd_stx) + sizeof(new->lmd_flags) + + sizeof(new->lmd_lmmsize)); comp_v1 = (struct lov_comp_md_v1 *)&new->lmd_lmm; comp_v1->lcm_magic = lum->lmm_magic; @@ -3359,7 +3766,8 @@ static void lov_dump_plain_user_lmm(struct find_param *param, char *path, struct lov_user_ost_data_v1 *objects; struct lov_user_md_v3 *lmmv3 = (void *)¶m->fp_lmd->lmd_lmm; - strlcpy(pool_name, lmmv3->lmm_pool_name, sizeof(pool_name)); + snprintf(pool_name, sizeof(pool_name), "%s", + lmmv3->lmm_pool_name); objects = lmmv3->lmm_objects; lov_dump_user_lmm_v1v3(¶m->fp_lmd->lmd_lmm, pool_name, objects, path, param->fp_obd_index, @@ -3368,6 +3776,84 @@ static void lov_dump_plain_user_lmm(struct find_param *param, char *path, } } +static uint32_t check_foreign_type(uint32_t foreign_type) +{ + uint32_t i; + + for (i = 0; i < LU_FOREIGN_TYPE_UNKNOWN; i++) { + if (lu_foreign_types[i].lft_name == NULL) + break; + if (foreign_type == lu_foreign_types[i].lft_type) + return i; + } + + return LU_FOREIGN_TYPE_UNKNOWN; +} + +static void lov_dump_foreign_lmm(struct find_param *param, char *path, + enum lov_dump_flags flags) +{ + struct lov_foreign_md *lfm = (void *)¶m->fp_lmd->lmd_lmm; + bool yaml = flags & LDF_YAML; + + if (!yaml && param->fp_depth && path) + llapi_printf(LLAPI_MSG_NORMAL, "%s\n", path); + + if (param->fp_verbose & VERBOSE_DETAIL) { + uint32_t type = check_foreign_type(lfm->lfm_type); + + llapi_printf(LLAPI_MSG_NORMAL, "lfm_magic: 0x%08X\n", + lfm->lfm_magic); + llapi_printf(LLAPI_MSG_NORMAL, "lfm_length: %u\n", + lfm->lfm_length); + llapi_printf(LLAPI_MSG_NORMAL, "lfm_type: 0x%08X", + lfm->lfm_type); + if (type < LU_FOREIGN_TYPE_UNKNOWN) + llapi_printf(LLAPI_MSG_NORMAL, " (%s)\n", + lu_foreign_types[type].lft_name); + else + llapi_printf(LLAPI_MSG_NORMAL, " (unknown)\n"); + + llapi_printf(LLAPI_MSG_NORMAL, "lfm_flags: 0x%08X\n", + lfm->lfm_flags); + } + llapi_printf(LLAPI_MSG_NORMAL, "lfm_value: '%.*s'\n", + lfm->lfm_length, lfm->lfm_value); + llapi_printf(LLAPI_MSG_NORMAL, "\n"); +} + +static void lmv_dump_foreign_lmm(struct find_param *param, char *path, + enum lov_dump_flags flags) +{ + struct lmv_foreign_md *lfm = (struct lmv_foreign_md *)param->fp_lmv_md; + bool yaml = flags & LDF_YAML; + + if (!yaml && param->fp_depth && path) + llapi_printf(LLAPI_MSG_NORMAL, "%s\n", path); + + if (param->fp_verbose & VERBOSE_DETAIL) { + uint32_t type = check_foreign_type(lfm->lfm_type); + + llapi_printf(LLAPI_MSG_NORMAL, "lfm_magic: 0x%08X\n", + lfm->lfm_magic); + llapi_printf(LLAPI_MSG_NORMAL, "lfm_length: %u\n", + lfm->lfm_length); + llapi_printf(LLAPI_MSG_NORMAL, "lfm_type: 0x%08X", + lfm->lfm_type); + if (type < LU_FOREIGN_TYPE_UNKNOWN) + llapi_printf(LLAPI_MSG_NORMAL, " (%s)\n", + lu_foreign_types[type].lft_name); + else + llapi_printf(LLAPI_MSG_NORMAL, " (unknown)\n"); + + llapi_printf(LLAPI_MSG_NORMAL, "lfm_flags: 0x%08X\n", + lfm->lfm_flags); + } + llapi_printf(LLAPI_MSG_NORMAL, "lfm_value: '%.*s'\n", + lfm->lfm_length, lfm->lfm_value); + llapi_printf(LLAPI_MSG_NORMAL, "\n"); +} + static void llapi_lov_dump_user_lmm(struct find_param *param, char *path, enum lov_dump_flags flags) { @@ -3386,15 +3872,20 @@ static void llapi_lov_dump_user_lmm(struct find_param *param, char *path, switch (magic) { case LOV_USER_MAGIC_V1: case LOV_USER_MAGIC_V3: + case LOV_USER_MAGIC_SPECIFIC: lov_dump_plain_user_lmm(param, path, flags); break; + case LOV_USER_MAGIC_FOREIGN: + lov_dump_foreign_lmm(param, path, flags); + break; case LMV_MAGIC_V1: case LMV_USER_MAGIC: { char pool_name[LOV_MAXPOOLNAME + 1]; struct lmv_user_md *lum; lum = (struct lmv_user_md *)param->fp_lmv_md; - strlcpy(pool_name, lum->lum_pool_name, sizeof(pool_name)); + snprintf(pool_name, sizeof(pool_name), "%s", + lum->lum_pool_name); lmv_dump_user_lmm(lum, pool_name, path, param->fp_obd_index, param->fp_max_depth, param->fp_verbose, flags); @@ -3403,6 +3894,9 @@ static void llapi_lov_dump_user_lmm(struct find_param *param, char *path, case LOV_USER_MAGIC_COMP_V1: lov_dump_comp_v1(param, path, flags); break; + case LMV_MAGIC_FOREIGN: + 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", @@ -3440,8 +3934,7 @@ int llapi_file_get_stripe(const char *path, struct lov_user_md *lum) fd = open(dname, O_RDONLY | O_NONBLOCK); if (fd == -1) { rc = -errno; - free(dname); - return rc; + goto out_free; } strcpy((char *)lum, fname); @@ -3451,6 +3944,7 @@ int llapi_file_get_stripe(const char *path, struct lov_user_md *lum) if (close(fd) == -1 && rc == 0) rc = -errno; +out_free: free(dname); return rc; } @@ -3470,7 +3964,7 @@ int llapi_file_lookup(int dirfd, const char *name) data.ioc_inlbuf1 = (char *)name; data.ioc_inllen1 = strlen(name) + 1; - rc = obd_ioctl_pack(&data, &buf, sizeof(rawbuf)); + 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", @@ -3491,25 +3985,25 @@ int llapi_file_lookup(int dirfd, const char *name) * * If 0 is returned, we need to do another RPC to the OSTs to obtain the * updated timestamps. */ -static int find_time_check(lstat_t *st, struct find_param *param, int mds) +static int find_time_check(lstatx_t *stx, struct find_param *param, int mds) { int rc = 1; int rc2; /* Check if file is accepted. */ if (param->fp_atime) { - rc2 = find_value_cmp(st->st_atime, param->fp_atime, + rc2 = find_value_cmp(stx->stx_atime.tv_sec, param->fp_atime, param->fp_asign, param->fp_exclude_atime, - 24 * 60 * 60, mds); + param->fp_time_margin, mds); if (rc2 < 0) return rc2; rc = rc2; } if (param->fp_mtime) { - rc2 = find_value_cmp(st->st_mtime, param->fp_mtime, + rc2 = find_value_cmp(stx->stx_mtime.tv_sec, param->fp_mtime, param->fp_msign, param->fp_exclude_mtime, - 24 * 60 * 60, mds); + param->fp_time_margin, mds); if (rc2 < 0) return rc2; @@ -3520,9 +4014,9 @@ static int find_time_check(lstat_t *st, struct find_param *param, int mds) } if (param->fp_ctime) { - rc2 = find_value_cmp(st->st_ctime, param->fp_ctime, + rc2 = find_value_cmp(stx->stx_ctime.tv_sec, param->fp_ctime, param->fp_csign, param->fp_exclude_ctime, - 24 * 60 * 60, mds); + param->fp_time_margin, mds); if (rc2 < 0) return rc2; @@ -3545,15 +4039,19 @@ 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; - lstat_t *st = ¶m->fp_lmd->lmd_st; + lstatx_t *stx = ¶m->fp_lmd->lmd_stx; int i, j, k, count = 1; if (param->fp_obd_uuid && param->fp_obd_index == OBD_NOT_FOUND) return 0; - if (!S_ISREG(st->st_mode)) + if (!S_ISREG(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. */ if (v1->lmm_magic == LOV_USER_MAGIC_COMP_V1) { @@ -3634,23 +4132,66 @@ static int find_check_stripe_size(struct find_param *param) { struct lov_comp_md_v1 *comp_v1 = NULL; struct lov_user_md_v1 *v1 = ¶m->fp_lmd->lmd_lmm; + __u32 stripe_size = 0; int ret, i, count = 1; + if (v1->lmm_magic == LOV_USER_MAGIC_FOREIGN) + return param->fp_exclude_stripe_size ? 1 : -1; + + ret = param->fp_exclude_stripe_size ? 1 : -1; if (v1->lmm_magic == LOV_USER_MAGIC_COMP_V1) { comp_v1 = (struct lov_comp_md_v1 *)v1; count = comp_v1->lcm_entry_count; - ret = param->fp_exclude_stripe_size ? 1 : -1; } for (i = 0; i < count; i++) { - if (comp_v1) + struct lov_comp_md_entry_v1 *ent; + + if (comp_v1) { v1 = lov_comp_entry(comp_v1, i); - ret = find_value_cmp(v1->lmm_stripe_size, param->fp_stripe_size, - param->fp_stripe_size_sign, - param->fp_exclude_stripe_size, - param->fp_stripe_size_units, 0); - /* If any stripe_size matches */ + ent = &comp_v1->lcm_entries[i]; + if (ent->lcme_flags & LCME_FL_EXTENSION) + continue; + if (!(ent->lcme_flags & LCME_FL_INIT)) + continue; + } + stripe_size = v1->lmm_stripe_size; + } + + ret = find_value_cmp(stripe_size, param->fp_stripe_size, + param->fp_stripe_size_sign, + param->fp_exclude_stripe_size, + param->fp_stripe_size_units, 0); + + return ret; +} + +static int find_check_ext_size(struct find_param *param) +{ + struct lov_comp_md_v1 *comp_v1; + struct lov_user_md_v1 *v1; + int ret, i; + + ret = param->fp_exclude_ext_size ? 1 : -1; + comp_v1 = (struct lov_comp_md_v1 *)¶m->fp_lmd->lmd_lmm; + if (comp_v1->lcm_magic != LOV_USER_MAGIC_COMP_V1) + return ret; + + for (i = 0; i < comp_v1->lcm_entry_count; i++) { + struct lov_comp_md_entry_v1 *ent; + + v1 = lov_comp_entry(comp_v1, i); + + ent = &comp_v1->lcm_entries[i]; + if (!(ent->lcme_flags & LCME_FL_EXTENSION)) + continue; + + ret = find_value_cmp(v1->lmm_stripe_size, param->fp_ext_size, + param->fp_ext_size_sign, + param->fp_exclude_ext_size, + param->fp_ext_size_units, 0); + /* If any ext_size matches */ if (ret != -1) break; } @@ -3665,15 +4206,28 @@ static __u32 find_get_stripe_count(struct find_param *param) int i, count = 1; __u32 stripe_count = 0; + if (v1->lmm_magic == LOV_USER_MAGIC_FOREIGN) + return 0; + if (v1->lmm_magic == LOV_USER_MAGIC_COMP_V1) { comp_v1 = (struct lov_comp_md_v1 *)v1; count = comp_v1->lcm_entry_count; } for (i = 0; i < count; i++) { - if (comp_v1) + if (comp_v1) { + struct lov_comp_md_entry_v1 *ent; + v1 = lov_comp_entry(comp_v1, i); - stripe_count += v1->lmm_stripe_count; + + ent = &comp_v1->lcm_entries[i]; + if (!(ent->lcme_flags & LCME_FL_INIT)) + continue; + + if (ent->lcme_flags & LCME_FL_EXTENSION) + continue; + } + stripe_count = v1->lmm_stripe_count; } return stripe_count; @@ -3697,6 +4251,10 @@ static int find_check_layout(struct find_param *param) if (comp_v1) v1 = lov_comp_entry(comp_v1, i); + /* foreign file have a special magic but no pattern field */ + if (v1->lmm_magic == LOV_USER_MAGIC_FOREIGN) + continue; + if (v1->lmm_pattern == LOV_PATTERN_INVALID) continue; @@ -3717,6 +4275,45 @@ static int find_check_layout(struct find_param *param) return -1; } +/* 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) +{ + if (S_ISREG(param->fp_lmd->lmd_stx.stx_mode)) { + struct lov_foreign_md *lfm; + + lfm = (void *)¶m->fp_lmd->lmd_lmm; + if (lfm->lfm_magic != LOV_USER_MAGIC_FOREIGN) { + 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 (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 (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; + } + } + return -1; +} + static int find_check_pool(struct find_param *param) { struct lov_comp_md_v1 *comp_v1 = NULL; @@ -3737,6 +4334,9 @@ static int find_check_pool(struct find_param *param) if (comp_v1 != NULL) v1 = lov_comp_entry(comp_v1, i); + if (v1->lmm_magic == LOV_USER_MAGIC_FOREIGN) + continue; + if (((v1->lmm_magic == LOV_USER_MAGIC_V1) && (param->fp_poolname[0] == '\0')) || ((v1->lmm_magic == LOV_USER_MAGIC_V3) && @@ -3758,12 +4358,15 @@ static int find_check_pool(struct find_param *param) static int find_check_comp_options(struct find_param *param) { - lstat_t *st = ¶m->fp_lmd->lmd_st; + 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_comp_md_entry_v1 *entry; int i, ret = 0; + if (v1->lmm_magic == LOV_USER_MAGIC_FOREIGN) + return -1; + if (v1->lmm_magic == LOV_USER_MAGIC_COMP_V1) { comp_v1 = (struct lov_comp_md_v1 *)v1; } else { @@ -3773,7 +4376,7 @@ 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(st->st_mode) ? 0 : LCME_FL_INIT; + entry->lcme_flags = S_ISDIR(stx->stx_mode) ? 0 : LCME_FL_INIT; entry->lcme_extent.e_start = 0; entry->lcme_extent.e_end = LUSTRE_EOF; } @@ -3798,16 +4401,13 @@ static int find_check_comp_options(struct find_param *param) entry = &comp_v1->lcm_entries[i]; if (param->fp_check_comp_flags) { - if (((entry->lcme_flags & param->fp_comp_flags) && - param->fp_exclude_comp_flags) || - (!(entry->lcme_flags & param->fp_comp_flags) && - !param->fp_exclude_comp_flags)) + ret = 1; + if (((param->fp_comp_flags & entry->lcme_flags) != + param->fp_comp_flags) || + (param->fp_comp_neg_flags & entry->lcme_flags)) { ret = -1; - else - ret = 1; - - if (ret == -1) continue; + } } if (param->fp_check_comp_start) { @@ -3831,17 +4431,52 @@ static int find_check_comp_options(struct find_param *param) break; } out: - if (forged_v1 != NULL) + if (forged_v1) free(forged_v1); return ret; } +static int find_check_mirror_options(struct find_param *param) +{ + struct lov_comp_md_v1 *comp_v1; + struct lov_user_md_v1 *v1 = ¶m->fp_lmd->lmd_lmm; + int ret = 0; + + if (v1->lmm_magic != LOV_USER_MAGIC_COMP_V1) + return -1; + + comp_v1 = (struct lov_comp_md_v1 *)v1; + + if (param->fp_check_mirror_count) { + ret = find_value_cmp(comp_v1->lcm_mirror_count + 1, + param->fp_mirror_count, + param->fp_mirror_count_sign, + param->fp_exclude_mirror_count, 1, 0); + if (ret == -1) + return ret; + } + + if (param->fp_check_mirror_state) { + ret = 1; + __u16 file_state = comp_v1->lcm_flags & LCM_FL_FLR_MASK; + + if ((param->fp_mirror_state != 0 && + file_state != param->fp_mirror_state) || + file_state == param->fp_mirror_neg_state) + return -1; + } + + return ret; +} + static bool find_check_lmm_info(struct find_param *param) { return param->fp_check_pool || param->fp_check_stripe_count || param->fp_check_stripe_size || param->fp_check_layout || param->fp_check_comp_count || param->fp_check_comp_end || param->fp_check_comp_start || param->fp_check_comp_flags || + param->fp_check_mirror_count || param->fp_check_foreign || + param->fp_check_mirror_state || param->fp_check_ext_size || param->fp_check_projid; } @@ -3869,11 +4504,12 @@ static int cb_find_init(char *path, DIR *parent, DIR **dirp, struct find_param *param = (struct find_param *)data; DIR *dir = dirp == NULL ? NULL : *dirp; int decision = 1; /* 1 is accepted; -1 is rejected. */ - lstat_t *st = ¶m->fp_lmd->lmd_st; + lstatx_t *stx = ¶m->fp_lmd->lmd_stx; int lustre_fs = 1; int checked_type = 0; int ret = 0; __u32 stripe_count = 0; + __u64 flags; int fd = -2; if (parent == NULL && dir == NULL) @@ -3909,7 +4545,8 @@ static int cb_find_init(char *path, DIR *parent, DIR **dirp, if (param->fp_obd_uuid || param->fp_mdt_uuid || param->fp_check_uid || param->fp_check_gid || param->fp_atime || param->fp_mtime || param->fp_ctime || - param->fp_check_size || find_check_lmm_info(param) || + param->fp_check_size || param->fp_check_blocks || + find_check_lmm_info(param) || param->fp_check_mdt_count || param->fp_check_hash_type) decision = 0; @@ -3917,16 +4554,27 @@ static int cb_find_init(char *path, DIR *parent, DIR **dirp, decision = 0; if (decision == 0) { - if (param->fp_check_mdt_count || param->fp_check_hash_type) { + if (dir && (param->fp_check_mdt_count || + param->fp_check_hash_type || param->fp_check_foreign)) { param->fp_get_lmv = 1; ret = cb_get_dirstripe(path, dir, param); - if (ret != 0) + 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; + } return ret; + } } param->fp_lmd->lmd_lmm.lmm_magic = 0; ret = get_lmd_info(path, parent, dir, param->fp_lmd, - param->fp_lum_size); + 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; @@ -3946,7 +4594,7 @@ static int cb_find_init(char *path, DIR *parent, DIR **dirp, if (dir != NULL) { ret = llapi_file_fget_mdtidx(dirfd(dir), ¶m->fp_file_mdt_index); - } else if (S_ISREG(st->st_mode)) { + } else if (S_ISREG(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 @@ -3980,7 +4628,7 @@ static int cb_find_init(char *path, DIR *parent, DIR **dirp, } if (param->fp_type && !checked_type) { - if ((st->st_mode & S_IFMT) == param->fp_type) { + if ((stx->stx_mode & S_IFMT) == param->fp_type) { if (param->fp_exclude_type) goto decided; } else { @@ -3992,7 +4640,8 @@ static int cb_find_init(char *path, DIR *parent, DIR **dirp, /* Prepare odb. */ if (param->fp_obd_uuid || param->fp_mdt_uuid) { if (lustre_fs && param->fp_got_uuids && - param->fp_dev != st->st_dev) { + param->fp_dev != makedev(stx->stx_dev_major, + stx->stx_dev_minor)) { /* A lustre/lustre mount point is crossed. */ param->fp_got_uuids = 0; param->fp_obds_printed = 0; @@ -4006,7 +4655,8 @@ static int cb_find_init(char *path, DIR *parent, DIR **dirp, if (ret) goto out; - param->fp_dev = st->st_dev; + param->fp_dev = makedev(stx->stx_dev_major, + 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; @@ -4015,12 +4665,24 @@ static int cb_find_init(char *path, DIR *parent, DIR **dirp, } } + if (param->fp_check_foreign) { + decision = find_check_foreign(param); + if (decision == -1) + goto decided; + } + if (param->fp_check_stripe_size) { decision = find_check_stripe_size(param); if (decision == -1) goto decided; } + if (param->fp_check_ext_size) { + decision = find_check_ext_size(param); + if (decision == -1) + goto decided; + } + if (param->fp_check_stripe_count) { decision = find_value_cmp(stripe_count, param->fp_stripe_count, param->fp_stripe_count_sign, @@ -4030,6 +4692,11 @@ static int cb_find_init(char *path, DIR *parent, DIR **dirp, } 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, @@ -4048,6 +4715,11 @@ static int cb_find_init(char *path, DIR *parent, DIR **dirp, 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)) { @@ -4086,7 +4758,7 @@ static int cb_find_init(char *path, DIR *parent, DIR **dirp, obd_matches: if (param->fp_check_uid) { - if (st->st_uid == param->fp_uid) { + if (stx->stx_uid == param->fp_uid) { if (param->fp_exclude_uid) goto decided; } else { @@ -4096,7 +4768,7 @@ obd_matches: } if (param->fp_check_gid) { - if (st->st_gid == param->fp_gid) { + if (stx->stx_gid == param->fp_gid) { if (param->fp_exclude_gid) goto decided; } else { @@ -4118,7 +4790,7 @@ obd_matches: if (ret) goto out; if (projid == param->fp_projid) { - if (param->fp_exclude_uid) + if (param->fp_exclude_projid) goto decided; } else { if (!param->fp_exclude_projid) @@ -4139,29 +4811,46 @@ obd_matches: goto decided; } + if (param->fp_check_mirror_count || param->fp_check_mirror_state) { + decision = find_check_mirror_options(param); + if (decision == -1) + goto decided; + } + /* Check the time on mds. */ decision = 1; if (param->fp_atime || param->fp_mtime || param->fp_ctime) { int for_mds; for_mds = lustre_fs ? - (S_ISREG(st->st_mode) && stripe_count) : 0; - decision = find_time_check(st, param, for_mds); - if (decision == -1) - goto decided; - } - - /* 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'. */ + (S_ISREG(stx->stx_mode) && stripe_count) : 0; + decision = find_time_check(stx, param, for_mds); + if (decision == -1) + goto decided; + } - if (param->fp_check_size && S_ISREG(st->st_mode) && stripe_count) + flags = param->fp_lmd->lmd_flags; + if (param->fp_check_size && + ((S_ISREG(stx->stx_mode) && stripe_count) || + S_ISDIR(stx->stx_mode)) && + !(flags & OBD_MD_FLSIZE || + (param->fp_lazy && flags & OBD_MD_FLLAZYSIZE))) decision = 0; - if (param->fp_check_size && S_ISDIR(st->st_mode)) + if (param->fp_check_blocks && + ((S_ISREG(stx->stx_mode) && stripe_count) || + S_ISDIR(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. + * 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. */ if (param->fp_obd_index != OBD_NOT_FOUND) @@ -4171,48 +4860,61 @@ obd_matches: print_failed_tgt(param, path, LL_STATFS_LMV); if (dir != NULL) - ret = fstat_f(dirfd(dir), st); + ret = fstat_f(dirfd(dir), &st); else if (de != NULL) - ret = fstatat_f(dirfd(parent), de->d_name, st, + ret = fstatat_f(dirfd(parent), de->d_name, &st, AT_SYMLINK_NOFOLLOW); else - ret = lstat_f(path, st); - - if (ret) { - if (errno == ENOENT) { - llapi_error(LLAPI_MSG_ERROR, -ENOENT, - "warning: %s: %s does not exist", - __func__, path); - goto decided; - } else { + ret = lstat_f(path, &st); + + if (ret) { + if (errno == ENOENT) { + llapi_error(LLAPI_MSG_ERROR, -ENOENT, + "warning: %s: %s does not exist", + __func__, path); + goto decided; + } else { ret = -errno; llapi_error(LLAPI_MSG_ERROR, ret, - "%s: IOC_LOV_GETINFO on %s failed", + "%s: stat on %s failed", __func__, path); goto out; } } + convert_lmd_statx(param->fp_lmd, &st, true); /* Check the time on osc. */ - decision = find_time_check(st, param, 0); + decision = find_time_check(stx, param, 0); if (decision == -1) goto decided; } - if (param->fp_check_size) - decision = find_value_cmp(st->st_size, param->fp_size, + if (param->fp_check_size) { + decision = find_value_cmp(stx->stx_size, param->fp_size, param->fp_size_sign, param->fp_exclude_size, param->fp_size_units, 0); + if (decision == -1) + goto decided; + } - if (decision != -1) { - 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"); + if (param->fp_check_blocks) { /* convert st_blocks to bytes */ + decision = find_value_cmp(stx->stx_blocks * 512, + param->fp_blocks, + param->fp_blocks_sign, + param->fp_exclude_blocks, + param->fp_blocks_units, 0); + if (decision == -1) + 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"); + decided: ret = 0; /* Do not get down anymore? */ @@ -4230,20 +4932,24 @@ out: static int cb_migrate_mdt_init(char *path, DIR *parent, DIR **dirp, void *param_data, struct dirent64 *de) { - struct find_param *param = (struct find_param *)param_data; - DIR *tmp_parent = parent; - 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; + struct find_param *param = (struct find_param *)param_data; + struct lmv_user_md *lmu = param->fp_lmv_md; + DIR *tmp_parent = parent; + 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) return -EINVAL; + if (!lmu) + return -EINVAL; + if (dirp != NULL) closedir(*dirp); @@ -4262,11 +4968,13 @@ static int cb_migrate_mdt_init(char *path, DIR *parent, DIR **dirp, path_copy = strdup(path); filename = basename(path_copy); + data.ioc_inlbuf1 = (char *)filename; data.ioc_inllen1 = strlen(filename) + 1; - data.ioc_inlbuf2 = (char *)¶m->fp_mdt_index; - data.ioc_inllen2 = sizeof(param->fp_mdt_index); - ret = obd_ioctl_pack(&data, &rawbuf, sizeof(raw)); + data.ioc_inlbuf2 = (char *)lmu; + data.ioc_inllen2 = lmv_user_md_size(lmu->lum_stripe_count, + lmu->lum_magic); + ret = llapi_ioctl_pack(&data, &rawbuf, sizeof(raw)); if (ret != 0) { llapi_error(LLAPI_MSG_ERROR, ret, "llapi_obd_statfs: error packing ioctl data"); @@ -4285,14 +4993,24 @@ migrate: 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", + 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); + goto out; } - ret = -errno; - fprintf(stderr, "%s migrate failed: %s (%d)\n", - path, strerror(-ret), ret); - goto out; } else if (param->fp_verbose & VERBOSE_DETAIL) { - fprintf(stdout, "migrate %s to MDT%d\n", - path, param->fp_mdt_index); + llapi_printf(LLAPI_MSG_NORMAL, + "migrate %s to MDT%d stripe count %d\n", + path, lmu->lum_stripe_offset, + lmu->lum_stripe_count); } out: @@ -4318,9 +5036,41 @@ out: return ret; } +/* dir migration finished, shrink its stripes */ +static int cb_migrate_mdt_fini(char *path, DIR *parent, DIR **dirp, void *data, + struct dirent64 *de) +{ + struct find_param *param = data; + struct lmv_user_md *lmu = param->fp_lmv_md; + int lmulen = lmv_user_md_size(lmu->lum_stripe_count, lmu->lum_magic); + int ret = 0; + + if (de && de->d_type != DT_DIR) + goto out; + + if (*dirp) { + /* + * close it before setxattr because the latter may destroy the + * original object, and cause close fail. + */ + ret = closedir(*dirp); + *dirp = NULL; + if (ret) + goto out; + } + + ret = setxattr(path, XATTR_NAME_LMV, lmu, lmulen, 0); + if (ret == -EALREADY) + ret = 0; +out: + cb_common_fini(path, parent, dirp, data, de); + return ret; +} + int llapi_migrate_mdt(char *path, struct find_param *param) { - return param_callback(path, cb_migrate_mdt_init, cb_common_fini, param); + return param_callback(path, cb_migrate_mdt_init, cb_migrate_mdt_fini, + param); } int llapi_mv(char *path, struct find_param *param) @@ -4435,26 +5185,14 @@ static int cb_getstripe(char *path, DIR *parent, DIR **dirp, void *data, return ret; } - if (d) { - if (param->fp_get_lmv || param->fp_get_default_lmv) { - ret = cb_get_dirstripe(path, d, param); - } else { - ret = ioctl(dirfd(d), LL_IOC_LOV_GETSTRIPE, - (void *)¶m->fp_lmd->lmd_lmm); - } - - } else if (parent && !param->fp_get_lmv && !param->fp_get_default_lmv) { - char *fname = strrchr(path, '/'); - fname = (fname == NULL ? path : fname + 1); - - strlcpy((char *)¶m->fp_lmd->lmd_lmm, fname, - param->fp_lum_size); - - ret = ioctl(dirfd(parent), IOC_MDC_GETFILESTRIPE, - (void *)¶m->fp_lmd->lmd_lmm); - } else { + 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 return 0; - } if (ret) { if (errno == ENODATA && d != NULL) { @@ -4469,7 +5207,7 @@ static int cb_getstripe(char *path, DIR *parent, DIR **dirp, void *data, lum->lum_magic = LMV_USER_MAGIC; lum->lum_stripe_count = 0; - lum->lum_stripe_offset = -1; + lum->lum_stripe_offset = LMV_OFFSET_DEFAULT; goto dump; } else if (param->fp_get_lmv) { struct lmv_user_md *lum = param->fp_lmv_md; @@ -4560,7 +5298,7 @@ int llapi_obd_fstatfs(int fd, __u32 type, __u32 index, data.ioc_pbuf2 = (char *)uuid_buf; data.ioc_plen2 = sizeof(struct obd_uuid); - rc = obd_ioctl_pack(&data, &rawbuf, sizeof(raw)); + rc = llapi_ioctl_pack(&data, &rawbuf, sizeof(raw)); if (rc != 0) { llapi_error(LLAPI_MSG_ERROR, rc, "llapi_obd_statfs: error packing ioctl data"); @@ -4599,26 +5337,32 @@ int llapi_obd_statfs(char *path, __u32 type, __u32 index, int llapi_ping(char *obd_type, char *obd_name) { + int flags = O_RDONLY; + char buf[1] = { 0 }; glob_t path; - char buf[1]; int rc, fd; rc = cfs_get_param_paths(&path, "%s/%s/ping", obd_type, obd_name); if (rc != 0) return -errno; - - fd = open(path.gl_pathv[0], O_WRONLY); +retry_open: + fd = open(path.gl_pathv[0], flags); if (fd < 0) { + if (errno == EACCES && flags == O_RDONLY) { + flags = O_WRONLY; + goto retry_open; + } rc = -errno; llapi_error(LLAPI_MSG_ERROR, rc, "error opening %s", path.gl_pathv[0]); goto failed; } - /* The purpose is to send a byte as a ping, whatever this byte is. */ - /* coverity[uninit_use_in_call] */ - rc = write(fd, buf, 1); + if (flags == O_RDONLY) + rc = read(fd, buf, sizeof(buf)); + else + rc = write(fd, buf, sizeof(buf)); if (rc < 0) rc = -errno; close(fd); @@ -4633,52 +5377,66 @@ failed: int llapi_target_iterate(int type_num, char **obd_type, void *args, llapi_cb_t cb) { - char buf[MAX_STRING_SIZE]; int i, rc = 0; glob_t param; FILE *fp; - rc = cfs_get_param_paths(¶m, "devices"); - if (rc != 0) - return -ENOENT; + for (i = 0; i < type_num; i++) { + int j; - fp = fopen(param.gl_pathv[0], "r"); - if (fp == NULL) { - rc = -errno; - llapi_error(LLAPI_MSG_ERROR, rc, "error: opening '%s'", - param.gl_pathv[0]); - goto free_path; - } + rc = cfs_get_param_paths(¶m, "%s/*/uuid", obd_type[i]); + if (rc != 0) + continue; + + for (j = 0; j < param.gl_pathc; j++) { + char obd_uuid[UUID_MAX + 1]; + char *obd_name; + char *ptr; - while (fgets(buf, sizeof(buf), fp) != NULL) { - char *obd_type_name = NULL; - char *obd_name = NULL; - char *obd_uuid = NULL; - char *bufp = buf; - struct obd_statfs osfs_buffer; + fp = fopen(param.gl_pathv[j], "r"); + if (fp == NULL) { + rc = -errno; + llapi_error(LLAPI_MSG_ERROR, rc, + "error: opening '%s'", + param.gl_pathv[j]); + goto free_path; + } - while(bufp[0] == ' ') - ++bufp; + if (fgets(obd_uuid, sizeof(obd_uuid), fp) == NULL) { + rc = -errno; + llapi_error(LLAPI_MSG_ERROR, rc, + "error: reading '%s'", + param.gl_pathv[j]); + goto free_path; + } - for(i = 0; i < 3; i++) { - obd_type_name = strsep(&bufp, " "); - } - obd_name = strsep(&bufp, " "); - obd_uuid = strsep(&bufp, " "); + /* Extract the obd_name from the sysfs path. + * 'topsysfs'/fs/lustre/'obd_type'/'obd_name'. + */ + obd_name = strstr(param.gl_pathv[j], "/fs/lustre/"); + if (!obd_name) { + rc = -EINVAL; + goto free_path; + } - memset(&osfs_buffer, 0, sizeof (osfs_buffer)); + /* skip /fs/lustre/'obd_type'/ */ + obd_name += strlen(obd_type[i]) + 12; + /* chop off after obd_name */ + ptr = strrchr(obd_name, '/'); + if (ptr) + *ptr = '\0'; - for (i = 0; i < type_num; i++) { - if (strcmp(obd_type_name, obd_type[i]) != 0) - continue; + cb(obd_type[i], obd_name, obd_uuid, args); - cb(obd_type_name, obd_name, obd_uuid, args); - } + fclose(fp); + fp = NULL; + } } - fclose(fp); free_path: + if (fp) + fclose(fp); cfs_free_param_data(¶m); - return 0; + return rc; } static void do_target_check(char *obd_type_name, char *obd_name, @@ -4706,7 +5464,7 @@ int llapi_target_check(int type_num, char **obd_type, char *dir) /* Is this a lustre fs? */ int llapi_is_lustre_mnttype(const char *type) { - return (strcmp(type, "lustre") == 0 || strcmp(type,"lustre_lite") == 0); + return strcmp(type, "lustre") == 0 || strcmp(type, "lustre_tgt") == 0; } /* Is this a lustre client fs? */ @@ -5038,6 +5796,20 @@ int llapi_get_data_version(int fd, __u64 *data_version, __u64 flags) return rc; } +/** + * Flush cached pages from all clients. + * + * \param fd File descriptor + * \retval 0 success + * \retval < 0 error + */ +int llapi_file_flush(int fd) +{ + __u64 dv; + + 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 @@ -5060,75 +5832,120 @@ int llapi_get_ost_layout_version(int fd, __u32 *layout_version) } /* - * Create a file without any name open it for read/write + * 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 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. + * - file is destroyed at final close * * \param[in] directory directory from which to inherit layout/MDT idx - * \param[in] idx MDT index on which the file is created, + * \param[in] mdt_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 + * \param[in] mode standard open(2) mode + * \param[in] stripe_param stripe parameters. May be NULL. * - * \retval 0 on success. + * \retval a file descriptor on success. * \retval -errno on error. */ -int llapi_create_volatile_idx(char *directory, int idx, int open_flags) +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]; - char filename[PATH_MAX]; - int saved_errno = errno; - int fd; - int rnumber; - int rc; + char file_path[PATH_MAX]; + int saved_errno = errno; + int fd; + unsigned int rnumber; + int rc; do { rnumber = random(); - if (idx == -1) - snprintf(filename, sizeof(filename), - LUSTRE_VOLATILE_HDR"::%.4X", rnumber); + if (mdt_idx == -1) + rc = snprintf(file_path, sizeof(file_path), + "%s/" LUSTRE_VOLATILE_HDR "::%.4X", + directory, rnumber); else - snprintf(filename, sizeof(filename), - LUSTRE_VOLATILE_HDR":%.4X:%.4X", idx, rnumber); + 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); - rc = snprintf(file_path, sizeof(file_path), - "%s/%s", directory, filename); - if (rc >= sizeof(file_path)) - return -E2BIG; + open_flags |= O_CREAT | O_EXCL | O_NOFOLLOW; - fd = open(file_path, - O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW | open_flags, - S_IRUSR | S_IWUSR); - } while (fd < 0 && errno == EEXIST); + 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, errno, + llapi_error(LLAPI_MSG_ERROR, rc, "Cannot create volatile file '%s' in '%s'", - filename + LUSTRE_VOLATILE_HDR_LEN, + file_path + strlen(directory) + 1 + + LUSTRE_VOLATILE_HDR_LEN, directory); - return -errno; + 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. */ + /* + * 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(). */ + /* + * 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 @@ -5265,7 +6082,7 @@ int llapi_open_by_fid(const char *lustre_dir, const struct lu_fid *fid, int flags) { char mntdir[PATH_MAX]; - char path[PATH_MAX]; + char path[PATH_MAX + 64]; int rc; rc = llapi_search_mounts(lustre_dir, 0, mntdir, NULL);