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