/* * Copyright (c) 1982, 1986, 1989 Regents of the University of California. * 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. * * @(#)ffs_subr.c 7.8 (Berkeley) 05/09/89 */ #ifdef KERNEL #include "param.h" #include "systm.h" #include "buf.h" #include "time.h" #include "kernel.h" #include "file.h" #include "mount.h" #include "vnode.h" #include "../ufs/inode.h" #include "../ufs/ufsmount.h" #include "../ufs/fs.h" #include "../ufs/quota.h" #else #include #include #include #include #include #include #include #include #include #include #include #endif #ifdef KERNEL /* * 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. */ syncip(ip) register struct inode *ip; { register struct fs *fs; register struct buf *bp; struct buf *lastbufp; long lbn, lastlbn; int s, error, allerror = 0; daddr_t blkno; fs = ip->i_fs; lastlbn = howmany(ip->i_size, fs->fs_bsize); if (lastlbn < nbuf / 2) { for (lbn = 0; lbn < lastlbn; lbn++) { error = bmap(ip, lbn, &blkno, (daddr_t *)0, (int *)0); if (error) allerror = error; if (error = blkflush(ip->i_devvp, blkno, blksize(fs, ip, lbn))) allerror = error; } } 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 = splbio(); 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); if (error = bwrite(bp)) allerror = error; } } if (error = iupdat(ip, &time, &time, 1)) allerror = error; return (allerror); } #endif KERNEL 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) struct fs *fs; int fragmap; long fraglist[]; int cnt; { int inblk; register int field, subfield; register int siz, pos; inblk = (int)(fragtbl[fs->fs_frag][fragmap]) << 1; fragmap <<= 1; for (siz = 1; siz < fs->fs_frag; siz++) { if ((inblk & (1 << (siz + (fs->fs_frag % NBBY)))) == 0) continue; field = around[siz]; subfield = inside[siz]; for (pos = siz; pos <= fs->fs_frag; pos++) { if ((fragmap & field) == subfield) { fraglist[siz] += cnt; pos += siz; field <<= siz; subfield <<= siz; } field <<= 1; subfield <<= 1; } } } #ifdef KERNEL /* * Check that a specified block number is in range. */ badblock(fs, bn) register struct fs *fs; daddr_t bn; { if ((unsigned)bn >= fs->fs_size) { printf("bad block %d, ", bn); fserr(fs, "bad block"); return (1); } return (0); } #endif /* * block operations * * check if a block is available */ isblock(fs, cp, h) struct fs *fs; unsigned char *cp; daddr_t h; { unsigned char mask; switch ((int)fs->fs_frag) { case 8: return (cp[h] == 0xff); case 4: mask = 0x0f << ((h & 0x1) << 2); return ((cp[h >> 1] & mask) == mask); case 2: mask = 0x03 << ((h & 0x3) << 1); return ((cp[h >> 2] & mask) == mask); case 1: mask = 0x01 << (h & 0x7); return ((cp[h >> 3] & mask) == mask); default: panic("isblock"); return (NULL); } } /* * take a block out of the map */ clrblock(fs, cp, h) struct fs *fs; u_char *cp; daddr_t h; { switch ((int)fs->fs_frag) { case 8: cp[h] = 0; return; case 4: cp[h >> 1] &= ~(0x0f << ((h & 0x1) << 2)); return; case 2: cp[h >> 2] &= ~(0x03 << ((h & 0x3) << 1)); return; case 1: cp[h >> 3] &= ~(0x01 << (h & 0x7)); return; default: panic("clrblock"); } } /* * put a block into the map */ setblock(fs, cp, h) struct fs *fs; unsigned char *cp; daddr_t h; { switch ((int)fs->fs_frag) { case 8: cp[h] = 0xff; return; case 4: cp[h >> 1] |= (0x0f << ((h & 0x1) << 2)); return; case 2: cp[h >> 2] |= (0x03 << ((h & 0x3) << 1)); return; case 1: cp[h >> 3] |= (0x01 << (h & 0x7)); return; default: panic("setblock"); } } #ifdef KERNEL /* * 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. * Filesystems still working on a mount are skipped. * * panic: no fs -- the device is not mounted. * this "cannot happen" */ struct fs * getfs(dev) dev_t dev; { register struct ufsmount *mp; register struct fs *fs; for (mp = &mounttab[0]; mp < &mounttab[NMOUNT]; mp++) { if (mp->um_fs == NULL || mp->um_dev != dev || mp->um_fs == (struct fs *)1) /* XXX */ continue; fs = mp->um_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); } /* * 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 * * rather than * * provided the information need remain valid only * as long as the file system is mounted. */ getfsx(dev) dev_t dev; { register struct ufsmount *mp; if (dev == swapdev) return (MSWAPX); for(mp = &mounttab[0]; mp < &mounttab[NMOUNT]; mp++) if (mp->um_dev == dev) return (mp - &mounttab[0]); return (-1); } #endif #if (!defined(vax) && !defined(tahoe)) || defined(VAX630) || defined(VAX650) /* * C definitions of special instructions. * Normally expanded with inline. */ scanc(size, cp, table, mask) u_int size; register u_char *cp, table[]; register u_char mask; { register u_char *end = &cp[size]; while (cp < end && (table[*cp] & mask) == 0) cp++; return (end - cp); } #endif #if !defined(vax) && !defined(tahoe) skpc(mask, size, cp) register u_char mask; u_int size; register u_char *cp; { register u_char *end = &cp[size]; while (cp < end && *cp == mask) cp++; return (end - cp); } locc(mask, size, cp) register u_char mask; u_int size; register u_char *cp; { register u_char *end = &cp[size]; while (cp < end && *cp != mask) cp++; return (end - cp); } #endif