The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/fs/ext2fs/ext2_balloc.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  *  modified for Lites 1.1
    3  *
    4  *  Aug 1995, Godmar Back (gback@cs.utah.edu)
    5  *  University of Utah, Department of Computer Science
    6  */
    7 /*-
    8  * SPDX-License-Identifier: BSD-3-Clause
    9  *
   10  * Copyright (c) 1982, 1986, 1989, 1993
   11  *      The Regents of the University of California.  All rights reserved.
   12  *
   13  * Redistribution and use in source and binary forms, with or without
   14  * modification, are permitted provided that the following conditions
   15  * are met:
   16  * 1. Redistributions of source code must retain the above copyright
   17  *    notice, this list of conditions and the following disclaimer.
   18  * 2. Redistributions in binary form must reproduce the above copyright
   19  *    notice, this list of conditions and the following disclaimer in the
   20  *    documentation and/or other materials provided with the distribution.
   21  * 3. Neither the name of the University nor the names of its contributors
   22  *    may be used to endorse or promote products derived from this software
   23  *    without specific prior written permission.
   24  *
   25  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   27  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   28  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   29  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   30  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   31  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   32  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   33  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   34  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   35  * SUCH DAMAGE.
   36  *
   37  *      @(#)ffs_balloc.c        8.4 (Berkeley) 9/23/93
   38  * $FreeBSD: releng/12.0/sys/fs/ext2fs/ext2_balloc.c 327584 2018-01-05 10:04:01Z fsu $
   39  */
   40 
   41 #include <sys/param.h>
   42 #include <sys/systm.h>
   43 #include <sys/bio.h>
   44 #include <sys/buf.h>
   45 #include <sys/limits.h>
   46 #include <sys/lock.h>
   47 #include <sys/mount.h>
   48 #include <sys/vnode.h>
   49 
   50 #include <fs/ext2fs/fs.h>
   51 #include <fs/ext2fs/inode.h>
   52 #include <fs/ext2fs/ext2fs.h>
   53 #include <fs/ext2fs/ext2_dinode.h>
   54 #include <fs/ext2fs/ext2_extern.h>
   55 #include <fs/ext2fs/ext2_mount.h>
   56 
   57 static int
   58 ext2_ext_balloc(struct inode *ip, uint32_t lbn, int size,
   59     struct ucred *cred, struct buf **bpp, int flags)
   60 {
   61         struct m_ext2fs *fs;
   62         struct buf *bp = NULL;
   63         struct vnode *vp = ITOV(ip);
   64         daddr_t newblk;
   65         int osize, nsize, blks, error, allocated;
   66 
   67         fs = ip->i_e2fs;
   68         blks = howmany(size, fs->e2fs_bsize);
   69 
   70         error = ext4_ext_get_blocks(ip, lbn, blks, cred, NULL, &allocated, &newblk);
   71         if (error)
   72                 return (error);
   73 
   74         if (allocated) {
   75                 if (ip->i_size < (lbn + 1) * fs->e2fs_bsize)
   76                         nsize = fragroundup(fs, size);
   77                 else
   78                         nsize = fs->e2fs_bsize;
   79 
   80                 bp = getblk(vp, lbn, nsize, 0, 0, 0);
   81                 if(!bp)
   82                         return (EIO);
   83 
   84                 bp->b_blkno = fsbtodb(fs, newblk);
   85                 if (flags & BA_CLRBUF)
   86                         vfs_bio_clrbuf(bp);
   87         } else {
   88                 if (ip->i_size >= (lbn + 1) * fs->e2fs_bsize) {
   89 
   90                         error = bread(vp, lbn, fs->e2fs_bsize, NOCRED, &bp);
   91                         if (error) {
   92                                 brelse(bp);
   93                                 return (error);
   94                         }
   95                         bp->b_blkno = fsbtodb(fs, newblk);
   96                         *bpp = bp;
   97                         return (0);
   98                 }
   99 
  100                 /*
  101                  * Consider need to reallocate a fragment.
  102                  */
  103                 osize = fragroundup(fs, blkoff(fs, ip->i_size));
  104                 nsize = fragroundup(fs, size);
  105                 if (nsize <= osize)
  106                         error = bread(vp, lbn, osize, NOCRED, &bp);
  107                 else
  108                         error = bread(vp, lbn, fs->e2fs_bsize, NOCRED, &bp);
  109                 if (error) {
  110                         brelse(bp);
  111                         return (error);
  112                 }
  113                 bp->b_blkno = fsbtodb(fs, newblk);
  114         }
  115 
  116         *bpp = bp;
  117 
  118         return (error);
  119 }
  120 
  121 /*
  122  * Balloc defines the structure of filesystem storage
  123  * by allocating the physical blocks on a device given
  124  * the inode and the logical block number in a file.
  125  */
  126 int
  127 ext2_balloc(struct inode *ip, e2fs_lbn_t lbn, int size, struct ucred *cred,
  128     struct buf **bpp, int flags)
  129 {
  130         struct m_ext2fs *fs;
  131         struct ext2mount *ump;
  132         struct buf *bp, *nbp;
  133         struct vnode *vp = ITOV(ip);
  134         struct indir indirs[EXT2_NIADDR + 2];
  135         e4fs_daddr_t nb, newb;
  136         e2fs_daddr_t *bap, pref;
  137         int osize, nsize, num, i, error;
  138 
  139         *bpp = NULL;
  140         if (lbn < 0)
  141                 return (EFBIG);
  142         fs = ip->i_e2fs;
  143         ump = ip->i_ump;
  144 
  145         /*
  146          * check if this is a sequential block allocation.
  147          * If so, increment next_alloc fields to allow ext2_blkpref
  148          * to make a good guess
  149          */
  150         if (lbn == ip->i_next_alloc_block + 1) {
  151                 ip->i_next_alloc_block++;
  152                 ip->i_next_alloc_goal++;
  153         }
  154 
  155         if (ip->i_flag & IN_E4EXTENTS)
  156                 return (ext2_ext_balloc(ip, lbn, size, cred, bpp, flags));
  157 
  158         /*
  159          * The first EXT2_NDADDR blocks are direct blocks
  160          */
  161         if (lbn < EXT2_NDADDR) {
  162                 nb = ip->i_db[lbn];
  163                 /*
  164                  * no new block is to be allocated, and no need to expand
  165                  * the file
  166                  */
  167                 if (nb != 0 && ip->i_size >= (lbn + 1) * fs->e2fs_bsize) {
  168                         error = bread(vp, lbn, fs->e2fs_bsize, NOCRED, &bp);
  169                         if (error) {
  170                                 brelse(bp);
  171                                 return (error);
  172                         }
  173                         bp->b_blkno = fsbtodb(fs, nb);
  174                         *bpp = bp;
  175                         return (0);
  176                 }
  177                 if (nb != 0) {
  178                         /*
  179                          * Consider need to reallocate a fragment.
  180                          */
  181                         osize = fragroundup(fs, blkoff(fs, ip->i_size));
  182                         nsize = fragroundup(fs, size);
  183                         if (nsize <= osize) {
  184                                 error = bread(vp, lbn, osize, NOCRED, &bp);
  185                                 if (error) {
  186                                         brelse(bp);
  187                                         return (error);
  188                                 }
  189                                 bp->b_blkno = fsbtodb(fs, nb);
  190                         } else {
  191                                 /*
  192                                  * Godmar thinks: this shouldn't happen w/o
  193                                  * fragments
  194                                  */
  195                                 printf("nsize %d(%d) > osize %d(%d) nb %d\n",
  196                                     (int)nsize, (int)size, (int)osize,
  197                                     (int)ip->i_size, (int)nb);
  198                                 panic(
  199                                     "ext2_balloc: Something is terribly wrong");
  200 /*
  201  * please note there haven't been any changes from here on -
  202  * FFS seems to work.
  203  */
  204                         }
  205                 } else {
  206                         if (ip->i_size < (lbn + 1) * fs->e2fs_bsize)
  207                                 nsize = fragroundup(fs, size);
  208                         else
  209                                 nsize = fs->e2fs_bsize;
  210                         EXT2_LOCK(ump);
  211                         error = ext2_alloc(ip, lbn,
  212                             ext2_blkpref(ip, lbn, (int)lbn, &ip->i_db[0], 0),
  213                             nsize, cred, &newb);
  214                         if (error)
  215                                 return (error);
  216                         /*
  217                          * If the newly allocated block exceeds 32-bit limit,
  218                          * we can not use it in file block maps.
  219                          */
  220                         if (newb > UINT_MAX)
  221                                 return (EFBIG);
  222                         bp = getblk(vp, lbn, nsize, 0, 0, 0);
  223                         bp->b_blkno = fsbtodb(fs, newb);
  224                         if (flags & BA_CLRBUF)
  225                                 vfs_bio_clrbuf(bp);
  226                 }
  227                 ip->i_db[lbn] = dbtofsb(fs, bp->b_blkno);
  228                 ip->i_flag |= IN_CHANGE | IN_UPDATE;
  229                 *bpp = bp;
  230                 return (0);
  231         }
  232         /*
  233          * Determine the number of levels of indirection.
  234          */
  235         pref = 0;
  236         if ((error = ext2_getlbns(vp, lbn, indirs, &num)) != 0)
  237                 return (error);
  238 #ifdef INVARIANTS
  239         if (num < 1)
  240                 panic("ext2_balloc: ext2_getlbns returned indirect block");
  241 #endif
  242         /*
  243          * Fetch the first indirect block allocating if necessary.
  244          */
  245         --num;
  246         nb = ip->i_ib[indirs[0].in_off];
  247         if (nb == 0) {
  248                 EXT2_LOCK(ump);
  249                 pref = ext2_blkpref(ip, lbn, indirs[0].in_off +
  250                     EXT2_NDIR_BLOCKS, &ip->i_db[0], 0);
  251                 if ((error = ext2_alloc(ip, lbn, pref, fs->e2fs_bsize, cred,
  252                     &newb)))
  253                         return (error);
  254                 if (newb > UINT_MAX)
  255                         return (EFBIG);
  256                 nb = newb;
  257                 bp = getblk(vp, indirs[1].in_lbn, fs->e2fs_bsize, 0, 0, 0);
  258                 bp->b_blkno = fsbtodb(fs, newb);
  259                 vfs_bio_clrbuf(bp);
  260                 /*
  261                  * Write synchronously so that indirect blocks
  262                  * never point at garbage.
  263                  */
  264                 if ((error = bwrite(bp)) != 0) {
  265                         ext2_blkfree(ip, nb, fs->e2fs_bsize);
  266                         return (error);
  267                 }
  268                 ip->i_ib[indirs[0].in_off] = newb;
  269                 ip->i_flag |= IN_CHANGE | IN_UPDATE;
  270         }
  271         /*
  272          * Fetch through the indirect blocks, allocating as necessary.
  273          */
  274         for (i = 1;;) {
  275                 error = bread(vp,
  276                     indirs[i].in_lbn, (int)fs->e2fs_bsize, NOCRED, &bp);
  277                 if (error) {
  278                         brelse(bp);
  279                         return (error);
  280                 }
  281                 bap = (e2fs_daddr_t *)bp->b_data;
  282                 nb = bap[indirs[i].in_off];
  283                 if (i == num)
  284                         break;
  285                 i += 1;
  286                 if (nb != 0) {
  287                         bqrelse(bp);
  288                         continue;
  289                 }
  290                 EXT2_LOCK(ump);
  291                 if (pref == 0)
  292                         pref = ext2_blkpref(ip, lbn, indirs[i].in_off, bap,
  293                             bp->b_lblkno);
  294                 error = ext2_alloc(ip, lbn, pref, (int)fs->e2fs_bsize, cred, &newb);
  295                 if (error) {
  296                         brelse(bp);
  297                         return (error);
  298                 }
  299                 if (newb > UINT_MAX)
  300                         return (EFBIG);
  301                 nb = newb;
  302                 nbp = getblk(vp, indirs[i].in_lbn, fs->e2fs_bsize, 0, 0, 0);
  303                 nbp->b_blkno = fsbtodb(fs, nb);
  304                 vfs_bio_clrbuf(nbp);
  305                 /*
  306                  * Write synchronously so that indirect blocks
  307                  * never point at garbage.
  308                  */
  309                 if ((error = bwrite(nbp)) != 0) {
  310                         ext2_blkfree(ip, nb, fs->e2fs_bsize);
  311                         EXT2_UNLOCK(ump);
  312                         brelse(bp);
  313                         return (error);
  314                 }
  315                 bap[indirs[i - 1].in_off] = nb;
  316                 /*
  317                  * If required, write synchronously, otherwise use
  318                  * delayed write.
  319                  */
  320                 if (flags & IO_SYNC) {
  321                         bwrite(bp);
  322                 } else {
  323                         if (bp->b_bufsize == fs->e2fs_bsize)
  324                                 bp->b_flags |= B_CLUSTEROK;
  325                         bdwrite(bp);
  326                 }
  327         }
  328         /*
  329          * Get the data block, allocating if necessary.
  330          */
  331         if (nb == 0) {
  332                 EXT2_LOCK(ump);
  333                 pref = ext2_blkpref(ip, lbn, indirs[i].in_off, &bap[0],
  334                     bp->b_lblkno);
  335                 if ((error = ext2_alloc(ip,
  336                     lbn, pref, (int)fs->e2fs_bsize, cred, &newb)) != 0) {
  337                         brelse(bp);
  338                         return (error);
  339                 }
  340                 if (newb > UINT_MAX)
  341                         return (EFBIG);
  342                 nb = newb;
  343                 nbp = getblk(vp, lbn, fs->e2fs_bsize, 0, 0, 0);
  344                 nbp->b_blkno = fsbtodb(fs, nb);
  345                 if (flags & BA_CLRBUF)
  346                         vfs_bio_clrbuf(nbp);
  347                 bap[indirs[i].in_off] = nb;
  348                 /*
  349                  * If required, write synchronously, otherwise use
  350                  * delayed write.
  351                  */
  352                 if (flags & IO_SYNC) {
  353                         bwrite(bp);
  354                 } else {
  355                         if (bp->b_bufsize == fs->e2fs_bsize)
  356                                 bp->b_flags |= B_CLUSTEROK;
  357                         bdwrite(bp);
  358                 }
  359                 *bpp = nbp;
  360                 return (0);
  361         }
  362         brelse(bp);
  363         if (flags & BA_CLRBUF) {
  364                 int seqcount = (flags & BA_SEQMASK) >> BA_SEQSHIFT;
  365 
  366                 if (seqcount && (vp->v_mount->mnt_flag & MNT_NOCLUSTERR) == 0) {
  367                         error = cluster_read(vp, ip->i_size, lbn,
  368                             (int)fs->e2fs_bsize, NOCRED,
  369                             MAXBSIZE, seqcount, 0, &nbp);
  370                 } else {
  371                         error = bread(vp, lbn, (int)fs->e2fs_bsize, NOCRED, &nbp);
  372                 }
  373                 if (error) {
  374                         brelse(nbp);
  375                         return (error);
  376                 }
  377         } else {
  378                 nbp = getblk(vp, lbn, fs->e2fs_bsize, 0, 0, 0);
  379                 nbp->b_blkno = fsbtodb(fs, nb);
  380         }
  381         *bpp = nbp;
  382         return (0);
  383 }

Cache object: a08872572dc7b886d22e82a34f78780c


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.