scoutfs-utils: hidden and indexed xattrs

Add support for the xattr tags which can hide or index xattrs by their
name.  We get an item that indexes inodes by the presence of an xattr, a
listxattr_raw ioctl which can show hidden xattrs, and an ioctl that
finds inodes which have an xattr.

Signed-off-by: Zach Brown <zab@versity.com>
This commit is contained in:
Zach Brown
2019-06-18 16:52:29 -07:00
parent 8d505668fe
commit 674224d454
6 changed files with 329 additions and 3 deletions

117
utils/src/find_xattrs.c Normal file
View File

@@ -0,0 +1,117 @@
#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 <getopt.h>
#include "sparse.h"
#include "util.h"
#include "format.h"
#include "ioctl.h"
#include "cmd.h"
static struct option long_ops[] = {
{ "name", 1, NULL, 'n' },
{ "file", 1, NULL, 'f' },
{ NULL, 0, NULL, 0}
};
static int find_xattrs_cmd(int argc, char **argv)
{
struct scoutfs_ioctl_find_xattrs fx;
char *path = NULL;
char *name = NULL;
u64 inos[32];
int fd = -1;
int ret;
int c;
int i;
memset(&fx, 0, sizeof(fx));
while ((c = getopt_long(argc, argv, "f:n:", long_ops, NULL)) != -1) {
switch (c) {
case 'f':
path = strdup(optarg);
if (!path) {
fprintf(stderr, "path mem alloc failed\n");
ret = -ENOMEM;
goto out;
}
break;
case 'n':
name = strdup(optarg);
if (!name) {
fprintf(stderr, "name mem alloc failed\n");
ret = -ENOMEM;
goto out;
}
break;
case '?':
default:
ret = -EINVAL;
goto out;
}
}
if (path == NULL) {
fprintf(stderr, "must specify -f path to file\n");
ret = -EINVAL;
goto out;
}
fd = open(path, O_RDONLY);
if (fd < 0) {
ret = -errno;
fprintf(stderr, "failed to open '%s': %s (%d)\n",
path, strerror(errno), errno);
goto out;
}
fx.next_ino = 0;
fx.name_ptr = (unsigned long)name;
fx.inodes_ptr = (unsigned long)inos;
fx.name_bytes = strlen(name);
fx.nr_inodes = array_size(inos);
for (;;) {
ret = ioctl(fd, SCOUTFS_IOC_FIND_XATTRS, &fx);
if (ret == 0)
break;
if (ret < 0) {
ret = -errno;
fprintf(stderr, "find_xattrs ioctl failed: "
"%s (%d)\n", strerror(errno), errno);
goto out;
}
for (i = 0; i < ret; i++)
printf("%llu\n", inos[i]);
fx.next_ino = inos[ret - 1] + 1;
if (fx.next_ino == 0)
break;
}
ret = 0;
out:
if (fd >= 0)
close(fd);
free(path);
free(name);
return ret;
};
static void __attribute__((constructor)) find_xattrs_ctor(void)
{
cmd_register("find-xattrs", "-n name -f <path>",
"print inode numbers of inodes which may have given xattr",
find_xattrs_cmd);
}

View File

