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