summaryrefslogtreecommitdiff
path: root/libbcachefs/xattr.c
diff options
context:
space:
mode:
Diffstat (limited to 'libbcachefs/xattr.c')
-rw-r--r--libbcachefs/xattr.c92
1 files changed, 56 insertions, 36 deletions
diff --git a/libbcachefs/xattr.c b/libbcachefs/xattr.c
index 488d5369..4e82e42c 100644
--- a/libbcachefs/xattr.c
+++ b/libbcachefs/xattr.c
@@ -11,6 +11,16 @@
#include <linux/posix_acl_xattr.h>
#include <linux/xattr.h>
+static unsigned xattr_val_u64s(unsigned name_len, unsigned val_len)
+{
+ return DIV_ROUND_UP(sizeof(struct bch_xattr) +
+ name_len + val_len, sizeof(u64));
+}
+
+#define xattr_val(_xattr) ((_xattr)->x_name + (_xattr)->x_name_len)
+
+static const struct xattr_handler *bch2_xattr_type_to_handler(unsigned);
+
struct xattr_search_key {
u8 type;
struct qstr name;
@@ -31,8 +41,6 @@ static u64 bch2_xattr_hash(const struct bch_hash_info *info,
return bch2_str_hash_end(&ctx, info);
}
-#define xattr_val(_xattr) ((_xattr)->x_name + (_xattr)->x_name_len)
-
static u64 xattr_hash_key(const struct bch_hash_info *info, const void *key)
{
return bch2_xattr_hash(info, key);
@@ -66,7 +74,7 @@ static bool xattr_cmp_bkey(struct bkey_s_c _l, struct bkey_s_c _r)
memcmp(l.v->x_name, r.v->x_name, r.v->x_name_len);
}
-static const struct bch_hash_desc xattr_hash_desc = {
+const struct bch_hash_desc bch2_xattr_hash_desc = {
.btree_id = BTREE_ID_XATTRS,
.key_type = BCH_XATTR,
.whiteout_type = BCH_XATTR_WHITEOUT,
@@ -79,12 +87,33 @@ static const struct bch_hash_desc xattr_hash_desc = {
static const char *bch2_xattr_invalid(const struct bch_fs *c,
struct bkey_s_c k)
{
+ const struct xattr_handler *handler;
+ struct bkey_s_c_xattr xattr;
+ unsigned u64s;
+
switch (k.k->type) {
case BCH_XATTR:
- return bkey_val_bytes(k.k) < sizeof(struct bch_xattr)
- ? "value too small"
- : NULL;
+ if (bkey_val_bytes(k.k) < sizeof(struct bch_xattr))
+ return "value too small";
+ xattr = bkey_s_c_to_xattr(k);
+ u64s = xattr_val_u64s(xattr.v->x_name_len,
+ le16_to_cpu(xattr.v->x_val_len));
+
+ if (bkey_val_u64s(k.k) < u64s)
+ return "value too small";
+
+ if (bkey_val_u64s(k.k) > u64s)
+ return "value too big";
+
+ handler = bch2_xattr_type_to_handler(xattr.v->x_type);
+ if (!handler)
+ return "invalid type";
+
+ if (memchr(xattr.v->x_name, '\0', xattr.v->x_name_len))
+ return "xattr name has invalid characters";
+
+ return NULL;
case BCH_XATTR_WHITEOUT:
return bkey_val_bytes(k.k) != 0
? "value size should be zero"
@@ -98,34 +127,29 @@ static const char *bch2_xattr_invalid(const struct bch_fs *c,
static void bch2_xattr_to_text(struct bch_fs *c, char *buf,
size_t size, struct bkey_s_c k)
{
+ const struct xattr_handler *handler;
struct bkey_s_c_xattr xattr;
- int n;
+ size_t n = 0;
switch (k.k->type) {
case BCH_XATTR:
xattr = bkey_s_c_to_xattr(k);
- if (size) {
- n = min_t(unsigned, size, xattr.v->x_name_len);
- memcpy(buf, xattr.v->x_name, n);
- buf[size - 1] = '\0';
- buf += n;
- size -= n;
- }
-
- n = scnprintf(buf, size, " -> ");
- buf += n;
- size -= n;
-
- if (size) {
- n = min_t(unsigned, size,
- le16_to_cpu(xattr.v->x_val_len));
- memcpy(buf, xattr_val(xattr.v), n);
- buf[size - 1] = '\0';
- buf += n;
- size -= n;
- }
-
+ handler = bch2_xattr_type_to_handler(xattr.v->x_type);
+ if (handler && handler->prefix)
+ n += scnprintf(buf + n, size - n, "%s", handler->prefix);
+ else if (handler)
+ n += scnprintf(buf + n, size - n, "(type %u)",
+ xattr.v->x_type);
+ else
+ n += scnprintf(buf + n, size - n, "(unknown type %u)",
+ xattr.v->x_type);
+
+ n += bch_scnmemcpy(buf + n, size - n, xattr.v->x_name,
+ xattr.v->x_name_len);
+ n += scnprintf(buf + n, size - n, ":");
+ n += bch_scnmemcpy(buf + n, size - n, xattr_val(xattr.v),
+ le16_to_cpu(xattr.v->x_val_len));
break;
case BCH_XATTR_WHITEOUT:
scnprintf(buf, size, "whiteout");
@@ -147,7 +171,7 @@ int bch2_xattr_get(struct bch_fs *c, struct inode *inode,
struct bkey_s_c_xattr xattr;
int ret;
- k = bch2_hash_lookup(xattr_hash_desc, &ei->str_hash, c,
+ k = bch2_hash_lookup(bch2_xattr_hash_desc, &ei->str_hash, c,
ei->vfs_inode.i_ino, &iter,
&X_SEARCH(type, name, strlen(name)));
if (IS_ERR(k.k))
@@ -175,15 +199,13 @@ int __bch2_xattr_set(struct bch_fs *c, u64 inum,
int ret;
if (!value) {
- ret = bch2_hash_delete(xattr_hash_desc, hash_info,
+ ret = bch2_hash_delete(bch2_xattr_hash_desc, hash_info,
c, inum,
journal_seq, &search);
} else {
struct bkey_i_xattr *xattr;
unsigned u64s = BKEY_U64s +
- DIV_ROUND_UP(sizeof(struct bch_xattr) +
- search.name.len + size,
- sizeof(u64));
+ xattr_val_u64s(search.name.len, size);
if (u64s > U8_MAX)
return -ERANGE;
@@ -200,7 +222,7 @@ int __bch2_xattr_set(struct bch_fs *c, u64 inum,
memcpy(xattr->v.x_name, search.name.name, search.name.len);
memcpy(xattr_val(&xattr->v), value, size);
- ret = bch2_hash_set(xattr_hash_desc, hash_info, c,
+ ret = bch2_hash_set(bch2_xattr_hash_desc, hash_info, c,
inum, journal_seq,
&xattr->k_i,
(flags & XATTR_CREATE ? BCH_HASH_SET_MUST_CREATE : 0)|
@@ -225,8 +247,6 @@ int bch2_xattr_set(struct bch_fs *c, struct inode *inode,
&ei->journal_seq);
}
-static const struct xattr_handler *bch2_xattr_type_to_handler(unsigned);
-
static size_t bch2_xattr_emit(struct dentry *dentry,
const struct bch_xattr *xattr,
char *buffer, size_t buffer_size)