-/* ffs_subr.c 6.6 85/03/19 */
+/*
+ * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
+ * All rights reserved.
+ *
+ * %sccs.include.redist.c%
+ *
+ * @(#)ffs_subr.c 7.17 (Berkeley) %G%
+ */
-#ifdef KERNEL
-#include "param.h"
-#include "systm.h"
-#include "mount.h"
-#include "fs.h"
-#include "buf.h"
-#include "inode.h"
-#include "dir.h"
-#include "user.h"
-#include "quota.h"
-#include "kernel.h"
-#else
#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/mount.h>
-#include <sys/fs.h>
-#include <sys/buf.h>
-#include <sys/inode.h>
-#include <sys/dir.h>
-#include <sys/user.h>
-#include <sys/quota.h>
-#endif
+#include <ufs/ffs/fs.h>
+#include <ufs/ffs/ffs_extern.h>
#ifdef KERNEL
-int syncprt = 0;
-
-/*
- * Update is the internal name of 'sync'. It goes through the disk
- * queues to initiate sandbagged IO; goes through the inodes to write
- * modified nodes; and it goes through the mount table to initiate
- * the writing of the modified super blocks.
- */
-update()
-{
- register struct inode *ip;
- register struct mount *mp;
- struct fs *fs;
-
- if (syncprt)
- bufstats();
- if (updlock)
- return;
- updlock++;
- /*
- * Write back modified superblocks.
- * Consistency check that the superblock
- * of each file system is still in the buffer cache.
- */
- for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) {
- if (mp->m_bufp == NULL || mp->m_dev == NODEV)
- continue;
- fs = mp->m_bufp->b_un.b_fs;
- if (fs->fs_fmod == 0)
- continue;
- if (fs->fs_ronly != 0) { /* XXX */
- printf("fs = %s\n", fs->fs_fsmnt);
- panic("update: rofs mod");
- }
- fs->fs_fmod = 0;
- fs->fs_time = time.tv_sec;
- sbupdate(mp);
- }
- /*
- * Write back each (modified) inode.
- */
- for (ip = inode; ip < inodeNINODE; ip++) {
- if ((ip->i_flag & ILOCKED) != 0 || ip->i_count == 0 ||
- (ip->i_flag & (IMOD|IACC|IUPD|ICHG)) == 0)
- continue;
- ip->i_flag |= ILOCKED;
- ip->i_count++;
- iupdat(ip, &time, &time, 0);
- iput(ip);
- }
- updlock = 0;
- /*
- * Force stale buffer cache information to be flushed,
- * for all devices.
- */
- bflush(NODEV);
-}
+#include <sys/buf.h>
+#include <sys/vnode.h>
+#include <ufs/ufs/quota.h>
+#include <ufs/ufs/inode.h>
/*
- * Flush all the blocks associated with an inode.
- * There are two strategies based on the size of the file;
- * large files are those with more than (nbuf / 2) blocks.
- * Large files
- * Walk through the buffer pool and push any dirty pages
- * associated with the device on which the file resides.
- * Small files
- * Look up each block in the file to see if it is in the
- * buffer pool writing any that are found to disk.
- * Note that we make a more stringent check of
- * writing out any block in the buffer pool that may
- * overlap the inode. This brings the inode up to
- * date with recent mods to the cooked device.
+ * Return buffer with the contents of block "offset" from the beginning of
+ * directory "ip". If "res" is non-zero, fill it in with a pointer to the
+ * remaining space in the directory.
*/
-syncip(ip)
- register struct inode *ip;
+int
+ffs_blkatoff(vp, offset, res, bpp)
+ struct vnode *vp;
+ off_t offset;
+ char **res;
+ struct buf **bpp;
{
+ struct inode *ip;
register struct fs *fs;
- register struct buf *bp;
- struct buf *lastbufp;
- long lbn, lastlbn, s;
- daddr_t blkno;
+ struct buf *bp;
+ daddr_t lbn;
+ int bsize, error;
+ ip = VTOI(vp);
fs = ip->i_fs;
- lastlbn = howmany(ip->i_size, fs->fs_bsize);
- if (lastlbn < nbuf / 2) {
- for (lbn = 0; lbn < lastlbn; lbn++) {
- blkno = fsbtodb(fs, bmap(ip, lbn, B_READ));
- blkflush(ip->i_dev, blkno, blksize(fs, ip, lbn));
- }
- } else {
- lastbufp = &buf[nbuf];
- for (bp = buf; bp < lastbufp; bp++) {
- if (bp->b_dev != ip->i_dev ||
- (bp->b_flags & B_DELWRI) == 0)
- continue;
- s = spl6();
- if (bp->b_flags & B_BUSY) {
- bp->b_flags |= B_WANTED;
- sleep((caddr_t)bp, PRIBIO+1);
- splx(s);
- bp--;
- continue;
- }
- splx(s);
- notavail(bp);
- bwrite(bp);
- }
+ lbn = lblkno(fs, offset);
+ bsize = blksize(fs, ip, lbn);
+
+ *bpp = NULL;
+ if (error = bread(vp, lbn, bsize, NOCRED, &bp)) {
+ brelse(bp);
+ return (error);
}
- ip->i_flag |= ICHG;
- iupdat(ip, &time, &time, 1);
+ if (res)
+ *res = bp->b_un.b_addr + blkoff(fs, offset);
+ *bpp = bp;
+ return (0);
}
#endif
-extern int around[9];
-extern int inside[9];
-extern u_char *fragtbl[];
-
/*
* Update the frsum fields to reflect addition or deletion
* of some frags.
*/
-fragacct(fs, fragmap, fraglist, cnt)
+void
+ffs_fragacct(fs, fragmap, fraglist, cnt)
struct fs *fs;
int fragmap;
long fraglist[];
}
}
-#ifdef KERNEL
-/*
- * Check that a specified block number is in range.
- */
-badblock(fs, bn)
- register struct fs *fs;
- daddr_t bn;
+#if defined(KERNEL) && defined(DIAGNOSTIC)
+void
+ffs_checkoverlap(bp, ip)
+ struct buf *bp;
+ struct inode *ip;
{
+ register struct buf *ebp, *ep;
+ register daddr_t start, last;
+ struct vnode *vp;
- if ((unsigned)bn >= fs->fs_size) {
- printf("bad block %d, ", bn);
- fserr(fs, "bad block");
- return (1);
+ ebp = &buf[nbuf];
+ start = bp->b_blkno;
+ last = start + btodb(bp->b_bcount) - 1;
+ for (ep = buf; ep < ebp; ep++) {
+ if (ep == bp || (ep->b_flags & B_INVAL) ||
+ ep->b_vp == NULLVP)
+ continue;
+ if (VOP_BMAP(ep->b_vp, (daddr_t)0, &vp, (daddr_t)0))
+ continue;
+ if (vp != ip->i_devvp)
+ continue;
+ /* look for overlap */
+ if (ep->b_bcount == 0 || ep->b_blkno > last ||
+ ep->b_blkno + btodb(ep->b_bcount) <= start)
+ continue;
+ vprint("Disk overlap", vp);
+ (void)printf("\tstart %d, end %d overlap start %d, end %d\n",
+ start, last, ep->b_blkno,
+ ep->b_blkno + btodb(ep->b_bcount) - 1);
+ panic("Disk buffer overlap");
}
- return (0);
}
-#endif
+#endif /* DIAGNOSTIC */
/*
* block operations
*
* check if a block is available
*/
-isblock(fs, cp, h)
+int
+ffs_isblock(fs, cp, h)
struct fs *fs;
unsigned char *cp;
daddr_t h;
{
unsigned char mask;
- switch (fs->fs_frag) {
+ switch ((int)fs->fs_frag) {
case 8:
return (cp[h] == 0xff);
case 4:
mask = 0x01 << (h & 0x7);
return ((cp[h >> 3] & mask) == mask);
default:
- panic("isblock");
- return (NULL);
+ panic("ffs_isblock");
}
}
/*
* take a block out of the map
*/
-clrblock(fs, cp, h)
+void
+ffs_clrblock(fs, cp, h)
struct fs *fs;
u_char *cp;
daddr_t h;
{
- switch ((fs)->fs_frag) {
+ switch ((int)fs->fs_frag) {
case 8:
cp[h] = 0;
return;
cp[h >> 3] &= ~(0x01 << (h & 0x7));
return;
default:
- panic("clrblock");
+ panic("ffs_clrblock");
}
}
/*
* put a block into the map
*/
-setblock(fs, cp, h)
+void
+ffs_setblock(fs, cp, h)
struct fs *fs;
unsigned char *cp;
daddr_t h;
{
- switch (fs->fs_frag) {
+ switch ((int)fs->fs_frag) {
case 8:
cp[h] = 0xff;
cp[h >> 3] |= (0x01 << (h & 0x7));
return;
default:
- panic("setblock");
+ panic("ffs_setblock");
}
}
-#ifdef KERNEL
+#if (!defined(vax) && !defined(tahoe) && !defined(hp300)) \
+ || defined(VAX630) || defined(VAX650)
/*
- * Getfs maps a device number into a pointer to the incore super block.
- *
- * The algorithm is a linear search through the mount table. A
- * consistency check of the super block magic number is performed.
- *
- * panic: no fs -- the device is not mounted.
- * this "cannot happen"
+ * C definitions of special instructions.
+ * Normally expanded with inline.
*/
-struct fs *
-getfs(dev)
- dev_t dev;
+int
+scanc(size, cp, table, mask)
+ u_int size;
+ register u_char *cp, table[];
+ register u_char mask;
{
- register struct mount *mp;
- register struct fs *fs;
+ register u_char *end = &cp[size];
- for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) {
- if (mp->m_bufp == NULL || mp->m_dev != dev)
- continue;
- fs = mp->m_bufp->b_un.b_fs;
- if (fs->fs_magic != FS_MAGIC) {
- printf("dev = 0x%x, fs = %s\n", dev, fs->fs_fsmnt);
- panic("getfs: bad magic");
- }
- return (fs);
- }
- printf("dev = 0x%x\n", dev);
- panic("getfs: no fs");
- return (NULL);
+ while (cp < end && (table[*cp] & mask) == 0)
+ cp++;
+ return (end - cp);
}
+#endif
-/*
- * Getfsx returns the index in the file system
- * table of the specified device. The swap device
- * is also assigned a pseudo-index. The index may
- * be used as a compressed indication of the location
- * of a block, recording
- * <getfsx(dev),blkno>
- * rather than
- * <dev, blkno>
- * provided the information need remain valid only
- * as long as the file system is mounted.
- */
-getfsx(dev)
- dev_t dev;
+#if !defined(vax) && !defined(tahoe) && !defined(hp300)
+int
+skpc(mask, size, cp)
+ register u_char mask;
+ u_int size;
+ register u_char *cp;
{
- register struct mount *mp;
+ register u_char *end = &cp[size];
- if (dev == swapdev)
- return (MSWAPX);
- for(mp = &mount[0]; mp < &mount[NMOUNT]; mp++)
- if (mp->m_dev == dev)
- return (mp - &mount[0]);
- return (-1);
+ while (cp < end && *cp == mask)
+ cp++;
+ return (end - cp);
}
-/*
- * Print out statistics on the current allocation of the buffer pool.
- * Can be enabled to print out on every ``sync'' by setting "syncprt"
- * above.
- */
-bufstats()
+int
+locc(mask, size, cp)
+ register u_char mask;
+ u_int size;
+ register u_char *cp;
{
- int s, i, j, count;
- register struct buf *bp, *dp;
- int counts[MAXBSIZE/CLBYTES+1];
- static char *bname[BQUEUES] = { "LOCKED", "LRU", "AGE", "EMPTY" };
+ register u_char *end = &cp[size];
- for (bp = bfreelist, i = 0; bp < &bfreelist[BQUEUES]; bp++, i++) {
- count = 0;
- for (j = 0; j <= MAXBSIZE/CLBYTES; j++)
- counts[j] = 0;
- s = spl6();
- for (dp = bp->av_forw; dp != bp; dp = dp->av_forw) {
- counts[dp->b_bufsize/CLBYTES]++;
- count++;
- }
- splx(s);
- printf("%s: total-%d", bname[i], count);
- for (j = 0; j <= MAXBSIZE/CLBYTES; j++)
- if (counts[j] != 0)
- printf(", %d-%d", j * CLBYTES, counts[j]);
- printf("\n");
- }
+ while (cp < end && *cp != mask)
+ cp++;
+ return (end - cp);
}
#endif