File:  [DragonFly] / src / sys / vfs / gnu / ext2fs / ext2_alloc.c
Revision 1.5: download - view: text, annotated - select for diffs
Wed Aug 20 09:56:31 2003 UTC (10 years, 11 months ago) by rob
Branches: MAIN
CVS tags: HEAD
__P()!=wanted, remove old style prototypes from the vfs subtree

    1: /*
    2:  *  modified for Lites 1.1
    3:  *
    4:  *  Aug 1995, Godmar Back (gback@cs.utah.edu)
    5:  *  University of Utah, Department of Computer Science
    6:  */
    7: /*
    8:  * Copyright (c) 1982, 1986, 1989, 1993
    9:  *	The Regents of the University of California.  All rights reserved.
   10:  *
   11:  * Redistribution and use in source and binary forms, with or without
   12:  * modification, are permitted provided that the following conditions
   13:  * are met:
   14:  * 1. Redistributions of source code must retain the above copyright
   15:  *    notice, this list of conditions and the following disclaimer.
   16:  * 2. Redistributions in binary form must reproduce the above copyright
   17:  *    notice, this list of conditions and the following disclaimer in the
   18:  *    documentation and/or other materials provided with the distribution.
   19:  * 3. All advertising materials mentioning features or use of this software
   20:  *    must display the following acknowledgement:
   21:  *	This product includes software developed by the University of
   22:  *	California, Berkeley and its contributors.
   23:  * 4. Neither the name of the University nor the names of its contributors
   24:  *    may be used to endorse or promote products derived from this software
   25:  *    without specific prior written permission.
   26:  *
   27:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   28:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   29:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   30:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   31:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   32:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   33:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   34:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   35:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   36:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   37:  * SUCH DAMAGE.
   38:  *
   39:  *	@(#)ext2_alloc.c	8.8 (Berkeley) 2/21/94
   40:  * $FreeBSD: src/sys/gnu/ext2fs/ext2_alloc.c,v 1.28.2.2 2002/07/01 00:18:51 iedowse Exp $
   41:  * $DragonFly: src/sys/vfs/gnu/ext2fs/ext2_alloc.c,v 1.5 2003/08/20 09:56:31 rob Exp $
   42:  */
   43: 
   44: #include "opt_quota.h"
   45: 
   46: #include <sys/param.h>
   47: #include <sys/systm.h>
   48: #include <sys/conf.h>
   49: #include <sys/vnode.h>
   50: #include <sys/stat.h>
   51: #include <sys/mount.h>
   52: #include <sys/syslog.h>
   53: 
   54: #include <vfs/ufs/quota.h>
   55: #include <vfs/ufs/inode.h>
   56: #include <vfs/ufs/ufsmount.h>
   57: 
   58: #include "ext2_fs.h"
   59: #include "ext2_fs_sb.h"
   60: #include "fs.h"
   61: #include "ext2_extern.h"
   62: 
   63: static void	ext2_fserr (struct ext2_sb_info *, u_int, char *);
   64: 
   65: /*
   66:  * Linux calls this functions at the following locations:
   67:  * (1) the inode is freed
   68:  * (2) a preallocation miss occurs
   69:  * (3) truncate is called
   70:  * (4) release_file is called and f_mode & 2
   71:  *
   72:  * I call it in ext2_inactive, ext2_truncate, ext2_vfree and in (2)
   73:  * the call in vfree might be redundant
   74:  */
   75: void
   76: ext2_discard_prealloc(ip)
   77: 	struct inode * ip;
   78: {
   79: #ifdef EXT2_PREALLOCATE
   80:         if (ip->i_prealloc_count) {
   81:                 int i = ip->i_prealloc_count;
   82:                 ip->i_prealloc_count = 0;
   83:                 ext2_free_blocks (ITOV(ip)->v_mount,
   84:                                   ip->i_prealloc_block,
   85:                                   i);
   86:         }
   87: #endif
   88: }
   89: 
   90: /*
   91:  * Allocate a block in the file system.
   92:  * 
   93:  * this takes the framework from ffs_alloc. To implement the
   94:  * actual allocation, it calls ext2_new_block, the ported version
   95:  * of the same Linux routine.
   96:  *
   97:  * we note that this is always called in connection with ext2_blkpref
   98:  *
   99:  * preallocation is done as Linux does it
  100:  */
  101: int
  102: ext2_alloc(ip, lbn, bpref, size, cred, bnp)
  103: 	struct inode *ip;
  104: 	daddr_t lbn, bpref;
  105: 	int size;
  106: 	struct ucred *cred;
  107: 	daddr_t *bnp;
  108: {
  109: 	struct ext2_sb_info *fs;
  110: 	daddr_t bno;
  111: #if QUOTA
  112: 	int error;
  113: #endif
  114: 	
  115: 	*bnp = 0;
  116: 	fs = ip->i_e2fs;
  117: #if DIAGNOSTIC
  118: 	if ((u_int)size > fs->s_blocksize || blkoff(fs, size) != 0) {
  119: 		printf("dev = %s, bsize = %lu, size = %d, fs = %s\n",
  120: 		    devtoname(ip->i_dev), fs->s_blocksize, size, fs->fs_fsmnt);
  121: 		panic("ext2_alloc: bad size");
  122: 	}
  123: 	if (cred == NOCRED)
  124: 		panic("ext2_alloc: missing credential");
  125: #endif /* DIAGNOSTIC */
  126: 	if (size == fs->s_blocksize && fs->s_es->s_free_blocks_count == 0)
  127: 		goto nospace;
  128: 	if (cred->cr_uid != 0 && 
  129: 		fs->s_es->s_free_blocks_count < fs->s_es->s_r_blocks_count)
  130: 		goto nospace;
  131: #if QUOTA
  132: 	if ((error = chkdq(ip, (long)btodb(size), cred, 0)) != 0)
  133: 		return (error);
  134: #endif
  135: 	if (bpref >= fs->s_es->s_blocks_count)
  136: 		bpref = 0;
  137: 	/* call the Linux code */
  138: #ifdef EXT2_PREALLOCATE
  139: 	/* To have a preallocation hit, we must
  140: 	 * - have at least one block preallocated
  141: 	 * - and our preferred block must have that block number or one below
  142: 	 */
  143:         if (ip->i_prealloc_count &&
  144:             (bpref == ip->i_prealloc_block ||
  145:              bpref + 1 == ip->i_prealloc_block))
  146:         {
  147:                 bno = ip->i_prealloc_block++;
  148:                 ip->i_prealloc_count--;
  149:                 /* ext2_debug ("preallocation hit (%lu/%lu).\n",
  150:                             ++alloc_hits, ++alloc_attempts); */
  151: 
  152: 		/* Linux gets, clears, and releases the buffer at this
  153: 		   point - we don't have to that; we leave it to the caller
  154: 		 */
  155:         } else {
  156:                 ext2_discard_prealloc (ip);
  157:                 /* ext2_debug ("preallocation miss (%lu/%lu).\n",
  158:                             alloc_hits, ++alloc_attempts); */
  159:                 if (S_ISREG(ip->i_mode))
  160:                         bno = ext2_new_block
  161:                                 (ITOV(ip)->v_mount, bpref,
  162:                                  &ip->i_prealloc_count,
  163:                                  &ip->i_prealloc_block);
  164:                 else
  165: 			bno = (daddr_t)ext2_new_block(ITOV(ip)->v_mount, 
  166: 					bpref, 0, 0);
  167:         }
  168: #else
  169: 	bno = (daddr_t)ext2_new_block(ITOV(ip)->v_mount, bpref, 0, 0);
  170: #endif
  171: 
  172: 	if (bno > 0) {
  173: 		/* set next_alloc fields as done in block_getblk */
  174: 		ip->i_next_alloc_block = lbn;
  175: 		ip->i_next_alloc_goal = bno;
  176: 
  177: 		ip->i_blocks += btodb(size);
  178: 		ip->i_flag |= IN_CHANGE | IN_UPDATE;
  179: 		*bnp = bno;
  180: 		return (0);
  181: 	}
  182: #if QUOTA
  183: 	/*
  184: 	 * Restore user's disk quota because allocation failed.
  185: 	 */
  186: 	(void) chkdq(ip, (long)-btodb(size), cred, FORCE);
  187: #endif
  188: nospace:
  189: 	ext2_fserr(fs, cred->cr_uid, "file system full");
  190: 	uprintf("\n%s: write failed, file system is full\n", fs->fs_fsmnt);
  191: 	return (ENOSPC);
  192: }
  193: 
  194: /*
  195:  * Reallocate a sequence of blocks into a contiguous sequence of blocks.
  196:  *
  197:  * The vnode and an array of buffer pointers for a range of sequential
  198:  * logical blocks to be made contiguous is given. The allocator attempts
  199:  * to find a range of sequential blocks starting as close as possible to
  200:  * an fs_rotdelay offset from the end of the allocation for the logical
  201:  * block immediately preceeding the current range. If successful, the
  202:  * physical block numbers in the buffer pointers and in the inode are
  203:  * changed to reflect the new allocation. If unsuccessful, the allocation
  204:  * is left unchanged. The success in doing the reallocation is returned.
  205:  * Note that the error return is not reflected back to the user. Rather
  206:  * the previous block allocation will be used.
  207:  */
  208: 
  209: #ifdef FANCY_REALLOC
  210: #include <sys/sysctl.h>
  211: static int doasyncfree = 1;
  212: #ifdef	OPT_DEBUG
  213: SYSCTL_INT(_debug, 14, doasyncfree, CTLFLAG_RW, &doasyncfree, 0, "");
  214: #endif	/* OPT_DEBUG */
  215: #endif
  216: 
  217: int
  218: ext2_reallocblks(ap)
  219: 	struct vop_reallocblks_args /* {
  220: 		struct vnode *a_vp;
  221: 		struct cluster_save *a_buflist;
  222: 	} */ *ap;
  223: {
  224: #ifndef FANCY_REALLOC
  225: /* printf("ext2_reallocblks not implemented\n"); */
  226: return ENOSPC;
  227: #else
  228: 
  229: 	struct ext2_sb_info *fs;
  230: 	struct inode *ip;
  231: 	struct vnode *vp;
  232: 	struct buf *sbp, *ebp;
  233: 	daddr_t *bap, *sbap, *ebap;
  234: 	struct cluster_save *buflist;
  235: 	daddr_t start_lbn, end_lbn, soff, eoff, newblk, blkno;
  236: 	struct indir start_ap[NIADDR + 1], end_ap[NIADDR + 1], *idp;
  237: 	int i, len, start_lvl, end_lvl, pref, ssize;
  238: 
  239: 	vp = ap->a_vp;
  240: 	ip = VTOI(vp);
  241: 	fs = ip->i_e2fs;
  242: #ifdef UNKLAR
  243: 	if (fs->fs_contigsumsize <= 0)
  244: 		return (ENOSPC);
  245: #endif
  246: 	buflist = ap->a_buflist;
  247: 	len = buflist->bs_nchildren;
  248: 	start_lbn = buflist->bs_children[0]->b_lblkno;
  249: 	end_lbn = start_lbn + len - 1;
  250: #if DIAGNOSTIC
  251: 	for (i = 1; i < len; i++)
  252: 		if (buflist->bs_children[i]->b_lblkno != start_lbn + i)
  253: 			panic("ext2_reallocblks: non-cluster");
  254: #endif
  255: 	/*
  256: 	 * If the latest allocation is in a new cylinder group, assume that
  257: 	 * the filesystem has decided to move and do not force it back to
  258: 	 * the previous cylinder group.
  259: 	 */
  260: 	if (dtog(fs, dbtofsb(fs, buflist->bs_children[0]->b_blkno)) !=
  261: 	    dtog(fs, dbtofsb(fs, buflist->bs_children[len - 1]->b_blkno)))
  262: 		return (ENOSPC);
  263: 	if (ufs_getlbns(vp, start_lbn, start_ap, &start_lvl) ||
  264: 	    ufs_getlbns(vp, end_lbn, end_ap, &end_lvl))
  265: 		return (ENOSPC);
  266: 	/*
  267: 	 * Get the starting offset and block map for the first block.
  268: 	 */
  269: 	if (start_lvl == 0) {
  270: 		sbap = &ip->i_db[0];
  271: 		soff = start_lbn;
  272: 	} else {
  273: 		idp = &start_ap[start_lvl - 1];
  274: 		if (bread(vp, idp->in_lbn, (int)fs->s_blocksize, NOCRED, &sbp)) {
  275: 			brelse(sbp);
  276: 			return (ENOSPC);
  277: 		}
  278: 		sbap = (daddr_t *)sbp->b_data;
  279: 		soff = idp->in_off;
  280: 	}
  281: 	/*
  282: 	 * Find the preferred location for the cluster.
  283: 	 */
  284: 	pref = ext2_blkpref(ip, start_lbn, soff, sbap);
  285: 	/*
  286: 	 * If the block range spans two block maps, get the second map.
  287: 	 */
  288: 	if (end_lvl == 0 || (idp = &end_ap[end_lvl - 1])->in_off + 1 >= len) {
  289: 		ssize = len;
  290: 	} else {
  291: #if DIAGNOSTIC
  292: 		if (start_ap[start_lvl-1].in_lbn == idp->in_lbn)
  293: 			panic("ext2_reallocblk: start == end");
  294: #endif
  295: 		ssize = len - (idp->in_off + 1);
  296: 		if (bread(vp, idp->in_lbn, (int)fs->s_blocksize, NOCRED, &ebp))
  297: 			goto fail;
  298: 		ebap = (daddr_t *)ebp->b_data;
  299: 	}
  300: 	/*
  301: 	 * Search the block map looking for an allocation of the desired size.
  302: 	 */
  303: 	if ((newblk = (daddr_t)ext2_hashalloc(ip, dtog(fs, pref), (long)pref,
  304: 	    len, (u_long (*)())ext2_clusteralloc)) == 0)
  305: 		goto fail;
  306: 	/*
  307: 	 * We have found a new contiguous block.
  308: 	 *
  309: 	 * First we have to replace the old block pointers with the new
  310: 	 * block pointers in the inode and indirect blocks associated
  311: 	 * with the file.
  312: 	 */
  313: 	blkno = newblk;
  314: 	for (bap = &sbap[soff], i = 0; i < len; i++, blkno += fs->s_frags_per_block) {
  315: 		if (i == ssize)
  316: 			bap = ebap;
  317: #if DIAGNOSTIC
  318: 		if (buflist->bs_children[i]->b_blkno != fsbtodb(fs, *bap))
  319: 			panic("ext2_reallocblks: alloc mismatch");
  320: #endif
  321: 		*bap++ = blkno;
  322: 	}
  323: 	/*
  324: 	 * Next we must write out the modified inode and indirect blocks.
  325: 	 * For strict correctness, the writes should be synchronous since
  326: 	 * the old block values may have been written to disk. In practise
  327: 	 * they are almost never written, but if we are concerned about 
  328: 	 * strict correctness, the `doasyncfree' flag should be set to zero.
  329: 	 *
  330: 	 * The test on `doasyncfree' should be changed to test a flag
  331: 	 * that shows whether the associated buffers and inodes have
  332: 	 * been written. The flag should be set when the cluster is
  333: 	 * started and cleared whenever the buffer or inode is flushed.
  334: 	 * We can then check below to see if it is set, and do the
  335: 	 * synchronous write only when it has been cleared.
  336: 	 */
  337: 	if (sbap != &ip->i_db[0]) {
  338: 		if (doasyncfree)
  339: 			bdwrite(sbp);
  340: 		else
  341: 			bwrite(sbp);
  342: 	} else {
  343: 		ip->i_flag |= IN_CHANGE | IN_UPDATE;
  344: 		if (!doasyncfree)
  345: 			UFS_UPDATE(vp, 1);
  346: 	}
  347: 	if (ssize < len)
  348: 		if (doasyncfree)
  349: 			bdwrite(ebp);
  350: 		else
  351: 			bwrite(ebp);
  352: 	/*
  353: 	 * Last, free the old blocks and assign the new blocks to the buffers.
  354: 	 */
  355: 	for (blkno = newblk, i = 0; i < len; i++, blkno += fs->s_frags_per_block) {
  356: 		ext2_blkfree(ip, dbtofsb(fs, buflist->bs_children[i]->b_blkno),
  357: 		    fs->s_blocksize);
  358: 		buflist->bs_children[i]->b_blkno = fsbtodb(fs, blkno);
  359: 	}
  360: 	return (0);
  361: 
  362: fail:
  363: 	if (ssize < len)
  364: 		brelse(ebp);
  365: 	if (sbap != &ip->i_db[0])
  366: 		brelse(sbp);
  367: 	return (ENOSPC);
  368: 
  369: #endif /* FANCY_REALLOC */
  370: }
  371: 
  372: /*
  373:  * Allocate an inode in the file system.
  374:  * 
  375:  * we leave the actual allocation strategy to the (modified)
  376:  * ext2_new_inode(), to make sure we get the policies right
  377:  */
  378: int
  379: ext2_valloc(pvp, mode, cred, vpp)
  380: 	struct vnode *pvp;
  381: 	int mode;
  382: 	struct ucred *cred;
  383: 	struct vnode **vpp;
  384: {
  385: 	struct inode *pip;
  386: 	struct ext2_sb_info *fs;
  387: 	struct inode *ip;
  388: 	ino_t ino;
  389: 	int i, error;
  390: 	
  391: 	*vpp = NULL;
  392: 	pip = VTOI(pvp);
  393: 	fs = pip->i_e2fs;
  394: 	if (fs->s_es->s_free_inodes_count == 0)
  395: 		goto noinodes;
  396: 
  397: 	/* call the Linux routine - it returns the inode number only */
  398: 	ino = ext2_new_inode(pip, mode);
  399: 
  400: 	if (ino == 0)
  401: 		goto noinodes;
  402: 	error = VFS_VGET(pvp->v_mount, ino, vpp);
  403: 	if (error) {
  404: 		UFS_VFREE(pvp, ino, mode);
  405: 		return (error);
  406: 	}
  407: 	ip = VTOI(*vpp);
  408: 
  409: 	/* 
  410: 	  the question is whether using VGET was such good idea at all -
  411: 	  Linux doesn't read the old inode in when it's allocating a
  412: 	  new one. I will set at least i_size & i_blocks the zero. 
  413: 	*/ 
  414: 	ip->i_mode = 0;
  415: 	ip->i_size = 0;
  416: 	ip->i_blocks = 0;
  417: 	ip->i_flags = 0;
  418:         /* now we want to make sure that the block pointers are zeroed out */
  419:         for (i = 0; i < NDADDR; i++)
  420:                 ip->i_db[i] = 0;
  421:         for (i = 0; i < NIADDR; i++)
  422:                 ip->i_ib[i] = 0;
  423: 
  424: 	/*
  425: 	 * Set up a new generation number for this inode.
  426: 	 * XXX check if this makes sense in ext2
  427: 	 */
  428: 	if (ip->i_gen == 0 || ++ip->i_gen == 0)
  429: 		ip->i_gen = random() / 2 + 1;
  430: /*
  431: printf("ext2_valloc: allocated inode %d\n", ino);
  432: */
  433: 	return (0);
  434: noinodes:
  435: 	ext2_fserr(fs, cred->cr_uid, "out of inodes");
  436: 	uprintf("\n%s: create/symlink failed, no inodes free\n", fs->fs_fsmnt);
  437: 	return (ENOSPC);
  438: }
  439: 
  440: /*
  441:  * Select the desired position for the next block in a file.  
  442:  *
  443:  * we try to mimic what Remy does in inode_getblk/block_getblk
  444:  *
  445:  * we note: blocknr == 0 means that we're about to allocate either
  446:  * a direct block or a pointer block at the first level of indirection
  447:  * (In other words, stuff that will go in i_db[] or i_ib[])
  448:  *
  449:  * blocknr != 0 means that we're allocating a block that is none
  450:  * of the above. Then, blocknr tells us the number of the block
  451:  * that will hold the pointer
  452:  */
  453: daddr_t
  454: ext2_blkpref(ip, lbn, indx, bap, blocknr)
  455: 	struct inode *ip;
  456: 	daddr_t lbn;
  457: 	int indx;
  458: 	daddr_t *bap;
  459: 	daddr_t blocknr;
  460: {
  461: 	int	tmp;
  462: 
  463: 	/* if the next block is actually what we thought it is,
  464: 	   then set the goal to what we thought it should be
  465: 	*/
  466: 	if(ip->i_next_alloc_block == lbn)
  467: 		return ip->i_next_alloc_goal;
  468: 
  469: 	/* now check whether we were provided with an array that basically
  470: 	   tells us previous blocks to which we want to stay closeby
  471: 	*/
  472: 	if(bap) 
  473:                 for (tmp = indx - 1; tmp >= 0; tmp--) 
  474: 			if (bap[tmp]) 
  475: 				return bap[tmp];
  476: 
  477: 	/* else let's fall back to the blocknr, or, if there is none,
  478: 	   follow the rule that a block should be allocated near its inode
  479: 	*/
  480: 	return blocknr ? blocknr :
  481: 			(daddr_t)(ip->i_block_group * 
  482: 			EXT2_BLOCKS_PER_GROUP(ip->i_e2fs)) + 
  483: 			ip->i_e2fs->s_es->s_first_data_block;
  484: }
  485: 
  486: /*
  487:  * Free a block or fragment.
  488:  *
  489:  * pass on to the Linux code
  490:  */
  491: void
  492: ext2_blkfree(ip, bno, size)
  493: 	struct inode *ip;
  494: 	daddr_t bno;
  495: 	long size;
  496: {
  497: 	struct ext2_sb_info *fs;
  498: 
  499: 	fs = ip->i_e2fs;
  500: 	/*
  501: 	 *	call Linux code with mount *, block number, count
  502: 	 */
  503: 	ext2_free_blocks(ITOV(ip)->v_mount, bno, size / fs->s_frag_size);
  504: }
  505: 
  506: /*
  507:  * Free an inode.
  508:  *
  509:  * the maintenance of the actual bitmaps is again up to the linux code
  510:  */
  511: int
  512: ext2_vfree(pvp, ino, mode)
  513: 	struct vnode *pvp;
  514: 	ino_t ino;
  515: 	int mode;
  516: {
  517: 	struct ext2_sb_info *fs;
  518: 	struct inode *pip;
  519: 	mode_t save_i_mode;
  520: 
  521: 	pip = VTOI(pvp);
  522: 	fs = pip->i_e2fs;
  523: 	if ((u_int)ino > fs->s_inodes_per_group * fs->s_groups_count)
  524: 		panic("ext2_vfree: range: dev = (%d, %d), ino = %d, fs = %s",
  525: 		    major(pip->i_dev), minor(pip->i_dev), ino, fs->fs_fsmnt);
  526: 
  527: /* ext2_debug("ext2_vfree (%d, %d) called\n", pip->i_number, mode);
  528:  */
  529: 	ext2_discard_prealloc(pip);
  530: 
  531: 	/* we need to make sure that ext2_free_inode can adjust the
  532: 	   used_dir_counts in the group summary information - I'd
  533: 	   really like to know what the rationale behind this
  534: 	   'set i_mode to zero to denote an unused inode' is
  535: 	 */
  536: 	save_i_mode = pip->i_mode;
  537: 	pip->i_mode = mode;
  538: 	ext2_free_inode(pip);	
  539: 	pip->i_mode = save_i_mode;
  540: 	return (0);
  541: }
  542: 
  543: /*
  544:  * Fserr prints the name of a file system with an error diagnostic.
  545:  * 
  546:  * The form of the error message is:
  547:  *	fs: error message
  548:  */
  549: static void
  550: ext2_fserr(fs, uid, cp)
  551: 	struct ext2_sb_info *fs;
  552: 	u_int uid;
  553: 	char *cp;
  554: {
  555: 
  556: 	log(LOG_ERR, "uid %d on %s: %s\n", uid, fs->fs_fsmnt, cp);
  557: }