@@ -108,6 +108,11 @@ struct scoutfs_key {
#define skii_major _sk_second
#define skii_ino _sk_third
/* xattr index */
#define skxi_hash _sk_first
#define skxi_ino _sk_second
#define skxi_id _sk_third
/* node free extent */
#define sknf_node_id _sk_first
#define sknf_major _sk_second
@@ -351,9 +356,10 @@ struct scoutfs_segment_block {
* Keys are first sorted by major key zones.
*/
#define SCOUTFS_INODE_INDEX_ZONE 1
#define SCOUTFS_NODE_ZONE 2
#define SCOUTFS_FS_ZONE 3
#define SCOUTFS_LOCK_ZONE 4
#define SCOUTFS_XATTR_INDEX_ZONE 2
#define SCOUTFS_NODE_ZONE 3
#define SCOUTFS_FS_ZONE 4
#define SCOUTFS_LOCK_ZONE 5
#define SCOUTFS_MAX_ZONE 8 /* power of 2 is efficient */
/* inode index zone */
@@ -361,6 +367,9 @@ struct scoutfs_segment_block {
#define SCOUTFS_INODE_INDEX_DATA_SEQ_TYPE 2
#define SCOUTFS_INODE_INDEX_NR 3 /* don't forget to update */
/* xattr index zone */
#define SCOUTFS_XATTR_INDEX_NAME_TYPE 1
/* node zone (also used in server alloc btree) */
#define SCOUTFS_FREE_EXTENT_BLKNO_TYPE 1
#define SCOUTFS_FREE_EXTENT_BLOCKS_TYPE 2

View File

@@ -271,4 +271,44 @@ struct scoutfs_ioctl_setattr_more {
#define SCOUTFS_IOC_SETATTR_MORE _IOW(SCOUTFS_IOCTL_MAGIC, 10, \
struct scoutfs_ioctl_setattr_more)
struct scoutfs_ioctl_listxattr_raw {
__u64 id_pos;
__u64 buf_ptr;
__u32 buf_bytes;
__u32 hash_pos;
} __packed;
#define SCOUTFS_IOC_LISTXATTR_RAW _IOW(SCOUTFS_IOCTL_MAGIC, 11, \
struct scoutfs_ioctl_listxattr_raw)
/*
* Return the inode numbers of inodes which might contain the given
* named xattr. The inode may not have a set xattr with that name, the
* caller must check the returned inodes to see if they match.
*
* @next_ino: The next inode number that could be returned. Initialized
* to 0 when first searching and set to one past the last inode number
* returned to continue searching.
* @name_ptr: The address of the name of the xattr to search for. It does
* not need to be null terminated.
* @inodes_ptr: The address of the array of uint64_t inode numbers in which
* to store inode numbers that may contain the xattr. EFAULT may be returned
* if this address is not naturally aligned.
* @name_bytes: The number of non-null bytes found in the name at name_ptr.
* @nr_inodes: The number of elements in the array found at inodes_ptr.
*
* This requires the CAP_SYS_ADMIN capability and will return -EPERM if
* it's not granted.
*/
struct scoutfs_ioctl_find_xattrs {
__u64 next_ino;
__u64 name_ptr;
__u64 inodes_ptr;
__u16 name_bytes;
__u16 nr_inodes;
} __packed;
#define SCOUTFS_IOC_FIND_XATTRS _IOW(SCOUTFS_IOCTL_MAGIC, 12, \
struct scoutfs_ioctl_find_xattrs)
#endif

View File

@@ -21,6 +21,7 @@
char *scoutfs_zone_strings[SCOUTFS_MAX_ZONE] = {
[SCOUTFS_INODE_INDEX_ZONE] = "ind",
[SCOUTFS_XATTR_INDEX_ZONE] = "xnd",
[SCOUTFS_NODE_ZONE] = "nod",
[SCOUTFS_FS_ZONE] = "fs",
};
@@ -28,6 +29,7 @@ char *scoutfs_zone_strings[SCOUTFS_MAX_ZONE] = {
char *scoutfs_type_strings[SCOUTFS_MAX_ZONE][SCOUTFS_MAX_TYPE] = {
[SCOUTFS_INODE_INDEX_ZONE][SCOUTFS_INODE_INDEX_META_SEQ_TYPE] = "msq",
[SCOUTFS_INODE_INDEX_ZONE][SCOUTFS_INODE_INDEX_DATA_SEQ_TYPE] = "dsq",
[SCOUTFS_XATTR_INDEX_ZONE][SCOUTFS_XATTR_INDEX_NAME_TYPE] = "nam",
[SCOUTFS_NODE_ZONE][SCOUTFS_FREE_EXTENT_BLKNO_TYPE] = "fbn",
[SCOUTFS_NODE_ZONE][SCOUTFS_FREE_EXTENT_BLOCKS_TYPE] = "fbs",
[SCOUTFS_NODE_ZONE][SCOUTFS_ORPHAN_TYPE] = "orp",

147
utils/src/listxattr_raw.c Normal file
View File

@@ -0,0 +1,147 @@
#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 <getopt.h>
#include <ctype.h>
#include "sparse.h"
#include "util.h"
#include "format.h"
#include "ioctl.h"
#include "cmd.h"
static struct option long_ops[] = {
{ "file", 1, NULL, 'f' },
{ NULL, 0, NULL, 0}
};
static int listxattr_raw_cmd(int argc, char **argv)
{
struct scoutfs_ioctl_listxattr_raw lxr;
char *path = NULL;
char *buf = NULL;
char *name;
int fd = -1;
int bytes;
int len;
int ret;
int c;
int i;
while ((c = getopt_long(argc, argv, "f:", long_ops, NULL)) != -1) {
switch (c) {
case 'f':
path = strdup(optarg);
if (!path) {
fprintf(stderr, "path mem alloc failed\n");
ret = -ENOMEM;
goto out;
}
break;
case '?':
default:
ret = -EINVAL;
goto out;
}
}
if (path == NULL) {
fprintf(stderr, "must specify -f path to file\n");
ret = -EINVAL;
goto out;
}
memset(&lxr, 0, sizeof(lxr));
lxr.id_pos = 0;
lxr.hash_pos = 0;
lxr.buf_bytes = 256 * 1024;
buf = malloc(lxr.buf_bytes);
if (!buf) {
fprintf(stderr, "xattr name buf alloc failed\n");
return -ENOMEM;
}
lxr.buf_ptr = (unsigned long)buf;
fd = open(path, O_RDONLY);
if (fd < 0) {
ret = -errno;
fprintf(stderr, "failed to open '%s': %s (%d)\n",
path, strerror(errno), errno);
goto out;
}
for (;;) {
ret = ioctl(fd, SCOUTFS_IOC_LISTXATTR_RAW, &lxr);
if (ret == 0)
break;
if (ret < 0) {
ret = -errno;
fprintf(stderr, "listxattr_raw ioctl failed: "
"%s (%d)\n", strerror(errno), errno);
goto out;
}
bytes = ret;
if (bytes > lxr.buf_bytes) {
fprintf(stderr, "listxattr_raw overflowed\n");
ret = -EFAULT;
goto out;
}
if (buf[bytes - 1] != '\0') {
fprintf(stderr, "listxattr_raw didn't term\n");
ret = -EINVAL;
goto out;
}
name = buf;
do {
len = strlen(name);
if (len == 0) {
fprintf(stderr, "listxattr_raw empty name\n");
ret = -EINVAL;
goto out;
}
if (len > SCOUTFS_XATTR_MAX_NAME_LEN) {
fprintf(stderr, "listxattr_raw long name\n");
ret = -EINVAL;
goto out;
}
for (i = 0; i < len; i++) {
if (!isprint(name[i]))
name[i] = '?';
}
printf("%s\n", name);
name += len + 1;
bytes -= len + 1;
} while (bytes > 0);
}
ret = 0;
out:
if (fd >= 0)
close(fd);
free(buf);
return ret;
};
static void __attribute__((constructor)) listxattr_raw_ctor(void)
{
cmd_register("listxattr-raw", "-f <path>",
"print only the names of all xattrs on the file",
listxattr_raw_cmd);
}

View File

@@ -197,6 +197,13 @@ static void print_inode_index(struct scoutfs_key *key, void *val, int val_len)
le64_to_cpu(key->skii_major), le64_to_cpu(key->skii_ino));
}
static void print_xattr_index(struct scoutfs_key *key, void *val, int val_len)
{
printf(" xattr index: hash 0x%016llx ino %llu id %llu\n",
le64_to_cpu(key->skxi_hash), le64_to_cpu(key->skxi_ino),
le64_to_cpu(key->skxi_id));
}
typedef void (*print_func_t)(struct scoutfs_key *key, void *val, int val_len);
static print_func_t find_printer(u8 zone, u8 type)
@@ -206,6 +213,10 @@ static print_func_t find_printer(u8 zone, u8 type)
type <= SCOUTFS_INODE_INDEX_DATA_SEQ_TYPE)
return print_inode_index;
if (zone == SCOUTFS_XATTR_INDEX_ZONE &&
type >= SCOUTFS_XATTR_INDEX_NAME_TYPE)
return print_xattr_index;
if (zone == SCOUTFS_NODE_ZONE) {
if (type == SCOUTFS_FREE_EXTENT_BLKNO_TYPE ||
type == SCOUTFS_FREE_EXTENT_BLOCKS_TYPE)