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 /*      $NetBSD: ffs_inode.c,v 1.62 2004/01/25 18:06:49 hannken Exp $   */
    2 
    3 /*
    4  * Copyright (c) 1982, 1986, 1989, 1993
    5  *      The Regents of the University of California.  All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  * 3. Neither the name of the University nor the names of its contributors
   16  *    may be used to endorse or promote products derived from this software
   17  *    without specific prior written permission.
   18  *
   19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   29  * SUCH DAMAGE.
   30  *
   31  *      @(#)ffs_inode.c 8.13 (Berkeley) 4/21/95
   32  */
   33 
   34 #include <sys/cdefs.h>
   35 __KERNEL_RCSID(0, "$NetBSD: ffs_inode.c,v 1.62 2004/01/25 18:06:49 hannken Exp $");
   36 
   37 #if defined(_KERNEL_OPT)
   38 #include "opt_ffs.h"
   39 #include "opt_quota.h"
   40 #endif
   41 
   42 #include <sys/param.h>
   43 #include <sys/systm.h>
   44 #include <sys/mount.h>
   45 #include <sys/proc.h>
   46 #include <sys/file.h>
   47 #include <sys/buf.h>
   48 #include <sys/vnode.h>
   49 #include <sys/kernel.h>
   50 #include <sys/malloc.h>
   51 #include <sys/trace.h>
   52 #include <sys/resourcevar.h>
   53 
   54 #include <ufs/ufs/quota.h>
   55 #include <ufs/ufs/inode.h>
   56 #include <ufs/ufs/ufsmount.h>
   57 #include <ufs/ufs/ufs_extern.h>
   58 #include <ufs/ufs/ufs_bswap.h>
   59 
   60 #include <ufs/ffs/fs.h>
   61 #include <ufs/ffs/ffs_extern.h>
   62 
   63 static int ffs_indirtrunc __P((struct inode *, daddr_t, daddr_t,
   64                                daddr_t, int, int64_t *));
   65 
   66 /*
   67  * Update the access, modified, and inode change times as specified
   68  * by the IN_ACCESS, IN_UPDATE, and IN_CHANGE flags respectively.
   69  * The IN_MODIFIED flag is used to specify that the inode needs to be
   70  * updated but that the times have already been set. The access
   71  * and modified times are taken from the second and third parameters;
   72  * the inode change time is always taken from the current time. If
   73  * UPDATE_WAIT flag is set, or UPDATE_DIROP is set and we are not doing
   74  * softupdates, then wait for the disk write of the inode to complete.
   75  */
   76 
   77 int
   78 ffs_update(v)
   79         void *v;
   80 {
   81         struct vop_update_args /* {
   82                 struct vnode *a_vp;
   83                 struct timespec *a_access;
   84                 struct timespec *a_modify;
   85                 int a_flags;
   86         } */ *ap = v;
   87         struct fs *fs;
   88         struct buf *bp;
   89         struct inode *ip;
   90         int error;
   91         struct timespec ts;
   92         caddr_t cp;
   93         int waitfor, flags;
   94 
   95         if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY)
   96                 return (0);
   97         ip = VTOI(ap->a_vp);
   98         TIMEVAL_TO_TIMESPEC(&time, &ts);
   99         FFS_ITIMES(ip,
  100             ap->a_access ? ap->a_access : &ts,
  101             ap->a_modify ? ap->a_modify : &ts, &ts);
  102         flags = ip->i_flag & (IN_MODIFIED | IN_ACCESSED);
  103         if (flags == 0)
  104                 return (0);
  105         fs = ip->i_fs;
  106 
  107         if ((flags & IN_MODIFIED) != 0 &&
  108             (ap->a_vp->v_mount->mnt_flag & MNT_ASYNC) == 0) {
  109                 waitfor = ap->a_flags & UPDATE_WAIT;
  110                 if ((ap->a_flags & UPDATE_DIROP) && !DOINGSOFTDEP(ap->a_vp))
  111                         waitfor |= UPDATE_WAIT;
  112         } else
  113                 waitfor = 0;
  114 
  115         /*
  116          * Ensure that uid and gid are correct. This is a temporary
  117          * fix until fsck has been changed to do the update.
  118          */
  119         if (fs->fs_magic == FS_UFS1_MAGIC &&                    /* XXX */
  120             fs->fs_old_inodefmt < FS_44INODEFMT) {              /* XXX */
  121                 ip->i_ffs1_ouid = ip->i_uid;    /* XXX */
  122                 ip->i_ffs1_ogid = ip->i_gid;    /* XXX */
  123         }                                                       /* XXX */
  124         error = bread(ip->i_devvp,
  125                       fsbtodb(fs, ino_to_fsba(fs, ip->i_number)),
  126                       (int)fs->fs_bsize, NOCRED, &bp);
  127         if (error) {
  128                 brelse(bp);
  129                 return (error);
  130         }
  131         ip->i_flag &= ~(IN_MODIFIED | IN_ACCESSED);
  132         if (DOINGSOFTDEP(ap->a_vp))
  133                 softdep_update_inodeblock(ip, bp, waitfor);
  134         else if (ip->i_ffs_effnlink != ip->i_nlink)
  135                 panic("ffs_update: bad link cnt");
  136         if (fs->fs_magic == FS_UFS1_MAGIC) {
  137                 cp = (caddr_t)bp->b_data +
  138                     (ino_to_fsbo(fs, ip->i_number) * DINODE1_SIZE);
  139 #ifdef FFS_EI
  140                 if (UFS_FSNEEDSWAP(fs))
  141                         ffs_dinode1_swap(ip->i_din.ffs1_din,
  142                             (struct ufs1_dinode *)cp);
  143                 else
  144 #endif
  145                         memcpy(cp, ip->i_din.ffs1_din, DINODE1_SIZE);
  146         } else {
  147                 cp = (caddr_t)bp->b_data +
  148                     (ino_to_fsbo(fs, ip->i_number) * DINODE2_SIZE);
  149 #ifdef FFS_EI
  150                 if (UFS_FSNEEDSWAP(fs))
  151                         ffs_dinode2_swap(ip->i_din.ffs2_din,
  152                             (struct ufs2_dinode *)cp);
  153                 else
  154 #endif
  155                         memcpy(cp, ip->i_din.ffs2_din, DINODE2_SIZE);
  156         }
  157         if (waitfor) {
  158                 return (bwrite(bp));
  159         } else {
  160                 bdwrite(bp);
  161                 return (0);
  162         }
  163 }
  164 
  165 #define SINGLE  0       /* index of single indirect block */
  166 #define DOUBLE  1       /* index of double indirect block */
  167 #define TRIPLE  2       /* index of triple indirect block */
  168 /*
  169  * Truncate the inode oip to at most length size, freeing the
  170  * disk blocks.
  171  */
  172 int
  173 ffs_truncate(v)
  174         void *v;
  175 {
  176         struct vop_truncate_args /* {
  177                 struct vnode *a_vp;
  178                 off_t a_length;
  179                 int a_flags;
  180                 struct ucred *a_cred;
  181                 struct proc *a_p;
  182         } */ *ap = v;
  183         struct vnode *ovp = ap->a_vp;
  184         struct genfs_node *gp = VTOG(ovp);
  185         daddr_t lastblock;
  186         struct inode *oip;
  187         daddr_t bn, lastiblock[NIADDR], indir_lbn[NIADDR];
  188         daddr_t oldblks[NDADDR + NIADDR], newblks[NDADDR + NIADDR];
  189         off_t length = ap->a_length;
  190         struct fs *fs;
  191         int offset, size, level;
  192         int64_t count, blocksreleased = 0;
  193         int i, ioflag, aflag, nblocks;
  194         int error, allerror = 0;
  195         off_t osize;
  196 
  197         if (length < 0)
  198                 return (EINVAL);
  199         oip = VTOI(ovp);
  200         if (ovp->v_type == VLNK &&
  201             (oip->i_size < ovp->v_mount->mnt_maxsymlinklen ||
  202              (ovp->v_mount->mnt_maxsymlinklen == 0 &&
  203               DIP(oip, blocks) == 0))) {
  204                 KDASSERT(length == 0);
  205                 memset(SHORTLINK(oip), 0, (size_t)oip->i_size);
  206                 oip->i_size = 0;
  207                 DIP_ASSIGN(oip, size, 0);
  208                 oip->i_flag |= IN_CHANGE | IN_UPDATE;
  209                 return (VOP_UPDATE(ovp, NULL, NULL, UPDATE_WAIT));
  210         }
  211         if (oip->i_size == length) {
  212                 oip->i_flag |= IN_CHANGE | IN_UPDATE;
  213                 return (VOP_UPDATE(ovp, NULL, NULL, 0));
  214         }
  215 #ifdef QUOTA
  216         if ((error = getinoquota(oip)) != 0)
  217                 return (error);
  218 #endif
  219         fs = oip->i_fs;
  220         if (length > fs->fs_maxfilesize)
  221                 return (EFBIG);
  222 
  223         osize = oip->i_size;
  224         ioflag = ap->a_flags;
  225         aflag = ioflag & IO_SYNC ? B_SYNC : 0;
  226 
  227         /*
  228          * Lengthen the size of the file. We must ensure that the
  229          * last byte of the file is allocated. Since the smallest
  230          * value of osize is 0, length will be at least 1.
  231          */
  232 
  233         if (osize < length) {
  234                 if (lblkno(fs, osize) < NDADDR &&
  235                     lblkno(fs, osize) != lblkno(fs, length) &&
  236                     blkroundup(fs, osize) != osize) {
  237                         error = ufs_balloc_range(ovp, osize,
  238                             blkroundup(fs, osize) - osize, ap->a_cred, aflag);
  239                         if (error) {
  240                                 return error;
  241                         }
  242                         if (ioflag & IO_SYNC) {
  243                                 ovp->v_size = blkroundup(fs, osize);
  244                                 simple_lock(&ovp->v_interlock);
  245                                 VOP_PUTPAGES(ovp,
  246                                     trunc_page(osize & ~(fs->fs_bsize - 1)),
  247                                     round_page(ovp->v_size),
  248                                     PGO_CLEANIT | PGO_SYNCIO);
  249                         }
  250                 }
  251                 error = ufs_balloc_range(ovp, length - 1, 1, ap->a_cred,
  252                     aflag);
  253                 if (error) {
  254                         (void) VOP_TRUNCATE(ovp, osize, ioflag & IO_SYNC,
  255                             ap->a_cred, ap->a_p);
  256                         return error;
  257                 }
  258                 uvm_vnp_setsize(ovp, length);
  259                 oip->i_flag |= IN_CHANGE | IN_UPDATE;
  260                 KASSERT(ovp->v_size == oip->i_size);
  261                 return (VOP_UPDATE(ovp, NULL, NULL, 1));
  262         }
  263 
  264         /*
  265          * When truncating a regular file down to a non-block-aligned size,
  266          * we must zero the part of last block which is past the new EOF.
  267          * We must synchronously flush the zeroed pages to disk
  268          * since the new pages will be invalidated as soon as we
  269          * inform the VM system of the new, smaller size.
  270          * We must do this before acquiring the GLOCK, since fetching
  271          * the pages will acquire the GLOCK internally.
  272          * So there is a window where another thread could see a whole
  273          * zeroed page past EOF, but that's life.
  274          */
  275 
  276         offset = blkoff(fs, length);
  277         if (ovp->v_type == VREG && length < osize && offset != 0) {
  278                 voff_t eoz;
  279 
  280                 error = ufs_balloc_range(ovp, length - 1, 1, ap->a_cred,
  281                     aflag);
  282                 if (error) {
  283                         return error;
  284                 }
  285                 size = blksize(fs, oip, lblkno(fs, length));
  286                 eoz = MIN(lblktosize(fs, lblkno(fs, length)) + size, osize);
  287                 uvm_vnp_zerorange(ovp, length, eoz - length);
  288                 simple_lock(&ovp->v_interlock);
  289                 error = VOP_PUTPAGES(ovp, trunc_page(length), round_page(eoz),
  290                     PGO_CLEANIT | PGO_DEACTIVATE | PGO_SYNCIO);
  291                 if (error) {
  292                         return error;
  293                 }
  294         }
  295 
  296         lockmgr(&gp->g_glock, LK_EXCLUSIVE, NULL);
  297 
  298         if (DOINGSOFTDEP(ovp)) {
  299                 if (length > 0) {
  300                         /*
  301                          * If a file is only partially truncated, then
  302                          * we have to clean up the data structures
  303                          * describing the allocation past the truncation
  304                          * point. Finding and deallocating those structures
  305                          * is a lot of work. Since partial truncation occurs
  306                          * rarely, we solve the problem by syncing the file
  307                          * so that it will have no data structures left.
  308                          */
  309                         if ((error = VOP_FSYNC(ovp, ap->a_cred, FSYNC_WAIT,
  310                             0, 0, ap->a_p)) != 0) {
  311                                 lockmgr(&gp->g_glock, LK_RELEASE, NULL);
  312                                 return (error);
  313                         }
  314                         if (oip->i_flag & IN_SPACECOUNTED)
  315                                 fs->fs_pendingblocks -= DIP(oip, blocks);
  316                 } else {
  317                         uvm_vnp_setsize(ovp, length);
  318 #ifdef QUOTA
  319                         (void) chkdq(oip, -DIP(oip, blocks), NOCRED, 0);
  320 #endif
  321                         softdep_setup_freeblocks(oip, length, 0);
  322                         (void) vinvalbuf(ovp, 0, ap->a_cred, ap->a_p, 0, 0);
  323                         lockmgr(&gp->g_glock, LK_RELEASE, NULL);
  324                         oip->i_flag |= IN_CHANGE | IN_UPDATE;
  325                         return (VOP_UPDATE(ovp, NULL, NULL, 0));
  326                 }
  327         }
  328         oip->i_size = length;
  329         DIP_ASSIGN(oip, size, length);
  330         uvm_vnp_setsize(ovp, length);
  331         /*
  332          * Calculate index into inode's block list of
  333          * last direct and indirect blocks (if any)
  334          * which we want to keep.  Lastblock is -1 when
  335          * the file is truncated to 0.
  336          */
  337         lastblock = lblkno(fs, length + fs->fs_bsize - 1) - 1;
  338         lastiblock[SINGLE] = lastblock - NDADDR;
  339         lastiblock[DOUBLE] = lastiblock[SINGLE] - NINDIR(fs);
  340         lastiblock[TRIPLE] = lastiblock[DOUBLE] - NINDIR(fs) * NINDIR(fs);
  341         nblocks = btodb(fs->fs_bsize);
  342         /*
  343          * Update file and block pointers on disk before we start freeing
  344          * blocks.  If we crash before free'ing blocks below, the blocks
  345          * will be returned to the free list.  lastiblock values are also
  346          * normalized to -1 for calls to ffs_indirtrunc below.
  347          */
  348         for (level = TRIPLE; level >= SINGLE; level--) {
  349                 oldblks[NDADDR + level] = DIP(oip, ib[level]);
  350                 if (lastiblock[level] < 0) {
  351                         DIP_ASSIGN(oip, ib[level], 0);
  352                         lastiblock[level] = -1;
  353                 }
  354         }
  355         for (i = 0; i < NDADDR; i++) {
  356                 oldblks[i] = DIP(oip, db[i]);
  357                 if (i > lastblock)
  358                         DIP_ASSIGN(oip, db[i], 0);
  359         }
  360         oip->i_flag |= IN_CHANGE | IN_UPDATE;
  361         error = VOP_UPDATE(ovp, NULL, NULL, UPDATE_WAIT);
  362         if (error && !allerror)
  363                 allerror = error;
  364 
  365         /*
  366          * Having written the new inode to disk, save its new configuration
  367          * and put back the old block pointers long enough to process them.
  368          * Note that we save the new block configuration so we can check it
  369          * when we are done.
  370          */
  371         for (i = 0; i < NDADDR; i++) {
  372                 newblks[i] = DIP(oip, db[i]);
  373                 DIP_ASSIGN(oip, db[i], oldblks[i]);
  374         }
  375         for (i = 0; i < NIADDR; i++) {
  376                 newblks[NDADDR + i] = DIP(oip, ib[i]);
  377                 DIP_ASSIGN(oip, ib[i], oldblks[NDADDR + i]);
  378         }
  379 
  380         oip->i_size = osize;
  381         DIP_ASSIGN(oip, size, osize);
  382         error = vtruncbuf(ovp, lastblock + 1, 0, 0);
  383         if (error && !allerror)
  384                 allerror = error;
  385 
  386         /*
  387          * Indirect blocks first.
  388          */
  389         indir_lbn[SINGLE] = -NDADDR;
  390         indir_lbn[DOUBLE] = indir_lbn[SINGLE] - NINDIR(fs) - 1;
  391         indir_lbn[TRIPLE] = indir_lbn[DOUBLE] - NINDIR(fs) * NINDIR(fs) - 1;
  392         for (level = TRIPLE; level >= SINGLE; level--) {
  393                 if (oip->i_ump->um_fstype == UFS1)
  394                         bn = ufs_rw32(oip->i_ffs1_ib[level],UFS_FSNEEDSWAP(fs));
  395                 else
  396                         bn = ufs_rw64(oip->i_ffs2_ib[level],UFS_FSNEEDSWAP(fs));
  397                 if (bn != 0) {
  398                         error = ffs_indirtrunc(oip, indir_lbn[level],
  399                             fsbtodb(fs, bn), lastiblock[level], level, &count);
  400                         if (error)
  401                                 allerror = error;
  402                         blocksreleased += count;
  403                         if (lastiblock[level] < 0) {
  404                                 DIP_ASSIGN(oip, ib[level], 0);
  405                                 ffs_blkfree(oip, bn, fs->fs_bsize);
  406                                 blocksreleased += nblocks;
  407                         }
  408                 }
  409                 if (lastiblock[level] >= 0)
  410                         goto done;
  411         }
  412 
  413         /*
  414          * All whole direct blocks or frags.
  415          */
  416         for (i = NDADDR - 1; i > lastblock; i--) {
  417                 long bsize;
  418 
  419                 if (oip->i_ump->um_fstype == UFS1)
  420                         bn = ufs_rw32(oip->i_ffs1_db[i], UFS_FSNEEDSWAP(fs));
  421                 else
  422                         bn = ufs_rw64(oip->i_ffs2_db[i], UFS_FSNEEDSWAP(fs));
  423                 if (bn == 0)
  424                         continue;
  425                 DIP_ASSIGN(oip, db[i], 0);
  426                 bsize = blksize(fs, oip, i);
  427                 ffs_blkfree(oip, bn, bsize);
  428                 blocksreleased += btodb(bsize);
  429         }
  430         if (lastblock < 0)
  431                 goto done;
  432 
  433         /*
  434          * Finally, look for a change in size of the
  435          * last direct block; release any frags.
  436          */
  437         if (oip->i_ump->um_fstype == UFS1)
  438                 bn = ufs_rw32(oip->i_ffs1_db[lastblock], UFS_FSNEEDSWAP(fs));
  439         else
  440                 bn = ufs_rw64(oip->i_ffs2_db[lastblock], UFS_FSNEEDSWAP(fs));
  441         if (bn != 0) {
  442                 long oldspace, newspace;
  443 
  444                 /*
  445                  * Calculate amount of space we're giving
  446                  * back as old block size minus new block size.
  447                  */
  448                 oldspace = blksize(fs, oip, lastblock);
  449                 oip->i_size = length;
  450                 DIP_ASSIGN(oip, size, length);
  451                 newspace = blksize(fs, oip, lastblock);
  452                 if (newspace == 0)
  453                         panic("itrunc: newspace");
  454                 if (oldspace - newspace > 0) {
  455                         /*
  456                          * Block number of space to be free'd is
  457                          * the old block # plus the number of frags
  458                          * required for the storage we're keeping.
  459                          */
  460                         bn += numfrags(fs, newspace);
  461                         ffs_blkfree(oip, bn, oldspace - newspace);
  462                         blocksreleased += btodb(oldspace - newspace);
  463                 }
  464         }
  465 
  466 done:
  467 #ifdef DIAGNOSTIC
  468         for (level = SINGLE; level <= TRIPLE; level++)
  469                 if (newblks[NDADDR + level] != DIP(oip, ib[level]))
  470                         panic("itrunc1");
  471         for (i = 0; i < NDADDR; i++)
  472                 if (newblks[i] != DIP(oip, db[i]))
  473                         panic("itrunc2");
  474         if (length == 0 &&
  475             (!LIST_EMPTY(&ovp->v_cleanblkhd) || !LIST_EMPTY(&ovp->v_dirtyblkhd)))
  476                 panic("itrunc3");
  477 #endif /* DIAGNOSTIC */
  478         /*
  479          * Put back the real size.
  480          */
  481         oip->i_size = length;
  482         DIP_ASSIGN(oip, size, length);
  483         DIP_ADD(oip, blocks, -blocksreleased);
  484         lockmgr(&gp->g_glock, LK_RELEASE, NULL);
  485         oip->i_flag |= IN_CHANGE;
  486 #ifdef QUOTA
  487         (void) chkdq(oip, -blocksreleased, NOCRED, 0);
  488 #endif
  489         KASSERT(ovp->v_type != VREG || ovp->v_size == oip->i_size);
  490         return (allerror);
  491 }
  492 
  493 /*
  494  * Release blocks associated with the inode ip and stored in the indirect
  495  * block bn.  Blocks are free'd in LIFO order up to (but not including)
  496  * lastbn.  If level is greater than SINGLE, the block is an indirect block
  497  * and recursive calls to indirtrunc must be used to cleanse other indirect
  498  * blocks.
  499  *
  500  * NB: triple indirect blocks are untested.
  501  */
  502 static int
  503 ffs_indirtrunc(ip, lbn, dbn, lastbn, level, countp)
  504         struct inode *ip;
  505         daddr_t lbn, lastbn;
  506         daddr_t dbn;
  507         int level;
  508         int64_t *countp;
  509 {
  510         int i;
  511         struct buf *bp;
  512         struct fs *fs = ip->i_fs;
  513         int32_t *bap1 = NULL;
  514         int64_t *bap2 = NULL;
  515         struct vnode *vp;
  516         daddr_t nb, nlbn, last;
  517         char *copy = NULL;
  518         int64_t blkcount, factor, blocksreleased = 0;
  519         int nblocks;
  520         int error = 0, allerror = 0;
  521 #ifdef FFS_EI
  522         const int needswap = UFS_FSNEEDSWAP(fs);
  523 #endif
  524 #define RBAP(ip, i) (((ip)->i_ump->um_fstype == UFS1) ? \
  525             ufs_rw32(bap1[i], needswap) : ufs_rw64(bap2[i], needswap))
  526 #define BAP_ASSIGN(ip, i, value)                                        \
  527         do {                                                            \
  528                 if ((ip)->i_ump->um_fstype == UFS1)                     \
  529                         bap1[i] = (value);                              \
  530                 else                                                    \
  531                         bap2[i] = (value);                              \
  532         } while(0)
  533 
  534         /*
  535          * Calculate index in current block of last
  536          * block to be kept.  -1 indicates the entire
  537          * block so we need not calculate the index.
  538          */
  539         factor = 1;
  540         for (i = SINGLE; i < level; i++)
  541                 factor *= NINDIR(fs);
  542         last = lastbn;
  543         if (lastbn > 0)
  544                 last /= factor;
  545         nblocks = btodb(fs->fs_bsize);
  546         /*
  547          * Get buffer of block pointers, zero those entries corresponding
  548          * to blocks to be free'd, and update on disk copy first.  Since
  549          * double(triple) indirect before single(double) indirect, calls
  550          * to bmap on these blocks will fail.  However, we already have
  551          * the on disk address, so we have to set the b_blkno field
  552          * explicitly instead of letting bread do everything for us.
  553          */
  554         vp = ITOV(ip);
  555         bp = getblk(vp, lbn, (int)fs->fs_bsize, 0, 0);
  556         if (bp->b_flags & (B_DONE | B_DELWRI)) {
  557                 /* Braces must be here in case trace evaluates to nothing. */
  558                 trace(TR_BREADHIT, pack(vp, fs->fs_bsize), lbn);
  559         } else {
  560                 trace(TR_BREADMISS, pack(vp, fs->fs_bsize), lbn);
  561                 curproc->p_stats->p_ru.ru_inblock++;    /* pay for read */
  562                 bp->b_flags |= B_READ;
  563                 if (bp->b_bcount > bp->b_bufsize)
  564                         panic("ffs_indirtrunc: bad buffer size");
  565                 bp->b_blkno = dbn;
  566                 BIO_SETPRIO(bp, BPRIO_TIMECRITICAL);
  567                 VOP_STRATEGY(vp, bp);
  568                 error = biowait(bp);
  569         }
  570         if (error) {
  571                 brelse(bp);
  572                 *countp = 0;
  573                 return (error);
  574         }
  575 
  576         if (ip->i_ump->um_fstype == UFS1)
  577                 bap1 = (int32_t *)bp->b_data;
  578         else
  579                 bap2 = (int64_t *)bp->b_data;
  580         if (lastbn >= 0) {
  581                 copy = malloc(fs->fs_bsize, M_TEMP, M_WAITOK);
  582                 memcpy((caddr_t)copy, bp->b_data, (u_int)fs->fs_bsize);
  583                 for (i = last + 1; i < NINDIR(fs); i++)
  584                         BAP_ASSIGN(ip, i, 0);
  585                 error = bwrite(bp);
  586                 if (error)
  587                         allerror = error;
  588                 if (ip->i_ump->um_fstype == UFS1)
  589                         bap1 = (int32_t *)copy;
  590                 else
  591                         bap2 = (int64_t *)copy;
  592         }
  593 
  594         /*
  595          * Recursively free totally unused blocks.
  596          */
  597         for (i = NINDIR(fs) - 1, nlbn = lbn + 1 - i * factor; i > last;
  598             i--, nlbn += factor) {
  599                 nb = RBAP(ip, i);
  600                 if (nb == 0)
  601                         continue;
  602                 if (level > SINGLE) {
  603                         error = ffs_indirtrunc(ip, nlbn, fsbtodb(fs, nb),
  604                                                (daddr_t)-1, level - 1,
  605                                                &blkcount);
  606                         if (error)
  607                                 allerror = error;
  608                         blocksreleased += blkcount;
  609                 }
  610                 ffs_blkfree(ip, nb, fs->fs_bsize);
  611                 blocksreleased += nblocks;
  612         }
  613 
  614         /*
  615          * Recursively free last partial block.
  616          */
  617         if (level > SINGLE && lastbn >= 0) {
  618                 last = lastbn % factor;
  619                 nb = RBAP(ip, i);
  620                 if (nb != 0) {
  621                         error = ffs_indirtrunc(ip, nlbn, fsbtodb(fs, nb),
  622                                                last, level - 1, &blkcount);
  623                         if (error)
  624                                 allerror = error;
  625                         blocksreleased += blkcount;
  626                 }
  627         }
  628 
  629         if (copy != NULL) {
  630                 FREE(copy, M_TEMP);
  631         } else {
  632                 bp->b_flags |= B_INVAL;
  633                 brelse(bp);
  634         }
  635 
  636         *countp = blocksreleased;
  637         return (allerror);
  638 }

Cache object: b283d962d23557f3b67a91905866b668


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