.br
Create a new composite
.I file
-with one or more component layouts, or set or replace the default file layout
-on an existing
-.IR directory .
+with one or more component layouts (where \fIend\fR marks the end of the
+current component), or set or replace the default file layout on an existing
+.IR directory.
.TP
.B lfs setstripe --component-add -E \fIend1\fR [\fISTRIPE_OPTIONS\fR] \
... <\fIfile\fR>
to add more components to the end of the file.
.RE
.TP
+.B -z, --extension-size, ext-size\fR <\fIext_size\fR>
+This option modifies the \fB-E\fR option, components which have this
+option specified are created as pairs of components, extendable and
+extension ones.
+.PP
+.RS
+The extendable component starts at offset 0 if this is the first
+component of the file. In this case it ends at offset \fIext_size\fR and
+it gets the flag \fBinit\fR (initialized). The extendable component starts
+at the end of the previous component if this is not the first component of
+the file. In this case it ends at the same offset (0-length component).
+.PP
+The extension component covers the rest of the specified region up to
+the \fIend\fR specified by \fB-E\fR option and gets the flag \fBextension\fR.
+This component covers the space reserved for the extendable component but
+not used immediately, the later extension of the extendable component is done
+by \fIext_size\fR each time until the extension component is used up. This is
+used to control the space on OSTs the stripe is located on, in case one of
+them is low on space, the remaining extension component region is added to the
+next component.
+.RE
+.TP
.B --component-add
Add components to the end an existing composite file. It is not possible
to add components incrementally to the default directory layout, since the
covers [0, 4MiB), the second component has 4 stripes and covers [4MiB, 64MiB),
the last component stripes over all available OSTs and covers [64MiB, EOF).
.TP
+.B lfs setstripe -E -1 -z 64M /mnt/lustre/file1
+This creates a file with a composite layout, the component one covers [0, 64MiB)
+and the second component the rest [64MiB, EOF) originally. Once written beyond
+64MiB the component one is extended to [0, 128MiB), once written beyond 128MiB
+it is extended to [0, 192MiB), etc; the second component is shortened
+appropriately.
+.PP
+.RS
+When one of the OSTs of the first component layout is low on space, e.g. while
+writing beyond 192MiB, the first component is left as [0, 192MiB), and a new
+component is allocated between them, its layout repeats the first component
+layout but initialized on different OSTs so that the full OSTs are avoided.
+It is allocated and immediately extended to [192MiB, 256MiB), the following
+extension component is shortended again.
+.RE
+.TP
+.B lfs setstripe -E 1G -z 64M -E 100G -z 256M -E -1 -z 1G /mnt/lustre/file1
+This creates a file with a composite layout, the component one covers [0,
+64MiB), the third component covers [1G, 1G), the fifth component covers
+[100GiB, 100GiB) originally. The second, fourth and sixth extension components
+cover the left space accordingly. The process of writing is similar to above,
+but when one of the OSTs of the first component layout is low on space, e.g.
+while writing beyond 192MiB in the example above, the first component is left
+as [0, 192MiB), the second (extension) component is removed, and its range
+spills over to the third and the fourth components - they are moved left to
+start at 192MiB instead of 100GiB; the third component is immediately extended
+and becomes [192MiB, 448MiB), the fourth (the extension one) component becomes
+[448MiB, 100GiB).
+.TP
.B lfs setstripe --component-add -E eof -c 4 /mnt/lustre/file1
This add a component which starts at the end of last existing component to
the end of file.
--- /dev/null
+.TH llapi_layout_extension_size_get 3 "2019 May 23" "Lustre User API"
+.SH NAME
+llapi_layout_extension_size_get, llapi_layout_extension_size_set \- get or set
+the extension size of an extension component of a Lustre file
+.SH SYNOPSIS
+.nf
+.B #include <lustre/lustreapi.h>
+.PP
+.BI "int llapi_layout_extension_size_get(const struct llapi_layout *" layout ",
+.BI " uint64_t *" ext_size );
+.PP
+.BI "int llapi_layout_extension_size_set(struct llapi_layout *" layout ",
+.BI " uint64_t " ext_size );
+.fi
+.SH DESCRIPTION
+.PP
+The extension size is the unit of increasing the previous component size when
+writing within the region of the current extension component. At the time of the
+change the OSTs of the previous component layout are checked if they have
+at least \fIext_size\fR free space. In case there is no enough free space,
+the space covered by the extension component spills over to the next component
+(see examples in \fBlfs-setstripe (1)\fR).
+.PP
+In case of a random write to a middle of the extension component, the extension
+happens from the beginning of the extension component up to the current writing
+position plus the \fIext_size\fR. However, the check for low space is still
+done for the \fIext_size\fR.
+.PP
+.B llapi_layout_extension_size_get()
+stores into
+.I ext_size
+the extension size of
+.IR layout .
+.PP
+.B llapi_layout_extension_size_get()
+sets the extension size of
+.I layout
+to
+.IR ext_size .
+.SH RETURN VALUES
+.B llapi_layout_extension_size_get()
+and
+.B llapi_layout_extension_size_set()
+return 0 on success, or -1 if an error occurred (in which case, errno is
+set appropriately).
+.SH ERRORS
+.TP 15
+.SM EINVAL
+An invalid argument was specified.
+.SH "SEE ALSO"
+.BR lfs-setstripe (1),
+.BR llapi_layout_alloc (3),
+.BR llapi_layout_file_open (3),
+.BR llapi_layout_stripe_size_set (3),
+.BR llapi_layout_stripe_size_get (3),
+.BR llapi_layout (7),
+.BR lustreapi (7)
--- /dev/null
+.so man3/llapi_layout_extension_size_get.3
.SH "SEE ALSO"
.BR llapi_layout_alloc (3),
.BR llapi_layout_file_open (3),
+.BR llapi_layout_extension_size_set (3),
+.BR llapi_layout_extension_size_get (3),
.BR llapi_layout (7),
.BR lustreapi (7)
*/
int llapi_layout_stripe_size_set(struct llapi_layout *layout, uint64_t size);
+
+/******************** Extension Size ********************/
+
+/**
+ * Store the extension size of \a layout in \a size.
+ *
+ * \retval 0 Success.
+ * \retval -1 Invalid argument, errno set to EINVAL.
+ */
+int llapi_layout_extension_size_get(const struct llapi_layout *layout,
+ uint64_t *size);
+
+/**
+ * Set the extension size of \a layout to \a stripe_size.
+ *
+ * \retval 0 Success.
+ * \retval -1 Invalid argument, errno set to EINVAL.
+ */
+int llapi_layout_extension_size_set(struct llapi_layout *layout, uint64_t size);
+
+
/******************** Stripe Pattern ********************/
/**
{ LCME_FL_PREF_RW, "prefer" },
{ LCME_FL_OFFLINE, "offline" },
{ LCME_FL_NOSYNC, "nosync" },
+ { LCME_FL_EXTENSION, "extension" },
};
/**
(le32_to_cpu(((struct lov_foreign_md *)lfm)->lfm_length) + \
offsetof(struct lov_foreign_md, lfm_value))
+/**
+ * The stripe size fields are shared for the extension size storage, however
+ * the extension size is stored in KB, not bytes.
+ */
+#define SEL_UNIT_SIZE 1024llu
+
struct lu_extent {
__u64 e_start;
__u64 e_end;
}
enum lov_comp_md_entry_flags {
- LCME_FL_STALE = 0x00000001, /* FLR: stale data */
- LCME_FL_PREF_RD = 0x00000002, /* FLR: preferred for reading */
- LCME_FL_PREF_WR = 0x00000004, /* FLR: preferred for writing */
- LCME_FL_PREF_RW = LCME_FL_PREF_RD | LCME_FL_PREF_WR,
- LCME_FL_OFFLINE = 0x00000008, /* Not used */
- LCME_FL_INIT = 0x00000010, /* instantiated */
- LCME_FL_NOSYNC = 0x00000020, /* FLR: no sync for the mirror */
- LCME_FL_NEG = 0x80000000 /* used to indicate a negative flag,
- won't be stored on disk */
+ LCME_FL_STALE = 0x00000001, /* FLR: stale data */
+ LCME_FL_PREF_RD = 0x00000002, /* FLR: preferred for reading */
+ LCME_FL_PREF_WR = 0x00000004, /* FLR: preferred for writing */
+ LCME_FL_PREF_RW = LCME_FL_PREF_RD | LCME_FL_PREF_WR,
+ LCME_FL_OFFLINE = 0x00000008, /* Not used */
+ LCME_FL_INIT = 0x00000010, /* instantiated */
+ LCME_FL_NOSYNC = 0x00000020, /* FLR: no sync for the mirror */
+ LCME_FL_EXTENSION = 0x00000040, /* extension comp, never init */
+ LCME_FL_NEG = 0x80000000 /* used to indicate a negative flag,
+ * won't be stored on disk
+ */
};
#define LCME_KNOWN_FLAGS (LCME_FL_NEG | LCME_FL_INIT | LCME_FL_STALE | \
- LCME_FL_PREF_RW | LCME_FL_NOSYNC)
-/* The flags can be set by users at mirror creation time. */
-#define LCME_USER_FLAGS (LCME_FL_PREF_RW)
+ LCME_FL_PREF_RW | LCME_FL_NOSYNC | \
+ LCME_FL_EXTENSION)
+
+/* The mirror flags can be set by users at creation time. */
+#define LCME_USER_MIRROR_FLAGS (LCME_FL_PREF_RW)
+
+/* The allowed flags obtained from the client at component creation time. */
+#define LCME_CL_COMP_FLAGS (LCME_USER_MIRROR_FLAGS | LCME_FL_EXTENSION)
-/* The flags are for mirrors */
+/* The mirror flags sent by client */
#define LCME_MIRROR_FLAGS (LCME_FL_NOSYNC)
/* These flags have meaning when set in a default layout and will be inherited
* from the default/template layout set on a directory.
*/
-#define LCME_TEMPLATE_FLAGS (LCME_FL_PREF_RW | LCME_FL_NOSYNC)
+#define LCME_TEMPLATE_FLAGS (LCME_FL_PREF_RW | LCME_FL_NOSYNC | \
+ LCME_FL_EXTENSION)
/* the highest bit in obdo::o_layout_version is used to mark if the file is
* being resynced. */
lod_comp->llc_extent = *ext;
lod_comp->llc_flags =
comp_v1->lcm_entries[i].lcme_flags &
- LCME_USER_FLAGS;
+ LCME_CL_COMP_FLAGS;
}
pool_name = NULL;
if ((flags && comp_id) || (!flags && !comp_id))
return -EINVAL;
- /* LCME_FL_INIT is the only supported flag in PFL */
if (flags) {
if (flags & ~LCME_KNOWN_FLAGS) {
fprintf(stderr,
struct lfs_setstripe_args {
unsigned long long lsa_comp_end;
unsigned long long lsa_stripe_size;
+ unsigned long long lsa_extension_size;
long long lsa_stripe_count;
long long lsa_stripe_off;
__u32 lsa_comp_flags;
unsigned int lsa_mirror_count;
int lsa_nr_tgts;
bool lsa_first_comp;
+ bool lsa_extension_comp;
__u32 *lsa_tgts;
char *lsa_pool_name;
};
{
struct llapi_layout *layout = *composite;
uint64_t prev_end = 0;
+ uint64_t size;
int i = 0, rc;
+new_comp:
if (layout == NULL) {
layout = llapi_layout_alloc();
if (layout == NULL) {
return -ENOMEM;
}
*composite = layout;
+ lsa->lsa_first_comp = true;
} else {
uint64_t start;
return rc;
}
}
- /* reset lsa_first_comp */
- lsa->lsa_first_comp = false;
+
+ rc = llapi_layout_comp_flags_set(layout, lsa->lsa_comp_flags);
+ if (rc) {
+ fprintf(stderr, "Set flags 0x%x failed: %s\n",
+ lsa->lsa_comp_flags, strerror(errno));
+ return rc;
+ }
if (set_extent) {
+ uint64_t comp_end = lsa->lsa_comp_end;
+
+ /* Extension space handling:
+ * If this is the first component, length is extension_size.
+ * If not, it is zero length, so it can be removed if there is
+ * insufficient space to extend it.
+ */
+ if (lsa->lsa_extension_comp && lsa->lsa_first_comp)
+ comp_end = prev_end + lsa->lsa_extension_size;
+ else if (lsa->lsa_extension_comp)
+ comp_end = prev_end;
+
rc = llapi_layout_comp_extent_set(layout, prev_end,
- lsa->lsa_comp_end);
+ comp_end);
if (rc) {
- fprintf(stderr, "Set extent [%lu, %llu) failed. %s\n",
- prev_end, lsa->lsa_comp_end, strerror(errno));
+ fprintf(stderr, "Set extent [%lu, %lu) failed. %s\n",
+ prev_end, comp_end, strerror(errno));
return rc;
}
}
+ /* reset lsa_first_comp */
+ lsa->lsa_first_comp = false;
/* Data-on-MDT component setting */
if (lsa->lsa_pattern == LLAPI_LAYOUT_MDT) {
}
}
- rc = llapi_layout_stripe_size_set(layout, lsa->lsa_stripe_size);
+ size = lsa->lsa_comp_flags & LCME_FL_EXTENSION ?
+ lsa->lsa_extension_size : lsa->lsa_stripe_size;
+
+ if (lsa->lsa_comp_flags & LCME_FL_EXTENSION)
+ rc = llapi_layout_extension_size_set(layout, size);
+ else
+ rc = llapi_layout_stripe_size_set(layout, size);
+
if (rc) {
- fprintf(stderr, "Set stripe size %llu failed: %s\n",
- lsa->lsa_stripe_size, strerror(errno));
+ fprintf(stderr, "Set stripe size %lu failed: %s\n",
+ size, strerror(errno));
return rc;
}
return rc;
}
- rc = llapi_layout_comp_flags_set(layout, lsa->lsa_comp_flags);
- if (rc) {
- fprintf(stderr, "Set flags 0x%x failed: %s\n",
- lsa->lsa_comp_flags, strerror(errno));
- return rc;
- }
-
if (lsa->lsa_pool_name != NULL) {
rc = llapi_layout_pool_name_set(layout, lsa->lsa_pool_name);
if (rc) {
return rc;
}
+ /* Create the second, virtual component of extension space */
+ if (lsa->lsa_extension_comp) {
+ lsa->lsa_comp_flags |= LCME_FL_EXTENSION;
+ lsa->lsa_extension_comp = false;
+ goto new_comp;
+ }
+
return 0;
}
{ .val = 'v', .name = "verbose", .has_arg = no_argument},
{ .val = 'x', .name = "xattr", .has_arg = required_argument },
{ .val = 'y', .name = "yaml", .has_arg = required_argument },
+ { .val = 'z', .name = "ext-size", .has_arg = required_argument},
+ { .val = 'z', .name = "extension-size", .has_arg = required_argument},
{ .name = NULL } };
setstripe_args_init(&lsa);
snprintf(cmd, sizeof(cmd), "%s %s", progname, argv[0]);
progname = cmd;
while ((c = getopt_long(argc, argv,
- "bc:C:dDE:f:H:i:I:m:N::no:p:L:s:S:vx:y:",
+ "bc:C:dDE:f:H:i:I:m:N::no:p:L:s:S:vx:y:z:",
long_opts, NULL)) >= 0) {
switch (c) {
case 0:
result = -EINVAL;
goto usage_error;
}
- if (last_mirror->m_flags & ~LCME_USER_FLAGS) {
+ if (last_mirror->m_flags & ~LCME_USER_MIRROR_FLAGS) {
fprintf(stderr,
"%s: unsupported mirror flags: %s\n",
progname, optarg);
if (lsa.lsa_comp_end != 0) {
result = comp_args_to_layout(lpp, &lsa, true);
if (result) {
- fprintf(stderr,
- "%s %s: invalid layout\n",
- progname, argv[0]);
+ fprintf(stderr, "%s: invalid layout\n",
+ progname);
goto usage_error;
}
from_yaml = true;
template = optarg;
break;
+ case 'z':
+ result = llapi_parse_size(optarg,
+ &lsa.lsa_extension_size,
+ &size_units, 0);
+ if (result) {
+ fprintf(stderr,
+ "%s %s: invalid extension size '%s'\n",
+ progname, argv[0], optarg);
+ goto usage_error;
+ }
+
+ lsa.lsa_extension_comp = true;
+ break;
default:
fprintf(stderr, "%s %s: unrecognized option '%s'\n",
progname, argv[0], argv[optind - 1]);
if (lsa.lsa_comp_end != 0) {
result = comp_args_to_layout(lpp, &lsa, true);
- if (result)
+ if (result) {
+ fprintf(stderr, "error: %s: invalid layout\n",
+ progname);
+ result = -EINVAL;
goto error;
+ }
}
if (mirror_flags & MF_NO_VERIFY) {
}
}
- /* Only LCME_FL_INIT flags is used in PFL, and it shouldn't be
- * altered by user space tool, so we don't need to support the
- * --component-set for this moment. */
if (comp_set && !comp_id) {
fprintf(stderr, "%s %s: --component-set doesn't have component-id set\n",
progname, argv[0]);
result = adjust_first_extent(fname, layout);
if (result == -ENODATA)
comp_add = 0;
- else if (result != 0)
+ else if (result != 0) {
+ fprintf(stderr, "error: %s: invalid layout\n",
+ progname);
goto error;
+ }
}
if (from_yaml && from_copy) {
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,
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 ? " " : "";
" 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)
if (verbose & VERBOSE_STRIPE_SIZE) {
llapi_printf(LLAPI_MSG_NORMAL, "%s", separator);
- if (verbose & ~VERBOSE_STRIPE_SIZE)
+ if (verbose & ~VERBOSE_STRIPE_SIZE && extension)
+ llapi_printf(LLAPI_MSG_NORMAL, "%s%sextension_size: ",
+ space, prefix);
+ else if (verbose & ~VERBOSE_STRIPE_SIZE)
llapi_printf(LLAPI_MSG_NORMAL, "%s%sstripe_size: ",
space, prefix);
if (is_dir && !is_raw && lum->lmm_stripe_size == 0) {
"Cannot determine default"
" stripe size.");
} else {
- llapi_printf(LLAPI_MSG_NORMAL, "%u",
+ /* Extension size is in KiB */
+ llapi_printf(LLAPI_MSG_NORMAL, "%llu",
+ extension ?
+ lum->lmm_stripe_size * SEL_UNIT_SIZE :
lum->lmm_stripe_size);
}
if (!yaml && is_dir)
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;
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)) {
/**
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);
}
}
llapi_stripe_count_is_valid(stripe_count));
}
+static bool llapi_layout_extension_size_is_valid(uint64_t ext_size)
+{
+ return (ext_size != 0 &&
+ llapi_stripe_size_is_aligned(ext_size) &&
+ !llapi_stripe_size_is_too_big(ext_size));
+}
+
static bool llapi_layout_stripe_size_is_valid(uint64_t stripe_size)
{
return stripe_size == LLAPI_LAYOUT_DEFAULT ||
}
/**
- * Get the stripe size of \a layout.
+ * Get the stripe/extension size of \a layout.
*
* \param[in] layout layout to get stripe size from
* \param[out] size integer to store stripe size in
+ * \param[in] extension flag if extenion size is requested
*
* \retval 0 on success
* \retval -1 if arguments are invalid
*/
-int llapi_layout_stripe_size_get(const struct llapi_layout *layout,
- uint64_t *size)
+static int layout_stripe_size_get(const struct llapi_layout *layout,
+ uint64_t *size, bool extension)
{
struct llapi_layout_comp *comp;
+ int comp_ext;
comp = __llapi_layout_cur_comp(layout);
if (comp == NULL)
return -1;
}
+ comp_ext = comp->llc_flags & LCME_FL_EXTENSION;
+ if ((comp_ext && !extension) || (!comp_ext && extension)) {
+ errno = EINVAL;
+ return -1;
+ }
+
*size = comp->llc_stripe_size;
+ if (comp->llc_flags & LCME_FL_EXTENSION)
+ *size *= SEL_UNIT_SIZE;
return 0;
}
+int llapi_layout_stripe_size_get(const struct llapi_layout *layout,
+ uint64_t *size)
+{
+ return layout_stripe_size_get(layout, size, false);
+}
+
+int llapi_layout_extension_size_get(const struct llapi_layout *layout,
+ uint64_t *size)
+{
+ return layout_stripe_size_get(layout, size, true);
+}
+
/**
- * Set the stripe size of \a layout.
+ * Set the stripe/extension size of \a layout.
*
* \param[in] layout layout to set stripe size in
* \param[in] size value to be set
+ * \param[in] extension flag if extenion size is passed
*
* \retval 0 on success
* \retval -1 if arguments are invalid
*/
-int llapi_layout_stripe_size_set(struct llapi_layout *layout,
- uint64_t size)
+static int layout_stripe_size_set(struct llapi_layout *layout,
+ uint64_t size, bool extension)
{
struct llapi_layout_comp *comp;
+ int comp_ext;
comp = __llapi_layout_cur_comp(layout);
if (comp == NULL)
return -1;
- if (!llapi_layout_stripe_size_is_valid(size)) {
+ comp_ext = comp->llc_flags & LCME_FL_EXTENSION;
+ if ((comp_ext && !extension) || (!comp_ext && extension)) {
errno = EINVAL;
return -1;
}
- comp->llc_stripe_size = size;
+ if (comp_ext)
+ size /= SEL_UNIT_SIZE;
+
+ if ((comp_ext && !llapi_layout_extension_size_is_valid(size)) ||
+ (!comp_ext && !llapi_layout_stripe_size_is_valid(size))) {
+ errno = EINVAL;
+ return -1;
+ }
+ comp->llc_stripe_size = size;
return 0;
}
+int llapi_layout_stripe_size_set(struct llapi_layout *layout,
+ uint64_t size)
+{
+ return layout_stripe_size_set(layout, size, false);
+}
+
+int llapi_layout_extension_size_set(struct llapi_layout *layout,
+ uint64_t size)
+{
+ return layout_stripe_size_set(layout, size, true);
+}
+
/**
* Get the RAID pattern of \a layout.
*