}
/**
+ * Check if the given \a lum_size is large enough to hold the required
+ * fields in \a lum.
+ *
+ * \param[in] lum the struct lov_user_md to check
+ * \param[in] lum_size the number of bytes in \a lum
+ *
+ * \retval true the \a lum_size is too small
+ * \retval false the \a lum_size is large enough
+ */
+static bool llapi_layout_lum_truncated(struct lov_user_md *lum, size_t lum_size)
+{
+ uint32_t magic;
+
+ if (lum_size < sizeof(lum->lmm_magic))
+ return true;
+
+ if (lum->lmm_magic == LOV_MAGIC_V1 ||
+ lum->lmm_magic == __swab32(LOV_MAGIC_V1))
+ magic = LOV_MAGIC_V1;
+ else if (lum->lmm_magic == LOV_MAGIC_V3 ||
+ lum->lmm_magic == __swab32(LOV_MAGIC_V3))
+ magic = LOV_MAGIC_V3;
+ else if (lum->lmm_magic == LOV_MAGIC_COMP_V1 ||
+ lum->lmm_magic == __swab32(LOV_MAGIC_COMP_V1))
+ magic = LOV_MAGIC_COMP_V1;
+ else
+ return true;
+
+ if (magic == LOV_MAGIC_V1 || magic == LOV_MAGIC_V3)
+ return lum_size < lov_user_md_size(0, magic);
+ else
+ return lum_size < sizeof(struct lov_comp_md_v1);
+}
+
+/* Verify if the objects count in lum is consistent with the
+ * stripe count in lum. It applies to regular file only. */
+static bool llapi_layout_lum_valid(struct lov_user_md *lum, int lum_size)
+{
+ struct lov_comp_md_v1 *comp_v1 = NULL;
+ int i, ent_count, obj_count;
+
+ if (lum->lmm_magic == LOV_MAGIC_COMP_V1) {
+ comp_v1 = (struct lov_comp_md_v1 *)lum;
+ ent_count = comp_v1->lcm_entry_count;
+ } else if (lum->lmm_magic == LOV_MAGIC_V1 ||
+ lum->lmm_magic == LOV_MAGIC_V3) {
+ ent_count = 1;
+ } else {
+ return false;
+ }
+
+ for (i = 0; i < ent_count; i++) {
+ if (comp_v1) {
+ lum = (struct lov_user_md *)((char *)comp_v1 +
+ comp_v1->lcm_entries[i].lcme_offset);
+ lum_size = comp_v1->lcm_entries[i].lcme_size;
+ }
+ obj_count = llapi_layout_objects_in_lum(lum, lum_size);
+
+ if (comp_v1) {
+ if (!(comp_v1->lcm_entries[i].lcme_flags &
+ LCME_FL_INIT) && obj_count != 0)
+ return false;
+ } else if (obj_count != lum->lmm_stripe_count) {
+ return false;
+ }
+ }
+ return true;
+}
+
+/**
* Convert the data from a lov_user_md to a newly allocated llapi_layout.
* The caller is responsible for freeing the returned pointer.
*
- * \param[in] lum LOV user metadata structure to copy data from
- * \param[in] lum_size size the the lum passed in
+ * \param[in] lov_xattr LOV user metadata xattr to copy data from
+ * \param[in] lov_xattr_size size the lov_xattr_size passed in
+ * \param[in] flags bitwise-or'd flags to control the behavior
*
* \retval valid llapi_layout pointer on success
* \retval NULL if memory allocation fails
*/
-static struct llapi_layout *
-llapi_layout_from_lum(const struct lov_user_md *lum, int lum_size)
+struct llapi_layout *llapi_layout_get_by_xattr(void *lov_xattr,
+ ssize_t lov_xattr_size,
+ uint32_t flags)
{
+ struct lov_user_md *lum = lov_xattr;
struct lov_comp_md_v1 *comp_v1 = NULL;
struct lov_comp_md_entry_v1 *ent;
struct lov_user_md *v1;
- struct llapi_layout *layout;
+ struct llapi_layout *layout = NULL;
struct llapi_layout_comp *comp;
int i, ent_count = 0, obj_count;
- layout = __llapi_layout_alloc();
- if (layout == NULL)
+ if (lov_xattr == NULL || lov_xattr_size <= 0) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ /* Return an error if we got back a partial layout. */
+ if (llapi_layout_lum_truncated(lov_xattr, lov_xattr_size)) {
+ errno = ERANGE;
return NULL;
+ }
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+ if (flags & LLAPI_LXF_COPY) {
+ lum = malloc(lov_xattr_size);
+ if (lum == NULL) {
+ errno = ENOMEM;
+ return NULL;
+ }
+ memcpy(lum, lov_xattr, lov_xattr_size);
+ }
+#endif
+
+ llapi_layout_swab_lov_user_md(lum, lov_xattr_size);
+
+ if ((flags & LLAPI_LXF_CHECK) &&
+ !llapi_layout_lum_valid(lum, lov_xattr_size)) {
+ errno = EBADSLT;
+ goto out;
+ }
+
+ layout = __llapi_layout_alloc();
+ if (layout == NULL) {
+ errno = ENOMEM;
+ goto out;
+ }
if (lum->lmm_magic == LOV_MAGIC_COMP_V1) {
comp_v1 = (struct lov_comp_md_v1 *)lum;
lum->lmm_magic == LOV_MAGIC_V3) {
ent_count = 1;
layout->llot_is_composite = false;
+
+ if (lov_xattr_size <= 0) {
+ errno = EINVAL;
+ goto out_layout;
+ }
+ } else {
+ errno = EOPNOTSUPP;
+ goto out_layout;
}
if (ent_count == 0) {
errno = EINVAL;
- goto error;
+ goto out_layout;
}
v1 = (struct lov_user_md *)lum;
ent = &comp_v1->lcm_entries[i];
v1 = (struct lov_user_md *)((char *)comp_v1 +
ent->lcme_offset);
- lum_size = ent->lcme_size;
+ lov_xattr_size = ent->lcme_size;
} else {
ent = NULL;
}
- obj_count = llapi_layout_objects_in_lum(v1, lum_size);
+ obj_count = llapi_layout_objects_in_lum(v1, lov_xattr_size);
comp = __llapi_comp_alloc(obj_count);
if (comp == NULL)
- goto error;
+ goto out_layout;
if (ent != NULL) {
comp->llc_extent.e_start = ent->lcme_extent.e_start;
if (v1->lmm_pattern == LOV_PATTERN_RAID0)
comp->llc_pattern = LLAPI_LAYOUT_RAID0;
+ else if (v1->lmm_pattern == LOV_PATTERN_MDT)
+ comp->llc_pattern = LLAPI_LAYOUT_MDT;
else
- /* Lustre only supports RAID0 for now. */
+ /* Lustre only supports RAID0 and DoM for now. */
comp->llc_pattern = v1->lmm_pattern;
if (v1->lmm_stripe_size == 0)
layout->llot_cur_comp = comp;
}
+out:
+ if (lum != lov_xattr)
+ free(lum);
return layout;
-error:
+out_layout:
llapi_layout_free(layout);
- return NULL;
+ layout = NULL;
+ goto out;
}
/**
{
char *p;
- strncpy(buf, path, size);
+ strncpy(buf, path, size - 1);
p = strrchr(buf, '/');
if (p != NULL) {
}
/**
- * Check if the given \a lum_size is large enough to hold the required
- * fields in \a lum.
- *
- * \param[in] lum the struct lov_user_md to check
- * \param[in] lum_size the number of bytes in \a lum
- *
- * \retval true the \a lum_size is too small
- * \retval false the \a lum_size is large enough
- */
-static bool llapi_layout_lum_truncated(struct lov_user_md *lum, size_t lum_size)
-{
- uint32_t magic;
-
- if (lum_size < sizeof(lum->lmm_magic))
- return true;
-
- if (lum->lmm_magic == LOV_MAGIC_V1 ||
- lum->lmm_magic == __swab32(LOV_MAGIC_V1))
- magic = LOV_MAGIC_V1;
- else if (lum->lmm_magic == LOV_MAGIC_V3 ||
- lum->lmm_magic == __swab32(LOV_MAGIC_V3))
- magic = LOV_MAGIC_V3;
- else if (lum->lmm_magic == LOV_MAGIC_COMP_V1 ||
- lum->lmm_magic == __swab32(LOV_MAGIC_COMP_V1))
- magic = LOV_MAGIC_COMP_V1;
- else
- return true;
-
- if (magic == LOV_MAGIC_V1 || magic == LOV_MAGIC_V3)
- return lum_size < lov_user_md_size(0, magic);
- else
- return lum_size < sizeof(struct lov_comp_md_v1);
-}
-
-/* Verify if the objects count in lum is consistent with the
- * stripe count in lum. It applies to regular file only. */
-static bool llapi_layout_lum_valid(struct lov_user_md *lum, int lum_size)
-{
- struct lov_comp_md_v1 *comp_v1 = NULL;
- int i, ent_count, obj_count;
-
- if (lum->lmm_magic == LOV_MAGIC_COMP_V1) {
- comp_v1 = (struct lov_comp_md_v1 *)lum;
- ent_count = comp_v1->lcm_entry_count;
- } else if (lum->lmm_magic == LOV_MAGIC_V1 ||
- lum->lmm_magic == LOV_MAGIC_V3) {
- ent_count = 1;
- } else {
- return false;
- }
-
- for (i = 0; i < ent_count; i++) {
- if (comp_v1) {
- lum = (struct lov_user_md *)((char *)comp_v1 +
- comp_v1->lcm_entries[i].lcme_offset);
- lum_size = comp_v1->lcm_entries[i].lcme_size;
- }
- obj_count = llapi_layout_objects_in_lum(lum, lum_size);
-
- if (comp_v1) {
- if (!(comp_v1->lcm_entries[i].lcme_flags &
- LCME_FL_INIT) && obj_count != 0)
- return false;
- } else if (obj_count != lum->lmm_stripe_count) {
- return false;
- }
- }
- return true;
-}
-
-/**
* Get the striping layout for the file referenced by file descriptor \a fd.
*
* If the filesystem does not support the "lustre." xattr namespace, the
goto out;
}
- /* Return an error if we got back a partial layout. */
- if (llapi_layout_lum_truncated(lum, bytes_read)) {
- errno = EINTR;
- goto out;
- }
-
- llapi_layout_swab_lov_user_md(lum, bytes_read);
-
/* Directories may have a positive non-zero lum->lmm_stripe_count
* yet have an empty lum->lmm_objects array. For non-directories the
* amount of data returned from the kernel must be consistent
if (fstat(fd, &st) < 0)
goto out;
- if (!S_ISDIR(st.st_mode) && !llapi_layout_lum_valid(lum, bytes_read)) {
- errno = EINTR;
- goto out;
- }
-
- layout = llapi_layout_from_lum(lum, bytes_read);
+ layout = llapi_layout_get_by_xattr(lum, bytes_read,
+ S_ISDIR(st.st_mode) ? 0 : LLAPI_LXF_CHECK);
out:
free(lum);
return layout;
struct llapi_resync_comp *comp_array,
int comp_size, uint64_t start, uint64_t end)
{
- size_t count;
+ uint64_t count;
size_t page_size = sysconf(_SC_PAGESIZE);
const size_t buflen = 4 << 20; /* 4M */
void *buf;
uint64_t pos = start;
int i;
int rc;
+ int rc2 = 0;
rc = posix_memalign(&buf, page_size, buflen);
if (rc)
while (count > 0) {
uint32_t src;
uint64_t mirror_end = 0;
+ uint64_t bytes_left;
ssize_t bytes_read;
size_t to_read;
size_t to_write;
return -ENOENT;
if (mirror_end == OBD_OBJECT_EOF) {
- to_read = count;
+ bytes_left = count;
} else {
- to_read = MIN(count, mirror_end - pos);
- to_read = (to_read + page_size - 1) & ~(page_size - 1);
+ bytes_left = MIN(count, mirror_end - pos);
+ bytes_left = ((bytes_left - 1) | (page_size - 1)) + 1;
}
- to_read = MIN(buflen, to_read);
+ to_read = MIN(buflen, bytes_left);
bytes_read = llapi_mirror_read(fd, src, buf, to_read, pos);
if (bytes_read == 0) {
}
/* round up to page align to make direct IO happy. */
- to_write = (bytes_read + page_size - 1) & ~(page_size - 1);
+ to_write = ((bytes_read - 1) | (page_size - 1)) + 1;
for (i = 0; i < comp_size; i++) {
ssize_t written;
* meanings.
*/
comp_array[i].lrc_synced = true;
+ llapi_error(LLAPI_MSG_ERROR, written,
+ "component %u not synced\n",
+ comp_array[i].lrc_id);
+ if (rc2 == 0)
+ rc2 = (int)written;
continue;
}
assert(written == to_write2);
free(buf);
if (rc < 0) {
+ /* fatal error happens */
for (i = 0; i < comp_size; i++)
comp_array[i].lrc_synced = false;
return rc;
}
+ /**
+ * no fatal error happens, each lrc_synced tells whether the component
+ * has been resync successfully (note: we'd reverse the value to
+ * reflect its true meaning.
+ */
for (i = 0; i < comp_size; i++) {
comp_array[i].lrc_synced = !comp_array[i].lrc_synced;
if (comp_array[i].lrc_synced && pos & (page_size - 1)) {
}
}
- /* partially successful is successful */
+ /**
+ * returns the first error code for partially successful resync if
+ * possible.
+ */
+ return rc2;
+}
+
+int lov_comp_md_size(struct lov_comp_md_v1 *lcm)
+{
+ if (lcm->lcm_magic == LOV_MAGIC_V1 || lcm->lcm_magic == LOV_MAGIC_V3) {
+ struct lov_user_md *lum = (void *)lcm;
+
+ return lov_user_md_size(lum->lmm_stripe_count, lum->lmm_magic);
+ }
+
+ if (lcm->lcm_magic != LOV_MAGIC_COMP_V1)
+ return -EOPNOTSUPP;
+
+ return lcm->lcm_size;
+}
+
+int llapi_get_lum_file_fd(int dir_fd, const char *fname, __u64 *valid,
+ lstatx_t *statx, struct lov_user_md *lum,
+ size_t lumsize)
+{
+ struct lov_user_mds_data *lmd;
+ char buf[65536 + offsetof(typeof(*lmd), lmd_lmm)];
+ int parent_fd = -1;
+ int rc;
+
+ if (lum && lumsize < sizeof(*lum))
+ return -EINVAL;
+
+ /* If a file name is provided, it is relative to the parent directory */
+ if (fname) {
+ parent_fd = dir_fd;
+ dir_fd = -1;
+ }
+
+ lmd = (struct lov_user_mds_data *)buf;
+ rc = get_lmd_info_fd(fname, parent_fd, dir_fd, buf, sizeof(buf),
+ GET_LMD_INFO);
+ if (rc)
+ return rc;
+
+ *valid = lmd->lmd_flags;
+ if (statx)
+ memcpy(statx, &lmd->lmd_stx, sizeof(*statx));
+
+ if (lum) {
+ if (lmd->lmd_lmmsize > lumsize)
+ return -EOVERFLOW;
+ memcpy(lum, &lmd->lmd_lmm, lmd->lmd_lmmsize);
+ }
+
return 0;
}
+
+int llapi_get_lum_dir_fd(int dir_fd, __u64 *valid, lstatx_t *statx,
+ struct lov_user_md *lum, size_t lumsize)
+{
+ return llapi_get_lum_file_fd(dir_fd, NULL, valid, statx, lum, lumsize);
+}
+
+int llapi_get_lum_file(const char *path, __u64 *valid, lstatx_t *statx,
+ struct lov_user_md *lum, size_t lumsize)
+{
+ char parent[PATH_MAX];
+ const char *fname;
+ char *tmp;
+ int offset;
+ int dir_fd;
+ int rc;
+
+ tmp = strrchr(path, '/');
+ if (!tmp) {
+ strncpy(parent, ".", sizeof(parent) - 1);
+ offset = -1;
+ } else {
+ strncpy(parent, path, tmp - path);
+ offset = tmp - path - 1;
+ parent[tmp - path] = 0;
+ }
+
+ fname = path;
+ if (offset >= 0)
+ fname += offset + 2;
+
+ dir_fd = open(parent, O_RDONLY);
+ if (dir_fd < 0) {
+ rc = -errno;
+ llapi_error(LLAPI_MSG_ERROR, rc, "cannot open '%s'", path);
+ return rc;
+ }
+
+ rc = llapi_get_lum_file_fd(dir_fd, fname, valid, statx, lum, lumsize);
+ close(dir_fd);
+ return rc;
+}
+
+int llapi_get_lum_dir(const char *path, __u64 *valid, lstatx_t *statx,
+ struct lov_user_md *lum, size_t lumsize)
+{
+ int dir_fd;
+ int rc;
+
+ dir_fd = open(path, O_RDONLY);
+ if (dir_fd < 0) {
+ rc = -errno;
+ llapi_error(LLAPI_MSG_ERROR, rc, "cannot open '%s'", path);
+ return rc;
+ }
+
+ rc = llapi_get_lum_dir_fd(dir_fd, valid, statx, lum, lumsize);
+ close(dir_fd);
+ return rc;
+}