diff options
Diffstat (limited to 'libbcachefs/xattr.c')
-rw-r--r-- | libbcachefs/xattr.c | 92 |
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) |