Commit 0293ce3a authored by Mandy Kirkconnell's avatar Mandy Kirkconnell Committed by Nathan Scott

[XFS] 929045 567344 This mod introduces multi-level in-core file extent

functionality, building upon the new layout introduced in mod
xfs-linux:xfs-kern:207390a.  The new multi-level extent allocations are
only required for heavily fragmented files, so the old-style linear extent
list is used on files until the extents reach a pre-determined size of 4k.
4k buffers are used because this is the system page size on Linux i386 and
systems with larger page sizes don't seem to gain much, if anything, by
using their native page size as the extent buffer size. Also, using 4k
extent buffers everywhere provides a consistent interface for CXFS across
different platforms.  The 4k extent buffers are managed by an indirection
array (xfs_ext_irec_t) which is basically just a pointer array with a bit
of extra information to keep track of the number of extents in each buffer
as well as the extent offset of each buffer.  Major changes include:  -
Add multi-level in-core file extent functionality to the xfs_iext_  
subroutines introduced in mod:	xfs-linux:xfs-kern:207390a  - Introduce 13
new subroutines which add functionality for multi-level   in-core file
extents:	 xfs_iext_add_indirect_multi()	      
xfs_iext_remove_indirect()	   xfs_iext_realloc_indirect()	      
xfs_iext_indirect_to_direct()	      xfs_iext_bno_to_irec()	    
xfs_iext_idx_to_irec()	       xfs_iext_irec_init()	   
xfs_iext_irec_new()	    xfs_iext_irec_remove()	  
xfs_iext_irec_compact() 	xfs_iext_irec_compact_pages()	     
xfs_iext_irec_compact_full()	     xfs_iext_irec_update_extoffs()

