aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaulo Alcantara <pcacjr@zytor.com>2012-07-16 14:56:30 -0300
committerPaulo Alcantara <pcacjr@zytor.com>2012-07-21 01:21:46 -0300
commit8440ec2a8ea4fda9a3326d53b9e5189163d685d7 (patch)
tree2082ce71dd75d0759844678dfb2faf33adf2d9d7
parentd5bf0b25e039410a6e9a058ab69c137bc3ef1219 (diff)
downloadsyslinux-8440ec2a8ea4fda9a3326d53b9e5189163d685d7.tar.gz
syslinux-8440ec2a8ea4fda9a3326d53b9e5189163d685d7.tar.xz
syslinux-8440ec2a8ea4fda9a3326d53b9e5189163d685d7.zip
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>
-rw-r--r--core/fs/xfs/xfs.c107
-rw-r--r--core/fs/xfs/xfs.h26
-rw-r--r--core/fs/xfs/xfs_ag.h11
3 files changed, 120 insertions, 24 deletions
diff --git a/core/fs/xfs/xfs.c b/core/fs/xfs/xfs.c
index 9269f27f..79d5a5fc 100644
--- a/core/fs/xfs/xfs.c
+++ b/core/fs/xfs/xfs.c
@@ -100,7 +100,6 @@ static xfs_dinode_t *xfs_get_ino_core(struct fs_info *fs, xfs_ino_t ino)
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;
}
@@ -115,9 +114,10 @@ out:
*/
static const void *xfs_get_ino_chunk(struct fs_info *fs, xfs_ino_t ino)
{
- const int len = 64 * XFS_INFO(fs)->inodesize;
+ int nblks = ((64 * XFS_INFO(fs)->inodesize) + BLOCK_SIZE(fs) - 1) >>
+ BLOCK_SHIFT(fs);
+ const int len = (nblks + 1) << BLOCK_SHIFT(fs);
void *buf;
- block_t nblks;
uint8_t *p;
block_t start_blk = ino_to_bytes(fs, ino) >> BLOCK_SHIFT(fs);
off_t offset = 0;
@@ -128,7 +128,6 @@ static const void *xfs_get_ino_chunk(struct fs_info *fs, xfs_ino_t ino)
memset(buf, 0, len);
- nblks = len >> BLOCK_SHIFT(fs);
while (nblks--) {
p = (uint8_t *)get_cache(fs->fs_dev, start_blk++);
@@ -298,6 +297,7 @@ found:
if (ncore) {
if (be16_to_cpu(ncore->di_magic) ==
be16_to_cpu(*(uint16_t *)XFS_DINODE_MAGIC)) {
+ xfs_debug("Inode's core has been found");
goto core_found;
} else {
xfs_error("Inode core's magic number does not match!");
@@ -321,18 +321,96 @@ core_found:
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_IFDIR)
+ if (be16_to_cpu(ncore->di_mode) & S_IFDIR) {
inode->mode = DT_DIR;
- else if (be16_to_cpu(ncore->di_mode) & S_IFREG)
+ xfs_debug("Found a directory inode!");
+ } else if (be16_to_cpu(ncore->di_mode) & S_IFREG) {
inode->mode = DT_REG;
-
- xfs_debug("Found a %s inode", inode->mode == DT_DIR ? "directory" : "file");
+ xfs_debug("Found a file inode!");
+ xfs_debug("inode size %llu", inode->size);
+ }
xfs_ino_core_free(inode, ncore);
return inode;
}
+static uint32_t xfs_getfssec(struct file *file, char *buf, int sectors,
+ bool *have_more)
+{
+ xfs_debug("in");
+
+ 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_rec_t *rec;
+ uint64_t startoff;
+ uint64_t startblock;
+ uint64_t blockcount;
+ block_t blk;
+
+ (void)lstart;
+
+ xfs_debug("in");
+
+ /* Check if we need the region for the chunk of 64 inodes */
+ if (XFS_PVT(inode)->i_chunk_offset) {
+ core = (xfs_dinode_t *)((uint8_t *)xfs_get_ino_chunk(fs, inode->ino) +
+ XFS_PVT(inode)->i_chunk_offset);
+
+ xfs_debug("core's magic number 0x%04x", be16_to_cpu(core->di_magic));
+
+ 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!");
+ goto out;
+ }
+ } else {
+ core = xfs_get_ino_core(fs, inode->ino);
+ }
+
+ if (core->di_format == XFS_DINODE_FMT_EXTENTS) {
+ /* The data fork contains the file's data extents */
+ if (XFS_PVT(inode)->i_cur_extent == be32_to_cpu(core->di_nextents))
+ goto out;
+
+ rec = (xfs_bmbt_rec_t *)&core->di_literal_area[0] +
+ XFS_PVT(inode)->i_cur_extent++;
+
+ xfs_debug("l0 0x%llx l1 0x%llx", rec->l0, rec->l1);
+
+ /* l0:9-62 are startoff */
+ startoff = (be64_to_cpu(rec->l0) & ((1ULL << 63) -1)) >> 9;
+ /* l0:0-8 and l1:21-63 are startblock */
+ startblock = (be64_to_cpu(rec->l0) & ((1ULL << 9) - 1)) |
+ (be64_to_cpu(rec->l1) >> 21);
+ /* l1:0-20 are blockcount */
+ blockcount = be64_to_cpu(rec->l1) & ((1ULL << 21) - 1);
+
+ xfs_debug("startoff 0x%llx startblock 0x%llx blockcount 0x%llx",
+ startoff, startblock, blockcount);
+
+ blk = fsblock_to_bytes(fs, startblock) >> BLOCK_SHIFT(fs);
+
+ xfs_debug("blk %llu", blk);
+
+ XFS_PVT(inode)->i_offset = startoff;
+
+ inode->next_extent.pstart = blk << BLOCK_SHIFT(fs) >> SECTOR_SHIFT(fs);
+ inode->next_extent.len = ((blockcount << BLOCK_SHIFT(fs)) +
+ SECTOR_SIZE(fs) - 1) >> SECTOR_SHIFT(fs);
+ }
+
+ return 0;
+
+out:
+ return -1;
+}
+
static struct inode *xfs_iget(const char *dname, struct inode *parent)
{
struct fs_info *fs = parent->fs;
@@ -360,12 +438,21 @@ static struct inode *xfs_iget(const char *dname, struct inode *parent)
/* TODO: Handle both shortform and block directories */
if (core->di_format == XFS_DINODE_FMT_LOCAL) {
inode = xfs_fmt_local_find_entry(dname, parent, core);
+ if (!inode) {
+ xfs_error("Entry not found!");
+ goto out;
+ }
} else {
xfs_debug("format %hhu", core->di_format);
xfs_debug("TODO: format \"local\" is the only supported ATM");
goto out;
}
+ if (inode->mode == DT_REG) {
+ XFS_PVT(inode)->i_offset = 0;
+ XFS_PVT(inode)->i_cur_extent = 0;
+ }
+
xfs_ino_core_free(inode, core);
return inode;
@@ -557,11 +644,11 @@ const struct fs_ops xfs_fs_ops = {
.fs_init = xfs_fs_init,
.iget_root = xfs_iget_root,
.searchdir = NULL,
- .getfssec = NULL,
+ .getfssec = xfs_getfssec,
.load_config = generic_load_config,
.close_file = generic_close_file,
.mangle_name = generic_mangle_name,
.readdir = NULL,
.iget = xfs_iget,
- .next_extent = NULL,
+ .next_extent = xfs_next_extent,
};
diff --git a/core/fs/xfs/xfs.h b/core/fs/xfs/xfs.h
index 17720f87..73fee37c 100644
--- a/core/fs/xfs/xfs.h
+++ b/core/fs/xfs/xfs.h
@@ -72,15 +72,21 @@ struct xfs_fs_info;
(((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(x) \
- (agnumber_to_bytes(fs, XFS_FSB_TO_AGNO(mp, (x))) + \
- agblock_to_bytes(fs, XFS_FSB_TO_AGBNO(mp, (x))))
+#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))))
@@ -286,6 +292,8 @@ struct xfs_inode {
xfs_agblock_t i_agblock;
block_t i_ino_blk;
uint64_t i_chunk_offset;
+ uint64_t i_offset;
+ uint32_t i_cur_extent;
};
typedef struct { uint8_t i[8]; } __attribute__((__packed__)) xfs_dir2_ino8_t;
@@ -316,6 +324,18 @@ typedef struct xfs_dir2_sf {
xfs_dir2_sf_entry_t list[1]; /* shortform entries */
} __attribute__((__packed__)) xfs_dir2_sf_t;
+typedef enum {
+ XFS_EXT_NORM,
+ XFS_EXT_UNWRITTEN,
+ XFS_EXT_DMAPI_OFFLINE,
+ XFS_EXT_INVALID,
+} xfs_exntst_t;
+
+typedef struct xfs_bmbt_rec {
+ uint64_t l0;
+ uint64_t l1;
+} __attribute__((__packed__)) xfs_bmbt_rec_t;
+
typedef xfs_ino_t xfs_intino_t;
static inline xfs_intino_t xfs_dir2_sf_get_inumber(xfs_dir2_sf_t *sfp,
diff --git a/core/fs/xfs/xfs_ag.h b/core/fs/xfs/xfs_ag.h
index 808e1c92..a2988b10 100644
--- a/core/fs/xfs/xfs_ag.h
+++ b/core/fs/xfs/xfs_ag.h
@@ -175,17 +175,6 @@ typedef struct xfs_agfl {
(unsigned int)(pag)->pagf_levels[XFS_BTNUM_BNOi], \
(unsigned int)(pag)->pagf_levels[XFS_BTNUM_CNTi], mp))
-#define XFS_AGB_TO_FSB(mp,agno,agbno) \
- (((xfs_fsblock_t)(agno) << (mp)->m_sb.sb_agblklog) | (agbno))
-#define XFS_FSB_TO_AGNO(mp,fsbno) \
- ((xfs_agnumber_t)((fsbno) >> (mp)->m_sb.sb_agblklog))
-#define XFS_FSB_TO_AGBNO(mp,fsbno) \
- ((xfs_agblock_t)((fsbno) & xfs_mask32lo((mp)->m_sb.sb_agblklog)))
-#define XFS_AGB_TO_DADDR(mp,agno,agbno) \
- ((xfs_daddr_t)XFS_FSB_TO_BB(mp, \
- (xfs_fsblock_t)(agno) * (mp)->m_sb.sb_agblocks + (agbno)))
-#define XFS_AG_DADDR(mp,agno,d) (XFS_AGB_TO_DADDR(mp, agno, 0) + (d))
-
/*
* 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.