add SCCS header
[unix-history] / usr / src / sys / ufs / lfs / lfs_balloc.c
index 56b32a0..bbcdc04 100644 (file)
 /*
 /*
- * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
+ * Copyright (c) 1989, 1991 Regents of the University of California.
  * All rights reserved.
  *
  * All rights reserved.
  *
- * Redistribution and use in source and binary forms are permitted
- * provided that the above copyright notice and this paragraph are
- * duplicated in all such forms and that any documentation,
- * advertising materials, and other materials related to such
- * distribution and use acknowledge that the software was developed
- * by the University of California, Berkeley.  The name of the
- * University may not be used to endorse or promote products derived
- * from this software without specific prior written permission.
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ * %sccs.include.redist.c%
  *
  *
- *     @(#)lfs_balloc.c        7.4 (Berkeley) %G%
+ *     @(#)lfs_balloc.c        7.20 (Berkeley) %G%
  */
 
  */
 
-#include "param.h"
-#include "systm.h"
-#include "user.h"
-#include "buf.h"
-#include "proc.h"
-#include "file.h"
-#include "vnode.h"
-#include "../ufs/inode.h"
-#include "../ufs/fs.h"
+#include <sys/param.h>
+#include <sys/buf.h>
+#include <sys/proc.h>
+#include <sys/vnode.h>
+#include <sys/mount.h>
+#include <sys/resourcevar.h>
+#include <sys/specdev.h>
+#include <sys/trace.h>
+
+#include <ufs/ufs/quota.h>
+#include <ufs/ufs/inode.h>
+#include <ufs/ufs/ufsmount.h>
+
+#include <ufs/lfs/lfs.h>
+#include <ufs/lfs/lfs_extern.h>
 
 /*
 
 /*
- * Bmap defines the structure of file system storage
- * by returning the physical block number on a device given the
- * inode and the logical block number in a file.
- * When convenient, it also leaves the physical
- * block number of the next block of the file in rablock
- * for use in read-ahead.
+ * Bmap converts a the logical block number of a file to its physical block
+ * number on the disk. The conversion is done by using the logical block
+ * number to index into the array of block pointers described by the dinode.
  */
  */
-bmap(ip, bn, bnp, rablockp, rasizep)
-       register struct inode *ip;
+int
+lfs_bmap(vp, bn, vpp, bnp)
+       struct vnode *vp;
        register daddr_t bn;
        register daddr_t bn;
