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/10.1/sys/ufs/ffs/ffs_inode.c 251171 2013-05-31 00:43:41Z jeff $");
   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/rwlock.h>
   47 #include <sys/vmmeter.h>
   48 #include <sys/stat.h>
   49 
   50 #include <vm/vm.h>
   51 #include <vm/vm_extern.h>
   52 #include <vm/vm_object.h>
   53 
   54 #include <ufs/ufs/extattr.h>
   55 #include <ufs/ufs/quota.h>
   56 #include <ufs/ufs/ufsmount.h>
   57 #include <ufs/ufs/inode.h>
   58 #include <ufs/ufs/ufs_extern.h>
   59 
   60 #include <ufs/ffs/fs.h>
   61 #include <ufs/ffs/ffs_extern.h>
   62 
   63 static int ffs_indirtrunc(struct inode *, ufs2_daddr_t, ufs2_daddr_t,
   64             ufs2_daddr_t, int, ufs2_daddr_t *);
   65 
   66 /*
   67  * Update the access, modified, and inode change times as specified by the
   68  * IN_ACCESS, IN_UPDATE, and IN_CHANGE flags respectively.  Write the inode
   69  * to disk if the IN_MODIFIED flag is set (it may be set initially, or by
   70  * the timestamp update).  The IN_LAZYMOD flag is set to force a write
   71  * later if not now.  The IN_LAZYACCESS is set instead of IN_MODIFIED if the fs
   72  * is currently being suspended (or is suspended) and vnode has been accessed.
   73  * If we write now, then clear IN_MODIFIED, IN_LAZYACCESS and IN_LAZYMOD to
   74  * reflect the presumably successful write, and if waitfor is set, then wait
   75  * for the write to complete.
   76  */
   77 int
   78 ffs_update(vp, waitfor)
   79         struct vnode *vp;
   80         int waitfor;
   81 {
   82         struct fs *fs;
   83         struct buf *bp;
   84         struct inode *ip;
   85         int flags, error;
   86 
   87         ASSERT_VOP_ELOCKED(vp, "ffs_update");
   88         ufs_itimes(vp);
   89         ip = VTOI(vp);
   90         if ((ip->i_flag & IN_MODIFIED) == 0 && waitfor == 0)
   91                 return (0);
   92         ip->i_flag &= ~(IN_LAZYACCESS | IN_LAZYMOD | IN_MODIFIED);
   93         fs = ip->i_fs;
   94         if (fs->fs_ronly && ip->i_ump->um_fsckpid == 0)
   95                 return (0);
   96         /*
   97          * If we are updating a snapshot and another process is currently
   98          * writing the buffer containing the inode for this snapshot then
   99          * a deadlock can occur when it tries to check the snapshot to see
  100          * if that block needs to be copied. Thus when updating a snapshot
  101          * we check to see if the buffer is already locked, and if it is
  102          * we drop the snapshot lock until the buffer has been written
  103          * and is available to us. We have to grab a reference to the
  104          * snapshot vnode to prevent it from being removed while we are
  105          * waiting for the buffer.
  106          */
  107         flags = 0;
  108         if (IS_SNAPSHOT(ip))
  109                 flags = GB_LOCK_NOWAIT;
  110 loop:
  111         error = breadn_flags(ip->i_devvp,
  112              fsbtodb(fs, ino_to_fsba(fs, ip->i_number)),
  113              (int) fs->fs_bsize, 0, 0, 0, NOCRED, flags, &bp);
  114         if (error != 0) {
  115                 if (error != EBUSY) {
  116                         brelse(bp);
  117                         return (error);
  118                 }
  119                 KASSERT((IS_SNAPSHOT(ip)), ("EBUSY from non-snapshot"));
  120                 /*
  121                  * Wait for our inode block to become available.
  122                  *
  123                  * Hold a reference to the vnode to protect against
  124                  * ffs_snapgone(). Since we hold a reference, it can only
  125                  * get reclaimed (VI_DOOMED flag) in a forcible downgrade
  126                  * or unmount. For an unmount, the entire filesystem will be
  127                  * gone, so we cannot attempt to touch anything associated
  128                  * with it while the vnode is unlocked; all we can do is 
  129                  * pause briefly and try again. If when we relock the vnode
  130                  * we discover that it has been reclaimed, updating it is no
  131                  * longer necessary and we can just return an error.
  132                  */
  133                 vref(vp);
  134                 VOP_UNLOCK(vp, 0);
  135                 pause("ffsupd", 1);
  136                 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
  137                 vrele(vp);
  138                 if ((vp->v_iflag & VI_DOOMED) != 0)
  139                         return (ENOENT);
  140                 goto loop;
  141         }
  142         if (DOINGSOFTDEP(vp))
  143                 softdep_update_inodeblock(ip, bp, waitfor);
  144         else if (ip->i_effnlink != ip->i_nlink)
  145                 panic("ffs_update: bad link cnt");
  146         if (ip->i_ump->um_fstype == UFS1)
  147                 *((struct ufs1_dinode *)bp->b_data +
  148                     ino_to_fsbo(fs, ip->i_number)) = *ip->i_din1;
  149         else
  150                 *((struct ufs2_dinode *)bp->b_data +
  151                     ino_to_fsbo(fs, ip->i_number)) = *ip->i_din2;
  152         if (waitfor && !DOINGASYNC(vp))
  153                 error = bwrite(bp);
  154         else if (vm_page_count_severe() || buf_dirty_count_severe()) {
  155                 bawrite(bp);
  156                 error = 0;
  157         } else {
  158                 if (bp->b_bufsize == fs->fs_bsize)
  159                         bp->b_flags |= B_CLUSTEROK;
  160                 bdwrite(bp);
  161                 error = 0;
  162         }
  163         return (error);
  164 }
  165 
  166 #define SINGLE  0       /* index of single indirect block */
  167 #define DOUBLE  1       /* index of double indirect block */
  168 #define TRIPLE  2       /* index of triple indirect block */
  169 /*
  170  * Truncate the inode ip to at most length size, freeing the
  171  * disk blocks.
  172  */
  173 int
  174 ffs_truncate(vp, length, flags, cred)
  175         struct vnode *vp;
  176         off_t length;
  177         int flags;
  178         struct ucred *cred;
  179 {
  180         struct inode *ip;
  181         ufs2_daddr_t bn, lbn, lastblock, lastiblock[NIADDR], indir_lbn[NIADDR];
  182         ufs2_daddr_t oldblks[NDADDR + NIADDR], newblks[NDADDR + NIADDR];
  183         ufs2_daddr_t count, blocksreleased = 0, datablocks;
  184         struct bufobj *bo;
  185         struct fs *fs;
  186         struct buf *bp;
  187         struct ufsmount *ump;
  188         int softdeptrunc, journaltrunc;
  189         int needextclean, extblocks;
  190         int offset, size, level, nblocks;
  191         int i, error, allerror;
  192         off_t osize;
  193 
  194         ip = VTOI(vp);
  195         fs = ip->i_fs;
  196         ump = ip->i_ump;
  197         bo = &vp->v_bufobj;
  198 
  199         ASSERT_VOP_LOCKED(vp, "ffs_truncate");
  200 
  201         if (length < 0)
  202                 return (EINVAL);
  203         if (length > fs->fs_maxfilesize)
  204                 return (EFBIG);
  205 #ifdef QUOTA
  206         error = getinoquota(ip);
  207         if (error)
  208                 return (error);
  209 #endif
  210         /*
  211          * Historically clients did not have to specify which data
  212          * they were truncating. So, if not specified, we assume
  213          * traditional behavior, e.g., just the normal data.
  214          */
  215         if ((flags & (IO_EXT | IO_NORMAL)) == 0)
  216                 flags |= IO_NORMAL;
  217         if (!DOINGSOFTDEP(vp) && !DOINGASYNC(vp))
  218                 flags |= IO_SYNC;
  219         /*
  220          * If we are truncating the extended-attributes, and cannot
  221          * do it with soft updates, then do it slowly here. If we are
  222          * truncating both the extended attributes and the file contents
  223          * (e.g., the file is being unlinked), then pick it off with
  224          * soft updates below.
  225          */
  226         allerror = 0;
  227         needextclean = 0;
  228         softdeptrunc = 0;
  229         journaltrunc = DOINGSUJ(vp);
  230         if (journaltrunc == 0 && DOINGSOFTDEP(vp) && length == 0)
  231                 softdeptrunc = !softdep_slowdown(vp);
  232         extblocks = 0;
  233         datablocks = DIP(ip, i_blocks);
  234         if (fs->fs_magic == FS_UFS2_MAGIC && ip->i_din2->di_extsize > 0) {
  235                 extblocks = btodb(fragroundup(fs, ip->i_din2->di_extsize));
  236                 datablocks -= extblocks;
  237         }
  238         if ((flags & IO_EXT) && extblocks > 0) {
  239                 if (length != 0)
  240                         panic("ffs_truncate: partial trunc of extdata");
  241                 if (softdeptrunc || journaltrunc) {
  242                         if ((flags & IO_NORMAL) == 0)
  243                                 goto extclean;
  244                         needextclean = 1;
  245                 } else {
  246                         if ((error = ffs_syncvnode(vp, MNT_WAIT, 0)) != 0)
  247                                 return (error);
  248 #ifdef QUOTA
  249                         (void) chkdq(ip, -extblocks, NOCRED, 0);
  250 #endif
  251                         vinvalbuf(vp, V_ALT, 0, 0);
  252                         vn_pages_remove(vp,
  253                             OFF_TO_IDX(lblktosize(fs, -extblocks)), 0);
  254                         osize = ip->i_din2->di_extsize;
  255                         ip->i_din2->di_blocks -= extblocks;
  256                         ip->i_din2->di_extsize = 0;
  257                         for (i = 0; i < NXADDR; i++) {
  258                                 oldblks[i] = ip->i_din2->di_extb[i];
  259                                 ip->i_din2->di_extb[i] = 0;
  260                         }
  261                         ip->i_flag |= IN_CHANGE;
  262                         if ((error = ffs_update(vp, !DOINGASYNC(vp))))
  263                                 return (error);
  264                         for (i = 0; i < NXADDR; i++) {
  265                                 if (oldblks[i] == 0)
  266                                         continue;
  267                                 ffs_blkfree(ump, fs, ip->i_devvp, oldblks[i],
  268                                     sblksize(fs, osize, i), ip->i_number,
  269                                     vp->v_type, NULL);
  270                         }
  271                 }
  272         }
  273         if ((flags & IO_NORMAL) == 0)
  274                 return (0);
  275         if (vp->v_type == VLNK &&
  276             (ip->i_size < vp->v_mount->mnt_maxsymlinklen ||
  277              datablocks == 0)) {
  278 #ifdef INVARIANTS
  279                 if (length != 0)
  280                         panic("ffs_truncate: partial truncate of symlink");
  281 #endif
  282                 bzero(SHORTLINK(ip), (u_int)ip->i_size);
  283                 ip->i_size = 0;
  284                 DIP_SET(ip, i_size, 0);
  285                 ip->i_flag |= IN_CHANGE | IN_UPDATE;
  286                 if (needextclean)
  287                         goto extclean;
  288                 return (ffs_update(vp, !DOINGASYNC(vp)));
  289         }
  290         if (ip->i_size == length) {
  291                 ip->i_flag |= IN_CHANGE | IN_UPDATE;
  292                 if (needextclean)
  293                         goto extclean;
  294                 return (ffs_update(vp, 0));
  295         }
  296         if (fs->fs_ronly)
  297                 panic("ffs_truncate: read-only filesystem");
  298         if (IS_SNAPSHOT(ip))
  299                 ffs_snapremove(vp);
  300         vp->v_lasta = vp->v_clen = vp->v_cstart = vp->v_lastw = 0;
  301         osize = ip->i_size;
  302         /*
  303          * Lengthen the size of the file. We must ensure that the
  304          * last byte of the file is allocated. Since the smallest
  305          * value of osize is 0, length will be at least 1.
  306          */
  307         if (osize < length) {
  308                 vnode_pager_setsize(vp, length);
  309                 flags |= BA_CLRBUF;
  310                 error = UFS_BALLOC(vp, length - 1, 1, cred, flags, &bp);
  311                 if (error) {
  312                         vnode_pager_setsize(vp, osize);
  313                         return (error);
  314                 }
  315                 ip->i_size = length;
  316                 DIP_SET(ip, i_size, length);
  317                 if (bp->b_bufsize == fs->fs_bsize)
  318                         bp->b_flags |= B_CLUSTEROK;
  319                 if (flags & IO_SYNC)
  320                         bwrite(bp);
  321                 else if (DOINGASYNC(vp))
  322                         bdwrite(bp);
  323                 else
  324                         bawrite(bp);
  325                 ip->i_flag |= IN_CHANGE | IN_UPDATE;
  326                 return (ffs_update(vp, !DOINGASYNC(vp)));
  327         }
  328         if (DOINGSOFTDEP(vp)) {
  329                 if (softdeptrunc == 0 && journaltrunc == 0) {
  330                         /*
  331                          * If a file is only partially truncated, then
  332                          * we have to clean up the data structures
  333                          * describing the allocation past the truncation
  334                          * point. Finding and deallocating those structures
  335                          * is a lot of work. Since partial truncation occurs
  336                          * rarely, we solve the problem by syncing the file
  337                          * so that it will have no data structures left.
  338                          */
  339                         if ((error = ffs_syncvnode(vp, MNT_WAIT, 0)) != 0)
  340                                 return (error);
  341                 } else {
  342                         flags = IO_NORMAL | (needextclean ? IO_EXT: 0);
  343                         if (journaltrunc)
  344                                 softdep_journal_freeblocks(ip, cred, length,
  345                                     flags);
  346                         else
  347                                 softdep_setup_freeblocks(ip, length, flags);
  348                         ASSERT_VOP_LOCKED(vp, "ffs_truncate1");
  349                         if (journaltrunc == 0) {
  350                                 ip->i_flag |= IN_CHANGE | IN_UPDATE;
  351                                 error = ffs_update(vp, 0);
  352                         }
  353                         return (error);
  354                 }
  355         }
  356         /*
  357          * Shorten the size of the file. If the file is not being
  358          * truncated to a block boundary, the contents of the
  359          * partial block following the end of the file must be
  360          * zero'ed in case it ever becomes accessible again because
  361          * of subsequent file growth. Directories however are not
  362          * zero'ed as they should grow back initialized to empty.
  363          */
  364         offset = blkoff(fs, length);
  365         if (offset == 0) {
  366                 ip->i_size = length;
  367                 DIP_SET(ip, i_size, length);
  368         } else {
  369                 lbn = lblkno(fs, length);
  370                 flags |= BA_CLRBUF;
  371                 error = UFS_BALLOC(vp, length - 1, 1, cred, flags, &bp);
  372                 if (error)
  373                         return (error);
  374                 /*
  375                  * When we are doing soft updates and the UFS_BALLOC
  376                  * above fills in a direct block hole with a full sized
  377                  * block that will be truncated down to a fragment below,
  378                  * we must flush out the block dependency with an FSYNC
  379                  * so that we do not get a soft updates inconsistency
  380                  * when we create the fragment below.
  381                  */
  382                 if (DOINGSOFTDEP(vp) && lbn < NDADDR &&
  383                     fragroundup(fs, blkoff(fs, length)) < fs->fs_bsize &&
  384                     (error = ffs_syncvnode(vp, MNT_WAIT, 0)) != 0)
  385                         return (error);
  386                 ip->i_size = length;
  387                 DIP_SET(ip, i_size, length);
  388                 size = blksize(fs, ip, lbn);
  389                 if (vp->v_type != VDIR)
  390                         bzero((char *)bp->b_data + offset,
  391                             (u_int)(size - offset));
  392                 /* Kirk's code has reallocbuf(bp, size, 1) here */
  393                 allocbuf(bp, size);
  394                 if (bp->b_bufsize == fs->fs_bsize)
  395                         bp->b_flags |= B_CLUSTEROK;
  396                 if (flags & IO_SYNC)
  397                         bwrite(bp);
  398                 else if (DOINGASYNC(vp))
  399                         bdwrite(bp);
  400                 else
  401                         bawrite(bp);
  402         }
  403         /*
  404          * Calculate index into inode's block list of
  405          * last direct and indirect blocks (if any)
  406          * which we want to keep.  Lastblock is -1 when
  407          * the file is truncated to 0.
  408          */
  409         lastblock = lblkno(fs, length + fs->fs_bsize - 1) - 1;
  410         lastiblock[SINGLE] = lastblock - NDADDR;
  411         lastiblock[DOUBLE] = lastiblock[SINGLE] - NINDIR(fs);
  412         lastiblock[TRIPLE] = lastiblock[DOUBLE] - NINDIR(fs) * NINDIR(fs);
  413         nblocks = btodb(fs->fs_bsize);
  414         /*
  415          * Update file and block pointers on disk before we start freeing
  416          * blocks.  If we crash before free'ing blocks below, the blocks
  417          * will be returned to the free list.  lastiblock values are also
  418          * normalized to -1 for calls to ffs_indirtrunc below.
  419          */
  420         for (level = TRIPLE; level >= SINGLE; level--) {
  421                 oldblks[NDADDR + level] = DIP(ip, i_ib[level]);
  422                 if (lastiblock[level] < 0) {
  423                         DIP_SET(ip, i_ib[level], 0);
  424                         lastiblock[level] = -1;
  425                 }
  426         }
  427         for (i = 0; i < NDADDR; i++) {
  428                 oldblks[i] = DIP(ip, i_db[i]);
  429                 if (i > lastblock)
  430                         DIP_SET(ip, i_db[i], 0);
  431         }
  432         ip->i_flag |= IN_CHANGE | IN_UPDATE;
  433         allerror = ffs_update(vp, !DOINGASYNC(vp));
  434         
  435         /*
  436          * Having written the new inode to disk, save its new configuration
  437          * and put back the old block pointers long enough to process them.
  438          * Note that we save the new block configuration so we can check it
  439          * when we are done.
  440          */
  441         for (i = 0; i < NDADDR; i++) {
  442                 newblks[i] = DIP(ip, i_db[i]);
  443                 DIP_SET(ip, i_db[i], oldblks[i]);
  444         }
  445         for (i = 0; i < NIADDR; i++) {
  446                 newblks[NDADDR + i] = DIP(ip, i_ib[i]);
  447                 DIP_SET(ip, i_ib[i], oldblks[NDADDR + i]);
  448         }
  449         ip->i_size = osize;
  450         DIP_SET(ip, i_size, osize);
  451 
  452         error = vtruncbuf(vp, cred, length, fs->fs_bsize);
  453         if (error && (allerror == 0))
  454                 allerror = error;
  455 
  456         /*
  457          * Indirect blocks first.
  458          */
  459         indir_lbn[SINGLE] = -NDADDR;
  460         indir_lbn[DOUBLE] = indir_lbn[SINGLE] - NINDIR(fs) - 1;
  461         indir_lbn[TRIPLE] = indir_lbn[DOUBLE] - NINDIR(fs) * NINDIR(fs) - 1;
  462         for (level = TRIPLE; level >= SINGLE; level--) {
  463                 bn = DIP(ip, i_ib[level]);
  464                 if (bn != 0) {
  465                         error = ffs_indirtrunc(ip, indir_lbn[level],
  466                             fsbtodb(fs, bn), lastiblock[level], level, &count);
  467                         if (error)
  468                                 allerror = error;
  469                         blocksreleased += count;
  470                         if (lastiblock[level] < 0) {
  471                                 DIP_SET(ip, i_ib[level], 0);
  472                                 ffs_blkfree(ump, fs, ip->i_devvp, bn,
  473                                     fs->fs_bsize, ip->i_number,
  474                                     vp->v_type, NULL);
  475                                 blocksreleased += nblocks;
  476                         }
  477                 }
  478                 if (lastiblock[level] >= 0)
  479                         goto done;
  480         }
  481 
  482         /*
  483          * All whole direct blocks or frags.
  484          */
  485         for (i = NDADDR - 1; i > lastblock; i--) {
  486                 long bsize;
  487 
  488                 bn = DIP(ip, i_db[i]);
  489                 if (bn == 0)
  490                         continue;
  491                 DIP_SET(ip, i_db[i], 0);
  492                 bsize = blksize(fs, ip, i);
  493                 ffs_blkfree(ump, fs, ip->i_devvp, bn, bsize, ip->i_number,
  494                     vp->v_type, NULL);
  495                 blocksreleased += btodb(bsize);
  496         }
  497         if (lastblock < 0)
  498                 goto done;
  499 
  500         /*
  501          * Finally, look for a change in size of the
  502          * last direct block; release any frags.
  503          */
  504         bn = DIP(ip, i_db[lastblock]);
  505         if (bn != 0) {
  506                 long oldspace, newspace;
  507 
  508                 /*
  509                  * Calculate amount of space we're giving
  510                  * back as old block size minus new block size.
  511                  */
  512                 oldspace = blksize(fs, ip, lastblock);
  513                 ip->i_size = length;
  514                 DIP_SET(ip, i_size, length);
  515                 newspace = blksize(fs, ip, lastblock);
  516                 if (newspace == 0)
  517                         panic("ffs_truncate: newspace");
  518                 if (oldspace - newspace > 0) {
  519                         /*
  520                          * Block number of space to be free'd is
  521                          * the old block # plus the number of frags
  522                          * required for the storage we're keeping.
  523                          */
  524                         bn += numfrags(fs, newspace);
  525                         ffs_blkfree(ump, fs, ip->i_devvp, bn,
  526                            oldspace - newspace, ip->i_number, vp->v_type, NULL);
  527                         blocksreleased += btodb(oldspace - newspace);
  528                 }
  529         }
  530 done:
  531 #ifdef INVARIANTS
  532         for (level = SINGLE; level <= TRIPLE; level++)
  533                 if (newblks[NDADDR + level] != DIP(ip, i_ib[level]))
  534                         panic("ffs_truncate1");
  535         for (i = 0; i < NDADDR; i++)
  536                 if (newblks[i] != DIP(ip, i_db[i]))
  537                         panic("ffs_truncate2");
  538         BO_LOCK(bo);
  539         if (length == 0 &&
  540             (fs->fs_magic != FS_UFS2_MAGIC || ip->i_din2->di_extsize == 0) &&
  541             (bo->bo_dirty.bv_cnt > 0 || bo->bo_clean.bv_cnt > 0))
  542                 panic("ffs_truncate3");
  543         BO_UNLOCK(bo);
  544 #endif /* INVARIANTS */
  545         /*
  546          * Put back the real size.
  547          */
  548         ip->i_size = length;
  549         DIP_SET(ip, i_size, length);
  550         if (DIP(ip, i_blocks) >= blocksreleased)
  551                 DIP_SET(ip, i_blocks, DIP(ip, i_blocks) - blocksreleased);
  552         else    /* sanity */
  553                 DIP_SET(ip, i_blocks, 0);
  554         ip->i_flag |= IN_CHANGE;
  555 #ifdef QUOTA
  556         (void) chkdq(ip, -blocksreleased, NOCRED, 0);
  557 #endif
  558         return (allerror);
  559 
  560 extclean:
  561         if (journaltrunc)
  562                 softdep_journal_freeblocks(ip, cred, length, IO_EXT);
  563         else
  564                 softdep_setup_freeblocks(ip, length, IO_EXT);
  565         return (ffs_update(vp, !DOINGASYNC(vp)));
  566 }
  567 
  568 /*
  569  * Release blocks associated with the inode ip and stored in the indirect
  570  * block bn.  Blocks are free'd in LIFO order up to (but not including)
  571  * lastbn.  If level is greater than SINGLE, the block is an indirect block
  572  * and recursive calls to indirtrunc must be used to cleanse other indirect
  573  * blocks.
  574  */
  575 static int
  576 ffs_indirtrunc(ip, lbn, dbn, lastbn, level, countp)
  577         struct inode *ip;
  578         ufs2_daddr_t lbn, lastbn;
  579         ufs2_daddr_t dbn;
  580         int level;
  581         ufs2_daddr_t *countp;
  582 {
  583         struct buf *bp;
  584         struct fs *fs = ip->i_fs;
  585         struct vnode *vp;
  586         caddr_t copy = NULL;
  587         int i, nblocks, error = 0, allerror = 0;
  588         ufs2_daddr_t nb, nlbn, last;
  589         ufs2_daddr_t blkcount, factor, blocksreleased = 0;
  590         ufs1_daddr_t *bap1 = NULL;
  591         ufs2_daddr_t *bap2 = NULL;
  592 #       define BAP(ip, i) (((ip)->i_ump->um_fstype == UFS1) ? bap1[i] : bap2[i])
  593 
  594         /*
  595          * Calculate index in current block of last
  596          * block to be kept.  -1 indicates the entire
  597          * block so we need not calculate the index.
  598          */
  599         factor = lbn_offset(fs, level);
  600         last = lastbn;
  601         if (lastbn > 0)
  602                 last /= factor;
  603         nblocks = btodb(fs->fs_bsize);
  604         /*
  605          * Get buffer of block pointers, zero those entries corresponding
  606          * to blocks to be free'd, and update on disk copy first.  Since
  607          * double(triple) indirect before single(double) indirect, calls
  608          * to bmap on these blocks will fail.  However, we already have
  609          * the on disk address, so we have to set the b_blkno field
  610          * explicitly instead of letting bread do everything for us.
  611          */
  612         vp = ITOV(ip);
  613         bp = getblk(vp, lbn, (int)fs->fs_bsize, 0, 0, 0);
  614         if ((bp->b_flags & B_CACHE) == 0) {
  615                 curthread->td_ru.ru_inblock++;  /* pay for read */
  616                 bp->b_iocmd = BIO_READ;
  617                 bp->b_flags &= ~B_INVAL;
  618                 bp->b_ioflags &= ~BIO_ERROR;
  619                 if (bp->b_bcount > bp->b_bufsize)
  620                         panic("ffs_indirtrunc: bad buffer size");
  621                 bp->b_blkno = dbn;
  622                 vfs_busy_pages(bp, 0);
  623                 bp->b_iooffset = dbtob(bp->b_blkno);
  624                 bstrategy(bp);
  625                 error = bufwait(bp);
  626         }
  627         if (error) {
  628                 brelse(bp);
  629                 *countp = 0;
  630                 return (error);
  631         }
  632 
  633         if (ip->i_ump->um_fstype == UFS1)
  634                 bap1 = (ufs1_daddr_t *)bp->b_data;
  635         else
  636                 bap2 = (ufs2_daddr_t *)bp->b_data;
  637         if (lastbn != -1) {
  638                 copy = malloc(fs->fs_bsize, M_TEMP, M_WAITOK);
  639                 bcopy((caddr_t)bp->b_data, copy, (u_int)fs->fs_bsize);
  640                 for (i = last + 1; i < NINDIR(fs); i++)
  641                         if (ip->i_ump->um_fstype == UFS1)
  642                                 bap1[i] = 0;
  643                         else
  644                                 bap2[i] = 0;
  645                 if (DOINGASYNC(vp)) {
  646                         bdwrite(bp);
  647                 } else {
  648                         error = bwrite(bp);
  649                         if (error)
  650                                 allerror = error;
  651                 }
  652                 if (ip->i_ump->um_fstype == UFS1)
  653                         bap1 = (ufs1_daddr_t *)copy;
  654                 else
  655                         bap2 = (ufs2_daddr_t *)copy;
  656         }
  657 
  658         /*
  659          * Recursively free totally unused blocks.
  660          */
  661         for (i = NINDIR(fs) - 1, nlbn = lbn + 1 - i * factor; i > last;
  662             i--, nlbn += factor) {
  663                 nb = BAP(ip, i);
  664                 if (nb == 0)
  665                         continue;
  666                 if (level > SINGLE) {
  667                         if ((error = ffs_indirtrunc(ip, nlbn, fsbtodb(fs, nb),
  668                             (ufs2_daddr_t)-1, level - 1, &blkcount)) != 0)
  669                                 allerror = error;
  670                         blocksreleased += blkcount;
  671                 }
  672                 ffs_blkfree(ip->i_ump, fs, ip->i_devvp, nb, fs->fs_bsize,
  673                     ip->i_number, vp->v_type, NULL);
  674                 blocksreleased += nblocks;
  675         }
  676 
  677         /*
  678          * Recursively free last partial block.
  679          */
  680         if (level > SINGLE && lastbn >= 0) {
  681                 last = lastbn % factor;
  682                 nb = BAP(ip, i);
  683                 if (nb != 0) {
  684                         error = ffs_indirtrunc(ip, nlbn, fsbtodb(fs, nb),
  685                             last, level - 1, &blkcount);
  686                         if (error)
  687                                 allerror = error;
  688                         blocksreleased += blkcount;
  689                 }
  690         }
  691         if (copy != NULL) {
  692                 free(copy, M_TEMP);
  693         } else {
  694                 bp->b_flags |= B_INVAL | B_NOCACHE;
  695                 brelse(bp);
  696         }
  697 
  698         *countp = blocksreleased;
  699         return (allerror);
  700 }
  701 
  702 int
  703 ffs_rdonly(struct inode *ip)
  704 {
  705 
  706         return (ip->i_ump->um_fs->fs_ronly != 0);
  707 }
  708 

Cache object: 5fa2401d1ee91777e61e92ca21713124


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