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