xref: /linux/fs/jfs/jfs_extent.c (revision 42249094f79422fbf5ed4b54eeb48ff096809b8f)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  *   Copyright (C) International Business Machines Corp., 2000-2004
31da177e4SLinus Torvalds  *
41da177e4SLinus Torvalds  *   This program is free software;  you can redistribute it and/or modify
51da177e4SLinus Torvalds  *   it under the terms of the GNU General Public License as published by
61da177e4SLinus Torvalds  *   the Free Software Foundation; either version 2 of the License, or
71da177e4SLinus Torvalds  *   (at your option) any later version.
81da177e4SLinus Torvalds  *
91da177e4SLinus Torvalds  *   This program is distributed in the hope that it will be useful,
101da177e4SLinus Torvalds  *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
111da177e4SLinus Torvalds  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
121da177e4SLinus Torvalds  *   the GNU General Public License for more details.
131da177e4SLinus Torvalds  *
141da177e4SLinus Torvalds  *   You should have received a copy of the GNU General Public License
151da177e4SLinus Torvalds  *   along with this program;  if not, write to the Free Software
161da177e4SLinus Torvalds  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
171da177e4SLinus Torvalds  */
181da177e4SLinus Torvalds 
191da177e4SLinus Torvalds #include <linux/fs.h>
201da177e4SLinus Torvalds #include <linux/quotaops.h>
211da177e4SLinus Torvalds #include "jfs_incore.h"
221868f4aaSDave Kleikamp #include "jfs_inode.h"
231da177e4SLinus Torvalds #include "jfs_superblock.h"
241da177e4SLinus Torvalds #include "jfs_dmap.h"
251da177e4SLinus Torvalds #include "jfs_extent.h"
261da177e4SLinus Torvalds #include "jfs_debug.h"
271da177e4SLinus Torvalds 
281da177e4SLinus Torvalds /*
291da177e4SLinus Torvalds  * forward references
301da177e4SLinus Torvalds  */
311da177e4SLinus Torvalds static int extBalloc(struct inode *, s64, s64 *, s64 *);
321da177e4SLinus Torvalds #ifdef _NOTYET
331da177e4SLinus Torvalds static int extBrealloc(struct inode *, s64, s64, s64 *, s64 *);
341da177e4SLinus Torvalds #endif
351da177e4SLinus Torvalds static s64 extRoundDown(s64 nb);
361da177e4SLinus Torvalds 
371da177e4SLinus Torvalds #define DPD(a)		(printk("(a): %d\n",(a)))
381da177e4SLinus Torvalds #define DPC(a)		(printk("(a): %c\n",(a)))
391da177e4SLinus Torvalds #define DPL1(a)					\
401da177e4SLinus Torvalds {						\
411da177e4SLinus Torvalds 	if ((a) >> 32)				\
421da177e4SLinus Torvalds 		printk("(a): %x%08x  ",(a));	\
431da177e4SLinus Torvalds 	else					\
441da177e4SLinus Torvalds 		printk("(a): %x  ",(a) << 32);	\
451da177e4SLinus Torvalds }
461da177e4SLinus Torvalds #define DPL(a)					\
471da177e4SLinus Torvalds {						\
481da177e4SLinus Torvalds 	if ((a) >> 32)				\
491da177e4SLinus Torvalds 		printk("(a): %x%08x\n",(a));	\
501da177e4SLinus Torvalds 	else					\
511da177e4SLinus Torvalds 		printk("(a): %x\n",(a) << 32);	\
521da177e4SLinus Torvalds }
531da177e4SLinus Torvalds 
541da177e4SLinus Torvalds #define DPD1(a)		(printk("(a): %d  ",(a)))
551da177e4SLinus Torvalds #define DPX(a)		(printk("(a): %08x\n",(a)))
561da177e4SLinus Torvalds #define DPX1(a)		(printk("(a): %08x  ",(a)))
571da177e4SLinus Torvalds #define DPS(a)		(printk("%s\n",(a)))
581da177e4SLinus Torvalds #define DPE(a)		(printk("\nENTERING: %s\n",(a)))
591da177e4SLinus Torvalds #define DPE1(a)		(printk("\nENTERING: %s",(a)))
601da177e4SLinus Torvalds #define DPS1(a)		(printk("  %s  ",(a)))
611da177e4SLinus Torvalds 
621da177e4SLinus Torvalds 
631da177e4SLinus Torvalds /*
641da177e4SLinus Torvalds  * NAME:	extAlloc()
651da177e4SLinus Torvalds  *
661da177e4SLinus Torvalds  * FUNCTION:	allocate an extent for a specified page range within a
671da177e4SLinus Torvalds  *		file.
681da177e4SLinus Torvalds  *
691da177e4SLinus Torvalds  * PARAMETERS:
701da177e4SLinus Torvalds  *	ip	- the inode of the file.
711da177e4SLinus Torvalds  *	xlen	- requested extent length.
721da177e4SLinus Torvalds  *	pno	- the starting page number with the file.
731da177e4SLinus Torvalds  *	xp	- pointer to an xad.  on entry, xad describes an
741da177e4SLinus Torvalds  *		  extent that is used as an allocation hint if the
751da177e4SLinus Torvalds  *		  xaddr of the xad is non-zero.  on successful exit,
761da177e4SLinus Torvalds  *		  the xad describes the newly allocated extent.
774d81715fSRichard Knutsson  *	abnr	- bool indicating whether the newly allocated extent
781da177e4SLinus Torvalds  *		  should be marked as allocated but not recorded.
791da177e4SLinus Torvalds  *
801da177e4SLinus Torvalds  * RETURN VALUES:
811da177e4SLinus Torvalds  *	0	- success
821da177e4SLinus Torvalds  *	-EIO	- i/o error.
831da177e4SLinus Torvalds  *	-ENOSPC	- insufficient disk resources.
841da177e4SLinus Torvalds  */
851da177e4SLinus Torvalds int
864d81715fSRichard Knutsson extAlloc(struct inode *ip, s64 xlen, s64 pno, xad_t * xp, bool abnr)
871da177e4SLinus Torvalds {
881da177e4SLinus Torvalds 	struct jfs_sb_info *sbi = JFS_SBI(ip->i_sb);
891da177e4SLinus Torvalds 	s64 nxlen, nxaddr, xoff, hint, xaddr = 0;
901da177e4SLinus Torvalds 	int rc;
911da177e4SLinus Torvalds 	int xflag;
921da177e4SLinus Torvalds 
931da177e4SLinus Torvalds 	/* This blocks if we are low on resources */
941da177e4SLinus Torvalds 	txBeginAnon(ip->i_sb);
951da177e4SLinus Torvalds 
961da177e4SLinus Torvalds 	/* Avoid race with jfs_commit_inode() */
971de87444SIngo Molnar 	mutex_lock(&JFS_IP(ip)->commit_mutex);
981da177e4SLinus Torvalds 
991da177e4SLinus Torvalds 	/* validate extent length */
1001da177e4SLinus Torvalds 	if (xlen > MAXXLEN)
1011da177e4SLinus Torvalds 		xlen = MAXXLEN;
1021da177e4SLinus Torvalds 
1031da177e4SLinus Torvalds 	/* get the page's starting extent offset */
1041da177e4SLinus Torvalds 	xoff = pno << sbi->l2nbperpage;
1051da177e4SLinus Torvalds 
1061da177e4SLinus Torvalds 	/* check if an allocation hint was provided */
1071da177e4SLinus Torvalds 	if ((hint = addressXAD(xp))) {
1081da177e4SLinus Torvalds 		/* get the size of the extent described by the hint */
1091da177e4SLinus Torvalds 		nxlen = lengthXAD(xp);
1101da177e4SLinus Torvalds 
1111da177e4SLinus Torvalds 		/* check if the hint is for the portion of the file
1121da177e4SLinus Torvalds 		 * immediately previous to the current allocation
1131da177e4SLinus Torvalds 		 * request and if hint extent has the same abnr
1141da177e4SLinus Torvalds 		 * value as the current request.  if so, we can
1151da177e4SLinus Torvalds 		 * extend the hint extent to include the current
1161da177e4SLinus Torvalds 		 * extent if we can allocate the blocks immediately
1171da177e4SLinus Torvalds 		 * following the hint extent.
1181da177e4SLinus Torvalds 		 */
1191da177e4SLinus Torvalds 		if (offsetXAD(xp) + nxlen == xoff &&
1204d81715fSRichard Knutsson 		    abnr == ((xp->flag & XAD_NOTRECORDED) ? true : false))
1211da177e4SLinus Torvalds 			xaddr = hint + nxlen;
1221da177e4SLinus Torvalds 
1231da177e4SLinus Torvalds 		/* adjust the hint to the last block of the extent */
1241da177e4SLinus Torvalds 		hint += (nxlen - 1);
1251da177e4SLinus Torvalds 	}
1261da177e4SLinus Torvalds 
1271da177e4SLinus Torvalds 	/* allocate the disk blocks for the extent.  initially, extBalloc()
1281da177e4SLinus Torvalds 	 * will try to allocate disk blocks for the requested size (xlen).
12925985edcSLucas De Marchi 	 * if this fails (xlen contiguous free blocks not available), it'll
1301da177e4SLinus Torvalds 	 * try to allocate a smaller number of blocks (producing a smaller
1311da177e4SLinus Torvalds 	 * extent), with this smaller number of blocks consisting of the
1321da177e4SLinus Torvalds 	 * requested number of blocks rounded down to the next smaller
1331da177e4SLinus Torvalds 	 * power of 2 number (i.e. 16 -> 8).  it'll continue to round down
1341da177e4SLinus Torvalds 	 * and retry the allocation until the number of blocks to allocate
1351da177e4SLinus Torvalds 	 * is smaller than the number of blocks per page.
1361da177e4SLinus Torvalds 	 */
1371da177e4SLinus Torvalds 	nxlen = xlen;
1381da177e4SLinus Torvalds 	if ((rc = extBalloc(ip, hint ? hint : INOHINT(ip), &nxlen, &nxaddr))) {
1391de87444SIngo Molnar 		mutex_unlock(&JFS_IP(ip)->commit_mutex);
1401da177e4SLinus Torvalds 		return (rc);
1411da177e4SLinus Torvalds 	}
1421da177e4SLinus Torvalds 
1431da177e4SLinus Torvalds 	/* Allocate blocks to quota. */
1445dd4056dSChristoph Hellwig 	rc = dquot_alloc_block(ip, nxlen);
1455dd4056dSChristoph Hellwig 	if (rc) {
1461da177e4SLinus Torvalds 		dbFree(ip, nxaddr, (s64) nxlen);
1471de87444SIngo Molnar 		mutex_unlock(&JFS_IP(ip)->commit_mutex);
1485dd4056dSChristoph Hellwig 		return rc;
1491da177e4SLinus Torvalds 	}
1501da177e4SLinus Torvalds 
1511da177e4SLinus Torvalds 	/* determine the value of the extent flag */
1524d81715fSRichard Knutsson 	xflag = abnr ? XAD_NOTRECORDED : 0;
1531da177e4SLinus Torvalds 
1541da177e4SLinus Torvalds 	/* if we can extend the hint extent to cover the current request,
1551da177e4SLinus Torvalds 	 * extend it.  otherwise, insert a new extent to
1561da177e4SLinus Torvalds 	 * cover the current request.
1571da177e4SLinus Torvalds 	 */
1581da177e4SLinus Torvalds 	if (xaddr && xaddr == nxaddr)
1591da177e4SLinus Torvalds 		rc = xtExtend(0, ip, xoff, (int) nxlen, 0);
1601da177e4SLinus Torvalds 	else
1611da177e4SLinus Torvalds 		rc = xtInsert(0, ip, xflag, xoff, (int) nxlen, &nxaddr, 0);
1621da177e4SLinus Torvalds 
1631da177e4SLinus Torvalds 	/* if the extend or insert failed,
1641da177e4SLinus Torvalds 	 * free the newly allocated blocks and return the error.
1651da177e4SLinus Torvalds 	 */
1661da177e4SLinus Torvalds 	if (rc) {
1671da177e4SLinus Torvalds 		dbFree(ip, nxaddr, nxlen);
1685dd4056dSChristoph Hellwig 		dquot_free_block(ip, nxlen);
1691de87444SIngo Molnar 		mutex_unlock(&JFS_IP(ip)->commit_mutex);
1701da177e4SLinus Torvalds 		return (rc);
1711da177e4SLinus Torvalds 	}
1721da177e4SLinus Torvalds 
1731da177e4SLinus Torvalds 	/* set the results of the extent allocation */
1741da177e4SLinus Torvalds 	XADaddress(xp, nxaddr);
1751da177e4SLinus Torvalds 	XADlength(xp, nxlen);
1761da177e4SLinus Torvalds 	XADoffset(xp, xoff);
1771da177e4SLinus Torvalds 	xp->flag = xflag;
1781da177e4SLinus Torvalds 
1791da177e4SLinus Torvalds 	mark_inode_dirty(ip);
1801da177e4SLinus Torvalds 
1811de87444SIngo Molnar 	mutex_unlock(&JFS_IP(ip)->commit_mutex);
1821da177e4SLinus Torvalds 	/*
1831da177e4SLinus Torvalds 	 * COMMIT_SyncList flags an anonymous tlock on page that is on
1841da177e4SLinus Torvalds 	 * sync list.
1851da177e4SLinus Torvalds 	 * We need to commit the inode to get the page written disk.
1861da177e4SLinus Torvalds 	 */
1871da177e4SLinus Torvalds 	if (test_and_clear_cflag(COMMIT_Synclist,ip))
1881da177e4SLinus Torvalds 		jfs_commit_inode(ip, 0);
1891da177e4SLinus Torvalds 
1901da177e4SLinus Torvalds 	return (0);
1911da177e4SLinus Torvalds }
1921da177e4SLinus Torvalds 
1931da177e4SLinus Torvalds 
1941da177e4SLinus Torvalds #ifdef _NOTYET
1951da177e4SLinus Torvalds /*
1961da177e4SLinus Torvalds  * NAME:	extRealloc()
1971da177e4SLinus Torvalds  *
1981da177e4SLinus Torvalds  * FUNCTION:	extend the allocation of a file extent containing a
1991da177e4SLinus Torvalds  *		partial back last page.
2001da177e4SLinus Torvalds  *
2011da177e4SLinus Torvalds  * PARAMETERS:
2021da177e4SLinus Torvalds  *	ip	- the inode of the file.
2031da177e4SLinus Torvalds  *	cp	- cbuf for the partial backed last page.
2041da177e4SLinus Torvalds  *	xlen	- request size of the resulting extent.
2051da177e4SLinus Torvalds  *	xp	- pointer to an xad. on successful exit, the xad
2061da177e4SLinus Torvalds  *		  describes the newly allocated extent.
2074d81715fSRichard Knutsson  *	abnr	- bool indicating whether the newly allocated extent
2081da177e4SLinus Torvalds  *		  should be marked as allocated but not recorded.
2091da177e4SLinus Torvalds  *
2101da177e4SLinus Torvalds  * RETURN VALUES:
2111da177e4SLinus Torvalds  *	0	- success
2121da177e4SLinus Torvalds  *	-EIO	- i/o error.
2131da177e4SLinus Torvalds  *	-ENOSPC	- insufficient disk resources.
2141da177e4SLinus Torvalds  */
2154d81715fSRichard Knutsson int extRealloc(struct inode *ip, s64 nxlen, xad_t * xp, bool abnr)
2161da177e4SLinus Torvalds {
2171da177e4SLinus Torvalds 	struct super_block *sb = ip->i_sb;
2181da177e4SLinus Torvalds 	s64 xaddr, xlen, nxaddr, delta, xoff;
2191da177e4SLinus Torvalds 	s64 ntail, nextend, ninsert;
2201da177e4SLinus Torvalds 	int rc, nbperpage = JFS_SBI(sb)->nbperpage;
2211da177e4SLinus Torvalds 	int xflag;
2221da177e4SLinus Torvalds 
2231da177e4SLinus Torvalds 	/* This blocks if we are low on resources */
2241da177e4SLinus Torvalds 	txBeginAnon(ip->i_sb);
2251da177e4SLinus Torvalds 
2261de87444SIngo Molnar 	mutex_lock(&JFS_IP(ip)->commit_mutex);
2271da177e4SLinus Torvalds 	/* validate extent length */
2281da177e4SLinus Torvalds 	if (nxlen > MAXXLEN)
2291da177e4SLinus Torvalds 		nxlen = MAXXLEN;
2301da177e4SLinus Torvalds 
2311da177e4SLinus Torvalds 	/* get the extend (partial) page's disk block address and
2321da177e4SLinus Torvalds 	 * number of blocks.
2331da177e4SLinus Torvalds 	 */
2341da177e4SLinus Torvalds 	xaddr = addressXAD(xp);
2351da177e4SLinus Torvalds 	xlen = lengthXAD(xp);
2361da177e4SLinus Torvalds 	xoff = offsetXAD(xp);
2371da177e4SLinus Torvalds 
2381da177e4SLinus Torvalds 	/* if the extend page is abnr and if the request is for
2391da177e4SLinus Torvalds 	 * the extent to be allocated and recorded,
2401da177e4SLinus Torvalds 	 * make the page allocated and recorded.
2411da177e4SLinus Torvalds 	 */
2421da177e4SLinus Torvalds 	if ((xp->flag & XAD_NOTRECORDED) && !abnr) {
2431da177e4SLinus Torvalds 		xp->flag = 0;
2441da177e4SLinus Torvalds 		if ((rc = xtUpdate(0, ip, xp)))
2451da177e4SLinus Torvalds 			goto exit;
2461da177e4SLinus Torvalds 	}
2471da177e4SLinus Torvalds 
2481da177e4SLinus Torvalds 	/* try to allocated the request number of blocks for the
2491da177e4SLinus Torvalds 	 * extent.  dbRealloc() first tries to satisfy the request
2501da177e4SLinus Torvalds 	 * by extending the allocation in place. otherwise, it will
2511da177e4SLinus Torvalds 	 * try to allocate a new set of blocks large enough for the
2521da177e4SLinus Torvalds 	 * request.  in satisfying a request, dbReAlloc() may allocate
2531da177e4SLinus Torvalds 	 * less than what was request but will always allocate enough
2541da177e4SLinus Torvalds 	 * space as to satisfy the extend page.
2551da177e4SLinus Torvalds 	 */
2561da177e4SLinus Torvalds 	if ((rc = extBrealloc(ip, xaddr, xlen, &nxlen, &nxaddr)))
2571da177e4SLinus Torvalds 		goto exit;
2581da177e4SLinus Torvalds 
2591da177e4SLinus Torvalds 	/* Allocat blocks to quota. */
2605dd4056dSChristoph Hellwig 	rc = dquot_alloc_block(ip, nxlen);
2615dd4056dSChristoph Hellwig 	if (rc) {
2621da177e4SLinus Torvalds 		dbFree(ip, nxaddr, (s64) nxlen);
2631de87444SIngo Molnar 		mutex_unlock(&JFS_IP(ip)->commit_mutex);
2645dd4056dSChristoph Hellwig 		return rc;
2651da177e4SLinus Torvalds 	}
2661da177e4SLinus Torvalds 
2671da177e4SLinus Torvalds 	delta = nxlen - xlen;
2681da177e4SLinus Torvalds 
2691da177e4SLinus Torvalds 	/* check if the extend page is not abnr but the request is abnr
2701da177e4SLinus Torvalds 	 * and the allocated disk space is for more than one page.  if this
2711da177e4SLinus Torvalds 	 * is the case, there is a miss match of abnr between the extend page
2721da177e4SLinus Torvalds 	 * and the one or more pages following the extend page.  as a result,
2731da177e4SLinus Torvalds 	 * two extents will have to be manipulated. the first will be that
2741da177e4SLinus Torvalds 	 * of the extent of the extend page and will be manipulated thru
2751da177e4SLinus Torvalds 	 * an xtExtend() or an xtTailgate(), depending upon whether the
2761da177e4SLinus Torvalds 	 * disk allocation occurred as an inplace extension.  the second
2771da177e4SLinus Torvalds 	 * extent will be manipulated (created) through an xtInsert() and
2781da177e4SLinus Torvalds 	 * will be for the pages following the extend page.
2791da177e4SLinus Torvalds 	 */
2801da177e4SLinus Torvalds 	if (abnr && (!(xp->flag & XAD_NOTRECORDED)) && (nxlen > nbperpage)) {
2811da177e4SLinus Torvalds 		ntail = nbperpage;
2821da177e4SLinus Torvalds 		nextend = ntail - xlen;
2831da177e4SLinus Torvalds 		ninsert = nxlen - nbperpage;
2841da177e4SLinus Torvalds 
2851da177e4SLinus Torvalds 		xflag = XAD_NOTRECORDED;
2861da177e4SLinus Torvalds 	} else {
2871da177e4SLinus Torvalds 		ntail = nxlen;
2881da177e4SLinus Torvalds 		nextend = delta;
2891da177e4SLinus Torvalds 		ninsert = 0;
2901da177e4SLinus Torvalds 
2911da177e4SLinus Torvalds 		xflag = xp->flag;
2921da177e4SLinus Torvalds 	}
2931da177e4SLinus Torvalds 
2941da177e4SLinus Torvalds 	/* if we were able to extend the disk allocation in place,
2951da177e4SLinus Torvalds 	 * extend the extent.  otherwise, move the extent to a
2961da177e4SLinus Torvalds 	 * new disk location.
2971da177e4SLinus Torvalds 	 */
2981da177e4SLinus Torvalds 	if (xaddr == nxaddr) {
2991da177e4SLinus Torvalds 		/* extend the extent */
3001da177e4SLinus Torvalds 		if ((rc = xtExtend(0, ip, xoff + xlen, (int) nextend, 0))) {
3011da177e4SLinus Torvalds 			dbFree(ip, xaddr + xlen, delta);
3025dd4056dSChristoph Hellwig 			dquot_free_block(ip, nxlen);
3031da177e4SLinus Torvalds 			goto exit;
3041da177e4SLinus Torvalds 		}
3051da177e4SLinus Torvalds 	} else {
3061da177e4SLinus Torvalds 		/*
3071da177e4SLinus Torvalds 		 * move the extent to a new location:
3081da177e4SLinus Torvalds 		 *
3091da177e4SLinus Torvalds 		 * xtTailgate() accounts for relocated tail extent;
3101da177e4SLinus Torvalds 		 */
3111da177e4SLinus Torvalds 		if ((rc = xtTailgate(0, ip, xoff, (int) ntail, nxaddr, 0))) {
3121da177e4SLinus Torvalds 			dbFree(ip, nxaddr, nxlen);
3135dd4056dSChristoph Hellwig 			dquot_free_block(ip, nxlen);
3141da177e4SLinus Torvalds 			goto exit;
3151da177e4SLinus Torvalds 		}
3161da177e4SLinus Torvalds 	}
3171da177e4SLinus Torvalds 
3181da177e4SLinus Torvalds 
3191da177e4SLinus Torvalds 	/* check if we need to also insert a new extent */
3201da177e4SLinus Torvalds 	if (ninsert) {
3211da177e4SLinus Torvalds 		/* perform the insert.  if it fails, free the blocks
3221da177e4SLinus Torvalds 		 * to be inserted and make it appear that we only did
3231da177e4SLinus Torvalds 		 * the xtExtend() or xtTailgate() above.
3241da177e4SLinus Torvalds 		 */
3251da177e4SLinus Torvalds 		xaddr = nxaddr + ntail;
3261da177e4SLinus Torvalds 		if (xtInsert (0, ip, xflag, xoff + ntail, (int) ninsert,
3271da177e4SLinus Torvalds 			      &xaddr, 0)) {
3281da177e4SLinus Torvalds 			dbFree(ip, xaddr, (s64) ninsert);
3291da177e4SLinus Torvalds 			delta = nextend;
3301da177e4SLinus Torvalds 			nxlen = ntail;
3311da177e4SLinus Torvalds 			xflag = 0;
3321da177e4SLinus Torvalds 		}
3331da177e4SLinus Torvalds 	}
3341da177e4SLinus Torvalds 
3351da177e4SLinus Torvalds 	/* set the return results */
3361da177e4SLinus Torvalds 	XADaddress(xp, nxaddr);
3371da177e4SLinus Torvalds 	XADlength(xp, nxlen);
3381da177e4SLinus Torvalds 	XADoffset(xp, xoff);
3391da177e4SLinus Torvalds 	xp->flag = xflag;
3401da177e4SLinus Torvalds 
3411da177e4SLinus Torvalds 	mark_inode_dirty(ip);
3421da177e4SLinus Torvalds exit:
3431de87444SIngo Molnar 	mutex_unlock(&JFS_IP(ip)->commit_mutex);
3441da177e4SLinus Torvalds 	return (rc);
3451da177e4SLinus Torvalds }
3461da177e4SLinus Torvalds #endif			/* _NOTYET */
3471da177e4SLinus Torvalds 
3481da177e4SLinus Torvalds 
3491da177e4SLinus Torvalds /*
3501da177e4SLinus Torvalds  * NAME:	extHint()
3511da177e4SLinus Torvalds  *
3521da177e4SLinus Torvalds  * FUNCTION:	produce an extent allocation hint for a file offset.
3531da177e4SLinus Torvalds  *
3541da177e4SLinus Torvalds  * PARAMETERS:
3551da177e4SLinus Torvalds  *	ip	- the inode of the file.
3561da177e4SLinus Torvalds  *	offset  - file offset for which the hint is needed.
3571da177e4SLinus Torvalds  *	xp	- pointer to the xad that is to be filled in with
3581da177e4SLinus Torvalds  *		  the hint.
3591da177e4SLinus Torvalds  *
3601da177e4SLinus Torvalds  * RETURN VALUES:
3611da177e4SLinus Torvalds  *	0	- success
3621da177e4SLinus Torvalds  *	-EIO	- i/o error.
3631da177e4SLinus Torvalds  */
3641da177e4SLinus Torvalds int extHint(struct inode *ip, s64 offset, xad_t * xp)
3651da177e4SLinus Torvalds {
3661da177e4SLinus Torvalds 	struct super_block *sb = ip->i_sb;
367fec1878fSDave Kleikamp 	int nbperpage = JFS_SBI(sb)->nbperpage;
3681da177e4SLinus Torvalds 	s64 prev;
369fec1878fSDave Kleikamp 	int rc = 0;
370fec1878fSDave Kleikamp 	s64 xaddr;
371fec1878fSDave Kleikamp 	int xlen;
372fec1878fSDave Kleikamp 	int xflag;
3731da177e4SLinus Torvalds 
3741da177e4SLinus Torvalds 	/* init the hint as "no hint provided" */
3751da177e4SLinus Torvalds 	XADaddress(xp, 0);
3761da177e4SLinus Torvalds 
3771da177e4SLinus Torvalds 	/* determine the starting extent offset of the page previous
3781da177e4SLinus Torvalds 	 * to the page containing the offset.
3791da177e4SLinus Torvalds 	 */
3801da177e4SLinus Torvalds 	prev = ((offset & ~POFFSET) >> JFS_SBI(sb)->l2bsize) - nbperpage;
3811da177e4SLinus Torvalds 
382fec1878fSDave Kleikamp 	/* if the offset is in the first page of the file, no hint provided.
3831da177e4SLinus Torvalds 	 */
3841da177e4SLinus Torvalds 	if (prev < 0)
385fec1878fSDave Kleikamp 		goto out;
3861da177e4SLinus Torvalds 
387fec1878fSDave Kleikamp 	rc = xtLookup(ip, prev, nbperpage, &xflag, &xaddr, &xlen, 0);
3881da177e4SLinus Torvalds 
389fec1878fSDave Kleikamp 	if ((rc == 0) && xlen) {
390fec1878fSDave Kleikamp 		if (xlen != nbperpage) {
391*eb8630d7SJoe Perches 			jfs_error(ip->i_sb, "corrupt xtree\n");
392fec1878fSDave Kleikamp 			rc = -EIO;
3931da177e4SLinus Torvalds 		}
394fec1878fSDave Kleikamp 		XADaddress(xp, xaddr);
395fec1878fSDave Kleikamp 		XADlength(xp, xlen);
396f7c52fd1SDave Kleikamp 		XADoffset(xp, prev);
397fec1878fSDave Kleikamp 		/*
398fec1878fSDave Kleikamp 		 * only preserve the abnr flag within the xad flags
3991da177e4SLinus Torvalds 		 * of the returned hint.
4001da177e4SLinus Torvalds 		 */
401fec1878fSDave Kleikamp 		xp->flag  = xflag & XAD_NOTRECORDED;
402fec1878fSDave Kleikamp 	} else
403fec1878fSDave Kleikamp 		rc = 0;
4041da177e4SLinus Torvalds 
405fec1878fSDave Kleikamp out:
406fec1878fSDave Kleikamp 	return (rc);
4071da177e4SLinus Torvalds }
4081da177e4SLinus Torvalds 
4091da177e4SLinus Torvalds 
4101da177e4SLinus Torvalds /*
4111da177e4SLinus Torvalds  * NAME:	extRecord()
4121da177e4SLinus Torvalds  *
4131da177e4SLinus Torvalds  * FUNCTION:	change a page with a file from not recorded to recorded.
4141da177e4SLinus Torvalds  *
4151da177e4SLinus Torvalds  * PARAMETERS:
4161da177e4SLinus Torvalds  *	ip	- inode of the file.
4171da177e4SLinus Torvalds  *	cp	- cbuf of the file page.
4181da177e4SLinus Torvalds  *
4191da177e4SLinus Torvalds  * RETURN VALUES:
4201da177e4SLinus Torvalds  *	0	- success
4211da177e4SLinus Torvalds  *	-EIO	- i/o error.
4221da177e4SLinus Torvalds  *	-ENOSPC	- insufficient disk resources.
4231da177e4SLinus Torvalds  */
4241da177e4SLinus Torvalds int extRecord(struct inode *ip, xad_t * xp)
4251da177e4SLinus Torvalds {
4261da177e4SLinus Torvalds 	int rc;
4271da177e4SLinus Torvalds 
4281da177e4SLinus Torvalds 	txBeginAnon(ip->i_sb);
4291da177e4SLinus Torvalds 
4301de87444SIngo Molnar 	mutex_lock(&JFS_IP(ip)->commit_mutex);
4311da177e4SLinus Torvalds 
4321da177e4SLinus Torvalds 	/* update the extent */
4331da177e4SLinus Torvalds 	rc = xtUpdate(0, ip, xp);
4341da177e4SLinus Torvalds 
4351de87444SIngo Molnar 	mutex_unlock(&JFS_IP(ip)->commit_mutex);
4361da177e4SLinus Torvalds 	return rc;
4371da177e4SLinus Torvalds }
4381da177e4SLinus Torvalds 
4391da177e4SLinus Torvalds 
4401da177e4SLinus Torvalds #ifdef _NOTYET
4411da177e4SLinus Torvalds /*
4421da177e4SLinus Torvalds  * NAME:	extFill()
4431da177e4SLinus Torvalds  *
4441da177e4SLinus Torvalds  * FUNCTION:	allocate disk space for a file page that represents
4451da177e4SLinus Torvalds  *		a file hole.
4461da177e4SLinus Torvalds  *
4471da177e4SLinus Torvalds  * PARAMETERS:
4481da177e4SLinus Torvalds  *	ip	- the inode of the file.
4491da177e4SLinus Torvalds  *	cp	- cbuf of the file page represent the hole.
4501da177e4SLinus Torvalds  *
4511da177e4SLinus Torvalds  * RETURN VALUES:
4521da177e4SLinus Torvalds  *	0	- success
4531da177e4SLinus Torvalds  *	-EIO	- i/o error.
4541da177e4SLinus Torvalds  *	-ENOSPC	- insufficient disk resources.
4551da177e4SLinus Torvalds  */
4561da177e4SLinus Torvalds int extFill(struct inode *ip, xad_t * xp)
4571da177e4SLinus Torvalds {
4581da177e4SLinus Torvalds 	int rc, nbperpage = JFS_SBI(ip->i_sb)->nbperpage;
459ba52de12STheodore Ts'o 	s64 blkno = offsetXAD(xp) >> ip->i_blkbits;
4601da177e4SLinus Torvalds 
4611da177e4SLinus Torvalds //	assert(ISSPARSE(ip));
4621da177e4SLinus Torvalds 
4631da177e4SLinus Torvalds 	/* initialize the extent allocation hint */
4641da177e4SLinus Torvalds 	XADaddress(xp, 0);
4651da177e4SLinus Torvalds 
4661da177e4SLinus Torvalds 	/* allocate an extent to fill the hole */
4674d81715fSRichard Knutsson 	if ((rc = extAlloc(ip, nbperpage, blkno, xp, false)))
4681da177e4SLinus Torvalds 		return (rc);
4691da177e4SLinus Torvalds 
4701da177e4SLinus Torvalds 	assert(lengthPXD(xp) == nbperpage);
4711da177e4SLinus Torvalds 
4721da177e4SLinus Torvalds 	return (0);
4731da177e4SLinus Torvalds }
4741da177e4SLinus Torvalds #endif			/* _NOTYET */
4751da177e4SLinus Torvalds 
4761da177e4SLinus Torvalds 
4771da177e4SLinus Torvalds /*
4781da177e4SLinus Torvalds  * NAME:	extBalloc()
4791da177e4SLinus Torvalds  *
4801da177e4SLinus Torvalds  * FUNCTION:	allocate disk blocks to form an extent.
4811da177e4SLinus Torvalds  *
4821da177e4SLinus Torvalds  *		initially, we will try to allocate disk blocks for the
4831da177e4SLinus Torvalds  *		requested size (nblocks).  if this fails (nblocks
48425985edcSLucas De Marchi  *		contiguous free blocks not available), we'll try to allocate
4851da177e4SLinus Torvalds  *		a smaller number of blocks (producing a smaller extent), with
4861da177e4SLinus Torvalds  *		this smaller number of blocks consisting of the requested
4871da177e4SLinus Torvalds  *		number of blocks rounded down to the next smaller power of 2
4881da177e4SLinus Torvalds  *		number (i.e. 16 -> 8).  we'll continue to round down and
4891da177e4SLinus Torvalds  *		retry the allocation until the number of blocks to allocate
4901da177e4SLinus Torvalds  *		is smaller than the number of blocks per page.
4911da177e4SLinus Torvalds  *
4921da177e4SLinus Torvalds  * PARAMETERS:
4931da177e4SLinus Torvalds  *	ip	 - the inode of the file.
4941da177e4SLinus Torvalds  *	hint	 - disk block number to be used as an allocation hint.
4951da177e4SLinus Torvalds  *	*nblocks - pointer to an s64 value.  on entry, this value specifies
4961da177e4SLinus Torvalds  *		   the desired number of block to be allocated. on successful
4971da177e4SLinus Torvalds  *		   exit, this value is set to the number of blocks actually
4981da177e4SLinus Torvalds  *		   allocated.
4991da177e4SLinus Torvalds  *	blkno	 - pointer to a block address that is filled in on successful
5001da177e4SLinus Torvalds  *		   return with the starting block number of the newly
5011da177e4SLinus Torvalds  *		   allocated block range.
5021da177e4SLinus Torvalds  *
5031da177e4SLinus Torvalds  * RETURN VALUES:
5041da177e4SLinus Torvalds  *	0	- success
5051da177e4SLinus Torvalds  *	-EIO	- i/o error.
5061da177e4SLinus Torvalds  *	-ENOSPC	- insufficient disk resources.
5071da177e4SLinus Torvalds  */
5081da177e4SLinus Torvalds static int
5091da177e4SLinus Torvalds extBalloc(struct inode *ip, s64 hint, s64 * nblocks, s64 * blkno)
5101da177e4SLinus Torvalds {
5111da177e4SLinus Torvalds 	struct jfs_inode_info *ji = JFS_IP(ip);
5121da177e4SLinus Torvalds 	struct jfs_sb_info *sbi = JFS_SBI(ip->i_sb);
5131da177e4SLinus Torvalds 	s64 nb, nblks, daddr, max;
5141da177e4SLinus Torvalds 	int rc, nbperpage = sbi->nbperpage;
5151da177e4SLinus Torvalds 	struct bmap *bmp = sbi->bmap;
5161da177e4SLinus Torvalds 	int ag;
5171da177e4SLinus Torvalds 
5181da177e4SLinus Torvalds 	/* get the number of blocks to initially attempt to allocate.
5191da177e4SLinus Torvalds 	 * we'll first try the number of blocks requested unless this
520d6e05edcSAndreas Mohr 	 * number is greater than the maximum number of contiguous free
5211da177e4SLinus Torvalds 	 * blocks in the map. in that case, we'll start off with the
5221da177e4SLinus Torvalds 	 * maximum free.
5231da177e4SLinus Torvalds 	 */
5241da177e4SLinus Torvalds 	max = (s64) 1 << bmp->db_maxfreebud;
5251da177e4SLinus Torvalds 	if (*nblocks >= max && *nblocks > nbperpage)
5261da177e4SLinus Torvalds 		nb = nblks = (max > nbperpage) ? max : nbperpage;
5271da177e4SLinus Torvalds 	else
5281da177e4SLinus Torvalds 		nb = nblks = *nblocks;
5291da177e4SLinus Torvalds 
5301da177e4SLinus Torvalds 	/* try to allocate blocks */
5311da177e4SLinus Torvalds 	while ((rc = dbAlloc(ip, hint, nb, &daddr)) != 0) {
5321da177e4SLinus Torvalds 		/* if something other than an out of space error,
5331da177e4SLinus Torvalds 		 * stop and return this error.
5341da177e4SLinus Torvalds 		 */
5351da177e4SLinus Torvalds 		if (rc != -ENOSPC)
5361da177e4SLinus Torvalds 			return (rc);
5371da177e4SLinus Torvalds 
5381da177e4SLinus Torvalds 		/* decrease the allocation request size */
5391da177e4SLinus Torvalds 		nb = min(nblks, extRoundDown(nb));
5401da177e4SLinus Torvalds 
5411da177e4SLinus Torvalds 		/* give up if we cannot cover a page */
5421da177e4SLinus Torvalds 		if (nb < nbperpage)
5431da177e4SLinus Torvalds 			return (rc);
5441da177e4SLinus Torvalds 	}
5451da177e4SLinus Torvalds 
5461da177e4SLinus Torvalds 	*nblocks = nb;
5471da177e4SLinus Torvalds 	*blkno = daddr;
5481da177e4SLinus Torvalds 
5491da177e4SLinus Torvalds 	if (S_ISREG(ip->i_mode) && (ji->fileset == FILESYSTEM_I)) {
5501da177e4SLinus Torvalds 		ag = BLKTOAG(daddr, sbi);
5511da177e4SLinus Torvalds 		spin_lock_irq(&ji->ag_lock);
5521da177e4SLinus Torvalds 		if (ji->active_ag == -1) {
5531da177e4SLinus Torvalds 			atomic_inc(&bmp->db_active[ag]);
5541da177e4SLinus Torvalds 			ji->active_ag = ag;
5551da177e4SLinus Torvalds 		} else if (ji->active_ag != ag) {
5561da177e4SLinus Torvalds 			atomic_dec(&bmp->db_active[ji->active_ag]);
5571da177e4SLinus Torvalds 			atomic_inc(&bmp->db_active[ag]);
5581da177e4SLinus Torvalds 			ji->active_ag = ag;
5591da177e4SLinus Torvalds 		}
5601da177e4SLinus Torvalds 		spin_unlock_irq(&ji->ag_lock);
5611da177e4SLinus Torvalds 	}
5621da177e4SLinus Torvalds 
5631da177e4SLinus Torvalds 	return (0);
5641da177e4SLinus Torvalds }
5651da177e4SLinus Torvalds 
5661da177e4SLinus Torvalds 
5671da177e4SLinus Torvalds #ifdef _NOTYET
5681da177e4SLinus Torvalds /*
5691da177e4SLinus Torvalds  * NAME:	extBrealloc()
5701da177e4SLinus Torvalds  *
5711da177e4SLinus Torvalds  * FUNCTION:	attempt to extend an extent's allocation.
5721da177e4SLinus Torvalds  *
57363f83c9fSDave Kleikamp  *		Initially, we will try to extend the extent's allocation
57463f83c9fSDave Kleikamp  *		in place.  If this fails, we'll try to move the extent
57563f83c9fSDave Kleikamp  *		to a new set of blocks.  If moving the extent, we initially
5761da177e4SLinus Torvalds  *		will try to allocate disk blocks for the requested size
57763f83c9fSDave Kleikamp  *		(newnblks).  if this fails (new contiguous free blocks not
57825985edcSLucas De Marchi  *		available), we'll try to allocate a smaller number of
5791da177e4SLinus Torvalds  *		blocks (producing a smaller extent), with this smaller
5801da177e4SLinus Torvalds  *		number of blocks consisting of the requested number of
5811da177e4SLinus Torvalds  *		blocks rounded down to the next smaller power of 2
58263f83c9fSDave Kleikamp  *		number (i.e. 16 -> 8).  We'll continue to round down and
5831da177e4SLinus Torvalds  *		retry the allocation until the number of blocks to allocate
5841da177e4SLinus Torvalds  *		is smaller than the number of blocks per page.
5851da177e4SLinus Torvalds  *
5861da177e4SLinus Torvalds  * PARAMETERS:
5871da177e4SLinus Torvalds  *	ip	 - the inode of the file.
5881da177e4SLinus Torvalds  *	blkno	 - starting block number of the extents current allocation.
5891da177e4SLinus Torvalds  *	nblks	 - number of blocks within the extents current allocation.
5901da177e4SLinus Torvalds  *	newnblks - pointer to a s64 value.  on entry, this value is the
5911da177e4SLinus Torvalds  *		   the new desired extent size (number of blocks).  on
5921da177e4SLinus Torvalds  *		   successful exit, this value is set to the extent's actual
5931da177e4SLinus Torvalds  *		   new size (new number of blocks).
5941da177e4SLinus Torvalds  *	newblkno - the starting block number of the extents new allocation.
5951da177e4SLinus Torvalds  *
5961da177e4SLinus Torvalds  * RETURN VALUES:
5971da177e4SLinus Torvalds  *	0	- success
5981da177e4SLinus Torvalds  *	-EIO	- i/o error.
5991da177e4SLinus Torvalds  *	-ENOSPC	- insufficient disk resources.
6001da177e4SLinus Torvalds  */
6011da177e4SLinus Torvalds static int
6021da177e4SLinus Torvalds extBrealloc(struct inode *ip,
6031da177e4SLinus Torvalds 	    s64 blkno, s64 nblks, s64 * newnblks, s64 * newblkno)
6041da177e4SLinus Torvalds {
6051da177e4SLinus Torvalds 	int rc;
6061da177e4SLinus Torvalds 
6071da177e4SLinus Torvalds 	/* try to extend in place */
6081da177e4SLinus Torvalds 	if ((rc = dbExtend(ip, blkno, nblks, *newnblks - nblks)) == 0) {
6091da177e4SLinus Torvalds 		*newblkno = blkno;
6101da177e4SLinus Torvalds 		return (0);
6111da177e4SLinus Torvalds 	} else {
6121da177e4SLinus Torvalds 		if (rc != -ENOSPC)
6131da177e4SLinus Torvalds 			return (rc);
6141da177e4SLinus Torvalds 	}
6151da177e4SLinus Torvalds 
6161da177e4SLinus Torvalds 	/* in place extension not possible.
6171da177e4SLinus Torvalds 	 * try to move the extent to a new set of blocks.
6181da177e4SLinus Torvalds 	 */
6191da177e4SLinus Torvalds 	return (extBalloc(ip, blkno, newnblks, newblkno));
6201da177e4SLinus Torvalds }
6211da177e4SLinus Torvalds #endif			/* _NOTYET */
6221da177e4SLinus Torvalds 
6231da177e4SLinus Torvalds 
6241da177e4SLinus Torvalds /*
6251da177e4SLinus Torvalds  * NAME:	extRoundDown()
6261da177e4SLinus Torvalds  *
6271da177e4SLinus Torvalds  * FUNCTION:	round down a specified number of blocks to the next
6281da177e4SLinus Torvalds  *		smallest power of 2 number.
6291da177e4SLinus Torvalds  *
6301da177e4SLinus Torvalds  * PARAMETERS:
6311da177e4SLinus Torvalds  *	nb	- the inode of the file.
6321da177e4SLinus Torvalds  *
6331da177e4SLinus Torvalds  * RETURN VALUES:
6341da177e4SLinus Torvalds  *	next smallest power of 2 number.
6351da177e4SLinus Torvalds  */
6361da177e4SLinus Torvalds static s64 extRoundDown(s64 nb)
6371da177e4SLinus Torvalds {
6381da177e4SLinus Torvalds 	int i;
6391da177e4SLinus Torvalds 	u64 m, k;
6401da177e4SLinus Torvalds 
6411da177e4SLinus Torvalds 	for (i = 0, m = (u64) 1 << 63; i < 64; i++, m >>= 1) {
6421da177e4SLinus Torvalds 		if (m & nb)
6431da177e4SLinus Torvalds 			break;
6441da177e4SLinus Torvalds 	}
6451da177e4SLinus Torvalds 
6461da177e4SLinus Torvalds 	i = 63 - i;
6471da177e4SLinus Torvalds 	k = (u64) 1 << i;
6481da177e4SLinus Torvalds 	k = ((k - 1) & nb) ? k : k >> 1;
6491da177e4SLinus Torvalds 
6501da177e4SLinus Torvalds 	return (k);
6511da177e4SLinus Torvalds }
652