[syslinux] [GIT-PULL] XFS filesystem driver

Paulo Alcantara pcacjr at zytor.com
Sun Sep 2 18:22:42 PDT 2012


This pull request contains the XFS filesystem driver for Syslinux.

Due to historical reasons (SGI IRIX's design of disk layouts), the first
sector in the primary AG on XFS filesystems contains the superblock,
which is a problem with BIOSes, since VBRs must be loaded up from the
first sector of the active partition.

Thus, we needed to handle this issue by putting the Syslinux
bootsector hard-coded in the 4th sector (at offset 2048) which is an
unused area in XFS filesystems. The MBR code will know how to load the
Syslinux bootsector from a XFS filesystem by checking the first 4 bytes
in the first sector of the active partition to see it contains a valid
XFS's superblock magic number. If the number matches, then it will load
the bootsector from 4th sector instead.

Since we hard-code the Syslinux bootsector at 0x800 (4th sector) due to
BIOS limitation, then we need to have a XFS filesystem with 4 KiB
filesystem block size. You can also test it with a filesystem block size
larger than 4 KiB but it won't _probably_ work.

Hi Peter,

Please consider pulling it.

		Paulo

The following changes since commit 0a0e0e41cad93cd16c323cf16f40264a21eedd6c:

  Correct initialization of the cache doubly-linked list (2012-07-19 07:29:55 -0700)

are available in the git repository at:

  git://zytor.com/users/pcacjr/syslinux.git xfs-for-hpa

for you to fetch changes up to 75cf6cebf0ffdf75f359528b01fc9039062e7b34:

  xfs: Fix the way we check di_mode of an inode (2012-09-02 20:07:20 -0300)

Signed-off-by: Paulo Alcantara <pcacjr at zytor.com>

----------------------------------------------------------------
Chen Baozi (14):
      extlinux: put set_attributes() back to ext2_fat_install_file().
      Fix the calculation of the block of the root of the inode B+tree.
      Add support for 64-bit filesystem compatible struct inode.
      xfs: rework the logic of xfs_get_ino_core()
      xfs: Implement dir2_block_find_entry() function.
      xfs: Implement xfs_dir2_leaf_find_entry() logic.
      xfs: get_dirblks() with count.
      xfs: rework xfs_dir2_node_find_entry()
      xfs: Add xfs_fmt_btree_find_entry()
      xfs: Add full B+tree search support in xfs_dir2_node_find_entry()
      xfs: cleanup unused structure
      xfs: Rework xfs_dir2_get_right_blk()
      xfs: Add XFS_DINODE_FMT_BTREE support in xfs_next_extent()
      xfs: Add xfs_readlink()

Paulo Alcantara (46):
      EXTLINUX: Initial XFS filesystem support
      mbr: Add support for loading VBRs from XFS filesystems
      xfs: Initial skeleton for XFS filesystem support
      xfs: Implement xfs_fs_init() function
      xfs: Add xfs_iget_root() to XFS filesystem ops
      xfs: Fix inode lookup in chunks of 64 inodes
      xfs: Add xfs_get_agi() function
      xfs: Fix inode size attribution
      xfs: Add xfs_iget() to filesystem ops
      xfs: Fix some inode number conversions
      xfs: Remove duplicate variable attribution
      xfs: Some bugfixes
      xfs: Remove unnecessary check in xfs_iget() function
      xfs: Make for-statement declaration more readable
      xfs: Fix minor typo
      xfs: Add xfs_getfssec() and xfs_next_extent() functions
      xfs: Cleanup
      xfs: Make sure that the dinode is read with success
      xfs: Only call fill_xfs_inode_pvt() if dinode was read
      xfs: Cleanup fill_xfs_inode_pvt() function
      xfs: Cleanup
      xfs: Add xfs_readdir() to filesystem ops
      xfs: Remove unnecessary debug message in xfs_getfssec()
      xfs: Fix bug in xfs_dir2_leaf_find_entry() function
      xfs: Make xfs_da_hashname() function static
      xfs: Fix binary search in xfs_dir2_leaf_find_entry() function
      xfs: Implement xfs_dir2_leaf_readdir() function
      xfs: Use bmbt_irec_get() to get extent information instead
      xfs: Use dprintf() for debug messages in xfs_debug()
      xfs: Use xfs_debug() for "Entry not found!" message
      xfs: Implement xfs_dir2_node_find_entry() function
      xfs: Fix memory leaks in xfs_dir2_node_find_entry() function
      xfs: Move dir2 functions to another source file
      xfs: Remove trailing whitespace in xfs_dir2_isleaf() function
      xfs: Move readdir functions to another source file
      xfs: Add xfs_fmt_local_find_entry() function
      xfs: Add xfs_fmt_local_readdir() function
      EXTLINUX: Add sanity check for XFS filesystems
      xfs: Implement xfs_readdir_dir2_node() function
      xfs: Cleanup xfs_readdir_dir2_leaf() function
      xfs: Fix memory leak in xfs_dir2_node_find_entry() function
      xfs: Remove some trailing whitespaces
      xfs: Cleanup and remove some trailing whitespaces
      xfs: Cleanup and remove some trailing whitespaces
      xfs: Cleanup previous commit
      xfs: Fix the way we check di_mode of an inode

 core/fs/xfs/misc.h        |   50 +++
 core/fs/xfs/xfs.c         |  439 ++++++++++++++++++++++++++
 core/fs/xfs/xfs.h         |  752 ++++++++++++++++++++++++++++++++++++++++++++
 core/fs/xfs/xfs_ag.h      |  189 +++++++++++
 core/fs/xfs/xfs_dinode.c  |   61 ++++
 core/fs/xfs/xfs_dinode.h  |   23 ++
 core/fs/xfs/xfs_dir2.c    |  759 +++++++++++++++++++++++++++++++++++++++++++++
 core/fs/xfs/xfs_dir2.h    |   54 ++++
 core/fs/xfs/xfs_fs.h      |  501 ++++++++++++++++++++++++++++++
 core/fs/xfs/xfs_readdir.c |  404 ++++++++++++++++++++++++
 core/fs/xfs/xfs_readdir.h |   30 ++
 core/fs/xfs/xfs_sb.h      |  206 ++++++++++++
 core/fs/xfs/xfs_types.h   |  135 ++++++++
 core/include/fs.h         |    6 +-
 core/ldlinux.asm          |    2 +
 extlinux/main.c           |  235 +++++++++++---
 extlinux/misc.h           |   50 +++
 extlinux/xfs.h            |   25 ++
 extlinux/xfs_fs.h         |  501 ++++++++++++++++++++++++++++++
 extlinux/xfs_sb.h         |  476 ++++++++++++++++++++++++++++
 extlinux/xfs_types.h      |  135 ++++++++
 libinstaller/syslxfs.h    |    5 +-
 mbr/mbr.S                 |   13 +
 23 files changed, 5011 insertions(+), 40 deletions(-)
 create mode 100644 core/fs/xfs/misc.h
 create mode 100644 core/fs/xfs/xfs.c
 create mode 100644 core/fs/xfs/xfs.h
 create mode 100644 core/fs/xfs/xfs_ag.h
 create mode 100644 core/fs/xfs/xfs_dinode.c
 create mode 100644 core/fs/xfs/xfs_dinode.h
 create mode 100644 core/fs/xfs/xfs_dir2.c
 create mode 100644 core/fs/xfs/xfs_dir2.h
 create mode 100644 core/fs/xfs/xfs_fs.h
 create mode 100644 core/fs/xfs/xfs_readdir.c
 create mode 100644 core/fs/xfs/xfs_readdir.h
 create mode 100644 core/fs/xfs/xfs_sb.h
 create mode 100644 core/fs/xfs/xfs_types.h
 create mode 100644 extlinux/misc.h
 create mode 100644 extlinux/xfs.h
 create mode 100644 extlinux/xfs_fs.h
 create mode 100644 extlinux/xfs_sb.h
 create mode 100644 extlinux/xfs_types.h

diff --git a/core/fs/xfs/misc.h b/core/fs/xfs/misc.h
new file mode 100644
index 0000000..7f2f1b3
--- /dev/null
+++ b/core/fs/xfs/misc.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2012 Paulo Alcantara <pcacjr at zytor.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef MISC_H_
+#define MISC_H_
+
+/* Return a 64-bit litte-endian value from a given 64-bit big-endian one */
+static inline uint64_t be64_to_cpu(uint64_t val)
+{
+    return (uint64_t)((((uint64_t)val & (uint64_t)0x00000000000000ffULL) << 56) |
+		      (((uint64_t)val & (uint64_t)0x000000000000ff00ULL) << 40) |
+		      (((uint64_t)val & (uint64_t)0x0000000000ff0000ULL) << 24) |
+		      (((uint64_t)val & (uint64_t)0x00000000ff000000ULL) <<  8) |
+		      (((uint64_t)val & (uint64_t)0x000000ff00000000ULL) >>  8) |
+		      (((uint64_t)val & (uint64_t)0x0000ff0000000000ULL) >> 24) |
+		      (((uint64_t)val & (uint64_t)0x00ff000000000000ULL) >> 40) |
+		      (((uint64_t)val & (uint64_t)0xff00000000000000ULL) >> 56));
+}
+
+/* Return a 32-bit litte-endian value from a given 32-bit big-endian one */
+static inline uint32_t be32_to_cpu(uint32_t val)
+{
+    return (uint32_t)((((uint32_t)val & (uint32_t)0x000000ffUL) << 24) |
+		      (((uint32_t)val & (uint32_t)0x0000ff00UL) <<  8) |
+		      (((uint32_t)val & (uint32_t)0x00ff0000UL) >>  8) |
+		      (((uint32_t)val & (uint32_t)0xff000000UL) >> 24));
+}
+
+/* Return a 16-bit litte-endian value from a given 16-bit big-endian one */
+static inline uint16_t be16_to_cpu(uint16_t val)
+{
+    return (uint16_t)((((uint16_t)val & (uint16_t)0x00ffU) << 8) |
+		      (((uint16_t)val & (uint16_t)0xff00U) >> 8));
+}
+
+#endif /* MISC_H_ */
diff --git a/core/fs/xfs/xfs.c b/core/fs/xfs/xfs.c
new file mode 100644
index 0000000..98d6255
--- /dev/null
+++ b/core/fs/xfs/xfs.c
@@ -0,0 +1,439 @@
+/*
+ * Copyright (c) 2012 Paulo Alcantara <pcacjr at zytor.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <dprintf.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/dirent.h>
+#include <cache.h>
+#include <core.h>
+#include <disk.h>
+#include <fs.h>
+#include <ilog2.h>
+#include <klibc/compiler.h>
+#include <ctype.h>
+
+#include "codepage.h"
+#include "xfs_types.h"
+#include "xfs_sb.h"
+#include "xfs_ag.h"
+#include "misc.h"
+#include "xfs.h"
+#include "xfs_dinode.h"
+#include "xfs_dir2.h"
+#include "xfs_readdir.h"
+
+static inline int xfs_fmt_local_readdir(struct file *file,
+					struct dirent *dirent, xfs_dinode_t *core)
+{
+    return xfs_readdir_dir2_block(file, dirent, core);
+}
+
+static inline int xfs_fmt_extents_readdir(struct file *file,
+					  struct dirent *dirent,
+					  xfs_dinode_t *core)
+{
+    int retval;
+
+    if (be32_to_cpu(core->di_nextents) <= 1) {
+	/* Single-block Directories */
+	retval = xfs_readdir_dir2_block(file, dirent, core);
+    } else if (xfs_dir2_isleaf(file->fs, core)) {
+	/* Leaf Directory */
+	retval = xfs_readdir_dir2_leaf(file, dirent, core);
+    } else {
+	/* Node Directory */
+	retval = xfs_readdir_dir2_node(file, dirent, core);
+    }
+
+    return retval;
+}
+
+static int xfs_readdir(struct file *file, struct dirent *dirent)
+{
+    struct fs_info *fs = file->fs;
+    xfs_dinode_t *core;
+    struct inode *inode = file->inode;
+    int retval = -1;
+
+    core = xfs_dinode_get_core(fs, inode->ino);
+    if (!core) {
+	xfs_error("Failed to get dinode from disk (ino %llx)", inode->ino);
+	return -1;
+    }
+
+    if (core->di_format == XFS_DINODE_FMT_LOCAL)
+	retval = xfs_fmt_local_readdir(file, dirent, core);
+    else if (core->di_format == XFS_DINODE_FMT_EXTENTS)
+	retval = xfs_fmt_extents_readdir(file, dirent, core);
+
+    return retval;
+}
+
+static uint32_t xfs_getfssec(struct file *file, char *buf, int sectors,
+			     bool *have_more)
+{
+    return generic_getfssec(file, buf, sectors, have_more);
+}
+
+static int xfs_next_extent(struct inode *inode, uint32_t lstart)
+{
+    struct fs_info *fs = inode->fs;
+    xfs_dinode_t *core = NULL;
+    xfs_bmbt_irec_t rec;
+    block_t bno;
+    xfs_bmdr_block_t *rblock;
+    int fsize;
+    xfs_bmbt_ptr_t *pp;
+    xfs_btree_block_t *blk;
+    uint16_t nextents;
+    block_t nextbno;
+    uint32_t index;
+
+    (void)lstart;
+
+    core = xfs_dinode_get_core(fs, inode->ino);
+    if (!core) {
+	xfs_error("Failed to get dinode from disk (ino %llx)", inode->ino);
+	goto out;
+    }
+
+    /* The data fork contains the file's data extents */
+    if (XFS_PVT(inode)->i_cur_extent == be32_to_cpu(core->di_nextents))
+        goto out;
+
+    if (core->di_format == XFS_DINODE_FMT_EXTENTS) {
+	bmbt_irec_get(&rec, (xfs_bmbt_rec_t *)&core->di_literal_area[0] +
+						XFS_PVT(inode)->i_cur_extent++);
+
+	bno = fsblock_to_bytes(fs, rec.br_startblock) >> BLOCK_SHIFT(fs);
+
+	XFS_PVT(inode)->i_offset = rec.br_startoff;
+
+	inode->next_extent.pstart = bno << BLOCK_SHIFT(fs) >> SECTOR_SHIFT(fs);
+	inode->next_extent.len = ((rec.br_blockcount << BLOCK_SHIFT(fs)) +
+				  SECTOR_SIZE(fs) - 1) >> SECTOR_SHIFT(fs);
+    } else if (core->di_format == XFS_DINODE_FMT_BTREE) {
+        xfs_debug("XFS_DINODE_FMT_BTREE");
+        index = XFS_PVT(inode)->i_cur_extent++;
+        rblock = (xfs_bmdr_block_t *)&core->di_literal_area[0];
+        fsize = XFS_DFORK_SIZE(core, fs, XFS_DATA_FORK);
+        pp = XFS_BMDR_PTR_ADDR(rblock, 1, xfs_bmdr_maxrecs(fsize, 0));
+        bno = fsblock_to_bytes(fs, be64_to_cpu(pp[0])) >> BLOCK_SHIFT(fs);
+
+        /* Find the leaf */
+        for (;;) {
+            blk = (xfs_btree_block_t *)get_cache(fs->fs_dev, bno);
+            if (be16_to_cpu(blk->bb_level) == 0)
+                break;
+
+            pp = XFS_BMBT_PTR_ADDR(fs, blk, 1,
+                    xfs_bmdr_maxrecs(XFS_INFO(fs)->blocksize, 0));
+            bno = fsblock_to_bytes(fs, be64_to_cpu(pp[0])) >> BLOCK_SHIFT(fs);
+        }
+
+        /* Find the right extent among threaded leaves */
+        for (;;) {
+            nextbno = be64_to_cpu(blk->bb_u.l.bb_rightsib);
+            nextents = be16_to_cpu(blk->bb_numrecs);
+            if (nextents - index > 0) {
+                bmbt_irec_get(&rec, XFS_BMDR_REC_ADDR(blk, index + 1));
+
+                bno = fsblock_to_bytes(fs, rec.br_startblock)
+						>> BLOCK_SHIFT(fs);
+
+                XFS_PVT(inode)->i_offset = rec.br_startoff;
+
+                inode->next_extent.pstart = bno << BLOCK_SHIFT(fs)
+                                                >> SECTOR_SHIFT(fs);
+                inode->next_extent.len = ((rec.br_blockcount
+                                            << BLOCK_SHIFT(fs))
+                                            + SECTOR_SIZE(fs) - 1)
+                                            >> SECTOR_SHIFT(fs);
+                break;
+            }
+
+            index -= nextents;
+            bno = fsblock_to_bytes(fs, nextbno) >> BLOCK_SHIFT(fs);
+            blk = (xfs_btree_block_t *)get_cache(fs->fs_dev, bno);
+        }
+    }
+
+    return 0;
+
+out:
+    return -1;
+}
+
+static inline struct inode *xfs_fmt_local_find_entry(const char *dname,
+						     struct inode *parent,
+						     xfs_dinode_t *core)
+{
+    return xfs_dir2_local_find_entry(dname, parent, core);
+}
+
+static inline struct inode *xfs_fmt_extents_find_entry(const char *dname,
+						       struct inode *parent,
+						       xfs_dinode_t *core)
+{
+    struct inode *inode;
+
+    if (be32_to_cpu(core->di_nextents) <= 1) {
+        /* Single-block Directories */
+        inode = xfs_dir2_block_find_entry(dname, parent, core);
+    } else if (xfs_dir2_isleaf(parent->fs, core)) {
+        /* Leaf Directory */
+	inode = xfs_dir2_leaf_find_entry(dname, parent, core);
+    } else {
+        /* Node Directory */
+        inode = xfs_dir2_node_find_entry(dname, parent, core);
+    }
+
+    return inode;
+}
+
+static inline struct inode *xfs_fmt_btree_find_entry(const char *dname,
+                                                     struct inode *parent,
+                                                     xfs_dinode_t *core)
+{
+    return xfs_dir2_node_find_entry(dname, parent, core);
+}
+
+static struct inode *xfs_iget(const char *dname, struct inode *parent)
+{
+    struct fs_info *fs = parent->fs;
+    xfs_dinode_t *core = NULL;
+    struct inode *inode = NULL;
+
+    xfs_debug("dname %s parent %p parent ino %lu", dname, parent, parent->ino);
+
+    core = xfs_dinode_get_core(fs, parent->ino);
+    if (!core) {
+        xfs_error("Failed to get dinode from disk (ino 0x%llx)", parent->ino);
+        goto out;
+    }
+
+    if (core->di_format == XFS_DINODE_FMT_LOCAL) {
+	inode = xfs_fmt_local_find_entry(dname, parent, core);
+    } else if (core->di_format == XFS_DINODE_FMT_EXTENTS) {
+        inode = xfs_fmt_extents_find_entry(dname, parent, core);
+    } else if (core->di_format == XFS_DINODE_FMT_BTREE) {
+        inode = xfs_fmt_btree_find_entry(dname, parent, core);
+    } else {
+	xfs_debug("format %hhu", core->di_format);
+	xfs_debug("TODO: format \"local\" and \"extents\" are the only "
+		  "supported ATM");
+	goto out;
+    }
+
+    if (!inode) {
+	xfs_debug("Entry not found!");
+	goto out;
+    }
+
+    if (inode->mode == DT_REG) {
+	XFS_PVT(inode)->i_offset = 0;
+	XFS_PVT(inode)->i_cur_extent = 0;
+    } else if (inode->mode == DT_DIR) {
+	XFS_PVT(inode)->i_btree_offset = 0;
+	XFS_PVT(inode)->i_leaf_ent_offset = 0;
+    }
+
+    return inode;
+
+out:
+    return NULL;
+}
+
+static int xfs_readlink(struct inode *inode, char *buf)
+{
+    struct fs_info *fs = inode->fs;
+    xfs_dinode_t *core;
+    int pathlen = -1;
+    xfs_bmbt_irec_t rec;
+    block_t db;
+    char *dir_buf;
+
+    core = xfs_dinode_get_core(fs, inode->ino);
+    if (!core) {
+	xfs_error("Failed to get dinode from disk (ino 0x%llx)", inode->ino);
+	goto out;
+    }
+
+    pathlen = be64_to_cpu(core->di_size);
+    if (!pathlen)
+	goto out;
+
+    if (pathlen < 0 || pathlen > MAXPATHLEN) {
+	xfs_error("inode (%llu) bad symlink length (%d)",
+		  inode->ino, pathlen);
+	goto out;
+    }
+
+    if (core->di_format == XFS_DINODE_FMT_LOCAL) {
+	memcpy(buf, (char *)&core->di_literal_area[0], pathlen);
+    } else if (core->di_format == XFS_DINODE_FMT_EXTENTS) {
+	bmbt_irec_get(&rec, (xfs_bmbt_rec_t *)&core->di_literal_area[0]);
+	db = fsblock_to_bytes(fs, rec.br_startblock) >> BLOCK_SHIFT(fs);
+	dir_buf = xfs_dir2_get_dirblks(fs, db, rec.br_blockcount);
+
+        /*
+         * Syslinux only supports filesystem block size larger than or equal to
+	 * 4 KiB. Thus, one directory block is far enough to hold the maximum
+	 * symbolic link file content, which is only 1024 bytes long.
+         */
+	memcpy(buf, dir_buf, pathlen);
+	free(dir_buf);
+    }
+
+out:
+    return pathlen;
+}
+
+static struct inode *xfs_iget_root(struct fs_info *fs)
+{
+    xfs_dinode_t *core = NULL;
+    struct inode *inode = xfs_new_inode(fs);
+
+    xfs_debug("Looking for the root inode...");
+
+    core = xfs_dinode_get_core(fs, XFS_INFO(fs)->rootino);
+    if (!core) {
+	xfs_error("Inode core's magic number does not match!");
+	xfs_debug("magic number 0x%04x", be16_to_cpu(core->di_magic));
+	goto out;
+    }
+
+    fill_xfs_inode_pvt(fs, inode, XFS_INFO(fs)->rootino);
+
+    xfs_debug("Root inode has been found!");
+
+    if ((be16_to_cpu(core->di_mode) & S_IFMT) != S_IFDIR) {
+	xfs_error("root inode is not a directory ?! No makes sense...");
+	goto out;
+    }
+
+    inode->ino			= XFS_INFO(fs)->rootino;
+    inode->mode 		= DT_DIR;
+    inode->size 		= be64_to_cpu(core->di_size);
+
+    return inode;
+
+out:
+    free(inode);
+
+    return NULL;
+}
+
+static inline int xfs_read_superblock(struct fs_info *fs, xfs_sb_t *sb)
+{
+    struct disk *disk = fs->fs_dev->disk;
+
+    if (!disk->rdwr_sectors(disk, sb, XFS_SB_DADDR, 1, false))
+	return -1;
+
+    return 0;
+}
+
+static struct xfs_fs_info *xfs_new_sb_info(xfs_sb_t *sb)
+{
+    struct xfs_fs_info *info;
+
+    info = malloc(sizeof *info);
+    if (!info)
+	malloc_error("xfs_fs_info structure");
+
+    info->blocksize		= be32_to_cpu(sb->sb_blocksize);
+    info->block_shift		= sb->sb_blocklog;
+    info->dirblksize		= 1 << (sb->sb_blocklog + sb->sb_dirblklog);
+    info->dirblklog		= sb->sb_dirblklog;
+    info->inopb_shift 		= sb->sb_inopblog;
+    info->agblk_shift 		= sb->sb_agblklog;
+    info->rootino 		= be64_to_cpu(sb->sb_rootino);
+    info->agblocks 		= be32_to_cpu(sb->sb_agblocks);
+    info->agblocks_shift 	= sb->sb_agblklog;
+    info->agcount 		= be32_to_cpu(sb->sb_agcount);
+    info->inodesize 		= be16_to_cpu(sb->sb_inodesize);
+    info->inode_shift 		= sb->sb_inodelog;
+
+    return info;
+}
+
+static int xfs_fs_init(struct fs_info *fs)
+{
+    struct disk *disk = fs->fs_dev->disk;
+    xfs_sb_t sb;
+    struct xfs_fs_info *info;
+
+    xfs_debug("fs %p", fs);
+
+    SECTOR_SHIFT(fs) = disk->sector_shift;
+    SECTOR_SIZE(fs) = 1 << SECTOR_SHIFT(fs);
+
+    if (xfs_read_superblock(fs, &sb)) {
+	xfs_error("Superblock read failed");
+	goto out;
+    }
+
+    if (!xfs_is_valid_magicnum(&sb)) {
+	xfs_error("Invalid superblock");
+	goto out;
+    }
+
+    xfs_debug("magicnum 0x%lX", be32_to_cpu(sb.sb_magicnum));
+
+    info = xfs_new_sb_info(&sb);
+    if (!info) {
+	xfs_error("Failed to fill in filesystem-specific info structure");
+	goto out;
+    }
+
+    fs->fs_info = info;
+
+    xfs_debug("block_shift %u blocksize 0x%lX (%lu)", info->block_shift,
+	      info->blocksize, info->blocksize);
+
+    xfs_debug("rootino 0x%llX (%llu)", info->rootino, info->rootino);
+
+    BLOCK_SHIFT(fs) = info->block_shift;
+    BLOCK_SIZE(fs) = info->blocksize;
+
+    cache_init(fs->fs_dev, BLOCK_SHIFT(fs));
+
+    XFS_INFO(fs)->dirleafblk = xfs_dir2_db_to_da(fs, XFS_DIR2_LEAF_FIRSTDB(fs));
+
+    return BLOCK_SHIFT(fs);
+
+out:
+    return -1;
+}
+
+const struct fs_ops xfs_fs_ops = {
+    .fs_name		= "xfs",
+    .fs_flags		= FS_USEMEM | FS_THISIND,
+    .fs_init		= xfs_fs_init,
+    .iget_root		= xfs_iget_root,
+    .searchdir		= NULL,
+    .getfssec		= xfs_getfssec,
+    .load_config	= generic_load_config,
+    .close_file         = generic_close_file,
+    .mangle_name	= generic_mangle_name,
+    .readdir		= xfs_readdir,
+    .iget		= xfs_iget,
+    .next_extent	= xfs_next_extent,
+    .readlink		= xfs_readlink,
+};
diff --git a/core/fs/xfs/xfs.h b/core/fs/xfs/xfs.h
new file mode 100644
index 0000000..da57221
--- /dev/null
+++ b/core/fs/xfs/xfs.h
@@ -0,0 +1,752 @@
+/*
+ * Copyright (c) 2012 Paulo Alcantara <pcacjr at zytor.com>
+ *
+ * Some parts borrowed from Linux kernel tree (linux/fs/xfs):
+ *
+ * Copyright (c) 2000-2005 Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef XFS_H_
+#define XFS_H_
+
+#include <disk.h>
+#include <fs.h>
+#include <dprintf.h>
+
+#include "xfs_types.h"
+#include "xfs_ag.h"
+
+#define xfs_error(fmt, args...) \
+    printf("xfs: " fmt "\n", ## args);
+
+#define xfs_debug(fmt, args...) \
+    dprintf("%s: " fmt "\n", __func__, ## args);
+
+struct xfs_fs_info;
+
+#define XFS_INFO(fs) ((struct xfs_fs_info *)((fs)->fs_info))
+#define XFS_PVT(ino) ((struct xfs_inode *)((ino)->pvt))
+
+#define XFS_INO_MASK(k)                 (uint32_t)((1ULL << (k)) - 1)
+#define XFS_INO_OFFSET_BITS(fs)		(fs)->inopb_shift
+#define XFS_INO_AGINO_BITS(fs) \
+    (XFS_INFO((fs))->inopb_shift + XFS_INFO((fs))->agblk_shift)
+
+#define XFS_INO_TO_AGINO(fs, i) \
+    ((xfs_agino_t)(i) & XFS_INO_MASK(XFS_INO_AGINO_BITS(fs)))
+
+#define XFS_INO_TO_AGNO(fs, ino) \
+    ((xfs_agnumber_t)((ino) >> (XFS_INFO((fs))->inopb_shift + \
+				XFS_INFO((fs))->agblk_shift)))
+
+#define XFS_INO_TO_OFFSET(fs, i) \
+	((int)(i) & XFS_INO_MASK(XFS_INO_OFFSET_BITS(fs)))
+
+#define XFS_AGNO_TO_FSB(fs, agno) \
+    ((block_t)((agno) << XFS_INFO((fs))->agblocks_shift))
+
+#define XFS_AGI_OFFS(fs, mp) \
+    ((xfs_agi_t *)((uint8_t *)(mp) + 2 * SECTOR_SIZE((fs))))
+
+#define XFS_GET_DIR_INO4(di) \
+    (((uint32_t)(di).i[0] << 24) | ((di).i[1] << 16) | ((di).i[2] << 8) | \
+		((di).i[3]))
+
+#define XFS_DI_HI(di) \
+    (((uint32_t)(di).i[1] << 16) | ((di).i[2] << 8) | ((di).i[3]))
+
+#define XFS_DI_LO(di) \
+    (((uint32_t)(di).i[4] << 24) | ((di).i[5] << 16) | ((di).i[6] << 8) | \
+		((di).i[7]))
+
+#define XFS_GET_DIR_INO8(di) \
+    (((xfs_ino_t)XFS_DI_LO(di) & 0xffffffffULL) | \
+     ((xfs_ino_t)XFS_DI_HI(di) << 32))
+
+#define XFS_FSB_TO_AGNO(fs, fsbno) \
+    ((xfs_agnumber_t)((fsbno) >> XFS_INFO((fs))->agblk_shift))
+#define XFS_FSB_TO_AGBNO(fs, fsbno) \
+    ((xfs_agblock_t)((fsbno) & (uint32_t)((1ULL << \
+					   XFS_INFO((fs))->agblk_shift) - 1)))
+
+#define agblock_to_bytes(fs, x) \
+    ((uint64_t)(x) << BLOCK_SHIFT((fs)))
+#define agino_to_bytes(fs, x) \
+    ((uint64_t)(x) << XFS_INFO((fs))->inode_shift)
+#define agnumber_to_bytes(fs, x) \
+    agblock_to_bytes(fs, (uint64_t)(x) * XFS_INFO((fs))->agblocks)
+#define fsblock_to_bytes(fs,x)				\
+    (agnumber_to_bytes(fs, XFS_FSB_TO_AGNO(fs, (x))) +	\
+     agblock_to_bytes(fs, XFS_FSB_TO_AGBNO(fs, (x))))
+#define ino_to_bytes(fs, x)			   \
+    (agnumber_to_bytes(fs, XFS_INO_TO_AGNO(fs, (x))) +	\
+     agino_to_bytes(fs, XFS_INO_TO_AGINO(fs, (x))))
+
+/* Superblock's LBA */
+#define XFS_SB_DADDR ((xfs_daddr_t)0) /* daddr in filesystem/ag */
+
+/* Magic numbers */
+#define	XFS_AGI_MAGIC 		"XAGI"
+#define XFS_IBT_MAGIC 		"IABT"
+#define XFS_DINODE_MAGIC	"IN"
+
+#define XFS_DIR2_BLOCK_MAGIC    0x58443242U      /* XD2B: single block dirs */
+#define XFS_DIR2_DATA_MAGIC     0x58443244U      /* XD2D: multiblock dirs */
+#define XFS_DIR2_FREE_MAGIC     0x58443246U      /* XD2F: free index blocks */
+
+#define XFS_DIR2_NULL_DATAPTR   ((uint32_t)0)
+
+/* File types and modes */
+#define S_IFMT  	00170000
+#define S_IFSOCK 	0140000
+#define S_IFLNK 	0120000
+#define S_IFREG  	0100000
+#define S_IFBLK  	0060000
+#define S_IFDIR  	0040000
+#define S_IFCHR  	0020000
+#define S_IFIFO  	0010000
+#define S_ISUID  	0004000
+#define S_ISGID  	0002000
+#define S_ISVTX  	0001000
+
+#define MAXPATHLEN 1024
+/*
+ * NOTE: The fields in the superblock are stored in big-endian format on disk.
+ */
+typedef struct xfs_sb {
+    uint32_t	sb_magicnum;	/* magic number == XFS_SB_MAGIC */
+    uint32_t	sb_blocksize;	/* logical block size, bytes */
+    xfs_drfsbno_t	sb_dblocks;	/* number of data blocks */
+    xfs_drfsbno_t	sb_rblocks;	/* number of realtime blocks */
+    xfs_drtbno_t	sb_rextents;	/* number of realtime extents */
+    uuid_t		sb_uuid;	/* file system unique id */
+    xfs_dfsbno_t	sb_logstart;	/* starting block of log if internal */
+    xfs_ino_t	sb_rootino;	/* root inode number */
+    xfs_ino_t	sb_rbmino;	/* bitmap inode for realtime extents */
+    xfs_ino_t	sb_rsumino;	/* summary inode for rt bitmap */
+    xfs_agblock_t	sb_rextsize;	/* realtime extent size, blocks */
+    xfs_agblock_t	sb_agblocks;	/* size of an allocation group */
+    xfs_agnumber_t	sb_agcount;	/* number of allocation groups */
+    xfs_extlen_t	sb_rbmblocks;	/* number of rt bitmap blocks */
+    xfs_extlen_t	sb_logblocks;	/* number of log blocks */
+    uint16_t	sb_versionnum;	/* header version == XFS_SB_VERSION */
+    uint16_t	sb_sectsize;	/* volume sector size, bytes */
+    uint16_t	sb_inodesize;	/* inode size, bytes */
+    uint16_t	sb_inopblock;	/* inodes per block */
+    char	sb_fname[12];	/* file system name */
+    uint8_t	sb_blocklog;	/* log2 of sb_blocksize */
+    uint8_t	sb_sectlog;	/* log2 of sb_sectsize */
+    uint8_t	sb_inodelog;	/* log2 of sb_inodesize */
+    uint8_t	sb_inopblog;	/* log2 of sb_inopblock */
+    uint8_t	sb_agblklog;	/* log2 of sb_agblocks (rounded up) */
+    uint8_t	sb_rextslog;	/* log2 of sb_rextents */
+    uint8_t	sb_inprogress;	/* mkfs is in progress, don't mount */
+    uint8_t	sb_imax_pct;	/* max % of fs for inode space */
+					/* statistics */
+    /*
+     * These fields must remain contiguous.  If you really
+     * want to change their layout, make sure you fix the
+     * code in xfs_trans_apply_sb_deltas().
+     */
+    uint64_t	sb_icount;	/* allocated inodes */
+    uint64_t	sb_ifree;	/* free inodes */
+    uint64_t	sb_fdblocks;	/* free data blocks */
+    uint64_t	sb_frextents;	/* free realtime extents */
+    /*
+     * End contiguous fields.
+     */
+    xfs_ino_t	sb_uquotino;	/* user quota inode */
+    xfs_ino_t	sb_gquotino;	/* group quota inode */
+    uint16_t	sb_qflags;	/* quota flags */
+    uint8_t	sb_flags;	/* misc. flags */
+    uint8_t	sb_shared_vn;	/* shared version number */
+    xfs_extlen_t	sb_inoalignmt;	/* inode chunk alignment, fsblocks */
+    uint32_t	sb_unit;	/* stripe or raid unit */
+    uint32_t	sb_width;	/* stripe or raid width */
+    uint8_t	sb_dirblklog;	/* log2 of dir block size (fsbs) */
+    uint8_t	sb_logsectlog;	/* log2 of the log sector size */
+    uint16_t	sb_logsectsize;	/* sector size for the log, bytes */
+    uint32_t	sb_logsunit;	/* stripe unit size for the log */
+    uint32_t	sb_features2;	/* additional feature bits */
+
+    /*
+     * bad features2 field as a result of failing to pad the sb
+     * structure to 64 bits. Some machines will be using this field
+     * for features2 bits. Easiest just to mark it bad and not use
+     * it for anything else.
+     */
+    uint32_t	sb_bad_features2;
+    uint8_t	pad[304]; /* must be padded to a sector boundary */
+} __attribute__((__packed__)) xfs_sb_t;
+
+/* In-memory structure that stores filesystem-specific information.
+ * The information stored is basically retrieved from the XFS superblock
+ * to be used statically around the driver.
+ */
+struct xfs_fs_info {
+    uint32_t 		blocksize; /* Filesystem block size */
+    uint8_t		block_shift; /* Filesystem block size in bits */
+    uint32_t		dirblksize;
+    uint8_t		dirblklog;
+    uint8_t		inopb_shift;
+    uint8_t		agblk_shift;
+    uint32_t		dirleafblk;
+
+    /* AG number bits (MSB of the inode number) */
+    uint8_t		ag_number_ino_shift;
+
+    xfs_ino_t 		rootino; /* Root inode number for the filesystem */
+    xfs_agblock_t	agblocks; /* Size of each AG in blocks */
+    uint8_t		agblocks_shift; /* agblocks in bits */
+    xfs_agnumber_t	agcount; /* Number of AGs in the filesytem */
+    uint16_t		inodesize; /* Size of the inode in bytes */
+    uint8_t		inode_shift; /* Inode size in bits */
+} __attribute__((__packed__));
+
+typedef struct xfs_agi {
+	/*
+	 * Common allocation group header information
+	 */
+    uint32_t		agi_magicnum;	/* magic number == XFS_AGI_MAGIC */
+    uint32_t		agi_versionnum;	/* header version == XFS_AGI_VERSION */
+    uint32_t		agi_seqno;	/* sequence # starting from 0 */
+    uint32_t		agi_length;	/* size in blocks of a.g. */
+    /*
+     * Inode information
+     * Inodes are mapped by interpreting the inode number, so no
+     * mapping data is needed here.
+     */
+    uint32_t		agi_count;	/* count of allocated inodes */
+    uint32_t		agi_root;	/* root of inode btree */
+    uint32_t		agi_level;	/* levels in inode btree */
+    uint32_t		agi_freecount;	/* number of free inodes */
+    uint32_t		agi_newino;	/* new inode just allocated */
+    uint32_t		agi_dirino;	/* last directory inode chunk */
+    /*
+     * Hash table of inodes which have been unlinked but are
+     * still being referenced.
+     */
+    uint32_t		agi_unlinked[XFS_AGI_UNLINKED_BUCKETS];
+} __attribute__((__packed__)) xfs_agi_t;
+
+/*
+ * Bmap btree record and extent descriptor.
+ *  l0:63 is an extent flag (value 1 indicates non-normal).
+ *  l0:9-62 are startoff.
+ *  l0:0-8 and l1:21-63 are startblock.
+ *  l1:0-20 are blockcount.
+ */
+typedef struct xfs_bmbt_rec {
+    uint64_t l0;
+    uint64_t l1;
+} __attribute__((__packed__)) xfs_bmbt_rec_t;
+
+typedef xfs_bmbt_rec_t xfs_bmdr_rec_t;
+
+/*
+ * Possible extent states.
+ */
+typedef enum {
+    XFS_EXT_NORM,
+    XFS_EXT_UNWRITTEN,
+    XFS_EXT_DMAPI_OFFLINE,
+    XFS_EXT_INVALID,
+} xfs_exntst_t;
+
+typedef struct xfs_bmbt_irec
+{
+    xfs_fileoff_t br_startoff;    /* starting file offset */
+    xfs_fsblock_t br_startblock;  /* starting block number */
+    xfs_filblks_t br_blockcount;  /* number of blocks */
+    xfs_exntst_t  br_state;       /* extent state */
+} __attribute__((__packed__)) xfs_bmbt_irec_t;
+
+static inline void bmbt_irec_get(xfs_bmbt_irec_t *dest,
+				 const xfs_bmbt_rec_t *src)
+{
+    uint64_t l0, l1;
+
+    l0 = be64_to_cpu(src->l0);
+    l1 = be64_to_cpu(src->l1);
+
+    dest->br_startoff = ((xfs_fileoff_t)l0 & 0x7ffffffffffffe00ULL) >> 9;
+    dest->br_startblock = (((xfs_fsblock_t)l0 & 0x00000000000001ffULL) << 43) |
+                          (((xfs_fsblock_t)l1) >> 21);
+    dest->br_blockcount = (xfs_filblks_t)(l1 & 0x00000000001fffffULL);
+    dest->br_state = (l0 & 0x8000000000000000ULL) ?
+					XFS_EXT_UNWRITTEN : XFS_EXT_NORM;
+}
+
+typedef struct xfs_timestamp {
+    int32_t t_sec;
+    int32_t t_nsec;
+} __attribute__((__packed__)) xfs_timestamp_t;
+
+/*
+ * Fork identifiers.
+ */
+#define XFS_DATA_FORK 0
+#define xFS_ATTR_FORK 1
+
+typedef enum xfs_dinode_fmt {
+    XFS_DINODE_FMT_DEV,
+    XFS_DINODE_FMT_LOCAL,
+    XFS_DINODE_FMT_EXTENTS,
+    XFS_DINODE_FMT_BTREE,
+    XFS_DINODE_FMT_UUID,
+} xfs_dinode_fmt_t;
+
+typedef struct xfs_dinode {
+    uint16_t		di_magic;	/* inode magic # = XFS_DINODE_MAGIC */
+    uint16_t		di_mode;	/* mode and type of file */
+    uint8_t		di_version;	/* inode version */
+    uint8_t		di_format;	/* format of di_c data */
+    uint16_t		di_onlink;	/* old number of links to file */
+    uint32_t		di_uid;		/* owner's user id */
+    uint32_t		di_gid;		/* owner's group id */
+    uint32_t		di_nlink;	/* number of links to file */
+    uint16_t		di_projid_lo;	/* lower part of owner's project id */
+    uint16_t		di_projid_hi;	/* higher part owner's project id */
+    uint8_t		di_pad[6];	/* unused, zeroed space */
+    uint16_t		di_flushiter;	/* incremented on flush */
+    xfs_timestamp_t	di_atime;	/* time last accessed */
+    xfs_timestamp_t	di_mtime;	/* time last modified */
+    xfs_timestamp_t	di_ctime;	/* time created/inode modified */
+    uint64_t		di_size;	/* number of bytes in file */
+    uint64_t		di_nblocks;	/* # of direct & btree blocks used */
+    uint32_t		di_extsize;	/* basic/minimum extent size for file */
+    uint32_t		di_nextents;	/* number of extents in data fork */
+    uint16_t		di_anextents;	/* number of extents in attribute fork*/
+    uint8_t		di_forkoff;	/* attr fork offs, <<3 for 64b align */
+    int8_t		di_aformat;	/* format of attr fork's data */
+    uint32_t		di_dmevmask;	/* DMIG event mask */
+    uint16_t		di_dmstate;	/* DMIG state info */
+    uint16_t		di_flags;	/* random flags, XFS_DIFLAG_... */
+    uint32_t		di_gen;		/* generation number */
+
+    /* di_next_unlinked is the only non-core field in the old dinode */
+    uint32_t		di_next_unlinked;/* agi unlinked list ptr */
+    uint8_t		di_literal_area[1];
+} __attribute__((packed)) xfs_dinode_t;
+
+/*
+ * Inode size for given fs.
+ */
+#define XFS_LITINO(fs) \
+        ((int)((XFS_INFO(fs)->inodesize) - sizeof(struct xfs_dinode) - 1))
+
+#define XFS_BROOT_SIZE_ADJ \
+        (XFS_BTREE_LBLOCK_LEN - sizeof(xfs_bmdr_block_t))
+
+/*
+ * Inode data & attribute fork sizes, per inode.
+ */
+#define XFS_DFORK_Q(dip)	((dip)->di_forkoff != 0)
+#define XFS_DFORK_BOFF(dip)	((int)((dip)->di_forkoff << 3))
+
+#define XFS_DFORK_DSIZE(dip, fs) \
+        (XFS_DFORK_Q(dip) ? \
+                XFS_DFORK_BOFF(dip) : \
+                XFS_LITINO(fs))
+#define XFS_DFORK_ASIZE(dip, fs) \
+        (XFS_DFORK_Q(dip) ? \
+                XFS_LITINO(fs) - XFS_DFORK_BOFF(dip) : \
+                0)
+#define XFS_DFORK_SIZE(dip, fs, w) \
+        ((w) == XFS_DATA_FORK ? \
+                XFS_DFORK_DSIZE(dip, fs) : \
+                XFS_DFORK_ASIZE(dip, fs))
+
+struct xfs_inode {
+    xfs_agblock_t 	i_agblock;
+    block_t		i_ino_blk;
+    uint64_t		i_block_offset;
+    uint64_t		i_offset;
+    uint32_t		i_cur_extent;
+    uint32_t		i_btree_offset;
+    uint16_t		i_leaf_ent_offset;
+};
+
+typedef struct { uint8_t i[8]; } __attribute__((__packed__)) xfs_dir2_ino8_t;
+typedef struct { uint8_t i[4]; } __attribute__((__packed__)) xfs_dir2_ino4_t;
+
+typedef union {
+    xfs_dir2_ino8_t i8;
+    xfs_dir2_ino4_t i4;
+} __attribute__((__packed__)) xfs_dir2_inou_t;
+
+typedef struct { uint8_t i[2]; } __attribute__((__packed__)) xfs_dir2_sf_off_t;
+
+typedef struct xfs_dir2_sf_hdr {
+    uint8_t		count;		/* count of entries */
+    uint8_t           	i8count;        /* count of 8-byte inode #s */
+    xfs_dir2_inou_t     parent;         /* parent dir inode number */
+} __attribute__((__packed__)) xfs_dir2_sf_hdr_t;
+
+typedef struct xfs_dir2_sf_entry {
+    uint8_t             namelen;        /* actual name length */
+    xfs_dir2_sf_off_t   offset;         /* saved offset */
+    uint8_t             name[1];        /* name, variable size */
+    xfs_dir2_inou_t	inumber;	/* inode number, var. offset */
+} __attribute__((__packed__)) xfs_dir2_sf_entry_t;
+
+typedef struct xfs_dir2_sf {
+    xfs_dir2_sf_hdr_t       hdr;            /* shortform header */
+    xfs_dir2_sf_entry_t     list[1];        /* shortform entries */
+} __attribute__((__packed__)) xfs_dir2_sf_t;
+
+typedef xfs_ino_t	xfs_intino_t;
+
+static inline xfs_intino_t xfs_dir2_sf_get_inumber(xfs_dir2_sf_t *sfp,
+						   xfs_dir2_inou_t *from)
+{
+    return ((sfp)->hdr.i8count == 0 ? \
+	    (xfs_intino_t)XFS_GET_DIR_INO4((from)->i4) : \
+	    (xfs_intino_t)XFS_GET_DIR_INO8((from)->i8));
+}
+
+/*
+ * DIR2 Data block structures.
+ *
+ * A pure data block looks like the following drawing on disk:
+ *
+ *    +-------------------------------------------------+
+ *    | xfs_dir2_data_hdr_t                             |
+ *    +-------------------------------------------------+
+ *    | xfs_dir2_data_entry_t OR xfs_dir2_data_unused_t |
+ *    | xfs_dir2_data_entry_t OR xfs_dir2_data_unused_t |
+ *    | xfs_dir2_data_entry_t OR xfs_dir2_data_unused_t |
+ *    | ...                                             |
+ *    +-------------------------------------------------+
+ *    | unused space                                    |
+ *    +-------------------------------------------------+
+ *
+ * As all the entries are variable size structure the accessors below should
+ * be used to iterate over them.
+ *
+ * In addition to the pure data blocks for the data and node formats.
+ * most structures are also used for the combined data/freespace "block"
+ * format below.
+ */
+#define XFS_DIR2_DATA_ALIGN_LOG 3
+#define XFS_DIR2_DATA_ALIGN     (1 << XFS_DIR2_DATA_ALIGN_LOG)
+#define XFS_DIR2_DATA_FREE_TAG  0xffff
+#define XFS_DIR2_DATA_FD_COUNT  3
+
+/*
+ * Directory address space divided into sections.
+ * spaces separated by 32GB.
+ */
+#define XFS_DIR2_SPACE_SIZE	(1ULL << (32 + XFS_DIR2_DATA_ALIGN_LOG))
+
+typedef struct xfs_dir2_data_free {
+    uint16_t offset;
+    uint16_t length;
+} __attribute__((__packed__)) xfs_dir2_data_free_t;
+
+typedef struct xfs_dir2_data_hdr {
+    uint32_t magic;
+    xfs_dir2_data_free_t bestfree[XFS_DIR2_DATA_FD_COUNT];
+} __attribute__((__packed__)) xfs_dir2_data_hdr_t;
+
+typedef struct xfs_dir2_data_entry {
+    uint64_t inumber; /* inode number */
+    uint8_t  namelen; /* name length */
+    uint8_t  name[];  /* name types, no null */
+ /* uint16_t tag; */  /* starting offset of us */
+} __attribute__((__packed__)) xfs_dir2_data_entry_t;
+
+typedef struct xfs_dir2_data_unused {
+    uint16_t freetag; /* XFS_DIR2_DATA_FREE_TAG */
+    uint16_t length;  /* total free length */
+                      /* variable offset */
+ /* uint16_t tag; */  /* starting offset of us */
+} __attribute__((__packed__)) xfs_dir2_data_unused_t;
+
+/**
+ * rol32 - rotate a 32-bit value left
+ * @word: value to rotate
+ * @shift: bits to roll
+ */
+static inline uint32_t rol32(uint32_t word, signed int shift)
+{
+    return (word << shift) | (word >> (32 - shift));
+}
+
+#define roundup(x, y) (					\
+{							\
+	const typeof(y) __y = y;			\
+	(((x) + (__y - 1)) / __y) * __y;		\
+}							\
+)
+
+static inline int xfs_dir2_data_entsize(int n)
+{
+    return (int)roundup(offsetof(struct xfs_dir2_data_entry, name[0]) + n + 
+			(unsigned int)sizeof(uint16_t), XFS_DIR2_DATA_ALIGN);
+}
+
+static inline uint16_t *
+xfs_dir2_data_entry_tag_p(struct xfs_dir2_data_entry *dep)
+{
+    return (uint16_t *)((char *)dep +
+	    xfs_dir2_data_entsize(dep->namelen) - sizeof(uint16_t));
+}
+
+static inline uint16_t *
+xfs_dir2_data_unused_tag_p(struct xfs_dir2_data_unused *dup)
+{
+    return (uint16_t *)((char *)dup +
+	    be16_to_cpu(dup->length) - sizeof(uint16_t));
+}
+
+typedef struct xfs_dir2_block_tail {
+    uint32_t 		count;			/* count of leaf entries */
+    uint32_t 		stale;			/* count of stale lf entries */
+} __attribute__((__packed__)) xfs_dir2_block_tail_t;
+
+static inline struct xfs_dir2_block_tail *
+xfs_dir2_block_tail_p(struct xfs_fs_info *fs_info, struct xfs_dir2_data_hdr *hdr)
+{
+    return ((struct xfs_dir2_block_tail *)
+	    ((char *)hdr + fs_info->dirblksize)) - 1;
+}
+
+static inline uint32_t
+xfs_dir2_db_to_da(struct fs_info *fs, uint32_t db)
+{
+    return db << XFS_INFO(fs)->dirblklog;
+}
+
+static inline int64_t
+xfs_dir2_dataptr_to_byte(uint32_t dp)
+{
+    return (int64_t)dp << XFS_DIR2_DATA_ALIGN_LOG;
+}
+
+static inline uint32_t
+xfs_dir2_byte_to_db(struct fs_info *fs, int64_t by)
+{
+    return (uint32_t)
+	    (by >> (XFS_INFO(fs)->block_shift + XFS_INFO(fs)->dirblklog));
+}
+
+static inline uint32_t
+xfs_dir2_dataptr_to_db(struct fs_info *fs, uint32_t dp)
+{
+    return xfs_dir2_byte_to_db(fs, xfs_dir2_dataptr_to_byte(dp));
+}
+
+static inline unsigned int
+xfs_dir2_byte_to_off(struct fs_info *fs, int64_t by)
+{
+    return (unsigned int)(by &
+        (( 1 << (XFS_INFO(fs)->block_shift + XFS_INFO(fs)->dirblklog)) - 1));
+}
+
+static inline unsigned int
+xfs_dir2_dataptr_to_off(struct fs_info *fs, uint32_t dp)
+{
+    return xfs_dir2_byte_to_off(fs, xfs_dir2_dataptr_to_byte(dp));
+}
+
+#define XFS_DIR2_LEAF_SPACE	1
+#define XFS_DIR2_LEAF_OFFSET	(XFS_DIR2_LEAF_SPACE * XFS_DIR2_SPACE_SIZE)
+#define XFS_DIR2_LEAF_FIRSTDB(fs)	\
+	xfs_dir2_byte_to_db(fs, XFS_DIR2_LEAF_OFFSET)
+
+typedef struct xfs_da_blkinfo {
+    uint32_t		forw;
+    uint32_t 		back;
+    uint16_t		magic;
+    uint16_t	 	pad;
+} __attribute__((__packed__)) xfs_da_blkinfo_t;
+
+typedef struct xfs_dir2_leaf_hdr {
+    xfs_da_blkinfo_t	info;
+    uint16_t		count;
+    uint16_t		stale;
+} __attribute__((__packed__)) xfs_dir2_leaf_hdr_t;
+
+typedef struct xfs_dir2_leaf_entry {
+    uint32_t		hashval;		/* hash value of name */
+    uint32_t		address;		/* address of data entry */
+} __attribute__((__packed__)) xfs_dir2_leaf_entry_t;
+
+typedef struct xfs_dir2_leaf {
+    xfs_dir2_leaf_hdr_t 	hdr;	/* leaf header */
+    xfs_dir2_leaf_entry_t	ents[];	/* entries */
+} __attribute__((__packed__)) xfs_dir2_leaf_t;
+
+#define XFS_DA_NODE_MAGIC	0xfebeU	/* magic number: non-leaf blocks */
+#define XFS_ATTR_LEAF_MAGIC	0xfbeeU	/* magic number: attribute leaf blks */
+#define XFS_DIR2_LEAF1_MAGIC	0xd2f1U /* magic number: v2 dirlf single blks */
+#define XFS_DIR2_LEAFN_MAGIC	0xd2ffU	/* magic number: V2 dirlf multi blks */
+
+typedef struct xfs_da_intnode {
+    struct xfs_da_node_hdr {	/* constant-structure header block */
+	xfs_da_blkinfo_t info;	/* block type, links, etc. */
+	uint16_t count;		/* count of active entries */
+	uint16_t level;		/* level above leaves (leaf == 0) */
+    } hdr;
+    struct xfs_da_node_entry {
+	uint32_t hashval;	/* hash value for this descendant */
+	uint32_t before;	/* Btree block before this key */
+    } btree[1];
+} __attribute__((__packed__)) xfs_da_intnode_t;
+
+typedef struct xfs_da_node_hdr xfs_da_node_hdr_t;
+typedef struct xfs_da_node_entry xfs_da_node_entry_t;
+
+static inline bool xfs_is_valid_magicnum(const xfs_sb_t *sb)
+{
+    return sb->sb_magicnum == *(uint32_t *)XFS_SB_MAGIC;
+}
+
+static inline bool xfs_is_valid_agi(xfs_agi_t *agi)
+{
+    return agi->agi_magicnum == *(uint32_t *)XFS_AGI_MAGIC;
+}
+
+static inline struct inode *xfs_new_inode(struct fs_info *fs)
+{
+    struct inode *inode;
+
+    inode = alloc_inode(fs, 0, sizeof(struct xfs_inode));
+    if (!inode)
+	malloc_error("xfs_inode structure");
+
+    return inode;
+}
+
+static inline void fill_xfs_inode_pvt(struct fs_info *fs, struct inode *inode,
+				      xfs_ino_t ino)
+{
+    XFS_PVT(inode)->i_agblock =
+	agnumber_to_bytes(fs, XFS_INO_TO_AGNO(fs, ino)) >> BLOCK_SHIFT(fs);
+    XFS_PVT(inode)->i_ino_blk = ino_to_bytes(fs, ino) >> BLOCK_SHIFT(fs);
+    XFS_PVT(inode)->i_block_offset = XFS_INO_TO_OFFSET(XFS_INFO(fs), ino) <<
+                                     XFS_INFO(fs)->inode_shift;
+}
+
+/*
+ * Generic btree header.
+ *
+ * This is a combination of the actual format used on disk for short and long
+ * format btrees. The first three fields are shared by both format, but
+ * the pointers are different and should be used with care.
+ *
+ * To get the size of the actual short or long form headers please use
+ * the size macros belows. Never use sizeof(xfs_btree_block);
+ */
+typedef struct xfs_btree_block {
+    uint32_t bb_magic;			/* magic number for block type */
+    uint16_t bb_level;			/* 0 is a leaf */
+    uint16_t bb_numrecs;		/* current # of data records */
+    union {
+        struct {
+            uint32_t bb_leftsib;
+            uint32_t bb_rightsib;
+        } s;				/* short form pointers */
+        struct {
+            uint64_t bb_leftsib;
+            uint64_t bb_rightsib;
+        } l;				/* long form pointers */
+    } bb_u;				/* rest */
+} xfs_btree_block_t;
+
+#define XFS_BTREE_SBLOCK_LEN 16 /* size of a short form block */
+#define XFS_BTREE_LBLOCK_LEN 24 /* size of a long form block */
+
+/*
+ * Bmap root header, on-disk form only.
+ */
+typedef struct xfs_bmdr_block {
+    uint16_t bb_level;		/* 0 is a leaf */
+    uint16_t bb_numrecs;	/* current # of data records */
+} xfs_bmdr_block_t;
+
+/*
+ * Key structure for non-leaf levels of the tree.
+ */
+typedef struct xfs_bmbt_key {
+    uint64_t br_startoff;	/* starting file offset */
+} xfs_bmbt_key_t, xfs_bmdr_key_t;
+
+/* btree pointer type */
+typedef uint64_t xfs_bmbt_ptr_t, xfs_bmdr_ptr_t;
+
+/*
+ * Btree block header size depends on a superblock flag.
+ *
+ * (not quite yet, but soon)
+ */
+#define XFS_BMBT_BLOCK_LEN(fs) XFS_BTREE_LBLOCK_LEN
+
+#define XFS_BMBT_REC_ADDR(fs, block, index) \
+        ((xfs_bmbt_rec_t *) \
+                ((char *)(block) + \
+                 XFS_BMBT_BLOCK_LEN(fs) + \
+                 ((index) - 1) * sizeof(xfs_bmbt_rec_t)))
+
+#define XFS_BMBT_KEY_ADDR(fs, block, index) \
+        ((xfs_bmbt_key_t *) \
+                ((char *)(block) + \
+                 XFS_BMBT_BLOCK_LEN(fs) + \
+                 ((index) - 1) * sizeof(xfs_bmbt_key_t)))
+
+#define XFS_BMBT_PTR_ADDR(fs, block, index, maxrecs) \
+        ((xfs_bmbt_ptr_t *) \
+                ((char *)(block) + \
+                 XFS_BMBT_BLOCK_LEN(fs) + \
+                 (maxrecs) * sizeof(xfs_bmbt_key_t) + \
+                 ((index) - 1) * sizeof(xfs_bmbt_ptr_t)))
+
+#define XFS_BMDR_REC_ADDR(block, index) \
+        ((xfs_bmdr_rec_t *) \
+                ((char *)(block) + \
+                 sizeof(struct xfs_bmdr_block) + \
+                 ((index) - 1) * sizeof(xfs_bmdr_rec_t)))
+
+#define XFS_BMDR_KEY_ADDR(block, index) \
+        ((xfs_bmdr_key_t *) \
+                ((char *)(block) + \
+                 sizeof(struct xfs_bmdr_block) + \
+                 ((index) - 1) * sizeof(xfs_bmdr_key_t)))
+
+#define XFS_BMDR_PTR_ADDR(block, index, maxrecs) \
+        ((xfs_bmdr_ptr_t *) \
+                ((char *)(block) + \
+                 sizeof(struct xfs_bmdr_block) + \
+                 (maxrecs) * sizeof(xfs_bmdr_key_t) + \
+                 ((index) - 1) * sizeof(xfs_bmdr_ptr_t)))
+
+/*
+ * Calculate number of records in a bmap btree inode root.
+ */
+static inline int
+xfs_bmdr_maxrecs(int blocklen, int leaf)
+{
+    blocklen -= sizeof(xfs_bmdr_block_t);
+
+    if (leaf)
+        return blocklen / sizeof(xfs_bmdr_rec_t);
+
+    return blocklen / (sizeof(xfs_bmdr_key_t) + sizeof(xfs_bmdr_ptr_t));
+}
+
+#endif /* XFS_H_ */
diff --git a/core/fs/xfs/xfs_ag.h b/core/fs/xfs/xfs_ag.h
new file mode 100644
index 0000000..a2988b1
--- /dev/null
+++ b/core/fs/xfs/xfs_ag.h
@@ -0,0 +1,189 @@
+/*
+ * Taken from Linux kernel tree (linux/fs/xfs)
+ *
+ * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * Copyright (c) 2012 Paulo Alcantara <pcacjr at zytor.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef XFS_AG_H_
+#define	XFS_AG_H_
+
+#include "xfs_types.h"
+
+/*
+ * Allocation group header
+ * This is divided into three structures, placed in sequential 512-byte
+ * buffers after a copy of the superblock (also in a 512-byte buffer).
+ */
+
+typedef uint32_t xfs_agino_t;
+
+struct xfs_buf;
+struct xfs_mount;
+struct xfs_trans;
+
+#define	XFS_AGF_MAGIC	"XAGF"
+#define	XFS_AGF_VERSION	1
+#define	XFS_AGI_VERSION	1
+
+#define	XFS_AGF_GOOD_VERSION(v)	((v) == XFS_AGF_VERSION)
+#define	XFS_AGI_GOOD_VERSION(v)	((v) == XFS_AGI_VERSION)
+
+/*
+ * Btree number 0 is bno, 1 is cnt.  This value gives the size of the
+ * arrays below.
+ */
+#define	XFS_BTNUM_AGF	((int)XFS_BTNUM_CNTi + 1)
+
+/*
+ * The second word of agf_levels in the first a.g. overlaps the EFS
+ * superblock's magic number.  Since the magic numbers valid for EFS
+ * are > 64k, our value cannot be confused for an EFS superblock's.
+ */
+
+typedef struct xfs_agf {
+	/*
+	 * Common allocation group header information
+	 */
+	uint32_t		agf_magicnum;	/* magic number == XFS_AGF_MAGIC */
+	uint32_t		agf_versionnum;	/* header version == XFS_AGF_VERSION */
+	uint32_t		agf_seqno;	/* sequence # starting from 0 */
+	uint32_t		agf_length;	/* size in blocks of a.g. */
+	/*
+	 * Freespace information
+	 */
+	uint32_t		agf_roots[XFS_BTNUM_AGF];	/* root blocks */
+	uint32_t		agf_spare0;	/* spare field */
+	uint32_t		agf_levels[XFS_BTNUM_AGF];	/* btree levels */
+	uint32_t		agf_spare1;	/* spare field */
+	uint32_t		agf_flfirst;	/* first freelist block's index */
+	uint32_t		agf_fllast;	/* last freelist block's index */
+	uint32_t		agf_flcount;	/* count of blocks in freelist */
+	uint32_t		agf_freeblks;	/* total free blocks */
+	uint32_t		agf_longest;	/* longest free space */
+	uint32_t		agf_btreeblks;	/* # of blocks held in AGF btrees */
+} xfs_agf_t;
+
+#define	XFS_AGF_MAGICNUM	0x00000001
+#define	XFS_AGF_VERSIONNUM	0x00000002
+#define	XFS_AGF_SEQNO		0x00000004
+#define	XFS_AGF_LENGTH		0x00000008
+#define	XFS_AGF_ROOTS		0x00000010
+#define	XFS_AGF_LEVELS		0x00000020
+#define	XFS_AGF_FLFIRST		0x00000040
+#define	XFS_AGF_FLLAST		0x00000080
+#define	XFS_AGF_FLCOUNT		0x00000100
+#define	XFS_AGF_FREEBLKS	0x00000200
+#define	XFS_AGF_LONGEST		0x00000400
+#define	XFS_AGF_BTREEBLKS	0x00000800
+#define	XFS_AGF_NUM_BITS	12
+#define	XFS_AGF_ALL_BITS	((1 << XFS_AGF_NUM_BITS) - 1)
+
+#define XFS_AGF_FLAGS \
+	{ XFS_AGF_MAGICNUM,	"MAGICNUM" }, \
+	{ XFS_AGF_VERSIONNUM,	"VERSIONNUM" }, \
+	{ XFS_AGF_SEQNO,	"SEQNO" }, \
+	{ XFS_AGF_LENGTH,	"LENGTH" }, \
+	{ XFS_AGF_ROOTS,	"ROOTS" }, \
+	{ XFS_AGF_LEVELS,	"LEVELS" }, \
+	{ XFS_AGF_FLFIRST,	"FLFIRST" }, \
+	{ XFS_AGF_FLLAST,	"FLLAST" }, \
+	{ XFS_AGF_FLCOUNT,	"FLCOUNT" }, \
+	{ XFS_AGF_FREEBLKS,	"FREEBLKS" }, \
+	{ XFS_AGF_LONGEST,	"LONGEST" }, \
+	{ XFS_AGF_BTREEBLKS,	"BTREEBLKS" }
+
+/* disk block (xfs_daddr_t) in the AG */
+#define XFS_AGF_DADDR(mp)	((xfs_daddr_t)(1 << (mp)->m_sectbb_log))
+#define	XFS_AGF_BLOCK(mp)	XFS_HDR_BLOCK(mp, XFS_AGF_DADDR(mp))
+#define	XFS_BUF_TO_AGF(bp)	((xfs_agf_t *)((bp)->b_addr))
+
+extern int xfs_read_agf(struct xfs_mount *mp, struct xfs_trans *tp,
+			xfs_agnumber_t agno, int flags, struct xfs_buf **bpp);
+
+/*
+ * Size of the unlinked inode hash table in the agi.
+ */
+#define	XFS_AGI_UNLINKED_BUCKETS	64
+
+#define	XFS_AGI_MAGICNUM	0x00000001
+#define	XFS_AGI_VERSIONNUM	0x00000002
+#define	XFS_AGI_SEQNO		0x00000004
+#define	XFS_AGI_LENGTH		0x00000008
+#define	XFS_AGI_COUNT		0x00000010
+#define	XFS_AGI_ROOT		0x00000020
+#define	XFS_AGI_LEVEL		0x00000040
+#define	XFS_AGI_FREECOUNT	0x00000080
+#define	XFS_AGI_NEWINO		0x00000100
+#define	XFS_AGI_DIRINO		0x00000200
+#define	XFS_AGI_UNLINKED	0x00000400
+#define	XFS_AGI_NUM_BITS	11
+#define	XFS_AGI_ALL_BITS	((1 << XFS_AGI_NUM_BITS) - 1)
+
+/* disk block (xfs_daddr_t) in the AG */
+#define XFS_AGI_DADDR(mp)	((xfs_daddr_t)(2 << (mp)->m_sectbb_log))
+#define	XFS_AGI_BLOCK(mp)	XFS_HDR_BLOCK(mp, XFS_AGI_DADDR(mp))
+#define	XFS_BUF_TO_AGI(bp)	((xfs_agi_t *)((bp)->b_addr))
+
+extern int xfs_read_agi(struct xfs_mount *mp, struct xfs_trans *tp,
+				xfs_agnumber_t agno, struct xfs_buf **bpp);
+
+/*
+ * The third a.g. block contains the a.g. freelist, an array
+ * of block pointers to blocks owned by the allocation btree code.
+ */
+#define XFS_AGFL_DADDR(mp)	((xfs_daddr_t)(3 << (mp)->m_sectbb_log))
+#define	XFS_AGFL_BLOCK(mp)	XFS_HDR_BLOCK(mp, XFS_AGFL_DADDR(mp))
+#define XFS_AGFL_SIZE(mp)	((mp)->m_sb.sb_sectsize / sizeof(xfs_agblock_t))
+#define	XFS_BUF_TO_AGFL(bp)	((xfs_agfl_t *)((bp)->b_addr))
+
+typedef struct xfs_agfl {
+	uint32_t		agfl_bno[1];	/* actually XFS_AGFL_SIZE(mp) */
+} xfs_agfl_t;
+
+/*
+ * tags for inode radix tree
+ */
+#define XFS_ICI_NO_TAG		(-1)	/* special flag for an untagged lookup
+					   in xfs_inode_ag_iterator */
+#define XFS_ICI_RECLAIM_TAG	0	/* inode is to be reclaimed */
+
+#define	XFS_AG_MAXLEVELS(mp)		((mp)->m_ag_maxlevels)
+#define	XFS_MIN_FREELIST_RAW(bl,cl,mp)	\
+	(MIN(bl + 1, XFS_AG_MAXLEVELS(mp)) + MIN(cl + 1, XFS_AG_MAXLEVELS(mp)))
+#define	XFS_MIN_FREELIST(a,mp)		\
+	(XFS_MIN_FREELIST_RAW(		\
+		be32_to_cpu((a)->agf_levels[XFS_BTNUM_BNOi]), \
+		be32_to_cpu((a)->agf_levels[XFS_BTNUM_CNTi]), mp))
+#define	XFS_MIN_FREELIST_PAG(pag,mp)	\
+	(XFS_MIN_FREELIST_RAW(		\
+		(unsigned int)(pag)->pagf_levels[XFS_BTNUM_BNOi], \
+		(unsigned int)(pag)->pagf_levels[XFS_BTNUM_CNTi], mp))
+
+/*
+ * For checking for bad ranges of xfs_daddr_t's, covering multiple
+ * allocation groups or a single xfs_daddr_t that's a superblock copy.
+ */
+#define	XFS_AG_CHECK_DADDR(mp,d,len)	\
+	((len) == 1 ? \
+	    ASSERT((d) == XFS_SB_DADDR || \
+		   xfs_daddr_to_agbno(mp, d) != XFS_SB_DADDR) : \
+	    ASSERT(xfs_daddr_to_agno(mp, d) == \
+		   xfs_daddr_to_agno(mp, (d) + (len) - 1)))
+
+#endif	/* XFS_AG_H_ */
diff --git a/core/fs/xfs/xfs_dinode.c b/core/fs/xfs/xfs_dinode.c
new file mode 100644
index 0000000..8e2d8d0
--- /dev/null
+++ b/core/fs/xfs/xfs_dinode.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2012 Paulo Alcantara <pcacjr at zytor.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <cache.h>
+#include <core.h>
+#include <fs.h>
+
+#include "xfs_types.h"
+#include "xfs_sb.h"
+#include "xfs_ag.h"
+#include "misc.h"
+#include "xfs.h"
+
+#include "xfs_dinode.h"
+
+xfs_dinode_t *xfs_dinode_get_core(struct fs_info *fs, xfs_ino_t ino)
+{
+    block_t blk;
+    xfs_dinode_t *core;
+    uint64_t offset;
+
+    xfs_debug("ino %lu", ino);
+
+    blk = ino_to_bytes(fs, ino) >> BLOCK_SHIFT(fs);
+    offset = XFS_INO_TO_OFFSET(XFS_INFO(fs), ino) << XFS_INFO(fs)->inode_shift;
+    if (offset > BLOCK_SIZE(fs)) {
+        xfs_error("Invalid inode offset in block!");
+        xfs_debug("offset: 0x%llx", offset);
+        goto out;
+    }
+
+    xfs_debug("blk %llu block offset 0x%llx", blk, blk << BLOCK_SHIFT(fs));
+    xfs_debug("inode offset in block (in bytes) is 0x%llx", offset);
+
+    core = (xfs_dinode_t *)((uint8_t *)get_cache(fs->fs_dev, blk) + offset);
+    if (be16_to_cpu(core->di_magic) !=
+	be16_to_cpu(*(uint16_t *)XFS_DINODE_MAGIC)) {
+	xfs_error("Inode core's magic number does not match!");
+	xfs_debug("magic number 0x%04x", (be16_to_cpu(core->di_magic)));
+	goto out;
+    }
+
+    return core;
+
+out:
+    return NULL;
+}
diff --git a/core/fs/xfs/xfs_dinode.h b/core/fs/xfs/xfs_dinode.h
new file mode 100644
index 0000000..80deec7
--- /dev/null
+++ b/core/fs/xfs/xfs_dinode.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2012 Paulo Alcantara <pcacjr at zytor.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef XFS_DINODE_H_
+#define XFS_DINODE_H_
+
+xfs_dinode_t *xfs_dinode_get_core(struct fs_info *fs, xfs_ino_t ino);
+
+#endif /* XFS_DINODE_H_ */
diff --git a/core/fs/xfs/xfs_dir2.c b/core/fs/xfs/xfs_dir2.c
new file mode 100644
index 0000000..c52196a
--- /dev/null
+++ b/core/fs/xfs/xfs_dir2.c
@@ -0,0 +1,759 @@
+/*
+ * Copyright (c) 2012 Paulo Alcantara <pcacjr at zytor.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <cache.h>
+#include <core.h>
+#include <fs.h>
+
+#include "xfs_types.h"
+#include "xfs_sb.h"
+#include "xfs_ag.h"
+#include "misc.h"
+#include "xfs.h"
+#include "xfs_dinode.h"
+
+#include "xfs_dir2.h"
+
+char *xfs_dir2_get_entry_name(uint8_t *start, uint8_t *end)
+{
+    char *s;
+    char *p;
+
+    s = malloc(end - start + 1);
+    if (!s)
+	malloc_error("string");
+
+    p = s;
+    while (start < end)
+	*p++ = *start++;
+
+    *p = '\0';
+
+    return s;
+}
+
+uint32_t xfs_dir2_da_hashname(const uint8_t *name, int namelen)
+{
+    uint32_t hash;
+
+    /*
+     * Do four characters at a time as long as we can.
+     */
+    for (hash = 0; namelen >= 4; namelen -=4, name += 4)
+        hash = (name[0] << 21) ^ (name[1] << 14) ^ (name[2] << 7) ^
+               (name[3] << 0) ^ rol32(hash, 7 * 4);
+
+    /*
+     * Now do the rest of the characters.
+     */
+    switch (namelen) {
+    case 3:
+        return (name[0] << 14) ^ (name[1] << 7) ^ (name[2] << 0) ^
+               rol32(hash, 7 * 3);
+    case 2:
+        return (name[0] << 7) ^ (name[1] << 0) ^ rol32(hash, 7 * 2);
+    case 1:
+        return (name[0] << 0) ^ rol32(hash, 7 * 1);
+    default: /* case 0: */
+        return hash;
+    }
+}
+
+void *xfs_dir2_get_dirblks(struct fs_info *fs, block_t startblock,
+			   xfs_filblks_t c)
+{
+    int count = c << XFS_INFO(fs)->dirblklog;
+    uint8_t *p;
+    uint8_t *buf;
+    off_t offset = 0;
+
+    buf = malloc(c * XFS_INFO(fs)->dirblksize);
+    if (!buf)
+        malloc_error("buffer memory");
+
+    memset(buf, 0, XFS_INFO(fs)->dirblksize);
+
+    while (count--) {
+        p = (uint8_t *)get_cache(fs->fs_dev, startblock++);
+        memcpy(buf + offset, p,  BLOCK_SIZE(fs));
+        offset += BLOCK_SIZE(fs);
+    }
+
+    return buf;
+}
+
+struct inode *xfs_dir2_local_find_entry(const char *dname, struct inode *parent,
+					xfs_dinode_t *core)
+{
+    xfs_dir2_sf_t *sf = (xfs_dir2_sf_t *)&core->di_literal_area[0];
+    xfs_dir2_sf_entry_t *sf_entry;
+    uint8_t count = sf->hdr.i8count ? sf->hdr.i8count : sf->hdr.count;
+    struct fs_info *fs = parent->fs;
+    struct inode *inode;
+    xfs_intino_t ino;
+    xfs_dinode_t *ncore = NULL;
+
+    xfs_debug("count %hhu i8count %hhu", sf->hdr.count, sf->hdr.i8count);
+
+    sf_entry = (xfs_dir2_sf_entry_t *)((uint8_t *)&sf->list[0] -
+				       (!sf->hdr.i8count ? 4 : 0));
+    while (count--) {
+	uint8_t *start_name = &sf_entry->name[0];
+	uint8_t *end_name = start_name + sf_entry->namelen;
+	char *name;
+
+	name = xfs_dir2_get_entry_name(start_name, end_name);
+
+	xfs_debug("entry name: %s", name);
+
+	if (!strncmp(name, dname, strlen(dname))) {
+	    free(name);
+	    goto found;
+	}
+
+	free(name);
+
+	sf_entry = (xfs_dir2_sf_entry_t *)((uint8_t *)sf_entry +
+					   offsetof(struct xfs_dir2_sf_entry,
+						    name[0]) +
+					   sf_entry->namelen +
+					   (sf->hdr.i8count ? 8 : 4));
+    }
+
+    return NULL;
+
+found:
+    inode = xfs_new_inode(fs);
+
+    ino = xfs_dir2_sf_get_inumber(sf, (xfs_dir2_inou_t *)(
+				      (uint8_t *)sf_entry +
+				      offsetof(struct xfs_dir2_sf_entry,
+					       name[0]) +
+				      sf_entry->namelen));
+
+    xfs_debug("entry inode's number %lu", ino);
+
+    ncore = xfs_dinode_get_core(fs, ino);
+    if (!ncore) {
+        xfs_error("Failed to get dinode!");
+        goto out;
+    }
+
+    fill_xfs_inode_pvt(fs, inode, ino);
+
+    inode->ino			= ino;
+    inode->size 		= be64_to_cpu(ncore->di_size);
+
+    if ((be16_to_cpu(ncore->di_mode) & S_IFMT) == S_IFDIR) {
+	inode->mode = DT_DIR;
+	xfs_debug("Found a directory inode!");
+    } else if ((be16_to_cpu(ncore->di_mode) & S_IFMT) == S_IFREG) {
+	inode->mode = DT_REG;
+	xfs_debug("Found a file inode!");
+	xfs_debug("inode size %llu", inode->size);
+    } else if ((be16_to_cpu(ncore->di_mode) & S_IFMT) == S_IFLNK) {
+	inode->mode = DT_LNK;
+	xfs_debug("Found a symbolic link inode!");
+    }
+
+    return inode;
+
+out:
+    free(inode);
+
+    return NULL;
+}
+
+struct inode *xfs_dir2_block_find_entry(const char *dname, struct inode *parent,
+					xfs_dinode_t *core)
+{
+    xfs_bmbt_irec_t r;
+    block_t dir_blk;
+    struct fs_info *fs = parent->fs;
+    uint8_t *dirblk_buf;
+    uint8_t *p, *endp;
+    xfs_dir2_data_hdr_t *hdr;
+    struct inode *inode = NULL;
+    xfs_dir2_block_tail_t *btp;
+    xfs_dir2_data_unused_t *dup;
+    xfs_dir2_data_entry_t *dep;
+    xfs_intino_t ino;
+    xfs_dinode_t *ncore;
+
+    bmbt_irec_get(&r, (xfs_bmbt_rec_t *)&core->di_literal_area[0]);
+    dir_blk = fsblock_to_bytes(fs, r.br_startblock) >> BLOCK_SHIFT(fs);
+
+    dirblk_buf = xfs_dir2_get_dirblks(fs, dir_blk, r.br_blockcount);
+    hdr = (xfs_dir2_data_hdr_t *)dirblk_buf;
+    if (be32_to_cpu(hdr->magic) != XFS_DIR2_BLOCK_MAGIC) {
+        xfs_error("Block directory header's magic number does not match!");
+        xfs_debug("hdr->magic: 0x%lx", be32_to_cpu(hdr->magic));
+        goto out;
+    }
+
+    p = (uint8_t *)(hdr + 1);
+
+    btp = xfs_dir2_block_tail_p(XFS_INFO(fs), hdr);
+    endp = (uint8_t *)((xfs_dir2_leaf_entry_t *)btp - be32_to_cpu(btp->count));
+
+    while (p < endp) {
+        uint8_t *start_name;
+        uint8_t *end_name;
+        char *name;
+
+        dup = (xfs_dir2_data_unused_t *)p;
+        if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) {
+            p += be16_to_cpu(dup->length);
+            continue;
+        }
+
+        dep = (xfs_dir2_data_entry_t *)p;
+
+        start_name = &dep->name[0];
+        end_name = start_name + dep->namelen;
+        name = xfs_dir2_get_entry_name(start_name, end_name);
+
+        if (!strncmp(name, dname, strlen(dname))) {
+            free(name);
+            goto found;
+        }
+
+        free(name);
+	p += xfs_dir2_data_entsize(dep->namelen);
+    }
+
+out:
+    free(dirblk_buf);
+
+    return NULL;
+
+found:
+    inode = xfs_new_inode(fs);
+
+    ino = be64_to_cpu(dep->inumber);
+
+    xfs_debug("entry inode's number %lu", ino);
+
+    ncore = xfs_dinode_get_core(fs, ino);
+    if (!ncore) {
+        xfs_error("Failed to get dinode!");
+        goto failed;
+    }
+
+    fill_xfs_inode_pvt(fs, inode, ino);
+
+    inode->ino = ino;
+    XFS_PVT(inode)->i_ino_blk = ino_to_bytes(fs, ino) >> BLOCK_SHIFT(fs);
+    inode->size = be64_to_cpu(ncore->di_size);
+
+    if ((be16_to_cpu(ncore->di_mode) & S_IFMT) == S_IFDIR) {
+        inode->mode = DT_DIR;
+        xfs_debug("Found a directory inode!");
+    } else if ((be16_to_cpu(ncore->di_mode) & S_IFMT) == S_IFREG) {
+        inode->mode = DT_REG;
+        xfs_debug("Found a file inode!");
+        xfs_debug("inode size %llu", inode->size);
+    } else if ((be16_to_cpu(ncore->di_mode) & S_IFMT) == S_IFLNK) {
+        inode->mode = DT_LNK;
+        xfs_debug("Found a symbolic link inode!");
+    }
+
+    xfs_debug("entry inode's number %lu", ino);
+
+    free(dirblk_buf);
+    return inode;
+
+failed:
+    free(inode);
+    free(dirblk_buf);
+
+    return NULL;
+}
+
+struct inode *xfs_dir2_leaf_find_entry(const char *dname, struct inode *parent,
+				       xfs_dinode_t *core)
+{
+    xfs_dir2_leaf_t *leaf;
+    xfs_bmbt_irec_t irec;
+    block_t leaf_blk, dir_blk;
+    xfs_dir2_leaf_entry_t *lep;
+    int low;
+    int high;
+    int mid = 0;
+    uint32_t hash = 0;
+    uint32_t hashwant;
+    uint32_t newdb, curdb = -1;
+    xfs_dir2_data_entry_t *dep;
+    struct inode *ip;
+    xfs_dir2_data_hdr_t *data_hdr;
+    uint8_t *start_name;
+    uint8_t *end_name;
+    char *name;
+    xfs_intino_t ino;
+    xfs_dinode_t *ncore;
+    uint8_t *buf = NULL;
+
+    bmbt_irec_get(&irec, ((xfs_bmbt_rec_t *)&core->di_literal_area[0]) +
+					be32_to_cpu(core->di_nextents) - 1);
+    leaf_blk = fsblock_to_bytes(parent->fs, irec.br_startblock) >>
+	    BLOCK_SHIFT(parent->fs);
+
+    leaf = (xfs_dir2_leaf_t *)xfs_dir2_get_dirblks(parent->fs, leaf_blk,
+						   irec.br_blockcount);
+    if (be16_to_cpu(leaf->hdr.info.magic) != XFS_DIR2_LEAF1_MAGIC) {
+        xfs_error("Single leaf block header's magic number does not match!");
+        goto out;
+    }
+
+    if (!leaf->hdr.count)
+        goto out;
+
+    hashwant = xfs_dir2_da_hashname((uint8_t *)dname, strlen(dname));
+
+    /* Binary search */
+    for (lep = leaf->ents, low = 0, high = be16_to_cpu(leaf->hdr.count) - 1;
+	 low <= high; ) {
+        mid = (low + high) >> 1;
+        if ((hash = be32_to_cpu(lep[mid].hashval)) == hashwant)
+            break;
+        if (hash < hashwant)
+            low = mid + 1;
+        else
+            high = mid - 1;
+    }
+
+    /* If hash is not the one we want, then the directory does not contain the
+     * entry we're looking for and there is nothing to do anymore.
+     */
+    if (hash != hashwant)
+	goto out;
+
+    while (mid > 0 && be32_to_cpu(lep[mid - 1].hashval) == hashwant)
+	mid--;
+
+    for (lep = &leaf->ents[mid];
+	 mid < be16_to_cpu(leaf->hdr.count) &&
+	 be32_to_cpu(lep->hashval) == hashwant;
+	 lep++, mid++) {
+        /* Skip over stale leaf entries. */
+        if (be32_to_cpu(lep->address) == XFS_DIR2_NULL_DATAPTR)
+            continue;
+
+        newdb = xfs_dir2_dataptr_to_db(parent->fs, be32_to_cpu(lep->address));
+        if (newdb != curdb) {
+            if (buf)
+                free(buf);
+
+            bmbt_irec_get(&irec,
+		  ((xfs_bmbt_rec_t *)&core->di_literal_area[0]) + newdb);
+            dir_blk = fsblock_to_bytes(parent->fs, irec.br_startblock) >>
+		      BLOCK_SHIFT(parent->fs);
+            buf = xfs_dir2_get_dirblks(parent->fs, dir_blk, irec.br_blockcount);
+            data_hdr = (xfs_dir2_data_hdr_t *)buf;
+            if (be32_to_cpu(data_hdr->magic) != XFS_DIR2_DATA_MAGIC) {
+                xfs_error("Leaf directory's data magic No. does not match!");
+                goto out1;
+            }
+
+            curdb = newdb;
+        }
+
+        dep = (xfs_dir2_data_entry_t *)((char *)buf +
+               xfs_dir2_dataptr_to_off(parent->fs, be32_to_cpu(lep->address)));
+
+        start_name = &dep->name[0];
+        end_name = start_name + dep->namelen;
+        name = xfs_dir2_get_entry_name(start_name, end_name);
+
+        if (!strncmp(name, dname, strlen(dname))) {
+            free(name);
+            goto found;
+        }
+
+        free(name);
+    }
+
+out1:
+    free(buf);
+out:
+    free(leaf);
+
+    return NULL;
+
+found:
+    ip = xfs_new_inode(parent->fs);
+
+    ino = be64_to_cpu(dep->inumber);
+
+    xfs_debug("entry inode's number %lu", ino);
+
+    ncore = xfs_dinode_get_core(parent->fs, ino);
+    if (!ncore) {
+        xfs_error("Failed to get dinode!");
+        goto failed;
+    }
+
+    fill_xfs_inode_pvt(parent->fs, ip, ino);
+
+    ip->ino = ino;
+    XFS_PVT(ip)->i_ino_blk = ino_to_bytes(parent->fs, ino) >>
+	                        BLOCK_SHIFT(parent->fs);
+    ip->size = be64_to_cpu(ncore->di_size);
+
+    if ((be16_to_cpu(ncore->di_mode) & S_IFMT) == S_IFDIR) {
+        ip->mode = DT_DIR;
+        xfs_debug("Found a directory inode!");
+    } else if ((be16_to_cpu(ncore->di_mode) & S_IFMT) == S_IFREG) {
+        ip->mode = DT_REG;
+        xfs_debug("Found a file inode!");
+        xfs_debug("inode size %llu", ip->size);
+    } else if ((be16_to_cpu(ncore->di_mode) & S_IFMT) == S_IFLNK) {
+        ip->mode = DT_LNK;
+        xfs_debug("Found a symbolic link inode!");
+    }
+
+    xfs_debug("entry inode's number %lu", ino);
+
+    free(buf);
+    free(leaf);
+
+    return ip;
+
+failed:
+    free(ip);
+    free(buf);
+    free(leaf);
+
+    return ip;
+}
+
+static xfs_fsblock_t
+select_child(xfs_dfiloff_t off,
+             xfs_bmbt_key_t *kp,
+             xfs_bmbt_ptr_t *pp,
+             int nrecs)
+{
+    int i;
+
+    for (i = 0; i < nrecs; i++) {
+        if (be64_to_cpu(kp[i].br_startoff) == off)
+            return be64_to_cpu(pp[i]);
+        if (be64_to_cpu(kp[i].br_startoff) > off) {
+            if (i == 0)
+                return be64_to_cpu(pp[i]);
+            else
+                return be64_to_cpu(pp[i-1]);
+        }
+    }
+
+    return be64_to_cpu(pp[nrecs - 1]);
+}
+
+block_t xfs_dir2_get_right_blk(struct fs_info *fs, xfs_dinode_t *core,
+			       block_t fsblkno, int *error)
+{
+    uint32_t idx;
+    xfs_bmbt_irec_t irec;
+    block_t bno;
+    block_t nextbno;
+    xfs_bmdr_block_t *rblock;
+    int fsize;
+    int nextents;
+    xfs_bmbt_ptr_t *pp;
+    xfs_bmbt_key_t *kp;
+    xfs_btree_block_t *blk;
+    xfs_bmbt_rec_t *xp;
+
+    *error = 0;
+    if (core->di_format == XFS_DINODE_FMT_EXTENTS) {
+        xfs_debug("XFS_DINODE_FMT_EXTENTS");
+        for (idx = 0; idx < be32_to_cpu(core->di_nextents); idx++) {
+            bmbt_irec_get(&irec,
+                          ((xfs_bmbt_rec_t *)&core->di_literal_area[0]) + idx);
+            if (fsblkno >= irec.br_startoff &&
+                fsblkno < irec.br_startoff + irec.br_blockcount)
+                break;
+        }
+    } else if (core->di_format == XFS_DINODE_FMT_BTREE) {
+        xfs_debug("XFS_DINODE_FMT_BTREE");
+        bno = NULLFSBLOCK;
+        rblock = (xfs_bmdr_block_t *)&core->di_literal_area[0];
+        fsize = XFS_DFORK_SIZE(core, fs, XFS_DATA_FORK);
+        pp = XFS_BMDR_PTR_ADDR(rblock, 1, xfs_bmdr_maxrecs(fsize, 0));
+        kp = XFS_BMDR_KEY_ADDR(rblock, 1);
+        bno = fsblock_to_bytes(fs,
+                  select_child(fsblkno, kp, pp,
+                      be16_to_cpu(rblock->bb_numrecs))) >> BLOCK_SHIFT(fs);
+
+        /* Find the leaf */
+        for (;;) {
+            blk = (xfs_btree_block_t *)get_cache(fs->fs_dev, bno);
+            if (be16_to_cpu(blk->bb_level) == 0)
+                break;
+            pp = XFS_BMBT_PTR_ADDR(fs, blk, 1,
+                     xfs_bmdr_maxrecs(XFS_INFO(fs)->blocksize, 0));
+            kp = XFS_BMBT_KEY_ADDR(fs, blk, 1);
+            bno = fsblock_to_bytes(fs,
+                      select_child(fsblkno, kp, pp,
+                          be16_to_cpu(blk->bb_numrecs))) >> BLOCK_SHIFT(fs);
+        }
+
+        /* Find the records among leaves */
+        for (;;) {
+            nextbno = be64_to_cpu(blk->bb_u.l.bb_rightsib);
+            nextents = be16_to_cpu(blk->bb_numrecs);
+            xp = (xfs_bmbt_rec_t *)XFS_BMBT_REC_ADDR(fs, blk, 1);
+            for (idx = 0; idx < nextents; idx++) {
+                bmbt_irec_get(&irec, xp + idx);
+                if (fsblkno >= irec.br_startoff &&
+                    fsblkno < irec.br_startoff + irec.br_blockcount) {
+                    nextbno = NULLFSBLOCK;
+                    break;
+                }
+            }
+            if (nextbno == NULLFSBLOCK)
+                break;
+            bno = fsblock_to_bytes(fs, nextbno) >> BLOCK_SHIFT(fs);
+            blk = (xfs_btree_block_t *)get_cache(fs->fs_dev, bno);
+        }
+    }
+
+    if (fsblkno < irec.br_startoff ||
+        fsblkno >= irec.br_startoff + irec.br_blockcount)
+        *error = 1;
+
+    return fsblock_to_bytes(fs,
+                fsblkno - irec.br_startoff + irec.br_startblock) >>
+                BLOCK_SHIFT(fs);
+}
+
+struct inode *xfs_dir2_node_find_entry(const char *dname, struct inode *parent,
+				       xfs_dinode_t *core)
+{
+    block_t fsblkno;
+    xfs_da_intnode_t *node = NULL;
+    uint32_t hashwant;
+    uint32_t hash = 0;
+    xfs_da_node_entry_t *btree;
+    uint16_t max;
+    uint16_t span;
+    uint16_t probe;
+    int error;
+    xfs_dir2_data_hdr_t *data_hdr;
+    xfs_dir2_leaf_t *leaf;
+    xfs_dir2_leaf_entry_t *lep;
+    xfs_dir2_data_entry_t *dep;
+    struct inode *ip;
+    uint8_t *start_name;
+    uint8_t *end_name;
+    char *name;
+    int low;
+    int high;
+    int mid = 0;
+    uint32_t newdb, curdb = -1;
+    xfs_intino_t ino;
+    xfs_dinode_t *ncore;
+    uint8_t *buf = NULL;
+
+    hashwant = xfs_dir2_da_hashname((uint8_t *)dname, strlen(dname));
+
+    fsblkno = xfs_dir2_get_right_blk(parent->fs, core,
+                  xfs_dir2_byte_to_db(parent->fs, XFS_DIR2_LEAF_OFFSET),
+                  &error);
+    if (error) {
+        xfs_error("Cannot find right rec!");
+        return NULL;
+    }
+
+    node = (xfs_da_intnode_t *)xfs_dir2_get_dirblks(parent->fs, fsblkno, 1);
+    if (be16_to_cpu(node->hdr.info.magic) != XFS_DA_NODE_MAGIC) {
+        xfs_error("Node's magic number does not match!");
+        goto out;
+    }
+
+    do {
+        if (!node->hdr.count)
+            goto out;
+
+        /* Given a hash to lookup, you read the node's btree array and first
+         * "hashval" in the array that exceeds the given hash and it can then
+         * be found in the block pointed by the "before" value.
+         */
+        max = be16_to_cpu(node->hdr.count);
+
+        probe = span = max/2;
+        for (btree = &node->btree[probe];
+             span > 4; btree = &node->btree[probe]) {
+            span /= 2;
+            hash = be32_to_cpu(btree->hashval);
+
+            if (hash < hashwant)
+                probe += span;
+            else if (hash > hashwant)
+                probe -= span;
+            else
+                break;
+        }
+
+        while ((probe > 0) && (be32_to_cpu(btree->hashval) >= hashwant)) {
+            btree--;
+            probe--;
+        }
+
+        while ((probe < max) && (be32_to_cpu(btree->hashval) < hashwant)) {
+            btree++;
+            probe++;
+        }
+
+        if (probe == max)
+            fsblkno = be32_to_cpu(node->btree[max-1].before);
+        else
+            fsblkno = be32_to_cpu(node->btree[probe].before);
+
+        fsblkno = xfs_dir2_get_right_blk(parent->fs, core, fsblkno, &error);
+        if (error) {
+            xfs_error("Cannot find right rec!");
+            goto out;
+        }
+
+        free(node);
+        node = (xfs_da_intnode_t *)xfs_dir2_get_dirblks(parent->fs,
+                                                        fsblkno, 1);
+    } while(be16_to_cpu(node->hdr.info.magic) == XFS_DA_NODE_MAGIC);
+
+    leaf = (xfs_dir2_leaf_t*)node;
+    if (be16_to_cpu(leaf->hdr.info.magic) != XFS_DIR2_LEAFN_MAGIC) {
+        xfs_error("Leaf's magic number does not match!");
+        goto out;
+    }
+
+    if (!leaf->hdr.count)
+        goto out;
+
+    for (lep = leaf->ents, low = 0, high = be16_to_cpu(leaf->hdr.count) - 1;
+         low <= high; ) {
+        mid = (low + high) >> 1;
+
+        if ((hash = be32_to_cpu(lep[mid].hashval)) == hashwant)
+            break;
+        if (hash < hashwant)
+            low = mid + 1;
+        else
+            high = mid - 1;
+    }
+
+    /* If hash is not the one we want, then the directory does not contain the
+     * entry we're looking for and there is nothing to do anymore.
+     */
+    if (hash != hashwant)
+        goto out;
+
+    while (mid > 0 && be32_to_cpu(lep[mid - 1].hashval) == hashwant)
+        mid--;
+
+    for (lep = &leaf->ents[mid];
+         mid < be16_to_cpu(leaf->hdr.count) &&
+         be32_to_cpu(lep->hashval) == hashwant;
+         lep++, mid++) {
+        /* Skip over stale leaf entries. */
+        if (be32_to_cpu(lep->address) == XFS_DIR2_NULL_DATAPTR)
+            continue;
+
+        newdb = xfs_dir2_dataptr_to_db(parent->fs, be32_to_cpu(lep->address));
+        if (newdb != curdb) {
+            if (buf)
+                free(buf);
+
+            fsblkno = xfs_dir2_get_right_blk(parent->fs, core, newdb, &error);
+            if (error) {
+                xfs_error("Cannot find data block!");
+                goto out;
+            }
+
+            buf = xfs_dir2_get_dirblks(parent->fs, fsblkno, 1);
+            data_hdr = (xfs_dir2_data_hdr_t *)buf;
+            if (be32_to_cpu(data_hdr->magic) != XFS_DIR2_DATA_MAGIC) {
+                xfs_error("Leaf directory's data magic No. does not match!");
+                goto out1;
+            }
+
+            curdb = newdb;
+        }
+
+        dep = (xfs_dir2_data_entry_t *)((char *)buf +
+               xfs_dir2_dataptr_to_off(parent->fs, be32_to_cpu(lep->address)));
+
+        start_name = &dep->name[0];
+        end_name = start_name + dep->namelen;
+        name = xfs_dir2_get_entry_name(start_name, end_name);
+        if (!strncmp(name, dname, strlen(dname))) {
+            free(name);
+            goto found;
+        }
+
+        free(name);
+    }
+
+out1:
+    free(buf);
+
+out:
+    free(node);
+
+    return NULL;
+
+found:
+    ip = xfs_new_inode(parent->fs);
+    ino = be64_to_cpu(dep->inumber);
+    ncore = xfs_dinode_get_core(parent->fs, ino);
+    if (!ncore) {
+        xfs_error("Failed to get dinode!");
+        goto failed;
+    }
+
+    fill_xfs_inode_pvt(parent->fs, ip, ino);
+    ip->ino = ino;
+    XFS_PVT(ip)->i_ino_blk = ino_to_bytes(parent->fs, ino) >>
+        BLOCK_SHIFT(parent->fs);
+    ip->size = be64_to_cpu(ncore->di_size);
+
+    if ((be16_to_cpu(ncore->di_mode) & S_IFMT) == S_IFDIR) {
+        ip->mode = DT_DIR;
+        xfs_debug("Found a directory inode!");
+    } else if ((be16_to_cpu(ncore->di_mode) & S_IFMT) == S_IFREG) {
+        ip->mode = DT_REG;
+        xfs_debug("Found a file inode!");
+        xfs_debug("inode size %llu", ip->size);
+    } else if ((be16_to_cpu(ncore->di_mode) & S_IFMT) == S_IFLNK) {
+        ip->mode = DT_LNK;
+        xfs_debug("Found a symbolic link inode!");
+    }
+
+    xfs_debug("entry inode's number %lu", ino);
+
+    free(buf);
+    free(node);
+
+    return ip;
+
+failed:
+    free(ip);
+    free(buf);
+    free(node);
+
+    return NULL;
+}
diff --git a/core/fs/xfs/xfs_dir2.h b/core/fs/xfs/xfs_dir2.h
new file mode 100644
index 0000000..e1b9622
--- /dev/null
+++ b/core/fs/xfs/xfs_dir2.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2012 Paulo Alcantara <pcacjr at zytor.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef XFS_DIR2_H_
+#define XFS_DIR2_H_
+
+#include <core.h>
+#include <fs.h>
+
+#include "xfs.h"
+
+char *xfs_dir2_get_entry_name(uint8_t *start, uint8_t *end);
+void *xfs_dir2_get_dirblks(struct fs_info *fs, block_t startblock,
+			   xfs_filblks_t c);
+uint32_t xfs_dir2_da_hashname(const uint8_t *name, int namelen);
+block_t xfs_dir2_get_right_blk(struct fs_info *fs, xfs_dinode_t *core,
+			       block_t fsblkno, int *error);
+
+struct inode *xfs_dir2_local_find_entry(const char *dname, struct inode *parent,
+					xfs_dinode_t *core);
+struct inode *xfs_dir2_block_find_entry(const char *dname, struct inode *parent,
+					xfs_dinode_t *core);
+struct inode *xfs_dir2_leaf_find_entry(const char *dname, struct inode *parent,
+				       xfs_dinode_t *core);
+struct inode *xfs_dir2_node_find_entry(const char *dname, struct inode *parent,
+				       xfs_dinode_t *core);
+
+static inline bool xfs_dir2_isleaf(struct fs_info *fs, xfs_dinode_t *dip)
+{
+    uint64_t last = 0;
+    xfs_bmbt_irec_t irec;
+
+    bmbt_irec_get(&irec, ((xfs_bmbt_rec_t *)&dip->di_literal_area[0]) +
+		         be32_to_cpu(dip->di_nextents) - 1);
+    last = irec.br_startoff + irec.br_blockcount;
+
+    return (last == XFS_INFO(fs)->dirleafblk + (1 << XFS_INFO(fs)->dirblklog));
+}
+
+#endif /* XFS_DIR2_H_ */
diff --git a/core/fs/xfs/xfs_fs.h b/core/fs/xfs/xfs_fs.h
new file mode 100644
index 0000000..587820e
--- /dev/null
+++ b/core/fs/xfs/xfs_fs.h
@@ -0,0 +1,501 @@
+/*
+ * Taken from Linux kernel tree (linux/fs/xfs)
+ *
+ * Copyright (c) 1995-2005 Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * Copyright (c) 2012 Paulo Alcantara <pcacjr at zytor.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef XFS_FS_H_
+#define XFS_FS_H_
+
+/*
+ * SGI's XFS filesystem's major stuff (constants, structures)
+ */
+
+/*
+ * Direct I/O attribute record used with XFS_IOC_DIOINFO
+ * d_miniosz is the min xfer size, xfer size multiple and file seek offset
+ * alignment.
+ */
+struct dioattr {
+	uint32_t		d_mem;		/* data buffer memory alignment */
+	uint32_t		d_miniosz;	/* min xfer size		*/
+	uint32_t		d_maxiosz;	/* max xfer size		*/
+};
+
+/*
+ * Structure for XFS_IOC_FSGETXATTR[A] and XFS_IOC_FSSETXATTR.
+ */
+struct fsxattr {
+	uint32_t		fsx_xflags;	/* xflags field value (get/set) */
+	uint32_t		fsx_extsize;	/* extsize field value (get/set)*/
+	uint32_t		fsx_nextents;	/* nextents field value (get)	*/
+	uint32_t		fsx_projid;	/* project identifier (get/set) */
+	unsigned char	fsx_pad[12];
+};
+
+/*
+ * Flags for the bs_xflags/fsx_xflags field
+ * There should be a one-to-one correspondence between these flags and the
+ * XFS_DIFLAG_s.
+ */
+#define XFS_XFLAG_REALTIME	0x00000001	/* data in realtime volume */
+#define XFS_XFLAG_PREALLOC	0x00000002	/* preallocated file extents */
+#define XFS_XFLAG_IMMUTABLE	0x00000008	/* file cannot be modified */
+#define XFS_XFLAG_APPEND	0x00000010	/* all writes append */
+#define XFS_XFLAG_SYNC		0x00000020	/* all writes synchronous */
+#define XFS_XFLAG_NOATIME	0x00000040	/* do not update access time */
+#define XFS_XFLAG_NODUMP	0x00000080	/* do not include in backups */
+#define XFS_XFLAG_RTINHERIT	0x00000100	/* create with rt bit set */
+#define XFS_XFLAG_PROJINHERIT	0x00000200	/* create with parents projid */
+#define XFS_XFLAG_NOSYMLINKS	0x00000400	/* disallow symlink creation */
+#define XFS_XFLAG_EXTSIZE	0x00000800	/* extent size allocator hint */
+#define XFS_XFLAG_EXTSZINHERIT	0x00001000	/* inherit inode extent size */
+#define XFS_XFLAG_NODEFRAG	0x00002000  	/* do not defragment */
+#define XFS_XFLAG_FILESTREAM	0x00004000	/* use filestream allocator */
+#define XFS_XFLAG_HASATTR	0x80000000	/* no DIFLAG for this	*/
+
+/*
+ * Structure for XFS_IOC_GETBMAP.
+ * On input, fill in bmv_offset and bmv_length of the first structure
+ * to indicate the area of interest in the file, and bmv_entries with
+ * the number of array elements given back.  The first structure is
+ * updated on return to give the offset and length for the next call.
+ */
+struct getbmap {
+	int64_t		bmv_offset;	/* file offset of segment in blocks */
+	int64_t		bmv_block;	/* starting block (64-bit daddr_t)  */
+	int64_t		bmv_length;	/* length of segment, blocks	    */
+	int32_t		bmv_count;	/* # of entries in array incl. 1st  */
+	int32_t		bmv_entries;	/* # of entries filled in (output)  */
+};
+
+/*
+ *	Structure for XFS_IOC_GETBMAPX.	 Fields bmv_offset through bmv_entries
+ *	are used exactly as in the getbmap structure.  The getbmapx structure
+ *	has additional bmv_iflags and bmv_oflags fields. The bmv_iflags field
+ *	is only used for the first structure.  It contains input flags
+ *	specifying XFS_IOC_GETBMAPX actions.  The bmv_oflags field is filled
+ *	in by the XFS_IOC_GETBMAPX command for each returned structure after
+ *	the first.
+ */
+struct getbmapx {
+	int64_t		bmv_offset;	/* file offset of segment in blocks */
+	int64_t		bmv_block;	/* starting block (64-bit daddr_t)  */
+	int64_t		bmv_length;	/* length of segment, blocks	    */
+	int32_t		bmv_count;	/* # of entries in array incl. 1st  */
+	int32_t		bmv_entries;	/* # of entries filled in (output). */
+	int32_t		bmv_iflags;	/* input flags (1st structure)	    */
+	int32_t		bmv_oflags;	/* output flags (after 1st structure)*/
+	int32_t		bmv_unused1;	/* future use			    */
+	int32_t		bmv_unused2;	/* future use			    */
+};
+
+/*	bmv_iflags values - set by XFS_IOC_GETBMAPX caller.	*/
+#define BMV_IF_ATTRFORK		0x1	/* return attr fork rather than data */
+#define BMV_IF_NO_DMAPI_READ	0x2	/* Do not generate DMAPI read event  */
+#define BMV_IF_PREALLOC		0x4	/* rtn status BMV_OF_PREALLOC if req */
+#define BMV_IF_DELALLOC		0x8	/* rtn status BMV_OF_DELALLOC if req */
+#define BMV_IF_NO_HOLES		0x10	/* Do not return holes */
+#define BMV_IF_VALID	\
+	(BMV_IF_ATTRFORK|BMV_IF_NO_DMAPI_READ|BMV_IF_PREALLOC|	\
+	 BMV_IF_DELALLOC|BMV_IF_NO_HOLES)
+
+/*	bmv_oflags values - returned for each non-header segment */
+#define BMV_OF_PREALLOC		0x1	/* segment = unwritten pre-allocation */
+#define BMV_OF_DELALLOC		0x2	/* segment = delayed allocation */
+#define BMV_OF_LAST		0x4	/* segment is the last in the file */
+
+/*
+ * Structure for XFS_IOC_FSSETDM.
+ * For use by backup and restore programs to set the XFS on-disk inode
+ * fields di_dmevmask and di_dmstate.  These must be set to exactly and
+ * only values previously obtained via xfs_bulkstat!  (Specifically the
+ * xfs_bstat_t fields bs_dmevmask and bs_dmstate.)
+ */
+struct fsdmidata {
+	uint32_t		fsd_dmevmask;	/* corresponds to di_dmevmask */
+	__u16		fsd_padding;
+	__u16		fsd_dmstate;	/* corresponds to di_dmstate  */
+};
+
+/*
+ * File segment locking set data type for 64 bit access.
+ * Also used for all the RESV/FREE interfaces.
+ */
+typedef struct xfs_flock64 {
+	__s16		l_type;
+	__s16		l_whence;
+	int64_t		l_start;
+	int64_t		l_len;		/* len == 0 means until end of file */
+	int32_t		l_sysid;
+	uint32_t		l_pid;
+	int32_t		l_pad[4];	/* reserve area			    */
+} xfs_flock64_t;
+
+/*
+ * Output for XFS_IOC_FSGEOMETRY_V1
+ */
+typedef struct xfs_fsop_geom_v1 {
+	uint32_t		blocksize;	/* filesystem (data) block size */
+	uint32_t		rtextsize;	/* realtime extent size		*/
+	uint32_t		agblocks;	/* fsblocks in an AG		*/
+	uint32_t		agcount;	/* number of allocation groups	*/
+	uint32_t		logblocks;	/* fsblocks in the log		*/
+	uint32_t		sectsize;	/* (data) sector size, bytes	*/
+	uint32_t		inodesize;	/* inode size in bytes		*/
+	uint32_t		imaxpct;	/* max allowed inode space(%)	*/
+	uint64_t		datablocks;	/* fsblocks in data subvolume	*/
+	uint64_t		rtblocks;	/* fsblocks in realtime subvol	*/
+	uint64_t		rtextents;	/* rt extents in realtime subvol*/
+	uint64_t		logstart;	/* starting fsblock of the log	*/
+	unsigned char	uuid[16];	/* unique id of the filesystem	*/
+	uint32_t		sunit;		/* stripe unit, fsblocks	*/
+	uint32_t		swidth;		/* stripe width, fsblocks	*/
+	int32_t		version;	/* structure version		*/
+	uint32_t		flags;		/* superblock version flags	*/
+	uint32_t		logsectsize;	/* log sector size, bytes	*/
+	uint32_t		rtsectsize;	/* realtime sector size, bytes	*/
+	uint32_t		dirblocksize;	/* directory block size, bytes	*/
+} xfs_fsop_geom_v1_t;
+
+/*
+ * Output for XFS_IOC_FSGEOMETRY
+ */
+typedef struct xfs_fsop_geom {
+	uint32_t		blocksize;	/* filesystem (data) block size */
+	uint32_t		rtextsize;	/* realtime extent size		*/
+	uint32_t		agblocks;	/* fsblocks in an AG		*/
+	uint32_t		agcount;	/* number of allocation groups	*/
+	uint32_t		logblocks;	/* fsblocks in the log		*/
+	uint32_t		sectsize;	/* (data) sector size, bytes	*/
+	uint32_t		inodesize;	/* inode size in bytes		*/
+	uint32_t		imaxpct;	/* max allowed inode space(%)	*/
+	uint64_t		datablocks;	/* fsblocks in data subvolume	*/
+	uint64_t		rtblocks;	/* fsblocks in realtime subvol	*/
+	uint64_t		rtextents;	/* rt extents in realtime subvol*/
+	uint64_t		logstart;	/* starting fsblock of the log	*/
+	unsigned char	uuid[16];	/* unique id of the filesystem	*/
+	uint32_t		sunit;		/* stripe unit, fsblocks	*/
+	uint32_t		swidth;		/* stripe width, fsblocks	*/
+	int32_t		version;	/* structure version		*/
+	uint32_t		flags;		/* superblock version flags	*/
+	uint32_t		logsectsize;	/* log sector size, bytes	*/
+	uint32_t		rtsectsize;	/* realtime sector size, bytes	*/
+	uint32_t		dirblocksize;	/* directory block size, bytes	*/
+	uint32_t		logsunit;	/* log stripe unit, bytes */
+} xfs_fsop_geom_t;
+
+/* Output for XFS_FS_COUNTS */
+typedef struct xfs_fsop_counts {
+	uint64_t	freedata;	/* free data section blocks */
+	uint64_t	freertx;	/* free rt extents */
+	uint64_t	freeino;	/* free inodes */
+	uint64_t	allocino;	/* total allocated inodes */
+} xfs_fsop_counts_t;
+
+/* Input/Output for XFS_GET_RESBLKS and XFS_SET_RESBLKS */
+typedef struct xfs_fsop_resblks {
+	uint64_t  resblks;
+	uint64_t  resblks_avail;
+} xfs_fsop_resblks_t;
+
+#define XFS_FSOP_GEOM_VERSION	0
+
+#define XFS_FSOP_GEOM_FLAGS_ATTR	0x0001	/* attributes in use	*/
+#define XFS_FSOP_GEOM_FLAGS_NLINK	0x0002	/* 32-bit nlink values	*/
+#define XFS_FSOP_GEOM_FLAGS_QUOTA	0x0004	/* quotas enabled	*/
+#define XFS_FSOP_GEOM_FLAGS_IALIGN	0x0008	/* inode alignment	*/
+#define XFS_FSOP_GEOM_FLAGS_DALIGN	0x0010	/* large data alignment */
+#define XFS_FSOP_GEOM_FLAGS_SHARED	0x0020	/* read-only shared	*/
+#define XFS_FSOP_GEOM_FLAGS_EXTFLG	0x0040	/* special extent flag	*/
+#define XFS_FSOP_GEOM_FLAGS_DIRV2	0x0080	/* directory version 2	*/
+#define XFS_FSOP_GEOM_FLAGS_LOGV2	0x0100	/* log format version 2	*/
+#define XFS_FSOP_GEOM_FLAGS_SECTOR	0x0200	/* sector sizes >1BB	*/
+#define XFS_FSOP_GEOM_FLAGS_ATTR2	0x0400	/* inline attributes rework */
+#define XFS_FSOP_GEOM_FLAGS_DIRV2CI	0x1000	/* ASCII only CI names */
+#define XFS_FSOP_GEOM_FLAGS_LAZYSB	0x4000	/* lazy superblock counters */
+
+
+/*
+ * Minimum and maximum sizes need for growth checks
+ */
+#define XFS_MIN_AG_BLOCKS	64
+#define XFS_MIN_LOG_BLOCKS	512ULL
+#define XFS_MAX_LOG_BLOCKS	(1024 * 1024ULL)
+#define XFS_MIN_LOG_BYTES	(10 * 1024 * 1024ULL)
+
+/* keep the maximum size under 2^31 by a small amount */
+#define XFS_MAX_LOG_BYTES \
+	((2 * 1024 * 1024 * 1024ULL) - XFS_MIN_LOG_BYTES)
+
+/* Used for sanity checks on superblock */
+#define XFS_MAX_DBLOCKS(s) ((xfs_drfsbno_t)(s)->sb_agcount * (s)->sb_agblocks)
+#define XFS_MIN_DBLOCKS(s) ((xfs_drfsbno_t)((s)->sb_agcount - 1) *	\
+			 (s)->sb_agblocks + XFS_MIN_AG_BLOCKS)
+
+/*
+ * Structures for XFS_IOC_FSGROWFSDATA, XFS_IOC_FSGROWFSLOG & XFS_IOC_FSGROWFSRT
+ */
+typedef struct xfs_growfs_data {
+	uint64_t		newblocks;	/* new data subvol size, fsblocks */
+	uint32_t		imaxpct;	/* new inode space percentage limit */
+} xfs_growfs_data_t;
+
+typedef struct xfs_growfs_log {
+	uint32_t		newblocks;	/* new log size, fsblocks */
+	uint32_t		isint;		/* 1 if new log is internal */
+} xfs_growfs_log_t;
+
+typedef struct xfs_growfs_rt {
+	uint64_t		newblocks;	/* new realtime size, fsblocks */
+	uint32_t		extsize;	/* new realtime extent size, fsblocks */
+} xfs_growfs_rt_t;
+
+
+/*
+ * Structures returned from ioctl XFS_IOC_FSBULKSTAT & XFS_IOC_FSBULKSTAT_SINGLE
+ */
+typedef struct xfs_bstime {
+	time_t		tv_sec;		/* seconds		*/
+	int32_t		tv_nsec;	/* and nanoseconds	*/
+} xfs_bstime_t;
+
+typedef struct xfs_bstat {
+	uint64_t		bs_ino;		/* inode number			*/
+	__u16		bs_mode;	/* type and mode		*/
+	__u16		bs_nlink;	/* number of links		*/
+	uint32_t		bs_uid;		/* user id			*/
+	uint32_t		bs_gid;		/* group id			*/
+	uint32_t		bs_rdev;	/* device value			*/
+	int32_t		bs_blksize;	/* block size			*/
+	int64_t		bs_size;	/* file size			*/
+	xfs_bstime_t	bs_atime;	/* access time			*/
+	xfs_bstime_t	bs_mtime;	/* modify time			*/
+	xfs_bstime_t	bs_ctime;	/* inode change time		*/
+	int64_t		bs_blocks;	/* number of blocks		*/
+	uint32_t		bs_xflags;	/* extended flags		*/
+	int32_t		bs_extsize;	/* extent size			*/
+	int32_t		bs_extents;	/* number of extents		*/
+	uint32_t		bs_gen;		/* generation count		*/
+	__u16		bs_projid_lo;	/* lower part of project id	*/
+#define	bs_projid	bs_projid_lo	/* (previously just bs_projid)	*/
+	__u16		bs_forkoff;	/* inode fork offset in bytes	*/
+	__u16		bs_projid_hi;	/* higher part of project id	*/
+	unsigned char	bs_pad[10];	/* pad space, unused		*/
+	uint32_t		bs_dmevmask;	/* DMIG event mask		*/
+	__u16		bs_dmstate;	/* DMIG state info		*/
+	__u16		bs_aextents;	/* attribute number of extents	*/
+} xfs_bstat_t;
+
+/*
+ * The user-level BulkStat Request interface structure.
+ */
+typedef struct xfs_fsop_bulkreq {
+	uint64_t		__user *lastip;	/* last inode # pointer		*/
+	int32_t		icount;		/* count of entries in buffer	*/
+	void		__user *ubuffer;/* user buffer for inode desc.	*/
+	int32_t		__user *ocount;	/* output count pointer		*/
+} xfs_fsop_bulkreq_t;
+
+
+/*
+ * Structures returned from xfs_inumbers routine (XFS_IOC_FSINUMBERS).
+ */
+typedef struct xfs_inogrp {
+	uint64_t		xi_startino;	/* starting inode number	*/
+	int32_t		xi_alloccount;	/* # bits set in allocmask	*/
+	uint64_t		xi_allocmask;	/* mask of allocated inodes	*/
+} xfs_inogrp_t;
+
+
+/*
+ * Error injection.
+ */
+typedef struct xfs_error_injection {
+	int32_t		fd;
+	int32_t		errtag;
+} xfs_error_injection_t;
+
+
+/*
+ * The user-level Handle Request interface structure.
+ */
+typedef struct xfs_fsop_handlereq {
+	uint32_t		fd;		/* fd for FD_TO_HANDLE		*/
+	void		__user *path;	/* user pathname		*/
+	uint32_t		oflags;		/* open flags			*/
+	void		__user *ihandle;/* user supplied handle		*/
+	uint32_t		ihandlen;	/* user supplied length		*/
+	void		__user *ohandle;/* user buffer for handle	*/
+	uint32_t		__user *ohandlen;/* user buffer length		*/
+} xfs_fsop_handlereq_t;
+
+/*
+ * Compound structures for passing args through Handle Request interfaces
+ * xfs_fssetdm_by_handle, xfs_attrlist_by_handle, xfs_attrmulti_by_handle
+ * - ioctls: XFS_IOC_FSSETDM_BY_HANDLE, XFS_IOC_ATTRLIST_BY_HANDLE, and
+ *	     XFS_IOC_ATTRMULTI_BY_HANDLE
+ */
+
+typedef struct xfs_fsop_setdm_handlereq {
+	struct xfs_fsop_handlereq	hreq;	/* handle information	*/
+	struct fsdmidata		__user *data;	/* DMAPI data	*/
+} xfs_fsop_setdm_handlereq_t;
+
+typedef struct xfs_attrlist_cursor {
+	uint32_t		opaque[4];
+} xfs_attrlist_cursor_t;
+
+typedef struct xfs_fsop_attrlist_handlereq {
+	struct xfs_fsop_handlereq	hreq; /* handle interface structure */
+	struct xfs_attrlist_cursor	pos; /* opaque cookie, list offset */
+	uint32_t				flags;	/* which namespace to use */
+	uint32_t				buflen;	/* length of buffer supplied */
+	void				__user *buffer;	/* returned names */
+} xfs_fsop_attrlist_handlereq_t;
+
+typedef struct xfs_attr_multiop {
+	uint32_t		am_opcode;
+#define ATTR_OP_GET	1	/* return the indicated attr's value */
+#define ATTR_OP_SET	2	/* set/create the indicated attr/value pair */
+#define ATTR_OP_REMOVE	3	/* remove the indicated attr */
+	int32_t		am_error;
+	void		__user *am_attrname;
+	void		__user *am_attrvalue;
+	uint32_t		am_length;
+	uint32_t		am_flags;
+} xfs_attr_multiop_t;
+
+typedef struct xfs_fsop_attrmulti_handlereq {
+	struct xfs_fsop_handlereq	hreq; /* handle interface structure */
+	uint32_t				opcount;/* count of following multiop */
+	struct xfs_attr_multiop		__user *ops; /* attr_multi data */
+} xfs_fsop_attrmulti_handlereq_t;
+
+/*
+ * per machine unique filesystem identifier types.
+ */
+typedef struct { uint32_t val[2]; } xfs_fsid_t; /* file system id type */
+
+typedef struct xfs_fid {
+	__u16	fid_len;		/* length of remainder	*/
+	__u16	fid_pad;
+	uint32_t	fid_gen;		/* generation number	*/
+	uint64_t	fid_ino;		/* 64 bits inode number */
+} xfs_fid_t;
+
+typedef struct xfs_handle {
+	union {
+		int64_t	    align;	/* force alignment of ha_fid	 */
+		xfs_fsid_t  _ha_fsid;	/* unique file system identifier */
+	} ha_u;
+	xfs_fid_t	ha_fid;		/* file system specific file ID	 */
+} xfs_handle_t;
+#define ha_fsid ha_u._ha_fsid
+
+#define XFS_HSIZE(handle)	(((char *) &(handle).ha_fid.fid_pad	 \
+				 - (char *) &(handle))			  \
+				 + (handle).ha_fid.fid_len)
+
+/*
+ * Flags for going down operation
+ */
+#define XFS_FSOP_GOING_FLAGS_DEFAULT		0x0	/* going down */
+#define XFS_FSOP_GOING_FLAGS_LOGFLUSH		0x1	/* flush log but not data */
+#define XFS_FSOP_GOING_FLAGS_NOLOGFLUSH		0x2	/* don't flush log nor data */
+
+/*
+ * ioctl commands that are used by Linux filesystems
+ */
+#define XFS_IOC_GETXFLAGS	FS_IOC_GETFLAGS
+#define XFS_IOC_SETXFLAGS	FS_IOC_SETFLAGS
+#define XFS_IOC_GETVERSION	FS_IOC_GETVERSION
+
+/*
+ * ioctl commands that replace IRIX fcntl()'s
+ * For 'documentation' purposed more than anything else,
+ * the "cmd #" field reflects the IRIX fcntl number.
+ */
+#define XFS_IOC_ALLOCSP		_IOW ('X', 10, struct xfs_flock64)
+#define XFS_IOC_FREESP		_IOW ('X', 11, struct xfs_flock64)
+#define XFS_IOC_DIOINFO		_IOR ('X', 30, struct dioattr)
+#define XFS_IOC_FSGETXATTR	_IOR ('X', 31, struct fsxattr)
+#define XFS_IOC_FSSETXATTR	_IOW ('X', 32, struct fsxattr)
+#define XFS_IOC_ALLOCSP64	_IOW ('X', 36, struct xfs_flock64)
+#define XFS_IOC_FREESP64	_IOW ('X', 37, struct xfs_flock64)
+#define XFS_IOC_GETBMAP		_IOWR('X', 38, struct getbmap)
+#define XFS_IOC_FSSETDM		_IOW ('X', 39, struct fsdmidata)
+#define XFS_IOC_RESVSP		_IOW ('X', 40, struct xfs_flock64)
+#define XFS_IOC_UNRESVSP	_IOW ('X', 41, struct xfs_flock64)
+#define XFS_IOC_RESVSP64	_IOW ('X', 42, struct xfs_flock64)
+#define XFS_IOC_UNRESVSP64	_IOW ('X', 43, struct xfs_flock64)
+#define XFS_IOC_GETBMAPA	_IOWR('X', 44, struct getbmap)
+#define XFS_IOC_FSGETXATTRA	_IOR ('X', 45, struct fsxattr)
+/*	XFS_IOC_SETBIOSIZE ---- deprecated 46	   */
+/*	XFS_IOC_GETBIOSIZE ---- deprecated 47	   */
+#define XFS_IOC_GETBMAPX	_IOWR('X', 56, struct getbmap)
+#define XFS_IOC_ZERO_RANGE	_IOW ('X', 57, struct xfs_flock64)
+
+/*
+ * ioctl commands that replace IRIX syssgi()'s
+ */
+#define XFS_IOC_FSGEOMETRY_V1	     _IOR ('X', 100, struct xfs_fsop_geom_v1)
+#define XFS_IOC_FSBULKSTAT	     _IOWR('X', 101, struct xfs_fsop_bulkreq)
+#define XFS_IOC_FSBULKSTAT_SINGLE    _IOWR('X', 102, struct xfs_fsop_bulkreq)
+#define XFS_IOC_FSINUMBERS	     _IOWR('X', 103, struct xfs_fsop_bulkreq)
+#define XFS_IOC_PATH_TO_FSHANDLE     _IOWR('X', 104, struct xfs_fsop_handlereq)
+#define XFS_IOC_PATH_TO_HANDLE	     _IOWR('X', 105, struct xfs_fsop_handlereq)
+#define XFS_IOC_FD_TO_HANDLE	     _IOWR('X', 106, struct xfs_fsop_handlereq)
+#define XFS_IOC_OPEN_BY_HANDLE	     _IOWR('X', 107, struct xfs_fsop_handlereq)
+#define XFS_IOC_READLINK_BY_HANDLE   _IOWR('X', 108, struct xfs_fsop_handlereq)
+#define XFS_IOC_SWAPEXT		     _IOWR('X', 109, struct xfs_swapext)
+#define XFS_IOC_FSGROWFSDATA	     _IOW ('X', 110, struct xfs_growfs_data)
+#define XFS_IOC_FSGROWFSLOG	     _IOW ('X', 111, struct xfs_growfs_log)
+#define XFS_IOC_FSGROWFSRT	     _IOW ('X', 112, struct xfs_growfs_rt)
+#define XFS_IOC_FSCOUNTS	     _IOR ('X', 113, struct xfs_fsop_counts)
+#define XFS_IOC_SET_RESBLKS	     _IOWR('X', 114, struct xfs_fsop_resblks)
+#define XFS_IOC_GET_RESBLKS	     _IOR ('X', 115, struct xfs_fsop_resblks)
+#define XFS_IOC_ERROR_INJECTION	     _IOW ('X', 116, struct xfs_error_injection)
+#define XFS_IOC_ERROR_CLEARALL	     _IOW ('X', 117, struct xfs_error_injection)
+/*	XFS_IOC_ATTRCTL_BY_HANDLE -- deprecated 118	 */
+/*	XFS_IOC_FREEZE		  -- FIFREEZE   119	 */
+/*	XFS_IOC_THAW		  -- FITHAW     120	 */
+#define XFS_IOC_FSSETDM_BY_HANDLE    _IOW ('X', 121, struct xfs_fsop_setdm_handlereq)
+#define XFS_IOC_ATTRLIST_BY_HANDLE   _IOW ('X', 122, struct xfs_fsop_attrlist_handlereq)
+#define XFS_IOC_ATTRMULTI_BY_HANDLE  _IOW ('X', 123, struct xfs_fsop_attrmulti_handlereq)
+#define XFS_IOC_FSGEOMETRY	     _IOR ('X', 124, struct xfs_fsop_geom)
+#define XFS_IOC_GOINGDOWN	     _IOR ('X', 125, __uint32_t)
+/*	XFS_IOC_GETFSUUID ---------- deprecated 140	 */
+
+
+#ifndef HAVE_BBMACROS
+/*
+ * Block I/O parameterization.	A basic block (BB) is the lowest size of
+ * filesystem allocation, and must equal 512.  Length units given to bio
+ * routines are in BB's.
+ */
+#define BBSHIFT		9
+#define BBSIZE		(1<<BBSHIFT)
+#define BBMASK		(BBSIZE-1)
+#define BTOBB(bytes)	(((uint64_t)(bytes) + BBSIZE - 1) >> BBSHIFT)
+#define BTOBBT(bytes)	((uint64_t)(bytes) >> BBSHIFT)
+#define BBTOB(bbs)	((bbs) << BBSHIFT)
+#endif
+
+#endif	/* XFS_FS_H_ */
diff --git a/core/fs/xfs/xfs_readdir.c b/core/fs/xfs/xfs_readdir.c
new file mode 100644
index 0000000..0e013e5
--- /dev/null
+++ b/core/fs/xfs/xfs_readdir.c
@@ -0,0 +1,404 @@
+/*
+ * Copyright (c) 2012 Paulo Alcantara <pcacjr at zytor.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <cache.h>
+#include <core.h>
+#include <fs.h>
+
+#include "xfs_types.h"
+#include "xfs_sb.h"
+#include "xfs_ag.h"
+#include "misc.h"
+#include "xfs.h"
+#include "xfs_dinode.h"
+#include "xfs_dir2.h"
+
+#include "xfs_readdir.h"
+
+static int fill_dirent(struct fs_info *fs, struct dirent *dirent,
+		       uint32_t offset, xfs_ino_t ino, char *name,
+		       size_t namelen)
+{
+    xfs_dinode_t *core;
+
+    dirent->d_ino = ino;
+    dirent->d_off = offset;
+    dirent->d_reclen = offsetof(struct dirent, d_name) + namelen + 1;
+
+    core = xfs_dinode_get_core(fs, ino);
+    if (!core) {
+        xfs_error("Failed to get dinode from disk (ino 0x%llx)", ino);
+        return -1;
+    }
+
+    if (be16_to_cpu(core->di_mode) & S_IFDIR)
+	dirent->d_type = DT_DIR;
+    else if (be16_to_cpu(core->di_mode) & S_IFREG)
+	dirent->d_type = DT_REG;
+    else if (be16_to_cpu(core->di_mode) & S_IFLNK)
+        dirent->d_type = DT_LNK;
+
+    memcpy(dirent->d_name, name, namelen + 1);
+
+    return 0;
+}
+
+int xfs_readdir_dir2_local(struct file *file, struct dirent *dirent,
+			   xfs_dinode_t *core)
+{
+    xfs_dir2_sf_t *sf = (xfs_dir2_sf_t *)&core->di_literal_area[0];
+    xfs_dir2_sf_entry_t *sf_entry;
+    uint8_t count = sf->hdr.i8count ? sf->hdr.i8count : sf->hdr.count;
+    uint32_t offset = file->offset;
+    uint8_t *start_name;
+    uint8_t *end_name;
+    char *name;
+    xfs_ino_t ino;
+    struct fs_info *fs = file->fs;
+    int retval = 0;
+
+    xfs_debug("count %hhu i8count %hhu", sf->hdr.count, sf->hdr.i8count);
+
+    if (file->offset + 1 > count)
+	return -1;
+
+    file->offset++;
+
+    sf_entry = (xfs_dir2_sf_entry_t *)((uint8_t *)&sf->list[0] -
+				       (!sf->hdr.i8count ? 4 : 0));
+
+    if (file->offset - 1) {
+	offset = file->offset;
+	while (--offset) {
+	    sf_entry = (xfs_dir2_sf_entry_t *)(
+				(uint8_t *)sf_entry +
+				offsetof(struct xfs_dir2_sf_entry,
+					 name[0]) +
+				sf_entry->namelen +
+				(sf->hdr.i8count ? 8 : 4));
+	}
+    }
+
+    start_name = &sf_entry->name[0];
+    end_name = start_name + sf_entry->namelen;
+
+    name = xfs_dir2_get_entry_name(start_name, end_name);
+
+    ino = xfs_dir2_sf_get_inumber(sf, (xfs_dir2_inou_t *)(
+				      (uint8_t *)sf_entry +
+				      offsetof(struct xfs_dir2_sf_entry,
+					       name[0]) +
+				      sf_entry->namelen));
+
+    retval = fill_dirent(fs, dirent, file->offset, ino, (char *)name,
+			 end_name - start_name);
+    if (retval)
+	xfs_error("Failed to fill in dirent structure");
+
+    free(name);
+
+    return retval;
+}
+
+int xfs_readdir_dir2_block(struct file *file, struct dirent *dirent,
+			   xfs_dinode_t *core)
+{
+    xfs_bmbt_irec_t r;
+    block_t dir_blk;
+    struct fs_info *fs = file->fs;
+    uint8_t *dirblk_buf;
+    uint8_t *p;
+    uint32_t offset;
+    xfs_dir2_data_hdr_t *hdr;
+    xfs_dir2_block_tail_t *btp;
+    xfs_dir2_data_unused_t *dup;
+    xfs_dir2_data_entry_t *dep;
+    uint8_t *start_name;
+    uint8_t *end_name;
+    char *name;
+    xfs_ino_t ino;
+    int retval = 0;
+
+    bmbt_irec_get(&r, (xfs_bmbt_rec_t *)&core->di_literal_area[0]);
+    dir_blk = fsblock_to_bytes(fs, r.br_startblock) >> BLOCK_SHIFT(fs);
+
+    dirblk_buf = xfs_dir2_get_dirblks(fs, dir_blk, r.br_blockcount);
+    hdr = (xfs_dir2_data_hdr_t *)dirblk_buf;
+    if (be32_to_cpu(hdr->magic) != XFS_DIR2_BLOCK_MAGIC) {
+        xfs_error("Block directory header's magic number does not match!");
+        xfs_debug("hdr->magic: 0x%lx", be32_to_cpu(hdr->magic));
+
+	free(dirblk_buf);
+
+	return -1;
+    }
+
+    btp = xfs_dir2_block_tail_p(XFS_INFO(fs), hdr);
+
+    if (file->offset + 1 > be32_to_cpu(btp->count))
+	return -1;
+
+    file->offset++;
+
+    p = (uint8_t *)(hdr + 1);
+
+    if (file->offset - 1) {
+	offset = file->offset;
+	while (--offset) {
+	    dep = (xfs_dir2_data_entry_t *)p;
+
+	    dup = (xfs_dir2_data_unused_t *)p;
+	    if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) {
+		p += be16_to_cpu(dup->length);
+		continue;
+	    }
+
+	    p += xfs_dir2_data_entsize(dep->namelen);
+	}
+    }
+
+    dep = (xfs_dir2_data_entry_t *)p;
+
+    start_name = &dep->name[0];
+    end_name = start_name + dep->namelen;
+    name = xfs_dir2_get_entry_name(start_name, end_name);
+
+    ino = be64_to_cpu(dep->inumber);
+
+    retval = fill_dirent(fs, dirent, file->offset, ino, name,
+			 end_name - start_name);
+    if (retval)
+	xfs_error("Failed to fill in dirent structure");
+
+    free(dirblk_buf);
+    free(name);
+
+    return retval;
+}
+
+int xfs_readdir_dir2_leaf(struct file *file, struct dirent *dirent,
+			  xfs_dinode_t *core)
+{
+    xfs_bmbt_irec_t irec;
+    struct fs_info *fs = file->fs;
+    xfs_dir2_leaf_t *leaf;
+    block_t leaf_blk, dir_blk;
+    xfs_dir2_leaf_entry_t *lep;
+    uint32_t db;
+    unsigned int offset;
+    xfs_dir2_data_entry_t *dep;
+    xfs_dir2_data_hdr_t *data_hdr;
+    uint8_t *start_name;
+    uint8_t *end_name;
+    char *name;
+    xfs_intino_t ino;
+    uint8_t *buf = NULL;
+    int retval = 0;
+
+    bmbt_irec_get(&irec, ((xfs_bmbt_rec_t *)&core->di_literal_area[0]) +
+					be32_to_cpu(core->di_nextents) - 1);
+    leaf_blk = fsblock_to_bytes(fs, irec.br_startblock) >>
+					BLOCK_SHIFT(file->fs);
+
+    leaf = (xfs_dir2_leaf_t *)xfs_dir2_get_dirblks(fs, leaf_blk,
+						   irec.br_blockcount);
+    if (be16_to_cpu(leaf->hdr.info.magic) != XFS_DIR2_LEAF1_MAGIC) {
+        xfs_error("Single leaf block header's magic number does not match!");
+        goto out;
+    }
+
+    if (!leaf->hdr.count)
+        goto out;
+
+    if (file->offset + 1 > be16_to_cpu(leaf->hdr.count))
+	goto out;
+
+    lep = &leaf->ents[file->offset++];
+
+    /* Skip over stale leaf entries */
+    for ( ; be32_to_cpu(lep->address) == XFS_DIR2_NULL_DATAPTR;
+	  lep++, file->offset++);
+
+    db = xfs_dir2_dataptr_to_db(fs, be32_to_cpu(lep->address));
+
+    bmbt_irec_get(&irec, (xfs_bmbt_rec_t *)&core->di_literal_area[0] + db);
+
+    dir_blk = fsblock_to_bytes(fs, irec.br_startblock) >> BLOCK_SHIFT(fs);
+
+    buf = xfs_dir2_get_dirblks(fs, dir_blk, irec.br_blockcount);
+    data_hdr = (xfs_dir2_data_hdr_t *)buf;
+    if (be32_to_cpu(data_hdr->magic) != XFS_DIR2_DATA_MAGIC) {
+	xfs_error("Leaf directory's data magic number does not match!");
+	goto out1;
+    }
+
+    offset = xfs_dir2_dataptr_to_off(fs, be32_to_cpu(lep->address));
+
+    dep = (xfs_dir2_data_entry_t *)((uint8_t *)buf + offset);
+
+    start_name = &dep->name[0];
+    end_name = start_name + dep->namelen;
+    name = xfs_dir2_get_entry_name(start_name, end_name);
+
+    ino = be64_to_cpu(dep->inumber);
+
+    retval = fill_dirent(fs, dirent, file->offset, ino, name,
+			 end_name - start_name);
+    if (retval)
+	xfs_error("Failed to fill in dirent structure");
+
+    free(name);
+    free(buf);
+    free(leaf);
+
+    return retval;
+
+out1:
+    free(buf);
+
+out:
+    free(leaf);
+
+    return -1;
+}
+
+int xfs_readdir_dir2_node(struct file *file, struct dirent *dirent,
+			  xfs_dinode_t *core)
+{
+    struct fs_info *fs = file->fs;
+    xfs_bmbt_irec_t irec;
+    uint32_t node_off = 0;
+    block_t fsblkno;
+    xfs_da_intnode_t *node = NULL;
+    struct inode *inode = file->inode;
+    int error;
+    xfs_dir2_data_hdr_t *data_hdr;
+    xfs_dir2_leaf_t *leaf;
+    xfs_dir2_leaf_entry_t *lep;
+    unsigned int offset;
+    xfs_dir2_data_entry_t *dep;
+    uint8_t *start_name;
+    uint8_t *end_name;
+    char *name;
+    uint32_t db;
+    uint8_t *buf = NULL;
+    int retval = 0;
+
+    do {
+        bmbt_irec_get(&irec, (xfs_bmbt_rec_t *)&core->di_literal_area[0] +
+								++node_off);
+    } while (irec.br_startoff < xfs_dir2_byte_to_db(fs, XFS_DIR2_LEAF_OFFSET));
+
+    fsblkno = fsblock_to_bytes(fs, irec.br_startblock) >> BLOCK_SHIFT(fs);
+
+    node = (xfs_da_intnode_t *)xfs_dir2_get_dirblks(fs, fsblkno, 1);
+    if (be16_to_cpu(node->hdr.info.magic) != XFS_DA_NODE_MAGIC) {
+        xfs_error("Node's magic number does not match!");
+        goto out;
+    }
+
+try_next_btree:
+    if (!node->hdr.count ||
+	XFS_PVT(inode)->i_btree_offset >= be16_to_cpu(node->hdr.count))
+        goto out;
+
+    fsblkno = be32_to_cpu(node->btree[XFS_PVT(inode)->i_btree_offset].before);
+    fsblkno = xfs_dir2_get_right_blk(fs, core, fsblkno, &error);
+    if (error) {
+        xfs_error("Cannot find leaf rec!");
+        goto out;
+    }
+
+    leaf = (xfs_dir2_leaf_t*)xfs_dir2_get_dirblks(fs, fsblkno, 1);
+    if (be16_to_cpu(leaf->hdr.info.magic) != XFS_DIR2_LEAFN_MAGIC) {
+        xfs_error("Leaf's magic number does not match!");
+        goto out1;
+    }
+
+    if (!leaf->hdr.count ||
+	XFS_PVT(inode)->i_leaf_ent_offset >= be16_to_cpu(leaf->hdr.count)) {
+	XFS_PVT(inode)->i_btree_offset++;
+	XFS_PVT(inode)->i_leaf_ent_offset = 0;
+	free(leaf);
+	goto try_next_btree;
+    }
+
+    lep = &leaf->ents[XFS_PVT(inode)->i_leaf_ent_offset];
+
+    /* Skip over stale leaf entries */
+    for ( ; XFS_PVT(inode)->i_leaf_ent_offset < be16_to_cpu(leaf->hdr.count) &&
+			be32_to_cpu(lep->address) == XFS_DIR2_NULL_DATAPTR;
+	  lep++, XFS_PVT(inode)->i_leaf_ent_offset++);
+
+    if (XFS_PVT(inode)->i_leaf_ent_offset == be16_to_cpu(leaf->hdr.count)) {
+	XFS_PVT(inode)->i_btree_offset++;
+	XFS_PVT(inode)->i_leaf_ent_offset = 0;
+	free(leaf);
+	goto try_next_btree;
+    } else {
+	XFS_PVT(inode)->i_leaf_ent_offset++;
+    }
+
+    db = xfs_dir2_dataptr_to_db(fs, be32_to_cpu(lep->address));
+
+    fsblkno = xfs_dir2_get_right_blk(fs, core, db, &error);
+    if (error) {
+	xfs_error("Cannot find data block!");
+	goto out1;
+    }
+
+    buf = xfs_dir2_get_dirblks(fs, fsblkno, 1);
+    data_hdr = (xfs_dir2_data_hdr_t *)buf;
+    if (be32_to_cpu(data_hdr->magic) != XFS_DIR2_DATA_MAGIC) {
+	xfs_error("Leaf directory's data magic No. does not match!");
+	goto out2;
+    }
+
+    offset = xfs_dir2_dataptr_to_off(fs, be32_to_cpu(lep->address));
+
+    dep = (xfs_dir2_data_entry_t *)((uint8_t *)buf + offset);
+
+    start_name = &dep->name[0];
+    end_name = start_name + dep->namelen;
+    name = xfs_dir2_get_entry_name(start_name, end_name);
+
+    retval = fill_dirent(fs, dirent, 0, be64_to_cpu(dep->inumber), name,
+			 end_name - start_name);
+    if (retval)
+	xfs_error("Failed to fill in dirent structure");
+
+    free(name);
+    free(buf);
+    free(leaf);
+    free(node);
+
+    return retval;
+
+out2:
+    free(buf);
+
+out1:
+    free(leaf);
+
+out:
+    free(node);
+
+    XFS_PVT(inode)->i_btree_offset = 0;
+    XFS_PVT(inode)->i_leaf_ent_offset = 0;
+
+    return -1;
+}
diff --git a/core/fs/xfs/xfs_readdir.h b/core/fs/xfs/xfs_readdir.h
new file mode 100644
index 0000000..2e564ec
--- /dev/null
+++ b/core/fs/xfs/xfs_readdir.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2012 Paulo Alcantara <pcacjr at zytor.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef XFS_READDIR_H_
+#define XFS_READDIR_H_
+
+int xfs_readdir_dir2_local(struct file *file, struct dirent *dirent,
+			   xfs_dinode_t *core);
+int xfs_readdir_dir2_block(struct file *file, struct dirent *dirent,
+			   xfs_dinode_t *core);
+int xfs_readdir_dir2_leaf(struct file *file, struct dirent *dirent,
+			  xfs_dinode_t *core);
+int xfs_readdir_dir2_node(struct file *file, struct dirent *dirent,
+			  xfs_dinode_t *core);
+
+#endif /* XFS_READDIR_H_ */
diff --git a/core/fs/xfs/xfs_sb.h b/core/fs/xfs/xfs_sb.h
new file mode 100644
index 0000000..12024ab
--- /dev/null
+++ b/core/fs/xfs/xfs_sb.h
@@ -0,0 +1,206 @@
+/*
+ * Taken from Linux kernel tree (linux/fs/xfs)
+ *
+ * Copyright (c) 2000-2005 Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * Copyright (c) 2012 Paulo Alcantara <pcacjr at zytor.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+#ifndef XFS_SB_H_
+#define	XFS_SB_H_
+
+#include <stddef.h>
+
+#include <sys/types.h>
+
+typedef unsigned char uuid_t[16];
+
+/*
+ * Super block
+ * Fits into a sector-sized buffer at address 0 of each allocation group.
+ * Only the first of these is ever updated except during growfs.
+ */
+
+struct xfs_buf;
+struct xfs_mount;
+
+#define	XFS_SB_MAGIC		"XFSB"		/* '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_NUMBITS		0x000f
+#define	XFS_SB_VERSION_ALLFBITS		0xfff0
+#define	XFS_SB_VERSION_SASHFBITS	0xf000
+#define	XFS_SB_VERSION_REALFBITS	0x0ff0
+#define	XFS_SB_VERSION_ATTRBIT		0x0010
+#define	XFS_SB_VERSION_NLINKBIT		0x0020
+#define	XFS_SB_VERSION_QUOTABIT		0x0040
+#define	XFS_SB_VERSION_ALIGNBIT		0x0080
+#define	XFS_SB_VERSION_DALIGNBIT	0x0100
+#define	XFS_SB_VERSION_SHAREDBIT	0x0200
+#define XFS_SB_VERSION_LOGV2BIT		0x0400
+#define XFS_SB_VERSION_SECTORBIT	0x0800
+#define	XFS_SB_VERSION_EXTFLGBIT	0x1000
+#define	XFS_SB_VERSION_DIRV2BIT		0x2000
+#define	XFS_SB_VERSION_BORGBIT		0x4000	/* ASCII only case-insens. */
+#define	XFS_SB_VERSION_MOREBITSBIT	0x8000
+#define	XFS_SB_VERSION_OKSASHFBITS	\
+	(XFS_SB_VERSION_EXTFLGBIT | \
+	 XFS_SB_VERSION_DIRV2BIT | \
+	 XFS_SB_VERSION_BORGBIT)
+#define	XFS_SB_VERSION_OKREALFBITS	\
+	(XFS_SB_VERSION_ATTRBIT | \
+	 XFS_SB_VERSION_NLINKBIT | \
+	 XFS_SB_VERSION_QUOTABIT | \
+	 XFS_SB_VERSION_ALIGNBIT | \
+	 XFS_SB_VERSION_DALIGNBIT | \
+	 XFS_SB_VERSION_SHAREDBIT | \
+	 XFS_SB_VERSION_LOGV2BIT | \
+	 XFS_SB_VERSION_SECTORBIT | \
+	 XFS_SB_VERSION_MOREBITSBIT)
+#define	XFS_SB_VERSION_OKREALBITS	\
+	(XFS_SB_VERSION_NUMBITS | \
+	 XFS_SB_VERSION_OKREALFBITS | \
+	 XFS_SB_VERSION_OKSASHFBITS)
+
+/*
+ * There are two words to hold XFS "feature" bits: the original
+ * word, sb_versionnum, and sb_features2.  Whenever a bit is set in
+ * sb_features2, the feature bit XFS_SB_VERSION_MOREBITSBIT must be set.
+ *
+ * These defines represent bits in sb_features2.
+ */
+#define XFS_SB_VERSION2_REALFBITS	0x00ffffff	/* Mask: features */
+#define XFS_SB_VERSION2_RESERVED1BIT	0x00000001
+#define XFS_SB_VERSION2_LAZYSBCOUNTBIT	0x00000002	/* Superblk counters */
+#define XFS_SB_VERSION2_RESERVED4BIT	0x00000004
+#define XFS_SB_VERSION2_ATTR2BIT	0x00000008	/* Inline attr rework */
+#define XFS_SB_VERSION2_PARENTBIT	0x00000010	/* parent pointers */
+#define XFS_SB_VERSION2_PROJID32BIT	0x00000080	/* 32 bit project id */
+
+#define	XFS_SB_VERSION2_OKREALFBITS	\
+	(XFS_SB_VERSION2_LAZYSBCOUNTBIT	| \
+	 XFS_SB_VERSION2_ATTR2BIT	| \
+	 XFS_SB_VERSION2_PROJID32BIT)
+#define	XFS_SB_VERSION2_OKSASHFBITS	\
+	(0)
+#define XFS_SB_VERSION2_OKREALBITS	\
+	(XFS_SB_VERSION2_OKREALFBITS |	\
+	 XFS_SB_VERSION2_OKSASHFBITS )
+
+/*
+ * Sequence number values for the fields.
+ */
+typedef enum {
+	XFS_SBS_MAGICNUM, XFS_SBS_BLOCKSIZE, XFS_SBS_DBLOCKS, XFS_SBS_RBLOCKS,
+	XFS_SBS_REXTENTS, XFS_SBS_UUID, XFS_SBS_LOGSTART, XFS_SBS_ROOTINO,
+	XFS_SBS_RBMINO, XFS_SBS_RSUMINO, XFS_SBS_REXTSIZE, XFS_SBS_AGBLOCKS,
+	XFS_SBS_AGCOUNT, XFS_SBS_RBMBLOCKS, XFS_SBS_LOGBLOCKS,
+	XFS_SBS_VERSIONNUM, XFS_SBS_SECTSIZE, XFS_SBS_INODESIZE,
+	XFS_SBS_INOPBLOCK, XFS_SBS_FNAME, XFS_SBS_BLOCKLOG,
+	XFS_SBS_SECTLOG, XFS_SBS_INODELOG, XFS_SBS_INOPBLOG, XFS_SBS_AGBLKLOG,
+	XFS_SBS_REXTSLOG, XFS_SBS_INPROGRESS, XFS_SBS_IMAX_PCT, XFS_SBS_ICOUNT,
+	XFS_SBS_IFREE, XFS_SBS_FDBLOCKS, XFS_SBS_FREXTENTS, XFS_SBS_UQUOTINO,
+	XFS_SBS_GQUOTINO, XFS_SBS_QFLAGS, XFS_SBS_FLAGS, XFS_SBS_SHARED_VN,
+	XFS_SBS_INOALIGNMT, XFS_SBS_UNIT, XFS_SBS_WIDTH, XFS_SBS_DIRBLKLOG,
+	XFS_SBS_LOGSECTLOG, XFS_SBS_LOGSECTSIZE, XFS_SBS_LOGSUNIT,
+	XFS_SBS_FEATURES2, XFS_SBS_BAD_FEATURES2,
+	XFS_SBS_FIELDCOUNT
+} xfs_sb_field_t;
+
+/*
+ * Mask values, defined based on the xfs_sb_field_t values.
+ * Only define the ones we're using.
+ */
+#define	XFS_SB_MVAL(x)		(1LL << XFS_SBS_ ## x)
+#define	XFS_SB_UUID		XFS_SB_MVAL(UUID)
+#define	XFS_SB_FNAME		XFS_SB_MVAL(FNAME)
+#define	XFS_SB_ROOTINO		XFS_SB_MVAL(ROOTINO)
+#define	XFS_SB_RBMINO		XFS_SB_MVAL(RBMINO)
+#define	XFS_SB_RSUMINO		XFS_SB_MVAL(RSUMINO)
+#define	XFS_SB_VERSIONNUM	XFS_SB_MVAL(VERSIONNUM)
+#define XFS_SB_UQUOTINO		XFS_SB_MVAL(UQUOTINO)
+#define XFS_SB_GQUOTINO		XFS_SB_MVAL(GQUOTINO)
+#define XFS_SB_QFLAGS		XFS_SB_MVAL(QFLAGS)
+#define XFS_SB_SHARED_VN	XFS_SB_MVAL(SHARED_VN)
+#define XFS_SB_UNIT		XFS_SB_MVAL(UNIT)
+#define XFS_SB_WIDTH		XFS_SB_MVAL(WIDTH)
+#define XFS_SB_ICOUNT		XFS_SB_MVAL(ICOUNT)
+#define XFS_SB_IFREE		XFS_SB_MVAL(IFREE)
+#define XFS_SB_FDBLOCKS		XFS_SB_MVAL(FDBLOCKS)
+#define XFS_SB_FEATURES2	XFS_SB_MVAL(FEATURES2)
+#define XFS_SB_BAD_FEATURES2	XFS_SB_MVAL(BAD_FEATURES2)
+#define	XFS_SB_NUM_BITS		((int)XFS_SBS_FIELDCOUNT)
+#define	XFS_SB_ALL_BITS		((1LL << XFS_SB_NUM_BITS) - 1)
+#define	XFS_SB_MOD_BITS		\
+	(XFS_SB_UUID | XFS_SB_ROOTINO | XFS_SB_RBMINO | XFS_SB_RSUMINO | \
+	 XFS_SB_VERSIONNUM | XFS_SB_UQUOTINO | XFS_SB_GQUOTINO | \
+	 XFS_SB_QFLAGS | XFS_SB_SHARED_VN | XFS_SB_UNIT | XFS_SB_WIDTH | \
+	 XFS_SB_ICOUNT | XFS_SB_IFREE | XFS_SB_FDBLOCKS | XFS_SB_FEATURES2 | \
+	 XFS_SB_BAD_FEATURES2)
+
+
+/*
+ * Misc. Flags - warning - these will be cleared by xfs_repair unless
+ * a feature bit is set when the flag is used.
+ */
+#define XFS_SBF_NOFLAGS		0x00	/* no flags set */
+#define XFS_SBF_READONLY	0x01	/* only read-only mounts allowed */
+
+/*
+ * define max. shared version we can interoperate with
+ */
+#define XFS_SB_MAX_SHARED_VN	0
+
+#define	XFS_SB_VERSION_NUM(sbp)	((sbp)->sb_versionnum & XFS_SB_VERSION_NUMBITS)
+
+/*
+ * end of superblock version macros
+ */
+
+#define	XFS_SB_BLOCK(mp)	XFS_HDR_BLOCK(mp, XFS_SB_DADDR)
+#define XFS_BUF_TO_SBP(bp)	((xfs_dsb_t *)((bp)->b_addr))
+
+#define	XFS_HDR_BLOCK(mp,d)	((xfs_agblock_t)XFS_BB_TO_FSBT(mp,d))
+#define	XFS_DADDR_TO_FSB(mp,d)	XFS_AGB_TO_FSB(mp, \
+			xfs_daddr_to_agno(mp,d), xfs_daddr_to_agbno(mp,d))
+#define	XFS_FSB_TO_DADDR(mp,fsbno)	XFS_AGB_TO_DADDR(mp, \
+			XFS_FSB_TO_AGNO(mp,fsbno), XFS_FSB_TO_AGBNO(mp,fsbno))
+
+/*
+ * File system sector to basic block conversions.
+ */
+#define XFS_FSS_TO_BB(mp,sec)	((sec) << (mp)->m_sectbb_log)
+
+/*
+ * File system block to basic block conversions.
+ */
+#define	XFS_FSB_TO_BB(mp,fsbno)	((fsbno) << (mp)->m_blkbb_log)
+#define	XFS_BB_TO_FSB(mp,bb)	\
+	(((bb) + (XFS_FSB_TO_BB(mp,1) - 1)) >> (mp)->m_blkbb_log)
+#define	XFS_BB_TO_FSBT(mp,bb)	((bb) >> (mp)->m_blkbb_log)
+
+/*
+ * File system block to byte conversions.
+ */
+#define XFS_FSB_TO_B(mp,fsbno)	((xfs_fsize_t)(fsbno) << (mp)->m_sb.sb_blocklog)
+#define XFS_B_TO_FSB(mp,b)	\
+	((((uint64_t)(b)) + (mp)->m_blockmask) >> (mp)->m_sb.sb_blocklog)
+#define XFS_B_TO_FSBT(mp,b)	(((uint64_t)(b)) >> (mp)->m_sb.sb_blocklog)
+#define XFS_B_FSB_OFFSET(mp,b)	((b) & (mp)->m_blockmask)
+
+#endif	/* XFS_SB_H_ */
diff --git a/core/fs/xfs/xfs_types.h b/core/fs/xfs/xfs_types.h
new file mode 100644
index 0000000..9280886
--- /dev/null
+++ b/core/fs/xfs/xfs_types.h
@@ -0,0 +1,135 @@
+/*
+ * Taken from Linux kernel tree (linux/fs/xfs)
+ *
+ * Copyright (c) 2000-2005 Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * Copyright (c) 2012 Paulo Alcantara <pcacjr at zytor.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+#ifndef XFS_TYPES_H_
+#define	XFS_TYPES_H_
+
+#include <stddef.h>
+
+#include <sys/types.h>
+
+typedef enum { B_FALSE,B_TRUE }	boolean_t;
+typedef uint32_t		prid_t;		/* project ID */
+typedef uint32_t		inst_t;		/* an instruction */
+
+typedef int64_t			xfs_off_t;	/* <file offset> type */
+typedef unsigned long long	xfs_ino_t;	/* <inode> type */
+typedef int64_t			xfs_daddr_t;	/* <disk address> type */
+typedef char *			xfs_caddr_t;	/* <core address> type */
+typedef uint32_t			xfs_dev_t;
+typedef uint32_t			xfs_nlink_t;
+
+/* __psint_t is the same size as a pointer */
+typedef int32_t __psint_t;
+typedef uint32_t __psunsigned_t;
+
+typedef uint32_t	xfs_agblock_t;	/* blockno in alloc. group */
+typedef	uint32_t	xfs_extlen_t;	/* extent length in blocks */
+typedef	uint32_t	xfs_agnumber_t;	/* allocation group number */
+typedef int32_t	xfs_extnum_t;	/* # of extents in a file */
+typedef int16_t	xfs_aextnum_t;	/* # extents in an attribute fork */
+typedef	int64_t	xfs_fsize_t;	/* bytes in a file */
+typedef uint64_t	xfs_ufsize_t;	/* unsigned bytes in a file */
+
+typedef	int32_t	xfs_suminfo_t;	/* type of bitmap summary info */
+typedef	int32_t	xfs_rtword_t;	/* word type for bitmap manipulations */
+
+typedef	int64_t	xfs_lsn_t;	/* log sequence number */
+typedef	int32_t	xfs_tid_t;	/* transaction identifier */
+
+typedef	uint32_t	xfs_dablk_t;	/* dir/attr block number (in file) */
+typedef	uint32_t	xfs_dahash_t;	/* dir/attr hash value */
+
+/*
+ * These types are 64 bits on disk but are either 32 or 64 bits in memory.
+ * Disk based types:
+ */
+typedef uint64_t	xfs_dfsbno_t;	/* blockno in filesystem (agno|agbno) */
+typedef uint64_t	xfs_drfsbno_t;	/* blockno in filesystem (raw) */
+typedef	uint64_t	xfs_drtbno_t;	/* extent (block) in realtime area */
+typedef	uint64_t	xfs_dfiloff_t;	/* block number in a file */
+typedef	uint64_t	xfs_dfilblks_t;	/* number of blocks in a file */
+
+/*
+ * Memory based types are conditional.
+ */
+typedef	uint64_t	xfs_fsblock_t;	/* blockno in filesystem (agno|agbno) */
+typedef uint64_t	xfs_rfsblock_t;	/* blockno in filesystem (raw) */
+typedef uint64_t	xfs_rtblock_t;	/* extent (block) in realtime area */
+typedef	int64_t	xfs_srtblock_t;	/* signed version of xfs_rtblock_t */
+
+typedef uint64_t	xfs_fileoff_t;	/* block number in a file */
+typedef int64_t	xfs_sfiloff_t;	/* signed block number in a file */
+typedef uint64_t	xfs_filblks_t;	/* number of blocks in a file */
+
+/*
+ * Null values for the types.
+ */
+#define	NULLDFSBNO	((xfs_dfsbno_t)-1)
+#define	NULLDRFSBNO	((xfs_drfsbno_t)-1)
+#define	NULLDRTBNO	((xfs_drtbno_t)-1)
+#define	NULLDFILOFF	((xfs_dfiloff_t)-1)
+
+#define	NULLFSBLOCK	((xfs_fsblock_t)-1)
+#define	NULLRFSBLOCK	((xfs_rfsblock_t)-1)
+#define	NULLRTBLOCK	((xfs_rtblock_t)-1)
+#define	NULLFILEOFF	((xfs_fileoff_t)-1)
+
+#define	NULLAGBLOCK	((xfs_agblock_t)-1)
+#define	NULLAGNUMBER	((xfs_agnumber_t)-1)
+#define	NULLEXTNUM	((xfs_extnum_t)-1)
+
+#define NULLCOMMITLSN	((xfs_lsn_t)-1)
+
+/*
+ * Max values for extlen, extnum, aextnum.
+ */
+#define	MAXEXTLEN	((xfs_extlen_t)0x001fffff)	/* 21 bits */
+#define	MAXEXTNUM	((xfs_extnum_t)0x7fffffff)	/* signed int */
+#define	MAXAEXTNUM	((xfs_aextnum_t)0x7fff)		/* signed short */
+
+/*
+ * Min numbers of data/attr fork btree root pointers.
+ */
+#define MINDBTPTRS	3
+#define MINABTPTRS	2
+
+/*
+ * MAXNAMELEN is the length (including the terminating null) of
+ * the longest permissible file (component) name.
+ */
+#define MAXNAMELEN	256
+
+typedef enum {
+	XFS_LOOKUP_EQi, XFS_LOOKUP_LEi, XFS_LOOKUP_GEi
+} xfs_lookup_t;
+
+typedef enum {
+	XFS_BTNUM_BNOi, XFS_BTNUM_CNTi, XFS_BTNUM_BMAPi, XFS_BTNUM_INOi,
+	XFS_BTNUM_MAX
+} xfs_btnum_t;
+
+struct xfs_name {
+	const unsigned char	*name;
+	int			len;
+};
+
+#endif	/* XFS_TYPES_H_ */
diff --git a/core/include/fs.h b/core/include/fs.h
index e1f5733..a9c76ae 100644
--- a/core/include/fs.h
+++ b/core/include/fs.h
@@ -98,9 +98,9 @@ struct inode {
     const char *name;		/* Name, valid for generic path search only */
     int		 refcnt;
     int          mode;   /* FILE , DIR or SYMLINK */
-    uint32_t     size;
-    uint32_t	 blocks; /* How many blocks the file take */
-    uint32_t     ino;    /* Inode number */
+    uint64_t     size;
+    uint64_t	 blocks; /* How many blocks the file take */
+    uint64_t     ino;    /* Inode number */
     uint32_t     atime;  /* Access time */
     uint32_t     mtime;  /* Modify time */
     uint32_t     ctime;  /* Create time */
diff --git a/core/ldlinux.asm b/core/ldlinux.asm
index a2f859d..a1f96b7 100644
--- a/core/ldlinux.asm
+++ b/core/ldlinux.asm
@@ -39,6 +39,8 @@ ROOT_FS_OPS:
 		dd ext2_fs_ops
 		extern ntfs_fs_ops
 		dd ntfs_fs_ops
+		extern xfs_fs_ops
+		dd xfs_fs_ops
 		extern btrfs_fs_ops
 		dd btrfs_fs_ops
 		dd 0
diff --git a/extlinux/main.c b/extlinux/main.c
index 73f3fbe..d1a800c 100644
--- a/extlinux/main.c
+++ b/extlinux/main.c
@@ -14,7 +14,8 @@
 /*
  * extlinux.c
  *
- * Install the syslinux boot block on an fat, ntfs, ext2/3/4 and btrfs filesystem
+ * Install the syslinux boot block on an fat, ntfs, ext2/3/4, btrfs and xfs
+ * filesystem.
  */
 
 #define  _GNU_SOURCE		/* Enable everything */
@@ -46,6 +47,10 @@
 #include "btrfs.h"
 #include "fat.h"
 #include "ntfs.h"
+#include "xfs.h"
+#include "xfs_types.h"
+#include "xfs_sb.h"
+#include "misc.h"
 #include "../version.h"
 #include "syslxint.h"
 #include "syslxcom.h" /* common functions shared with extlinux and syslinux */
@@ -64,6 +69,13 @@
 #define EXT2_SUPER_OFFSET 1024
 #endif
 
+/* Since we have unused 2048 bytes in the primary AG of an XFS partition,
+ * we will use the first 0~512 bytes starting from 2048 for the Syslinux
+ * boot sector.
+ */
+#define XFS_BOOTSECT_OFFSET	(4 << SECTOR_SHIFT)
+#define XFS_SUPPORTED_BLOCKSIZE 4096 /* 4 KiB filesystem block size */
+
 /* the btrfs partition first 64K blank area is used to store boot sector and
    boot image, the boot sector is from 0~512, the boot image starts after */
 #define BTRFS_BOOTSECT_AREA	65536
@@ -295,7 +307,8 @@ int patch_file_and_bootblock(int fd, const char *dir, int devfd)
     nsect = (boot_image_len + SECTOR_SIZE - 1) >> SECTOR_SHIFT;
     nsect += 2;			/* Two sectors for the ADV */
     sectp = alloca(sizeof(sector_t) * nsect);
-    if (fs_type == EXT2 || fs_type == VFAT || fs_type == NTFS) {
+    if (fs_type == EXT2 || fs_type == VFAT || fs_type == NTFS ||
+	fs_type == XFS) {
 	if (sectmap(fd, sectp, nsect)) {
 		perror("bmap");
 		exit(1);
@@ -328,6 +341,7 @@ int install_bootblock(int fd, const char *device)
     struct btrfs_super_block sb2;
     struct fat_boot_sector sb3;
     struct ntfs_boot_sector sb4;
+    xfs_sb_t sb5;
     bool ok = false;
 
     if (fs_type == EXT2) {
@@ -335,6 +349,7 @@ int install_bootblock(int fd, const char *device)
 		perror("reading superblock");
 		return 1;
 	}
+
 	if (sb.s_magic == EXT2_SUPER_MAGIC)
 		ok = true;
     } else if (fs_type == BTRFS) {
@@ -350,6 +365,7 @@ int install_bootblock(int fd, const char *device)
 		perror("reading fat superblock");
 		return 1;
 	}
+
 	if (fat_check_sb_fields(&sb3))
 		ok = true;
     } else if (fs_type == NTFS) {
@@ -360,12 +376,34 @@ int install_bootblock(int fd, const char *device)
 
         if (ntfs_check_sb_fields(&sb4))
              ok = true;
+    } else if (fs_type == XFS) {
+	if (xpread(fd, &sb5, sizeof sb5, 0) != sizeof sb5) {
+	    perror("reading xfs superblock");
+	    return 1;
+	}
+
+	if (sb5.sb_magicnum == *(u32 *)XFS_SB_MAGIC) {
+	    if (be32_to_cpu(sb5.sb_blocksize) != XFS_SUPPORTED_BLOCKSIZE) {
+		fprintf(stderr,
+			"You need to have 4 KiB filesystem block size for "
+			" being able to install Syslinux in your XFS "
+			"partition (because there is no enough space in MBR to "
+			"determine where Syslinux bootsector can be installed "
+			"regardless the filesystem block size)\n");
+		return 1;
+	    }
+
+	    ok = true;
+	}
     }
+
     if (!ok) {
-	fprintf(stderr, "no fat, ntfs, ext2/3/4 or btrfs superblock found on %s\n",
-			device);
+	fprintf(stderr,
+		"no fat, ntfs, ext2/3/4, btrfs or xfs superblock found on %s\n",
+		device);
 	return 1;
     }
+
     if (fs_type == VFAT) {
 	struct fat_boot_sector *sbs = (struct fat_boot_sector *)syslinux_bootsect;
         if (xpwrite(fd, &sbs->FAT_bsHead, FAT_bsHeadLen, 0) != FAT_bsHeadLen ||
@@ -385,6 +423,12 @@ int install_bootblock(int fd, const char *device)
             perror("writing ntfs bootblock");
             return 1;
         }
+    } else if (fs_type == XFS) {
+	if (xpwrite(fd, syslinux_bootsect, syslinux_bootsect_len,
+		    XFS_BOOTSECT_OFFSET) != syslinux_bootsect_len) {
+	    perror("writing xfs bootblock");
+	    return 1;
+	}
     } else {
 	if (xpwrite(fd, syslinux_bootsect, syslinux_bootsect_len, 0)
 	    != syslinux_bootsect_len) {
@@ -396,11 +440,61 @@ int install_bootblock(int fd, const char *device)
     return 0;
 }
 
+static int rewrite_boot_image(int devfd, const char *filename)
+{
+    int fd;
+    int ret;
+    int modbytes;
+    char path[PATH_MAX];
+    char slash;
+
+    /* Let's create LDLINUX.SYS file again (if it already exists, of course) */
+    fd = open(filename,  O_WRONLY | O_TRUNC | O_CREAT | O_SYNC,
+	      S_IRUSR | S_IRGRP | S_IROTH);
+    if (fd < 0) {
+	perror(filename);
+	return -1;
+    }
+
+    /* Write boot image data into LDLINUX.SYS file */
+    ret = xpwrite(fd, boot_image, boot_image_len, 0);
+    if (ret != boot_image_len) {
+	perror("writing bootblock");
+	goto error;
+    }
+
+    /* Write ADV */
+    ret = xpwrite(fd, syslinux_adv, 2 * ADV_SIZE, boot_image_len);
+    if (ret != 2 * ADV_SIZE) {
+	fprintf(stderr, "%s: write failure on %s\n", program, filename);
+	goto error;
+    }
+
+    sscanf(filename, "%s%cldlinux.sys", path, &slash);
+
+    /* Map the file, and patch the initial sector accordingly */
+    modbytes = patch_file_and_bootblock(fd, path, devfd);
+
+    /* Write the patch area again - this relies on the file being overwritten
+     * in place! */
+    ret = xpwrite(fd, boot_image, modbytes, 0);
+    if (ret != modbytes) {
+	fprintf(stderr, "%s: write failure on %s\n", program, filename);
+	goto error;
+    }
+
+    return fd;
+
+error:
+    close(fd);
+
+    return -1;
+}
+
 int ext2_fat_install_file(const char *path, int devfd, struct stat *rst)
 {
     char *file, *oldfile;
     int fd = -1, dirfd = -1;
-    int modbytes;
     int r1, r2;
 
     r1 = asprintf(&file, "%s%sldlinux.sys",
@@ -429,30 +523,9 @@ int ext2_fat_install_file(const char *path, int devfd, struct stat *rst)
     }
     close(fd);
 
-    fd = open(file, O_WRONLY | O_TRUNC | O_CREAT | O_SYNC,
-	      S_IRUSR | S_IRGRP | S_IROTH);
-    if (fd < 0) {
-	perror(file);
+    fd = rewrite_boot_image(devfd, file);
+    if (fd < 0)
 	goto bail;
-    }
-
-    /* Write it the first time */
-    if (xpwrite(fd, boot_image, boot_image_len, 0) != boot_image_len ||
-	xpwrite(fd, syslinux_adv, 2 * ADV_SIZE,
-		boot_image_len) != 2 * ADV_SIZE) {
-	fprintf(stderr, "%s: write failure on %s\n", program, file);
-	goto bail;
-    }
-
-    /* Map the file, and patch the initial sector accordingly */
-    modbytes = patch_file_and_bootblock(fd, path, devfd);
-
-    /* Write the patch area again - this relies on the file being
-       overwritten in place! */
-    if (xpwrite(fd, boot_image, modbytes, 0) != modbytes) {
-	fprintf(stderr, "%s: write failure on %s\n", program, file);
-	goto bail;
-    }
 
     /* Attempt to set immutable flag and remove all write access */
     /* Only set immutable flag if file is owned by root */
@@ -515,6 +588,70 @@ int btrfs_install_file(const char *path, int devfd, struct stat *rst)
 }
 
 /*
+ * Due to historical reasons (SGI IRIX's design of disk layouts), the first
+ * sector in the primary AG on XFS filesystems contains the superblock, which is
+ * a problem with bootloaders that rely on BIOSes (that load VBRs which are
+ * (located in the first sector of the partition).
+ *
+ * Thus, we need to handle this issue, otherwise Syslinux will damage the XFS's
+ * superblock.
+ */
+static int xfs_install_file(const char *path, int devfd, struct stat *rst)
+{
+    static char file[PATH_MAX];
+    int dirfd = -1;
+    int fd = -1;
+
+    snprintf(file, PATH_MAX, "%s%sldlinux.sys",
+	     path, path[0] && path[strlen(path) - 1] == '/' ? "" : "/");
+
+    dirfd = open(path, O_RDONLY | O_DIRECTORY);
+    if (dirfd < 0) {
+	perror(path);
+	goto bail;
+    }
+
+    fd = open(file, O_RDONLY);
+    if (fd < 0) {
+	if (errno != ENOENT) {
+	    perror(file);
+	    goto bail;
+	}
+    } else {
+	clear_attributes(fd);
+    }
+
+    close(fd);
+
+    fd = rewrite_boot_image(devfd, file);
+    if (fd < 0)
+	goto bail;
+
+    /* Attempt to set immutable flag and remove all write access */
+    /* Only set immutable flag if file is owned by root */
+    set_attributes(fd);
+
+    if (fstat(fd, rst)) {
+	perror(file);
+	goto bail;
+    }
+
+    close(dirfd);
+    close(fd);
+
+    return 0;
+
+bail:
+    if (dirfd >= 0)
+	close(dirfd);
+
+    if (fd >= 0)
+	close(fd);
+
+    return 1;
+}
+
+/*
  *  * test if path is a subvolume:
  *   * this function return
  *    * 0-> path exists but it is not a subvolume
@@ -748,11 +885,14 @@ static char * get_default_subvol(char * rootdir, char * subvol)
 
 int install_file(const char *path, int devfd, struct stat *rst)
 {
-	if (fs_type == EXT2 || fs_type == VFAT || fs_type == NTFS)
-		return ext2_fat_install_file(path, devfd, rst);
-	else if (fs_type == BTRFS)
-		return btrfs_install_file(path, devfd, rst);
-	return 1;
+    if (fs_type == EXT2 || fs_type == VFAT || fs_type == NTFS)
+	return ext2_fat_install_file(path, devfd, rst);
+    else if (fs_type == BTRFS)
+	return btrfs_install_file(path, devfd, rst);
+    else if (fs_type == XFS)
+	return xfs_install_file(path, devfd, rst);
+
+    return 1;
 }
 
 #ifdef __KLIBC__
@@ -847,14 +987,22 @@ static const char *find_device(const char *mtab_file, dev_t dev)
 	    }
 
 	    break;
+	case XFS:
+	    if (!strcmp(mnt->mnt_type, "xfs") && !stat(mnt->mnt_fsname, &dst) &&
+		dst.st_rdev == dev) {
+		done = true;
+		break;
+	    }
 	case NONE:
 	    break;
 	}
+
 	if (done) {
 	    devname = strdup(mnt->mnt_fsname);
 	    break;
 	}
     }
+
     endmntent(mtab);
 
     return devname;
@@ -1098,6 +1246,7 @@ static int open_device(const char *path, struct stat *st, const char **_devname)
 	fprintf(stderr, "%s: statfs %s: %s\n", program, path, strerror(errno));
 	return -1;
     }
+
     if (sfs.f_type == EXT2_SUPER_MAGIC)
 	fs_type = EXT2;
     else if (sfs.f_type == BTRFS_SUPER_MAGIC)
@@ -1106,10 +1255,13 @@ static int open_device(const char *path, struct stat *st, const char **_devname)
 	fs_type = VFAT;
     else if (sfs.f_type == NTFS_SB_MAGIC ||
                 sfs.f_type == FUSE_SUPER_MAGIC /* ntfs-3g */)
-        fs_type = NTFS;
+	fs_type = NTFS;
+    else if (sfs.f_type == XFS_SUPER_MAGIC)
+	fs_type = XFS;
 
     if (!fs_type) {
-	fprintf(stderr, "%s: not a fat, ntfs, ext2/3/4 or btrfs filesystem: %s\n",
+	fprintf(stderr,
+		"%s: not a fat, ntfs, ext2/3/4, btrfs or xfs filesystem: %s\n",
 		program, path);
 	return -1;
     }
@@ -1143,6 +1295,16 @@ static int btrfs_read_adv(int devfd)
     return syslinux_validate_adv(syslinux_adv) ? 1 : 0;
 }
 
+static inline int xfs_read_adv(int devfd)
+{
+    const size_t adv_size = 2 * ADV_SIZE;
+
+    if (xpread(devfd, syslinux_adv, adv_size, boot_image_len) != adv_size)
+	return -1;
+
+    return syslinux_validate_adv(syslinux_adv) ? 1 : 0;
+}
+
 static int ext_read_adv(const char *path, int devfd, const char **namep)
 {
     int err;
@@ -1151,6 +1313,9 @@ static int ext_read_adv(const char *path, int devfd, const char **namep)
     if (fs_type == BTRFS) {
 	/* btrfs "ldlinux.sys" is in 64k blank area */
 	return btrfs_read_adv(devfd);
+    } else if (fs_type == XFS) {
+	/* XFS "ldlinux.sys" is in the first 2048 bytes of the primary AG */
+	return xfs_read_adv(devfd);
     } else {
 	err = read_adv(path, name = "ldlinux.sys");
 	if (err == 2)		/* ldlinux.sys does not exist */
diff --git a/extlinux/misc.h b/extlinux/misc.h
new file mode 100644
index 0000000..7f2f1b3
--- /dev/null
+++ b/extlinux/misc.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2012 Paulo Alcantara <pcacjr at zytor.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef MISC_H_
+#define MISC_H_
+
+/* Return a 64-bit litte-endian value from a given 64-bit big-endian one */
+static inline uint64_t be64_to_cpu(uint64_t val)
+{
+    return (uint64_t)((((uint64_t)val & (uint64_t)0x00000000000000ffULL) << 56) |
+		      (((uint64_t)val & (uint64_t)0x000000000000ff00ULL) << 40) |
+		      (((uint64_t)val & (uint64_t)0x0000000000ff0000ULL) << 24) |
+		      (((uint64_t)val & (uint64_t)0x00000000ff000000ULL) <<  8) |
+		      (((uint64_t)val & (uint64_t)0x000000ff00000000ULL) >>  8) |
+		      (((uint64_t)val & (uint64_t)0x0000ff0000000000ULL) >> 24) |
+		      (((uint64_t)val & (uint64_t)0x00ff000000000000ULL) >> 40) |
+		      (((uint64_t)val & (uint64_t)0xff00000000000000ULL) >> 56));
+}
+
+/* Return a 32-bit litte-endian value from a given 32-bit big-endian one */
+static inline uint32_t be32_to_cpu(uint32_t val)
+{
+    return (uint32_t)((((uint32_t)val & (uint32_t)0x000000ffUL) << 24) |
+		      (((uint32_t)val & (uint32_t)0x0000ff00UL) <<  8) |
+		      (((uint32_t)val & (uint32_t)0x00ff0000UL) >>  8) |
+		      (((uint32_t)val & (uint32_t)0xff000000UL) >> 24));
+}
+
+/* Return a 16-bit litte-endian value from a given 16-bit big-endian one */
+static inline uint16_t be16_to_cpu(uint16_t val)
+{
+    return (uint16_t)((((uint16_t)val & (uint16_t)0x00ffU) << 8) |
+		      (((uint16_t)val & (uint16_t)0xff00U) >> 8));
+}
+
+#endif /* MISC_H_ */
diff --git a/extlinux/xfs.h b/extlinux/xfs.h
new file mode 100644
index 0000000..412c266
--- /dev/null
+++ b/extlinux/xfs.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2012 Paulo Alcantara <pcacjr at zytor.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#ifndef XFS_H_
+#define XFS_H_
+
+#define XFS_SUPER_MAGIC 0x58465342
+
+#endif /* XFS_H_ */
diff --git a/extlinux/xfs_fs.h b/extlinux/xfs_fs.h
new file mode 100644
index 0000000..587820e
--- /dev/null
+++ b/extlinux/xfs_fs.h
@@ -0,0 +1,501 @@
+/*
+ * Taken from Linux kernel tree (linux/fs/xfs)
+ *
+ * Copyright (c) 1995-2005 Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * Copyright (c) 2012 Paulo Alcantara <pcacjr at zytor.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef XFS_FS_H_
+#define XFS_FS_H_
+
+/*
+ * SGI's XFS filesystem's major stuff (constants, structures)
+ */
+
+/*
+ * Direct I/O attribute record used with XFS_IOC_DIOINFO
+ * d_miniosz is the min xfer size, xfer size multiple and file seek offset
+ * alignment.
+ */
+struct dioattr {
+	uint32_t		d_mem;		/* data buffer memory alignment */
+	uint32_t		d_miniosz;	/* min xfer size		*/
+	uint32_t		d_maxiosz;	/* max xfer size		*/
+};
+
+/*
+ * Structure for XFS_IOC_FSGETXATTR[A] and XFS_IOC_FSSETXATTR.
+ */
+struct fsxattr {
+	uint32_t		fsx_xflags;	/* xflags field value (get/set) */
+	uint32_t		fsx_extsize;	/* extsize field value (get/set)*/
+	uint32_t		fsx_nextents;	/* nextents field value (get)	*/
+	uint32_t		fsx_projid;	/* project identifier (get/set) */
+	unsigned char	fsx_pad[12];
+};
+
+/*
+ * Flags for the bs_xflags/fsx_xflags field
+ * There should be a one-to-one correspondence between these flags and the
+ * XFS_DIFLAG_s.
+ */
+#define XFS_XFLAG_REALTIME	0x00000001	/* data in realtime volume */
+#define XFS_XFLAG_PREALLOC	0x00000002	/* preallocated file extents */
+#define XFS_XFLAG_IMMUTABLE	0x00000008	/* file cannot be modified */
+#define XFS_XFLAG_APPEND	0x00000010	/* all writes append */
+#define XFS_XFLAG_SYNC		0x00000020	/* all writes synchronous */
+#define XFS_XFLAG_NOATIME	0x00000040	/* do not update access time */
+#define XFS_XFLAG_NODUMP	0x00000080	/* do not include in backups */
+#define XFS_XFLAG_RTINHERIT	0x00000100	/* create with rt bit set */
+#define XFS_XFLAG_PROJINHERIT	0x00000200	/* create with parents projid */
+#define XFS_XFLAG_NOSYMLINKS	0x00000400	/* disallow symlink creation */
+#define XFS_XFLAG_EXTSIZE	0x00000800	/* extent size allocator hint */
+#define XFS_XFLAG_EXTSZINHERIT	0x00001000	/* inherit inode extent size */
+#define XFS_XFLAG_NODEFRAG	0x00002000  	/* do not defragment */
+#define XFS_XFLAG_FILESTREAM	0x00004000	/* use filestream allocator */
+#define XFS_XFLAG_HASATTR	0x80000000	/* no DIFLAG for this	*/
+
+/*
+ * Structure for XFS_IOC_GETBMAP.
+ * On input, fill in bmv_offset and bmv_length of the first structure
+ * to indicate the area of interest in the file, and bmv_entries with
+ * the number of array elements given back.  The first structure is
+ * updated on return to give the offset and length for the next call.
+ */
+struct getbmap {
+	int64_t		bmv_offset;	/* file offset of segment in blocks */
+	int64_t		bmv_block;	/* starting block (64-bit daddr_t)  */
+	int64_t		bmv_length;	/* length of segment, blocks	    */
+	int32_t		bmv_count;	/* # of entries in array incl. 1st  */
+	int32_t		bmv_entries;	/* # of entries filled in (output)  */
+};
+
+/*
+ *	Structure for XFS_IOC_GETBMAPX.	 Fields bmv_offset through bmv_entries
+ *	are used exactly as in the getbmap structure.  The getbmapx structure
+ *	has additional bmv_iflags and bmv_oflags fields. The bmv_iflags field
+ *	is only used for the first structure.  It contains input flags
+ *	specifying XFS_IOC_GETBMAPX actions.  The bmv_oflags field is filled
+ *	in by the XFS_IOC_GETBMAPX command for each returned structure after
+ *	the first.
+ */
+struct getbmapx {
+	int64_t		bmv_offset;	/* file offset of segment in blocks */
+	int64_t		bmv_block;	/* starting block (64-bit daddr_t)  */
+	int64_t		bmv_length;	/* length of segment, blocks	    */
+	int32_t		bmv_count;	/* # of entries in array incl. 1st  */
+	int32_t		bmv_entries;	/* # of entries filled in (output). */
+	int32_t		bmv_iflags;	/* input flags (1st structure)	    */
+	int32_t		bmv_oflags;	/* output flags (after 1st structure)*/
+	int32_t		bmv_unused1;	/* future use			    */
+	int32_t		bmv_unused2;	/* future use			    */
+};
+
+/*	bmv_iflags values - set by XFS_IOC_GETBMAPX caller.	*/
+#define BMV_IF_ATTRFORK		0x1	/* return attr fork rather than data */
+#define BMV_IF_NO_DMAPI_READ	0x2	/* Do not generate DMAPI read event  */
+#define BMV_IF_PREALLOC		0x4	/* rtn status BMV_OF_PREALLOC if req */
+#define BMV_IF_DELALLOC		0x8	/* rtn status BMV_OF_DELALLOC if req */
+#define BMV_IF_NO_HOLES		0x10	/* Do not return holes */
+#define BMV_IF_VALID	\
+	(BMV_IF_ATTRFORK|BMV_IF_NO_DMAPI_READ|BMV_IF_PREALLOC|	\
+	 BMV_IF_DELALLOC|BMV_IF_NO_HOLES)
+
+/*	bmv_oflags values - returned for each non-header segment */
+#define BMV_OF_PREALLOC		0x1	/* segment = unwritten pre-allocation */
+#define BMV_OF_DELALLOC		0x2	/* segment = delayed allocation */
+#define BMV_OF_LAST		0x4	/* segment is the last in the file */
+
+/*
+ * Structure for XFS_IOC_FSSETDM.
+ * For use by backup and restore programs to set the XFS on-disk inode
+ * fields di_dmevmask and di_dmstate.  These must be set to exactly and
+ * only values previously obtained via xfs_bulkstat!  (Specifically the
+ * xfs_bstat_t fields bs_dmevmask and bs_dmstate.)
+ */
+struct fsdmidata {
+	uint32_t		fsd_dmevmask;	/* corresponds to di_dmevmask */
+	__u16		fsd_padding;
+	__u16		fsd_dmstate;	/* corresponds to di_dmstate  */
+};
+
+/*
+ * File segment locking set data type for 64 bit access.
+ * Also used for all the RESV/FREE interfaces.
+ */
+typedef struct xfs_flock64 {
+	__s16		l_type;
+	__s16		l_whence;
+	int64_t		l_start;
+	int64_t		l_len;		/* len == 0 means until end of file */
+	int32_t		l_sysid;
+	uint32_t		l_pid;
+	int32_t		l_pad[4];	/* reserve area			    */
+} xfs_flock64_t;
+
+/*
+ * Output for XFS_IOC_FSGEOMETRY_V1
+ */
+typedef struct xfs_fsop_geom_v1 {
+	uint32_t		blocksize;	/* filesystem (data) block size */
+	uint32_t		rtextsize;	/* realtime extent size		*/
+	uint32_t		agblocks;	/* fsblocks in an AG		*/
+	uint32_t		agcount;	/* number of allocation groups	*/
+	uint32_t		logblocks;	/* fsblocks in the log		*/
+	uint32_t		sectsize;	/* (data) sector size, bytes	*/
+	uint32_t		inodesize;	/* inode size in bytes		*/
+	uint32_t		imaxpct;	/* max allowed inode space(%)	*/
+	uint64_t		datablocks;	/* fsblocks in data subvolume	*/
+	uint64_t		rtblocks;	/* fsblocks in realtime subvol	*/
+	uint64_t		rtextents;	/* rt extents in realtime subvol*/
+	uint64_t		logstart;	/* starting fsblock of the log	*/
+	unsigned char	uuid[16];	/* unique id of the filesystem	*/
+	uint32_t		sunit;		/* stripe unit, fsblocks	*/
+	uint32_t		swidth;		/* stripe width, fsblocks	*/
+	int32_t		version;	/* structure version		*/
+	uint32_t		flags;		/* superblock version flags	*/
+	uint32_t		logsectsize;	/* log sector size, bytes	*/
+	uint32_t		rtsectsize;	/* realtime sector size, bytes	*/
+	uint32_t		dirblocksize;	/* directory block size, bytes	*/
+} xfs_fsop_geom_v1_t;
+
+/*
+ * Output for XFS_IOC_FSGEOMETRY
+ */
+typedef struct xfs_fsop_geom {
+	uint32_t		blocksize;	/* filesystem (data) block size */
+	uint32_t		rtextsize;	/* realtime extent size		*/
+	uint32_t		agblocks;	/* fsblocks in an AG		*/
+	uint32_t		agcount;	/* number of allocation groups	*/
+	uint32_t		logblocks;	/* fsblocks in the log		*/
+	uint32_t		sectsize;	/* (data) sector size, bytes	*/
+	uint32_t		inodesize;	/* inode size in bytes		*/
+	uint32_t		imaxpct;	/* max allowed inode space(%)	*/
+	uint64_t		datablocks;	/* fsblocks in data subvolume	*/
+	uint64_t		rtblocks;	/* fsblocks in realtime subvol	*/
+	uint64_t		rtextents;	/* rt extents in realtime subvol*/
+	uint64_t		logstart;	/* starting fsblock of the log	*/
+	unsigned char	uuid[16];	/* unique id of the filesystem	*/
+	uint32_t		sunit;		/* stripe unit, fsblocks	*/
+	uint32_t		swidth;		/* stripe width, fsblocks	*/
+	int32_t		version;	/* structure version		*/
+	uint32_t		flags;		/* superblock version flags	*/
+	uint32_t		logsectsize;	/* log sector size, bytes	*/
+	uint32_t		rtsectsize;	/* realtime sector size, bytes	*/
+	uint32_t		dirblocksize;	/* directory block size, bytes	*/
+	uint32_t		logsunit;	/* log stripe unit, bytes */
+} xfs_fsop_geom_t;
+
+/* Output for XFS_FS_COUNTS */
+typedef struct xfs_fsop_counts {
+	uint64_t	freedata;	/* free data section blocks */
+	uint64_t	freertx;	/* free rt extents */
+	uint64_t	freeino;	/* free inodes */
+	uint64_t	allocino;	/* total allocated inodes */
+} xfs_fsop_counts_t;
+
+/* Input/Output for XFS_GET_RESBLKS and XFS_SET_RESBLKS */
+typedef struct xfs_fsop_resblks {
+	uint64_t  resblks;
+	uint64_t  resblks_avail;
+} xfs_fsop_resblks_t;
+
+#define XFS_FSOP_GEOM_VERSION	0
+
+#define XFS_FSOP_GEOM_FLAGS_ATTR	0x0001	/* attributes in use	*/
+#define XFS_FSOP_GEOM_FLAGS_NLINK	0x0002	/* 32-bit nlink values	*/
+#define XFS_FSOP_GEOM_FLAGS_QUOTA	0x0004	/* quotas enabled	*/
+#define XFS_FSOP_GEOM_FLAGS_IALIGN	0x0008	/* inode alignment	*/
+#define XFS_FSOP_GEOM_FLAGS_DALIGN	0x0010	/* large data alignment */
+#define XFS_FSOP_GEOM_FLAGS_SHARED	0x0020	/* read-only shared	*/
+#define XFS_FSOP_GEOM_FLAGS_EXTFLG	0x0040	/* special extent flag	*/
+#define XFS_FSOP_GEOM_FLAGS_DIRV2	0x0080	/* directory version 2	*/
+#define XFS_FSOP_GEOM_FLAGS_LOGV2	0x0100	/* log format version 2	*/
+#define XFS_FSOP_GEOM_FLAGS_SECTOR	0x0200	/* sector sizes >1BB	*/
+#define XFS_FSOP_GEOM_FLAGS_ATTR2	0x0400	/* inline attributes rework */
+#define XFS_FSOP_GEOM_FLAGS_DIRV2CI	0x1000	/* ASCII only CI names */
+#define XFS_FSOP_GEOM_FLAGS_LAZYSB	0x4000	/* lazy superblock counters */
+
+
+/*
+ * Minimum and maximum sizes need for growth checks
+ */
+#define XFS_MIN_AG_BLOCKS	64
+#define XFS_MIN_LOG_BLOCKS	512ULL
+#define XFS_MAX_LOG_BLOCKS	(1024 * 1024ULL)
+#define XFS_MIN_LOG_BYTES	(10 * 1024 * 1024ULL)
+
+/* keep the maximum size under 2^31 by a small amount */
+#define XFS_MAX_LOG_BYTES \
+	((2 * 1024 * 1024 * 1024ULL) - XFS_MIN_LOG_BYTES)
+
+/* Used for sanity checks on superblock */
+#define XFS_MAX_DBLOCKS(s) ((xfs_drfsbno_t)(s)->sb_agcount * (s)->sb_agblocks)
+#define XFS_MIN_DBLOCKS(s) ((xfs_drfsbno_t)((s)->sb_agcount - 1) *	\
+			 (s)->sb_agblocks + XFS_MIN_AG_BLOCKS)
+
+/*
+ * Structures for XFS_IOC_FSGROWFSDATA, XFS_IOC_FSGROWFSLOG & XFS_IOC_FSGROWFSRT
+ */
+typedef struct xfs_growfs_data {
+	uint64_t		newblocks;	/* new data subvol size, fsblocks */
+	uint32_t		imaxpct;	/* new inode space percentage limit */
+} xfs_growfs_data_t;
+
+typedef struct xfs_growfs_log {
+	uint32_t		newblocks;	/* new log size, fsblocks */
+	uint32_t		isint;		/* 1 if new log is internal */
+} xfs_growfs_log_t;
+
+typedef struct xfs_growfs_rt {
+	uint64_t		newblocks;	/* new realtime size, fsblocks */
+	uint32_t		extsize;	/* new realtime extent size, fsblocks */
+} xfs_growfs_rt_t;
+
+
+/*
+ * Structures returned from ioctl XFS_IOC_FSBULKSTAT & XFS_IOC_FSBULKSTAT_SINGLE
+ */
+typedef struct xfs_bstime {
+	time_t		tv_sec;		/* seconds		*/
+	int32_t		tv_nsec;	/* and nanoseconds	*/
+} xfs_bstime_t;
+
+typedef struct xfs_bstat {
+	uint64_t		bs_ino;		/* inode number			*/
+	__u16		bs_mode;	/* type and mode		*/
+	__u16		bs_nlink;	/* number of links		*/
+	uint32_t		bs_uid;		/* user id			*/
+	uint32_t		bs_gid;		/* group id			*/
+	uint32_t		bs_rdev;	/* device value			*/
+	int32_t		bs_blksize;	/* block size			*/
+	int64_t		bs_size;	/* file size			*/
+	xfs_bstime_t	bs_atime;	/* access time			*/
+	xfs_bstime_t	bs_mtime;	/* modify time			*/
+	xfs_bstime_t	bs_ctime;	/* inode change time		*/
+	int64_t		bs_blocks;	/* number of blocks		*/
+	uint32_t		bs_xflags;	/* extended flags		*/
+	int32_t		bs_extsize;	/* extent size			*/
+	int32_t		bs_extents;	/* number of extents		*/
+	uint32_t		bs_gen;		/* generation count		*/
+	__u16		bs_projid_lo;	/* lower part of project id	*/
+#define	bs_projid	bs_projid_lo	/* (previously just bs_projid)	*/
+	__u16		bs_forkoff;	/* inode fork offset in bytes	*/
+	__u16		bs_projid_hi;	/* higher part of project id	*/
+	unsigned char	bs_pad[10];	/* pad space, unused		*/
+	uint32_t		bs_dmevmask;	/* DMIG event mask		*/
+	__u16		bs_dmstate;	/* DMIG state info		*/
+	__u16		bs_aextents;	/* attribute number of extents	*/
+} xfs_bstat_t;
+
+/*
+ * The user-level BulkStat Request interface structure.
+ */
+typedef struct xfs_fsop_bulkreq {
+	uint64_t		__user *lastip;	/* last inode # pointer		*/
+	int32_t		icount;		/* count of entries in buffer	*/
+	void		__user *ubuffer;/* user buffer for inode desc.	*/
+	int32_t		__user *ocount;	/* output count pointer		*/
+} xfs_fsop_bulkreq_t;
+
+
+/*
+ * Structures returned from xfs_inumbers routine (XFS_IOC_FSINUMBERS).
+ */
+typedef struct xfs_inogrp {
+	uint64_t		xi_startino;	/* starting inode number	*/
+	int32_t		xi_alloccount;	/* # bits set in allocmask	*/
+	uint64_t		xi_allocmask;	/* mask of allocated inodes	*/
+} xfs_inogrp_t;
+
+
+/*
+ * Error injection.
+ */
+typedef struct xfs_error_injection {
+	int32_t		fd;
+	int32_t		errtag;
+} xfs_error_injection_t;
+
+
+/*
+ * The user-level Handle Request interface structure.
+ */
+typedef struct xfs_fsop_handlereq {
+	uint32_t		fd;		/* fd for FD_TO_HANDLE		*/
+	void		__user *path;	/* user pathname		*/
+	uint32_t		oflags;		/* open flags			*/
+	void		__user *ihandle;/* user supplied handle		*/
+	uint32_t		ihandlen;	/* user supplied length		*/
+	void		__user *ohandle;/* user buffer for handle	*/
+	uint32_t		__user *ohandlen;/* user buffer length		*/
+} xfs_fsop_handlereq_t;
+
+/*
+ * Compound structures for passing args through Handle Request interfaces
+ * xfs_fssetdm_by_handle, xfs_attrlist_by_handle, xfs_attrmulti_by_handle
+ * - ioctls: XFS_IOC_FSSETDM_BY_HANDLE, XFS_IOC_ATTRLIST_BY_HANDLE, and
+ *	     XFS_IOC_ATTRMULTI_BY_HANDLE
+ */
+
+typedef struct xfs_fsop_setdm_handlereq {
+	struct xfs_fsop_handlereq	hreq;	/* handle information	*/
+	struct fsdmidata		__user *data;	/* DMAPI data	*/
+} xfs_fsop_setdm_handlereq_t;
+
+typedef struct xfs_attrlist_cursor {
+	uint32_t		opaque[4];
+} xfs_attrlist_cursor_t;
+
+typedef struct xfs_fsop_attrlist_handlereq {
+	struct xfs_fsop_handlereq	hreq; /* handle interface structure */
+	struct xfs_attrlist_cursor	pos; /* opaque cookie, list offset */
+	uint32_t				flags;	/* which namespace to use */
+	uint32_t				buflen;	/* length of buffer supplied */
+	void				__user *buffer;	/* returned names */
+} xfs_fsop_attrlist_handlereq_t;
+
+typedef struct xfs_attr_multiop {
+	uint32_t		am_opcode;
+#define ATTR_OP_GET	1	/* return the indicated attr's value */
+#define ATTR_OP_SET	2	/* set/create the indicated attr/value pair */
+#define ATTR_OP_REMOVE	3	/* remove the indicated attr */
+	int32_t		am_error;
+	void		__user *am_attrname;
+	void		__user *am_attrvalue;
+	uint32_t		am_length;
+	uint32_t		am_flags;
+} xfs_attr_multiop_t;
+
+typedef struct xfs_fsop_attrmulti_handlereq {
+	struct xfs_fsop_handlereq	hreq; /* handle interface structure */
+	uint32_t				opcount;/* count of following multiop */
+	struct xfs_attr_multiop		__user *ops; /* attr_multi data */
+} xfs_fsop_attrmulti_handlereq_t;
+
+/*
+ * per machine unique filesystem identifier types.
+ */
+typedef struct { uint32_t val[2]; } xfs_fsid_t; /* file system id type */
+
+typedef struct xfs_fid {
+	__u16	fid_len;		/* length of remainder	*/
+	__u16	fid_pad;
+	uint32_t	fid_gen;		/* generation number	*/
+	uint64_t	fid_ino;		/* 64 bits inode number */
+} xfs_fid_t;
+
+typedef struct xfs_handle {
+	union {
+		int64_t	    align;	/* force alignment of ha_fid	 */
+		xfs_fsid_t  _ha_fsid;	/* unique file system identifier */
+	} ha_u;
+	xfs_fid_t	ha_fid;		/* file system specific file ID	 */
+} xfs_handle_t;
+#define ha_fsid ha_u._ha_fsid
+
+#define XFS_HSIZE(handle)	(((char *) &(handle).ha_fid.fid_pad	 \
+				 - (char *) &(handle))			  \
+				 + (handle).ha_fid.fid_len)
+
+/*
+ * Flags for going down operation
+ */
+#define XFS_FSOP_GOING_FLAGS_DEFAULT		0x0	/* going down */
+#define XFS_FSOP_GOING_FLAGS_LOGFLUSH		0x1	/* flush log but not data */
+#define XFS_FSOP_GOING_FLAGS_NOLOGFLUSH		0x2	/* don't flush log nor data */
+
+/*
+ * ioctl commands that are used by Linux filesystems
+ */
+#define XFS_IOC_GETXFLAGS	FS_IOC_GETFLAGS
+#define XFS_IOC_SETXFLAGS	FS_IOC_SETFLAGS
+#define XFS_IOC_GETVERSION	FS_IOC_GETVERSION
+
+/*
+ * ioctl commands that replace IRIX fcntl()'s
+ * For 'documentation' purposed more than anything else,
+ * the "cmd #" field reflects the IRIX fcntl number.
+ */
+#define XFS_IOC_ALLOCSP		_IOW ('X', 10, struct xfs_flock64)
+#define XFS_IOC_FREESP		_IOW ('X', 11, struct xfs_flock64)
+#define XFS_IOC_DIOINFO		_IOR ('X', 30, struct dioattr)
+#define XFS_IOC_FSGETXATTR	_IOR ('X', 31, struct fsxattr)
+#define XFS_IOC_FSSETXATTR	_IOW ('X', 32, struct fsxattr)
+#define XFS_IOC_ALLOCSP64	_IOW ('X', 36, struct xfs_flock64)
+#define XFS_IOC_FREESP64	_IOW ('X', 37, struct xfs_flock64)
+#define XFS_IOC_GETBMAP		_IOWR('X', 38, struct getbmap)
+#define XFS_IOC_FSSETDM		_IOW ('X', 39, struct fsdmidata)
+#define XFS_IOC_RESVSP		_IOW ('X', 40, struct xfs_flock64)
+#define XFS_IOC_UNRESVSP	_IOW ('X', 41, struct xfs_flock64)
+#define XFS_IOC_RESVSP64	_IOW ('X', 42, struct xfs_flock64)
+#define XFS_IOC_UNRESVSP64	_IOW ('X', 43, struct xfs_flock64)
+#define XFS_IOC_GETBMAPA	_IOWR('X', 44, struct getbmap)
+#define XFS_IOC_FSGETXATTRA	_IOR ('X', 45, struct fsxattr)
+/*	XFS_IOC_SETBIOSIZE ---- deprecated 46	   */
+/*	XFS_IOC_GETBIOSIZE ---- deprecated 47	   */
+#define XFS_IOC_GETBMAPX	_IOWR('X', 56, struct getbmap)
+#define XFS_IOC_ZERO_RANGE	_IOW ('X', 57, struct xfs_flock64)
+
+/*
+ * ioctl commands that replace IRIX syssgi()'s
+ */
+#define XFS_IOC_FSGEOMETRY_V1	     _IOR ('X', 100, struct xfs_fsop_geom_v1)
+#define XFS_IOC_FSBULKSTAT	     _IOWR('X', 101, struct xfs_fsop_bulkreq)
+#define XFS_IOC_FSBULKSTAT_SINGLE    _IOWR('X', 102, struct xfs_fsop_bulkreq)
+#define XFS_IOC_FSINUMBERS	     _IOWR('X', 103, struct xfs_fsop_bulkreq)
+#define XFS_IOC_PATH_TO_FSHANDLE     _IOWR('X', 104, struct xfs_fsop_handlereq)
+#define XFS_IOC_PATH_TO_HANDLE	     _IOWR('X', 105, struct xfs_fsop_handlereq)
+#define XFS_IOC_FD_TO_HANDLE	     _IOWR('X', 106, struct xfs_fsop_handlereq)
+#define XFS_IOC_OPEN_BY_HANDLE	     _IOWR('X', 107, struct xfs_fsop_handlereq)
+#define XFS_IOC_READLINK_BY_HANDLE   _IOWR('X', 108, struct xfs_fsop_handlereq)
+#define XFS_IOC_SWAPEXT		     _IOWR('X', 109, struct xfs_swapext)
+#define XFS_IOC_FSGROWFSDATA	     _IOW ('X', 110, struct xfs_growfs_data)
+#define XFS_IOC_FSGROWFSLOG	     _IOW ('X', 111, struct xfs_growfs_log)
+#define XFS_IOC_FSGROWFSRT	     _IOW ('X', 112, struct xfs_growfs_rt)
+#define XFS_IOC_FSCOUNTS	     _IOR ('X', 113, struct xfs_fsop_counts)
+#define XFS_IOC_SET_RESBLKS	     _IOWR('X', 114, struct xfs_fsop_resblks)
+#define XFS_IOC_GET_RESBLKS	     _IOR ('X', 115, struct xfs_fsop_resblks)
+#define XFS_IOC_ERROR_INJECTION	     _IOW ('X', 116, struct xfs_error_injection)
+#define XFS_IOC_ERROR_CLEARALL	     _IOW ('X', 117, struct xfs_error_injection)
+/*	XFS_IOC_ATTRCTL_BY_HANDLE -- deprecated 118	 */
+/*	XFS_IOC_FREEZE		  -- FIFREEZE   119	 */
+/*	XFS_IOC_THAW		  -- FITHAW     120	 */
+#define XFS_IOC_FSSETDM_BY_HANDLE    _IOW ('X', 121, struct xfs_fsop_setdm_handlereq)
+#define XFS_IOC_ATTRLIST_BY_HANDLE   _IOW ('X', 122, struct xfs_fsop_attrlist_handlereq)
+#define XFS_IOC_ATTRMULTI_BY_HANDLE  _IOW ('X', 123, struct xfs_fsop_attrmulti_handlereq)
+#define XFS_IOC_FSGEOMETRY	     _IOR ('X', 124, struct xfs_fsop_geom)
+#define XFS_IOC_GOINGDOWN	     _IOR ('X', 125, __uint32_t)
+/*	XFS_IOC_GETFSUUID ---------- deprecated 140	 */
+
+
+#ifndef HAVE_BBMACROS
+/*
+ * Block I/O parameterization.	A basic block (BB) is the lowest size of
+ * filesystem allocation, and must equal 512.  Length units given to bio
+ * routines are in BB's.
+ */
+#define BBSHIFT		9
+#define BBSIZE		(1<<BBSHIFT)
+#define BBMASK		(BBSIZE-1)
+#define BTOBB(bytes)	(((uint64_t)(bytes) + BBSIZE - 1) >> BBSHIFT)
+#define BTOBBT(bytes)	((uint64_t)(bytes) >> BBSHIFT)
+#define BBTOB(bbs)	((bbs) << BBSHIFT)
+#endif
+
+#endif	/* XFS_FS_H_ */
diff --git a/extlinux/xfs_sb.h b/extlinux/xfs_sb.h
new file mode 100644
index 0000000..8f72d6a
--- /dev/null
+++ b/extlinux/xfs_sb.h
@@ -0,0 +1,476 @@
+/*
+ * Taken from Linux kernel tree (linux/fs/xfs)
+ *
+ * Copyright (c) 2000-2005 Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * Copyright (c) 2012 Paulo Alcantara <pcacjr at zytor.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+#ifndef XFS_SB_H_
+#define	XFS_SB_H__
+
+#include <stddef.h>
+
+#include <sys/types.h>
+#include <uuid/uuid.h>
+
+/*
+ * Super block
+ * Fits into a sector-sized buffer at address 0 of each allocation group.
+ * Only the first of these is ever updated except during growfs.
+ */
+
+struct xfs_buf;
+struct xfs_mount;
+
+#define	XFS_SB_MAGIC		"XFSB"		/* '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_NUMBITS		0x000f
+#define	XFS_SB_VERSION_ALLFBITS		0xfff0
+#define	XFS_SB_VERSION_SASHFBITS	0xf000
+#define	XFS_SB_VERSION_REALFBITS	0x0ff0
+#define	XFS_SB_VERSION_ATTRBIT		0x0010
+#define	XFS_SB_VERSION_NLINKBIT		0x0020
+#define	XFS_SB_VERSION_QUOTABIT		0x0040
+#define	XFS_SB_VERSION_ALIGNBIT		0x0080
+#define	XFS_SB_VERSION_DALIGNBIT	0x0100
+#define	XFS_SB_VERSION_SHAREDBIT	0x0200
+#define XFS_SB_VERSION_LOGV2BIT		0x0400
+#define XFS_SB_VERSION_SECTORBIT	0x0800
+#define	XFS_SB_VERSION_EXTFLGBIT	0x1000
+#define	XFS_SB_VERSION_DIRV2BIT		0x2000
+#define	XFS_SB_VERSION_BORGBIT		0x4000	/* ASCII only case-insens. */
+#define	XFS_SB_VERSION_MOREBITSBIT	0x8000
+#define	XFS_SB_VERSION_OKSASHFBITS	\
+	(XFS_SB_VERSION_EXTFLGBIT | \
+	 XFS_SB_VERSION_DIRV2BIT | \
+	 XFS_SB_VERSION_BORGBIT)
+#define	XFS_SB_VERSION_OKREALFBITS	\
+	(XFS_SB_VERSION_ATTRBIT | \
+	 XFS_SB_VERSION_NLINKBIT | \
+	 XFS_SB_VERSION_QUOTABIT | \
+	 XFS_SB_VERSION_ALIGNBIT | \
+	 XFS_SB_VERSION_DALIGNBIT | \
+	 XFS_SB_VERSION_SHAREDBIT | \
+	 XFS_SB_VERSION_LOGV2BIT | \
+	 XFS_SB_VERSION_SECTORBIT | \
+	 XFS_SB_VERSION_MOREBITSBIT)
+#define	XFS_SB_VERSION_OKREALBITS	\
+	(XFS_SB_VERSION_NUMBITS | \
+	 XFS_SB_VERSION_OKREALFBITS | \
+	 XFS_SB_VERSION_OKSASHFBITS)
+
+/*
+ * There are two words to hold XFS "feature" bits: the original
+ * word, sb_versionnum, and sb_features2.  Whenever a bit is set in
+ * sb_features2, the feature bit XFS_SB_VERSION_MOREBITSBIT must be set.
+ *
+ * These defines represent bits in sb_features2.
+ */
+#define XFS_SB_VERSION2_REALFBITS	0x00ffffff	/* Mask: features */
+#define XFS_SB_VERSION2_RESERVED1BIT	0x00000001
+#define XFS_SB_VERSION2_LAZYSBCOUNTBIT	0x00000002	/* Superblk counters */
+#define XFS_SB_VERSION2_RESERVED4BIT	0x00000004
+#define XFS_SB_VERSION2_ATTR2BIT	0x00000008	/* Inline attr rework */
+#define XFS_SB_VERSION2_PARENTBIT	0x00000010	/* parent pointers */
+#define XFS_SB_VERSION2_PROJID32BIT	0x00000080	/* 32 bit project id */
+
+#define	XFS_SB_VERSION2_OKREALFBITS	\
+	(XFS_SB_VERSION2_LAZYSBCOUNTBIT	| \
+	 XFS_SB_VERSION2_ATTR2BIT	| \
+	 XFS_SB_VERSION2_PROJID32BIT)
+#define	XFS_SB_VERSION2_OKSASHFBITS	\
+	(0)
+#define XFS_SB_VERSION2_OKREALBITS	\
+	(XFS_SB_VERSION2_OKREALFBITS |	\
+	 XFS_SB_VERSION2_OKSASHFBITS )
+
+/*
+ * Superblock - in core version.  Must match the ondisk version below.
+ * Must be padded to 64 bit alignment.
+ */
+typedef struct xfs_sb {
+	uint32_t	sb_magicnum;	/* magic number == XFS_SB_MAGIC */
+	uint32_t	sb_blocksize;	/* logical block size, bytes */
+	xfs_drfsbno_t	sb_dblocks;	/* number of data blocks */
+	xfs_drfsbno_t	sb_rblocks;	/* number of realtime blocks */
+	xfs_drtbno_t	sb_rextents;	/* number of realtime extents */
+	uuid_t		sb_uuid;	/* file system unique id */
+	xfs_dfsbno_t	sb_logstart;	/* starting block of log if internal */
+	xfs_ino_t	sb_rootino;	/* root inode number */
+	xfs_ino_t	sb_rbmino;	/* bitmap inode for realtime extents */
+	xfs_ino_t	sb_rsumino;	/* summary inode for rt bitmap */
+	xfs_agblock_t	sb_rextsize;	/* realtime extent size, blocks */
+	xfs_agblock_t	sb_agblocks;	/* size of an allocation group */
+	xfs_agnumber_t	sb_agcount;	/* number of allocation groups */
+	xfs_extlen_t	sb_rbmblocks;	/* number of rt bitmap blocks */
+	xfs_extlen_t	sb_logblocks;	/* number of log blocks */
+	uint16_t	sb_versionnum;	/* header version == XFS_SB_VERSION */
+	uint16_t	sb_sectsize;	/* volume sector size, bytes */
+	uint16_t	sb_inodesize;	/* inode size, bytes */
+	uint16_t	sb_inopblock;	/* inodes per block */
+	char		sb_fname[12];	/* file system name */
+	uint8_t	sb_blocklog;	/* log2 of sb_blocksize */
+	uint8_t	sb_sectlog;	/* log2 of sb_sectsize */
+	uint8_t	sb_inodelog;	/* log2 of sb_inodesize */
+	uint8_t	sb_inopblog;	/* log2 of sb_inopblock */
+	uint8_t	sb_agblklog;	/* log2 of sb_agblocks (rounded up) */
+	uint8_t	sb_rextslog;	/* log2 of sb_rextents */
+	uint8_t	sb_inprogress;	/* mkfs is in progress, don't mount */
+	uint8_t	sb_imax_pct;	/* max % of fs for inode space */
+					/* statistics */
+	/*
+	 * These fields must remain contiguous.  If you really
+	 * want to change their layout, make sure you fix the
+	 * code in xfs_trans_apply_sb_deltas().
+	 */
+	uint64_t	sb_icount;	/* allocated inodes */
+	uint64_t	sb_ifree;	/* free inodes */
+	uint64_t	sb_fdblocks;	/* free data blocks */
+	uint64_t	sb_frextents;	/* free realtime extents */
+	/*
+	 * End contiguous fields.
+	 */
+	xfs_ino_t	sb_uquotino;	/* user quota inode */
+	xfs_ino_t	sb_gquotino;	/* group quota inode */
+	uint16_t	sb_qflags;	/* quota flags */
+	uint8_t	sb_flags;	/* misc. flags */
+	uint8_t	sb_shared_vn;	/* shared version number */
+	xfs_extlen_t	sb_inoalignmt;	/* inode chunk alignment, fsblocks */
+	uint32_t	sb_unit;	/* stripe or raid unit */
+	uint32_t	sb_width;	/* stripe or raid width */
+	uint8_t	sb_dirblklog;	/* log2 of dir block size (fsbs) */
+	uint8_t	sb_logsectlog;	/* log2 of the log sector size */
+	uint16_t	sb_logsectsize;	/* sector size for the log, bytes */
+	uint32_t	sb_logsunit;	/* stripe unit size for the log */
+	uint32_t	sb_features2;	/* additional feature bits */
+
+	/*
+	 * bad features2 field as a result of failing to pad the sb
+	 * structure to 64 bits. Some machines will be using this field
+	 * for features2 bits. Easiest just to mark it bad and not use
+	 * it for anything else.
+	 */
+	uint32_t	sb_bad_features2;
+
+	/* must be padded to 64 bit alignment */
+} xfs_sb_t;
+
+/*
+ * Sequence number values for the fields.
+ */
+typedef enum {
+	XFS_SBS_MAGICNUM, XFS_SBS_BLOCKSIZE, XFS_SBS_DBLOCKS, XFS_SBS_RBLOCKS,
+	XFS_SBS_REXTENTS, XFS_SBS_UUID, XFS_SBS_LOGSTART, XFS_SBS_ROOTINO,
+	XFS_SBS_RBMINO, XFS_SBS_RSUMINO, XFS_SBS_REXTSIZE, XFS_SBS_AGBLOCKS,
+	XFS_SBS_AGCOUNT, XFS_SBS_RBMBLOCKS, XFS_SBS_LOGBLOCKS,
+	XFS_SBS_VERSIONNUM, XFS_SBS_SECTSIZE, XFS_SBS_INODESIZE,
+	XFS_SBS_INOPBLOCK, XFS_SBS_FNAME, XFS_SBS_BLOCKLOG,
+	XFS_SBS_SECTLOG, XFS_SBS_INODELOG, XFS_SBS_INOPBLOG, XFS_SBS_AGBLKLOG,
+	XFS_SBS_REXTSLOG, XFS_SBS_INPROGRESS, XFS_SBS_IMAX_PCT, XFS_SBS_ICOUNT,
+	XFS_SBS_IFREE, XFS_SBS_FDBLOCKS, XFS_SBS_FREXTENTS, XFS_SBS_UQUOTINO,
+	XFS_SBS_GQUOTINO, XFS_SBS_QFLAGS, XFS_SBS_FLAGS, XFS_SBS_SHARED_VN,
+	XFS_SBS_INOALIGNMT, XFS_SBS_UNIT, XFS_SBS_WIDTH, XFS_SBS_DIRBLKLOG,
+	XFS_SBS_LOGSECTLOG, XFS_SBS_LOGSECTSIZE, XFS_SBS_LOGSUNIT,
+	XFS_SBS_FEATURES2, XFS_SBS_BAD_FEATURES2,
+	XFS_SBS_FIELDCOUNT
+} xfs_sb_field_t;
+
+/*
+ * Mask values, defined based on the xfs_sb_field_t values.
+ * Only define the ones we're using.
+ */
+#define	XFS_SB_MVAL(x)		(1LL << XFS_SBS_ ## x)
+#define	XFS_SB_UUID		XFS_SB_MVAL(UUID)
+#define	XFS_SB_FNAME		XFS_SB_MVAL(FNAME)
+#define	XFS_SB_ROOTINO		XFS_SB_MVAL(ROOTINO)
+#define	XFS_SB_RBMINO		XFS_SB_MVAL(RBMINO)
+#define	XFS_SB_RSUMINO		XFS_SB_MVAL(RSUMINO)
+#define	XFS_SB_VERSIONNUM	XFS_SB_MVAL(VERSIONNUM)
+#define XFS_SB_UQUOTINO		XFS_SB_MVAL(UQUOTINO)
+#define XFS_SB_GQUOTINO		XFS_SB_MVAL(GQUOTINO)
+#define XFS_SB_QFLAGS		XFS_SB_MVAL(QFLAGS)
+#define XFS_SB_SHARED_VN	XFS_SB_MVAL(SHARED_VN)
+#define XFS_SB_UNIT		XFS_SB_MVAL(UNIT)
+#define XFS_SB_WIDTH		XFS_SB_MVAL(WIDTH)
+#define XFS_SB_ICOUNT		XFS_SB_MVAL(ICOUNT)
+#define XFS_SB_IFREE		XFS_SB_MVAL(IFREE)
+#define XFS_SB_FDBLOCKS		XFS_SB_MVAL(FDBLOCKS)
+#define XFS_SB_FEATURES2	XFS_SB_MVAL(FEATURES2)
+#define XFS_SB_BAD_FEATURES2	XFS_SB_MVAL(BAD_FEATURES2)
+#define	XFS_SB_NUM_BITS		((int)XFS_SBS_FIELDCOUNT)
+#define	XFS_SB_ALL_BITS		((1LL << XFS_SB_NUM_BITS) - 1)
+#define	XFS_SB_MOD_BITS		\
+	(XFS_SB_UUID | XFS_SB_ROOTINO | XFS_SB_RBMINO | XFS_SB_RSUMINO | \
+	 XFS_SB_VERSIONNUM | XFS_SB_UQUOTINO | XFS_SB_GQUOTINO | \
+	 XFS_SB_QFLAGS | XFS_SB_SHARED_VN | XFS_SB_UNIT | XFS_SB_WIDTH | \
+	 XFS_SB_ICOUNT | XFS_SB_IFREE | XFS_SB_FDBLOCKS | XFS_SB_FEATURES2 | \
+	 XFS_SB_BAD_FEATURES2)
+
+
+/*
+ * Misc. Flags - warning - these will be cleared by xfs_repair unless
+ * a feature bit is set when the flag is used.
+ */
+#define XFS_SBF_NOFLAGS		0x00	/* no flags set */
+#define XFS_SBF_READONLY	0x01	/* only read-only mounts allowed */
+
+/*
+ * define max. shared version we can interoperate with
+ */
+#define XFS_SB_MAX_SHARED_VN	0
+
+#define	XFS_SB_VERSION_NUM(sbp)	((sbp)->sb_versionnum & XFS_SB_VERSION_NUMBITS)
+
+static inline int xfs_sb_good_version(xfs_sb_t *sbp)
+{
+	/* We always support version 1-3 */
+	if (sbp->sb_versionnum >= XFS_SB_VERSION_1 &&
+	    sbp->sb_versionnum <= XFS_SB_VERSION_3)
+		return 1;
+
+	/* We support version 4 if all feature bits are supported */
+	if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) {
+		if ((sbp->sb_versionnum & ~XFS_SB_VERSION_OKREALBITS) ||
+		    ((sbp->sb_versionnum & XFS_SB_VERSION_MOREBITSBIT) &&
+		     (sbp->sb_features2 & ~XFS_SB_VERSION2_OKREALBITS)))
+			return 0;
+
+		if ((sbp->sb_versionnum & XFS_SB_VERSION_SHAREDBIT) &&
+		    sbp->sb_shared_vn > XFS_SB_MAX_SHARED_VN)
+			return 0;
+
+		return 1;
+	}
+
+	return 0;
+}
+
+/*
+ * Detect a mismatched features2 field.  Older kernels read/wrote
+ * this into the wrong slot, so to be safe we keep them in sync.
+ */
+static inline int xfs_sb_has_mismatched_features2(xfs_sb_t *sbp)
+{
+	return (sbp->sb_bad_features2 != sbp->sb_features2);
+}
+
+static inline unsigned xfs_sb_version_tonew(unsigned v)
+{
+	if (v == XFS_SB_VERSION_1)
+		return XFS_SB_VERSION_4;
+
+	if (v == XFS_SB_VERSION_2)
+		return XFS_SB_VERSION_4 | XFS_SB_VERSION_ATTRBIT;
+
+	return XFS_SB_VERSION_4 | XFS_SB_VERSION_ATTRBIT |
+		XFS_SB_VERSION_NLINKBIT;
+}
+
+static inline unsigned xfs_sb_version_toold(unsigned v)
+{
+	if (v & (XFS_SB_VERSION_QUOTABIT | XFS_SB_VERSION_ALIGNBIT))
+		return 0;
+	if (v & XFS_SB_VERSION_NLINKBIT)
+		return XFS_SB_VERSION_3;
+	if (v & XFS_SB_VERSION_ATTRBIT)
+		return XFS_SB_VERSION_2;
+	return XFS_SB_VERSION_1;
+}
+
+static inline int xfs_sb_version_hasattr(xfs_sb_t *sbp)
+{
+	return sbp->sb_versionnum == XFS_SB_VERSION_2 ||
+		sbp->sb_versionnum == XFS_SB_VERSION_3 ||
+		(XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4 &&
+		 (sbp->sb_versionnum & XFS_SB_VERSION_ATTRBIT));
+}
+
+static inline void xfs_sb_version_addattr(xfs_sb_t *sbp)
+{
+	if (sbp->sb_versionnum == XFS_SB_VERSION_1)
+		sbp->sb_versionnum = XFS_SB_VERSION_2;
+	else if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4)
+		sbp->sb_versionnum |= XFS_SB_VERSION_ATTRBIT;
+	else
+		sbp->sb_versionnum = XFS_SB_VERSION_4 | XFS_SB_VERSION_ATTRBIT;
+}
+
+static inline int xfs_sb_version_hasnlink(xfs_sb_t *sbp)
+{
+	return sbp->sb_versionnum == XFS_SB_VERSION_3 ||
+		 (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4 &&
+		  (sbp->sb_versionnum & XFS_SB_VERSION_NLINKBIT));
+}
+
+static inline void xfs_sb_version_addnlink(xfs_sb_t *sbp)
+{
+	if (sbp->sb_versionnum <= XFS_SB_VERSION_2)
+		sbp->sb_versionnum = XFS_SB_VERSION_3;
+	else
+		sbp->sb_versionnum |= XFS_SB_VERSION_NLINKBIT;
+}
+
+static inline int xfs_sb_version_hasquota(xfs_sb_t *sbp)
+{
+	return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4 &&
+		(sbp->sb_versionnum & XFS_SB_VERSION_QUOTABIT);
+}
+
+static inline void xfs_sb_version_addquota(xfs_sb_t *sbp)
+{
+	if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4)
+		sbp->sb_versionnum |= XFS_SB_VERSION_QUOTABIT;
+	else
+		sbp->sb_versionnum = xfs_sb_version_tonew(sbp->sb_versionnum) |
+					XFS_SB_VERSION_QUOTABIT;
+}
+
+static inline int xfs_sb_version_hasalign(xfs_sb_t *sbp)
+{
+	return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4 &&
+		(sbp->sb_versionnum & XFS_SB_VERSION_ALIGNBIT);
+}
+
+static inline int xfs_sb_version_hasdalign(xfs_sb_t *sbp)
+{
+	return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4 &&
+		(sbp->sb_versionnum & XFS_SB_VERSION_DALIGNBIT);
+}
+
+static inline int xfs_sb_version_hasshared(xfs_sb_t *sbp)
+{
+	return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4 &&
+		(sbp->sb_versionnum & XFS_SB_VERSION_SHAREDBIT);
+}
+
+static inline int xfs_sb_version_hasdirv2(xfs_sb_t *sbp)
+{
+	return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4 &&
+		(sbp->sb_versionnum & XFS_SB_VERSION_DIRV2BIT);
+}
+
+static inline int xfs_sb_version_haslogv2(xfs_sb_t *sbp)
+{
+	return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4 &&
+		(sbp->sb_versionnum & XFS_SB_VERSION_LOGV2BIT);
+}
+
+static inline int xfs_sb_version_hasextflgbit(xfs_sb_t *sbp)
+{
+	return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4 &&
+		(sbp->sb_versionnum & XFS_SB_VERSION_EXTFLGBIT);
+}
+
+static inline int xfs_sb_version_hassector(xfs_sb_t *sbp)
+{
+	return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4 &&
+		(sbp->sb_versionnum & XFS_SB_VERSION_SECTORBIT);
+}
+
+static inline int xfs_sb_version_hasasciici(xfs_sb_t *sbp)
+{
+	return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4 &&
+		(sbp->sb_versionnum & XFS_SB_VERSION_BORGBIT);
+}
+
+static inline int xfs_sb_version_hasmorebits(xfs_sb_t *sbp)
+{
+	return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4 &&
+		(sbp->sb_versionnum & XFS_SB_VERSION_MOREBITSBIT);
+}
+
+/*
+ * sb_features2 bit version macros.
+ *
+ * For example, for a bit defined as XFS_SB_VERSION2_FUNBIT, has a macro:
+ *
+ * SB_VERSION_HASFUNBIT(xfs_sb_t *sbp)
+ *	((xfs_sb_version_hasmorebits(sbp) &&
+ *	 ((sbp)->sb_features2 & XFS_SB_VERSION2_FUNBIT)
+ */
+
+static inline int xfs_sb_version_haslazysbcount(xfs_sb_t *sbp)
+{
+	return xfs_sb_version_hasmorebits(sbp) &&
+		(sbp->sb_features2 & XFS_SB_VERSION2_LAZYSBCOUNTBIT);
+}
+
+static inline int xfs_sb_version_hasattr2(xfs_sb_t *sbp)
+{
+	return xfs_sb_version_hasmorebits(sbp) &&
+		(sbp->sb_features2 & XFS_SB_VERSION2_ATTR2BIT);
+}
+
+static inline void xfs_sb_version_addattr2(xfs_sb_t *sbp)
+{
+	sbp->sb_versionnum |= XFS_SB_VERSION_MOREBITSBIT;
+	sbp->sb_features2 |= XFS_SB_VERSION2_ATTR2BIT;
+}
+
+static inline void xfs_sb_version_removeattr2(xfs_sb_t *sbp)
+{
+	sbp->sb_features2 &= ~XFS_SB_VERSION2_ATTR2BIT;
+	if (!sbp->sb_features2)
+		sbp->sb_versionnum &= ~XFS_SB_VERSION_MOREBITSBIT;
+}
+
+static inline int xfs_sb_version_hasprojid32bit(xfs_sb_t *sbp)
+{
+	return xfs_sb_version_hasmorebits(sbp) &&
+		(sbp->sb_features2 & XFS_SB_VERSION2_PROJID32BIT);
+}
+
+/*
+ * end of superblock version macros
+ */
+
+#define XFS_SB_DADDR		((xfs_daddr_t)0) /* daddr in filesystem/ag */
+#define	XFS_SB_BLOCK(mp)	XFS_HDR_BLOCK(mp, XFS_SB_DADDR)
+#define XFS_BUF_TO_SBP(bp)	((xfs_dsb_t *)((bp)->b_addr))
+
+#define	XFS_HDR_BLOCK(mp,d)	((xfs_agblock_t)XFS_BB_TO_FSBT(mp,d))
+#define	XFS_DADDR_TO_FSB(mp,d)	XFS_AGB_TO_FSB(mp, \
+			xfs_daddr_to_agno(mp,d), xfs_daddr_to_agbno(mp,d))
+#define	XFS_FSB_TO_DADDR(mp,fsbno)	XFS_AGB_TO_DADDR(mp, \
+			XFS_FSB_TO_AGNO(mp,fsbno), XFS_FSB_TO_AGBNO(mp,fsbno))
+
+/*
+ * File system sector to basic block conversions.
+ */
+#define XFS_FSS_TO_BB(mp,sec)	((sec) << (mp)->m_sectbb_log)
+
+/*
+ * File system block to basic block conversions.
+ */
+#define	XFS_FSB_TO_BB(mp,fsbno)	((fsbno) << (mp)->m_blkbb_log)
+#define	XFS_BB_TO_FSB(mp,bb)	\
+	(((bb) + (XFS_FSB_TO_BB(mp,1) - 1)) >> (mp)->m_blkbb_log)
+#define	XFS_BB_TO_FSBT(mp,bb)	((bb) >> (mp)->m_blkbb_log)
+
+/*
+ * File system block to byte conversions.
+ */
+#define XFS_FSB_TO_B(mp,fsbno)	((xfs_fsize_t)(fsbno) << (mp)->m_sb.sb_blocklog)
+#define XFS_B_TO_FSB(mp,b)	\
+	((((uint64_t)(b)) + (mp)->m_blockmask) >> (mp)->m_sb.sb_blocklog)
+#define XFS_B_TO_FSBT(mp,b)	(((uint64_t)(b)) >> (mp)->m_sb.sb_blocklog)
+#define XFS_B_FSB_OFFSET(mp,b)	((b) & (mp)->m_blockmask)
+
+#endif	/* XFS_SB_H_ */
diff --git a/extlinux/xfs_types.h b/extlinux/xfs_types.h
new file mode 100644
index 0000000..9280886
--- /dev/null
+++ b/extlinux/xfs_types.h
@@ -0,0 +1,135 @@
+/*
+ * Taken from Linux kernel tree (linux/fs/xfs)
+ *
+ * Copyright (c) 2000-2005 Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * Copyright (c) 2012 Paulo Alcantara <pcacjr at zytor.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+#ifndef XFS_TYPES_H_
+#define	XFS_TYPES_H_
+
+#include <stddef.h>
+
+#include <sys/types.h>
+
+typedef enum { B_FALSE,B_TRUE }	boolean_t;
+typedef uint32_t		prid_t;		/* project ID */
+typedef uint32_t		inst_t;		/* an instruction */
+
+typedef int64_t			xfs_off_t;	/* <file offset> type */
+typedef unsigned long long	xfs_ino_t;	/* <inode> type */
+typedef int64_t			xfs_daddr_t;	/* <disk address> type */
+typedef char *			xfs_caddr_t;	/* <core address> type */
+typedef uint32_t			xfs_dev_t;
+typedef uint32_t			xfs_nlink_t;
+
+/* __psint_t is the same size as a pointer */
+typedef int32_t __psint_t;
+typedef uint32_t __psunsigned_t;
+
+typedef uint32_t	xfs_agblock_t;	/* blockno in alloc. group */
+typedef	uint32_t	xfs_extlen_t;	/* extent length in blocks */
+typedef	uint32_t	xfs_agnumber_t;	/* allocation group number */
+typedef int32_t	xfs_extnum_t;	/* # of extents in a file */
+typedef int16_t	xfs_aextnum_t;	/* # extents in an attribute fork */
+typedef	int64_t	xfs_fsize_t;	/* bytes in a file */
+typedef uint64_t	xfs_ufsize_t;	/* unsigned bytes in a file */
+
+typedef	int32_t	xfs_suminfo_t;	/* type of bitmap summary info */
+typedef	int32_t	xfs_rtword_t;	/* word type for bitmap manipulations */
+
+typedef	int64_t	xfs_lsn_t;	/* log sequence number */
+typedef	int32_t	xfs_tid_t;	/* transaction identifier */
+
+typedef	uint32_t	xfs_dablk_t;	/* dir/attr block number (in file) */
+typedef	uint32_t	xfs_dahash_t;	/* dir/attr hash value */
+
+/*
+ * These types are 64 bits on disk but are either 32 or 64 bits in memory.
+ * Disk based types:
+ */
+typedef uint64_t	xfs_dfsbno_t;	/* blockno in filesystem (agno|agbno) */
+typedef uint64_t	xfs_drfsbno_t;	/* blockno in filesystem (raw) */
+typedef	uint64_t	xfs_drtbno_t;	/* extent (block) in realtime area */
+typedef	uint64_t	xfs_dfiloff_t;	/* block number in a file */
+typedef	uint64_t	xfs_dfilblks_t;	/* number of blocks in a file */
+
+/*
+ * Memory based types are conditional.
+ */
+typedef	uint64_t	xfs_fsblock_t;	/* blockno in filesystem (agno|agbno) */
+typedef uint64_t	xfs_rfsblock_t;	/* blockno in filesystem (raw) */
+typedef uint64_t	xfs_rtblock_t;	/* extent (block) in realtime area */
+typedef	int64_t	xfs_srtblock_t;	/* signed version of xfs_rtblock_t */
+
+typedef uint64_t	xfs_fileoff_t;	/* block number in a file */
+typedef int64_t	xfs_sfiloff_t;	/* signed block number in a file */
+typedef uint64_t	xfs_filblks_t;	/* number of blocks in a file */
+
+/*
+ * Null values for the types.
+ */
+#define	NULLDFSBNO	((xfs_dfsbno_t)-1)
+#define	NULLDRFSBNO	((xfs_drfsbno_t)-1)
+#define	NULLDRTBNO	((xfs_drtbno_t)-1)
+#define	NULLDFILOFF	((xfs_dfiloff_t)-1)
+
+#define	NULLFSBLOCK	((xfs_fsblock_t)-1)
+#define	NULLRFSBLOCK	((xfs_rfsblock_t)-1)
+#define	NULLRTBLOCK	((xfs_rtblock_t)-1)
+#define	NULLFILEOFF	((xfs_fileoff_t)-1)
+
+#define	NULLAGBLOCK	((xfs_agblock_t)-1)
+#define	NULLAGNUMBER	((xfs_agnumber_t)-1)
+#define	NULLEXTNUM	((xfs_extnum_t)-1)
+
+#define NULLCOMMITLSN	((xfs_lsn_t)-1)
+
+/*
+ * Max values for extlen, extnum, aextnum.
+ */
+#define	MAXEXTLEN	((xfs_extlen_t)0x001fffff)	/* 21 bits */
+#define	MAXEXTNUM	((xfs_extnum_t)0x7fffffff)	/* signed int */
+#define	MAXAEXTNUM	((xfs_aextnum_t)0x7fff)		/* signed short */
+
+/*
+ * Min numbers of data/attr fork btree root pointers.
+ */
+#define MINDBTPTRS	3
+#define MINABTPTRS	2
+
+/*
+ * MAXNAMELEN is the length (including the terminating null) of
+ * the longest permissible file (component) name.
+ */
+#define MAXNAMELEN	256
+
+typedef enum {
+	XFS_LOOKUP_EQi, XFS_LOOKUP_LEi, XFS_LOOKUP_GEi
+} xfs_lookup_t;
+
+typedef enum {
+	XFS_BTNUM_BNOi, XFS_BTNUM_CNTi, XFS_BTNUM_BMAPi, XFS_BTNUM_INOi,
+	XFS_BTNUM_MAX
+} xfs_btnum_t;
+
+struct xfs_name {
+	const unsigned char	*name;
+	int			len;
+};
+
+#endif	/* XFS_TYPES_H_ */
diff --git a/libinstaller/syslxfs.h b/libinstaller/syslxfs.h
index 7a23146..4d8f3b2 100644
--- a/libinstaller/syslxfs.h
+++ b/libinstaller/syslxfs.h
@@ -1,5 +1,5 @@
 /*
- *   Copyright 2011 Paulo Alcantara <pcacjr at gmail.com>
+ *   Copyright 2011-2012 Paulo Alcantara <pcacjr at zytor.com>
  *
  *   This program is free software; you can redistribute it and/or modify
  *   it under the terms of the GNU General Public License as published by
@@ -12,13 +12,14 @@
 #ifndef _SYSLXFS_H_
 #define _SYSLXFS_H_
 
-/* Global fs_type for handling fat, ntfs, ext2/3/4 and btrfs */
+/* Global fs_type for handling fat, ntfs, ext2/3/4, btrfs and xfs */
 enum filesystem {
     NONE,
     EXT2,
     BTRFS,
     VFAT,
     NTFS,
+    XFS,
 };
 
 extern int fs_type;
diff --git a/mbr/mbr.S b/mbr/mbr.S
index b71cfb7..270a356 100644
--- a/mbr/mbr.S
+++ b/mbr/mbr.S
@@ -265,6 +265,19 @@ boot:
 	movl	%eax, 8(%si)	/* Adjust in-memory partition table entry */
 	call	read_sector
 	jc	disk_error
+
+	/* Check if the read sector is a XFS superblock */
+	cmpl	$0x42534658, (bootsec) /* "XFSB" */
+	jne	no_xfs
+
+	/* We put the Syslinux boot sector at offset 0x800 (4 sectors), so we
+	 * need to adjust %eax (%eax + 4) to read the right sector into 0x7C00.
+	 */
+	addl	$0x800 >> 0x09, %eax /* plus 4 sectors */
+	call	read_sector
+	jc	disk_error
+
+no_xfs:
 	cmpw	$0xaa55, (bootsec+510)
 	jne	missing_os		/* Not a valid boot sector */
 	movw	$driveno, %sp	/* driveno == bootsec-6 */



More information about the Syslinux mailing list