scoutfs-utils: add statfs wrapper

Add a scoutfs command wrapper around the statfs_moe ioctl.  It's the
same as the stat_more ioctl but has different fields and a different
ioctl.

Signed-off-by: Zach Brown <zab@versity.com>
This commit is contained in:
Zach Brown
2019-07-19 16:34:37 -07:00
committed by Zach Brown
parent 7cd8738add
commit 70efa2f905
2 changed files with 136 additions and 30 deletions

View File

@@ -347,4 +347,26 @@ struct scoutfs_ioctl_find_xattrs {
#define SCOUTFS_IOC_FIND_XATTRS _IOR(SCOUTFS_IOCTL_MAGIC, 10, \
struct scoutfs_ioctl_find_xattrs)
/*
* Give the user information about the filesystem.
*
* @valid_bytes stores the number of bytes that are valid in the
* structure. The caller sets this to the size of the struct that they
* understand. The kernel then fills and copies back the min of the
* size they and the user caller understand. The user can tell if a
* field is set if all of its bytes are within the valid_bytes that the
* kernel set on return.
*
* New fields are only added to the end of the struct.
*/
struct scoutfs_ioctl_statfs_more {
__u64 valid_bytes;
__u64 fsid;
__u64 rid;
} __packed;
#define SCOUTFS_IOC_STATFS_MORE _IOR(SCOUTFS_IOCTL_MAGIC, 11, \
struct scoutfs_ioctl_statfs_more)
#endif

View File

@@ -16,43 +16,115 @@
#include "ioctl.h"
#include "cmd.h"
#define FIELD(f) { \
.name = #f, \
.offset = offsetof(struct scoutfs_ioctl_stat_more, f), \
}
static struct stat_more_field {
struct stat_more_field {
char *name;
size_t offset;
} fields[] = {
FIELD(meta_seq),
FIELD(data_seq),
FIELD(data_version),
FIELD(online_blocks),
FIELD(offline_blocks),
};
#define FIELD(f, o) { \
.name = #f, \
.offset = o, \
}
#define INODE_FIELD_OFF(f) offsetof(struct scoutfs_ioctl_stat_more, f)
#define INODE_FIELD(f) FIELD(f, INODE_FIELD_OFF(f))
static struct stat_more_field inode_fields[] = {
INODE_FIELD(meta_seq),
INODE_FIELD(data_seq),
INODE_FIELD(data_version),
INODE_FIELD(online_blocks),
INODE_FIELD(offline_blocks),
{ NULL, }
};
#define for_each_field(f) \
static void print_inode_field(void *st, size_t off)
{
struct scoutfs_ioctl_stat_more *stm = st;
switch(off) {
case INODE_FIELD_OFF(meta_seq):
printf("%llu", stm->meta_seq);
break;
case INODE_FIELD_OFF(data_seq):
printf("%llu", stm->data_seq);
break;
case INODE_FIELD_OFF(data_version):
printf("%llu", stm->data_version);
break;
case INODE_FIELD_OFF(online_blocks):
printf("%llu", stm->online_blocks);
break;
case INODE_FIELD_OFF(offline_blocks):
printf("%llu", stm->offline_blocks);
break;
};
}
#define FS_FIELD_OFF(f) offsetof(struct scoutfs_ioctl_statfs_more, f)
#define FS_FIELD(f) FIELD(f, FS_FIELD_OFF(f))
static struct stat_more_field fs_fields[] = {
FS_FIELD(fsid),
FS_FIELD(rid),
{ NULL, }
};
static void print_fs_field(void *st, size_t off)
{
struct scoutfs_ioctl_statfs_more *sfm = st;
switch(off) {
case FS_FIELD_OFF(fsid):
printf("%016llx", sfm->fsid);
break;
case FS_FIELD_OFF(rid):
printf("%016llx", sfm->rid);
break;
};
}
#define for_each_field(f, fields) \
for (f = fields; f->name; f++)
typedef void (*print_field_t)(void *st, size_t off);
static struct option long_ops[] = {
{ "single_field", 1, NULL, 's' },
{ NULL, 0, NULL, 0}
};
static int stat_more_cmd(int argc, char **argv)
static int do_stat(int argc, char **argv, int is_inode)
{
struct scoutfs_ioctl_stat_more stm;
union {
struct scoutfs_ioctl_stat_more stm;
struct scoutfs_ioctl_statfs_more sfm;
} st;
struct stat_more_field *single = NULL;
struct stat_more_field *fields;
struct stat_more_field *fi;
char *single_name = NULL;
print_field_t pr = NULL;
char *path;
int cmd;
int ret;
int fd;
int i;
int c;
memset(&st, 0, sizeof(st));
if (is_inode) {
cmd = SCOUTFS_IOC_STAT_MORE;
fields = inode_fields;
st.stm.valid_bytes = sizeof(struct scoutfs_ioctl_stat_more);
pr = print_inode_field;
} else {
cmd = SCOUTFS_IOC_STATFS_MORE;
fields = fs_fields;
st.sfm.valid_bytes = sizeof(struct scoutfs_ioctl_statfs_more);
pr = print_fs_field;
}
while ((c = getopt_long(argc, argv, "s:", long_ops, NULL)) != -1) {
switch (c) {
case 's':
@@ -66,15 +138,14 @@ static int stat_more_cmd(int argc, char **argv)
}
if (single_name) {
for_each_field(fi) {
for_each_field(fi, fields) {
if (strcmp(fi->name, single_name) == 0) {
single = fi;
break;
}
}
if (!single) {
fprintf(stderr, "unknown stat_more field: '%s'\n",
single_name);
fprintf(stderr, "unknown field: '%s'\n", single_name);
return -EINVAL;
}
}
@@ -95,24 +166,21 @@ static int stat_more_cmd(int argc, char **argv)
continue;
}
memset(&stm, 0, sizeof(stm));
stm.valid_bytes = sizeof(stm);
ret = ioctl(fd, SCOUTFS_IOC_STAT_MORE, &stm);
ret = ioctl(fd, cmd, &st);
if (ret < 0) {
ret = -errno;
fprintf(stderr, "stat_more ioctl failed on '%s': "
fprintf(stderr, "ioctl failed on '%s': "
"%s (%d)\n", path, strerror(errno), errno);
} else if (single) {
printf("%llu\n",
*(u64 *)((void *)&stm + single->offset));
pr(&st, single->offset);
printf("\n");
} else {
printf("%-17s %s\n", "path", path);
for_each_field(fi) {
printf("%-17s %llu\n", fi->name,
*(u64 *)((void *)&stm + fi->offset));
for_each_field(fi, fields) {
printf("%-17s ", fi->name);
pr(&st, fi->offset);
printf("\n");
}
}
@@ -122,8 +190,24 @@ static int stat_more_cmd(int argc, char **argv)
return 0;
}
static int stat_more_cmd(int argc, char **argv)
{
return do_stat(argc, argv, 1);
}
static int statfs_more_cmd(int argc, char **argv)
{
return do_stat(argc, argv, 0);
}
static void __attribute__((constructor)) stat_more_ctor(void)
{
cmd_register("stat", "<path>",
"print scoutfs stat information for path", stat_more_cmd);
"show scoutfs inode information", stat_more_cmd);
}
static void __attribute__((constructor)) statfs_more_ctor(void)
{
cmd_register("statfs", "<path>",
"show scoutfs file system information", statfs_more_cmd);
}