EXTLINUX: Initial XFS filesystem support

XFS filesystems are divided into a number of equally sized chunks called
Allocation Groups (AGs). Each AG can almost be thought of as an
individual filesystem that maintains its own's space usage.

Each AG has the following structure:
     - A super block describing the overall filesystem info
     - Free space management
     - Inode allocation and tracking

So, 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).

This patch adds support to the EXTLINUX installer to be able to install
Syslinux in an XFS partition, but with a limitation (temporarily) of
relying on the filesystem block size being 4+ KiB, otherwise there won't
be enough space to store the Syslinux boot sector in the blank area around
the 2048 to 4096 bytes of the primary AG/superblock.

Signed-off-by: Paulo Alcantara <pcacjr@zytor.com>
mbr: Add support for loading VBRs from XFS filesystems

Before reading the VBR into 0x7C00, we need to check the first 4 bytes of
the read sector and check whether it is a XFS superblock or not. If it
is, then we need to read the right sector, which is the 4th sector of
the XFS partition where the Syslinux boot sector lives in.

This patch adds support for booting off XFS partitions properly on
MBR HDDs.

Signed-off-by: Paulo Alcantara <pcacjr@zytor.com>
xfs: Initial skeleton for XFS filesystem support

And another filesystem driver for Syslinux. Heh :-)

This patch *only* prints out a sample message on the screen when it
finds an active partition formated as a XFS filesystem. If this really
happens, then the XFS filesystem support in the EXTLINUX installer is
working nicely and it's time to write the driver.

Signed-off-by: Paulo Alcantara <pcacjr@zytor.com>
xfs: Implement xfs_fs_init() function

The XFS filesystem driver is now able to read properly the XFS superblock
and store useful information to be used around the driver code, which is
kept (in memory) in the xfs_fs_info structure.

As XFS filesytems store their superblock's fields in big-endian format,
we need to have functions capable to transform a 16/32/64-bit big-endian
value into a 16/32/64-bit little-endian one, since Syslinux is only able
to boot up on x86 systems, which store values in litte-endian format. So,
the bexx_to_cpu() functions do this trick.

The driver isn't functional yet, but I'm looking forward to implement
the iget() family of functions ASAP, then we can to at least get a
"boot:" from a XFS filesystem.

Signed-off-by: Paulo Alcantara <pcacjr@zytor.com>
extlinux: put set_attributes() back to ext2_fat_install_file().

rewrite_boot_image() wraps the logic from previous
ext2_fat_install_file(). The deleted lines includes
the set_attributes(), while it is actually not
within the rewrite_boot_image().

We add set_attributes() and some helper judgement just
as what we do in xfs_install_file().

Signed-off-by: Chen Baozi <baozich@gmail.com>
Signed-off-by: Paulo Alcantara <pcacjr@zytor.com>
xfs: Add xfs_iget_root() to XFS filesystem ops

This patch adds initial implementation of the xfs_iget_root() filesystem
operation.

Note also that this is not going to work with inode B+trees with any
level associated with it other than only leafs in the tree. I intend to
finish these remaining features in xfs_iget_root() once I get xfs_iget()
function working properly.

I'm looking forward to implement xfs_iget() function since we have now
xfs_iget_root() function at some point.

Signed-off-by: Paulo Alcantara <pcacjr@zytor.com>
Fix the calculation of the block of the root of the inode B+tree.

We have saved the first block's No. to the blk by
"XFS_AGNO_TO_FSB(fs, agno)". So here the relative block number
in a.g. should plus to our previous calculation result, rather
than "agno" which is the a.g.'s No.,

Signed-off-by: Chen Baozi <baozich@gmail.com>
Signed-off-by: Paulo Alcantara <pcacjr@zytor.com>
xfs: Fix inode lookup in chunks of 64 inodes

Leaf entries found in inode btrees in XFS contain the starting inode
number of some chunk, count of free entries, and some bitmask to handle
the free entries.

There are several inode numbers where its respective filesystem block
can be the same, so we need to read retrieve them through those chunks
of inodes.

Signed-off-by: Paulo Alcantara <pcacjr@zytor.com>
xfs: Add xfs_get_agi() function

