diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c index 945ca697eb2..22a60a7c35c 100644 --- a/fs/ocfs2/xattr.c +++ b/fs/ocfs2/xattr.c @@ -1573,7 +1573,29 @@ static const struct ocfs2_xa_loc_operations ocfs2_xa_bucket_loc_ops = { static void ocfs2_xa_remove_entry(struct ocfs2_xa_loc *loc) { + int index, count; + struct ocfs2_xattr_header *xh = loc->xl_header; + struct ocfs2_xattr_entry *entry = loc->xl_entry; + ocfs2_xa_wipe_namevalue(loc); + loc->xl_entry = NULL; + + le16_add_cpu(&xh->xh_count, -1); + count = le16_to_cpu(xh->xh_count); + + /* + * Only zero out the entry if there are more remaining. This is + * important for an empty bucket, as it keeps track of the + * bucket's hash value. It doesn't hurt empty block storage. + */ + if (count) { + index = ((char *)entry - (char *)&xh->xh_entries) / + sizeof(struct ocfs2_xattr_entry); + memmove(&xh->xh_entries[index], &xh->xh_entries[index + 1], + (count - index) * sizeof(struct ocfs2_xattr_entry)); + memset(&xh->xh_entries[count], 0, + sizeof(struct ocfs2_xattr_entry)); + } } static void ocfs2_init_dinode_xa_loc(struct ocfs2_xa_loc *loc, @@ -1638,7 +1660,6 @@ static void ocfs2_xattr_set_entry_local(struct inode *inode, size_t min_offs) { size_t name_len = strlen(xi->name); - int i; struct ocfs2_xa_loc loc; if (xs->xattr_bh == xs->inode_bh) @@ -1686,25 +1707,12 @@ static void ocfs2_xattr_set_entry_local(struct inode *inode, return; } - /* Remove the old name+value. */ - 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; + if (!xi->value) + ocfs2_xa_remove_entry(&loc); + else + ocfs2_xa_wipe_namevalue(&loc); min_offs += size; - - if (!xi->value) { - /* Remove the old entry. */ - 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)); - } } if (xi->value) { /* Insert the new name+value. */ @@ -5001,8 +5009,8 @@ static void ocfs2_xattr_set_entry_normal(struct inode *inode, new_size = OCFS2_XATTR_SIZE(name_len) + OCFS2_XATTR_SIZE(xi->value_len); - ocfs2_xa_wipe_namevalue(&loc); if (xi->value) { + ocfs2_xa_wipe_namevalue(&loc); if (new_size > size) goto set_new_name_value; @@ -5024,20 +5032,8 @@ static void ocfs2_xattr_set_entry_normal(struct inode *inode, ocfs2_xattr_set_local(xe, local); return; } else { - /* - * Remove the old entry if there is more than one. - * We don't remove the last entry so that we can - * use it to indicate the hash value of the empty - * bucket. - */ - last -= 1; - le16_add_cpu(&xh->xh_count, -1); - if (xh->xh_count) { - memmove(xe, xe + 1, - (void *)last - (void *)xe); - memset(last, 0, - sizeof(struct ocfs2_xattr_entry)); - } else + ocfs2_xa_remove_entry(&loc); + if (!xh->xh_count) xh->xh_free_start = cpu_to_le16(OCFS2_XATTR_BUCKET_SIZE);