aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoel Becker <joel.becker@oracle.com>2009-08-14 19:07:44 -0400
committerJoel Becker <joel.becker@oracle.com>2010-02-26 18:41:08 -0500
commit11179f2c92cb025b1ff0b794f9714b3fb395855f (patch)
treec36647684270a69e968e6bf60145598a64b45f27
parent8545e03d82b6739461bbd60db7aba144f7dbe80f (diff)
ocfs2: Introduce ocfs2_xa_loc
The ocfs2 extended attribute (xattr) code is very flexible. It can store xattrs in the inode itself, in an external block, or in a tree of data structures. This allows the number of xattrs to be bounded by the filesystem size. However, the code that manages each possible storage location is different. Maintaining the ocfs2 xattr code requires changing each hunk separately. This patch is the start of a series introducing the ocfs2_xa_loc structure. This structure wraps the on-disk details of an xattr entry. The goal is that the generic xattr routines can use ocfs2_xa_loc without knowing the underlying storage location. This first pass merely implements the basic structure, initializing it, and wiping the name+value pair of the entry. Signed-off-by: Joel Becker <joel.becker@oracle.com>
-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;