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/ufs/ffs/ffs_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 /*      $NetBSD: ffs_balloc.c,v 1.34 2003/08/07 16:34:29 agc Exp $      */
    2 
    3 /*
    4  * Copyright (c) 2002 Networks Associates Technology, Inc.
    5  * All rights reserved.
    6  *
    7  * This software was developed for the FreeBSD Project by Marshall
    8  * Kirk McKusick and Network Associates Laboratories, the Security
    9  * Research Division of Network Associates, Inc. under DARPA/SPAWAR
   10  * contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS
   11  * research program
   12  *
   13  * Copyright (c) 1982, 1986, 1989, 1993
   14  *      The Regents of the University of California.  All rights reserved.
   15  *
   16  * Redistribution and use in source and binary forms, with or without
   17  * modification, are permitted provided that the following conditions
   18  * are met:
   19  * 1. Redistributions of source code must retain the above copyright
   20  *    notice, this list of conditions and the following disclaimer.
   21  * 2. Redistributions in binary form must reproduce the above copyright
   22  *    notice, this list of conditions and the following disclaimer in the
   23  *    documentation and/or other materials provided with the distribution.
   24  * 3. Neither the name of the University nor the names of its contributors
   25  *    may be used to endorse or promote products derived from this software
   26  *    without specific prior written permission.
   27  *
   28  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   29  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   30  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   31  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   32  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   33  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   34  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   35  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   36  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   37  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   38  * SUCH DAMAGE.
   39  *
   40  *      @(#)ffs_balloc.c        8.8 (Berkeley) 6/16/95
   41  */
   42 
   43 #include <sys/cdefs.h>
   44 __KERNEL_RCSID(0, "$NetBSD: ffs_balloc.c,v 1.34 2003/08/07 16:34:29 agc Exp $");
   45 
   46 #if defined(_KERNEL_OPT)
   47 #include "opt_quota.h"
   48 #endif
   49 
   50 #include <sys/param.h>
   51 #include <sys/systm.h>
   52 #include <sys/buf.h>
   53 #include <sys/file.h>
   54 #include <sys/mount.h>
   55 #include <sys/vnode.h>
   56 #include <sys/mount.h>
   57 
   58 #include <ufs/ufs/quota.h>
   59 #include <ufs/ufs/ufsmount.h>
   60 #include <ufs/ufs/inode.h>
   61 #include <ufs/ufs/ufs_extern.h>
   62 #include <ufs/ufs/ufs_bswap.h>
   63 
   64 #include <ufs/ffs/fs.h>
   65 #include <ufs/ffs/ffs_extern.h>
   66 
   67 #include <uvm/uvm.h>
   68 
   69 static int ffs_balloc_ufs1(void *);
   70 static int ffs_balloc_ufs2(void *);
   71 
   72 /*
   73  * Balloc defines the structure of file system storage
   74  * by allocating the physical blocks on a device given
   75  * the inode and the logical block number in a file.
   76  */
   77 
   78 int
   79 ffs_balloc(v)
   80         void *v;
   81 {
   82         struct vop_balloc_args *ap = v;
   83 
   84         if (VTOI(ap->a_vp)->i_fs->fs_magic == FS_UFS2_MAGIC)
   85                 return ffs_balloc_ufs2(v);
   86         else
   87                 return ffs_balloc_ufs1(v);
   88 }
   89 
   90 static int
   91 ffs_balloc_ufs1(v)
   92         void *v;
   93 {
   94         struct vop_balloc_args /* {
   95                 struct vnode *a_vp;
   96                 off_t a_startoffset;
   97                 int a_size;
   98                 struct ucred *a_cred;
   99                 int a_flags;
  100                 struct buf **a_bpp;
  101         } */ *ap = v;
  102         daddr_t lbn, lastlbn;
  103         int size;
  104         struct ucred *cred;
  105         int flags;
  106         int32_t nb;
  107         struct buf *bp, *nbp;
  108         struct vnode *vp = ap->a_vp;
  109         struct inode *ip = VTOI(vp);
  110         struct fs *fs = ip->i_fs;
  111         struct indir indirs[NIADDR + 2];
  112         daddr_t newb, pref;
  113         int32_t *bap;   /* XXX ondisk32 */
  114         int deallocated, osize, nsize, num, i, error;
  115         int32_t *blkp, *allocblk, allociblk[NIADDR + 1];
  116         int32_t *allocib;
  117         int unwindidx = -1;
  118         struct buf **bpp = ap->a_bpp;
  119 #ifdef FFS_EI
  120         const int needswap = UFS_FSNEEDSWAP(fs);
  121 #endif
  122         UVMHIST_FUNC("ffs_balloc"); UVMHIST_CALLED(ubchist);
  123 
  124         lbn = lblkno(fs, ap->a_startoffset);
  125         size = blkoff(fs, ap->a_startoffset) + ap->a_size;
  126         if (size > fs->fs_bsize)
  127                 panic("ffs_balloc: blk too big");
  128         if (bpp != NULL) {
  129                 *bpp = NULL;
  130         }
  131         UVMHIST_LOG(ubchist, "vp %p lbn 0x%x size 0x%x", vp, lbn, size,0);
  132 
  133         KASSERT(size <= fs->fs_bsize);
  134         if (lbn < 0)
  135                 return (EFBIG);
  136         cred = ap->a_cred;
  137         flags = ap->a_flags;
  138 
  139         /*
  140          * If the next write will extend the file into a new block,
  141          * and the file is currently composed of a fragment
  142          * this fragment has to be extended to be a full block.
  143          */
  144 
  145         lastlbn = lblkno(fs, ip->i_size);
  146         if (lastlbn < NDADDR && lastlbn < lbn) {
  147                 nb = lastlbn;
  148                 osize = blksize(fs, ip, nb);
  149                 if (osize < fs->fs_bsize && osize > 0) {
  150                         error = ffs_realloccg(ip, nb,
  151                                     ffs_blkpref_ufs1(ip, lastlbn, nb,
  152                                         &ip->i_ffs1_db[0]),
  153                                     osize, (int)fs->fs_bsize, cred, bpp, &newb);
  154                         if (error)
  155                                 return (error);
  156                         if (DOINGSOFTDEP(vp))
  157                                 softdep_setup_allocdirect(ip, nb, newb,
  158                                     ufs_rw32(ip->i_ffs1_db[nb], needswap),
  159                                     fs->fs_bsize, osize, bpp ? *bpp : NULL);
  160                         ip->i_size = lblktosize(fs, nb + 1);
  161                         ip->i_ffs1_size = ip->i_size;
  162                         uvm_vnp_setsize(vp, ip->i_ffs1_size);
  163                         ip->i_ffs1_db[nb] = ufs_rw32((int32_t)newb, needswap);
  164                         ip->i_flag |= IN_CHANGE | IN_UPDATE;
  165                         if (bpp) {
  166                                 if (flags & B_SYNC)
  167                                         bwrite(*bpp);
  168                                 else
  169                                         bawrite(*bpp);
  170                         }
  171                 }
  172         }
  173 
  174         /*
  175          * The first NDADDR blocks are direct blocks
  176          */
  177 
  178         if (lbn < NDADDR) {
  179                 nb = ufs_rw32(ip->i_ffs1_db[lbn], needswap);
  180                 if (nb != 0 && ip->i_size >= lblktosize(fs, lbn + 1)) {
  181 
  182                         /*
  183                          * The block is an already-allocated direct block
  184                          * and the file already extends past this block,
  185                          * thus this must be a whole block.
  186                          * Just read the block (if requested).
  187                          */
  188 
  189                         if (bpp != NULL) {
  190                                 error = bread(vp, lbn, fs->fs_bsize, NOCRED,
  191                                               bpp);
  192                                 if (error) {
  193                                         brelse(*bpp);
  194                                         return (error);
  195                                 }
  196                         }
  197                         return (0);
  198                 }
  199                 if (nb != 0) {
  200 
  201                         /*
  202                          * Consider need to reallocate a fragment.
  203                          */
  204 
  205                         osize = fragroundup(fs, blkoff(fs, ip->i_size));
  206                         nsize = fragroundup(fs, size);
  207                         if (nsize <= osize) {
  208 
  209                                 /*
  210                                  * The existing block is already
  211                                  * at least as big as we want.
  212                                  * Just read the block (if requested).
  213                                  */
  214 
  215                                 if (bpp != NULL) {
  216                                         error = bread(vp, lbn, osize, NOCRED,
  217                                                       bpp);
  218                                         if (error) {
  219                                                 brelse(*bpp);
  220                                                 return (error);
  221                                         }
  222                                 }
  223                                 return 0;
  224                         } else {
  225 
  226                                 /*
  227                                  * The existing block is smaller than we want,
  228                                  * grow it.
  229                                  */
  230 
  231                                 error = ffs_realloccg(ip, lbn,
  232                                     ffs_blkpref_ufs1(ip, lbn, (int)lbn,
  233                                         &ip->i_ffs1_db[0]), osize, nsize, cred,
  234                                         bpp, &newb);
  235                                 if (error)
  236                                         return (error);
  237                                 if (DOINGSOFTDEP(vp))
  238                                         softdep_setup_allocdirect(ip, lbn,
  239                                             newb, nb, nsize, osize,
  240                                             bpp ? *bpp : NULL);
  241                         }
  242                 } else {
  243 
  244                         /*
  245                          * the block was not previously allocated,
  246                          * allocate a new block or fragment.
  247                          */
  248 
  249                         if (ip->i_size < lblktosize(fs, lbn + 1))
  250                                 nsize = fragroundup(fs, size);
  251                         else
  252                                 nsize = fs->fs_bsize;
  253                         error = ffs_alloc(ip, lbn,
  254                             ffs_blkpref_ufs1(ip, lbn, (int)lbn,
  255                                 &ip->i_ffs1_db[0]),
  256                                 nsize, cred, &newb);
  257                         if (error)
  258                                 return (error);
  259                         if (bpp != NULL) {
  260                                 bp = getblk(vp, lbn, nsize, 0, 0);
  261                                 bp->b_blkno = fsbtodb(fs, newb);
  262                                 if (flags & B_CLRBUF)
  263                                         clrbuf(bp);
  264                                 *bpp = bp;
  265                         }
  266                         if (DOINGSOFTDEP(vp)) {
  267                                 softdep_setup_allocdirect(ip, lbn, newb, 0,
  268                                     nsize, 0, bpp ? *bpp : NULL);
  269                         }
  270                 }
  271                 ip->i_ffs1_db[lbn] = ufs_rw32((int32_t)newb, needswap);
  272                 ip->i_flag |= IN_CHANGE | IN_UPDATE;
  273                 return (0);
  274         }
  275 
  276         /*
  277          * Determine the number of levels of indirection.
  278          */
  279 
  280         pref = 0;
  281         if ((error = ufs_getlbns(vp, lbn, indirs, &num)) != 0)
  282                 return (error);
  283 
  284         /*
  285          * Fetch the first indirect block allocating if necessary.
  286          */
  287 
  288         --num;
  289         nb = ufs_rw32(ip->i_ffs1_ib[indirs[0].in_off], needswap);
  290         allocib = NULL;
  291         allocblk = allociblk;
  292         if (nb == 0) {
  293                 pref = ffs_blkpref_ufs1(ip, lbn, 0, (int32_t *)0);
  294                 error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, cred,
  295                     &newb);
  296                 if (error)
  297                         goto fail;
  298                 nb = newb;
  299                 *allocblk++ = nb;
  300                 bp = getblk(vp, indirs[1].in_lbn, fs->fs_bsize, 0, 0);
  301                 bp->b_blkno = fsbtodb(fs, nb);
  302                 clrbuf(bp);
  303                 if (DOINGSOFTDEP(vp)) {
  304                         softdep_setup_allocdirect(ip, NDADDR + indirs[0].in_off,
  305                             newb, 0, fs->fs_bsize, 0, bp);
  306                         bdwrite(bp);
  307                 } else {
  308 
  309                         /*
  310                          * Write synchronously so that indirect blocks
  311                          * never point at garbage.
  312                          */
  313 
  314                         if ((error = bwrite(bp)) != 0)
  315                                 goto fail;
  316                 }
  317                 unwindidx = 0;
  318                 allocib = &ip->i_ffs1_ib[indirs[0].in_off];
  319                 *allocib = ufs_rw32(nb, needswap);
  320                 ip->i_flag |= IN_CHANGE | IN_UPDATE;
  321         }
  322 
  323         /*
  324          * Fetch through the indirect blocks, allocating as necessary.
  325          */
  326 
  327         for (i = 1;;) {
  328                 error = bread(vp,
  329                     indirs[i].in_lbn, (int)fs->fs_bsize, NOCRED, &bp);
  330                 if (error) {
  331                         brelse(bp);
  332                         goto fail;
  333                 }
  334                 bap = (int32_t *)bp->b_data;    /* XXX ondisk32 */
  335                 nb = ufs_rw32(bap[indirs[i].in_off], needswap);
  336                 if (i == num)
  337                         break;
  338                 i++;
  339                 if (nb != 0) {
  340                         brelse(bp);
  341                         continue;
  342                 }
  343                 if (pref == 0)
  344                         pref = ffs_blkpref_ufs1(ip, lbn, 0, (int32_t *)0);
  345                 error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, cred,
  346                     &newb);
  347                 if (error) {
  348                         brelse(bp);
  349                         goto fail;
  350                 }
  351                 nb = newb;
  352                 *allocblk++ = nb;
  353                 nbp = getblk(vp, indirs[i].in_lbn, fs->fs_bsize, 0, 0);
  354                 nbp->b_blkno = fsbtodb(fs, nb);
  355                 clrbuf(nbp);
  356                 if (DOINGSOFTDEP(vp)) {
  357                         softdep_setup_allocindir_meta(nbp, ip, bp,
  358                             indirs[i - 1].in_off, nb);
  359                         bdwrite(nbp);
  360                 } else {
  361 
  362                         /*
  363                          * Write synchronously so that indirect blocks
  364                          * never point at garbage.
  365                          */
  366 
  367                         if ((error = bwrite(nbp)) != 0) {
  368                                 brelse(bp);
  369                                 goto fail;
  370                         }
  371                 }
  372                 if (unwindidx < 0)
  373                         unwindidx = i - 1;
  374                 bap[indirs[i - 1].in_off] = ufs_rw32(nb, needswap);
  375 
  376                 /*
  377                  * If required, write synchronously, otherwise use
  378                  * delayed write.
  379                  */
  380 
  381                 if (flags & B_SYNC) {
  382                         bwrite(bp);
  383                 } else {
  384                         bdwrite(bp);
  385                 }
  386         }
  387 
  388         /*
  389          * Get the data block, allocating if necessary.
  390          */
  391 
  392         if (nb == 0) {
  393                 pref = ffs_blkpref_ufs1(ip, lbn, indirs[num].in_off, &bap[0]);
  394                 error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, cred,
  395                     &newb);
  396                 if (error) {
  397                         brelse(bp);
  398                         goto fail;
  399                 }
  400                 nb = newb;
  401                 *allocblk++ = nb;
  402                 if (bpp != NULL) {
  403                         nbp = getblk(vp, lbn, fs->fs_bsize, 0, 0);
  404                         nbp->b_blkno = fsbtodb(fs, nb);
  405                         if (flags & B_CLRBUF)
  406                                 clrbuf(nbp);
  407                         *bpp = nbp;
  408                 }
  409                 if (DOINGSOFTDEP(vp))
  410                         softdep_setup_allocindir_page(ip, lbn, bp,
  411                             indirs[num].in_off, nb, 0, bpp ? *bpp : NULL);
  412                 bap[indirs[num].in_off] = ufs_rw32(nb, needswap);
  413                 if (allocib == NULL && unwindidx < 0) {
  414                         unwindidx = i - 1;
  415                 }
  416 
  417                 /*
  418                  * If required, write synchronously, otherwise use
  419                  * delayed write.
  420                  */
  421 
  422                 if (flags & B_SYNC) {
  423                         bwrite(bp);
  424                 } else {
  425                         bdwrite(bp);
  426                 }
  427                 return (0);
  428         }
  429         brelse(bp);
  430         if (bpp != NULL) {
  431                 if (flags & B_CLRBUF) {
  432                         error = bread(vp, lbn, (int)fs->fs_bsize, NOCRED, &nbp);
  433                         if (error) {
  434                                 brelse(nbp);
  435                                 goto fail;
  436                         }
  437                 } else {
  438                         nbp = getblk(vp, lbn, fs->fs_bsize, 0, 0);
  439                         nbp->b_blkno = fsbtodb(fs, nb);
  440                         clrbuf(nbp);
  441                 }
  442                 *bpp = nbp;
  443         }
  444         return (0);
  445 
  446 fail:
  447         /*
  448          * If we have failed part way through block allocation, we
  449          * have to deallocate any indirect blocks that we have allocated.
  450          */
  451 
  452         if (unwindidx >= 0) {
  453 
  454                 /*
  455                  * First write out any buffers we've created to resolve their
  456                  * softdeps.  This must be done in reverse order of creation
  457                  * so that we resolve the dependencies in one pass.
  458                  * Write the cylinder group buffers for these buffers too.
  459                  */
  460 
  461                 for (i = num; i >= unwindidx; i--) {
  462                         if (i == 0) {
  463                                 break;
  464                         }
  465                         bp = getblk(vp, indirs[i].in_lbn, (int)fs->fs_bsize, 0,
  466                             0);
  467                         if (bp->b_flags & B_DELWRI) {
  468                                 nb = fsbtodb(fs, cgtod(fs, dtog(fs,
  469                                     dbtofsb(fs, bp->b_blkno))));
  470                                 bwrite(bp);
  471                                 bp = getblk(ip->i_devvp, nb, (int)fs->fs_cgsize,
  472                                     0, 0);
  473                                 if (bp->b_flags & B_DELWRI) {
  474                                         bwrite(bp);
  475                                 } else {
  476                                         bp->b_flags |= B_INVAL;
  477                                         brelse(bp);
  478                                 }
  479                         } else {
  480                                 bp->b_flags |= B_INVAL;
  481                                 brelse(bp);
  482                         }
  483                 }
  484                 if (unwindidx == 0) {
  485                         ip->i_flag |= IN_MODIFIED | IN_CHANGE | IN_UPDATE;
  486                         VOP_UPDATE(vp, NULL, NULL, UPDATE_WAIT);
  487                 }
  488 
  489                 /*
  490                  * Now that any dependencies that we created have been
  491                  * resolved, we can undo the partial allocation.
  492                  */
  493 
  494                 if (unwindidx == 0) {
  495                         *allocib = 0;
  496                         ip->i_flag |= IN_MODIFIED | IN_CHANGE | IN_UPDATE;
  497                         VOP_UPDATE(vp, NULL, NULL, UPDATE_WAIT);
  498                 } else {
  499                         int r;
  500 
  501                         r = bread(vp, indirs[unwindidx].in_lbn,
  502                             (int)fs->fs_bsize, NOCRED, &bp);
  503                         if (r) {
  504                                 panic("Could not unwind indirect block, error %d", r);
  505                                 brelse(bp);
  506                         } else {
  507                                 bap = (int32_t *)bp->b_data; /* XXX ondisk32 */
  508                                 bap[indirs[unwindidx].in_off] = 0;
  509                                 bwrite(bp);
  510                         }
  511                 }
  512                 for (i = unwindidx + 1; i <= num; i++) {
  513                         bp = getblk(vp, indirs[i].in_lbn, (int)fs->fs_bsize, 0,
  514                             0);
  515                         bp->b_flags |= B_INVAL;
  516                         brelse(bp);
  517                 }
  518         }
  519         for (deallocated = 0, blkp = allociblk; blkp < allocblk; blkp++) {
  520                 ffs_blkfree(ip, *blkp, fs->fs_bsize);
  521                 deallocated += fs->fs_bsize;
  522         }
  523         if (deallocated) {
  524 #ifdef QUOTA
  525                 /*
  526                  * Restore user's disk quota because allocation failed.
  527                  */
  528                 (void)chkdq(ip, -btodb(deallocated), cred, FORCE);
  529 #endif
  530                 ip->i_ffs1_blocks -= btodb(deallocated);
  531                 ip->i_flag |= IN_CHANGE | IN_UPDATE;
  532         }
  533         return (error);
  534 }
  535 
  536 static int
  537 ffs_balloc_ufs2(v)
  538         void *v;
  539 {
  540         struct vop_balloc_args /* {
  541                 struct vnode *a_vp;
  542                 off_t a_startoffset;
  543                 int a_size;
  544                 struct ucred *a_cred;
  545                 int a_flags;
  546                 struct buf **a_bpp;
  547         } */ *ap = v;
  548         daddr_t lbn, lastlbn;
  549         int size;
  550         struct ucred *cred;
  551         int flags;
  552         struct buf *bp, *nbp;
  553         struct vnode *vp = ap->a_vp;
  554         struct inode *ip = VTOI(vp);
  555         struct fs *fs = ip->i_fs;
  556         struct indir indirs[NIADDR + 2];
  557         daddr_t newb, pref, nb;
  558         int64_t *bap;
  559         int deallocated, osize, nsize, num, i, error;
  560         daddr_t *blkp, *allocblk, allociblk[NIADDR + 1];
  561         int64_t *allocib;
  562         int unwindidx = -1;
  563         struct buf **bpp = ap->a_bpp;
  564 #ifdef FFS_EI
  565         const int needswap = UFS_FSNEEDSWAP(fs);
  566 #endif
  567         UVMHIST_FUNC("ffs_balloc"); UVMHIST_CALLED(ubchist);
  568 
  569         lbn = lblkno(fs, ap->a_startoffset);
  570         size = blkoff(fs, ap->a_startoffset) + ap->a_size;
  571         if (size > fs->fs_bsize)
  572                 panic("ffs_balloc: blk too big");
  573         if (bpp != NULL) {
  574                 *bpp = NULL;
  575         }
  576         UVMHIST_LOG(ubchist, "vp %p lbn 0x%x size 0x%x", vp, lbn, size,0);
  577 
  578         KASSERT(size <= fs->fs_bsize);
  579         if (lbn < 0)
  580                 return (EFBIG);
  581         cred = ap->a_cred;
  582         flags = ap->a_flags;
  583 
  584 #ifdef notyet
  585         /*
  586          * Check for allocating external data.
  587          */
  588         if (flags & IO_EXT) {
  589                 if (lbn >= NXADDR)
  590                         return (EFBIG);
  591                 /*
  592                  * If the next write will extend the data into a new block,
  593                  * and the data is currently composed of a fragment
  594                  * this fragment has to be extended to be a full block.
  595                  */
  596                 lastlbn = lblkno(fs, dp->di_extsize);
  597                 if (lastlbn < lbn) {
  598                         nb = lastlbn;
  599                         osize = sblksize(fs, dp->di_extsize, nb);
  600                         if (osize < fs->fs_bsize && osize > 0) {
  601                                 error = ffs_realloccg(ip, -1 - nb,
  602                                     dp->di_extb[nb],
  603                                     ffs_blkpref_ufs2(ip, lastlbn, (int)nb,
  604                                     &dp->di_extb[0]), osize,
  605                                     (int)fs->fs_bsize, cred, &bp);
  606                                 if (error)
  607                                         return (error);
  608                                 if (DOINGSOFTDEP(vp))
  609                                         softdep_setup_allocext(ip, nb,
  610                                             dbtofsb(fs, bp->b_blkno),
  611                                             dp->di_extb[nb],
  612                                             fs->fs_bsize, osize, bp);
  613                                 dp->di_extsize = smalllblktosize(fs, nb + 1);
  614                                 dp->di_extb[nb] = dbtofsb(fs, bp->b_blkno);
  615                                 bp->b_xflags |= BX_ALTDATA;
  616                                 ip->i_flag |= IN_CHANGE | IN_UPDATE;
  617                                 if (flags & IO_SYNC)
  618                                         bwrite(bp);
  619                                 else
  620                                         bawrite(bp);
  621                         }
  622                 }
  623                 /*
  624                  * All blocks are direct blocks
  625                  */
  626                 if (flags & BA_METAONLY)
  627                         panic("ffs_balloc_ufs2: BA_METAONLY for ext block");
  628                 nb = dp->di_extb[lbn];
  629                 if (nb != 0 && dp->di_extsize >= smalllblktosize(fs, lbn + 1)) {
  630                         error = bread(vp, -1 - lbn, fs->fs_bsize, NOCRED, &bp);
  631                         if (error) {
  632                                 brelse(bp);
  633                                 return (error);
  634                         }
  635                         bp->b_blkno = fsbtodb(fs, nb);
  636                         bp->b_xflags |= BX_ALTDATA;
  637                         *bpp = bp;
  638                         return (0);
  639                 }
  640                 if (nb != 0) {
  641                         /*
  642                          * Consider need to reallocate a fragment.
  643                          */
  644                         osize = fragroundup(fs, blkoff(fs, dp->di_extsize));
  645                         nsize = fragroundup(fs, size);
  646                         if (nsize <= osize) {
  647                                 error = bread(vp, -1 - lbn, osize, NOCRED, &bp);
  648                                 if (error) {
  649                                         brelse(bp);
  650                                         return (error);
  651                                 }
  652                                 bp->b_blkno = fsbtodb(fs, nb);
  653                                 bp->b_xflags |= BX_ALTDATA;
  654                         } else {
  655                                 error = ffs_realloccg(ip, -1 - lbn,
  656                                     dp->di_extb[lbn],
  657                                     ffs_blkpref_ufs2(ip, lbn, (int)lbn,
  658                                     &dp->di_extb[0]), osize, nsize, cred, &bp);
  659                                 if (error)
  660                                         return (error);
  661                                 bp->b_xflags |= BX_ALTDATA;
  662                                 if (DOINGSOFTDEP(vp))
  663                                         softdep_setup_allocext(ip, lbn,
  664                                             dbtofsb(fs, bp->b_blkno), nb,
  665                                             nsize, osize, bp);
  666                         }
  667                 } else {
  668                         if (dp->di_extsize < smalllblktosize(fs, lbn + 1))
  669                                 nsize = fragroundup(fs, size);
  670                         else
  671                                 nsize = fs->fs_bsize;
  672                         error = ffs_alloc(ip, lbn,
  673                            ffs_blkpref_ufs2(ip, lbn, (int)lbn, &dp->di_extb[0]),
  674                            nsize, cred, &newb);
  675                         if (error)
  676                                 return (error);
  677                         bp = getblk(vp, -1 - lbn, nsize, 0, 0);
  678                         bp->b_blkno = fsbtodb(fs, newb);
  679                         bp->b_xflags |= BX_ALTDATA;
  680                         if (flags & BA_CLRBUF)
  681                                 vfs_bio_clrbuf(bp);
  682                         if (DOINGSOFTDEP(vp))
  683                                 softdep_setup_allocext(ip, lbn, newb, 0,
  684                                     nsize, 0, bp);
  685                 }
  686                 dp->di_extb[lbn] = dbtofsb(fs, bp->b_blkno);
  687                 ip->i_flag |= IN_CHANGE | IN_UPDATE;
  688                 *bpp = bp;
  689                 return (0);
  690         }
  691 #endif
  692         /*
  693          * If the next write will extend the file into a new block,
  694          * and the file is currently composed of a fragment
  695          * this fragment has to be extended to be a full block.
  696          */
  697 
  698         lastlbn = lblkno(fs, ip->i_size);
  699         if (lastlbn < NDADDR && lastlbn < lbn) {
  700                 nb = lastlbn;
  701                 osize = blksize(fs, ip, nb);
  702                 if (osize < fs->fs_bsize && osize > 0) {
  703                         error = ffs_realloccg(ip, nb,
  704                                     ffs_blkpref_ufs2(ip, lastlbn, nb,
  705                                         &ip->i_ffs2_db[0]),
  706                                     osize, (int)fs->fs_bsize, cred, bpp, &newb);
  707                         if (error)
  708                                 return (error);
  709                         if (DOINGSOFTDEP(vp))
  710                                 softdep_setup_allocdirect(ip, nb, newb,
  711                                     ufs_rw64(ip->i_ffs2_db[nb], needswap),
  712                                     fs->fs_bsize, osize, bpp ? *bpp : NULL);
  713                         ip->i_size = lblktosize(fs, nb + 1);
  714                         ip->i_ffs2_size = ip->i_size;
  715                         uvm_vnp_setsize(vp, ip->i_size);
  716                         ip->i_ffs2_db[nb] = ufs_rw64(newb, needswap);
  717                         ip->i_flag |= IN_CHANGE | IN_UPDATE;
  718                         if (bpp) {
  719                                 if (flags & B_SYNC)
  720                                         bwrite(*bpp);
  721                                 else
  722                                         bawrite(*bpp);
  723                         }
  724                 }
  725         }
  726 
  727         /*
  728          * The first NDADDR blocks are direct blocks
  729          */
  730 
  731         if (lbn < NDADDR) {
  732                 nb = ufs_rw64(ip->i_ffs2_db[lbn], needswap);
  733                 if (nb != 0 && ip->i_size >= lblktosize(fs, lbn + 1)) {
  734 
  735                         /*
  736                          * The block is an already-allocated direct block
  737                          * and the file already extends past this block,
  738                          * thus this must be a whole block.
  739                          * Just read the block (if requested).
  740                          */
  741 
  742                         if (bpp != NULL) {
  743                                 error = bread(vp, lbn, fs->fs_bsize, NOCRED,
  744                                               bpp);
  745                                 if (error) {
  746                                         brelse(*bpp);
  747                                         return (error);
  748                                 }
  749                         }
  750                         return (0);
  751                 }
  752                 if (nb != 0) {
  753 
  754                         /*
  755                          * Consider need to reallocate a fragment.
  756                          */
  757 
  758                         osize = fragroundup(fs, blkoff(fs, ip->i_size));
  759                         nsize = fragroundup(fs, size);
  760                         if (nsize <= osize) {
  761 
  762                                 /*
  763                                  * The existing block is already
  764                                  * at least as big as we want.
  765                                  * Just read the block (if requested).
  766                                  */
  767 
  768                                 if (bpp != NULL) {
  769                                         error = bread(vp, lbn, osize, NOCRED,
  770                                                       bpp);
  771                                         if (error) {
  772                                                 brelse(*bpp);
  773                                                 return (error);
  774                                         }
  775                                 }
  776                                 return 0;
  777                         } else {
  778 
  779                                 /*
  780                                  * The existing block is smaller than we want,
  781                                  * grow it.
  782                                  */
  783 
  784                                 error = ffs_realloccg(ip, lbn,
  785                                     ffs_blkpref_ufs2(ip, lbn, (int)lbn,
  786                                         &ip->i_ffs2_db[0]), osize, nsize, cred,
  787                                         bpp, &newb);
  788                                 if (error)
  789                                         return (error);
  790                                 if (DOINGSOFTDEP(vp))
  791                                         softdep_setup_allocdirect(ip, lbn,
  792                                             newb, nb, nsize, osize,
  793                                             bpp ? *bpp : NULL);
  794                         }
  795                 } else {
  796 
  797                         /*
  798                          * the block was not previously allocated,
  799                          * allocate a new block or fragment.
  800                          */
  801 
  802                         if (ip->i_size < lblktosize(fs, lbn + 1))
  803                                 nsize = fragroundup(fs, size);
  804                         else
  805                                 nsize = fs->fs_bsize;
  806                         error = ffs_alloc(ip, lbn,
  807                             ffs_blkpref_ufs2(ip, lbn, (int)lbn,
  808                                 &ip->i_ffs2_db[0]), nsize, cred, &newb);
  809                         if (error)
  810                                 return (error);
  811                         if (bpp != NULL) {
  812                                 bp = getblk(vp, lbn, nsize, 0, 0);
  813                                 bp->b_blkno = fsbtodb(fs, newb);
  814                                 if (flags & B_CLRBUF)
  815                                         clrbuf(bp);
  816                                 *bpp = bp;
  817                         }
  818                         if (DOINGSOFTDEP(vp)) {
  819                                 softdep_setup_allocdirect(ip, lbn, newb, 0,
  820                                     nsize, 0, bpp ? *bpp : NULL);
  821                         }
  822                 }
  823                 ip->i_ffs2_db[lbn] = ufs_rw64(newb, needswap);
  824                 ip->i_flag |= IN_CHANGE | IN_UPDATE;
  825                 return (0);
  826         }
  827 
  828         /*
  829          * Determine the number of levels of indirection.
  830          */
  831 
  832         pref = 0;
  833         if ((error = ufs_getlbns(vp, lbn, indirs, &num)) != 0)
  834                 return (error);
  835 
  836         /*
  837          * Fetch the first indirect block allocating if necessary.
  838          */
  839 
  840         --num;
  841         nb = ufs_rw64(ip->i_ffs2_ib[indirs[0].in_off], needswap);
  842         allocib = NULL;
  843         allocblk = allociblk;
  844         if (nb == 0) {
  845                 pref = ffs_blkpref_ufs2(ip, lbn, 0, (int64_t *)0);
  846                 error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, cred,
  847                     &newb);
  848                 if (error)
  849                         goto fail;
  850                 nb = newb;
  851                 *allocblk++ = nb;
  852                 bp = getblk(vp, indirs[1].in_lbn, fs->fs_bsize, 0, 0);
  853                 bp->b_blkno = fsbtodb(fs, nb);
  854                 clrbuf(bp);
  855                 if (DOINGSOFTDEP(vp)) {
  856                         softdep_setup_allocdirect(ip, NDADDR + indirs[0].in_off,
  857                             newb, 0, fs->fs_bsize, 0, bp);
  858                         bdwrite(bp);
  859                 } else {
  860 
  861                         /*
  862                          * Write synchronously so that indirect blocks
  863                          * never point at garbage.
  864                          */
  865 
  866                         if ((error = bwrite(bp)) != 0)
  867                                 goto fail;
  868                 }
  869                 unwindidx = 0;
  870                 allocib = &ip->i_ffs2_ib[indirs[0].in_off];
  871                 *allocib = ufs_rw64(nb, needswap);
  872                 ip->i_flag |= IN_CHANGE | IN_UPDATE;
  873         }
  874 
  875         /*
  876          * Fetch through the indirect blocks, allocating as necessary.
  877          */
  878 
  879         for (i = 1;;) {
  880                 error = bread(vp,
  881                     indirs[i].in_lbn, (int)fs->fs_bsize, NOCRED, &bp);
  882                 if (error) {
  883                         brelse(bp);
  884                         goto fail;
  885                 }
  886                 bap = (int64_t *)bp->b_data;
  887                 nb = ufs_rw64(bap[indirs[i].in_off], needswap);
  888                 if (i == num)
  889                         break;
  890                 i++;
  891                 if (nb != 0) {
  892                         brelse(bp);
  893                         continue;
  894                 }
  895                 if (pref == 0)
  896                         pref = ffs_blkpref_ufs2(ip, lbn, 0, (int64_t *)0);
  897                 error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, cred,
  898                     &newb);
  899                 if (error) {
  900                         brelse(bp);
  901                         goto fail;
  902                 }
  903                 nb = newb;
  904                 *allocblk++ = nb;
  905                 nbp = getblk(vp, indirs[i].in_lbn, fs->fs_bsize, 0, 0);
  906                 nbp->b_blkno = fsbtodb(fs, nb);
  907                 clrbuf(nbp);
  908                 if (DOINGSOFTDEP(vp)) {
  909                         softdep_setup_allocindir_meta(nbp, ip, bp,
  910                             indirs[i - 1].in_off, nb);
  911                         bdwrite(nbp);
  912                 } else {
  913 
  914                         /*
  915                          * Write synchronously so that indirect blocks
  916                          * never point at garbage.
  917                          */
  918 
  919                         if ((error = bwrite(nbp)) != 0) {
  920                                 brelse(bp);
  921                                 goto fail;
  922                         }
  923                 }
  924                 if (unwindidx < 0)
  925                         unwindidx = i - 1;
  926                 bap[indirs[i - 1].in_off] = ufs_rw64(nb, needswap);
  927 
  928                 /*
  929                  * If required, write synchronously, otherwise use
  930                  * delayed write.
  931                  */
  932 
  933                 if (flags & B_SYNC) {
  934                         bwrite(bp);
  935                 } else {
  936                         bdwrite(bp);
  937                 }
  938         }
  939 
  940         /*
  941          * Get the data block, allocating if necessary.
  942          */
  943 
  944         if (nb == 0) {
  945                 pref = ffs_blkpref_ufs2(ip, lbn, indirs[num].in_off, &bap[0]);
  946                 error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, cred,
  947                     &newb);
  948                 if (error) {
  949                         brelse(bp);
  950                         goto fail;
  951                 }
  952                 nb = newb;
  953                 *allocblk++ = nb;
  954                 if (bpp != NULL) {
  955                         nbp = getblk(vp, lbn, fs->fs_bsize, 0, 0);
  956                         nbp->b_blkno = fsbtodb(fs, nb);
  957                         if (flags & B_CLRBUF)
  958                                 clrbuf(nbp);
  959                         *bpp = nbp;
  960                 }
  961                 if (DOINGSOFTDEP(vp))
  962                         softdep_setup_allocindir_page(ip, lbn, bp,
  963                             indirs[num].in_off, nb, 0, bpp ? *bpp : NULL);
  964                 bap[indirs[num].in_off] = ufs_rw64(nb, needswap);
  965                 if (allocib == NULL && unwindidx < 0) {
  966                         unwindidx = i - 1;
  967                 }
  968 
  969                 /*
  970                  * If required, write synchronously, otherwise use
  971                  * delayed write.
  972                  */
  973 
  974                 if (flags & B_SYNC) {
  975                         bwrite(bp);
  976                 } else {
  977                         bdwrite(bp);
  978                 }
  979                 return (0);
  980         }
  981         brelse(bp);
  982         if (bpp != NULL) {
  983                 if (flags & B_CLRBUF) {
  984                         error = bread(vp, lbn, (int)fs->fs_bsize, NOCRED, &nbp);
  985                         if (error) {
  986                                 brelse(nbp);
  987                                 goto fail;
  988                         }
  989                 } else {
  990                         nbp = getblk(vp, lbn, fs->fs_bsize, 0, 0);
  991                         nbp->b_blkno = fsbtodb(fs, nb);
  992                         clrbuf(nbp);
  993                 }
  994                 *bpp = nbp;
  995         }
  996         return (0);
  997 
  998 fail:
  999         /*
 1000          * If we have failed part way through block allocation, we
 1001          * have to deallocate any indirect blocks that we have allocated.
 1002          */
 1003 
 1004         if (unwindidx >= 0) {
 1005 
 1006                 /*
 1007                  * First write out any buffers we've created to resolve their
 1008                  * softdeps.  This must be done in reverse order of creation
 1009                  * so that we resolve the dependencies in one pass.
 1010                  * Write the cylinder group buffers for these buffers too.
 1011                  */
 1012 
 1013                 for (i = num; i >= unwindidx; i--) {
 1014                         if (i == 0) {
 1015                                 break;
 1016                         }
 1017                         bp = getblk(vp, indirs[i].in_lbn, (int)fs->fs_bsize, 0,
 1018                             0);
 1019                         if (bp->b_flags & B_DELWRI) {
 1020                                 nb = fsbtodb(fs, cgtod(fs, dtog(fs,
 1021                                     dbtofsb(fs, bp->b_blkno))));
 1022                                 bwrite(bp);
 1023                                 bp = getblk(ip->i_devvp, nb, (int)fs->fs_cgsize,
 1024                                     0, 0);
 1025                                 if (bp->b_flags & B_DELWRI) {
 1026                                         bwrite(bp);
 1027                                 } else {
 1028                                         bp->b_flags |= B_INVAL;
 1029                                         brelse(bp);
 1030                                 }
 1031                         } else {
 1032                                 bp->b_flags |= B_INVAL;
 1033                                 brelse(bp);
 1034                         }
 1035                 }
 1036                 if (unwindidx == 0) {
 1037                         ip->i_flag |= IN_MODIFIED | IN_CHANGE | IN_UPDATE;
 1038                         VOP_UPDATE(vp, NULL, NULL, UPDATE_WAIT);
 1039                 }
 1040 
 1041                 /*
 1042                  * Now that any dependencies that we created have been
 1043                  * resolved, we can undo the partial allocation.
 1044                  */
 1045 
 1046                 if (unwindidx == 0) {
 1047                         *allocib = 0;
 1048                         ip->i_flag |= IN_MODIFIED | IN_CHANGE | IN_UPDATE;
 1049                         VOP_UPDATE(vp, NULL, NULL, UPDATE_WAIT);
 1050                 } else {
 1051                         int r;
 1052 
 1053                         r = bread(vp, indirs[unwindidx].in_lbn,
 1054                             (int)fs->fs_bsize, NOCRED, &bp);
 1055                         if (r) {
 1056                                 panic("Could not unwind indirect block, error %d", r);
 1057                                 brelse(bp);
 1058                         } else {
 1059                                 bap = (int64_t *)bp->b_data;
 1060                                 bap[indirs[unwindidx].in_off] = 0;
 1061                                 bwrite(bp);
 1062                         }
 1063                 }
 1064                 for (i = unwindidx + 1; i <= num; i++) {
 1065                         bp = getblk(vp, indirs[i].in_lbn, (int)fs->fs_bsize, 0,
 1066                             0);
 1067                         bp->b_flags |= B_INVAL;
 1068                         brelse(bp);
 1069                 }
 1070         }
 1071         for (deallocated = 0, blkp = allociblk; blkp < allocblk; blkp++) {
 1072                 ffs_blkfree(ip, *blkp, fs->fs_bsize);
 1073                 deallocated += fs->fs_bsize;
 1074         }
 1075         if (deallocated) {
 1076 #ifdef QUOTA
 1077                 /*
 1078                  * Restore user's disk quota because allocation failed.
 1079                  */
 1080                 (void)chkdq(ip, -btodb(deallocated), cred, FORCE);
 1081 #endif
 1082                 ip->i_ffs2_blocks -= btodb(deallocated);
 1083                 ip->i_flag |= IN_CHANGE | IN_UPDATE;
 1084         }
 1085         return (error);
 1086 }

Cache object: 414d944b37dd283a1cb54865a95d3105


[ 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.