\fB\-\-thread\-count\fR=\fICOUNT\fR
use COUNT scaninng threads (default 4)
.TP
+\fB\-\-warnings\fR=\fIWARN_TYPE\fR
+enable additional warning diagnostic. Available warning type: get-attr - warning is reported when getting file attribute fails
+.TP
\fB\-h\fR, \fB\-\-help\fR
display this help text and exit
.TP
if (rc == INT_MIN)
LF3_FATAL_AT(begin + 1, "'%s' is not the name of a known user\n", name);
else if (rc < 0)
- LF3_FATAL_AT(begin + 1, "cannot get UID for user '%s': %s\n", name, strerror(-rc));
+ LF3_FATAL_AT(begin + 1,
+ "cannot get UID for user '%s': %s\n",
+ name, strerror(-rc));
return xsprintf("(= (uid) %llu)", (__ull)id);
}
if (rc == INT_MIN)
LF3_FATAL_AT(begin + 1, "'%s' is not the name of a known group\n", name);
else if (rc < 0)
- LF3_FATAL_AT(begin + 1, "cannot get GID for group '%s': %s\n", name, strerror(-rc));
+ LF3_FATAL_AT(begin + 1,
+ "cannot get GID for group '%s': %s\n",
+ name, strerror(-rc));
return xsprintf("(= (gid) %llu)", (__ull)id);
}
LF3_OPT_NOW,
LF3_OPT_SCAN_COMMAND,
LF3_OPT_THREAD_COUNT,
+ LF3_OPT_WARN,
LF3_OPT_HELP = 'h',
LF3_OPT_VERSION = 'v',
};
/* --now=EPOCH use EPOCH instead of current time (for testing) */
/* --scan-command=COMMAND use 'cat' to print the code we would send to lipe_scan3 */
" --thread-count=COUNT use COUNT scaninng threads\n"
+" --warnings=get-attr enable get attribute warnings\n"
" -h, --help display this help text and exit\n"
" -v, --version output version information and exit\n",
program_invocation_short_name);
{ "now", required_argument, 0, LF3_OPT_NOW },
{ "scan-command", required_argument, 0, LF3_OPT_SCAN_COMMAND },
{ "thread-count", required_argument, 0, LF3_OPT_THREAD_COUNT },
+ { "warnings", required_argument, 0, LF3_OPT_WARN },
{ "help", no_argument, 0, LF3_OPT_HELP },
{ "version", no_argument, 0, LF3_OPT_VERSION },
{ NULL },
const char *scan_command = LF3_SCAN_COMMAND;
const char *thread_count = NULL;
bool debug_scan = false;
+ const char *opt_warns = NULL;
int rc;
int c;
case LF3_OPT_THREAD_COUNT:
thread_count = optarg;
break;
+ case LF3_OPT_WARN:
+ opt_warns = optarg;
+ break;
case LF3_OPT_HELP:
help();
exit(EXIT_SUCCESS);
if (debug_scan)
lf3_init_add("(lipe-debug-enable #t)");
+ if (opt_warns) {
+ if (strcmp(opt_warns, "get-attr") == 0)
+ lf3_init_add("(lipe-warnings-get-attr-enable #t)");
+ else {
+ fprintf(stderr,
+ "Usage: --warnings=get-attr\n"
+ "Try '%s --help for more information.\n",
+ program_invocation_short_name);
+ exit(EXIT_FAILURE + 1);
+ }
+ }
+
+ LF3_DEBUG_S(opt_warns);
+
if (lf3_now == -1)
lf3_now = time(NULL);
The following can be called from any context:
(lipe-debug-enable [enable]) enable or disable debugging. Returns previous value.
+ (lipe-warnings-get-attr-enable [enable]) enable or disable warning report when get attr errored. Returns previous value.
(lipe-gettid) return calling thread ID (Linux tid for gdb -p, not pthread ID)
(lipe-getopt-client-mount-path) see above
(lipe-getopt-required-attrs) see above
};
extern bool ls3_debug;
+extern bool ls3_warn_get_attr;
extern const char *ls3_progname_;
extern __thread int ls3_tid;
#define LS3_WARNING(fmt, args...) \
fprintf(stderr, "%s[%d]: WARNING: "fmt, ls3_progname(), ls3_tid, ##args)
+/*
+#define LS3_WARN_GET_ATTR(fmt, args...) \
+ do { \
+ if (ls3_warn_get_attr) \
+ LS3_WARNING(fmt, ##args) \
+ } while (0)
+*/
+
#define LS3_ERROR_ONCE(fmt, args...) \
do { \
static int ls3_error_once; \
bool ls3_debug;
bool save_fsize_stats;
+bool ls3_warn_get_attr;
const char *ls3_progname_;
__thread int ls3_tid; /* gettid() thread id for debug messages. */
return scm_from_bool(old_debug);
}
+SCM_DEFINE(ls3_scm_warn_get_attr_enable, "lipe-warnings-get-attr-enable", 0, 1, 0,
+ (SCM enable), "get or set get attr warning")
+{
+ bool old_warn = ls3_warn_get_attr;
+
+ if (!SCM_UNBNDP(enable))
+ ls3_warn_get_attr = scm_is_true(enable);
+
+ return scm_from_bool(old_warn);
+}
+
SCM_DEFINE(ls3_scm_gettid, "lipe-gettid", 0, 0, 0, (), "print caller's thread ID (not pthread id)")
{
return scm_from_ulong(syscall(SYS_gettid));
{
struct ls3_object_attrs *loa = ls3_current()->lc_attrs;
+ /* *** See ls3_policy_exception_handler */
scm_throw(ls3_sym_read_attr_error,
scm_list_3(scm_from_ulong(loa->loa_ino),
scm_from_ulong(bits),
if ((loa->loa_valid & bits) == bits)
return loa;
-
ls3_read_attrs(ls3_current()->lc_instance, ls3_current()->lc_object,
loa,
bits,
false /* quit_on_error */);
-
return loa;
}
"lipe-getopt-device-path",
"lipe-getopt-required-attrs",
"lipe-getopt-thread-count",
+ "lipe-warnings-get-attr-enable",
"lipe-scan",
"lipe-scan-break",
"lipe-scan-client-mount-fd",
struct lipe_object;
struct json_object;
+#define BIT(pos) (1U << (pos))
+
+enum ls3_object_attr_bit_pos {
+ LS3_OBJECT_ATTR_BIT_BASE,
+ LS3_OBJECT_ATTR_BIT_PROJID,
+ LS3_OBJECT_ATTR_BIT_FILTER_FID,
+ LS3_OBJECT_ATTR_BIT_HSM,
+ LS3_OBJECT_ATTR_BIT_LINKS,
+ LS3_OBJECT_ATTR_BIT_LMV,
+ LS3_OBJECT_ATTR_BIT_LOV,
+ LS3_OBJECT_ATTR_BIT_SELF_FID,
+ LS3_OBJECT_ATTR_BIT_SOM,
+ LS3_OBJECT_ATTR_BIT_XATTRS,
+ LS3_OBJECT_ATTR_BIT_FILE_FID,
+ LS3_OBJECT_ATTR_BIT_SIZE,
+ LS3_OBJECT_ATTR_BIT_PATHS,
+
+ LS3_OBJECT_ATTR_BIT_MAX
+};
+
+#ifndef ARRAY_SIZE
+# define ARRAY_SIZE(a) ((sizeof(a)) / (sizeof((a)[0])))
+#endif
+
+static inline const char *ls3_object_attr_bit_pos2str(enum ls3_object_attr_bit_pos pos)
+{
+ const char *attr_bit_str[LS3_OBJECT_ATTR_BIT_MAX] = {
+ [LS3_OBJECT_ATTR_BIT_BASE] = "base",
+ [LS3_OBJECT_ATTR_BIT_PROJID] = "projid",
+ [LS3_OBJECT_ATTR_BIT_FILTER_FID] = "filter_fid",
+ [LS3_OBJECT_ATTR_BIT_HSM] = "hsm",
+ [LS3_OBJECT_ATTR_BIT_LINKS] = "links",
+ [LS3_OBJECT_ATTR_BIT_LMV] = "lmv",
+ [LS3_OBJECT_ATTR_BIT_LOV] = "lov",
+ [LS3_OBJECT_ATTR_BIT_SELF_FID] = "self_fid",
+ [LS3_OBJECT_ATTR_BIT_SOM] = "som",
+ [LS3_OBJECT_ATTR_BIT_XATTRS] = "xattrs",
+ [LS3_OBJECT_ATTR_BIT_FILE_FID] = "file_fid",
+ [LS3_OBJECT_ATTR_BIT_SIZE] = "size",
+ [LS3_OBJECT_ATTR_BIT_PATHS] = "paths",
+ };
+ if (pos >= ARRAY_SIZE(attr_bit_str))
+ return "<unknown>";
+ return attr_bit_str[pos];
+}
+
enum ls3_object_attr_bit {
/* Includes ino, mode, nlink, uid, gid, atime, ctime, mtime
* and flags. Does not include size/blocks. */
- LS3_OBJECT_ATTR_BASE = 0x0001,
- LS3_OBJECT_ATTR_PROJID = 0x0002,
+ LS3_OBJECT_ATTR_BASE = BIT(LS3_OBJECT_ATTR_BIT_BASE),
+ LS3_OBJECT_ATTR_PROJID = BIT(LS3_OBJECT_ATTR_BIT_PROJID),
/* OST objects XATTR_NAME_FID which saves the prarent FID
* (i.e. the FID of the file on MDT). Files on MDT don't have
* this xattr. */
- LS3_OBJECT_ATTR_FILTER_FID = 0x0004, /* XATTR_NAME_FID */
- LS3_OBJECT_ATTR_HSM = 0x0008, /* XATTR_NAME_HSM */
- LS3_OBJECT_ATTR_LINKS = 0x0010, /* XATTR_NAME_LINK */
- LS3_OBJECT_ATTR_LMV = 0x0020, /* XATTR_NAME_LMV */
- LS3_OBJECT_ATTR_LOV = 0x0040, /* XATTR_NAME_LOV */
- LS3_OBJECT_ATTR_SELF_FID = 0x0080, /* XATTR_NAME_LMA */
- LS3_OBJECT_ATTR_SOM = 0x0100, /* XATTR_NAME_SOM */
-
- LS3_OBJECT_ATTR_XATTRS = 0x0200,
+ /* XATTR_NAME_FID */
+ LS3_OBJECT_ATTR_FILTER_FID = BIT(LS3_OBJECT_ATTR_BIT_FILTER_FID),
+ /* XATTR_NAME_HSM */
+ LS3_OBJECT_ATTR_HSM = BIT(LS3_OBJECT_ATTR_BIT_HSM),
+ /* XATTR_NAME_LINK */
+ LS3_OBJECT_ATTR_LINKS = BIT(LS3_OBJECT_ATTR_BIT_LINKS),
+ /* XATTR_NAME_LMV */
+ LS3_OBJECT_ATTR_LMV = BIT(LS3_OBJECT_ATTR_BIT_LMV),
+ /* XATTR_NAME_LOV */
+ LS3_OBJECT_ATTR_LOV = BIT(LS3_OBJECT_ATTR_BIT_LOV),
+ /* XATTR_NAME_LMA */
+ LS3_OBJECT_ATTR_SELF_FID = BIT(LS3_OBJECT_ATTR_BIT_SELF_FID),
+ /* XATTR_NAME_SOM */
+ LS3_OBJECT_ATTR_SOM = BIT(LS3_OBJECT_ATTR_BIT_SOM),
+ LS3_OBJECT_ATTR_XATTRS = BIT(LS3_OBJECT_ATTR_BIT_XATTRS),
/* self_fid on MDT, FID of parent file on OST */
- LS3_OBJECT_ATTR_FILE_FID = 0x0400,
+ LS3_OBJECT_ATTR_FILE_FID = BIT(LS3_OBJECT_ATTR_BIT_FILE_FID),
/* The file size on MDT is always 0 (without Data on MDT). But
* Lazy Size on MDT can be used as an estimated size since the
* inaccuracy doesn't bother the policy engine. So, if DoM,
* use real size; if LSoM exists, use it as file size. */
- LS3_OBJECT_ATTR_SIZE = 0x0800,
+ LS3_OBJECT_ATTR_SIZE = BIT(LS3_OBJECT_ATTR_BIT_SIZE),
/* Paths from fid2path ioctl for LS3_OBJECT_ATTR_FID on client. */
- LS3_OBJECT_ATTR_PATHS = 0x1000,
+ LS3_OBJECT_ATTR_PATHS = BIT(LS3_OBJECT_ATTR_BIT_PATHS),
/* LS3_OBJECT_ATTR_EMPTY TODO Make work for striped directories. */
/* LS3_OBJECT_ATTR_ENTRIES TODO Make work for striped directories. */
- LS3_OBJECT_ATTR_ALL = 0x1fff,
+ LS3_OBJECT_ATTR_ALL =
+ LS3_OBJECT_ATTR_BASE |
+ LS3_OBJECT_ATTR_PROJID |
+ LS3_OBJECT_ATTR_FILTER_FID |
+ LS3_OBJECT_ATTR_HSM |
+ LS3_OBJECT_ATTR_LINKS |
+ LS3_OBJECT_ATTR_LMV |
+ LS3_OBJECT_ATTR_LOV |
+ LS3_OBJECT_ATTR_SELF_FID |
+ LS3_OBJECT_ATTR_SOM |
+ LS3_OBJECT_ATTR_XATTRS |
+ LS3_OBJECT_ATTR_FILE_FID |
+ LS3_OBJECT_ATTR_SIZE |
+ LS3_OBJECT_ATTR_PATHS,
+
LS3_OBJECT_ATTR_DEFAULT = -1U,
};
};
enum ls3_json_attr {
- LS3_JSON_ATTR_INO = 1U << LS3_JSON_BIT_INO,
- LS3_JSON_ATTR_MODE = 1U << LS3_JSON_BIT_MODE,
- LS3_JSON_ATTR_NLINK = 1U << LS3_JSON_BIT_NLINK,
- LS3_JSON_ATTR_UID = 1U << LS3_JSON_BIT_UID,
- LS3_JSON_ATTR_GID = 1U << LS3_JSON_BIT_GID,
- LS3_JSON_ATTR_PROJID = 1U << LS3_JSON_BIT_PROJID,
- LS3_JSON_ATTR_FLAGS = 1U << LS3_JSON_BIT_FLAGS,
- LS3_JSON_ATTR_ATIME = 1U << LS3_JSON_BIT_ATIME,
- LS3_JSON_ATTR_MTIME = 1U << LS3_JSON_BIT_MTIME,
- LS3_JSON_ATTR_CTIME = 1U << LS3_JSON_BIT_CTIME,
- LS3_JSON_ATTR_CRTIME = 1U << LS3_JSON_BIT_CRTIME,
- LS3_JSON_ATTR_SIZE = 1U << LS3_JSON_BIT_SIZE,
- LS3_JSON_ATTR_BLOCKS = 1U << LS3_JSON_BIT_BLOCKS,
- LS3_JSON_ATTR_FILE_FID = 1U << LS3_JSON_BIT_FILE_FID,
- LS3_JSON_ATTR_SELF_FID = 1U << LS3_JSON_BIT_SELF_FID,
- LS3_JSON_ATTR_FILTER_FID = 1U << LS3_JSON_BIT_FILTER_FID,
- LS3_JSON_ATTR_LMA = 1U << LS3_JSON_BIT_LMA,
- LS3_JSON_ATTR_HSM = 1U << LS3_JSON_BIT_HSM,
- LS3_JSON_ATTR_LOV = 1U << LS3_JSON_BIT_LOV,
- LS3_JSON_ATTR_LMV = 1U << LS3_JSON_BIT_LMV,
- LS3_JSON_ATTR_POOLS = 1U << LS3_JSON_BIT_POOLS,
- LS3_JSON_ATTR_LINKS = 1U << LS3_JSON_BIT_LINKS,
- LS3_JSON_ATTR_PATHS = 1U << LS3_JSON_BIT_PATHS,
- LS3_JSON_ATTR_SOM = 1U << LS3_JSON_BIT_SOM,
- LS3_JSON_ATTR_XATTRS = 1U << LS3_JSON_BIT_XATTRS,
- LS3_JSON_ATTR_DEVICE_NAME = 1U << LS3_JSON_BIT_DEVICE_NAME,
- LS3_JSON_ATTR_DEVICE_PATH = 1U << LS3_JSON_BIT_DEVICE_PATH,
+ LS3_JSON_ATTR_INO = BIT(LS3_JSON_BIT_INO),
+ LS3_JSON_ATTR_MODE = BIT(LS3_JSON_BIT_MODE),
+ LS3_JSON_ATTR_NLINK = BIT(LS3_JSON_BIT_NLINK),
+ LS3_JSON_ATTR_UID = BIT(LS3_JSON_BIT_UID),
+ LS3_JSON_ATTR_GID = BIT(LS3_JSON_BIT_GID),
+ LS3_JSON_ATTR_PROJID = BIT(LS3_JSON_BIT_PROJID),
+ LS3_JSON_ATTR_FLAGS = BIT(LS3_JSON_BIT_FLAGS),
+ LS3_JSON_ATTR_ATIME = BIT(LS3_JSON_BIT_ATIME),
+ LS3_JSON_ATTR_MTIME = BIT(LS3_JSON_BIT_MTIME),
+ LS3_JSON_ATTR_CTIME = BIT(LS3_JSON_BIT_CTIME),
+ LS3_JSON_ATTR_CRTIME = BIT(LS3_JSON_BIT_CRTIME),
+ LS3_JSON_ATTR_SIZE = BIT(LS3_JSON_BIT_SIZE),
+ LS3_JSON_ATTR_BLOCKS = BIT(LS3_JSON_BIT_BLOCKS),
+ LS3_JSON_ATTR_FILE_FID = BIT(LS3_JSON_BIT_FILE_FID),
+ LS3_JSON_ATTR_SELF_FID = BIT(LS3_JSON_BIT_SELF_FID),
+ LS3_JSON_ATTR_FILTER_FID = BIT(LS3_JSON_BIT_FILTER_FID),
+ LS3_JSON_ATTR_LMA = BIT(LS3_JSON_BIT_LMA),
+ LS3_JSON_ATTR_HSM = BIT(LS3_JSON_BIT_HSM),
+ LS3_JSON_ATTR_LOV = BIT(LS3_JSON_BIT_LOV),
+ LS3_JSON_ATTR_LMV = BIT(LS3_JSON_BIT_LMV),
+ LS3_JSON_ATTR_POOLS = BIT(LS3_JSON_BIT_POOLS),
+ LS3_JSON_ATTR_LINKS = BIT(LS3_JSON_BIT_LINKS),
+ LS3_JSON_ATTR_PATHS = BIT(LS3_JSON_BIT_PATHS),
+ LS3_JSON_ATTR_SOM = BIT(LS3_JSON_BIT_SOM),
+ LS3_JSON_ATTR_XATTRS = BIT(LS3_JSON_BIT_XATTRS),
+ LS3_JSON_ATTR_DEVICE_NAME = BIT(LS3_JSON_BIT_DEVICE_NAME),
+ LS3_JSON_ATTR_DEVICE_PATH = BIT(LS3_JSON_BIT_DEVICE_PATH),
/* Print the fast and mostly correct attributes by default. */
LS3_JSON_ATTR_DEFAULT =
size_t sc_thread_count;
intmax_t sc_thread_rc_max;
intmax_t sc_break_rc;
- uintmax_t sc_read_attr_error_count;
+ uintmax_t sc_read_attr_error_count[LS3_OBJECT_ATTR_BIT_MAX];
+ uintmax_t sc_read_attr_error_count_total;
uintmax_t sc_other_error_count;
};
unsigned long ti_group_start;
unsigned long ti_group_current;
unsigned long ti_group_end;
- uintmax_t ti_read_attr_error_count;
+ uintmax_t ti_read_attr_error_count[LS3_OBJECT_ATTR_BIT_MAX];
uintmax_t ti_other_error_count;
int ti_started;
int ti_should_stop; /* Use __ATOMIC_RELAXED. */
size_t value_size = 0;
int rc;
+ if (li->li_device_is_ost) {
+ /* No links xattr on OST */
+ return 0;
+ }
+
+ if (!li->li_device_is_mdt) {
+ LS3_ERROR_ONCE("cannot get links on device '%s' "
+ "with unrecognized type\n",
+ li->li_device_path);
+ return -EINVAL;
+ }
+
assert(lipe_list_empty(&loa->loa_links));
/* We use the link xattr plus caching to speed up paths but we
ext2fs_xattrs_close(&lo.u.lo_ldiskfs.lol_xattr_handle);
lipe_object_attrs_fini(&loa);
-}
+} /* ls3_scan_inode */
static int ldiskfs_scan_groups(ext2_inode_scan scan,
ext2_filsys fs,
static int ls3_scan_control_join(struct ls3_scan_control *sc)
{
int rc = 0;
- int i;
+ int i, j;
for (i = 0; i < sc->sc_thread_count; i++) {
struct ls3_thread_info *ti = &sc->sc_thread_infos[i];
if (sc->sc_thread_rc_max < imaxabs(thread_rc))
sc->sc_thread_rc_max = imaxabs(thread_rc);
- sc->sc_read_attr_error_count += ti->ti_read_attr_error_count;
+ for (j = 0; j < ARRAY_SIZE(ti->ti_read_attr_error_count); j++) {
+ sc->sc_read_attr_error_count[j] +=
+ ti->ti_read_attr_error_count[j];
+ sc->sc_read_attr_error_count_total +=
+ ti->ti_read_attr_error_count[j];
+ }
+
sc->sc_other_error_count += ti->ti_other_error_count;
}
.sc_group_desc_count = fs->group_desc_count,
};
intmax_t rc, rc2;
+ enum ls3_object_attr_bit_pos pos;
LS3_DEBUG_U(sc.sc_group_desc_count);
LS3_DEBUG_D(rc);
LS3_DEBUG_D(sc.sc_thread_rc_max);
- LS3_DEBUG_U(sc.sc_read_attr_error_count);
- LS3_DEBUG_U(sc.sc_other_error_count);
- if (sc.sc_read_attr_error_count > 0)
- LS3_WARNING("device '%s': read attr error count %"PRIuMAX"\n",
- li->li_device_path, sc.sc_read_attr_error_count);
+ if (sc.sc_read_attr_error_count_total > 0) {
+ LS3_WARNING("device '%s': read attr error count %"PRIuMAX" :\n",
+ li->li_device_path, sc.sc_read_attr_error_count_total);
+
+ for (pos = 0; pos < ARRAY_SIZE(sc.sc_read_attr_error_count); pos++) {
+ if (sc.sc_read_attr_error_count[pos] != 0)
+ LS3_WARNING(" '%s'\t: %"PRIuMAX"\n",
+ ls3_object_attr_bit_pos2str(pos),
+ (uintmax_t)(sc.sc_read_attr_error_count[pos]));
+ }
+ }
if (sc.sc_other_error_count > 0)
LS3_WARNING("device '%s': other error count %"PRIuMAX"\n",
return SCM_BOOL_T;
if (scm_is_eq(key, ls3_sym_read_attr_error)) {
- ti->ti_read_attr_error_count++;
+ size_t len, i;
+ unsigned long bits;
+
+ const SCM vector = scm_make_vector(scm_length(args), SCM_UNDEFINED);
+
+ len = scm_c_vector_length(vector);
+ for (i = 0; i < len && scm_is_pair(args); i++) {
+ scm_c_vector_set_x(vector, i, scm_car(args));
+ args = scm_cdr(args);
+ }
+
+ bits = scm_to_ulong(SCM_SIMPLE_VECTOR_REF(vector, 1));
+
+ bits &= LS3_OBJECT_ATTR_ALL;
+
+ while (bits) {
+ enum ls3_object_attr_bit_pos pos = __builtin_ffsl(bits)-1;
+
+ ti->ti_read_attr_error_count[pos]++;
+
+ /* Report each get attribute warning only when enabled */
+ if (ls3_warn_get_attr) {
+ int64_t loa_ino =
+ scm_to_ulong(SCM_SIMPLE_VECTOR_REF(vector, 0));
+ int error =
+ scm_to_int(SCM_SIMPLE_VECTOR_REF(vector, 2));
+
+ LS3_WARNING("read attr error: ino: %llu, "
+ "attr: '%s', error: %d\n",
+ (unsigned long long int)loa_ino,
+ ls3_object_attr_bit_pos2str(pos),
+ error);
+ }
+
+ bits &= ~(1UL << pos);
+ }
} else if (scm_is_eq(key, ls3_sym_scan_break)) {
struct ls3_scan_control *sc = ti->ti_scan_control;
SCM rc;
(assert (eq? #t (lipe-debug-enable #f)))
(assert (eq? #f (lipe-debug-enable)))
+(assert (procedure? lipe-warnings-get-attr-enable))
+(assert (eq? #f (lipe-warnings-get-attr-enable)))
+(assert (eq? #f (lipe-warnings-get-attr-enable #t)))
+(assert (eq? #t (lipe-warnings-get-attr-enable)))
+(assert (eq? #t (lipe-warnings-get-attr-enable #f)))
+(assert (eq? #f (lipe-warnings-get-attr-enable)))
+
(assert (procedure? lipe-gettid))
(assert (integer? (lipe-gettid)))
(assert (positive? (lipe-gettid)))