ocfs2: Wrap calculation of name+value pair size.
An ocfs2 xattr entry stores the text name and value as a pair in the storage area. Obviously names and values can be variable-sized. If a value is too large for the entry storage, a tree root is stored instead. The name+value pair is also padded. Because of this, there are a million places in the code that do: if (needs_external_tree(value_size) namevalue_size = pad(name_size) + tree_root_size; else namevalue_size = pad(name_size) + pad(value_size); Let's create some convenience functions to make the code more readable. There are three forms. The first takes the raw sizes. The second takes an ocfs2_xattr_info structure. The third takes an existing ocfs2_xattr_entry. Signed-off-by: Joel Becker <joel.becker@oracle.com>
This commit is contained in:
170
fs/ocfs2/xattr.c
170
fs/ocfs2/xattr.c
@@ -183,6 +183,33 @@ struct ocfs2_xa_loc {
|
|||||||
const struct ocfs2_xa_loc_operations *xl_ops;
|
const struct ocfs2_xa_loc_operations *xl_ops;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Convenience functions to calculate how much space is needed for a
|
||||||
|
* given name+value pair
|
||||||
|
*/
|
||||||
|
static int namevalue_size(int name_len, uint64_t value_len)
|
||||||
|
{
|
||||||
|
if (value_len > OCFS2_XATTR_INLINE_SIZE)
|
||||||
|
return OCFS2_XATTR_SIZE(name_len) + OCFS2_XATTR_ROOT_SIZE;
|
||||||
|
else
|
||||||
|
return OCFS2_XATTR_SIZE(name_len) + OCFS2_XATTR_SIZE(value_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int namevalue_size_xi(struct ocfs2_xattr_info *xi)
|
||||||
|
{
|
||||||
|
return namevalue_size(xi->xi_name_len, xi->xi_value_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int namevalue_size_xe(struct ocfs2_xattr_entry *xe)
|
||||||
|
{
|
||||||
|
u64 value_len = le64_to_cpu(xe->xe_value_size);
|
||||||
|
|
||||||
|
BUG_ON((value_len > OCFS2_XATTR_INLINE_SIZE) &&
|
||||||
|
ocfs2_xattr_is_local(xe));
|
||||||
|
return namevalue_size(xe->xe_name_len, value_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int ocfs2_xattr_bucket_get_name_value(struct super_block *sb,
|
static int ocfs2_xattr_bucket_get_name_value(struct super_block *sb,
|
||||||
struct ocfs2_xattr_header *xh,
|
struct ocfs2_xattr_header *xh,
|
||||||
int index,
|
int index,
|
||||||
@@ -529,15 +556,20 @@ static void ocfs2_xattr_hash_entry(struct inode *inode,
|
|||||||
|
|
||||||
static int ocfs2_xattr_entry_real_size(int name_len, size_t value_len)
|
static int ocfs2_xattr_entry_real_size(int name_len, size_t value_len)
|
||||||
{
|
{
|
||||||
int size = 0;
|
return namevalue_size(name_len, value_len) +
|
||||||
|
sizeof(struct ocfs2_xattr_entry);
|
||||||
|
}
|
||||||
|
|
||||||
if (value_len <= OCFS2_XATTR_INLINE_SIZE)
|
static int ocfs2_xi_entry_usage(struct ocfs2_xattr_info *xi)
|
||||||
size = OCFS2_XATTR_SIZE(name_len) + OCFS2_XATTR_SIZE(value_len);
|
{
|
||||||
else
|
return namevalue_size_xi(xi) +
|
||||||
size = OCFS2_XATTR_SIZE(name_len) + OCFS2_XATTR_ROOT_SIZE;
|
sizeof(struct ocfs2_xattr_entry);
|
||||||
size += sizeof(struct ocfs2_xattr_entry);
|
}
|
||||||
|
|
||||||
return size;
|
static int ocfs2_xe_entry_usage(struct ocfs2_xattr_entry *xe)
|
||||||
|
{
|
||||||
|
return namevalue_size_xe(xe) +
|
||||||
|
sizeof(struct ocfs2_xattr_entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ocfs2_calc_security_init(struct inode *dir,
|
int ocfs2_calc_security_init(struct inode *dir,
|
||||||
@@ -1363,8 +1395,7 @@ static int ocfs2_xattr_cleanup(struct inode *inode,
|
|||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
void *val = xs->base + offs;
|
void *val = xs->base + offs;
|
||||||
size_t size = OCFS2_XATTR_SIZE(xi->xi_name_len) +
|
size_t size = namevalue_size_xi(xi);
|
||||||
OCFS2_XATTR_ROOT_SIZE;
|
|
||||||
|
|
||||||
ret = vb->vb_access(handle, INODE_CACHE(inode), vb->vb_bh,
|
ret = vb->vb_access(handle, INODE_CACHE(inode), vb->vb_bh,
|
||||||
OCFS2_JOURNAL_ACCESS_WRITE);
|
OCFS2_JOURNAL_ACCESS_WRITE);
|
||||||
@@ -1430,8 +1461,7 @@ static int ocfs2_xattr_set_value_outside(struct inode *inode,
|
|||||||
{
|
{
|
||||||
void *val = xs->base + offs;
|
void *val = xs->base + offs;
|
||||||
struct ocfs2_xattr_value_root *xv = NULL;
|
struct ocfs2_xattr_value_root *xv = NULL;
|
||||||
size_t size = OCFS2_XATTR_SIZE(xi->xi_name_len) +
|
size_t size = namevalue_size_xi(xi);
|
||||||
OCFS2_XATTR_ROOT_SIZE;
|
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
memset(val, 0, size);
|
memset(val, 0, size);
|
||||||
@@ -1490,15 +1520,10 @@ static void ocfs2_xa_block_wipe_namevalue(struct ocfs2_xa_loc *loc)
|
|||||||
int namevalue_offset, first_namevalue_offset, namevalue_size;
|
int namevalue_offset, first_namevalue_offset, namevalue_size;
|
||||||
struct ocfs2_xattr_entry *entry = loc->xl_entry;
|
struct ocfs2_xattr_entry *entry = loc->xl_entry;
|
||||||
struct ocfs2_xattr_header *xh = loc->xl_header;
|
struct ocfs2_xattr_header *xh = loc->xl_header;
|
||||||
u64 value_size = le64_to_cpu(entry->xe_value_size);
|
|
||||||
int count = le16_to_cpu(xh->xh_count);
|
int count = le16_to_cpu(xh->xh_count);
|
||||||
|
|
||||||
namevalue_offset = le16_to_cpu(entry->xe_name_offset);
|
namevalue_offset = le16_to_cpu(entry->xe_name_offset);
|
||||||
namevalue_size = OCFS2_XATTR_SIZE(entry->xe_name_len);
|
namevalue_size = namevalue_size_xe(entry);
|
||||||
if (value_size > OCFS2_XATTR_INLINE_SIZE)
|
|
||||||
namevalue_size += OCFS2_XATTR_ROOT_SIZE;
|
|
||||||
else
|
|
||||||
namevalue_size += OCFS2_XATTR_SIZE(value_size);
|
|
||||||
|
|
||||||
for (i = 0, first_namevalue_offset = loc->xl_size;
|
for (i = 0, first_namevalue_offset = loc->xl_size;
|
||||||
i < count; i++) {
|
i < count; i++) {
|
||||||
@@ -1553,17 +1578,8 @@ static void *ocfs2_xa_bucket_offset_pointer(struct ocfs2_xa_loc *loc,
|
|||||||
|
|
||||||
static void ocfs2_xa_bucket_wipe_namevalue(struct ocfs2_xa_loc *loc)
|
static void ocfs2_xa_bucket_wipe_namevalue(struct ocfs2_xa_loc *loc)
|
||||||
{
|
{
|
||||||
int namevalue_size;
|
le16_add_cpu(&loc->xl_header->xh_name_value_len,
|
||||||
struct ocfs2_xattr_entry *entry = loc->xl_entry;
|
-namevalue_size_xe(loc->xl_entry));
|
||||||
u64 value_size = le64_to_cpu(entry->xe_value_size);
|
|
||||||
|
|
||||||
namevalue_size = OCFS2_XATTR_SIZE(entry->xe_name_len);
|
|
||||||
if (value_size > OCFS2_XATTR_INLINE_SIZE)
|
|
||||||
namevalue_size += OCFS2_XATTR_ROOT_SIZE;
|
|
||||||
else
|
|
||||||
namevalue_size += OCFS2_XATTR_SIZE(value_size);
|
|
||||||
|
|
||||||
le16_add_cpu(&loc->xl_header->xh_name_value_len, -namevalue_size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Operations for xattrs stored in buckets. */
|
/* Operations for xattrs stored in buckets. */
|
||||||
@@ -1683,16 +1699,8 @@ static void ocfs2_xattr_set_entry_local(struct inode *inode,
|
|||||||
offs = le16_to_cpu(xs->here->xe_name_offset);
|
offs = le16_to_cpu(xs->here->xe_name_offset);
|
||||||
val = xs->base + offs;
|
val = xs->base + offs;
|
||||||
|
|
||||||
if (le64_to_cpu(xs->here->xe_value_size) >
|
size = namevalue_size_xe(xs->here);
|
||||||
OCFS2_XATTR_INLINE_SIZE)
|
if (xi->xi_value && (size == namevalue_size_xi(xi))) {
|
||||||
size = OCFS2_XATTR_SIZE(xi->xi_name_len) +
|
|
||||||
OCFS2_XATTR_ROOT_SIZE;
|
|
||||||
else
|
|
||||||
size = OCFS2_XATTR_SIZE(xi->xi_name_len) +
|
|
||||||
OCFS2_XATTR_SIZE(le64_to_cpu(xs->here->xe_value_size));
|
|
||||||
|
|
||||||
if (xi->xi_value && size == OCFS2_XATTR_SIZE(xi->xi_name_len) +
|
|
||||||
OCFS2_XATTR_SIZE(xi->xi_value_len)) {
|
|
||||||
/* The old and the new value have the
|
/* The old and the new value have the
|
||||||
same size. Just replace the value. */
|
same size. Just replace the value. */
|
||||||
ocfs2_xattr_set_local(xs->here, 1);
|
ocfs2_xattr_set_local(xs->here, 1);
|
||||||
@@ -1716,8 +1724,7 @@ static void ocfs2_xattr_set_entry_local(struct inode *inode,
|
|||||||
}
|
}
|
||||||
if (xi->xi_value) {
|
if (xi->xi_value) {
|
||||||
/* Insert the new name+value. */
|
/* Insert the new name+value. */
|
||||||
size_t size = OCFS2_XATTR_SIZE(xi->xi_name_len) +
|
size_t size = namevalue_size_xi(xi);
|
||||||
OCFS2_XATTR_SIZE(xi->xi_value_len);
|
|
||||||
void *val = xs->base + min_offs - size;
|
void *val = xs->base + min_offs - size;
|
||||||
|
|
||||||
xs->here->xe_name_offset = cpu_to_le16(min_offs - size);
|
xs->here->xe_name_offset = cpu_to_le16(min_offs - size);
|
||||||
@@ -1788,41 +1795,25 @@ static int ocfs2_xattr_set_entry(struct inode *inode,
|
|||||||
if (free < 0)
|
if (free < 0)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
if (!xs->not_found) {
|
if (!xs->not_found)
|
||||||
size_t size = 0;
|
free += ocfs2_xe_entry_usage(xs->here);
|
||||||
if (ocfs2_xattr_is_local(xs->here))
|
|
||||||
size = OCFS2_XATTR_SIZE(xi->xi_name_len) +
|
|
||||||
OCFS2_XATTR_SIZE(le64_to_cpu(xs->here->xe_value_size));
|
|
||||||
else
|
|
||||||
size = OCFS2_XATTR_SIZE(xi->xi_name_len) +
|
|
||||||
OCFS2_XATTR_ROOT_SIZE;
|
|
||||||
free += (size + sizeof(struct ocfs2_xattr_entry));
|
|
||||||
}
|
|
||||||
/* Check free space in inode or block */
|
/* Check free space in inode or block */
|
||||||
if (xi->xi_value && xi->xi_value_len > OCFS2_XATTR_INLINE_SIZE) {
|
if (xi->xi_value) {
|
||||||
if (free < sizeof(struct ocfs2_xattr_entry) +
|
if (free < ocfs2_xi_entry_usage(xi)) {
|
||||||
OCFS2_XATTR_SIZE(xi->xi_name_len) +
|
|
||||||
OCFS2_XATTR_ROOT_SIZE) {
|
|
||||||
ret = -ENOSPC;
|
ret = -ENOSPC;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
size_l = OCFS2_XATTR_SIZE(xi->xi_name_len) +
|
if (xi->xi_value_len > OCFS2_XATTR_INLINE_SIZE) {
|
||||||
OCFS2_XATTR_ROOT_SIZE;
|
size_l = namevalue_size_xi(xi);
|
||||||
xi_l.xi_value = (void *)&def_xv;
|
xi_l.xi_value = (void *)&def_xv;
|
||||||
xi_l.xi_value_len = OCFS2_XATTR_ROOT_SIZE;
|
xi_l.xi_value_len = OCFS2_XATTR_ROOT_SIZE;
|
||||||
} else if (xi->xi_value) {
|
|
||||||
if (free < sizeof(struct ocfs2_xattr_entry) +
|
|
||||||
OCFS2_XATTR_SIZE(xi->xi_name_len) +
|
|
||||||
OCFS2_XATTR_SIZE(xi->xi_value_len)) {
|
|
||||||
ret = -ENOSPC;
|
|
||||||
goto out;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!xs->not_found) {
|
if (!xs->not_found) {
|
||||||
/* For existing extended attribute */
|
/* For existing extended attribute */
|
||||||
size_t size = OCFS2_XATTR_SIZE(xi->xi_name_len) +
|
size_t size = namevalue_size_xe(xs->here);
|
||||||
OCFS2_XATTR_SIZE(le64_to_cpu(xs->here->xe_value_size));
|
|
||||||
size_t offs = le16_to_cpu(xs->here->xe_name_offset);
|
size_t offs = le16_to_cpu(xs->here->xe_name_offset);
|
||||||
void *val = xs->base + offs;
|
void *val = xs->base + offs;
|
||||||
|
|
||||||
@@ -2589,7 +2580,6 @@ static int ocfs2_xattr_can_be_in_inode(struct inode *inode,
|
|||||||
struct ocfs2_xattr_info *xi,
|
struct ocfs2_xattr_info *xi,
|
||||||
struct ocfs2_xattr_search *xs)
|
struct ocfs2_xattr_search *xs)
|
||||||
{
|
{
|
||||||
u64 value_size;
|
|
||||||
struct ocfs2_xattr_entry *last;
|
struct ocfs2_xattr_entry *last;
|
||||||
int free, i;
|
int free, i;
|
||||||
size_t min_offs = xs->end - xs->base;
|
size_t min_offs = xs->end - xs->base;
|
||||||
@@ -2612,13 +2602,7 @@ static int ocfs2_xattr_can_be_in_inode(struct inode *inode,
|
|||||||
|
|
||||||
BUG_ON(!xs->not_found);
|
BUG_ON(!xs->not_found);
|
||||||
|
|
||||||
if (xi->xi_value_len > OCFS2_XATTR_INLINE_SIZE)
|
if (free >= (sizeof(struct ocfs2_xattr_entry) + namevalue_size_xi(xi)))
|
||||||
value_size = OCFS2_XATTR_ROOT_SIZE;
|
|
||||||
else
|
|
||||||
value_size = OCFS2_XATTR_SIZE(xi->xi_value_len);
|
|
||||||
|
|
||||||
if (free >= sizeof(struct ocfs2_xattr_entry) +
|
|
||||||
OCFS2_XATTR_SIZE(xi->xi_name_len) + value_size)
|
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -3980,7 +3964,7 @@ static int ocfs2_defrag_xattr_bucket(struct inode *inode,
|
|||||||
struct ocfs2_xattr_bucket *bucket)
|
struct ocfs2_xattr_bucket *bucket)
|
||||||
{
|
{
|
||||||
int ret, i;
|
int ret, i;
|
||||||
size_t end, offset, len, value_len;
|
size_t end, offset, len;
|
||||||
struct ocfs2_xattr_header *xh;
|
struct ocfs2_xattr_header *xh;
|
||||||
char *entries, *buf, *bucket_buf = NULL;
|
char *entries, *buf, *bucket_buf = NULL;
|
||||||
u64 blkno = bucket_blkno(bucket);
|
u64 blkno = bucket_blkno(bucket);
|
||||||
@@ -4034,12 +4018,7 @@ static int ocfs2_defrag_xattr_bucket(struct inode *inode,
|
|||||||
end = OCFS2_XATTR_BUCKET_SIZE;
|
end = OCFS2_XATTR_BUCKET_SIZE;
|
||||||
for (i = 0; i < le16_to_cpu(xh->xh_count); i++, xe++) {
|
for (i = 0; i < le16_to_cpu(xh->xh_count); i++, xe++) {
|
||||||
offset = le16_to_cpu(xe->xe_name_offset);
|
offset = le16_to_cpu(xe->xe_name_offset);
|
||||||
if (ocfs2_xattr_is_local(xe))
|
len = namevalue_size_xe(xe);
|
||||||
value_len = OCFS2_XATTR_SIZE(
|
|
||||||
le64_to_cpu(xe->xe_value_size));
|
|
||||||
else
|
|
||||||
value_len = OCFS2_XATTR_ROOT_SIZE;
|
|
||||||
len = OCFS2_XATTR_SIZE(xe->xe_name_len) + value_len;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We must make sure that the name/value pair
|
* We must make sure that the name/value pair
|
||||||
@@ -4228,7 +4207,7 @@ static int ocfs2_divide_xattr_bucket(struct inode *inode,
|
|||||||
int new_bucket_head)
|
int new_bucket_head)
|
||||||
{
|
{
|
||||||
int ret, i;
|
int ret, i;
|
||||||
int count, start, len, name_value_len = 0, xe_len, name_offset = 0;
|
int count, start, len, name_value_len = 0, name_offset = 0;
|
||||||
struct ocfs2_xattr_bucket *s_bucket = NULL, *t_bucket = NULL;
|
struct ocfs2_xattr_bucket *s_bucket = NULL, *t_bucket = NULL;
|
||||||
struct ocfs2_xattr_header *xh;
|
struct ocfs2_xattr_header *xh;
|
||||||
struct ocfs2_xattr_entry *xe;
|
struct ocfs2_xattr_entry *xe;
|
||||||
@@ -4319,13 +4298,7 @@ static int ocfs2_divide_xattr_bucket(struct inode *inode,
|
|||||||
name_value_len = 0;
|
name_value_len = 0;
|
||||||
for (i = 0; i < start; i++) {
|
for (i = 0; i < start; i++) {
|
||||||
xe = &xh->xh_entries[i];
|
xe = &xh->xh_entries[i];
|
||||||
xe_len = OCFS2_XATTR_SIZE(xe->xe_name_len);
|
name_value_len += namevalue_size_xe(xe);
|
||||||
if (ocfs2_xattr_is_local(xe))
|
|
||||||
xe_len +=
|
|
||||||
OCFS2_XATTR_SIZE(le64_to_cpu(xe->xe_value_size));
|
|
||||||
else
|
|
||||||
xe_len += OCFS2_XATTR_ROOT_SIZE;
|
|
||||||
name_value_len += xe_len;
|
|
||||||
if (le16_to_cpu(xe->xe_name_offset) < name_offset)
|
if (le16_to_cpu(xe->xe_name_offset) < name_offset)
|
||||||
name_offset = le16_to_cpu(xe->xe_name_offset);
|
name_offset = le16_to_cpu(xe->xe_name_offset);
|
||||||
}
|
}
|
||||||
@@ -4355,12 +4328,6 @@ static int ocfs2_divide_xattr_bucket(struct inode *inode,
|
|||||||
xh->xh_free_start = cpu_to_le16(OCFS2_XATTR_BUCKET_SIZE);
|
xh->xh_free_start = cpu_to_le16(OCFS2_XATTR_BUCKET_SIZE);
|
||||||
for (i = 0; i < le16_to_cpu(xh->xh_count); i++) {
|
for (i = 0; i < le16_to_cpu(xh->xh_count); i++) {
|
||||||
xe = &xh->xh_entries[i];
|
xe = &xh->xh_entries[i];
|
||||||
xe_len = OCFS2_XATTR_SIZE(xe->xe_name_len);
|
|
||||||
if (ocfs2_xattr_is_local(xe))
|
|
||||||
xe_len +=
|
|
||||||
OCFS2_XATTR_SIZE(le64_to_cpu(xe->xe_value_size));
|
|
||||||
else
|
|
||||||
xe_len += OCFS2_XATTR_ROOT_SIZE;
|
|
||||||
if (le16_to_cpu(xe->xe_name_offset) <
|
if (le16_to_cpu(xe->xe_name_offset) <
|
||||||
le16_to_cpu(xh->xh_free_start))
|
le16_to_cpu(xh->xh_free_start))
|
||||||
xh->xh_free_start = xe->xe_name_offset;
|
xh->xh_free_start = xe->xe_name_offset;
|
||||||
@@ -4997,12 +4964,7 @@ static void ocfs2_xattr_set_entry_normal(struct inode *inode,
|
|||||||
if (!xs->not_found) {
|
if (!xs->not_found) {
|
||||||
xe = xs->here;
|
xe = xs->here;
|
||||||
offs = le16_to_cpu(xe->xe_name_offset);
|
offs = le16_to_cpu(xe->xe_name_offset);
|
||||||
if (ocfs2_xattr_is_local(xe))
|
size = namevalue_size_xe(xe);
|
||||||
size = OCFS2_XATTR_SIZE(xi->xi_name_len) +
|
|
||||||
OCFS2_XATTR_SIZE(le64_to_cpu(xe->xe_value_size));
|
|
||||||
else
|
|
||||||
size = OCFS2_XATTR_SIZE(xi->xi_name_len) +
|
|
||||||
OCFS2_XATTR_SIZE(OCFS2_XATTR_ROOT_SIZE);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the new value will be stored outside, xi->xi_value has
|
* If the new value will be stored outside, xi->xi_value has
|
||||||
@@ -5011,8 +4973,7 @@ static void ocfs2_xattr_set_entry_normal(struct inode *inode,
|
|||||||
* new_size safely here.
|
* new_size safely here.
|
||||||
* See ocfs2_xattr_set_in_bucket.
|
* See ocfs2_xattr_set_in_bucket.
|
||||||
*/
|
*/
|
||||||
new_size = OCFS2_XATTR_SIZE(xi->xi_name_len) +
|
new_size = namevalue_size_xi(xi);
|
||||||
OCFS2_XATTR_SIZE(xi->xi_value_len);
|
|
||||||
|
|
||||||
if (xi->xi_value) {
|
if (xi->xi_value) {
|
||||||
ocfs2_xa_wipe_namevalue(&loc);
|
ocfs2_xa_wipe_namevalue(&loc);
|
||||||
@@ -5078,8 +5039,7 @@ static void ocfs2_xattr_set_entry_normal(struct inode *inode,
|
|||||||
|
|
||||||
set_new_name_value:
|
set_new_name_value:
|
||||||
/* Insert the new name+value. */
|
/* Insert the new name+value. */
|
||||||
size = OCFS2_XATTR_SIZE(xi->xi_name_len) +
|
size = namevalue_size_xi(xi);
|
||||||
OCFS2_XATTR_SIZE(xi->xi_value_len);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We must make sure that the name/value pair
|
* We must make sure that the name/value pair
|
||||||
|
Reference in New Issue
Block a user