Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

[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
Loading
Loading
Loading
Loading
+51 −8
Original line number Diff line number Diff line
@@ -3423,6 +3423,7 @@ xfs_bmap_local_to_extents(
		xfs_bmap_forkoff_reset(args.mp, ip, whichfork);
		xfs_idata_realloc(ip, -ifp->if_bytes, whichfork);
		xfs_iext_add(ifp, 0, 1);
		ASSERT((ifp->if_flags & (XFS_IFEXTENTS|XFS_IFEXTIREC)) == XFS_IFEXTENTS);
		ep = xfs_iext_get_ext(ifp, 0);
		xfs_bmbt_set_allf(ep, 0, args.fsbno, 1, XFS_EXT_NORM);
		xfs_bmap_trace_post_update(fname, "new", ip, 0, whichfork);
@@ -3551,6 +3552,54 @@ xfs_bmap_do_search_extents(
	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.
 * If bno lies in a hole, point to the next entry.  If bno lies past eof,
@@ -3569,20 +3618,14 @@ xfs_bmap_search_extents(
	xfs_bmbt_irec_t *prevp)         /* out: previous extent entry found */
{
	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 */
	int		rt;		/* realtime flag    */

	XFS_STATS_INC(xs_look_exlist);
	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,
					  lastxp, gotp, prevp);
	ep = xfs_bmap_search_multi_extents(ifp, bno, eofp, lastxp, gotp, prevp);

	rt = (whichfork == XFS_DATA_FORK) && XFS_IS_REALTIME_INODE(ip);
	if (unlikely(!rt && !gotp->br_startblock && (*lastxp != NULLEXTNUM))) {
                cmn_err(CE_PANIC,"Access to block zero: fs: <%s> inode: %lld "
+18 −0
Original line number Diff line number Diff line
@@ -352,6 +352,24 @@ xfs_check_nostate_extents(
	xfs_extnum_t		idx,
	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	/* __XFS_BMAP_H__ */
+0 −8
Original line number Diff line number Diff line
@@ -372,14 +372,6 @@ extern int xfs_bmbt_get_rec(struct xfs_btree_cur *, xfs_fileoff_t *,
				xfs_exntst_t *, int *);
#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	/* __XFS_BMAP_BTREE_H__ */
+710 −5

File changed.

Preview size limit exceeded, changes collapsed.

+47 −5
Original line number Diff line number Diff line
@@ -24,9 +24,36 @@
#define	XFS_DATA_FORK	0
#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.
 */
#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_DATA		32
typedef struct xfs_ifork {
@@ -39,6 +66,7 @@ typedef struct xfs_ifork {
	xfs_extnum_t		if_lastex;	/* last if_extents used */
	union {
		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 */
	} if_u1;
	union {
@@ -61,9 +89,10 @@ typedef struct xfs_ifork {
/*
 * Per-fork incore inode flags.
 */
#define	XFS_IFINLINE	0x0001	/* Inline data is read in */
#define	XFS_IFEXTENTS	0x0002	/* All extent pointers are read in */
#define	XFS_IFBROOT	0x0004	/* i_broot points to the bmap b-tree root */
#define	XFS_IFINLINE	0x01	/* Inline data is read in */
#define	XFS_IFEXTENTS	0x02	/* All extent pointers are read in */
#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().
@@ -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,
				xfs_bmbt_irec_t *);
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_inline(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_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_inline_to_direct(xfs_ifork_t *, int);
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))