Commit 11179f2c92cb025b1ff0b794f9714b3fb395855f

Authored by Joel Becker
1 parent 8545e03d82

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>

Showing 1 changed file with 226 additions and 15 deletions Side-by-side Diff

... ... @@ -137,6 +137,51 @@
137 137 int not_found;
138 138 };
139 139  
  140 +/* Operations on struct ocfs2_xa_entry */
  141 +struct ocfs2_xa_loc;
  142 +struct 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 + */
  160 +struct 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 +
140 185 static int ocfs2_xattr_bucket_get_name_value(struct super_block *sb,
141 186 struct ocfs2_xattr_header *xh,
142 187 int index,
... ... @@ -1418,6 +1463,170 @@
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 + */
  1470 +static void ocfs2_xa_wipe_namevalue(struct ocfs2_xa_loc *loc)
  1471 +{
  1472 + loc->xl_ops->xlo_wipe_namevalue(loc);
  1473 +}
  1474 +
  1475 +static 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 + */
  1486 +static 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 + */
  1533 +static 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 +
  1538 +static 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 +
  1553 +static 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. */
  1569 +static 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 +
  1574 +static void ocfs2_xa_remove_entry(struct ocfs2_xa_loc *loc)
  1575 +{
  1576 + ocfs2_xa_wipe_namevalue(loc);
  1577 +}
  1578 +
  1579 +static 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 +
  1601 +static 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 +
  1618 +static 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 1630 * ocfs2_xattr_set_entry_local()
1422 1631 *
1423 1632 * Set, replace or remove extended attribute in local.
1424 1633  
... ... @@ -1430,7 +1639,14 @@
1430 1639 {
1431 1640 size_t name_len = strlen(xi->name);
1432 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 1650 if (xi->value && xs->not_found) {
1435 1651 /* Insert the new xattr entry. */
1436 1652 le16_add_cpu(&xs->header->xh_count, 1);
1437 1653  
... ... @@ -1469,9 +1685,9 @@
1469 1685 xi->value_len);
1470 1686 return;
1471 1687 }
  1688 +
1472 1689 /* Remove the old name+value. */
1473   - memmove(first_val + size, first_val, val - first_val);
1474   - memset(first_val, 0, size);
  1690 + ocfs2_xa_wipe_namevalue(&loc);
1475 1691 xs->here->xe_name_hash = 0;
1476 1692 xs->here->xe_name_offset = 0;
1477 1693 ocfs2_xattr_set_local(xs->here, 1);
1478 1694  
1479 1695  
... ... @@ -1479,23 +1695,15 @@
1479 1695  
1480 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 1698 if (!xi->value) {
1493 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 1704 memmove(xs->here, xs->here + 1,
1496 1705 (void *)last - (void *)xs->here);
1497 1706 memset(last, 0, sizeof(struct ocfs2_xattr_entry));
1498   - le16_add_cpu(&xs->header->xh_count, -1);
1499 1707 }
1500 1708 }
1501 1709 if (xi->value) {
1502 1710  
... ... @@ -4769,7 +4977,10 @@
4769 4977 size_t blocksize = inode->i_sb->s_blocksize;
4770 4978 char *val;
4771 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 4984 last = &xh->xh_entries[count];
4774 4985 if (!xs->not_found) {
4775 4986 xe = xs->here;
... ... @@ -4790,7 +5001,7 @@
4790 5001 new_size = OCFS2_XATTR_SIZE(name_len) +
4791 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 5005 if (xi->value) {
4795 5006 if (new_size > size)
4796 5007 goto set_new_name_value;