-       daddr_t *bnp;
-       daddr_t *rablockp;
-       int *rasizep;
+       struct vnode **vpp;
+       daddr_t *bnp;
 {
 {
-       register struct fs *fs;
+       register struct inode *ip;
+       register struct lfs *fs;
        register daddr_t nb;
        register daddr_t nb;
+       struct vnode *devvp;
        struct buf *bp;
        struct buf *bp;
-       daddr_t *bap;
-       int i, j, sh;
+       daddr_t *bap, daddr;
+       daddr_t lbn_ind;
+       int j, off, sh;
        int error;
 
        int error;
 
-       if (bn < 0)
-               return (EFBIG);
-       fs = ip->i_fs;
-
-       /*
-        * The first NDADDR blocks are direct blocks
-        */
-       if (bn < NDADDR) {
-               nb = ip->i_db[bn];
-               if (nb == 0) {
-                       *bnp = (daddr_t)-1;
-                       return (0);
-               }
-               if (rablockp && rasizep) {
-                       if (bn < NDADDR - 1) {
-                               *rablockp = fsbtodb(fs, ip->i_db[bn + 1]);
-                               *rasizep = blksize(fs, ip, bn + 1);
-                       } else {
-                               *rablockp = 0;
-                               *rasizep = 0;
-                       }
-               }
-               *bnp = fsbtodb(fs, nb);
-               return (0);
-       }
-
-       /*
-        * Determine how many levels of indirection.
-        */
-       sh = 1;
-       bn -= NDADDR;
-       for (j = NIADDR; j > 0; j--) {
-               sh *= NINDIR(fs);
-               if (bn < sh)
-                       break;
-               bn -= sh;
-       }
-       if (j == 0)
-               return (EFBIG);
-
        /*
        /*
-        * fetch the first indirect block
+        * Check for underlying vnode requests and ensure that logical
+        * to physical mapping is requested.
         */
         */
-       nb = ip->i_ib[NIADDR - j];
-       if (nb == 0) {
-               *bnp = (daddr_t)-1;
+       ip = VTOI(vp);
+       if (vpp != NULL)
+               *vpp = ip->i_devvp;
+       if (bnp == NULL)
                return (0);
                return (0);
-       }
-
-       /*
-        * fetch through the indirect blocks
-        */
-       for (; j <= NIADDR; j++) {
-               if (error = bread(ip->i_devvp, fsbtodb(fs, nb),
-                   (int)fs->fs_bsize, &bp)) {
-                       brelse(bp);
-                       return (error);
-               }
-               bap = bp->b_un.b_daddr;
-               sh /= NINDIR(fs);
-               i = (bn / sh) % NINDIR(fs);
-               nb = bap[i];
-               if (nb == 0) {
-                       *bnp = (daddr_t)-1;
-                       brelse(bp);
-                       return (0);
-               }
-               if (j < NIADDR)
-                       brelse(bp);
-       }
+printf("lfs_bmap: block number %d, inode %d\n", bn, ip->i_number);
+       fs = ip->i_lfs;
 
        /*
 
        /*
-        * calculate read-ahead.
+        * We access all blocks in the cache, even indirect blocks by means
+        * of a logical address. Indirect blocks (single, double, triple) all
+        * have negative block numbers. The first NDADDR blocks are direct
+        * blocks, the first NIADDR negative blocks are the indirect block
+        * pointers.  The single, double and triple indirect blocks in the
+        * inode * are addressed: -1, -2 and -3 respectively.  
+        *
+        * XXX
+        * We don't handle triple indirect at all.
+        *
+        * XXX
+        * This panic shouldn't be here???
         */
         */
-       if (rablockp && rasizep) {
-               if (i < NINDIR(fs) - 1) {
-                       *rablockp = fsbtodb(fs, bap[i + 1]);
-                       *rasizep = fs->fs_bsize;
-               } else {
-                       *rablockp = 0;
-                       *rasizep = 0;
-               }
-       }
-       *bnp = fsbtodb(fs, nb);
-       brelse(bp);
-       return (0);
-}
-
-/*
- * Balloc defines the structure of file system storage
- * by returning the physical block number on a device given the
- * inode and the logical block number in a file.
- * When unallocated entries are found, new physical blocks
- * are allocated.
- */
-balloc(ip, bn, size, bnp, flags)
-       register struct inode *ip;
-       register daddr_t bn;
-       int size;
-       daddr_t *bnp;
-       int flags;
-{
-       register struct fs *fs;
-       register daddr_t nb;
-       struct buf *bp, *nbp;
-       int osize, nsize, i, j, sh, error;
-       daddr_t lbn, *bap, pref, blkpref();
-
        if (bn < 0)
        if (bn < 0)
-               return (EFBIG);
-       fs = ip->i_fs;
+               panic("lfs_bmap: negative indirect block number %d", bn);
 
 
-       /*
-        * If the next write will extend the file into a new block,
-        * and the file is currently composed of a fragment
-        * this fragment has to be extended to be a full block.
-        */
-       nb = lblkno(fs, ip->i_size);
-       if (nb < NDADDR && nb < bn) {
-               osize = blksize(fs, ip, nb);
-               if (osize < fs->fs_bsize && osize > 0) {
-                       error = realloccg(ip, ip->i_db[nb],
-                               blkpref(ip, nb, (int)nb, &ip->i_db[0]),
-                               osize, (int)fs->fs_bsize, &bp);
-                       if (error) {
-                               *bnp = (daddr_t)-1;
-                               return (error);
-                       }
-                       ip->i_size = (nb + 1) * fs->fs_bsize;
-                       ip->i_db[nb] = dbtofsb(fs, bp->b_blkno);
-                       ip->i_flag |= IUPD|ICHG;
-                       bdwrite(bp);
-               }
-       }
-       /*
-        * The first NDADDR blocks are direct blocks
-        */
+       /* The first NDADDR blocks are direct blocks. */
        if (bn < NDADDR) {
                nb = ip->i_db[bn];
        if (bn < NDADDR) {
                nb = ip->i_db[bn];
-               if (nb == 0 || ip->i_size < (bn + 1) * fs->fs_bsize) {
-                       if (nb != 0) {
-                               /* consider need to reallocate a frag */
-                               osize = fragroundup(fs, blkoff(fs, ip->i_size));
-                               nsize = fragroundup(fs, size);
-                               if (nsize <= osize)
-                                       goto gotit;
-                               error = realloccg(ip, nb,
-                                       blkpref(ip, bn, (int)bn, &ip->i_db[0]),
-                                       osize, nsize, &bp);
-                       } else {
-                               if (ip->i_size < (bn + 1) * fs->fs_bsize)
-                                       nsize = fragroundup(fs, size);
-                               else
-                                       nsize = fs->fs_bsize;
-                               error = alloc(ip,
-                                       blkpref(ip, bn, (int)bn, &ip->i_db[0]),
-                                       nsize, &bp, flags);
-                       }
-                       if (error) {
-                               *bnp = (daddr_t)-1;
-                               return (error);
-                       }
-                       nb = dbtofsb(fs, bp->b_blkno);
-                       if ((ip->i_mode & IFMT) == IFDIR)
-                               /*
-                                * Write directory blocks synchronously
-                                * so they never appear with garbage in
-                                * them on the disk.
-                                * 
-                                * NB: Should free space and return error
-                                * if bwrite returns an error.
-                                */
-                               error = bwrite(bp);
-                       else
-                               bdwrite(bp);
-                       ip->i_db[bn] = nb;
-                       ip->i_flag |= IUPD|ICHG;
+               if (nb == 0) {
+                       *bnp = UNASSIGNED;
+                       return (0);
                }
                }
-gotit:
-               *bnp = fsbtodb(fs, nb);
+               *bnp = nb;
                return (0);
        }
 
                return (0);
        }
 
-       /*
-        * Determine how many levels of indirection.
-        */
-       pref = 0;
+       /* Determine the number of levels of indirection. */
        sh = 1;
        sh = 1;
-       lbn = bn;
        bn -= NDADDR;
        bn -= NDADDR;
+       lbn_ind = 0;
        for (j = NIADDR; j > 0; j--) {
        for (j = NIADDR; j > 0; j--) {
+               lbn_ind--;
                sh *= NINDIR(fs);
                if (bn < sh)
                        break;
                sh *= NINDIR(fs);
                if (bn < sh)
                        break;
@@ -248,80 +99,39 @@ gotit:
        if (j == 0)
                return (EFBIG);
 
        if (j == 0)
                return (EFBIG);
 
-       /*
-        * fetch the first indirect block
-        */
-       nb = ip->i_ib[NIADDR - j];
-       if (nb == 0) {
-               pref = blkpref(ip, lbn, 0, (daddr_t *)0);
-               error = alloc(ip, pref, (int)fs->fs_bsize, &bp, B_CLRBUF);
-               if (error) {
-                       *bnp = (daddr_t)-1;
-                       return (error);
+       /* Fetch through the indirect blocks. */
+       vp = ITOV(ip);
+       devvp = VFSTOUFS(vp->v_mount)->um_devvp;
+       for (off = NIADDR - j, bap = ip->i_ib; j <= NIADDR; j++) {
+               if((daddr = bap[off]) == 0) {
+                       daddr = UNASSIGNED;
+                       break;
                }
                }
-               nb = dbtofsb(fs, bp->b_blkno);
-               /*
-                * Write synchronously so that indirect blocks
-                * never point at garbage.
-                * 
-                * NB: Should free space and return error
-                * if bwrite returns an error.
-                */
-               error = bwrite(bp);
-               ip->i_ib[NIADDR - j] = nb;
-               ip->i_flag |= IUPD|ICHG;
-       }
-
-       /*
-        * fetch through the indirect blocks
-        */
-       for (; j <= NIADDR; j++) {
-#ifdef SECSIZE
-               bp = bread(ip->i_dev, fsbtodb(fs, nb), (int)fs->fs_bsize,
-                   fs->fs_dbsize);
-#else SECSIZE
-               if (error = bread(ip->i_devvp, fsbtodb(fs, nb),
-                   (int)fs->fs_bsize, &bp)) {
+               if (bp)
                        brelse(bp);
                        brelse(bp);
-                       return (error);
-               }
-               bap = bp->b_un.b_daddr;
-               sh /= NINDIR(fs);
-               i = (bn / sh) % NINDIR(fs);
-               nb = bap[i];
-               if (nb == 0) {
-                       if (pref == 0)
-                               if (j < NIADDR)
-                                       pref = blkpref(ip, lbn, 0,
-                                               (daddr_t *)0);
-                               else
-                                       pref = blkpref(ip, lbn, i, &bap[0]);
-                       error = alloc(ip, pref, (int)fs->fs_bsize, &nbp,
-                               (j < NIADDR) ? B_CLRBUF : flags);
-                       if (error) {
+               bp = getblk(vp, lbn_ind, fs->lfs_bsize);
+               if (bp->b_flags & (B_DONE | B_DELWRI)) {
+                       trace(TR_BREADHIT, pack(vp, size), lbn_ind);
+               } else {
+                       trace(TR_BREADMISS, pack(vp, size), lbn_ind);
+                       bp->b_blkno = daddr;
+                       bp->b_flags |= B_READ;
+                       bp->b_dev = devvp->v_rdev;
+                       (devvp->v_op->vop_strategy)(bp);
+                       curproc->p_stats->p_ru.ru_inblock++;    /* XXX */
+                       if (error = biowait(bp)) {
                                brelse(bp);
                                brelse(bp);
-                               *bnp = (daddr_t)-1;
                                return (error);
                        }
                                return (error);
                        }
-                       nb = dbtofsb(fs, nbp->b_blkno);
-                       if (j < NIADDR || (ip->i_mode & IFMT) == IFDIR)
-                               /*
-                                * Write synchronously so indirect blocks
-                                * never point at garbage and blocks
-                                * in directories never contain garbage.
-                                * 
-                                * NB: Should free space and return error
-                                * if bwrite returns an error.
-                                */
-                               error = bwrite(nbp);
-                       else
-                               bdwrite(nbp);
-                       bap[i] = nb;
-                       bdwrite(bp);
-               } else
-                       brelse(bp);
+               }
+               bap = bp->b_un.b_daddr;
+               sh /= NINDIR(fs);
+               off = (bn / sh) % NINDIR(fs);
+               lbn_ind  = -(NIADDR + 1 + off);
        }
        }
+       if (bp)
+               brelse(bp);
 
 
-       *bnp = fsbtodb(fs, nb);
+       *bnp = daddr;
        return (0);
 }
        return (0);
 }