Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 185435
b: refs/heads/master
c: 11179f2
h: refs/heads/master
i:
  185433: 5562112
  185431: ead4a02
v: v3
  • Loading branch information
Joel Becker committed Feb 26, 2010
1 parent 0682c4d commit 7549ebe
Show file tree
Hide file tree
Showing 2 changed files with 227 additions and 16 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 8545e03d82b6739461bbd60db7aba144f7dbe80f
refs/heads/master: 11179f2c92cb025b1ff0b794f9714b3fb395855f
241 changes: 226 additions & 15 deletions trunk/fs/ocfs2/xattr.c
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,51 @@ struct ocfs2_xattr_search {
int not_found;
};

/* Operations on struct ocfs2_xa_entry */
struct ocfs2_xa_loc;
struct ocfs2_xa_loc_operations {
/*
* Return a pointer to the appropriate buffer in loc->xl_storage
* at the given offset from loc->xl_header.
*/
void *(*xlo_offset_pointer)(struct ocfs2_xa_loc *loc, int offset);

/*
* Remove the name+value at this location. Do whatever is
* appropriate with the remaining name+value pairs.
*/
void (*xlo_wipe_namevalue)(struct ocfs2_xa_loc *loc);
};

/*
* Describes an xattr entry location. This is a memory structure
* tracking the on-disk structure.
*/
struct ocfs2_xa_loc {
/* The ocfs2_xattr_header inside the on-disk storage. Not NULL. */
struct ocfs2_xattr_header *xl_header;

/* Bytes from xl_header to the end of the storage */
int xl_size;

/*
* The ocfs2_xattr_entry this location describes. If this is
* NULL, this location describes the on-disk structure where it
* would have been.
*/
struct ocfs2_xattr_entry *xl_entry;

/*
* Internal housekeeping
*/

/* Buffer(s) containing this entry */
void *xl_storage;

/* Operations on the storage backing this location */
const struct ocfs2_xa_loc_operations *xl_ops;
};

static int ocfs2_xattr_bucket_get_name_value(struct super_block *sb,
struct ocfs2_xattr_header *xh,
int index,
Expand Down Expand Up @@ -1417,6 +1462,170 @@ static int ocfs2_xattr_set_value_outside(struct inode *inode,
return ret;
}

/*
* Wipe the name+value pair and allow the storage to reclaim it. This
* must be followed by either removal of the entry or a call to
* ocfs2_xa_add_namevalue().
*/
static void ocfs2_xa_wipe_namevalue(struct ocfs2_xa_loc *loc)
{
loc->xl_ops->xlo_wipe_namevalue(loc);
}

static void *ocfs2_xa_block_offset_pointer(struct ocfs2_xa_loc *loc,
int offset)
{
BUG_ON(offset >= loc->xl_size);
return (char *)loc->xl_header + offset;
}

/*
* Block storage for xattrs keeps the name+value pairs compacted. When
* we remove one, we have to shift any that preceded it towards the end.
*/
static void ocfs2_xa_block_wipe_namevalue(struct ocfs2_xa_loc *loc)
{
int i, offset;
int namevalue_offset, first_namevalue_offset, namevalue_size;
struct ocfs2_xattr_entry *entry = loc->xl_entry;
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);

namevalue_offset = le16_to_cpu(entry->xe_name_offset);
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);

for (i = 0, first_namevalue_offset = loc->xl_size;
i < count; i++) {
offset = le16_to_cpu(xh->xh_entries[i].xe_name_offset);
if (offset < first_namevalue_offset)
first_namevalue_offset = offset;
}

/* Shift the name+value pairs */
memmove((char *)xh + first_namevalue_offset + namevalue_size,
(char *)xh + first_namevalue_offset,
namevalue_offset - first_namevalue_offset);
memset((char *)xh + first_namevalue_offset, 0, namevalue_size);

/* Now tell xh->xh_entries about it */
for (i = 0; i < count; i++) {
offset = le16_to_cpu(xh->xh_entries[i].xe_name_offset);
if (offset < namevalue_offset)
le16_add_cpu(&xh->xh_entries[i].xe_name_offset,
namevalue_size);
}

/*
* Note that we don't update xh_free_start or xh_name_value_len
* because they're not used in block-stored xattrs.
*/
}

/*
* Operations for xattrs stored in blocks. This includes inline inode
* storage and unindexed ocfs2_xattr_blocks.
*/
static const struct ocfs2_xa_loc_operations ocfs2_xa_block_loc_ops = {
.xlo_offset_pointer = ocfs2_xa_block_offset_pointer,
.xlo_wipe_namevalue = ocfs2_xa_block_wipe_namevalue,
};

static void *ocfs2_xa_bucket_offset_pointer(struct ocfs2_xa_loc *loc,
int offset)
{
struct ocfs2_xattr_bucket *bucket = loc->xl_storage;
int block, block_offset;

BUG_ON(offset >= OCFS2_XATTR_BUCKET_SIZE);

/* The header is at the front of the bucket */
block = offset >> bucket->bu_inode->i_sb->s_blocksize_bits;
block_offset = offset % bucket->bu_inode->i_sb->s_blocksize;

return bucket_block(bucket, block) + block_offset;
}

