diff options
author | Tao Ma <boyu.mt@taobao.com> | 2012-12-10 14:06:01 -0500 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2012-12-10 14:06:01 -0500 |
commit | 61f86638d8a656101bb0f9c41c55d9685f8a2357 (patch) | |
tree | 0fae5bd89012c2d2d8a74cb79b67fea56b4f76d9 /fs/ext4 | |
parent | 9f40fe54635b7533f51993d0f5e7f014fc14d33a (diff) |
ext4: let empty_dir handle inline dir
empty_dir is used when deleting a dir. So it should handle inline dir
properly.
Signed-off-by: Tao Ma <boyu.mt@taobao.com>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Diffstat (limited to 'fs/ext4')
-rw-r--r-- | fs/ext4/inline.c | 90 | ||||
-rw-r--r-- | fs/ext4/namei.c | 8 | ||||
-rw-r--r-- | fs/ext4/xattr.h | 6 |
3 files changed, 104 insertions, 0 deletions
diff --git a/fs/ext4/inline.c b/fs/ext4/inline.c index f5e9c0e6d737..e5da458fabad 100644 --- a/fs/ext4/inline.c +++ b/fs/ext4/inline.c | |||
@@ -1565,6 +1565,96 @@ out: | |||
1565 | return err; | 1565 | return err; |
1566 | } | 1566 | } |
1567 | 1567 | ||
1568 | /* | ||
1569 | * Get the inline dentry at offset. | ||
1570 | */ | ||
1571 | static inline struct ext4_dir_entry_2 * | ||
1572 | ext4_get_inline_entry(struct inode *inode, | ||
1573 | struct ext4_iloc *iloc, | ||
1574 | unsigned int offset, | ||
1575 | void **inline_start, | ||
1576 | int *inline_size) | ||
1577 | { | ||
1578 | void *inline_pos; | ||
1579 | |||
1580 | BUG_ON(offset > ext4_get_inline_size(inode)); | ||
1581 | |||
1582 | if (offset < EXT4_MIN_INLINE_DATA_SIZE) { | ||
1583 | inline_pos = (void *)ext4_raw_inode(iloc)->i_block; | ||
1584 | *inline_size = EXT4_MIN_INLINE_DATA_SIZE; | ||
1585 | } else { | ||
1586 | inline_pos = ext4_get_inline_xattr_pos(inode, iloc); | ||
1587 | offset -= EXT4_MIN_INLINE_DATA_SIZE; | ||
1588 | *inline_size = ext4_get_inline_size(inode) - | ||
1589 | EXT4_MIN_INLINE_DATA_SIZE; | ||
1590 | } | ||
1591 | |||
1592 | if (inline_start) | ||
1593 | *inline_start = inline_pos; | ||
1594 | return (struct ext4_dir_entry_2 *)(inline_pos + offset); | ||
1595 | } | ||
1596 | |||
1597 | int empty_inline_dir(struct inode *dir, int *has_inline_data) | ||
1598 | { | ||
1599 | int err, inline_size; | ||
1600 | struct ext4_iloc iloc; | ||
1601 | void *inline_pos; | ||
1602 | unsigned int offset; | ||
1603 | struct ext4_dir_entry_2 *de; | ||
1604 | int ret = 1; | ||
1605 | |||
1606 | err = ext4_get_inode_loc(dir, &iloc); | ||
1607 | if (err) { | ||
1608 | EXT4_ERROR_INODE(dir, "error %d getting inode %lu block", | ||
1609 | err, dir->i_ino); | ||
1610 | return 1; | ||
1611 | } | ||
1612 | |||
1613 | down_read(&EXT4_I(dir)->xattr_sem); | ||
1614 | if (!ext4_has_inline_data(dir)) { | ||
1615 | *has_inline_data = 0; | ||
1616 | goto out; | ||
1617 | } | ||
1618 | |||
1619 | de = (struct ext4_dir_entry_2 *)ext4_raw_inode(&iloc)->i_block; | ||
1620 | if (!le32_to_cpu(de->inode)) { | ||
1621 | ext4_warning(dir->i_sb, | ||
1622 | "bad inline directory (dir #%lu) - no `..'", | ||
1623 | dir->i_ino); | ||
1624 | ret = 1; | ||
1625 | goto out; | ||
1626 | } | ||
1627 | |||
1628 | offset = EXT4_INLINE_DOTDOT_SIZE; | ||
1629 | while (offset < dir->i_size) { | ||
1630 | de = ext4_get_inline_entry(dir, &iloc, offset, | ||
1631 | &inline_pos, &inline_size); | ||
1632 | if (ext4_check_dir_entry(dir, NULL, de, | ||
1633 | iloc.bh, inline_pos, | ||
1634 | inline_size, offset)) { | ||
1635 | ext4_warning(dir->i_sb, | ||
1636 | "bad inline directory (dir #%lu) - " | ||
1637 | "inode %u, rec_len %u, name_len %d" | ||
1638 | "inline size %d\n", | ||
1639 | dir->i_ino, le32_to_cpu(de->inode), | ||
1640 | le16_to_cpu(de->rec_len), de->name_len, | ||
1641 | inline_size); | ||
1642 | ret = 1; | ||
1643 | goto out; | ||
1644 | } | ||
1645 | if (le32_to_cpu(de->inode)) { | ||
1646 | ret = 0; | ||
1647 | goto out; | ||
1648 | } | ||
1649 | offset += ext4_rec_len_from_disk(de->rec_len, inline_size); | ||
1650 | } | ||
1651 | |||
1652 | out: | ||
1653 | up_read(&EXT4_I(dir)->xattr_sem); | ||
1654 | brelse(iloc.bh); | ||
1655 | return ret; | ||
1656 | } | ||
1657 | |||
1568 | int ext4_destroy_inline_data(handle_t *handle, struct inode *inode) | 1658 | int ext4_destroy_inline_data(handle_t *handle, struct inode *inode) |
1569 | { | 1659 | { |
1570 | int ret; | 1660 | int ret; |
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index a32228a73df0..e3e20d0aa299 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c | |||
@@ -2464,6 +2464,14 @@ static int empty_dir(struct inode *inode) | |||
2464 | struct super_block *sb; | 2464 | struct super_block *sb; |
2465 | int err = 0; | 2465 | int err = 0; |
2466 | 2466 | ||
2467 | if (ext4_has_inline_data(inode)) { | ||
2468 | int has_inline_data = 1; | ||
2469 | |||
2470 | err = empty_inline_dir(inode, &has_inline_data); | ||
2471 | if (has_inline_data) | ||
2472 | return err; | ||
2473 | } | ||
2474 | |||
2467 | sb = inode->i_sb; | 2475 | sb = inode->i_sb; |
2468 | if (inode->i_size < EXT4_DIR_REC_LEN(1) + EXT4_DIR_REC_LEN(2) || | 2476 | if (inode->i_size < EXT4_DIR_REC_LEN(1) + EXT4_DIR_REC_LEN(2) || |
2469 | !(bh = ext4_bread(NULL, inode, 0, 0, &err))) { | 2477 | !(bh = ext4_bread(NULL, inode, 0, 0, &err))) { |
diff --git a/fs/ext4/xattr.h b/fs/ext4/xattr.h index f86e424d75e4..7747bbcebb33 100644 --- a/fs/ext4/xattr.h +++ b/fs/ext4/xattr.h | |||
@@ -180,6 +180,7 @@ extern int ext4_delete_inline_entry(handle_t *handle, | |||
180 | struct ext4_dir_entry_2 *de_del, | 180 | struct ext4_dir_entry_2 *de_del, |
181 | struct buffer_head *bh, | 181 | struct buffer_head *bh, |
182 | int *has_inline_data); | 182 | int *has_inline_data); |
183 | extern int empty_inline_dir(struct inode *dir, int *has_inline_data); | ||
183 | # else /* CONFIG_EXT4_FS_XATTR */ | 184 | # else /* CONFIG_EXT4_FS_XATTR */ |
184 | 185 | ||
185 | static inline int | 186 | static inline int |
@@ -381,6 +382,11 @@ static inline int ext4_delete_inline_entry(handle_t *handle, | |||
381 | { | 382 | { |
382 | return 0; | 383 | return 0; |
383 | } | 384 | } |
385 | |||
386 | static inline int empty_inline_dir(struct inode *dir, int *has_inline_data) | ||
387 | { | ||
388 | return 0; | ||
389 | } | ||
384 | # endif /* CONFIG_EXT4_FS_XATTR */ | 390 | # endif /* CONFIG_EXT4_FS_XATTR */ |
385 | 391 | ||
386 | #ifdef CONFIG_EXT4_FS_SECURITY | 392 | #ifdef CONFIG_EXT4_FS_SECURITY |