SGI-PV: 928864
SGI-Modid: xfs-linux-melb:xfs-kern:207393a
Signed-off-by: default avatarMandy Kirkconnell <alkirkco@sgi.com>
Signed-off-by: default avatarNathan Scott <nathans@sgi.com>
parent 4eea22f0
...@@ -3423,6 +3423,7 @@ xfs_bmap_local_to_extents( ...@@ -3423,6 +3423,7 @@ xfs_bmap_local_to_extents(
xfs_bmap_forkoff_reset(args.mp, ip, whichfork); xfs_bmap_forkoff_reset(args.mp, ip, whichfork);
xfs_idata_realloc(ip, -ifp->if_bytes, whichfork); xfs_idata_realloc(ip, -ifp->if_bytes, whichfork);
xfs_iext_add(ifp, 0, 1); xfs_iext_add(ifp, 0, 1);
ASSERT((ifp->if_flags & (XFS_IFEXTENTS|XFS_IFEXTIREC)) == XFS_IFEXTENTS);
ep = xfs_iext_get_ext(ifp, 0); ep = xfs_iext_get_ext(ifp, 0);
xfs_bmbt_set_allf(ep, 0, args.fsbno, 1, XFS_EXT_NORM); xfs_bmbt_set_allf(ep, 0, args.fsbno, 1, XFS_EXT_NORM);
xfs_bmap_trace_post_update(fname, "new", ip, 0, whichfork); xfs_bmap_trace_post_update(fname, "new", ip, 0, whichfork);
...@@ -3551,6 +3552,54 @@ xfs_bmap_do_search_extents( ...@@ -3551,6 +3552,54 @@ xfs_bmap_do_search_extents(
return ep; return ep;
} }
/*
* Call xfs_bmap_do_search_extents() to search for the extent
* record containing block bno. If in multi-level in-core extent
* allocation mode, find and extract the target extent buffer,
* otherwise just use the direct extent list.
*/
xfs_bmbt_rec_t * /* pointer to found extent entry */
xfs_bmap_search_multi_extents(
xfs_ifork_t *ifp, /* inode fork pointer */
xfs_fileoff_t bno, /* block number searched for */
int *eofp, /* out: end of file found */
xfs_extnum_t *lastxp, /* out: last extent index */
xfs_bmbt_irec_t *gotp, /* out: extent entry found */
xfs_bmbt_irec_t *prevp) /* out: previous extent entry found */
{
xfs_bmbt_rec_t *base; /* base of extent records */
xfs_bmbt_rec_t *ep; /* extent record pointer */
xfs_ext_irec_t *erp = NULL; /* indirection array pointer */
xfs_extnum_t lastx; /* last extent index */
xfs_extnum_t nextents; /* number of file extents */
/*
* For multi-level extent allocation mode, find the
* target extent list and pass only the contiguous
* list to xfs_bmap_do_search_extents. Convert lastx
* from a file extent index to an index within the
* target extent list.
*/
if (ifp->if_flags & XFS_IFEXTIREC) {
int erp_idx = 0;
erp = xfs_iext_bno_to_irec(ifp, bno, &erp_idx);
base = erp->er_extbuf;
nextents = erp->er_extcount;
lastx = ifp->if_lastex - erp->er_extoff;
} else {
base = &ifp->if_u1.if_extents[0];
nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
lastx = ifp->if_lastex;
}
ep = xfs_bmap_do_search_extents(base, lastx, nextents, bno,
eofp, lastxp, gotp, prevp);
/* Convert lastx back to file-based index */
if (ifp->if_flags & XFS_IFEXTIREC) {
*lastxp += erp->er_extoff;
}
return ep;
}
/* /*
* Search the extents list for the inode, for the extent containing bno. * Search the extents list for the inode, for the extent containing bno.
* If bno lies in a hole, point to the next entry. If bno lies past eof, * If bno lies in a hole, point to the next entry. If bno lies past eof,
...@@ -3569,20 +3618,14 @@ xfs_bmap_search_extents( ...@@ -3569,20 +3618,14 @@ xfs_bmap_search_extents(
xfs_bmbt_irec_t *prevp) /* out: previous extent entry found */ xfs_bmbt_irec_t *prevp) /* out: previous extent entry found */
{ {
xfs_ifork_t *ifp; /* inode fork pointer */ xfs_ifork_t *ifp; /* inode fork pointer */
xfs_bmbt_rec_t *base; /* base of extent list */
xfs_extnum_t lastx; /* last extent index used */
xfs_extnum_t nextents; /* number of file extents */
xfs_bmbt_rec_t *ep; /* extent record pointer */ xfs_bmbt_rec_t *ep; /* extent record pointer */
int rt; /* realtime flag */ int rt; /* realtime flag */
XFS_STATS_INC(xs_look_exlist); XFS_STATS_INC(xs_look_exlist);
ifp = XFS_IFORK_PTR(ip, whichfork); ifp = XFS_IFORK_PTR(ip, whichfork);
lastx = ifp->if_lastex;
nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
base = &ifp->if_u1.if_extents[0];
ep = xfs_bmap_do_search_extents(base, lastx, nextents, bno, eofp, ep = xfs_bmap_search_multi_extents(ifp, bno, eofp, lastxp, gotp, prevp);
lastxp, gotp, prevp);
rt = (whichfork == XFS_DATA_FORK) && XFS_IS_REALTIME_INODE(ip); rt = (whichfork == XFS_DATA_FORK) && XFS_IS_REALTIME_INODE(ip);
if (unlikely(!rt && !gotp->br_startblock && (*lastxp != NULLEXTNUM))) { if (unlikely(!rt && !gotp->br_startblock && (*lastxp != NULLEXTNUM))) {
cmn_err(CE_PANIC,"Access to block zero: fs: <%s> inode: %lld " cmn_err(CE_PANIC,"Access to block zero: fs: <%s> inode: %lld "
......
...@@ -352,6 +352,24 @@ xfs_check_nostate_extents( ...@@ -352,6 +352,24 @@ xfs_check_nostate_extents(
xfs_extnum_t idx, xfs_extnum_t idx,
xfs_extnum_t num); xfs_extnum_t num);
/*
* Call xfs_bmap_do_search_extents() to search for the extent
* record containing block bno. If in multi-level in-core extent
* allocation mode, find and extract the target extent buffer,
* otherwise just use the direct extent list.
*/
xfs_bmbt_rec_t *
xfs_bmap_search_multi_extents(struct xfs_ifork *, xfs_fileoff_t, int *,
xfs_extnum_t *, xfs_bmbt_irec_t *, xfs_bmbt_irec_t *);
/*
* Search an extent list for the extent which includes block
* bno.
*/
xfs_bmbt_rec_t *xfs_bmap_do_search_extents(xfs_bmbt_rec_t *,
xfs_extnum_t, xfs_extnum_t, xfs_fileoff_t, int *,
xfs_extnum_t *, xfs_bmbt_irec_t *, xfs_bmbt_irec_t *);
#endif /* __KERNEL__ */ #endif /* __KERNEL__ */
#endif /* __XFS_BMAP_H__ */ #endif /* __XFS_BMAP_H__ */
...@@ -372,14 +372,6 @@ extern int xfs_bmbt_get_rec(struct xfs_btree_cur *, xfs_fileoff_t *, ...@@ -372,14 +372,6 @@ extern int xfs_bmbt_get_rec(struct xfs_btree_cur *, xfs_fileoff_t *,
xfs_exntst_t *, int *); xfs_exntst_t *, int *);
#endif #endif
/*
* Search an extent list for the extent which includes block
* bno.
*/
xfs_bmbt_rec_t *xfs_bmap_do_search_extents(xfs_bmbt_rec_t *,
xfs_extnum_t, xfs_extnum_t, xfs_fileoff_t, int *,
xfs_extnum_t *, xfs_bmbt_irec_t *, xfs_bmbt_irec_t *);
#endif /* __KERNEL__ */ #endif /* __KERNEL__ */
#endif /* __XFS_BMAP_BTREE_H__ */ #endif /* __XFS_BMAP_BTREE_H__ */
This diff is collapsed.
...@@ -24,9 +24,36 @@ ...@@ -24,9 +24,36 @@
#define XFS_DATA_FORK 0 #define XFS_DATA_FORK 0
#define XFS_ATTR_FORK 1 #define XFS_ATTR_FORK 1
/*
* The following xfs_ext_irec_t struct introduces a second (top) level
* to the in-core extent allocation scheme. These structs are allocated
* in a contiguous block, creating an indirection array where each entry
* (irec) contains a pointer to a buffer of in-core extent records which
* it manages. Each extent buffer is 4k in size, since 4k is the system
* page size on Linux i386 and systems with larger page sizes don't seem
* to gain much, if anything, by using their native page size as the
* extent buffer size. Also, using 4k extent buffers everywhere provides
* a consistent interface for CXFS across different platforms.
*
* There is currently no limit on the number of irec's (extent lists)
* allowed, so heavily fragmented files may require an indirection array
* which spans multiple system pages of memory. The number of extents
* which would require this amount of contiguous memory is very large
* and should not cause problems in the foreseeable future. However,
* if the memory needed for the contiguous array ever becomes a problem,
* it is possible that a third level of indirection may be required.
*/
typedef struct xfs_ext_irec {
xfs_bmbt_rec_t *er_extbuf; /* block of extent records */
xfs_extnum_t er_extoff; /* extent offset in file */
xfs_extnum_t er_extcount; /* number of extents in page/block */
} xfs_ext_irec_t;
/* /*
* File incore extent information, present for each of data & attr forks. * File incore extent information, present for each of data & attr forks.
*/ */
#define XFS_IEXT_BUFSZ 4096
#define XFS_LINEAR_EXTS (XFS_IEXT_BUFSZ / (uint)sizeof(xfs_bmbt_rec_t))
#define XFS_INLINE_EXTS 2 #define XFS_INLINE_EXTS 2
#define XFS_INLINE_DATA 32 #define XFS_INLINE_DATA 32
typedef struct xfs_ifork { typedef struct xfs_ifork {
...@@ -39,6 +66,7 @@ typedef struct xfs_ifork { ...@@ -39,6 +66,7 @@ typedef struct xfs_ifork {
xfs_extnum_t if_lastex; /* last if_extents used */ xfs_extnum_t if_lastex; /* last if_extents used */
union { union {
xfs_bmbt_rec_t *if_extents; /* linear map file exts */ xfs_bmbt_rec_t *if_extents; /* linear map file exts */
xfs_ext_irec_t *if_ext_irec; /* irec map file exts */
char *if_data; /* inline file data */ char *if_data; /* inline file data */
} if_u1; } if_u1;
union { union {
...@@ -61,9 +89,10 @@ typedef struct xfs_ifork { ...@@ -61,9 +89,10 @@ typedef struct xfs_ifork {
/* /*
* Per-fork incore inode flags. * Per-fork incore inode flags.
*/ */
#define XFS_IFINLINE 0x0001 /* Inline data is read in */ #define XFS_IFINLINE 0x01 /* Inline data is read in */
#define XFS_IFEXTENTS 0x0002 /* All extent pointers are read in */ #define XFS_IFEXTENTS 0x02 /* All extent pointers are read in */
#define XFS_IFBROOT 0x0004 /* i_broot points to the bmap b-tree root */ #define XFS_IFBROOT 0x04 /* i_broot points to the bmap b-tree root */
#define XFS_IFEXTIREC 0x08 /* Indirection array of extent blocks */
/* /*
* Flags for xfs_imap() and xfs_dilocate(). * Flags for xfs_imap() and xfs_dilocate().
...@@ -438,13 +467,26 @@ xfs_bmbt_rec_t *xfs_iext_get_ext(xfs_ifork_t *, xfs_extnum_t); ...@@ -438,13 +467,26 @@ xfs_bmbt_rec_t *xfs_iext_get_ext(xfs_ifork_t *, xfs_extnum_t);
void xfs_iext_insert(xfs_ifork_t *, xfs_extnum_t, xfs_extnum_t, void xfs_iext_insert(xfs_ifork_t *, xfs_extnum_t, xfs_extnum_t,
xfs_bmbt_irec_t *); xfs_bmbt_irec_t *);
void xfs_iext_add(xfs_ifork_t *, xfs_extnum_t, int); void xfs_iext_add(xfs_ifork_t *, xfs_extnum_t, int);
void xfs_iext_add_indirect_multi(xfs_ifork_t *, int, xfs_extnum_t, int);
void xfs_iext_remove(xfs_ifork_t *, xfs_extnum_t, int); void xfs_iext_remove(xfs_ifork_t *, xfs_extnum_t, int);
void xfs_iext_remove_inline(xfs_ifork_t *, xfs_extnum_t, int); void xfs_iext_remove_inline(xfs_ifork_t *, xfs_extnum_t, int);
void xfs_iext_remove_direct(xfs_ifork_t *, xfs_extnum_t, int); void xfs_iext_remove_direct(xfs_ifork_t *, xfs_extnum_t, int);
void xfs_iext_remove_indirect(xfs_ifork_t *, xfs_extnum_t, int);
void xfs_iext_realloc_direct(xfs_ifork_t *, int); void xfs_iext_realloc_direct(xfs_ifork_t *, int);
void xfs_iext_realloc_indirect(xfs_ifork_t *, int);
void xfs_iext_indirect_to_direct(xfs_ifork_t *);
void xfs_iext_direct_to_inline(xfs_ifork_t *, xfs_extnum_t); void xfs_iext_direct_to_inline(xfs_ifork_t *, xfs_extnum_t);
void xfs_iext_inline_to_direct(xfs_ifork_t *, int); void xfs_iext_inline_to_direct(xfs_ifork_t *, int);
void xfs_iext_destroy(xfs_ifork_t *); void xfs_iext_destroy(xfs_ifork_t *);
xfs_ext_irec_t *xfs_iext_bno_to_irec(xfs_ifork_t *, xfs_fileoff_t, int *);
xfs_ext_irec_t *xfs_iext_idx_to_irec(xfs_ifork_t *, xfs_extnum_t *, int *, int);
void xfs_iext_irec_init(xfs_ifork_t *);
xfs_ext_irec_t *xfs_iext_irec_new(xfs_ifork_t *, int);
void xfs_iext_irec_remove(xfs_ifork_t *, int);
void xfs_iext_irec_compact(xfs_ifork_t *);
void xfs_iext_irec_compact_pages(xfs_ifork_t *);
void xfs_iext_irec_compact_full(xfs_ifork_t *);
void xfs_iext_irec_update_extoffs(xfs_ifork_t *, int, int);
#define xfs_ipincount(ip) ((unsigned int) atomic_read(&ip->i_pincount)) #define xfs_ipincount(ip) ((unsigned int) atomic_read(&ip->i_pincount))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment