[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <1367702922-3236-4-git-send-email-rpazdera@redhat.com>
Date: Sat, 4 May 2013 23:28:36 +0200
From: Radek Pazdera <rpazdera@...hat.com>
To: linux-ext4@...r.kernel.org
Cc: lczerner@...hat.com, kasparek@....vutbr.cz,
Radek Pazdera <rpazdera@...hat.com>
Subject: [RFC 3/9] ext4: Adding a link to itree to the dx_root struct
The dx_tail struct that can be stored at the end of each root block was
extended with an additional link to the itree root block.
This commit renames the dx_tail to dx_csum_entry and adds dx_itree_entry
that holds the 64bit block pointer to itree root.
Signed-off-by: Radek Pazdera <rpazdera@...hat.com>
---
fs/ext4/namei.c | 186 +++++++++++++++++++++++++++++++++++++++++++-------------
1 file changed, 145 insertions(+), 41 deletions(-)
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
index 4a22393..a3697a7 100644
--- a/fs/ext4/namei.c
+++ b/fs/ext4/namei.c
@@ -235,9 +235,30 @@ struct dx_map_entry
/*
* This goes at the end of each htree block.
*/
+struct dx_csum_entry {
+ u32 de_reserved;
+ __le32 de_checksum; /* crc32c(uuid+inum+dirblock) */
+};
+
+/*
+ * This goes at the end of a htree root block, if there is an itree
+ * available for that directory.
+ */
+struct dx_itree_entry {
+ __le64 de_itree_root;
+};
+
+/*
+ * This is a memory-only structure for easier handling the tail of
+ * dx_node. One or even both members can be set to NULL, which means
+ * that the node doesn't have the particular entry.
+ */
struct dx_tail {
- u32 dt_reserved;
- __le32 dt_checksum; /* crc32c(uuid+inum+dirblock) */
+ void *start;
+ int len;
+
+ struct dx_csum_entry *csum;
+ struct dx_itree_entry *itree;
};
static inline ext4_lblk_t dx_get_block(struct dx_entry *entry);
@@ -250,6 +271,10 @@ static void dx_set_count(struct dx_entry *entries, unsigned value);
static void dx_set_limit(struct dx_entry *entries, unsigned value);
static unsigned dx_root_limit(struct inode *dir, unsigned infosize);
static unsigned dx_node_limit(struct inode *dir);
+static int dx_get_itree_root(struct inode *inode, struct ext4_dir_entry *dirent,
+ ext4_fsblk_t *itree_root);
+static int dx_set_itree_root(struct inode *inode, struct ext4_dir_entry *dirent,
+ ext4_fsblk_t itree_root);
static struct dx_frame *dx_probe(const struct qstr *d_name,
struct inode *dir,
struct dx_hash_info *hinfo,
@@ -417,80 +442,119 @@ static struct dx_countlimit *get_dx_countlimit(struct inode *inode,
return (struct dx_countlimit *)(((void *)dirent) + count_offset);
}
-static __le32 ext4_dx_csum(struct inode *inode, struct ext4_dir_entry *dirent,
- int count_offset, int count, struct dx_tail *t)
+static int dx_get_tail(struct inode *inode, struct ext4_dir_entry *dirent,
+ struct dx_tail *tail)
+{
+ struct dx_countlimit *c;
+ int tail_space, limit, count_offset;
+ void *tail_ptr;
+
+ c = get_dx_countlimit(inode, dirent, &count_offset);
+ if (!c) {
+ EXT4_ERROR_INODE(inode, "dir seems corrupt? Run e2fsck -D.");
+ return -EIO;
+ }
+ limit = le16_to_cpu(c->limit);
+
+ memset(tail, 0, sizeof(struct dx_tail));
+ tail_ptr = tail->start = (void *)(((struct dx_entry *)c) + limit);
+ tail_space = EXT4_BLOCK_SIZE(inode->i_sb) -
+ (count_offset + (limit * sizeof(struct dx_entry)));
+
+ if (EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb,
+ EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) &&
+ tail_space >= sizeof(struct dx_csum_entry)) {
+ tail->len += sizeof(struct dx_csum_entry);
+ tail->csum = (struct dx_csum_entry *)tail_ptr;
+ tail_ptr += sizeof(struct dx_csum_entry);
+ tail_space -= sizeof(struct dx_csum_entry);
+ }
+
+ if (dx_itree(inode) && tail_space >= sizeof(struct dx_itree_entry)) {
+ tail->len += sizeof(struct dx_itree_entry);
+ tail->itree = (struct dx_itree_entry *)tail_ptr;
+ }
+
+ return 0;
+}
+
+static int ext4_dx_csum(struct inode *inode, struct ext4_dir_entry *dirent,
+ struct dx_tail *tail, __le32 *csum)
{
struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
struct ext4_inode_info *ei = EXT4_I(inode);
- __u32 csum, old_csum;
- int size;
+ __u32 new_csum, old_csum;
+ struct dx_countlimit *c;
+ int size, count, count_offset;
+
+ c = get_dx_countlimit(inode, dirent, &count_offset);
+ if (!c)
+ return -EIO;
+ count = le16_to_cpu(c->count);
size = count_offset + (count * sizeof(struct dx_entry));
- old_csum = t->dt_checksum;
- t->dt_checksum = 0;
- csum = ext4_chksum(sbi, ei->i_csum_seed, (__u8 *)dirent, size);
- csum = ext4_chksum(sbi, csum, (__u8 *)t, sizeof(struct dx_tail));
- t->dt_checksum = old_csum;
+ old_csum = tail->csum->de_checksum;
+ tail->csum->de_checksum = 0;
+ new_csum = ext4_chksum(sbi, ei->i_csum_seed, (__u8 *)dirent, size);
+ new_csum = ext4_chksum(sbi, new_csum, (__u8 *)tail->start, tail->len);
+ tail->csum->de_checksum = old_csum;
- return cpu_to_le32(csum);
+ *csum = cpu_to_le32(new_csum);
+ return 0;
}
static int ext4_dx_csum_verify(struct inode *inode,
struct ext4_dir_entry *dirent)
{
- struct dx_countlimit *c;
- struct dx_tail *t;
- int count_offset, limit, count;
+ struct dx_tail tail;
+ int err;
+ __le32 csum;
if (!EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb,
EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
return 1;
- c = get_dx_countlimit(inode, dirent, &count_offset);
- if (!c) {
- EXT4_ERROR_INODE(inode, "dir seems corrupt? Run e2fsck -D.");
+ err = dx_get_tail(inode, dirent, &tail);
+ if (err)
+ return err;
+
+ if (!tail.csum) {
+ warn_no_space_for_csum(inode);
return 1;
}
- limit = le16_to_cpu(c->limit);
- count = le16_to_cpu(c->count);
- if (count_offset + (limit * sizeof(struct dx_entry)) >
- EXT4_BLOCK_SIZE(inode->i_sb) - sizeof(struct dx_tail)) {
- warn_no_space_for_csum(inode);
+
+ err = ext4_dx_csum(inode, dirent, &tail, &csum);
+ if (err) {
+ EXT4_ERROR_INODE(inode, "dir seems corrupt? Run e2fsck -D.");
return 1;
}
- t = (struct dx_tail *)(((struct dx_entry *)c) + limit);
- if (t->dt_checksum != ext4_dx_csum(inode, dirent, count_offset,
- count, t))
+ if (tail.csum->de_checksum != csum)
return 0;
return 1;
}
static void ext4_dx_csum_set(struct inode *inode, struct ext4_dir_entry *dirent)
{
- struct dx_countlimit *c;
- struct dx_tail *t;
- int count_offset, limit, count;
+ struct dx_tail tail;
+ int err;
if (!EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb,
EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
return;
- c = get_dx_countlimit(inode, dirent, &count_offset);
- if (!c) {
- EXT4_ERROR_INODE(inode, "dir seems corrupt? Run e2fsck -D.");
+ err = dx_get_tail(inode, dirent, &tail);
+ if (err)
return;
- }
- limit = le16_to_cpu(c->limit);
- count = le16_to_cpu(c->count);
- if (count_offset + (limit * sizeof(struct dx_entry)) >
- EXT4_BLOCK_SIZE(inode->i_sb) - sizeof(struct dx_tail)) {
+
+ if (!tail.csum) {
warn_no_space_for_csum(inode);
return;
}
- t = (struct dx_tail *)(((struct dx_entry *)c) + limit);
- t->dt_checksum = ext4_dx_csum(inode, dirent, count_offset, count, t);
+ err = ext4_dx_csum(inode, dirent, &tail, &(tail.csum->de_checksum));
+ if (err)
+ EXT4_ERROR_INODE(inode, "dir seems corrupt? Run e2fsck -D.");
}
static inline int ext4_handle_dirty_dx_node(handle_t *handle,
@@ -563,7 +627,9 @@ static inline unsigned dx_root_limit(struct inode *dir, unsigned infosize)
if (EXT4_HAS_RO_COMPAT_FEATURE(dir->i_sb,
EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
- entry_space -= sizeof(struct dx_tail);
+ entry_space -= sizeof(struct dx_csum_entry);
+ if (dx_itree(dir))
+ entry_space -= sizeof(struct dx_itree_entry);
return entry_space / sizeof(struct dx_entry);
}
@@ -573,10 +639,48 @@ static inline unsigned dx_node_limit(struct inode *dir)
if (EXT4_HAS_RO_COMPAT_FEATURE(dir->i_sb,
EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
- entry_space -= sizeof(struct dx_tail);
+ entry_space -= sizeof(struct dx_csum_entry);
return entry_space / sizeof(struct dx_entry);
}
+static int dx_get_itree_root(struct inode *inode, struct ext4_dir_entry *dirent,
+ ext4_fsblk_t *itree_root)
+{
+ int err;
+ struct dx_tail tail;
+
+ err = dx_get_tail(inode, dirent, &tail);
+ if (err)
+ return err;
+
+ if (!tail.itree) {
+ EXT4_ERROR_INODE(inode, "dir seems corrupt? Run e2fsck -D.");
+ return -EIO;
+ }
+
+ *itree_root = le64_to_cpu(tail.itree->de_itree_root);
+ return 0;
+}
+
+static int dx_set_itree_root(struct inode *inode, struct ext4_dir_entry *dirent,
+ ext4_fsblk_t itree_root)
+{
+ int err;
+ struct dx_tail tail;
+
+ err = dx_get_tail(inode, dirent, &tail);
+ if (err)
+ return err;
+
+ if (!tail.itree) {
+ EXT4_ERROR_INODE(inode, "dir seems corrupt? Run e2fsck -D.");
+ return -EIO;
+ }
+
+ tail.itree->de_itree_root = cpu_to_le64(itree_root);
+ return 0;
+}
+
/*
* Debug
*/
--
1.7.11.7
--
To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Powered by blists - more mailing lists