Add xattr .totl. tag

Add the .totl. xattr tag.  When the tag is set the end of the name
specifies a total name with 3 encoded u64s separated by dots.  The value
of the xattr is a u64 that is added to the named total.   An ioctl is
added to read the totals.

Signed-off-by: Zach Brown <zab@versity.com>
This commit is contained in:
Zach Brown
2021-07-09 15:41:50 -07:00
parent a59fd5865d
commit b9a0f1709f
19 changed files with 1194 additions and 35 deletions

View File

@@ -142,6 +142,62 @@ If the
file is written to then the server cannot make forward progress and
shuts down. The request can similarly enter an errored state if enough
time passes before userspace completes the request.
.SH EXTENDED ATTRIBUTE TAGS
.B scoutfs
adds the
.IB scoutfs.
extended attribute namespace which uses a system of tags to extend the
functionality of extended attributes. Immediately following the
scoutfs. prefix are a series of tag words seperated by dots.
Any text starting after the last recognized tag is considered the xattr
name and is not parsed.
.sp
Tags may be combined in any order. Specifying a tag more than once
will return an error. There is no explicit boundary between the end of
tags and the start of the name so unknown or incorrect tags will be
successfully parsed as part of the name of the xattr. Tags can only be
created, updated, or removed with the CAP_SYS_ADMIN capability.
The following tags are currently supported:
.RS
.TP
.B .hide.
Attributes with the .hide. tag are not visible to the
.BR listxattr(2)
system call. They will instead be included in the output of the
.IB LISTXATTR_HIDDEN
ioctl. This is meant to be used by archival management agents to store
metadata that is bound to a specific volume and should not be
transferred with the file by tools that read extended attributes, like
.BR tar(1) .
.TP
.B .srch.
Attributes with the .srch. tag are indexed so that they can be
found by the
.IB SEARCH_XATTRS
ioctl. The search ioctl takes an extended attribute name and returns
the inode number of all the inodes which contain an extended attribute
with that name. The indexing structures behind .srch. tags are designed
to efficiently handle a large number of .srch. attributes per file with
no limits on the number of indexed files.
.TP
.B .totl.
Attributes with the .totl. flag are used to efficiently maintain counts
across all files in the system. The attribute's name must end in three
64bit values seperated by dots that specify the global total that the
extended attribute will contribute to. The value of the extended
attribute is a string representation of the 64bit quantity which will be
added to the total. As attributes are added, updated, or removed (and
particularly as a file is finally deleted), the corresponding global
total is also updated by the file system. All the totals with their
name, total value, and a count of contributing attributes can be read
with the
.IB READ_XATTR_TOTALS
ioctl.
.RE
.SH CORRUPTION DETECTION
A

View File

@@ -75,6 +75,17 @@ static void print_orphan(struct scoutfs_key *key, void *val, int val_len)
printf(" orphan: ino %llu\n", le64_to_cpu(key->sko_ino));
}
static void print_xattr_totl(struct scoutfs_key *key, void *val, int val_len)
{
struct scoutfs_xattr_totl_val *tval = val;
printf(" xattr totl: %llu.%llu.%llu = %lld, %lld\n",
le64_to_cpu(key->skxt_a), le64_to_cpu(key->skxt_b),
le64_to_cpu(key->skxt_c), le64_to_cpu(tval->total),
le64_to_cpu(tval->count));
}
static u8 *global_printable_name(u8 *name, int name_len)
{
static u8 name_buf[SCOUTFS_NAME_LEN + 1];
@@ -163,6 +174,9 @@ static print_func_t find_printer(u8 zone, u8 type)
return print_orphan;
}
if (zone == SCOUTFS_XATTR_TOTL_ZONE)
return print_xattr_totl;
if (zone == SCOUTFS_FS_ZONE) {
switch(type) {
case SCOUTFS_INODE_TYPE: return print_inode;

View File

@@ -0,0 +1,120 @@
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <argp.h>
#include "sparse.h"
#include "parse.h"
#include "util.h"
#include "format.h"
#include "ioctl.h"
#include "cmd.h"
struct xattr_args {
char *path;
};
static int do_read_xattr_totals(struct xattr_args *args)
{
struct scoutfs_ioctl_read_xattr_totals rxt;
struct scoutfs_ioctl_xattr_total *xts = NULL;
struct scoutfs_ioctl_xattr_total *xt;
u64 bytes = 1024 * 1024;
int fd = -1;
int ret;
int i;
xts = malloc(bytes);
if (!xts) {
fprintf(stderr, "xattr total mem alloc failed\n");
ret = -ENOMEM;
goto out;
}
fd = get_path(args->path, O_RDONLY);
if (fd < 0)
return fd;
memset(&rxt, 0, sizeof(rxt));
rxt.totals_ptr = (unsigned long)xts;
rxt.totals_bytes = bytes;
for (;;) {
ret = ioctl(fd, SCOUTFS_IOC_READ_XATTR_TOTALS, &rxt);
if (ret == 0)
break;
if (ret < 0) {
ret = -errno;
fprintf(stderr, "read_xattr_totals ioctl failed: "
"%s (%d)\n", strerror(errno), errno);
goto out;
}
for (i = 0, xt = xts; i < ret; i++, xt++)
printf("%llu.%llu.%llu = %lld, %lld\n",
xt->name[0], xt->name[1], xt->name[2], xt->total, xt->count);
memcpy(&rxt.pos_name, &xts[ret - 1].name, sizeof(rxt.pos_name));
if (++rxt.pos_name[2] == 0 && ++rxt.pos_name[1] == 0 && ++rxt.pos_name[0] == 0)
break;
}
ret = 0;
out:
if (fd >= 0)
close(fd);
free(xts);
return ret;
};
static int parse_opt(int key, char *arg, struct argp_state *state)
{
struct xattr_args *args = state->input;
switch (key) {
case 'p':
args->path = strdup_or_error(state, arg);
break;
default:
break;
}
return 0;
}
static struct argp_option options[] = {
{ "path", 'p', "PATH", 0, "Path to ScoutFS filesystem"},
{ NULL }
};
static struct argp argp = {
options,
parse_opt,
"",
"Print global value totals of .totl. xattrs"
};
static int read_xattr_totals_cmd(int argc, char **argv)
{
struct xattr_args xattr_args = {NULL};
int ret;
ret = argp_parse(&argp, argc, argv, 0, NULL, &xattr_args);
if (ret)
return ret;
return do_read_xattr_totals(&xattr_args);
}
static void __attribute__((constructor)) read_xattr_totals_ctor(void)
{
cmd_register_argp("read-xattr-totals", &argp, GROUP_INFO, read_xattr_totals_cmd);
}