root/ufs/ext2fs/ext2fs_balloc.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ext2fs_buf_alloc

    1 /*      $OpenBSD: ext2fs_balloc.c,v 1.14 2007/06/02 00:45:50 pedro Exp $        */
    2 /*      $NetBSD: ext2fs_balloc.c,v 1.10 2001/07/04 21:16:01 chs Exp $   */
    3 
    4 /*
    5  * Copyright (c) 1997 Manuel Bouyer.
    6  * Copyright (c) 1982, 1986, 1989, 1993
    7  *      The Regents of the University of California.  All rights reserved.
    8  *
    9  * Redistribution and use in source and binary forms, with or without
   10  * modification, are permitted provided that the following conditions
   11  * are met:
   12  * 1. Redistributions of source code must retain the above copyright
   13  *    notice, this list of conditions and the following disclaimer.
   14  * 2. Redistributions in binary form must reproduce the above copyright
   15  *    notice, this list of conditions and the following disclaimer in the
   16  *    documentation and/or other materials provided with the distribution.
   17  * 3. Neither the name of the University nor the names of its contributors
   18  *    may be used to endorse or promote products derived from this software
   19  *    without specific prior written permission.
   20  *
   21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   31  * SUCH DAMAGE.
   32  *
   33  *      @(#)ffs_balloc.c        8.4 (Berkeley) 9/23/93
   34  * Modified for ext2fs by Manuel Bouyer.
   35  */
   36 
   37 #include <sys/param.h>
   38 #include <sys/systm.h>
   39 #include <sys/buf.h>
   40 #include <sys/proc.h>
   41 #include <sys/file.h>
   42 #include <sys/vnode.h>
   43 
   44 #include <uvm/uvm_extern.h>
   45 
   46 #include <ufs/ufs/quota.h>
   47 #include <ufs/ufs/inode.h>
   48 #include <ufs/ufs/ufs_extern.h>
   49 
   50 #include <ufs/ext2fs/ext2fs.h>
   51 #include <ufs/ext2fs/ext2fs_extern.h>
   52 
   53 /*
   54  * Balloc defines the structure of file system storage
   55  * by allocating the physical blocks on a device given
   56  * the inode and the logical block number in a file.
   57  */
   58 int
   59 ext2fs_buf_alloc(struct inode *ip, daddr_t bn, int size, struct ucred *cred, 
   60     struct buf **bpp, int flags)
   61 {
   62         struct m_ext2fs *fs;
   63         int32_t nb;
   64         struct buf *bp, *nbp;
   65         struct vnode *vp = ITOV(ip);
   66         struct indir indirs[NIADDR + 2];
   67         int32_t newb, lbn, *bap, pref;
   68         int num, i, error;
   69         u_int deallocated;
   70         int32_t *allocib, *blkp, *allocblk, allociblk[NIADDR + 1];
   71         int unwindidx = -1;
   72 
   73         *bpp = NULL;
   74         if (bn < 0)
   75                 return (EFBIG);
   76         fs = ip->i_e2fs;
   77         lbn = bn;
   78 
   79         /*
   80          * The first NDADDR blocks are direct blocks
   81          */
   82         if (bn < NDADDR) {
   83                 nb = fs2h32(ip->i_e2fs_blocks[bn]);
   84                 if (nb != 0) {
   85                         error = bread(vp, bn, fs->e2fs_bsize, NOCRED, &bp);
   86                         if (error) {
   87                                 brelse(bp);
   88                                 return (error);
   89                         }
   90                         *bpp = bp;
   91                         return (0);
   92                 }
   93 
   94                 /*
   95                  * allocate a new direct block.
   96                  */
   97                 error = ext2fs_alloc(ip, bn,
   98                     ext2fs_blkpref(ip, bn, (int)bn, &ip->i_e2fs_blocks[0]),
   99                     cred, &newb);
  100                 if (error)
  101                         return (error);
  102                 ip->i_e2fs_last_lblk = lbn;
  103                 ip->i_e2fs_last_blk = newb;
  104                 ip->i_e2fs_blocks[bn] = h2fs32(newb);
  105                 ip->i_flag |= IN_CHANGE | IN_UPDATE;
  106                 bp = getblk(vp, bn, fs->e2fs_bsize, 0, 0);
  107                 bp->b_blkno = fsbtodb(fs, newb);
  108                 if (flags & B_CLRBUF)
  109                         clrbuf(bp);
  110                 *bpp = bp;
  111                 return (0);
  112         }
  113         /*
  114          * Determine the number of levels of indirection.
  115          */
  116         pref = 0;
  117         if ((error = ufs_getlbns(vp, bn, indirs, &num)) != 0)
  118                 return(error);
  119 #ifdef DIAGNOSTIC
  120         if (num < 1)
  121                 panic ("ext2fs_balloc: ufs_getlbns returned indirect block");
  122 #endif
  123         /*
  124          * Fetch the first indirect block allocating if necessary.
  125          */
  126         --num;
  127         nb = fs2h32(ip->i_e2fs_blocks[NDADDR + indirs[0].in_off]);
  128         allocib = NULL;
  129         allocblk = allociblk;
  130         if (nb == 0) {
  131                 pref = ext2fs_blkpref(ip, lbn, 0, (int32_t *)0);
  132                 error = ext2fs_alloc(ip, lbn, pref, cred, &newb);
  133                 if (error)
  134                         return (error);
  135                 nb = newb;
  136                 *allocblk++ = nb;
  137                 ip->i_e2fs_last_blk = newb;
  138                 bp = getblk(vp, indirs[1].in_lbn, fs->e2fs_bsize, 0, 0);
  139                 bp->b_blkno = fsbtodb(fs, newb);
  140                 clrbuf(bp);
  141                 /*
  142                  * Write synchronously so that indirect blocks
  143                  * never point at garbage.
  144                  */
  145                 if ((error = bwrite(bp)) != 0)
  146                         goto fail;
  147                 unwindidx = 0;
  148                 allocib = &ip->i_e2fs_blocks[NDADDR + indirs[0].in_off];
  149                 *allocib = h2fs32(newb);
  150                 ip->i_flag |= IN_CHANGE | IN_UPDATE;
  151         }
  152         /*
  153          * Fetch through the indirect blocks, allocating as necessary.
  154          */
  155         for (i = 1;;) {
  156                 error = bread(vp,
  157                     indirs[i].in_lbn, (int)fs->e2fs_bsize, NOCRED, &bp);
  158                 if (error) {
  159                         brelse(bp);
  160                         goto fail;
  161                 }
  162                 bap = (int32_t *)bp->b_data;
  163                 nb = fs2h32(bap[indirs[i].in_off]);
  164                 if (i == num)
  165                         break;
  166                 i++;
  167                 if (nb != 0) {
  168                         brelse(bp);
  169                         continue;
  170                 }
  171                 pref = ext2fs_blkpref(ip, lbn, 0, (int32_t *)0);
  172                 error = ext2fs_alloc(ip, lbn, pref, cred, &newb);
  173                 if (error) {
  174                         brelse(bp);
  175                         goto fail;
  176                 }
  177                 nb = newb;
  178                 *allocblk++ = nb;
  179                 ip->i_e2fs_last_blk = newb;
  180                 nbp = getblk(vp, indirs[i].in_lbn, fs->e2fs_bsize, 0, 0);
  181                 nbp->b_blkno = fsbtodb(fs, nb);
  182                 clrbuf(nbp);
  183                 /*
  184                  * Write synchronously so that indirect blocks
  185                  * never point at garbage.
  186                  */
  187                 if ((error = bwrite(nbp)) != 0) {
  188                         brelse(bp);
  189                         goto fail;
  190                 }
  191                 if (unwindidx < 0)
  192                         unwindidx = i - 1;
  193                 bap[indirs[i - 1].in_off] = h2fs32(nb);
  194                 /*
  195                  * If required, write synchronously, otherwise use
  196                  * delayed write.
  197                  */
  198                 if (flags & B_SYNC) {
  199                         bwrite(bp);
  200                 } else {
  201                         bdwrite(bp);
  202                 }
  203         }
  204         /*
  205          * Get the data block, allocating if necessary.
  206          */
  207         if (nb == 0) {
  208                 pref = ext2fs_blkpref(ip, lbn, indirs[num].in_off, &bap[0]);
  209                 error = ext2fs_alloc(ip, lbn, pref, cred, &newb);
  210                 if (error) {
  211                         brelse(bp);
  212                         goto fail;
  213                 }
  214                 nb = newb;
  215                 *allocblk++ = nb;
  216                 ip->i_e2fs_last_lblk = lbn;
  217                 ip->i_e2fs_last_blk = newb;
  218                 bap[indirs[num].in_off] = h2fs32(nb);
  219                 /*
  220                  * If required, write synchronously, otherwise use
  221                  * delayed write.
  222                  */
  223                 if (flags & B_SYNC) {
  224                         bwrite(bp);
  225                 } else {
  226                         bdwrite(bp);
  227                 }
  228                 nbp = getblk(vp, lbn, fs->e2fs_bsize, 0, 0);
  229                 nbp->b_blkno = fsbtodb(fs, nb);
  230                 if (flags & B_CLRBUF)
  231                         clrbuf(nbp);
  232                 *bpp = nbp;
  233                 return (0);
  234         }
  235         brelse(bp);
  236         if (flags & B_CLRBUF) {
  237                 error = bread(vp, lbn, (int)fs->e2fs_bsize, NOCRED, &nbp);
  238                 if (error) {
  239                         brelse(nbp);
  240                         goto fail;
  241                 }
  242         } else {
  243                 nbp = getblk(vp, lbn, fs->e2fs_bsize, 0, 0);
  244                 nbp->b_blkno = fsbtodb(fs, nb);
  245         }
  246 
  247         *bpp = nbp;
  248         return (0);
  249 fail:
  250         /*
  251          * If we have failed part way through block allocation, we
  252          * have to deallocate any indirect blocks that we have allocated.
  253          */
  254         for (deallocated = 0, blkp = allociblk; blkp < allocblk; blkp++) {
  255                 ext2fs_blkfree(ip, *blkp);
  256                 deallocated += fs->e2fs_bsize;
  257         }
  258         if (unwindidx >= 0) {
  259                 if (unwindidx == 0) {
  260                         *allocib = 0;
  261                 } else {
  262                         int r;
  263         
  264                         r = bread(vp, indirs[unwindidx].in_lbn, 
  265                             (int)fs->e2fs_bsize, NOCRED, &bp);
  266                         if (r) {
  267                                 panic("Could not unwind indirect block, error %d", r);
  268                                 brelse(bp);
  269                         } else {
  270                                 bap = (int32_t *)bp->b_data;
  271                                 bap[indirs[unwindidx].in_off] = 0;
  272                                 if (flags & B_SYNC)
  273                                         bwrite(bp);
  274                                 else
  275                                         bdwrite(bp);
  276                         }
  277                 }
  278                 for (i = unwindidx + 1; i <= num; i++) {
  279                         bp = getblk(vp, indirs[i].in_lbn, (int)fs->e2fs_bsize,
  280                             0, 0);
  281                         bp->b_flags |= B_INVAL;
  282                         brelse(bp);
  283                 }
  284         }
  285         if (deallocated) {
  286                 ip->i_e2fs_nblock -= btodb(deallocated);
  287                 ip->i_e2fs_flags |= IN_CHANGE | IN_UPDATE;
  288         }
  289         return error;
  290 }

/* [<][>][^][v][top][bottom][index][help] */