From c17a7036ed043097f585c35d96832cec867f17c0 Mon Sep 17 00:00:00 2001 From: Zach Brown Date: Mon, 22 Aug 2016 09:33:42 -0700 Subject: [PATCH] Add find xattr commands Add commands that use the find-xattr ioctls to show the inode numbers of inodes which probably contain xattrs matching the specified name or value. Signed-off-by: Zach Brown --- utils/src/find_xattr.c | 134 +++++++++++++++++++++++++++++++++++++++++ utils/src/format.h | 22 +++++-- utils/src/ioctl.h | 15 +++++ utils/src/print.c | 22 +++++++ 4 files changed, 187 insertions(+), 6 deletions(-) create mode 100644 utils/src/find_xattr.c diff --git a/utils/src/find_xattr.c b/utils/src/find_xattr.c new file mode 100644 index 00000000..9d489d07 --- /dev/null +++ b/utils/src/find_xattr.c @@ -0,0 +1,134 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sparse.h" +#include "util.h" +#include "ioctl.h" +#include "format.h" +#include "cmd.h" + +static int find_xattrs(bool find_name, int argc, char **argv) +{ + struct scoutfs_ioctl_find_xattr find; + char *endptr; + u64 first; + u64 last; + u64 *ino; + int ret; + int fd; + int ioc; + int count; + int i; + + if (find_name) + ioc = SCOUTFS_IOC_FIND_XATTR_NAME; + else + ioc = SCOUTFS_IOC_FIND_XATTR_VAL; + + if (argc != 4) { + fprintf(stderr, "must specify ino range, xattr str, and path\n"); + return -EINVAL; + } + + first = strtoull(argv[0], &endptr, 0); + if (*endptr != '\0' || + ((first == LLONG_MIN || first == LLONG_MAX) && errno == ERANGE)) { + fprintf(stderr, "error parsing inode number '%s'\n", + argv[0]); + return -EINVAL; + } + + last = strtoull(argv[1], &endptr, 0); + if (*endptr != '\0' || + ((last == LLONG_MIN || last == LLONG_MAX) && errno == ERANGE)) { + fprintf(stderr, "error parsing inode number '%s'\n", + argv[1]); + return -EINVAL; + } + + fd = open(argv[3], O_RDONLY); + if (fd < 0) { + ret = -errno; + fprintf(stderr, "failed to open '%s': %s (%d)\n", + argv[3], strerror(errno), errno); + return ret; + } + + count = 256; + ino = calloc(count, sizeof(*ino)); + if (!ino) { + fprintf(stderr, "couldn't allocate buffer for results\n"); + ret = -ENOMEM; + goto out; + } + + find.first_ino = first; + find.last_ino = last; + find.str_ptr = (unsigned long)argv[2]; + find.str_len = strlen(argv[2]); + find.ino_ptr = (unsigned long)ino; + find.ino_count = count; + + if (find.str_len > SCOUTFS_MAX_XATTR_LEN) { + fprintf(stderr, "xattr string len %u > %d\n", + find.str_len, SCOUTFS_MAX_XATTR_LEN); + ret = -EINVAL; + goto out; + } + + do { + ret = ioctl(fd, ioc, &find); + if (ret < 0) { + ret = -errno; + fprintf(stderr, "inodes_find_xattr ioctl failed: %s (%d)\n", + strerror(errno), errno); + goto out; + } + + for (i = 0; i < ret; i++) { + printf("%llu\n", ino[i]); + find.first_ino = ino[i] + 1; + + if (find.first_ino == 0) { + ret = 0; + break; + } + } + } while (ret > 0); + +out: + free(ino); + close(fd); + + return ret; +}; + +static int find_xattr_name(int argc, char **argv) +{ + return find_xattrs(true, argc, argv); +} + +static int find_xattr_val(int argc, char **argv) +{ + return find_xattrs(false, argc, argv); +} + +static void __attribute__((constructor)) find_xattr_ctor(void) +{ + cmd_register("find-xattr-name", " ", + "print inodes that might contain xattr name", + find_xattr_name); + cmd_register("find-xattr-value", " ", + "print inodes that might contain xattr value", + find_xattr_val); +} diff --git a/utils/src/format.h b/utils/src/format.h index a2137ca9..fbe60040 100644 --- a/utils/src/format.h +++ b/utils/src/format.h @@ -99,9 +99,11 @@ struct scoutfs_key { */ #define SCOUTFS_INODE_KEY 1 #define SCOUTFS_XATTR_KEY 2 -#define SCOUTFS_DIRENT_KEY 3 -#define SCOUTFS_LINK_BACKREF_KEY 4 -#define SCOUTFS_BMAP_KEY 5 +#define SCOUTFS_XATTR_NAME_HASH_KEY 3 +#define SCOUTFS_XATTR_VAL_HASH_KEY 4 +#define SCOUTFS_DIRENT_KEY 5 +#define SCOUTFS_LINK_BACKREF_KEY 6 +#define SCOUTFS_BMAP_KEY 7 #define SCOUTFS_MAX_ITEM_LEN 512 @@ -215,6 +217,15 @@ struct scoutfs_dirent { #define SCOUTFS_NAME_LEN 255 +/* + * This is arbitrarily limiting the max size of the single buffer + * that's needed in the inode_paths ioctl to return all the paths + * that link to an inode. The structures could easily support much + * more than this but then we'd need to grow a more thorough interface + * for iterating over referring paths. That sounds horrible. + */ +#define SCOUTFS_LINK_MAX 255 + /* * We only use 31 bits for readdir positions so that we don't confuse * old signed 32bit f_pos applications or those on the other side of @@ -237,9 +248,8 @@ enum { SCOUTFS_DT_WHT, }; -#define SCOUTFS_MAX_XATTR_NAME_LEN 255 -#define SCOUTFS_MAX_XATTR_VALUE_LEN 255 -#define SCOUTFS_XATTR_HASH_MASK 7ULL +#define SCOUTFS_MAX_XATTR_LEN 255 +#define SCOUTFS_XATTR_NAME_HASH_MASK 7ULL struct scoutfs_xattr { __u8 name_len; diff --git a/utils/src/ioctl.h b/utils/src/ioctl.h index 278d255f..a4991b69 100644 --- a/utils/src/ioctl.h +++ b/utils/src/ioctl.h @@ -37,4 +37,19 @@ struct scoutfs_ioctl_inode_paths { #define SCOUTFS_IOC_INODE_PATHS _IOW(SCOUTFS_IOCTL_MAGIC, 2, \ struct scoutfs_ioctl_inode_paths) +/* XXX might as well include a seq? 0 for current behaviour? */ +struct scoutfs_ioctl_find_xattr { + __u64 first_ino; + __u64 last_ino; + __u64 str_ptr; + __u32 str_len; + __u64 ino_ptr; + __u32 ino_count; +} __packed; + +#define SCOUTFS_IOC_FIND_XATTR_NAME _IOW(SCOUTFS_IOCTL_MAGIC, 3, \ + struct scoutfs_ioctl_find_xattr) +#define SCOUTFS_IOC_FIND_XATTR_VAL _IOW(SCOUTFS_IOCTL_MAGIC, 4, \ + struct scoutfs_ioctl_find_xattr) + #endif diff --git a/utils/src/print.c b/utils/src/print.c index b6399ca2..fb5a48a2 100644 --- a/utils/src/print.c +++ b/utils/src/print.c @@ -76,6 +76,22 @@ static void print_inode(struct scoutfs_inode *inode) le32_to_cpu(inode->mtime.nsec)); } +static void print_xattr(struct scoutfs_xattr *xat) +{ + /* XXX check lengths */ + + printf(" xattr: name %.*s val_len %u\n", + xat->name_len, xat->name, xat->value_len); +} + +static void print_xattr_val_hash(__le64 *refcount) +{ + /* XXX check lengths */ + + printf(" xattr_val_hash: refcount %llu\n", + le64_to_cpu(*refcount)); +} + static void print_dirent(struct scoutfs_dirent *dent, unsigned int val_len) { unsigned int name_len = val_len - sizeof(*dent); @@ -127,6 +143,12 @@ static void print_btree_val(struct scoutfs_btree_item *item, u8 level) case SCOUTFS_INODE_KEY: print_inode((void *)item->val); break; + case SCOUTFS_XATTR_KEY: + print_xattr((void *)item->val); + break; + case SCOUTFS_XATTR_VAL_HASH_KEY: + print_xattr_val_hash((void *)item->val); + break; case SCOUTFS_DIRENT_KEY: print_dirent((void *)item->val, le16_to_cpu(item->val_len)); break;