Signed-off-by: Paulo Alcantara <pcacjr@zytor.com>
xfs: Fix inode size attribution

Since the inode's size is stored on disk in big-endian format, we must
store it in the Syslinux's inode as little-endian, since Syslinux is
supposed to be running on x86 CPUs only.

Signed-off-by: Paulo Alcantara <pcacjr@zytor.com>
Add support for 64-bit filesystem compatible struct inode.

The struct inode of syslinux is designed for 32-bit filesystem.
However, mordern filesystem has already evolved into 64-bit,
such as XFS. So we modified it according the current linux
kernel's struct inode, which would support 64-bit file size,
block number and inode number.

Signed-off-by: Chen Baozi <baozich@gmail.com>
Signed-off-by: Paulo Alcantara <pcacjr@zytor.com>
xfs: Add xfs_iget() to filesystem ops

xfs_iget() function is responsible for finding an entry from a given
filename and parent inode of the entry being looked up.

XFS_INO_TO_FSB() returns a sparse enconding of the disk location, and not
the right filesystem block number we expected to have from the wrong byte
offset.

Now, there is a ino_to_bytes() macro who calculates correctly the block
offset from a given inode number, and then we get the *right* filesystem
block number we expected.

Also, use agnumber_to_bytes() in order to get the right filesystem block
where the given AG number resides.

Signed-off-by: Paulo Alcantara <pcacjr@zytor.com>
xfs: Fix some inode number conversions

Use ino_to_bytes() in conjuction with BLOCK_SHIFT() to calculate the
right filesystem block number from given inode numbers.

The old calculation wouldn't work since the calculation was returning
filesystem block numbers which are sparse enconding of the disk location.

Signed-off-by: Paulo Alcantara <pcacjr@zytor.com>
xfs: Remove duplicate variable attribution

Signed-off-by: Paulo Alcantara <pcacjr@zytor.com>
xfs: Some bugfixes

XFS inodes never share filesystem blocks with anything else. The driver
used to calculate wrong the offset within a chunk of inode found in inode
B+trees. The correct calculation is to get the lower bits of the inode
number (which is the inode number within a chunk) and multiply by inode
size to get the right offset.

The "bb_rumrecs" and "bb_level" fields (found in leaf entries of inode
B+trees) were being read incorrectly, since they're all stored in
big-endian on disk and we did not convert them to litte-endian respectively.

Besides, fix some memory leaks.

Signed-off-by: Paulo Alcantara <pcacjr@zytor.com>
xfs: Remove unnecessary check in xfs_iget() function

xfs_iget() function is _never_ called with parent inodes with mode set
to DT_REG (regular file) and this check was used for other puporses while
doing some test cases.

Signed-off-by: Paulo Alcantara <pcacjr@zytor.com>
xfs: Make for-statement declaration more readable

Signed-off-by: Paulo Alcantara <pcacjr@zytor.com>
xfs: Fix minor typo

Signed-off-by: Paulo Alcantara <pcacjr@zytor.com>
xfs: Add xfs_getfssec() and xfs_next_extent() functions

This is a initial implementation of both and they're not fully functional
yet.

xfs_getfssec() still needs to be modified to handle XFS-specific things
and xfs_next_extent() must handle inodes with different dinode formats
other than _only_ handling dinode format "extents".

Signed-off-by: Paulo Alcantara <pcacjr@zytor.com>
xfs: rework the logic of xfs_get_ino_core()

(Just remove a few lines of debugging dirty marks. Sorry for
 the previous carelessness.)

Since we can calculate the real blk address directly by a given
ino, there is no need for implementing such complex logic which
would look up an inode from agi_root.

It seems that XFS put 64 inodes into one logic chunk for
performance consideration. That is to say, if our purporse is
just to implement a workable read-only xfs support, there is
also no need to handle this case, which do reduce lots of
complexity.

Also, in order to handle the inode whose starting address is
in the middle of one block, we need to hold the info of
i_block_offset, which can be calculated by XFS_INO_TO_OFFSET.

Signed-off-by: Chen Baozi <baozich@gmail.com>
Signed-off-by: Paulo Alcantara <pcacjr@zytor.com>