aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/ocfs2/xattr.c241
1 files changed, 226 insertions, 15 deletions
diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c
index 8ae4e5d1f730..945ca697eb25 100644
--- a/fs/ocfs2/xattr.c
+++ b/fs/ocfs2/xattr.c
@@ -137,6 +137,51 @@ struct ocfs2_xattr_search {
137 int not_found; 137 int not_found;
138}; 138};
139 139
140/* Operations on struct ocfs2_xa_entry */
141struct ocfs2_xa_loc;
142struct ocfs2_xa_loc_operations {
143 /*
144 * Return a pointer to the appropriate buffer in loc->xl_storage
145 * at the given offset from loc->xl_header.
146 */
147 void *(*xlo_offset_pointer)(struct ocfs2_xa_loc *loc, int offset);
148
149 /*
150 * Remove the name+value at this location. Do whatever is
151 * appropriate with the remaining name+value pairs.
152 */
153 void (*xlo_wipe_namevalue)(struct ocfs2_xa_loc *loc);
154};
155
156/*
157 * Describes an xattr entry location. This is a memory structure
158 * tracking the on-disk structure.
159 */
160struct ocfs2_xa_loc {
161 /* The ocfs2_xattr_header inside the on-disk storage. Not NULL. */
162 struct ocfs2_xattr_header *xl_header;
163
164 /* Bytes from xl_header to the end of the storage */
165 int xl_size;
166
167 /*
168 * The ocfs2_xattr_entry this location describes. If this is
169 * NULL, this location describes the on-disk structure where it
170 * would have been.
171 */
172 struct ocfs2_xattr_entry *xl_entry;
173
174 /*
175 * Internal housekeeping
176 */
177
178 /* Buffer(s) containing this entry */
179 void *xl_storage;
180
181 /* Operations on the storage backing this location */
182 const struct ocfs2_xa_loc_operations *xl_ops;
183};
184
140static int ocfs2_xattr_bucket_get_name_value(struct super_block *sb, 185static int ocfs2_xattr_bucket_get_name_value(struct super_block *sb,
141 struct ocfs2_xattr_header *xh, 186 struct ocfs2_xattr_header *xh,
142 int index, 187 int index,
@@ -1418,6 +1463,170 @@ static int ocfs2_xattr_set_value_outside(struct inode *inode,
1418} 1463}
1419 1464
1420/* 1465/*
1466 * Wipe the name+value pair and allow the storage to reclaim it. This
1467 * must be followed by either removal of the entry or a call to
1468 * ocfs2_xa_add_namevalue().
1469 */
1470static void ocfs2_xa_wipe_namevalue(struct ocfs2_xa_loc *loc)
1471{
1472 loc->xl_ops->xlo_wipe_namevalue(loc);
1473}
1474
1475static void *ocfs2_xa_block_offset_pointer(struct ocfs2_xa_loc *loc,
1476 int offset)
1477{
1478 BUG_ON(offset >= loc->xl_size);
1479 return (char *)loc->xl_header + offset;
1480}
1481
1482/*
1483 * Block storage for xattrs keeps the name+value pairs compacted. When
1484 * we remove one, we have to shift any that preceded it towards the end.
1485 */
1486static void ocfs2_xa_block_wipe_namevalue(struct ocfs2_xa_loc *loc)
1487{
1488 int i, offset;
1489 int namevalue_offset, first_namevalue_offset, namevalue_size;
1490 struct ocfs2_xattr_entry *entry = loc->xl_entry;
1491 struct ocfs2_xattr_header *xh = loc->xl_header;
1492 u64 value_size = le64_to_cpu(entry->xe_value_size);
1493 int count = le16_to_cpu(xh->xh_count);
1494
1495 namevalue_offset = le16_to_cpu(entry->xe_name_offset);
1496 namevalue_size = OCFS2_XATTR_SIZE(entry->xe_name_len);
1497 if (value_size > OCFS2_XATTR_INLINE_SIZE)
1498 namevalue_size += OCFS2_XATTR_ROOT_SIZE;
1499 else
1500 namevalue_size += OCFS2_XATTR_SIZE(value_size);
1501
1502 for (i = 0, first_namevalue_offset = loc->xl_size;
1503 i < count; i++) {
1504 offset = le16_to_cpu(xh->xh_entries[i].xe_name_offset);
1505 if (offset < first_namevalue_offset)
1506 first_namevalue_offset = offset;
1507 }
1508
1509 /* Shift the name+value pairs */
1510 memmove((char *)xh + first_namevalue_offset + namevalue_size,
1511 (char *)xh + first_namevalue_offset,
1512 namevalue_offset - first_namevalue_offset);
1513 memset((char *)xh + first_namevalue_offset, 0, namevalue_size);
1514
1515 /* Now tell xh->xh_entries about it */
1516 for (i = 0; i < count; i++) {
1517 offset = le16_to_cpu(xh->xh_entries[i].xe_name_offset);
1518 if (offset < namevalue_offset)
1519 le16_add_cpu(&xh->xh_entries[i].xe_name_offset,
1520 namevalue_size);
1521 }
1522
1523 /*
1524 * Note that we don't update xh_free_start or xh_name_value_len
1525 * because they're not used in block-stored xattrs.
1526 */
1527}
1528
1529/*
1530 * Operations for xattrs stored in blocks. This includes inline inode
1531 * storage and unindexed ocfs2_xattr_blocks.
1532 */
1533static const struct ocfs2_xa_loc_operations ocfs2_xa_block_loc_ops = {
1534 .xlo_offset_pointer = ocfs2_xa_block_offset_pointer,
1535 .xlo_wipe_namevalue = ocfs2_xa_block_wipe_namevalue,
1536};
1537
1538static void *ocfs2_xa_bucket_offset_pointer(struct ocfs2_xa_loc *loc,
1539 int offset)
1540{
1541 struct ocfs2_xattr_bucket *bucket = loc->xl_storage;
1542 int block, block_offset;
1543
1544 BUG_ON(offset >= OCFS2_XATTR_BUCKET_SIZE);
1545
1546 /* The header is at the front of the bucket */
1547 block = offset >> bucket->bu_inode->i_sb->s_blocksize_bits;
1548 block_offset = offset % bucket->bu_inode->i_sb->s_blocksize;
1549
1550 return bucket_block(bucket, block) + block_offset;
1551}
1552
1553static void ocfs2_xa_bucket_wipe_namevalue(struct ocfs2_xa_loc *loc)
1554{
1555 int namevalue_size;
1556 struct ocfs2_xattr_entry *entry = loc->xl_entry;
1557 u64 value_size = le64_to_cpu(entry->xe_value_size);
1558
1559 namevalue_size = OCFS2_XATTR_SIZE(entry->xe_name_len);
1560 if (value_size > OCFS2_XATTR_INLINE_SIZE)
1561 namevalue_size += OCFS2_XATTR_ROOT_SIZE;
1562 else
1563 namevalue_size += OCFS2_XATTR_SIZE(value_size);
1564
1565 le16_add_cpu(&loc->xl_header->xh_name_value_len, -namevalue_size);
1566}
1567
1568/* Operations for xattrs stored in buckets. */
1569static const struct ocfs2_xa_loc_operations ocfs2_xa_bucket_loc_ops = {
1570 .xlo_offset_pointer = ocfs2_xa_bucket_offset_pointer,
1571 .xlo_wipe_namevalue = ocfs2_xa_bucket_wipe_namevalue,
1572};
1573
1574static void ocfs2_xa_remove_entry(struct ocfs2_xa_loc *loc)
1575{
1576 ocfs2_xa_wipe_namevalue(loc);
1577}
1578
1579static void ocfs2_init_dinode_xa_loc(struct ocfs2_xa_loc *loc,
1580 struct inode *inode,
1581 struct buffer_head *bh,
1582 struct ocfs2_xattr_entry *entry)
1583{
1584 struct ocfs2_dinode *di = (struct ocfs2_dinode *)bh->b_data;
1585
1586 loc->xl_ops = &ocfs2_xa_block_loc_ops;
1587 loc->xl_storage = bh;
1588 loc->xl_entry = entry;
1589
1590 if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_XATTR_FL)
1591 loc->xl_size = le16_to_cpu(di->i_xattr_inline_size);
1592 else {
1593 BUG_ON(entry);
1594 loc->xl_size = OCFS2_SB(inode->i_sb)->s_xattr_inline_size;
1595 }
1596 loc->xl_header =
1597 (struct ocfs2_xattr_header *)(bh->b_data + bh->b_size -
1598 loc->xl_size);
1599}
1600
1601static void ocfs2_init_xattr_block_xa_loc(struct ocfs2_xa_loc *loc,
1602 struct buffer_head *bh,
1603 struct ocfs2_xattr_entry *entry)
1604{
1605 struct ocfs2_xattr_block *xb =
1606 (struct ocfs2_xattr_block *)bh->b_data;
1607
1608 BUG_ON(le16_to_cpu(xb->xb_flags) & OCFS2_XATTR_INDEXED);
1609
1610 loc->xl_ops = &ocfs2_xa_block_loc_ops;
1611 loc->xl_storage = bh;
1612 loc->xl_header = &(xb->xb_attrs.xb_header);
1613 loc->xl_entry = entry;
1614 loc->xl_size = bh->b_size - offsetof(struct ocfs2_xattr_block,
1615 xb_attrs.xb_header);
1616}
1617
1618static void ocfs2_init_xattr_bucket_xa_loc(struct ocfs2_xa_loc *loc,
1619 struct ocfs2_xattr_bucket *bucket,
1620 struct ocfs2_xattr_entry *entry)
1621{
1622 loc->xl_ops = &ocfs2_xa_bucket_loc_ops;
1623 loc->xl_storage = bucket;
1624 loc->xl_header = bucket_xh(bucket);
1625 loc->xl_entry = entry;
1626 loc->xl_size = OCFS2_XATTR_BUCKET_SIZE;
1627}
1628
1629/*
1421 * ocfs2_xattr_set_entry_local() 1630 * ocfs2_xattr_set_entry_local()
1422 * 1631 *
1423 * Set, replace or remove extended attribute in local. 1632 * Set, replace or remove extended attribute in local.
@@ -1430,7 +1639,14 @@ static void ocfs2_xattr_set_entry_local(struct inode *inode,
1430{ 1639{
1431 size_t name_len = strlen(xi->name); 1640 size_t name_len = strlen(xi->name);
1432 int i; 1641 int i;
1642 struct ocfs2_xa_loc loc;
1433 1643
1644 if (xs->xattr_bh == xs->inode_bh)
1645 ocfs2_init_dinode_xa_loc(&loc, inode, xs->inode_bh,
1646 xs->not_found ? NULL : xs->here);
1647 else
1648 ocfs2_init_xattr_block_xa_loc(&loc, xs->xattr_bh,
1649 xs->not_found ? NULL : xs->here);
1434 if (xi->value && xs->not_found) { 1650 if (xi->value && xs->not_found) {
1435 /* Insert the new xattr entry. */ 1651 /* Insert the new xattr entry. */
1436 le16_add_cpu(&xs->header->xh_count, 1); 1652 le16_add_cpu(&xs->header->xh_count, 1);
@@ -1469,9 +1685,9 @@ static void ocfs2_xattr_set_entry_local(struct inode *inode,
1469 xi->value_len); 1685 xi->value_len);
1470 return; 1686 return;
1471 } 1687 }
1688
1472 /* Remove the old name+value. */ 1689 /* Remove the old name+value. */
1473 memmove(first_val + size, first_val, val - first_val); 1690 ocfs2_xa_wipe_namevalue(&loc);
1474 memset(first_val, 0, size);
1475 xs->here->xe_name_hash = 0; 1691 xs->here->xe_name_hash = 0;
1476 xs->here->xe_name_offset = 0; 1692 xs->here->xe_name_offset = 0;
1477 ocfs2_xattr_set_local(xs->here, 1); 1693 ocfs2_xattr_set_local(xs->here, 1);
@@ -1479,23 +1695,15 @@ static void ocfs2_xattr_set_entry_local(struct inode *inode,
1479 1695
1480 min_offs += size; 1696 min_offs += size;
1481 1697
1482 /* Adjust all value offsets. */
1483 last = xs->header->xh_entries;
1484 for (i = 0 ; i < le16_to_cpu(xs->header->xh_count); i++) {
1485 size_t o = le16_to_cpu(last->xe_name_offset);
1486
1487 if (o < offs)
1488 last->xe_name_offset = cpu_to_le16(o + size);
1489 last += 1;
1490 }
1491
1492 if (!xi->value) { 1698 if (!xi->value) {
1493 /* Remove the old entry. */ 1699 /* Remove the old entry. */
1494 last -= 1; 1700 i = le16_to_cpu(xs->header->xh_count) - 1;
1701 last = &xs->header->xh_entries[i];
1702 xs->header->xh_count = cpu_to_le16(i);
1703
1495 memmove(xs->here, xs->here + 1, 1704 memmove(xs->here, xs->here + 1,
1496 (void *)last - (void *)xs->here); 1705 (void *)last - (void *)xs->here);
1497 memset(last, 0, sizeof(struct ocfs2_xattr_entry)); 1706 memset(last, 0, sizeof(struct ocfs2_xattr_entry));
1498 le16_add_cpu(&xs->header->xh_count, -1);
1499 } 1707 }
1500 } 1708 }
1501 if (xi->value) { 1709 if (xi->value) {
@@ -4769,7 +4977,10 @@ static void ocfs2_xattr_set_entry_normal(struct inode *inode,
4769 size_t blocksize = inode->i_sb->s_blocksize; 4977 size_t blocksize = inode->i_sb->s_blocksize;
4770 char *val; 4978 char *val;
4771 size_t offs, size, new_size; 4979 size_t offs, size, new_size;
4980 struct ocfs2_xa_loc loc;
4772 4981
4982 ocfs2_init_xattr_bucket_xa_loc(&loc, xs->bucket,
4983 xs->not_found ? NULL : xs->here);
4773 last = &xh->xh_entries[count]; 4984 last = &xh->xh_entries[count];
4774 if (!xs->not_found) { 4985 if (!xs->not_found) {
4775 xe = xs->here; 4986 xe = xs->here;
@@ -4790,7 +5001,7 @@ static void ocfs2_xattr_set_entry_normal(struct inode *inode,
4790 new_size = OCFS2_XATTR_SIZE(name_len) + 5001 new_size = OCFS2_XATTR_SIZE(name_len) +
4791 OCFS2_XATTR_SIZE(xi->value_len); 5002 OCFS2_XATTR_SIZE(xi->value_len);
4792 5003
4793 le16_add_cpu(&xh->xh_name_value_len, -size); 5004 ocfs2_xa_wipe_namevalue(&loc);
4794 if (xi->value) { 5005 if (xi->value) {
4795 if (new_size > size) 5006 if (new_size > size)
4796 goto set_new_name_value; 5007 goto set_new_name_value;