#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;
-};
-
-#define X_SEARCH(_type, _name, _len) ((struct xattr_search_key) \
- { .type = _type, .name = QSTR_INIT(_name, _len) })
-
static u64 bch2_xattr_hash(const struct bch_hash_info *info,
const struct xattr_search_key *key)
{
{
const struct xattr_handler *handler;
struct bkey_s_c_xattr xattr;
- unsigned u64s;
switch (k.k->type) {
case 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)
+ if (bkey_val_u64s(k.k) <
+ xattr_val_u64s(xattr.v->x_name_len,
+ le16_to_cpu(xattr.v->x_val_len)))
return "value too small";
- if (bkey_val_u64s(k.k) > u64s)
+ if (bkey_val_u64s(k.k) >
+ xattr_val_u64s(xattr.v->x_name_len,
+ le16_to_cpu(xattr.v->x_val_len) + 4))
return "value too big";
handler = bch2_xattr_type_to_handler(xattr.v->x_type);
}
}
-void bch2_xattr_to_text(struct bch_fs *c, char *buf,
- size_t size, struct bkey_s_c k)
+int bch2_xattr_to_text(struct bch_fs *c, char *buf,
+ size_t size, struct bkey_s_c k)
{
+ char *out = buf, *end = buf + size;
const struct xattr_handler *handler;
struct bkey_s_c_xattr xattr;
- size_t n = 0;
switch (k.k->type) {
case BCH_XATTR:
handler = bch2_xattr_type_to_handler(xattr.v->x_type);
if (handler && handler->prefix)
- n += scnprintf(buf + n, size - n, "%s", handler->prefix);
+ out += scnprintf(out, end - out, "%s", handler->prefix);
else if (handler)
- n += scnprintf(buf + n, size - n, "(type %u)",
- xattr.v->x_type);
+ out += scnprintf(out, end - out, "(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));
+ out += scnprintf(out, end - out, "(unknown type %u)",
+ xattr.v->x_type);
+
+ out += bch_scnmemcpy(out, end - out, xattr.v->x_name,
+ xattr.v->x_name_len);
+ out += scnprintf(out, end - out, ":");
+ out += bch_scnmemcpy(out, end - out, xattr_val(xattr.v),
+ le16_to_cpu(xattr.v->x_val_len));
break;
case BCH_XATTR_WHITEOUT:
- scnprintf(buf, size, "whiteout");
+ out += scnprintf(out, end - out, "whiteout");
break;
}
+
+ return out - buf;
}
int bch2_xattr_get(struct bch_fs *c, struct bch_inode_info *inode,
- const char *name, void *buffer, size_t size, int type)
+ const char *name, void *buffer, size_t size, int type)
{
- struct btree_iter iter;
- struct bkey_s_c k;
+ struct btree_trans trans;
+ struct btree_iter *iter;
struct bkey_s_c_xattr xattr;
int ret;
- k = bch2_hash_lookup(bch2_xattr_hash_desc, &inode->ei_str_hash, c,
- inode->v.i_ino, &iter,
- &X_SEARCH(type, name, strlen(name)));
- if (IS_ERR(k.k))
- return bch2_btree_iter_unlock(&iter) ?: -ENODATA;
+ bch2_trans_init(&trans, c);
+
+ iter = bch2_hash_lookup(&trans, bch2_xattr_hash_desc,
+ &inode->ei_str_hash, inode->v.i_ino,
+ &X_SEARCH(type, name, strlen(name)),
+ 0);
+ if (IS_ERR(iter)) {
+ bch2_trans_exit(&trans);
+ BUG_ON(PTR_ERR(iter) == -EINTR);
+
+ return PTR_ERR(iter) == -ENOENT ? -ENODATA : PTR_ERR(iter);
+ }
- xattr = bkey_s_c_to_xattr(k);
+ xattr = bkey_s_c_to_xattr(bch2_btree_iter_peek_slot(iter));
ret = le16_to_cpu(xattr.v->x_val_len);
if (buffer) {
if (ret > size)
memcpy(buffer, xattr_val(xattr.v), ret);
}
- bch2_btree_iter_unlock(&iter);
+ bch2_trans_exit(&trans);
return ret;
}
-int __bch2_xattr_set(struct bch_fs *c, u64 inum,
- const struct bch_hash_info *hash_info,
- const char *name, const void *value, size_t size,
- int flags, int type, u64 *journal_seq)
+int bch2_xattr_set(struct btree_trans *trans, u64 inum,
+ const struct bch_hash_info *hash_info,
+ const char *name, const void *value, size_t size,
+ int type, int flags)
{
- struct xattr_search_key search = X_SEARCH(type, name, strlen(name));
int ret;
- if (!value) {
- ret = bch2_hash_delete(bch2_xattr_hash_desc, hash_info,
- c, inum,
- journal_seq, &search);
- } else {
+ if (value) {
struct bkey_i_xattr *xattr;
+ unsigned namelen = strlen(name);
unsigned u64s = BKEY_U64s +
- xattr_val_u64s(search.name.len, size);
+ xattr_val_u64s(namelen, size);
if (u64s > U8_MAX)
return -ERANGE;
- xattr = kmalloc(u64s * sizeof(u64), GFP_NOFS);
- if (!xattr)
- return -ENOMEM;
+ xattr = bch2_trans_kmalloc(trans, u64s * sizeof(u64));
+ if (IS_ERR(xattr))
+ return PTR_ERR(xattr);
bkey_xattr_init(&xattr->k_i);
xattr->k.u64s = u64s;
xattr->v.x_type = type;
- xattr->v.x_name_len = search.name.len;
+ xattr->v.x_name_len = namelen;
xattr->v.x_val_len = cpu_to_le16(size);
- memcpy(xattr->v.x_name, search.name.name, search.name.len);
+ memcpy(xattr->v.x_name, name, namelen);
memcpy(xattr_val(&xattr->v), value, size);
- 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)|
- (flags & XATTR_REPLACE ? BCH_HASH_SET_MUST_REPLACE : 0));
- kfree(xattr);
+ ret = __bch2_hash_set(trans, bch2_xattr_hash_desc, hash_info,
+ inum, &xattr->k_i,
+ (flags & XATTR_CREATE ? BCH_HASH_SET_MUST_CREATE : 0)|
+ (flags & XATTR_REPLACE ? BCH_HASH_SET_MUST_REPLACE : 0));
+ } else {
+ struct xattr_search_key search =
+ X_SEARCH(type, name, strlen(name));
+
+ ret = bch2_hash_delete(trans, bch2_xattr_hash_desc,
+ hash_info, inum, &search);
}
if (ret == -ENOENT)
return ret;
}
-int bch2_xattr_set(struct bch_fs *c, struct bch_inode_info *inode,
- const char *name, const void *value, size_t size,
- int flags, int type)
-{
- return __bch2_xattr_set(c, inode->v.i_ino, &inode->ei_str_hash,
- name, value, size, flags, type,
- &inode->ei_journal_seq);
-}
-
static size_t bch2_xattr_emit(struct dentry *dentry,
const struct bch_xattr *xattr,
char *buffer, size_t buffer_size)
struct bch_inode_info *inode = to_bch_ei(vinode);
struct bch_fs *c = inode->v.i_sb->s_fs_info;
- return bch2_xattr_set(c, inode, name, value, size, flags,
- handler->flags);
+ return bch2_trans_do(c, &inode->ei_journal_seq, BTREE_INSERT_ATOMIC,
+ bch2_xattr_set(&trans, inode->v.i_ino,
+ &inode->ei_str_hash,
+ name, value, size,
+ handler->flags, flags));
}
static const struct xattr_handler bch_xattr_user_handler = {
}
mutex_lock(&inode->ei_update_lock);
- ret = __bch2_write_inode(c, inode, inode_opt_set_fn, &s);
+ ret = bch2_write_inode(c, inode, inode_opt_set_fn, &s, 0);
mutex_unlock(&inode->ei_update_lock);
if (value &&