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