changeset 785:c2a9fdacbfcc

objstore: add dirblock_parse Parse an entire directory block into a struct dirblock. It preserves the dirent ordering. Signed-off-by: Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
author Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
date Thu, 26 Mar 2020 15:14:03 -0400
parents 6c935af513e5
children 3fc635b4636f
files src/objstore/dir.h src/objstore/dirblock.c
diffstat 2 files changed, 72 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/src/objstore/dir.h	Tue Mar 31 13:09:19 2020 -0400
+++ b/src/objstore/dir.h	Thu Mar 26 15:14:03 2020 -0400
@@ -210,6 +210,7 @@
 };
 
 extern void dirblock_init(struct dirblock *block);
+extern int dirblock_parse(struct dirblock *block, uint8_t *raw, uint16_t ndirents);
 extern int dirblock_serialize(struct dirblock *block, struct buffer *buf);
 extern int dirblock_add_dirent(struct dirblock *block, const char *name,
 			       const struct ndirent_tgt *tgt);
--- a/src/objstore/dirblock.c	Tue Mar 31 13:09:19 2020 -0400
+++ b/src/objstore/dirblock.c	Thu Mar 26 15:14:03 2020 -0400
@@ -36,6 +36,77 @@
 	block->ntgts = 0;
 }
 
+/* parse a block */
+int dirblock_parse(struct dirblock *block, uint8_t *raw, uint16_t ndirents)
+{
+	size_t i, j;
+
+	dirblock_init(block);
+
+	/* for each dirent */
+	for (i = 0; i < ndirents; i++) {
+		const int idx = block->ndirents;
+		struct ndirent_mem *dirent = &block->entries[idx].dirent;
+		size_t non_deleted_targets;
+		struct buffer tgtbuf;
+		int ret;
+
+		dirent_be2cpu(dirent,
+			      (void *) &raw[sizeof(struct obj_dir_header) +
+					    sizeof(struct ndirent_phys) * i]);
+
+		/* complete the fixed sized dirent */
+		block->entries[idx].name = &block->names[block->name_bytes];
+		block->entries[idx].tgts = &block->tgts[block->ntgts];
+
+		/* save the name */
+		memcpy(&block->names[block->name_bytes], &raw[dirent->nameoff],
+		       dirent->namelen);
+
+		/* save the targets */
+		buffer_init_static(&tgtbuf, &raw[dirent->tgtoff],
+				   DIR_BLOCK_SIZE - dirent->tgtoff, false);
+
+		non_deleted_targets = 0;
+		for (j = block->ntgts; j < (block->ntgts + dirent->ntgts); j++) {
+			ret = unpack_dirent_tgt(&tgtbuf, &block->tgts[j]);
+			if (ret)
+				return ret;
+
+			if (!block->tgts[j].deleted)
+				non_deleted_targets++;
+		}
+
+		/* check and correct dirent flags */
+		if (dirent->conflicts != (non_deleted_targets > 1))
+			cmn_err(CE_WARN, "Parsed dirent conflicts (%s) "
+				"mismatches targets (%zu !deleted)...fixed",
+				dirent->conflicts ? "true" : "false",
+				non_deleted_targets);
+		if (dirent->all_deleted != (non_deleted_targets == 0))
+			cmn_err(CE_WARN, "Parsed dirent all_deleted (%s) "
+				"mismatches targets (%zu !deleted)...fixed",
+				dirent->all_deleted ? "true" : "false",
+				non_deleted_targets);
+
+		dirent->conflicts = (non_deleted_targets > 1);
+		dirent->all_deleted = (non_deleted_targets == 0);
+
+		/* update block state */
+		block->used_bytes += sizeof(struct ndirent_phys) +
+			dirent->namelen + buffer_offset(&tgtbuf);
+		block->name_bytes += dirent->namelen;
+		block->ndirents++;
+		block->ntgts += dirent->ntgts;
+
+		/* poison the block's memory entries to avoid accidents */
+		dirent->tgtoff = DIRBLOCK_DIRENT_OFFSET_POISON;
+		dirent->nameoff = DIRBLOCK_DIRENT_OFFSET_POISON;
+	}
+
+	return 0;
+}
+
 static void __dirblock_serialize_check_dirent(struct dirblock *block,
 					      size_t dirent)
 {