diff options
author | Paulo Alcantara <pcacjr@zytor.com> | 2012-07-16 14:56:30 -0300 |
---|---|---|
committer | Paulo Alcantara <pcacjr@zytor.com> | 2012-07-21 01:21:46 -0300 |
commit | 8440ec2a8ea4fda9a3326d53b9e5189163d685d7 (patch) | |
tree | 2082ce71dd75d0759844678dfb2faf33adf2d9d7 | |
parent | d5bf0b25e039410a6e9a058ab69c137bc3ef1219 (diff) | |
download | syslinux-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.c | 107 | ||||
-rw-r--r-- | core/fs/xfs/xfs.h | 26 | ||||
-rw-r--r-- | core/fs/xfs/xfs_ag.h | 11 |
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. |