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_inode.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  * Copyright (c) 1982, 1986, 1989, 1993
    3  *      The Regents of the University of California.  All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  * 4. Neither the name of the University nor the names of its contributors
   14  *    may be used to endorse or promote products derived from this software
   15  *    without specific prior written permission.
   16  *
   17  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   27  * SUCH DAMAGE.
   28  *
   29  *      @(#)ffs_inode.c 8.13 (Berkeley) 4/21/95
   30  */
   31 
   32 #include <sys/cdefs.h>
   33 __FBSDID("$FreeBSD: releng/8.0/sys/ufs/ffs/ffs_inode.c 187790 2009-01-27 21:48:47Z rwatson $");
   34 
   35 #include "opt_quota.h"
   36 
   37 #include <sys/param.h>
   38 #include <sys/systm.h>
   39 #include <sys/mount.h>
   40 #include <sys/proc.h>
   41 #include <sys/bio.h>
   42 #include <sys/buf.h>
   43 #include <sys/vnode.h>
   44 #include <sys/malloc.h>
   45 #include <sys/resourcevar.h>
   46 #include <sys/vmmeter.h>
   47 #include <sys/stat.h>
   48 
   49 #include <vm/vm.h>
   50 #include <vm/vm_extern.h>
   51 #include <vm/vm_object.h>
   52 
   53 #include <ufs/ufs/extattr.h>
   54 #include <ufs/ufs/quota.h>
   55 #include <ufs/ufs/ufsmount.h>
   56 #include <ufs/ufs/inode.h>
   57 #include <ufs/ufs/ufs_extern.h>
   58 
   59 #include <ufs/ffs/fs.h>
   60 #include <ufs/ffs/ffs_extern.h>
   61 
   62 static int ffs_indirtrunc(struct inode *, ufs2_daddr_t, ufs2_daddr_t,
   63             ufs2_daddr_t, int, ufs2_daddr_t *);
   64 
   65 /*
   66  * Update the access, modified, and inode change times as specified by the
   67  * IN_ACCESS, IN_UPDATE, and IN_CHANGE flags respectively.  Write the inode
   68  * to disk if the IN_MODIFIED flag is set (it may be set initially, or by
   69  * the timestamp update).  The IN_LAZYMOD flag is set to force a write
   70  * later if not now.  The IN_LAZYACCESS is set instead of IN_MODIFIED if the fs
   71  * is currently being suspended (or is suspended) and vnode has been accessed.
   72  * If we write now, then clear IN_MODIFIED, IN_LAZYACCESS and IN_LAZYMOD to
   73  * reflect the presumably successful write, and if waitfor is set, then wait
   74  * for the write to complete.
   75  */
   76 int
   77 ffs_update(vp, waitfor)
   78         struct vnode *vp;
   79         int waitfor;
   80 {
   81         struct fs *fs;
   82         struct buf *bp;
   83         struct inode *ip;
   84         int error;
   85 
   86         ASSERT_VOP_ELOCKED(vp, "ffs_update");
   87         ufs_itimes(vp);
   88         ip = VTOI(vp);
   89         if ((ip->i_flag & IN_MODIFIED) == 0 && waitfor == 0)
   90                 return (0);
   91         ip->i_flag &= ~(IN_LAZYACCESS | IN_LAZYMOD | IN_MODIFIED);
   92         fs = ip->i_fs;
   93         if (fs->fs_ronly)
   94                 return (0);
   95         /*
   96          * Ensure that uid and gid are correct. This is a temporary
   97          * fix until fsck has been changed to do the update.
   98          */
   99         if (fs->fs_magic == FS_UFS1_MAGIC &&            /* XXX */
  100             fs->fs_old_inodefmt < FS_44INODEFMT) {      /* XXX */
  101                 ip->i_din1->di_ouid = ip->i_uid;        /* XXX */
  102                 ip->i_din1->di_ogid = ip->i_gid;        /* XXX */
  103         }                                               /* XXX */
  104         error = bread(ip->i_devvp, fsbtodb(fs, ino_to_fsba(fs, ip->i_number)),
  105                 (int)fs->fs_bsize, NOCRED, &bp);
  106         if (error) {
  107                 brelse(bp);
  108                 return (error);
  109         }
  110         if (DOINGSOFTDEP(vp))
  111                 softdep_update_inodeblock(ip, bp, waitfor);
  112         else if (ip->i_effnlink != ip->i_nlink)
  113                 panic("ffs_update: bad link cnt");
  114         if (ip->i_ump->um_fstype == UFS1)
  115                 *((struct ufs1_dinode *)bp->b_data +
  116                     ino_to_fsbo(fs, ip->i_number)) = *ip->i_din1;
  117         else
  118                 *((struct ufs2_dinode *)bp->b_data +
  119                     ino_to_fsbo(fs, ip->i_number)) = *ip->i_din2;
  120         if (waitfor && !DOINGASYNC(vp)) {
  121                 return (bwrite(bp));
  122         } else if (vm_page_count_severe() || buf_dirty_count_severe()) {
  123                 return (bwrite(bp));
  124         } else {
  125                 if (bp->b_bufsize == fs->fs_bsize)
  126                         bp->b_flags |= B_CLUSTEROK;
  127                 bdwrite(bp);
  128                 return (0);
  129         }
  130 }
  131 
  132 static void
  133 ffs_pages_remove(struct vnode *vp, vm_pindex_t start, vm_pindex_t end)
  134 {
  135         vm_object_t object;
  136 
  137         if ((object = vp->v_object) == NULL)
  138                 return;
  139         VM_OBJECT_LOCK(object);
  140         vm_object_page_remove(object, start, end, FALSE);
  141         VM_OBJECT_UNLOCK(object);
  142 }
  143 
  144 #define SINGLE  0       /* index of single indirect block */
  145 #define DOUBLE  1       /* index of double indirect block */
  146 #define TRIPLE  2       /* index of triple indirect block */
  147 /*
  148  * Truncate the inode ip to at most length size, freeing the
  149  * disk blocks.
  150  */
  151 int
  152 ffs_truncate(vp, length, flags, cred, td)
  153         struct vnode *vp;
  154         off_t length;
  155         int flags;
  156         struct ucred *cred;
  157         struct thread *td;
  158 {
  159         struct inode *ip;
  160         ufs2_daddr_t bn, lbn, lastblock, lastiblock[NIADDR], indir_lbn[NIADDR];
  161         ufs2_daddr_t oldblks[NDADDR + NIADDR], newblks[NDADDR + NIADDR];
  162         ufs2_daddr_t count, blocksreleased = 0, datablocks;
  163         struct bufobj *bo;
  164         struct fs *fs;
  165         struct buf *bp;
  166         struct ufsmount *ump;
  167         int needextclean, softdepslowdown, extblocks;
  168         int offset, size, level, nblocks;
  169         int i, error, allerror;
  170         off_t osize;
  171 
  172         ip = VTOI(vp);
  173         fs = ip->i_fs;
  174         ump = ip->i_ump;
  175         bo = &vp->v_bufobj;
  176 
  177         ASSERT_VOP_LOCKED(vp, "ffs_truncate");
  178 
  179         if (length < 0)
  180                 return (EINVAL);
  181         /*
  182          * Historically clients did not have to specify which data
  183          * they were truncating. So, if not specified, we assume
  184          * traditional behavior, e.g., just the normal data.
  185          */
  186         if ((flags & (IO_EXT | IO_NORMAL)) == 0)
  187                 flags |= IO_NORMAL;
  188         /*
  189          * If we are truncating the extended-attributes, and cannot
  190          * do it with soft updates, then do it slowly here. If we are
  191          * truncating both the extended attributes and the file contents
  192          * (e.g., the file is being unlinked), then pick it off with
  193          * soft updates below.
  194          */
  195         needextclean = 0;
  196         softdepslowdown = DOINGSOFTDEP(vp) && softdep_slowdown(vp);
  197         extblocks = 0;
  198         datablocks = DIP(ip, i_blocks);
  199         if (fs->fs_magic == FS_UFS2_MAGIC && ip->i_din2->di_extsize > 0) {
  200                 extblocks = btodb(fragroundup(fs, ip->i_din2->di_extsize));
  201                 datablocks -= extblocks;
  202         }
  203         if ((flags & IO_EXT) && extblocks > 0) {
  204                 if (DOINGSOFTDEP(vp) && softdepslowdown == 0 && length == 0) {
  205                         if ((flags & IO_NORMAL) == 0) {
  206                                 softdep_setup_freeblocks(ip, length, IO_EXT);
  207                                 return (0);
  208                         }
  209                         needextclean = 1;
  210                 } else {
  211                         if (length != 0)
  212                                 panic("ffs_truncate: partial trunc of extdata");
  213                         if ((error = ffs_syncvnode(vp, MNT_WAIT)) != 0)
  214                                 return (error);
  215                         osize = ip->i_din2->di_extsize;
  216                         ip->i_din2->di_blocks -= extblocks;
  217 #ifdef QUOTA
  218                         (void) chkdq(ip, -extblocks, NOCRED, 0);
  219 #endif
  220                         vinvalbuf(vp, V_ALT, 0, 0);
  221                         ffs_pages_remove(vp,
  222                             OFF_TO_IDX(lblktosize(fs, -extblocks)), 0);
  223                         ip->i_din2->di_extsize = 0;
  224                         for (i = 0; i < NXADDR; i++) {
  225                                 oldblks[i] = ip->i_din2->di_extb[i];
  226                                 ip->i_din2->di_extb[i] = 0;
  227                         }
  228                         ip->i_flag |= IN_CHANGE;
  229                         if ((error = ffs_update(vp, 1)))
  230                                 return (error);
  231                         for (i = 0; i < NXADDR; i++) {
  232                                 if (oldblks[i] == 0)
  233                                         continue;
  234                                 ffs_blkfree(ump, fs, ip->i_devvp, oldblks[i],
  235                                     sblksize(fs, osize, i), ip->i_number);
  236                         }
  237                 }
  238         }
  239         if ((flags & IO_NORMAL) == 0)
  240                 return (0);
  241         if (length > fs->fs_maxfilesize)
  242                 return (EFBIG);
  243         if (vp->v_type == VLNK &&
  244             (ip->i_size < vp->v_mount->mnt_maxsymlinklen ||
  245              datablocks == 0)) {
  246 #ifdef INVARIANTS
  247                 if (length != 0)
  248                         panic("ffs_truncate: partial truncate of symlink");
  249 #endif
  250                 bzero(SHORTLINK(ip), (u_int)ip->i_size);
  251                 ip->i_size = 0;
  252                 DIP_SET(ip, i_size, 0);
  253                 ip->i_flag |= IN_CHANGE | IN_UPDATE;
  254                 if (needextclean)
  255                         softdep_setup_freeblocks(ip, length, IO_EXT);
  256                 return (ffs_update(vp, 1));
  257         }
  258         if (ip->i_size == length) {
  259                 ip->i_flag |= IN_CHANGE | IN_UPDATE;
  260                 if (needextclean)
  261                         softdep_setup_freeblocks(ip, length, IO_EXT);
  262                 return (ffs_update(vp, 0));
  263         }
  264         if (fs->fs_ronly)
  265                 panic("ffs_truncate: read-only filesystem");
  266 #ifdef QUOTA
  267         error = getinoquota(ip);
  268         if (error)
  269                 return (error);
  270 #endif
  271         if ((ip->i_flags & SF_SNAPSHOT) != 0)
  272                 ffs_snapremove(vp);
  273         vp->v_lasta = vp->v_clen = vp->v_cstart = vp->v_lastw = 0;
  274         if (DOINGSOFTDEP(vp)) {
  275                 if (length > 0 || softdepslowdown) {
  276                         /*
  277                          * If a file is only partially truncated, then
  278                          * we have to clean up the data structures
  279                          * describing the allocation past the truncation
  280                          * point. Finding and deallocating those structures
  281                          * is a lot of work. Since partial truncation occurs
  282                          * rarely, we solve the problem by syncing the file
  283                          * so that it will have no data structures left.
  284                          */
  285                         if ((error = ffs_syncvnode(vp, MNT_WAIT)) != 0)
  286                                 return (error);
  287                         UFS_LOCK(ump);
  288                         if (ip->i_flag & IN_SPACECOUNTED)
  289                                 fs->fs_pendingblocks -= datablocks;
  290                         UFS_UNLOCK(ump);
  291                 } else {
  292 #ifdef QUOTA
  293                         (void) chkdq(ip, -datablocks, NOCRED, 0);
  294 #endif
  295                         softdep_setup_freeblocks(ip, length, needextclean ?
  296                             IO_EXT | IO_NORMAL : IO_NORMAL);
  297                         ASSERT_VOP_LOCKED(vp, "ffs_truncate1");
  298                         vinvalbuf(vp, needextclean ? 0 : V_NORMAL, 0, 0);
  299                         if (!needextclean)
  300                                 ffs_pages_remove(vp, 0,
  301                                     OFF_TO_IDX(lblktosize(fs, -extblocks)));
  302                         vnode_pager_setsize(vp, 0);
  303                         ip->i_flag |= IN_CHANGE | IN_UPDATE;
  304                         return (ffs_update(vp, 0));
  305                 }
  306         }
  307         osize = ip->i_size;
  308         /*
  309          * Lengthen the size of the file. We must ensure that the
  310          * last byte of the file is allocated. Since the smallest
  311          * value of osize is 0, length will be at least 1.
  312          */
  313         if (osize < length) {
  314                 vnode_pager_setsize(vp, length);
  315                 flags |= BA_CLRBUF;
  316                 error = UFS_BALLOC(vp, length - 1, 1, cred, flags, &bp);
  317                 if (error) {
  318                         vnode_pager_setsize(vp, osize);
  319                         return (error);
  320                 }
  321                 ip->i_size = length;
  322                 DIP_SET(ip, i_size, length);
  323                 if (bp->b_bufsize == fs->fs_bsize)
  324                         bp->b_flags |= B_CLUSTEROK;
  325                 if (flags & IO_SYNC)
  326                         bwrite(bp);
  327                 else
  328                         bawrite(bp);
  329                 ip->i_flag |= IN_CHANGE | IN_UPDATE;
  330                 return (ffs_update(vp, 1));
  331         }
  332         /*
  333          * Shorten the size of the file. If the file is not being
  334          * truncated to a block boundary, the contents of the
  335          * partial block following the end of the file must be
  336          * zero'ed in case it ever becomes accessible again because
  337          * of subsequent file growth. Directories however are not
  338          * zero'ed as they should grow back initialized to empty.
  339          */
  340         offset = blkoff(fs, length);
  341         if (offset == 0) {
  342                 ip->i_size = length;
  343                 DIP_SET(ip, i_size, length);
  344         } else {
  345                 lbn = lblkno(fs, length);
  346                 flags |= BA_CLRBUF;
  347                 error = UFS_BALLOC(vp, length - 1, 1, cred, flags, &bp);
  348                 if (error) {
  349                         return (error);
  350                 }
  351                 /*
  352                  * When we are doing soft updates and the UFS_BALLOC
  353                  * above fills in a direct block hole with a full sized
  354                  * block that will be truncated down to a fragment below,
  355                  * we must flush out the block dependency with an FSYNC
  356                  * so that we do not get a soft updates inconsistency
  357                  * when we create the fragment below.
  358                  */
  359                 if (DOINGSOFTDEP(vp) && lbn < NDADDR &&
  360                     fragroundup(fs, blkoff(fs, length)) < fs->fs_bsize &&
  361                     (error = ffs_syncvnode(vp, MNT_WAIT)) != 0)
  362                         return (error);
  363                 ip->i_size = length;
  364                 DIP_SET(ip, i_size, length);
  365                 size = blksize(fs, ip, lbn);
  366                 if (vp->v_type != VDIR)
  367                         bzero((char *)bp->b_data + offset,
  368                             (u_int)(size - offset));
  369                 /* Kirk's code has reallocbuf(bp, size, 1) here */
  370                 allocbuf(bp, size);
  371                 if (bp->b_bufsize == fs->fs_bsize)
  372                         bp->b_flags |= B_CLUSTEROK;
  373                 if (flags & IO_SYNC)
  374                         bwrite(bp);
  375                 else
  376                         bawrite(bp);
  377         }
  378         /*
  379          * Calculate index into inode's block list of
  380          * last direct and indirect blocks (if any)
  381          * which we want to keep.  Lastblock is -1 when
  382          * the file is truncated to 0.
  383          */
  384         lastblock = lblkno(fs, length + fs->fs_bsize - 1) - 1;
  385         lastiblock[SINGLE] = lastblock - NDADDR;
  386         lastiblock[DOUBLE] = lastiblock[SINGLE] - NINDIR(fs);
  387         lastiblock[TRIPLE] = lastiblock[DOUBLE] - NINDIR(fs) * NINDIR(fs);
  388         nblocks = btodb(fs->fs_bsize);
  389         /*
  390          * Update file and block pointers on disk before we start freeing
  391          * blocks.  If we crash before free'ing blocks below, the blocks
  392          * will be returned to the free list.  lastiblock values are also
  393          * normalized to -1 for calls to ffs_indirtrunc below.
  394          */
  395         for (level = TRIPLE; level >= SINGLE; level--) {
  396                 oldblks[NDADDR + level] = DIP(ip, i_ib[level]);
  397                 if (lastiblock[level] < 0) {
  398                         DIP_SET(ip, i_ib[level], 0);
  399                         lastiblock[level] = -1;
  400                 }
  401         }
  402         for (i = 0; i < NDADDR; i++) {
  403                 oldblks[i] = DIP(ip, i_db[i]);
  404                 if (i > lastblock)
  405                         DIP_SET(ip, i_db[i], 0);
  406         }
  407         ip->i_flag |= IN_CHANGE | IN_UPDATE;
  408         allerror = ffs_update(vp, 1);
  409         
  410         /*
  411          * Having written the new inode to disk, save its new configuration
  412          * and put back the old block pointers long enough to process them.
  413          * Note that we save the new block configuration so we can check it
  414          * when we are done.
  415          */
  416         for (i = 0; i < NDADDR; i++) {
  417                 newblks[i] = DIP(ip, i_db[i]);
  418                 DIP_SET(ip, i_db[i], oldblks[i]);
  419         }
  420         for (i = 0; i < NIADDR; i++) {
  421                 newblks[NDADDR + i] = DIP(ip, i_ib[i]);
  422                 DIP_SET(ip, i_ib[i], oldblks[NDADDR + i]);
  423         }
  424         ip->i_size = osize;
  425         DIP_SET(ip, i_size, osize);
  426 
  427         error = vtruncbuf(vp, cred, td, length, fs->fs_bsize);
  428         if (error && (allerror == 0))
  429                 allerror = error;
  430 
  431         /*
  432          * Indirect blocks first.
  433          */
  434         indir_lbn[SINGLE] = -NDADDR;
  435         indir_lbn[DOUBLE] = indir_lbn[SINGLE] - NINDIR(fs) - 1;
  436         indir_lbn[TRIPLE] = indir_lbn[DOUBLE] - NINDIR(fs) * NINDIR(fs) - 1;
  437         for (level = TRIPLE; level >= SINGLE; level--) {
  438                 bn = DIP(ip, i_ib[level]);
  439                 if (bn != 0) {
  440                         error = ffs_indirtrunc(ip, indir_lbn[level],
  441                             fsbtodb(fs, bn), lastiblock[level], level, &count);
  442                         if (error)
  443                                 allerror = error;
  444                         blocksreleased += count;
  445                         if (lastiblock[level] < 0) {
  446                                 DIP_SET(ip, i_ib[level], 0);
  447                                 ffs_blkfree(ump, fs, ip->i_devvp, bn,
  448                                     fs->fs_bsize, ip->i_number);
  449                                 blocksreleased += nblocks;
  450                         }
  451                 }
  452                 if (lastiblock[level] >= 0)
  453                         goto done;
  454         }
  455 
  456         /*
  457          * All whole direct blocks or frags.
  458          */
  459         for (i = NDADDR - 1; i > lastblock; i--) {
  460                 long bsize;
  461 
  462                 bn = DIP(ip, i_db[i]);
  463                 if (bn == 0)
  464                         continue;
  465                 DIP_SET(ip, i_db[i], 0);
  466                 bsize = blksize(fs, ip, i);
  467                 ffs_blkfree(ump, fs, ip->i_devvp, bn, bsize, ip->i_number);
  468                 blocksreleased += btodb(bsize);
  469         }
  470         if (lastblock < 0)
  471                 goto done;
  472 
  473         /*
  474          * Finally, look for a change in size of the
  475          * last direct block; release any frags.
  476          */
  477         bn = DIP(ip, i_db[lastblock]);
  478         if (bn != 0) {
  479                 long oldspace, newspace;
  480 
  481                 /*
  482                  * Calculate amount of space we're giving
  483                  * back as old block size minus new block size.
  484                  */
  485                 oldspace = blksize(fs, ip, lastblock);
  486                 ip->i_size = length;
  487                 DIP_SET(ip, i_size, length);
  488                 newspace = blksize(fs, ip, lastblock);
  489                 if (newspace == 0)
  490                         panic("ffs_truncate: newspace");
  491                 if (oldspace - newspace > 0) {
  492                         /*
  493                          * Block number of space to be free'd is
  494                          * the old block # plus the number of frags
  495                          * required for the storage we're keeping.
  496                          */
  497                         bn += numfrags(fs, newspace);
  498                         ffs_blkfree(ump, fs, ip->i_devvp, bn,
  499                             oldspace - newspace, ip->i_number);
  500                         blocksreleased += btodb(oldspace - newspace);
  501                 }
  502         }
  503 done:
  504 #ifdef INVARIANTS
  505         for (level = SINGLE; level <= TRIPLE; level++)
  506                 if (newblks[NDADDR + level] != DIP(ip, i_ib[level]))
  507                         panic("ffs_truncate1");
  508         for (i = 0; i < NDADDR; i++)
  509                 if (newblks[i] != DIP(ip, i_db[i]))
  510                         panic("ffs_truncate2");
  511         BO_LOCK(bo);
  512         if (length == 0 &&
  513             (fs->fs_magic != FS_UFS2_MAGIC || ip->i_din2->di_extsize == 0) &&
  514             (bo->bo_dirty.bv_cnt > 0 || bo->bo_clean.bv_cnt > 0))
  515                 panic("ffs_truncate3");
  516         BO_UNLOCK(bo);
  517 #endif /* INVARIANTS */
  518         /*
  519          * Put back the real size.
  520          */
  521         ip->i_size = length;
  522         DIP_SET(ip, i_size, length);
  523         DIP_SET(ip, i_blocks, DIP(ip, i_blocks) - blocksreleased);
  524 
  525         if (DIP(ip, i_blocks) < 0)                      /* sanity */
  526                 DIP_SET(ip, i_blocks, 0);
  527         ip->i_flag |= IN_CHANGE;
  528 #ifdef QUOTA
  529         (void) chkdq(ip, -blocksreleased, NOCRED, 0);
  530 #endif
  531         return (allerror);
  532 }
  533 
  534 /*
  535  * Release blocks associated with the inode ip and stored in the indirect
  536  * block bn.  Blocks are free'd in LIFO order up to (but not including)
  537  * lastbn.  If level is greater than SINGLE, the block is an indirect block
  538  * and recursive calls to indirtrunc must be used to cleanse other indirect
  539  * blocks.
  540  */
  541 static int
  542 ffs_indirtrunc(ip, lbn, dbn, lastbn, level, countp)
  543         struct inode *ip;
  544         ufs2_daddr_t lbn, lastbn;
  545         ufs2_daddr_t dbn;
  546         int level;
  547         ufs2_daddr_t *countp;
  548 {
  549         struct buf *bp;
  550         struct fs *fs = ip->i_fs;
  551         struct vnode *vp;
  552         caddr_t copy = NULL;
  553         int i, nblocks, error = 0, allerror = 0;
  554         ufs2_daddr_t nb, nlbn, last;
  555         ufs2_daddr_t blkcount, factor, blocksreleased = 0;
  556         ufs1_daddr_t *bap1 = NULL;
  557         ufs2_daddr_t *bap2 = NULL;
  558 #       define BAP(ip, i) (((ip)->i_ump->um_fstype == UFS1) ? bap1[i] : bap2[i])
  559 
  560         /*
  561          * Calculate index in current block of last
  562          * block to be kept.  -1 indicates the entire
  563          * block so we need not calculate the index.
  564          */
  565         factor = 1;
  566         for (i = SINGLE; i < level; i++)
  567                 factor *= NINDIR(fs);
  568         last = lastbn;
  569         if (lastbn > 0)
  570                 last /= factor;
  571         nblocks = btodb(fs->fs_bsize);
  572         /*
  573          * Get buffer of block pointers, zero those entries corresponding
  574          * to blocks to be free'd, and update on disk copy first.  Since
  575          * double(triple) indirect before single(double) indirect, calls
  576          * to bmap on these blocks will fail.  However, we already have
  577          * the on disk address, so we have to set the b_blkno field
  578          * explicitly instead of letting bread do everything for us.
  579          */
  580         vp = ITOV(ip);
  581         bp = getblk(vp, lbn, (int)fs->fs_bsize, 0, 0, 0);
  582         if ((bp->b_flags & B_CACHE) == 0) {
  583                 curthread->td_ru.ru_inblock++;  /* pay for read */
  584                 bp->b_iocmd = BIO_READ;
  585                 bp->b_flags &= ~B_INVAL;
  586                 bp->b_ioflags &= ~BIO_ERROR;
  587                 if (bp->b_bcount > bp->b_bufsize)
  588                         panic("ffs_indirtrunc: bad buffer size");
  589                 bp->b_blkno = dbn;
  590                 vfs_busy_pages(bp, 0);
  591                 bp->b_iooffset = dbtob(bp->b_blkno);
  592                 bstrategy(bp);
  593                 error = bufwait(bp);
  594         }
  595         if (error) {
  596                 brelse(bp);
  597                 *countp = 0;
  598                 return (error);
  599         }
  600 
  601         if (ip->i_ump->um_fstype == UFS1)
  602                 bap1 = (ufs1_daddr_t *)bp->b_data;
  603         else
  604                 bap2 = (ufs2_daddr_t *)bp->b_data;
  605         if (lastbn != -1) {
  606                 copy = malloc(fs->fs_bsize, M_TEMP, M_WAITOK);
  607                 bcopy((caddr_t)bp->b_data, copy, (u_int)fs->fs_bsize);
  608                 for (i = last + 1; i < NINDIR(fs); i++)
  609                         if (ip->i_ump->um_fstype == UFS1)
  610                                 bap1[i] = 0;
  611                         else
  612                                 bap2[i] = 0;
  613                 if (DOINGASYNC(vp)) {
  614                         bawrite(bp);
  615                 } else {
  616                         error = bwrite(bp);
  617                         if (error)
  618                                 allerror = error;
  619                 }
  620                 if (ip->i_ump->um_fstype == UFS1)
  621                         bap1 = (ufs1_daddr_t *)copy;
  622                 else
  623                         bap2 = (ufs2_daddr_t *)copy;
  624         }
  625 
  626         /*
  627          * Recursively free totally unused blocks.
  628          */
  629         for (i = NINDIR(fs) - 1, nlbn = lbn + 1 - i * factor; i > last;
  630             i--, nlbn += factor) {
  631                 nb = BAP(ip, i);
  632                 if (nb == 0)
  633                         continue;
  634                 if (level > SINGLE) {
  635                         if ((error = ffs_indirtrunc(ip, nlbn, fsbtodb(fs, nb),
  636                             (ufs2_daddr_t)-1, level - 1, &blkcount)) != 0)
  637                                 allerror = error;
  638                         blocksreleased += blkcount;
  639                 }
  640                 ffs_blkfree(ip->i_ump, fs, ip->i_devvp, nb, fs->fs_bsize,
  641                     ip->i_number);
  642                 blocksreleased += nblocks;
  643         }
  644 
  645         /*
  646          * Recursively free last partial block.
  647          */
  648         if (level > SINGLE && lastbn >= 0) {
  649                 last = lastbn % factor;
  650                 nb = BAP(ip, i);
  651                 if (nb != 0) {
  652                         error = ffs_indirtrunc(ip, nlbn, fsbtodb(fs, nb),
  653                             last, level - 1, &blkcount);
  654                         if (error)
  655                                 allerror = error;
  656                         blocksreleased += blkcount;
  657                 }
  658         }
  659         if (copy != NULL) {
  660                 free(copy, M_TEMP);
  661         } else {
  662                 bp->b_flags |= B_INVAL | B_NOCACHE;
  663                 brelse(bp);
  664         }
  665 
  666         *countp = blocksreleased;
  667         return (allerror);
  668 }
  669 
  670 int
  671 ffs_rdonly(struct inode *ip)
  672 {
  673 
  674         return (ip->i_ump->um_fs->fs_ronly != 0);
  675 }
  676 

Cache object: 14c843ac9751d6f0141ea4856e5bca4d


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