diff --git a/tsk/fs/tsk_xfs.h b/tsk/fs/tsk_xfs.h
index ab5ac0acd58d2cc003d319b440a75f91cf8fa3fa..9b79bb11347b3448099a8e9caf81f21985a10116 100644
--- a/tsk/fs/tsk_xfs.h
+++ b/tsk/fs/tsk_xfs.h
@@ -154,6 +154,43 @@ typedef uint32_t xfs_alloc_ptr_t;
 #define XFS_IN_IWOTH   0000002
 #define XFS_IN_IXOTH   0000001
 
+/* size of a short form block:
+*    uint32_t   bb_magic;
+*    uint16_t   bb_level;
+*    uint16_t	bb_numrecs;
+*    +
+*    uint32_t   bb_leftsib
+*    uint32_t   bb_rightsib
+*/
+#define XFS_BTREE_SBLOCK_LEN \
+	(sizeof(uint32_t) + sizeof(uint16_t) + sizeof(uint16_t) + \
+	 sizeof(uint32_t) + sizeof(uint32_t))
+
+/* sizes of CRC enabled btree blocks:
+*    uint32_t   bb_magic;
+*    uint16_t   bb_level;
+*    uint16_t	bb_numrecs;
+*    +
+*    uint32_t   bb_leftsib
+*    uint32_t   bb_rightsib
+*    uint64_t	bb_blkno;
+*	 uint64_t	bb_lsn;
+*	 xfs_uuid_t	bb_uuid;
+*	 uint32_t	bb_owner;
+*	 uint32_t	bb_crc;
+*/
+#define XFS_BTREE_SBLOCK_CRC_LEN \
+	(sizeof(uint32_t) + sizeof(uint16_t) + sizeof(uint16_t) + \
+	 sizeof(uint32_t) + sizeof(uint32_t) + sizeof(uint64_t) + sizeof(uint64_t) + \
+     sizeof(xfs_uuid_t) + sizeof(uint32_t) + sizeof(uint32_t))
+
+/*
+ * Btree block header size depends on a superblock flag.
+ */
+#define XFS_INOBT_BLOCK_LEN(sb) \
+	(xfs_sb_version_hascrc(sb) ? \
+		XFS_BTREE_SBLOCK_CRC_LEN : XFS_BTREE_SBLOCK_LEN)
+
 typedef struct xfs_btree_sblock xfs_inobt_block_t;
 
 typedef struct xfs_inobt_rec {
@@ -473,6 +510,13 @@ typedef struct xfs_dir2_leaf_entry {
 ** Super Block and related definitions 
 */
 
+#define	XFS_SB_MAGIC		0x58465342	/* 'XFSB' */
+#define	XFS_SB_VERSION_1	1		/* 5.3, 6.0.1, 6.1 */
+#define	XFS_SB_VERSION_2	2		/* 6.2 - attributes */
+#define	XFS_SB_VERSION_3	3		/* 6.2 - new inode version */
+#define	XFS_SB_VERSION_4	4		/* 6.2+ - bitmask version */
+#define	XFS_SB_VERSION_5	5		/* CRC enabled filesystem */
+
 /*
  * There are two words to hold XFS "feature" bits: the original
  * word, sb_versionnum, and sb_features2.  Whenever a bit is set in
@@ -622,6 +666,13 @@ typedef struct xfs_sb
     xfs_ino_t             sb_rrmapino;
 } xfs_sb_t;
 
+/*
+ * V5 superblock specific feature checks
+ */
+static inline bool xfs_sb_version_hascrc(xfs_sb *sb)
+{
+	return sb->sb_versionnum == XFS_SB_VERSION_5;
+}
 
 /*
  * Structure of an xfs file system handle.
diff --git a/tsk/fs/xfs.cpp b/tsk/fs/xfs.cpp
index 4107c4a6f3fe7be52bf58485c5c268f014d7239b..94554f5a8d976ba0efce901aea3e837bcfb6e17d 100644
--- a/tsk/fs/xfs.cpp
+++ b/tsk/fs/xfs.cpp
@@ -23,6 +23,20 @@ xfs_inobt_key_t ikeys[0x10000];
 xfs_inobt_ptr_t iptrs[0x10000];
 xfs_inobt_rec_t irecs[0x10000];
 
+/*
+ * Calculate number of records in an inobt btree block.
+ */
+uint32_t
+xfs_inobt_maxrecs(xfs_sb_t *sb, int leaf)
+{
+    uint32_t blocklen = sb->sb_blocksize;
+	blocklen -= XFS_INOBT_BLOCK_LEN(sb);
+
+	if (leaf)
+		return blocklen / sizeof(xfs_inobt_rec_t);
+	return blocklen / (sizeof(xfs_inobt_key_t) + sizeof(xfs_inobt_ptr_t));
+}
+
 /* xfs_inode_getallocflag - get an allocation state of the inode
  * @param xfsfs A xfsfs file system information structure
  * @param dino_inum Metadata address
@@ -105,10 +119,20 @@ TSK_FS_META_FLAG_ENUM xfs_inode_getallocflag(
     // while not leaf node
     while(cur_inobt_block->bb_level > 0)
     {
+        if(cur_inobt_block->bb_numrecs == 0)
+        {
+            if (tsk_verbose)
+            {
+                tsk_fprintf(stderr, "xfs_inode_getallocflag: empty node in AGI tree");
+            }
+
+            return (TSK_FS_META_FLAG_ENUM) NULL;
+        }
+
         // read all the keys
         len = cur_inobt_block->bb_numrecs * sizeof(xfs_inobt_key_t);
         cnt = tsk_fs_read(fs, 
-            (TSK_OFF_T) sb->sb_blocksize * cur_block_num + sizeof(xfs_inobt_key_t),
+            (TSK_OFF_T) sb->sb_blocksize * cur_block_num + sizeof(xfs_inobt_block_t),
             (char *) ikeys,
             len);
         if (cnt != len) {
@@ -122,12 +146,14 @@ TSK_FS_META_FLAG_ENUM xfs_inode_getallocflag(
             return (TSK_FS_META_FLAG_ENUM) NULL;
         }
 
+        uint32_t maxrecs = xfs_inobt_maxrecs(sb, 0 /* not leaf */);
+
         // read all the node pointers
         len = cur_inobt_block->bb_numrecs * sizeof(xfs_inobt_ptr_t);
         cnt = tsk_fs_read(fs,
             (TSK_OFF_T) sb->sb_blocksize * cur_block_num 
                 + (TSK_OFF_T) sizeof(xfs_inobt_block_t) 
-                + (TSK_OFF_T) (cur_inobt_block->bb_numrecs * sizeof(xfs_inobt_key_t)),
+                + (TSK_OFF_T) (maxrecs * sizeof(xfs_inobt_key_t)),
                 (char *) iptrs, 
                 len);
         if (cnt != len) {
@@ -141,48 +167,68 @@ TSK_FS_META_FLAG_ENUM xfs_inode_getallocflag(
             return (TSK_FS_META_FLAG_ENUM) NULL;
         }
 
-        // iterate over the keys
+        // iterate over the keys (in linear time for now, todo binary search)
+        // XFS should guarantee that keys/ptrs are sorted from lo to hi
         found_key = false;
         for(cur_key = 0; cur_key < cur_inobt_block->bb_numrecs; cur_key++)
         {
             ikeys[cur_key].ir_startino = 
                 tsk_getu32(TSK_BIG_ENDIAN, &ikeys[cur_key].ir_startino);
 
-            if(dino_aginum >= ikeys[cur_key].ir_startino
-                && dino_aginum - ikeys[cur_key].ir_startino < 64)
+            if(dino_aginum == ikeys[cur_key].ir_startino)
+            {
+                // exact match found, increment the cur_key, terminate the loop
+                found_key = true;
+                cur_key++;
+                break;
+            }
+            else if(dino_aginum > ikeys[cur_key].ir_startino)
             {
-                // found in a range, go one level down in b+tree, read the next
+                // inode can be in the range, but we aren't sure
+                // just take note, continue search
                 found_key = true;
+            }
+            else
+            {
+                // current key's startino is larger than the inode we look for
+                // terminate the loop
+                break;
+            }
+        }
+
+        if(found_key)
+        {
+            // if exact match was found, cur_key is artificially incremented
+            // otherwise cur_key also one value more than the valid one
+            cur_key--;
 
-                cur_block_num = (TSK_DADDR_T) ag_num * (TSK_DADDR_T) sb->sb_agblocks
+            cur_block_num = (TSK_DADDR_T) ag_num * (TSK_DADDR_T) sb->sb_agblocks
                     + (TSK_DADDR_T) tsk_getu32(TSK_BIG_ENDIAN, &iptrs[cur_key]);
 
-                if (tsk_verbose) { tsk_fprintf(stderr, "go one level down in b+tree, cur_block_num = %u \n", cur_block_num); }
+            if (tsk_verbose) { tsk_fprintf(stderr, "go one level down in b+tree, cur_block_num = %u at bb_level = %" PRIu64 "\n", cur_block_num, cur_inobt_block->bb_level); }
 
-                len = sizeof(xfs_inobt_block_t);
-                cnt = tsk_fs_read(fs,
-                    (TSK_OFF_T) sb->sb_blocksize * cur_block_num,
-                    (char *) cur_inobt_block,
-                    sizeof(xfs_inobt_block_t));
-                if (cnt != len) {
-                    if (cnt >= 0) {
-                        tsk_error_reset();
-                        tsk_error_set_errno(TSK_ERR_FS_READ);
-                    }
-                    tsk_error_set_errstr2("%s: Inode %" PRIuINUM, myname,
-                        dino_inum);
-                    free(cur_inobt_block);
-                    return (TSK_FS_META_FLAG_ENUM) NULL;
+            len = sizeof(xfs_inobt_block_t);
+            cnt = tsk_fs_read(fs,
+                (TSK_OFF_T) sb->sb_blocksize * cur_block_num,
+                (char *) cur_inobt_block,
+                sizeof(xfs_inobt_block_t));
+            if (cnt != len) {
+                if (cnt >= 0) {
+                    tsk_error_reset();
+                    tsk_error_set_errno(TSK_ERR_FS_READ);
                 }
-
-                cur_inobt_block->bb_level = 
-                    tsk_getu16(TSK_BIG_ENDIAN, &cur_inobt_block->bb_level);
-                cur_inobt_block->bb_numrecs =
-                    tsk_getu16(TSK_BIG_ENDIAN, &cur_inobt_block->bb_numrecs);
+                tsk_error_set_errstr2("%s: Inode %" PRIuINUM, myname,
+                    dino_inum);
+                free(cur_inobt_block);
+                return (TSK_FS_META_FLAG_ENUM) NULL;
             }
-        }
 
-        if(!found_key)
+            cur_inobt_block->bb_level =
+                tsk_getu16(TSK_BIG_ENDIAN, &cur_inobt_block->bb_level);
+            cur_inobt_block->bb_numrecs =
+                tsk_getu16(TSK_BIG_ENDIAN, &cur_inobt_block->bb_numrecs);
+        }
+        else
         {
             // The inode is not in a Inode B+tree, that means it's not tracked
             if (tsk_verbose) { tsk_fprintf(stderr, "xfs_inode_getallocflag: Inode %" PRIuINUM " not found in AGI tree, it's not tracked \n", dino_inum); }
@@ -194,11 +240,21 @@ TSK_FS_META_FLAG_ENUM xfs_inode_getallocflag(
 
     // Now we are at the leaf node
 
+    if(cur_inobt_block->bb_numrecs == 0)
+    {
+        if (tsk_verbose)
+        {
+            tsk_fprintf(stderr, "xfs_inode_getallocflag: empty leaf in AGI tree");
+        }
+
+        return (TSK_FS_META_FLAG_ENUM) NULL;
+    }
+
     // read all the records
     len = cur_inobt_block->bb_numrecs * sizeof(xfs_inobt_rec_t);
     cnt = tsk_fs_read(fs,
         (TSK_OFF_T) sb->sb_blocksize * cur_block_num
-            + sizeof(xfs_btree_sblock_t),
+            + sizeof(xfs_inobt_block_t),
                 (char *) irecs,
                 len);
     if (cnt != len) {
@@ -1152,7 +1208,7 @@ xfs_block_getflags(TSK_FS_INFO * a_fs, TSK_DADDR_T a_addr)
 
         // iterate over the keys
         found = false;
-        for(cur_key = 0; cur_key < cur_btree_sblock->bb_numrecs; cur_key++)
+        for(cur_key = 0; !found && cur_key < cur_btree_sblock->bb_numrecs; cur_key++)
         {
             recs[cur_key].ar_startblock =
                 tsk_getu32(TSK_BIG_ENDIAN, &recs[cur_key].ar_startblock);
@@ -1870,9 +1926,7 @@ xfs_istat(TSK_FS_INFO * fs, TSK_FS_ISTAT_FLAG_ENUM istat_flags, FILE * hFile, TS
  * Calculate number of records in a bmap btree inode root.
  */
 uint32_t
-xfs_bmdr_maxrecs(
-	uint32_t	blocklen,
-	bool		leaf)
+xfs_bmdr_maxrecs(uint32_t blocklen, bool leaf)
 {
 	blocklen -= sizeof(xfs_bmdr_block_t);
 
@@ -2101,9 +2155,11 @@ visit_btree_node(
         bool is_root)
 {
     XFSFS_INFO *xfs = (XFSFS_INFO *) a_fs;
-    // xfs_bmdr_block  and xfs_bmbt_block_t share those two fields
+
+    // xfs_bmdr_block and xfs_bmbt_block_t share those two fields
     uint16_t bb_numrecs = 0;
     uint16_t bb_level = 0;
+
     uint16_t header_offset = 0;
     ssize_t len = 0;
     ssize_t cnt = 0;