[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20191224081324.95807-12-harshadshirwadkar@gmail.com>
Date: Tue, 24 Dec 2019 00:13:16 -0800
From: Harshad Shirwadkar <harshadshirwadkar@...il.com>
To: linux-ext4@...r.kernel.org
Cc: Harshad Shirwadkar <harshadshirwadkar@...il.com>
Subject: [PATCH v4 12/20] ext4: add fast commit on-disk format structs and helpers
Add structs representing on-disk format of the commit header and
tlvs in the commit header. Also, add helpers to arrange data
in on-disk fast commit format.
Signed-off-by: Harshad Shirwadkar <harshadshirwadkar@...il.com>
---
fs/ext4/ext4_jbd2.c | 163 ++++++++++++++++++++++++++++++++++++++++++++
fs/ext4/ext4_jbd2.h | 45 ++++++++++++
2 files changed, 208 insertions(+)
diff --git a/fs/ext4/ext4_jbd2.c b/fs/ext4/ext4_jbd2.c
index 9e060ba927c1..9e34aa560ea1 100644
--- a/fs/ext4/ext4_jbd2.c
+++ b/fs/ext4/ext4_jbd2.c
@@ -4,6 +4,7 @@
*/
#include "ext4_jbd2.h"
+#include "ext4_extents.h"
#include <trace/events/ext4.h>
@@ -604,6 +605,168 @@ void ext4_fc_track_range(struct inode *inode, ext4_lblk_t start,
trace_ext4_fc_track_range(inode, start, end, ret);
}
+
+/*
+ * Adds tag, length and value at memory pointed to by dst. Returns
+ * true if tlv was added. Returns false if there's not enough space.
+ * If successful also updates *dst to point to the end of this tlv.
+ */
+static bool fc_try_add_tlv(u8 **dst, u8 *end, u16 tag, u16 len, u8 *val)
+{
+ struct ext4_fc_tl tl;
+
+ if (*dst + sizeof(tl) + len >= end)
+ return false;
+
+ tl.fc_tag = cpu_to_le16(tag);
+ tl.fc_len = cpu_to_le16(len);
+ memcpy(*dst, &tl, sizeof(tl));
+ memcpy(*dst + sizeof(tl), val, len);
+
+ *dst = *dst + sizeof(tl) + len;
+ return true;
+}
+
+/* Same as above, but tries to add dentry tlv. */
+static bool fc_try_add_dentry_info_tlv(u8 **dst, u8 *end, u16 tag,
+ int parent_ino, int ino, int dlen,
+ const unsigned char *dname)
+{
+ struct ext4_fc_dentry_info fcd;
+ struct ext4_fc_tl tl;
+
+
+ if (*dst + sizeof(tl) + sizeof(fcd) + dlen >= end)
+ return false;
+
+ fcd.fc_parent_ino = cpu_to_le32(parent_ino);
+ fcd.fc_ino = cpu_to_le32(ino);
+ tl.fc_tag = cpu_to_le16(tag);
+ tl.fc_len = cpu_to_le16(sizeof(fcd) + dlen);
+ memcpy(*dst, &tl, sizeof(tl));
+ *dst += sizeof(tl);
+ memcpy(*dst, &fcd, sizeof(fcd));
+ *dst += sizeof(fcd);
+ memcpy(*dst, dname, dlen);
+ *dst += dlen;
+
+ return true;
+}
+
+/* Get length of a particular tlv */
+static int fc_tag_len(struct ext4_fc_tl *tl)
+{
+ return le16_to_cpu(tl->fc_len);
+}
+
+/* Get a pointer to "value" of a tlv */
+static u8 *fc_tag_val(struct ext4_fc_tl *tl)
+{
+ return (u8 *)tl + sizeof(*tl);
+}
+
+/*
+ * Writes fast commit header and inode structure at memory
+ * pointed to by start. Returns 0 on success, error on failure.
+ * If successful, *last is upadated to point to the end of
+ * inode that was copied.
+ */
+static int fc_write_hdr(struct inode *inode, u8 *start, u8 *end,
+ u8 **last)
+{
+ struct ext4_fc_commit_hdr *fc_hdr = (struct ext4_fc_commit_hdr *)start;
+ struct ext4_inode_info *ei = EXT4_I(inode);
+ int inode_len = EXT4_GOOD_OLD_INODE_SIZE;
+ struct ext4_iloc iloc;
+ u8 *cur = start;
+ int ret;
+
+ if (ext4_is_inode_fc_ineligible(inode))
+ return -ECANCELED;
+
+ ret = ext4_get_inode_loc(inode, &iloc);
+ if (ret)
+ return ret;
+
+ fc_hdr->fc_magic = cpu_to_le32(EXT4_FC_MAGIC);
+ fc_hdr->fc_ino = cpu_to_le32(inode->i_ino);
+ fc_hdr->fc_features = 0;
+ fc_hdr->fc_csum = 0;
+
+ cur = (u8 *)(fc_hdr + 1);
+ if (EXT4_INODE_SIZE(inode->i_sb) > EXT4_GOOD_OLD_INODE_SIZE)
+ inode_len += ei->i_extra_isize;
+ if (cur + inode_len >= end)
+ return -ECANCELED;
+
+ memcpy(cur, ext4_raw_inode(&iloc), inode_len);
+ cur += inode_len;
+ *last = cur;
+
+ return 0;
+}
+
+/*
+ * Writes data tags (EXT4_FC_TAG_ADD_RANGE / EXT4_FC_TAG_DEL_RANGE)
+ * at memory pointed to by start. Returns number of TLVs that were
+ * added if successfully. Returns errors otherwise.
+ */
+static int fc_write_data(struct inode *inode, u8 *start, u8 *end,
+ u8 **last)
+{
+ ext4_lblk_t old_blk_size, cur_lblk_off, new_blk_size;
+ struct ext4_inode_info *ei = EXT4_I(inode);
+ struct ext4_map_blocks map;
+ struct ext4_extent extent;
+ struct ext4_fc_lrange lrange;
+ u8 *cur = start;
+ int num_tlvs = 0;
+ int ret;
+
+ write_lock(&ei->i_fc_lock);
+ old_blk_size = ei->i_fc_lblk_start;
+ new_blk_size = ei->i_fc_lblk_end;
+ ei->i_fc_lblk_start = ei->i_fc_lblk_end;
+ write_unlock(&ei->i_fc_lock);
+
+ cur_lblk_off = old_blk_size;
+ jbd_debug(1, "%s: will try writing %ld to %ld for inode %ld\n",
+ __func__, cur_lblk_off, new_blk_size, inode->i_ino);
+ while (cur_lblk_off <= new_blk_size) {
+ map.m_lblk = cur_lblk_off;
+ map.m_len = new_blk_size - cur_lblk_off + 1;
+ ret = ext4_map_blocks(NULL, inode, &map, 0);
+ if (ret < 0)
+ return ret;
+ if (map.m_len == 0)
+ return -ECANCELED;
+ if (map.m_flags & EXT4_MAP_UNWRITTEN)
+ return -ECANCELED;
+
+ cur_lblk_off += map.m_len;
+ if (ret == 0) {
+ lrange.fc_lblk = cpu_to_le32(map.m_lblk);
+ lrange.fc_len = cpu_to_le32(map.m_len);
+ if (!fc_try_add_tlv(&cur, end, EXT4_FC_TAG_DEL_RANGE,
+ sizeof(lrange), (u8 *)&lrange))
+ return -ENOSPC;
+
+ } else {
+ extent.ee_block = cpu_to_le32(map.m_lblk);
+ extent.ee_len = cpu_to_le16(map.m_len);
+ ext4_ext_store_pblock(&extent, map.m_pblk);
+ ext4_ext_mark_initialized(&extent);
+ if (!fc_try_add_tlv(&cur, end, EXT4_FC_TAG_ADD_RANGE,
+ sizeof(struct ext4_extent), (u8 *)&extent))
+ return -ENOSPC;
+ }
+ num_tlvs++;
+ }
+ *last = cur;
+
+ return num_tlvs;
+}
+
void ext4_init_fast_commit(struct super_block *sb, journal_t *journal)
{
if (!ext4_should_fast_commit(sb))
diff --git a/fs/ext4/ext4_jbd2.h b/fs/ext4/ext4_jbd2.h
index 60f484377c2e..d3a951d2e58d 100644
--- a/fs/ext4/ext4_jbd2.h
+++ b/fs/ext4/ext4_jbd2.h
@@ -470,7 +470,52 @@ static inline int ext4_should_dioread_nolock(struct inode *inode)
return 1;
}
+/* Ext4 fast commit related info */
+
+/* Magic of fast commit header */
+#define EXT4_FC_MAGIC 0xE2540090
+
#define EXT4_NUM_FC_BLKS 128
+
+struct ext4_fc_commit_hdr {
+ /* Fast commit magic, should be EXT4_FC_MAGIC */
+ __le32 fc_magic;
+ /* Features used by this fast commit block */
+ __u8 fc_features;
+ /* Number of TLVs in this fast commmit block */
+ __le16 fc_num_tlvs;
+ /* Inode number */
+ __le32 fc_ino;
+ /* Csum(hdr+contents) */
+ __le32 fc_csum;
+};
+
+/* Fast commit on disk tag length structure */
+struct ext4_fc_tl {
+ __le16 fc_tag;
+ __le16 fc_len;
+};
+
+/* On disk fast commit tlv value structure for dirent tags:
+ * - EXT4_FC_TAG_CREATE_DENTRY
+ * - EXT4_FC_TAG_ADD_DENTRY
+ * - EXT4_FC_TAG_DEL_DENTRY
+ */
+struct ext4_fc_dentry_info {
+ __le32 fc_parent_ino;
+ __le32 fc_ino;
+ u8 fc_dname[0];
+};
+
+/*
+ * On disk fast commit tlv value structure for tag
+ * EXT4_FC_TAG_HOLE.
+ */
+struct ext4_fc_lrange {
+ __le32 fc_lblk;
+ __le32 fc_len;
+};
+
void ext4_init_fast_commit(struct super_block *sb, journal_t *journal);
void ext4_init_inode_fc_info(struct inode *inode);
void ext4_fc_track_range(struct inode *inode, ext4_lblk_t start,
--
2.24.1.735.g03f4e72817-goog
Powered by blists - more mailing lists