mirror of
https://github.com/koverstreet/bcachefs-tools.git
synced 2025-02-22 00:00:03 +03:00
show-super can now print more stuff
This commit is contained in:
parent
88242ec7a3
commit
dbad1685bc
37
cmd_device.c
37
cmd_device.c
@ -237,13 +237,14 @@ int cmd_device_add(int argc, char *argv[])
|
||||
device_add_usage();
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
args_shift(optind);
|
||||
|
||||
if (argc - optind != 2)
|
||||
if (argc != 2)
|
||||
die("Please supply a filesystem and a device to add");
|
||||
|
||||
struct bchfs_handle fs = bcache_fs_open(argv[optind]);
|
||||
struct bchfs_handle fs = bcache_fs_open(arg_pop());
|
||||
|
||||
dev_opts.path = argv[optind + 1];
|
||||
dev_opts.path = arg_pop();
|
||||
dev_opts.fd = open_for_format(dev_opts.path, force);
|
||||
|
||||
format_opts.block_size =
|
||||
@ -296,12 +297,20 @@ int cmd_device_remove(int argc, char *argv[])
|
||||
case 'h':
|
||||
device_remove_usage();
|
||||
}
|
||||
args_shift(optind);
|
||||
|
||||
if (argc - optind != 2)
|
||||
die("Please supply a filesystem and at least one device to remove");
|
||||
char *fs = arg_pop();
|
||||
if (!fs)
|
||||
die("Please supply a filesystem");
|
||||
|
||||
disk_ioctl(argv[optind], argv[optind + 1],
|
||||
BCH_IOCTL_DISK_REMOVE, flags);
|
||||
char *dev = arg_pop();
|
||||
if (!dev)
|
||||
die("Please supply a device to remove");
|
||||
|
||||
if (argc)
|
||||
die("too many arguments");
|
||||
|
||||
disk_ioctl(fs, dev, BCH_IOCTL_DISK_REMOVE, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -469,21 +478,23 @@ int cmd_device_resize(int argc, char *argv[])
|
||||
case 'h':
|
||||
device_resize_usage();
|
||||
}
|
||||
args_shift(optind);
|
||||
|
||||
if (argc < optind + 1)
|
||||
char *dev = arg_pop();
|
||||
if (!dev)
|
||||
die("Please supply a device to resize");
|
||||
|
||||
char *dev = argv[optind];
|
||||
int dev_fd = xopen(dev, O_RDONLY);
|
||||
|
||||
if (argc == optind + 1)
|
||||
char *size_arg = arg_pop();
|
||||
if (!size_arg)
|
||||
size = get_size(dev, dev_fd);
|
||||
else if (bch2_strtoull_h(argv[optind + 1], &size))
|
||||
else if (bch2_strtoull_h(size_arg, &size))
|
||||
die("invalid size");
|
||||
|
||||
size >>= 9;
|
||||
|
||||
if (argc > optind + 2)
|
||||
if (argc)
|
||||
die("Too many arguments");
|
||||
|
||||
struct stat dev_stat = xfstat(dev_fd);
|
||||
@ -521,7 +532,7 @@ int cmd_device_resize(int argc, char *argv[])
|
||||
struct bch_opts opts = bch2_opts_empty();
|
||||
const char *err = bch2_fs_open(&dev, 1, opts, &c);
|
||||
if (err)
|
||||
die("error opening %s: %s", argv[optind], err);
|
||||
die("error opening %s: %s", dev, err);
|
||||
|
||||
struct bch_dev *ca, *resize = NULL;
|
||||
unsigned i;
|
||||
|
61
cmd_format.c
61
cmd_format.c
@ -269,7 +269,7 @@ int cmd_format(int argc, char *argv[])
|
||||
bch2_format(opts, devices.item, darray_size(devices));
|
||||
|
||||
if (!quiet)
|
||||
bch2_super_print(sb, HUMAN_READABLE);
|
||||
bch2_sb_print(sb, false, 1 << BCH_SB_FIELD_members, HUMAN_READABLE);
|
||||
free(sb);
|
||||
|
||||
if (opts.passphrase) {
|
||||
@ -280,18 +280,61 @@ int cmd_format(int argc, char *argv[])
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void show_super_usage(void)
|
||||
{
|
||||
puts("bcachefs show-super \n"
|
||||
"Usage: bcachefs show-super [OPTION].. device\n"
|
||||
"\n"
|
||||
"Options:\n"
|
||||
" -f, --fields=(fields) list of sections to print\n"
|
||||
" -l, --layout print superblock layout\n"
|
||||
" -h, --help display this help and exit\n"
|
||||
"Report bugs to <linux-bcache@vger.kernel.org>");
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
int cmd_show_super(int argc, char *argv[])
|
||||
{
|
||||
struct bch_sb_handle sb;
|
||||
static const struct option longopts[] = {
|
||||
{ "fields", 1, NULL, 'f' },
|
||||
{ "layout", 0, NULL, 'l' },
|
||||
{ "help", 0, NULL, 'h' },
|
||||
{ NULL }
|
||||
};
|
||||
unsigned fields = 1 << BCH_SB_FIELD_members;
|
||||
bool print_layout = false;
|
||||
int opt;
|
||||
|
||||
while ((opt = getopt_long(argc, argv, "f:lh", longopts, NULL)) != -1)
|
||||
switch (opt) {
|
||||
case 'f':
|
||||
fields = !strcmp(optarg, "all")
|
||||
? ~0
|
||||
: read_flag_list_or_die(optarg,
|
||||
bch2_sb_fields, "superblock field");
|
||||
break;
|
||||
case 'l':
|
||||
print_layout = true;
|
||||
break;
|
||||
case 'h':
|
||||
show_super_usage();
|
||||
break;
|
||||
}
|
||||
args_shift(optind);
|
||||
|
||||
char *dev = arg_pop();
|
||||
if (!dev)
|
||||
die("please supply a device");
|
||||
if (argc)
|
||||
die("too many arguments");
|
||||
|
||||
const char *err;
|
||||
|
||||
if (argc != 2)
|
||||
die("please supply a single device");
|
||||
|
||||
err = bch2_read_super(argv[1], bch2_opts_empty(), &sb);
|
||||
struct bch_sb_handle sb;
|
||||
err = bch2_read_super(dev, bch2_opts_empty(), &sb);
|
||||
if (err)
|
||||
die("Error opening %s: %s", argv[1], err);
|
||||
die("Error opening %s: %s", dev, err);
|
||||
|
||||
bch2_super_print(sb.sb, HUMAN_READABLE);
|
||||
bch2_sb_print(sb.sb, print_layout, fields, HUMAN_READABLE);
|
||||
bch2_free_super(&sb);
|
||||
return 0;
|
||||
}
|
||||
|
15
cmd_fs.c
15
cmd_fs.c
@ -10,21 +10,6 @@
|
||||
#include "cmds.h"
|
||||
#include "libbcachefs.h"
|
||||
|
||||
static inline int printf_pad(unsigned pad, const char * fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
int ret;
|
||||
|
||||
va_start(args, fmt);
|
||||
ret = vprintf(fmt, args);
|
||||
va_end(args);
|
||||
|
||||
while (ret++ < pad)
|
||||
putchar(' ');
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void print_fs_usage(const char *path, enum units units)
|
||||
{
|
||||
unsigned i, j;
|
||||
|
286
libbcachefs.c
286
libbcachefs.c
@ -1,3 +1,4 @@
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdbool.h>
|
||||
@ -310,18 +311,207 @@ static unsigned get_dev_has_data(struct bch_sb *sb, unsigned dev)
|
||||
return data_has;
|
||||
}
|
||||
|
||||
void bch2_super_print(struct bch_sb *sb, int units)
|
||||
/* superblock printing: */
|
||||
|
||||
static void bch2_sb_print_layout(struct bch_sb *sb, enum units units)
|
||||
{
|
||||
struct bch_sb_layout *l = &sb->layout;
|
||||
unsigned i;
|
||||
|
||||
printf(" type: %u\n"
|
||||
" superblock max size: %s\n"
|
||||
" nr superblocks: %u\n"
|
||||
" Offsets: ",
|
||||
l->layout_type,
|
||||
pr_units(1 << l->sb_max_size_bits, units),
|
||||
l->nr_superblocks);
|
||||
|
||||
for (i = 0; i < l->nr_superblocks; i++) {
|
||||
if (i)
|
||||
printf(", ");
|
||||
printf("%llu", le64_to_cpu(l->sb_offset[i]));
|
||||
}
|
||||
putchar('\n');
|
||||
}
|
||||
|
||||
static void bch2_sb_print_journal(struct bch_sb *sb, struct bch_sb_field *f,
|
||||
enum units units)
|
||||
{
|
||||
struct bch_sb_field_journal *journal = field_to_type(f, journal);
|
||||
unsigned i, nr = bch2_nr_journal_buckets(journal);
|
||||
|
||||
printf(" Buckets: ");
|
||||
for (i = 0; i < nr; i++) {
|
||||
if (i)
|
||||
putchar(' ');
|
||||
printf("%llu", le64_to_cpu(journal->buckets[i]));
|
||||
}
|
||||
putchar('\n');
|
||||
}
|
||||
|
||||
static void bch2_sb_print_members(struct bch_sb *sb, struct bch_sb_field *f,
|
||||
enum units units)
|
||||
{
|
||||
struct bch_sb_field_members *mi = field_to_type(f, members);
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < sb->nr_devices; i++) {
|
||||
struct bch_member *m = mi->members + i;
|
||||
time_t last_mount = le64_to_cpu(m->last_mount);
|
||||
char member_uuid_str[40];
|
||||
char data_allowed_str[100];
|
||||
char data_has_str[100];
|
||||
|
||||
if (!bch2_member_exists(m))
|
||||
continue;
|
||||
|
||||
uuid_unparse(m->uuid.b, member_uuid_str);
|
||||
bch2_scnprint_flag_list(data_allowed_str,
|
||||
sizeof(data_allowed_str),
|
||||
bch2_data_types,
|
||||
BCH_MEMBER_DATA_ALLOWED(m));
|
||||
if (!data_allowed_str[0])
|
||||
strcpy(data_allowed_str, "(none)");
|
||||
|
||||
bch2_scnprint_flag_list(data_has_str,
|
||||
sizeof(data_has_str),
|
||||
bch2_data_types,
|
||||
get_dev_has_data(sb, i));
|
||||
if (!data_has_str[0])
|
||||
strcpy(data_has_str, "(none)");
|
||||
|
||||
printf(" Device %u:\n"
|
||||
" UUID: %s\n"
|
||||
" Size: %s\n"
|
||||
" Bucket size: %s\n"
|
||||
" First bucket: %u\n"
|
||||
" Buckets: %llu\n"
|
||||
" Last mount: %s\n"
|
||||
" State: %s\n"
|
||||
" Tier: %llu\n"
|
||||
" Data allowed: %s\n"
|
||||
|
||||
" Has data: %s\n"
|
||||
|
||||
" Replacement policy: %s\n"
|
||||
" Discard: %llu\n",
|
||||
i, member_uuid_str,
|
||||
pr_units(le16_to_cpu(m->bucket_size) *
|
||||
le64_to_cpu(m->nbuckets), units),
|
||||
pr_units(le16_to_cpu(m->bucket_size), units),
|
||||
le16_to_cpu(m->first_bucket),
|
||||
le64_to_cpu(m->nbuckets),
|
||||
last_mount ? ctime(&last_mount) : "(never)",
|
||||
|
||||
BCH_MEMBER_STATE(m) < BCH_MEMBER_STATE_NR
|
||||
? bch2_dev_state[BCH_MEMBER_STATE(m)]
|
||||
: "unknown",
|
||||
|
||||
BCH_MEMBER_TIER(m),
|
||||
data_allowed_str,
|
||||
data_has_str,
|
||||
|
||||
BCH_MEMBER_REPLACEMENT(m) < CACHE_REPLACEMENT_NR
|
||||
? bch2_cache_replacement_policies[BCH_MEMBER_REPLACEMENT(m)]
|
||||
: "unknown",
|
||||
|
||||
BCH_MEMBER_DISCARD(m));
|
||||
}
|
||||
}
|
||||
|
||||
static void bch2_sb_print_crypt(struct bch_sb *sb, struct bch_sb_field *f,
|
||||
enum units units)
|
||||
{
|
||||
struct bch_sb_field_crypt *crypt = field_to_type(f, crypt);
|
||||
|
||||
printf(" KFD: %llu\n"
|
||||
" scrypt n: %llu\n"
|
||||
" scrypt r: %llu\n"
|
||||
" scrypt p: %llu\n",
|
||||
BCH_CRYPT_KDF_TYPE(crypt),
|
||||
BCH_KDF_SCRYPT_N(crypt),
|
||||
BCH_KDF_SCRYPT_R(crypt),
|
||||
BCH_KDF_SCRYPT_P(crypt));
|
||||
}
|
||||
|
||||
static void bch2_sb_print_replicas(struct bch_sb *sb, struct bch_sb_field *f,
|
||||
enum units units)
|
||||
{
|
||||
struct bch_sb_field_replicas *replicas = field_to_type(f, replicas);
|
||||
struct bch_replicas_entry *e;
|
||||
unsigned i;
|
||||
|
||||
for_each_replicas_entry(replicas, e) {
|
||||
printf_pad(32, " %s:", bch2_data_types[e->data_type]);
|
||||
|
||||
putchar('[');
|
||||
for (i = 0; i < e->nr; i++) {
|
||||
if (i)
|
||||
putchar(' ');
|
||||
printf("%u", e->devs[i]);
|
||||
}
|
||||
printf("]\n");
|
||||
}
|
||||
}
|
||||
|
||||
typedef void (*sb_field_print_fn)(struct bch_sb *, struct bch_sb_field *, enum units);
|
||||
|
||||
struct bch_sb_field_ops {
|
||||
sb_field_print_fn print;
|
||||
};
|
||||
|
||||
static const struct bch_sb_field_ops bch2_sb_field_ops[] = {
|
||||
#define x(f, nr) \
|
||||
[BCH_SB_FIELD_##f] = { \
|
||||
.print = bch2_sb_print_##f, \
|
||||
},
|
||||
BCH_SB_FIELDS()
|
||||
#undef x
|
||||
};
|
||||
|
||||
static inline void bch2_sb_field_print(struct bch_sb *sb,
|
||||
struct bch_sb_field *f,
|
||||
enum units units)
|
||||
{
|
||||
unsigned type = le32_to_cpu(f->type);
|
||||
|
||||
if (type < BCH_SB_FIELD_NR)
|
||||
bch2_sb_field_ops[type].print(sb, f, units);
|
||||
else
|
||||
printf("(unknown field %u)\n", type);
|
||||
}
|
||||
|
||||
void bch2_sb_print(struct bch_sb *sb, bool print_layout,
|
||||
unsigned fields, enum units units)
|
||||
{
|
||||
struct bch_sb_field_members *mi;
|
||||
char user_uuid_str[40], internal_uuid_str[40];
|
||||
char fields_have_str[200];
|
||||
char label[BCH_SB_LABEL_SIZE + 1];
|
||||
unsigned i;
|
||||
struct bch_sb_field *f;
|
||||
u64 fields_have = 0;
|
||||
unsigned nr_devices = 0;
|
||||
|
||||
memset(label, 0, sizeof(label));
|
||||
memcpy(label, sb->label, sizeof(sb->label));
|
||||
uuid_unparse(sb->user_uuid.b, user_uuid_str);
|
||||
uuid_unparse(sb->uuid.b, internal_uuid_str);
|
||||
|
||||
mi = bch2_sb_get_members(sb);
|
||||
if (mi) {
|
||||
struct bch_member *m;
|
||||
|
||||
for (m = mi->members;
|
||||
m < mi->members + sb->nr_devices;
|
||||
m++)
|
||||
nr_devices += bch2_member_exists(m);
|
||||
}
|
||||
|
||||
vstruct_for_each(sb, f)
|
||||
fields_have |= 1 << le32_to_cpu(f->type);
|
||||
bch2_scnprint_flag_list(fields_have_str, sizeof(fields_have_str),
|
||||
bch2_sb_fields, fields_have);
|
||||
|
||||
printf("External UUID: %s\n"
|
||||
"Internal UUID: %s\n"
|
||||
"Label: %s\n"
|
||||
@ -331,8 +521,8 @@ void bch2_super_print(struct bch_sb *sb, int units)
|
||||
"Error action: %s\n"
|
||||
"Clean: %llu\n"
|
||||
|
||||
"Metadata replicas: have %llu, want %llu\n"
|
||||
"Data replicas: have %llu, want %llu\n"
|
||||
"Metadata replicas: %llu\n"
|
||||
"Data replicas: %llu\n"
|
||||
|
||||
"Metadata checksum type: %s (%llu)\n"
|
||||
"Data checksum type: %s (%llu)\n"
|
||||
@ -343,7 +533,9 @@ void bch2_super_print(struct bch_sb *sb, int units)
|
||||
"GC reserve percentage: %llu%%\n"
|
||||
"Root reserve percentage: %llu%%\n"
|
||||
|
||||
"Devices: %u\n",
|
||||
"Devices: %u live, %u total\n"
|
||||
"Sections: %s\n"
|
||||
"Superblock size: %llu\n",
|
||||
user_uuid_str,
|
||||
internal_uuid_str,
|
||||
label,
|
||||
@ -357,9 +549,7 @@ void bch2_super_print(struct bch_sb *sb, int units)
|
||||
|
||||
BCH_SB_CLEAN(sb),
|
||||
|
||||
0LLU, //BCH_SB_META_REPLICAS_HAVE(sb),
|
||||
BCH_SB_META_REPLICAS_WANT(sb),
|
||||
0LLU, //BCH_SB_DATA_REPLICAS_HAVE(sb),
|
||||
BCH_SB_DATA_REPLICAS_WANT(sb),
|
||||
|
||||
BCH_SB_META_CSUM_TYPE(sb) < BCH_CSUM_OPT_NR
|
||||
@ -386,73 +576,33 @@ void bch2_super_print(struct bch_sb *sb, int units)
|
||||
BCH_SB_GC_RESERVE(sb),
|
||||
BCH_SB_ROOT_RESERVE(sb),
|
||||
|
||||
sb->nr_devices);
|
||||
nr_devices, sb->nr_devices,
|
||||
fields_have_str,
|
||||
vstruct_bytes(sb));
|
||||
|
||||
mi = bch2_sb_get_members(sb);
|
||||
if (!mi) {
|
||||
printf("Member info section missing\n");
|
||||
return;
|
||||
if (print_layout) {
|
||||
printf("\n"
|
||||
"Layout:\n");
|
||||
bch2_sb_print_layout(sb, units);
|
||||
}
|
||||
|
||||
for (i = 0; i < sb->nr_devices; i++) {
|
||||
struct bch_member *m = mi->members + i;
|
||||
time_t last_mount = le64_to_cpu(m->last_mount);
|
||||
char member_uuid_str[40];
|
||||
char data_allowed_str[100];
|
||||
char data_has_str[100];
|
||||
vstruct_for_each(sb, f) {
|
||||
unsigned type = le32_to_cpu(f->type);
|
||||
char name[60];
|
||||
|
||||
uuid_unparse(m->uuid.b, member_uuid_str);
|
||||
bch2_scnprint_flag_list(data_allowed_str,
|
||||
sizeof(data_allowed_str),
|
||||
bch2_data_types,
|
||||
BCH_MEMBER_DATA_ALLOWED(m));
|
||||
if (!data_allowed_str[0])
|
||||
strcpy(data_allowed_str, "(none)");
|
||||
if (!(fields & (1 << type)))
|
||||
continue;
|
||||
|
||||
bch2_scnprint_flag_list(data_has_str,
|
||||
sizeof(data_has_str),
|
||||
bch2_data_types,
|
||||
get_dev_has_data(sb, i));
|
||||
if (!data_has_str[0])
|
||||
strcpy(data_has_str, "(none)");
|
||||
if (type < BCH_SB_FIELD_NR) {
|
||||
scnprintf(name, sizeof(name), "%s", bch2_sb_fields[type]);
|
||||
name[0] = toupper(name[0]);
|
||||
} else {
|
||||
scnprintf(name, sizeof(name), "(unknown field %u)", type);
|
||||
}
|
||||
|
||||
printf("\n"
|
||||
"Device %u:\n"
|
||||
" UUID: %s\n"
|
||||
" Size: %s\n"
|
||||
" Bucket size: %s\n"
|
||||
" First bucket: %u\n"
|
||||
" Buckets: %llu\n"
|
||||
" Last mount: %s\n"
|
||||
" State: %s\n"
|
||||
" Tier: %llu\n"
|
||||
" Data allowed: %s\n"
|
||||
|
||||
" Has data: %s\n"
|
||||
|
||||
" Replacement policy: %s\n"
|
||||
" Discard: %llu\n",
|
||||
i, member_uuid_str,
|
||||
pr_units(le16_to_cpu(m->bucket_size) *
|
||||
le64_to_cpu(m->nbuckets), units),
|
||||
pr_units(le16_to_cpu(m->bucket_size), units),
|
||||
le16_to_cpu(m->first_bucket),
|
||||
le64_to_cpu(m->nbuckets),
|
||||
last_mount ? ctime(&last_mount) : "(never)",
|
||||
|
||||
BCH_MEMBER_STATE(m) < BCH_MEMBER_STATE_NR
|
||||
? bch2_dev_state[BCH_MEMBER_STATE(m)]
|
||||
: "unknown",
|
||||
|
||||
BCH_MEMBER_TIER(m),
|
||||
data_allowed_str,
|
||||
data_has_str,
|
||||
|
||||
BCH_MEMBER_REPLACEMENT(m) < CACHE_REPLACEMENT_NR
|
||||
? bch2_cache_replacement_policies[BCH_MEMBER_REPLACEMENT(m)]
|
||||
: "unknown",
|
||||
|
||||
BCH_MEMBER_DISCARD(m));
|
||||
printf("\n%s (size %llu):\n", name, vstruct_bytes(f));
|
||||
if (type < BCH_SB_FIELD_NR)
|
||||
bch2_sb_field_print(sb, f, units);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -75,7 +75,7 @@ struct bch_sb *bch2_format(struct format_opts, struct dev_opts *, size_t);
|
||||
void bch2_super_write(int, struct bch_sb *);
|
||||
struct bch_sb *__bch2_super_read(int, u64);
|
||||
|
||||
void bch2_super_print(struct bch_sb *, int);
|
||||
void bch2_sb_print(struct bch_sb *, bool, unsigned, enum units);
|
||||
|
||||
/* ioctl interface: */
|
||||
|
||||
|
17
tools-util.c
17
tools-util.c
@ -112,7 +112,22 @@ struct stat xfstat(int fd)
|
||||
return stat;
|
||||
}
|
||||
|
||||
/* Integer stuff: */
|
||||
/* Formatting: */
|
||||
|
||||
int printf_pad(unsigned pad, const char * fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
int ret;
|
||||
|
||||
va_start(args, fmt);
|
||||
ret = vprintf(fmt, args);
|
||||
va_end(args);
|
||||
|
||||
while (ret++ < pad)
|
||||
putchar(' ');
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct units_buf __pr_units(s64 _v, enum units units)
|
||||
{
|
||||
|
16
tools-util.h
16
tools-util.h
@ -47,6 +47,8 @@ struct stat xfstat(int);
|
||||
_ret; \
|
||||
})
|
||||
|
||||
int printf_pad(unsigned pad, const char * fmt, ...);
|
||||
|
||||
enum units {
|
||||
BYTES,
|
||||
SECTORS,
|
||||
@ -151,4 +153,18 @@ char *dev_to_name(dev_t);
|
||||
char *dev_to_path(dev_t);
|
||||
char *dev_to_mount(char *);
|
||||
|
||||
#define args_shift(_nr) \
|
||||
do { \
|
||||
argc -= (_nr); \
|
||||
argv += (_nr); \
|
||||
} while (0)
|
||||
|
||||
#define arg_pop() \
|
||||
({ \
|
||||
char *_ret = argc ? argv[0] : NULL; \
|
||||
if (_ret) \
|
||||
args_shift(1); \
|
||||
_ret; \
|
||||
})
|
||||
|
||||
#endif /* _TOOLS_UTIL_H */
|
||||
|
Loading…
Reference in New Issue
Block a user