jfs_extent.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:18k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  *   Copyright (c) International Business Machines Corp., 2000-2002
  3.  *
  4.  *   This program is free software;  you can redistribute it and/or modify
  5.  *   it under the terms of the GNU General Public License as published by
  6.  *   the Free Software Foundation; either version 2 of the License, or 
  7.  *   (at your option) any later version.
  8.  * 
  9.  *   This program is distributed in the hope that it will be useful,
  10.  *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
  11.  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
  12.  *   the GNU General Public License for more details.
  13.  *
  14.  *   You should have received a copy of the GNU General Public License
  15.  *   along with this program;  if not, write to the Free Software 
  16.  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  17.  */
  18. #include <linux/fs.h>
  19. #include "jfs_incore.h"
  20. #include "jfs_dmap.h"
  21. #include "jfs_extent.h"
  22. #include "jfs_debug.h"
  23. /*
  24.  * forward references
  25.  */
  26. static int extBalloc(struct inode *, s64, s64 *, s64 *);
  27. #ifdef _NOTYET
  28. static int extBrealloc(struct inode *, s64, s64, s64 *, s64 *);
  29. #endif
  30. static s64 extRoundDown(s64 nb);
  31. /*
  32.  * external references
  33.  */
  34. extern int dbExtend(struct inode *, s64, s64, s64);
  35. extern int jfs_commit_inode(struct inode *, int);
  36. #define DPD(a)          (printk("(a): %dn",(a)))
  37. #define DPC(a)          (printk("(a): %cn",(a)))
  38. #define DPL1(a)
  39. {
  40. if ((a) >> 32)
  41. printk("(a): %x%08x  ",(a));
  42. else
  43. printk("(a): %x  ",(a) << 32);
  44. }
  45. #define DPL(a)
  46. {
  47. if ((a) >> 32)
  48. printk("(a): %x%08xn",(a));
  49. else
  50. printk("(a): %xn",(a) << 32);
  51. }
  52. #define DPD1(a)         (printk("(a): %d  ",(a)))
  53. #define DPX(a)          (printk("(a): %08xn",(a)))
  54. #define DPX1(a)         (printk("(a): %08x  ",(a)))
  55. #define DPS(a)          (printk("%sn",(a)))
  56. #define DPE(a)          (printk("nENTERING: %sn",(a)))
  57. #define DPE1(a)          (printk("nENTERING: %s",(a)))
  58. #define DPS1(a)         (printk("  %s  ",(a)))
  59. /*
  60.  * NAME: extAlloc()
  61.  *
  62.  * FUNCTION:    allocate an extent for a specified page range within a
  63.  * file.
  64.  *
  65.  * PARAMETERS:
  66.  * ip - the inode of the file.
  67.  * xlen - requested extent length.
  68.  * pno - the starting page number with the file.
  69.  * xp - pointer to an xad.  on entry, xad describes an
  70.  *   extent that is used as an allocation hint if the
  71.  *   xaddr of the xad is non-zero.  on successful exit,
  72.  *   the xad describes the newly allocated extent.
  73.  * abnr - boolean_t indicating whether the newly allocated extent
  74.  *   should be marked as allocated but not recorded.
  75.  *
  76.  * RETURN VALUES:
  77.  *      0       - success
  78.  *      EIO - i/o error.
  79.  *      ENOSPC - insufficient disk resources.
  80.  */
  81. int
  82. extAlloc(struct inode *ip, s64 xlen, s64 pno, xad_t * xp, boolean_t abnr)
  83. {
  84. struct jfs_sb_info *sbi = JFS_SBI(ip->i_sb);
  85. s64 nxlen, nxaddr, xoff, hint, xaddr = 0;
  86. int rc, nbperpage;
  87. int xflag;
  88. /* This blocks if we are low on resources */
  89. txBeginAnon(ip->i_sb);
  90. /* Avoid race with jfs_commit_inode() */
  91. down(&JFS_IP(ip)->commit_sem);
  92. /* validate extent length */
  93. if (xlen > MAXXLEN)
  94. xlen = MAXXLEN;
  95. /* get the number of blocks per page */
  96. nbperpage = sbi->nbperpage;
  97. /* get the page's starting extent offset */
  98. xoff = pno << sbi->l2nbperpage;
  99. /* check if an allocation hint was provided */
  100. if ((hint = addressXAD(xp))) {
  101. /* get the size of the extent described by the hint */
  102. nxlen = lengthXAD(xp);
  103. /* check if the hint is for the portion of the file
  104.  * immediately previous to the current allocation
  105.  * request and if hint extent has the same abnr
  106.  * value as the current request.  if so, we can
  107.  * extend the hint extent to include the current
  108.  * extent if we can allocate the blocks immediately
  109.  * following the hint extent.
  110.  */
  111. if (offsetXAD(xp) + nxlen == xoff &&
  112.     abnr == ((xp->flag & XAD_NOTRECORDED) ? TRUE : FALSE))
  113. xaddr = hint + nxlen;
  114. /* adjust the hint to the last block of the extent */
  115. hint += (nxlen - 1);
  116. }
  117. /* allocate the disk blocks for the extent.  initially, extBalloc()
  118.  * will try to allocate disk blocks for the requested size (xlen). 
  119.  * if this fails (xlen contigious free blocks not avaliable), it'll
  120.  * try to allocate a smaller number of blocks (producing a smaller
  121.  * extent), with this smaller number of blocks consisting of the
  122.  * requested number of blocks rounded down to the next smaller
  123.  * power of 2 number (i.e. 16 -> 8).  it'll continue to round down
  124.  * and retry the allocation until the number of blocks to allocate
  125.  * is smaller than the number of blocks per page.
  126.  */
  127. nxlen = xlen;
  128. if ((rc = extBalloc(ip, hint ? hint : INOHINT(ip), &nxlen, &nxaddr))) {
  129. up(&JFS_IP(ip)->commit_sem);
  130. return (rc);
  131. }
  132. /* determine the value of the extent flag */
  133. xflag = (abnr == TRUE) ? XAD_NOTRECORDED : 0;
  134. /* if we can extend the hint extent to cover the current request, 
  135.  * extend it.  otherwise, insert a new extent to
  136.  * cover the current request.
  137.  */
  138. if (xaddr && xaddr == nxaddr)
  139. rc = xtExtend(0, ip, xoff, (int) nxlen, 0);
  140. else
  141. rc = xtInsert(0, ip, xflag, xoff, (int) nxlen, &nxaddr, 0);
  142. /* if the extend or insert failed, 
  143.  * free the newly allocated blocks and return the error.
  144.  */
  145. if (rc) {
  146. dbFree(ip, nxaddr, nxlen);
  147. up(&JFS_IP(ip)->commit_sem);
  148. return (rc);
  149. }
  150. /* update the number of blocks allocated to the file */
  151. ip->i_blocks += LBLK2PBLK(ip->i_sb, nxlen);
  152. /* set the results of the extent allocation */
  153. XADaddress(xp, nxaddr);
  154. XADlength(xp, nxlen);
  155. XADoffset(xp, xoff);
  156. xp->flag = xflag;
  157. mark_inode_dirty(ip);
  158. up(&JFS_IP(ip)->commit_sem);
  159. /*
  160.  * COMMIT_SyncList flags an anonymous tlock on page that is on
  161.  * sync list.
  162.  * We need to commit the inode to get the page written disk.
  163.  */
  164. if (test_and_clear_cflag(COMMIT_Synclist,ip))
  165. jfs_commit_inode(ip, 0);
  166. return (0);
  167. }
  168. #ifdef _NOTYET
  169. /*
  170.  * NAME:        extRealloc()
  171.  *
  172.  * FUNCTION:    extend the allocation of a file extent containing a
  173.  * partial back last page.
  174.  *
  175.  * PARAMETERS:
  176.  * ip - the inode of the file.
  177.  * cp - cbuf for the partial backed last page.
  178.  * xlen - request size of the resulting extent.
  179.  * xp - pointer to an xad. on successful exit, the xad
  180.  *   describes the newly allocated extent.
  181.  * abnr - boolean_t indicating whether the newly allocated extent
  182.  *   should be marked as allocated but not recorded.
  183.  *
  184.  * RETURN VALUES:
  185.  *      0       - success
  186.  *      EIO - i/o error.
  187.  *      ENOSPC - insufficient disk resources.
  188.  */
  189. int extRealloc(struct inode *ip, s64 nxlen, xad_t * xp, boolean_t abnr)
  190. {
  191. struct super_block *sb = ip->i_sb;
  192. s64 xaddr, xlen, nxaddr, delta, xoff;
  193. s64 ntail, nextend, ninsert;
  194. int rc, nbperpage = JFS_SBI(sb)->nbperpage;
  195. int xflag;
  196. /* This blocks if we are low on resources */
  197. txBeginAnon(ip->i_sb);
  198. down(&JFS_IP(ip)->commit_sem);
  199. /* validate extent length */
  200. if (nxlen > MAXXLEN)
  201. nxlen = MAXXLEN;
  202. /* get the extend (partial) page's disk block address and
  203.  * number of blocks.
  204.  */
  205. xaddr = addressXAD(xp);
  206. xlen = lengthXAD(xp);
  207. xoff = offsetXAD(xp);
  208. /* if the extend page is abnr and if the request is for
  209.  * the extent to be allocated and recorded, 
  210.  * make the page allocated and recorded.
  211.  */
  212. if ((xp->flag & XAD_NOTRECORDED) && !abnr) {
  213. xp->flag = 0;
  214. if ((rc = xtUpdate(0, ip, xp)))
  215. goto exit;
  216. }
  217. /* try to allocated the request number of blocks for the
  218.  * extent.  dbRealloc() first tries to satisfy the request
  219.  * by extending the allocation in place. otherwise, it will
  220.  * try to allocate a new set of blocks large enough for the
  221.  * request.  in satisfying a request, dbReAlloc() may allocate
  222.  * less than what was request but will always allocate enough
  223.  * space as to satisfy the extend page.
  224.  */
  225. if ((rc = extBrealloc(ip, xaddr, xlen, &nxlen, &nxaddr)))
  226. goto exit;
  227. delta = nxlen - xlen;
  228. /* check if the extend page is not abnr but the request is abnr
  229.  * and the allocated disk space is for more than one page.  if this
  230.  * is the case, there is a miss match of abnr between the extend page
  231.  * and the one or more pages following the extend page.  as a result,
  232.  * two extents will have to be manipulated. the first will be that
  233.  * of the extent of the extend page and will be manipulated thru
  234.  * an xtExtend() or an xtTailgate(), depending upon whether the
  235.  * disk allocation occurred as an inplace extension.  the second
  236.  * extent will be manipulated (created) through an xtInsert() and
  237.  * will be for the pages following the extend page.
  238.  */
  239. if (abnr && (!(xp->flag & XAD_NOTRECORDED)) && (nxlen > nbperpage)) {
  240. ntail = nbperpage;
  241. nextend = ntail - xlen;
  242. ninsert = nxlen - nbperpage;
  243. xflag = XAD_NOTRECORDED;
  244. } else {
  245. ntail = nxlen;
  246. nextend = delta;
  247. ninsert = 0;
  248. xflag = xp->flag;
  249. }
  250. /* if we were able to extend the disk allocation in place,
  251.  * extend the extent.  otherwise, move the extent to a
  252.  * new disk location.
  253.  */
  254. if (xaddr == nxaddr) {
  255. /* extend the extent */
  256. if ((rc = xtExtend(0, ip, xoff + xlen, (int) nextend, 0))) {
  257. dbFree(ip, xaddr + xlen, delta);
  258. goto exit;
  259. }
  260. } else {
  261. /*
  262.  * move the extent to a new location:
  263.  *
  264.  * xtTailgate() accounts for relocated tail extent;
  265.  */
  266. if ((rc = xtTailgate(0, ip, xoff, (int) ntail, nxaddr, 0))) {
  267. dbFree(ip, nxaddr, nxlen);
  268. goto exit;
  269. }
  270. }
  271. /* check if we need to also insert a new extent */
  272. if (ninsert) {
  273. /* perform the insert.  if it fails, free the blocks
  274.  * to be inserted and make it appear that we only did
  275.  * the xtExtend() or xtTailgate() above.
  276.  */
  277. xaddr = nxaddr + ntail;
  278. if (xtInsert (0, ip, xflag, xoff + ntail, (int) ninsert,
  279.       &xaddr, 0)) {
  280. dbFree(ip, xaddr, (s64) ninsert);
  281. delta = nextend;
  282. nxlen = ntail;
  283. xflag = 0;
  284. }
  285. }
  286. /* update the inode with the number of blocks allocated */
  287. ip->i_blocks += LBLK2PBLK(sb, delta);
  288. /* set the return results */
  289. XADaddress(xp, nxaddr);
  290. XADlength(xp, nxlen);
  291. XADoffset(xp, xoff);
  292. xp->flag = xflag;
  293. mark_inode_dirty(ip);
  294. exit:
  295. up(&JFS_IP(ip)->commit_sem);
  296. return (rc);
  297. }
  298. #endif /* _NOTYET */
  299. /*
  300.  * NAME:        extHint()
  301.  *
  302.  * FUNCTION:    produce an extent allocation hint for a file offset.
  303.  *
  304.  * PARAMETERS:
  305.  * ip - the inode of the file.
  306.  * offset  - file offset for which the hint is needed.
  307.  * xp - pointer to the xad that is to be filled in with
  308.  *   the hint.
  309.  *
  310.  * RETURN VALUES:
  311.  *      0       - success
  312.  *      EIO - i/o error.
  313.  */
  314. int extHint(struct inode *ip, s64 offset, xad_t * xp)
  315. {
  316. struct super_block *sb = ip->i_sb;
  317. struct xadlist xadl;
  318. struct lxdlist lxdl;
  319. lxd_t lxd;
  320. s64 prev;
  321. int rc, nbperpage = JFS_SBI(sb)->nbperpage;
  322. /* init the hint as "no hint provided" */
  323. XADaddress(xp, 0);
  324. /* determine the starting extent offset of the page previous
  325.  * to the page containing the offset.
  326.  */
  327. prev = ((offset & ~POFFSET) >> JFS_SBI(sb)->l2bsize) - nbperpage;
  328. /* if the offsets in the first page of the file,
  329.  * no hint provided.
  330.  */
  331. if (prev < 0)
  332. return (0);
  333. /* prepare to lookup the previous page's extent info */
  334. lxdl.maxnlxd = 1;
  335. lxdl.nlxd = 1;
  336. lxdl.lxd = &lxd;
  337. LXDoffset(&lxd, prev)
  338.     LXDlength(&lxd, nbperpage);
  339. xadl.maxnxad = 1;
  340. xadl.nxad = 0;
  341. xadl.xad = xp;
  342. /* perform the lookup */
  343. if ((rc = xtLookupList(ip, &lxdl, &xadl, 0)))
  344. return (rc);
  345. /* check if not extent exists for the previous page.  
  346.  * this is possible for sparse files.
  347.  */
  348. if (xadl.nxad == 0) {
  349. //              assert(ISSPARSE(ip));
  350. return (0);
  351. }
  352. /* only preserve the abnr flag within the xad flags
  353.  * of the returned hint.
  354.  */
  355. xp->flag &= XAD_NOTRECORDED;
  356. assert(xadl.nxad == 1);
  357. assert(lengthXAD(xp) == nbperpage);
  358. return (0);
  359. }
  360. /*
  361.  * NAME:        extRecord()
  362.  *
  363.  * FUNCTION:    change a page with a file from not recorded to recorded.
  364.  *
  365.  * PARAMETERS:
  366.  * ip - inode of the file.
  367.  * cp - cbuf of the file page.
  368.  *
  369.  * RETURN VALUES:
  370.  *      0       - success
  371.  *      EIO - i/o error.
  372.  *      ENOSPC - insufficient disk resources.
  373.  */
  374. int extRecord(struct inode *ip, xad_t * xp)
  375. {
  376. int rc;
  377. txBeginAnon(ip->i_sb);
  378. down(&JFS_IP(ip)->commit_sem);
  379. /* update the extent */
  380. rc = xtUpdate(0, ip, xp);
  381. up(&JFS_IP(ip)->commit_sem);
  382. return (rc);
  383. }
  384. #ifdef _NOTYET
  385. /*
  386.  * NAME:        extFill()
  387.  *
  388.  * FUNCTION:    allocate disk space for a file page that represents
  389.  * a file hole.
  390.  *
  391.  * PARAMETERS:
  392.  * ip - the inode of the file.
  393.  * cp - cbuf of the file page represent the hole.
  394.  *
  395.  * RETURN VALUES:
  396.  *      0       - success
  397.  *      EIO - i/o error.
  398.  *      ENOSPC - insufficient disk resources.
  399.  */
  400. int extFill(struct inode *ip, xad_t * xp)
  401. {
  402. int rc, nbperpage = JFS_SBI(ip->i_sb)->nbperpage;
  403. s64 blkno = offsetXAD(xp) >> ip->i_blksize;
  404. //      assert(ISSPARSE(ip));
  405. /* initialize the extent allocation hint */
  406. XADaddress(xp, 0);
  407. /* allocate an extent to fill the hole */
  408. if ((rc = extAlloc(ip, nbperpage, blkno, xp, FALSE)))
  409. return (rc);
  410. assert(lengthPXD(xp) == nbperpage);
  411. return (0);
  412. }
  413. #endif /* _NOTYET */
  414. /*
  415.  * NAME: extBalloc()
  416.  *
  417.  * FUNCTION:    allocate disk blocks to form an extent.
  418.  *
  419.  * initially, we will try to allocate disk blocks for the
  420.  * requested size (nblocks).  if this fails (nblocks 
  421.  * contigious free blocks not avaliable), we'll try to allocate
  422.  * a smaller number of blocks (producing a smaller extent), with
  423.  * this smaller number of blocks consisting of the requested
  424.  * number of blocks rounded down to the next smaller power of 2
  425.  * number (i.e. 16 -> 8).  we'll continue to round down and
  426.  * retry the allocation until the number of blocks to allocate
  427.  * is smaller than the number of blocks per page.
  428.  *
  429.  * PARAMETERS:
  430.  * ip  - the inode of the file.
  431.  * hint  - disk block number to be used as an allocation hint.
  432.  * *nblocks - pointer to an s64 value.  on entry, this value specifies
  433.  *    the desired number of block to be allocated. on successful
  434.  *    exit, this value is set to the number of blocks actually
  435.  *    allocated.
  436.  * blkno  - pointer to a block address that is filled in on successful
  437.  *    return with the starting block number of the newly 
  438.  *    allocated block range.
  439.  *
  440.  * RETURN VALUES:
  441.  *      0       - success
  442.  *      EIO - i/o error.
  443.  *      ENOSPC - insufficient disk resources.
  444.  */
  445. static int
  446. extBalloc(struct inode *ip, s64 hint, s64 * nblocks, s64 * blkno)
  447. {
  448. struct jfs_inode_info *ji = JFS_IP(ip);
  449. struct jfs_sb_info *sbi = JFS_SBI(ip->i_sb);
  450. s64 nb, nblks, daddr, max;
  451. int rc, nbperpage = sbi->nbperpage;
  452. struct bmap *bmp = sbi->bmap;
  453. int ag;
  454. /* get the number of blocks to initially attempt to allocate.
  455.  * we'll first try the number of blocks requested unless this
  456.  * number is greater than the maximum number of contigious free
  457.  * blocks in the map. in that case, we'll start off with the 
  458.  * maximum free.
  459.  */
  460. max = (s64) 1 << bmp->db_maxfreebud;
  461. if (*nblocks >= max && *nblocks > nbperpage)
  462. nb = nblks = (max > nbperpage) ? max : nbperpage;
  463. else
  464. nb = nblks = *nblocks;
  465. /* try to allocate blocks */
  466. while ((rc = dbAlloc(ip, hint, nb, &daddr))) {
  467. /* if something other than an out of space error,
  468.  * stop and return this error.
  469.  */
  470. if (rc != ENOSPC)
  471. return (rc);
  472. /* decrease the allocation request size */
  473. nb = min(nblks, extRoundDown(nb));
  474. /* give up if we cannot cover a page */
  475. if (nb < nbperpage)
  476. return (rc);
  477. }
  478. *nblocks = nb;
  479. *blkno = daddr;
  480. if (S_ISREG(ip->i_mode) && (ji->fileset == FILESYSTEM_I)) {
  481. ag = BLKTOAG(daddr, sbi);
  482. if (ji->active_ag == -1) {
  483. atomic_inc(&bmp->db_active[ag]);
  484. ji->active_ag = ag;
  485. } else if (ji->active_ag != ag) {
  486. atomic_dec(&bmp->db_active[ji->active_ag]);
  487. atomic_inc(&bmp->db_active[ag]);
  488. ji->active_ag = ag;
  489. }
  490. }
  491. return (0);
  492. }
  493. #ifdef _NOTYET
  494. /*
  495.  * NAME: extBrealloc()
  496.  *
  497.  * FUNCTION:    attempt to extend an extent's allocation.
  498.  *
  499.  * initially, we will try to extend the extent's allocation
  500.  * in place.  if this fails, we'll try to move the extent
  501.  * to a new set of blocks. if moving the extent, we initially
  502.  * will try to allocate disk blocks for the requested size
  503.  * (nnew).  if this fails  (nnew contigious free blocks not
  504.  * avaliable), we'll try  to allocate a smaller number of
  505.  * blocks (producing a smaller extent), with this smaller
  506.  * number of blocks consisting of the requested number of
  507.  * blocks rounded down to the next smaller power of 2
  508.  * number (i.e. 16 -> 8).  we'll continue to round down and
  509.  * retry the allocation until the number of blocks to allocate
  510.  * is smaller than the number of blocks per page.
  511.  *
  512.  * PARAMETERS:
  513.  * ip  - the inode of the file.
  514.  * blkno    - starting block number of the extents current allocation.
  515.  * nblks    - number of blocks within the extents current allocation.
  516.  * newnblks - pointer to a s64 value.  on entry, this value is the
  517.  *    the new desired extent size (number of blocks).  on
  518.  *    successful exit, this value is set to the extent's actual
  519.  *    new size (new number of blocks).
  520.  * newblkno - the starting block number of the extents new allocation.
  521.  *
  522.  * RETURN VALUES:
  523.  *      0       - success
  524.  *      EIO - i/o error.
  525.  *      ENOSPC - insufficient disk resources.
  526.  */
  527. static int
  528. extBrealloc(struct inode *ip,
  529.     s64 blkno, s64 nblks, s64 * newnblks, s64 * newblkno)
  530. {
  531. int rc;
  532. /* try to extend in place */
  533. if ((rc = dbExtend(ip, blkno, nblks, *newnblks - nblks)) == 0) {
  534. *newblkno = blkno;
  535. return (0);
  536. } else {
  537. if (rc != ENOSPC)
  538. return (rc);
  539. }
  540. /* in place extension not possible.  
  541.  * try to move the extent to a new set of blocks.
  542.  */
  543. return (extBalloc(ip, blkno, newnblks, newblkno));
  544. }
  545. #endif /* _NOTYET */
  546. /*
  547.  * NAME:        extRoundDown()
  548.  *
  549.  * FUNCTION:    round down a specified number of blocks to the next
  550.  * smallest power of 2 number.
  551.  *
  552.  * PARAMETERS:
  553.  * nb - the inode of the file.
  554.  *
  555.  * RETURN VALUES:
  556.  *      next smallest power of 2 number.
  557.  */
  558. static s64 extRoundDown(s64 nb)
  559. {
  560. int i;
  561. u64 m, k;
  562. for (i = 0, m = (u64) 1 << 63; i < 64; i++, m >>= 1) {
  563. if (m & nb)
  564. break;
  565. }
  566. i = 63 - i;
  567. k = (u64) 1 << i;
  568. k = ((k - 1) & nb) ? k : k >> 1;
  569. return (k);
  570. }