static void ocfs2_xa_bucket_wipe_namevalue(struct ocfs2_xa_loc *loc)
{
int namevalue_size;
struct ocfs2_xattr_entry *entry = 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. */
static const struct ocfs2_xa_loc_operations ocfs2_xa_bucket_loc_ops = {
.xlo_offset_pointer = ocfs2_xa_bucket_offset_pointer,
.xlo_wipe_namevalue = ocfs2_xa_bucket_wipe_namevalue,
};

static void ocfs2_xa_remove_entry(struct ocfs2_xa_loc *loc)
{
ocfs2_xa_wipe_namevalue(loc);
}

static void ocfs2_init_dinode_xa_loc(struct ocfs2_xa_loc *loc,
struct inode *inode,
struct buffer_head *bh,
struct ocfs2_xattr_entry *entry)
{
struct ocfs2_dinode *di = (struct ocfs2_dinode *)bh->b_data;

loc->xl_ops = &ocfs2_xa_block_loc_ops;
loc->xl_storage = bh;
loc->xl_entry = entry;

if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_XATTR_FL)
loc->xl_size = le16_to_cpu(di->i_xattr_inline_size);
else {
BUG_ON(entry);
loc->xl_size = OCFS2_SB(inode->i_sb)->s_xattr_inline_size;
}
loc->xl_header =
(struct ocfs2_xattr_header *)(bh->b_data + bh->b_size -
loc->xl_size);
}

static void ocfs2_init_xattr_block_xa_loc(struct ocfs2_xa_loc *loc,
struct buffer_head *bh,
struct ocfs2_xattr_entry *entry)
{
struct ocfs2_xattr_block *xb =
(struct ocfs2_xattr_block *)bh->b_data;

BUG_ON(le16_to_cpu(xb->xb_flags) & OCFS2_XATTR_INDEXED);

loc->xl_ops = &ocfs2_xa_block_loc_ops;
loc->xl_storage = bh;
loc->xl_header = &(xb->xb_attrs.xb_header);
loc->xl_entry = entry;
loc->xl_size = bh->b_size - offsetof(struct ocfs2_xattr_block,
xb_attrs.xb_header);
}

static void ocfs2_init_xattr_bucket_xa_loc(struct ocfs2_xa_loc *loc,
struct ocfs2_xattr_bucket *bucket,
struct ocfs2_xattr_entry *entry)
{
loc->xl_ops = &ocfs2_xa_bucket_loc_ops;
loc->xl_storage = bucket;
loc->xl_header = bucket_xh(bucket);
loc->xl_entry = entry;
loc->xl_size = OCFS2_XATTR_BUCKET_SIZE;
}

/*
* ocfs2_xattr_set_entry_local()
*
Expand All @@ -1430,7 +1639,14 @@ static void ocfs2_xattr_set_entry_local(struct inode *inode,
{
size_t name_len = strlen(xi->name);
int i;
struct ocfs2_xa_loc loc;

if (xs->xattr_bh == xs->inode_bh)
ocfs2_init_dinode_xa_loc(&loc, inode, xs->inode_bh,
xs->not_found ? NULL : xs->here);
else
ocfs2_init_xattr_block_xa_loc(&loc, xs->xattr_bh,
xs->not_found ? NULL : xs->here);
if (xi->value && xs->not_found) {
/* Insert the new xattr entry. */
le16_add_cpu(&xs->header->xh_count, 1);
Expand Down Expand Up @@ -1469,33 +1685,25 @@ static void ocfs2_xattr_set_entry_local(struct inode *inode,
xi->value_len);
return;
}

/* Remove the old name+value. */
memmove(first_val + size, first_val, val - first_val);
memset(first_val, 0, size);
ocfs2_xa_wipe_namevalue(&loc);
xs->here->xe_name_hash = 0;
xs->here->xe_name_offset = 0;
ocfs2_xattr_set_local(xs->here, 1);
xs->here->xe_value_size = 0;

min_offs += size;

/* Adjust all value offsets. */
last = xs->header->xh_entries;
for (i = 0 ; i < le16_to_cpu(xs->header->xh_count); i++) {
size_t o = le16_to_cpu(last->xe_name_offset);

if (o < offs)
last->xe_name_offset = cpu_to_le16(o + size);
last += 1;
}

if (!xi->value) {
/* Remove the old entry. */
last -= 1;
i = le16_to_cpu(xs->header->xh_count) - 1;
last = &xs->header->xh_entries[i];
xs->header->xh_count = cpu_to_le16(i);

memmove(xs->here, xs->here + 1,
(void *)last - (void *)xs->here);
memset(last, 0, sizeof(struct ocfs2_xattr_entry));
le16_add_cpu(&xs->header->xh_count, -1);
}
}
if (xi->value) {
Expand Down Expand Up @@ -4769,7 +4977,10 @@ static void ocfs2_xattr_set_entry_normal(struct inode *inode,
size_t blocksize = inode->i_sb->s_blocksize;
char *val;
size_t offs, size, new_size;
struct ocfs2_xa_loc loc;

ocfs2_init_xattr_bucket_xa_loc(&loc, xs->bucket,
xs->not_found ? NULL : xs->here);
last = &xh->xh_entries[count];
if (!xs->not_found) {
xe = xs->here;
Expand All @@ -4790,7 +5001,7 @@ static void ocfs2_xattr_set_entry_normal(struct inode *inode,
new_size = OCFS2_XATTR_SIZE(name_len) +
OCFS2_XATTR_SIZE(xi->value_len);

le16_add_cpu(&xh->xh_name_value_len, -size);
ocfs2_xa_wipe_namevalue(&loc);
if (xi->value) {
if (new_size > size)
goto set_new_name_value;
Expand Down

0 comments on commit 7549ebe

Please sign in to comment.